(原)torch和caffe中的BatchNorm層


轉載請注明出處:

http://www.cnblogs.com/darkknightzh/p/6015990.html

BatchNorm具體網上搜索。

caffe中batchNorm層是通過BatchNorm+Scale實現的,但是默認沒有bias。torch中的BatchNorm層使用函數SpatialBatchNormalization實現,該函數中有weight和bias。

如下代碼:

local net = nn.Sequential()
net:add(nn.SpatialBatchNormalization(64))
net:add(nn.SpatialBatchNormalization(64, 1e-5, 0.1, false))
print(net.modules)

輸出如下:

其中第一個為nn.SpatialBatchNormalization(64),第二個為nn.SpatialBatchNormalization(64, 1e-5, 0.1, false)

SpatialBatchNormalization 參數如下:

nn.SpatialBatchNormalization(N [,eps] [, momentum] [,affine])

默認情況下,eps=1e-5,momentum =0.1,affine=true。因而若要和caffe中的BatchNorm一樣,均沒有weight和bias,則需要將affine設置為false。若affine為默認值,有如下兩種方法可以使torch和caffe參數一致(不太確定):

1. 手動將bias設置為0,此時能和caffe中BatchNorm+Scale(默認的)一樣。

2. caffe中ScaleParameter的bias_term(equivalent to a ScaleLayer+BiasLayer)設置為true(該值默認為false)。

 

========================================================================

161110更新(可能有不對的地方):

對於Caffe

在使用BatchNorm時,Batch層共3個參數,1個存儲均值向量,一個存儲方差向量,第三個存儲縮放的值。最終的均值向量=均值向量/縮放;最終的方差向量=方差向量/縮放。

Scale層共2個參數,一個存儲的是γ向量,一個存儲的是β向量。

假設caffe中BatchNorm輸入為1(batch size)*64(channel)*128(height)*128(width)(輸出和輸入一樣),則BatchNorm層共3個參數:mean(64維的向量),variance(64維的向量),scalefactor(1維的向量)。其中mean存儲了每一channel的均值,variance存儲了每一channel的方差,scalefactor看着caffe的參數,好像都是999.982361(沒有過多測試,不太確定)。

在TEST階段,當輸入一個數,如0.001932,對應的mean= -5122.504395,variance=385844.062500,scale= 999.982361時,

縮放后的mean:-5122.504395/999.982361=-5.1225947524488384450613324368429

縮放后的variance:385844.062500/999.982361=385.85086852346988548531007538442

標准差:(385.85086852346988548531007538442+1e(-5))^0.5=

19.643087296132191385983152758013

縮放后的值:

(0.001932-(-5.1225947524488384450613324368429))/ 19.643087296132191385983152758013= 0.26088194158042966422836995726056

實際上得到的為0.260882。在精度范圍內一致。

總結起來就是,對每個維度使用對應的均值和方差。不同batch使用對應的參數。

在TRAIN階段,則是首先計算每個batch不同channel的均值及方差,而后通過論文中公式得到對應的輸出。

${{\hat{x_i}}}=\frac{{{x}_{i}}-{{\mu }_{B}}}{\sqrt{\sigma _{B}^{2}+\varepsilon }}$

$E\left[ x \right]={{E}_{B}}\left[ {{\mu }_{B}} \right]$

$Var\left[ x \right]=\frac{m}{m-1}{{E}_{B}}\left[ \sigma _{B}^{2} \right]$

實際中感覺caffe中,即便在訓練階段,依舊使用上面的var來計算方差。

 

caffe中scale,得到的scale_param包括weight和bias,均為channel維的向量(如64)。之后對於輸入,通過下式計算輸出。注意的是,不同channel使用各自的weight和bias,同一個channel的weight和bias都一樣。

${{y}_{i}}=\gamma {{\hat{x_i}}}+\beta $

 

對於torch

torch中SpatialBatchNormalization是跟在conv層之后,其輸入為4D數據(應該是batch_size*channel*height*width),另一個BatchNormalization層是跟在一般的層后面(這樣說不太准確吧),其輸入為2D數據(應該是batch_size*channel)。SpatialBatchNormalization繼承自BatchNormalization。

SpatialBatchNormalization和BatchNormalization的第一個參數N代表特征的維數(channel)。

affine=true時,SpatialBatchNormalization中結構:

affine=false時,SpatialBatchNormalization中結構:

當net:evaluate()時,上兩圖中最后一個參數train為false。

其中,running_mean存儲的是特征的mean(對應於caffe中最終的均指向量),running_var存儲的是特征的方差(對應於caffe中最終的方差向量)。weight存儲的是縮放時特征的γ,bias存儲的是縮放時特征的β。

 

BatchNorm的論文為:Batch Normalization Accelerating Deep Network Training by Reducing Internal Covariate Shift。

161110更新結束

161121更新

今天使用cudnn的BatchNormalization時,提示Only CUDA tensors are supported for cudnn.BatchNormalization,而后程序崩潰。網上搜索了一下,https://github.com/soumith/cudnn.torch/issues/219遇到了類似的問題。具體原因可能不太一樣吧。我這邊是使用BatchNormalization(或者SpatialBatchNormalization)的問題。該層affine=true時,會使用仿射(有weight和bias),affine=false時,無weight和bias。而cudnn實際上只支持affine=true的情況(目前是這樣),我這邊程序有affine=false的時候,此時使用cudnn的BatchNormalization(SpatialBatchNormalization繼承自BatchNormalization,下面不在說明SpatialBatchNormalization)就會直接assert錯誤了。

cudnn的BatchNormalization的部分初始化代碼如下(位置:/home/XXX/torch/install/share/lua/5.1/cudnn/BatchNormalization.lua):

function BatchNormalization:__init(nFeature, eps, momentum, affine)
   parent.__init(self)
   assert(nFeature and type(nFeature) == 'number',
          'Missing argument #1: Number of feature planes. ')
   assert(nFeature ~= 0, 'To set affine=false call BatchNormalization'
     .. '(nFeature,  eps, momentum, false) ')
   assert(affine == true or affine == nil, 'only affine supported')

實際上assert錯誤的地方是下面代碼的最后一行:

function BatchNormalization:createIODescriptors(input)
   assert(input:dim() == self.nDim)
   assert(torch.typename(self.weight) == 'torch.CudaTensor' and torch.typename(self.bias) == 'torch.CudaTensor',
          'Only CUDA tensors are supported for cudnn.BatchNormalization!')

從初始化代碼可以看出,cudnn的BatchNormalization只支持affine=true的情況。

該網頁也提供了解決方法:byronwwang在第5層的回復中注釋的代碼就是解決方法。在使用cudnn.convert時,可以通過第三個參數,不轉換某些層。https://github.com/soumith/cudnn.torch里面也給出了不轉換層時的代碼(Conversion between cudnn and nn這部分):

cudnn.convert(net, cudnn, function(module)
   return torch.type(module):find('BatchNormalization')
end)

此時BatchNormalization會使用nn模塊中的BatchNormalization。

161121更新結束

========================================================================


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM