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