torch 深度学习 (2)
前面我们完成了数据的下载和预处理,接下来就该搭建网络模型了,CNN网络的东西可以参考博主 zouxy09的系列文章Deep Learning (深度学习) 学习笔记整理系列之 (七)
-
加载包
- require 'torch'
- require 'image'
- require 'nn'
-
函数运行参数的设置
- if not opt then
- print "==> processing options"
- cmd = torch.CmdLine()
- cmd:text()
- cmd:text('options:')
- -- 选择构建何种结构:线性|MLP|ConvNet。默认:convnet
- cmd:option('-model','convnet','type of model to construct: linear | mlp | convnet')
- -- 是否需要可视化
- cmd:option('-visualize',true,'visualize input data and weights during training')
- -- 参数
- opt = cmd:parse(arg or {})
- end
-
设置网络模型用到的一些参数
- -- 输出类别数,也就是输出节点个数
- noutputs =10
- -- 输入节点的个数
- nfeats = 3 -- YUV三个通道,可以认为是3个features map
- width =32
- height =32
- -- Linear 和 mlp model下的输入节点个数,就是将输入图像拉成列向量
- ninputs = nfeats*width*height
-
- -- 为mlp定义隐层节点的个数
- nhiddens = ninputs/2
-
- -- 为convnet定义隐层feature maps的个数以及滤波器的尺寸
- nstates = {16,256,128} --第一个隐层有16个feature map,第二个隐层有256个特征图,第三个隐层有128个节点
- fanin = {1,4} -- 定义了卷积层的输入和输出对应关系,以fanin[2]举例,表示该卷积层有16个map输入,256个map输出,每个输出map是有fanin[2]个输入map对应filters卷积得到的结果
- filtsize =5 --滤波器的大小,方形滤波器
- poolsize = 2 -- 池化池尺寸
- normkernel = image.gaussian1D(7) --长度为7的一维高斯模板,用来local contrast normalization
-
构建模型
- if opt.model == linear then
- -- 线性模型
- model = nn.Sequntial()
- model:add(nn.Reshape(ninputs)) -- 输入层
- model:add(nn.Linear(ninputs,noutputs)) -- 线性模型 y=Wx+b
- elseif opt.model == mlp then
- -- 多层感知器
- model = nn.Sequential()
- model:add(nn.Reshape(ninputs)) --输入层
- model:add(nn.Linear(ninputs,nhiddens)) --线性层
- model:add(nn.Tanh()) -- 非线性层
- model:add(nn.Linear(nhiddens,noutputs)) -- 线性层
- -- MLP 目标: `!$y=W_2 f(W_1X+b) + b $` 这里的激活函数采用的是Tanh(),MLP后面还可以接一层输出层Tanh()
- elseif opt.model == convnet then
- -- 卷积神经网络
- model = nn.Sequential()
- -- 第一阶段
- model:add(nn.SpatialConvolutionMap(nn.tables.random(nfeats,nstates[1],fanin[1]),filtsize,filtsize))
- -- 这一步直接输入的是图像进行卷积,所以没有了 nn.Reshape(ninputs)输入层。 参数:nn.tables.random(nfeats,nstates[1],fanin[1])指定了卷积层中输入maps和输出maps之间的对应关系,这里表示bstates[1]个输出maps的每一map都是由fanin[1]个输入maps得到的。filtsize则是卷积算子的大小
- -- 所以该层的连接个数为(filtsize*filtsize*fanin[1]+1)*nstates[1],1是偏置。这里的fanin[1]连接是随机的,也可以采用全连接 nn.tables.full(nfeats,nstates[1]), 当输入maps和输出maps个数相同时,还可以采用一对一连接 nn.tables.oneToOne(nfeats).
- -- 参见解释文档 [Convolutional layers](https://github.com/torch/nn/blob/master/doc/concolution.md#nn.convlayers.dok)
-
- model:add(nn.Tanh()) --非线性变换层
- model:SpatialLPPooling(nstates[1],2,poolsize,poolsize,poolsize,poolsize)
- -- 参数(feature maps个数,Lp范数,池化尺寸大小(w,h), 滑动窗步长(dw,dh))
- model:SpatialSubtractiveNormalization(nstates[1],normalkernel)
- -- local contrast normalization
- -- 具体操作是先在每个map的local邻域进行减法归一化,然后在不同的feature map上进行除法归一化。类似与图像点的均值化和方差归一化。参考[1^x][Nonlinear Image Representation Using Divisive Normalization], [Gaussian Scale Mixtures](stats.stackexchange.com/174502/what-are gaussian-scale-mixtures-and-how-to-generate-samples-of-gaussian-scale),还有解释文档 [Convolutional layers](https://github.com/torch/nn/blob/master/doc/concolution.md#nn.convlayers.dok)
-
- --[[
- 这里需要说的一点是传统的CNN一般是先卷积再池化再非线性变换,但这两年CNN一般都是先非线性变换再池化了
- --]]
- -- 第二阶段
- model:add(nn.SpatialConvolutionMap(nn.tables.random(nstates[1],nstates[2],fanin[2]),filtsize,filtsize))
- model:add(nn.Tanh())
- model:add(nn.SpatialLPPooling(nstates[2],2,poolsize,poolsize))
- model:add(nn.SpatialSubtractiveNormalization(nstates[2],kernel))
-
- --第三阶段
- model:add(nn.Reshape(nstates[2]*filtsize*filtsize)) --矢量化,全连接
- model:add(nn.Linear(nstates[2]*filtsize*filtsize,nstates[3]))
- model:add(nn.Tanh())
- model:add(nn.Linear(nstates[3],noutputs))
- else
- error('unknown -model')
- end
-
显示网络结构以及参数
- print('==> here is the model')
- print(model)
结果如下图

model.png
可以发现,可训练参数分别在1,5部分,所以可以观察权重矩阵的大小
- print('==> 权重矩阵的大小 ')
- print(model:get(1).weight:size())
- print('==> 偏置的大小')
- print(model:get(1).bias:numel())

weights numel.png
-
参数的可视化
- if opt.visualize then
- image.display(image=model:get(1).weight, padding=2,zoom=4,legend='filters@ layer 1')
- image.diaplay(image=model:get(5).weight,padding=2,zoom=4,legend='filters @ layer 2')
- end

weights visualization.png