自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

利用Pytorch進行CNN詳細(xì)剖析

開發(fā) 前端
本文緣起于一次CNN作業(yè)中的一道題,這道題涉及到了基本的CNN網(wǎng)絡(luò)搭建,能夠讓人比較全面地對CNN有一個了解,所以想做一下,于是有了本文。

本文緣起于一次CNN作業(yè)中的一道題,這道題涉及到了基本的CNN網(wǎng)絡(luò)搭建,在MNIST數(shù)據(jù)集上的分類結(jié)果,Batch Normalization的影響,Dropout的影響,卷積核大小的影響,數(shù)據(jù)集大小的影響,不同部分?jǐn)?shù)據(jù)集的影響,隨機數(shù)種子的影響,以及不同激活單元的影響等,能夠讓人比較全面地對CNN有一個了解,所以想做一下,于是有了本文。

工具

開源深度學(xué)習(xí)庫: PyTorch

數(shù)據(jù)集: MNIST

實現(xiàn)

初始要求

利用Pytorch進行CNN詳細(xì)剖析

首先建立基本的BASE網(wǎng)絡(luò),在Pytorch中有如下code:

 

  1. class Net(nn.Module): 
  2.     def __init__(self): 
  3.         super(Net, self).__init__() 
  4.         self.conv1 = nn.Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1), padding=0) 
  5.         self.conv2 = nn.Conv2d(20, 50, kernel_size=(5, 5), stride=(1, 1), padding=0) 
  6.         self.fc1 = nn.Linear(4*4*50, 500) 
  7.         self.fc2 = nn.Linear(500, 10) 
  8.  
  9.     def forward(self, x): 
  10.         x = F.max_pool2d(self.conv1(x), 2) 
  11.         x = F.max_pool2d(self.conv2(x), 2) 
  12.         x = x.view(-1, 4*4*50) 
  13.         x = F.relu(self.fc1(x)) 
  14.         x = self.fc2(x) 
  15.         return F.log_softmax(x) 

這部分代碼見 base.py 。

問題A:預(yù)處理

利用Pytorch進行CNN詳細(xì)剖析

即要求將MNIST數(shù)據(jù)集按照規(guī)則讀取并且tranform到適合處理的格式。這里讀取的代碼沿用了BigDL Python Support的讀取方式,無需細(xì)說,根據(jù)MNIST主頁上的數(shù)據(jù)格式可以很快讀出,關(guān)鍵block有讀取32位比特的函數(shù):

 

  1. def _read32(bytestream): 
  2.     dt = numpy.dtype(numpy.uint32).newbyteorder('>')    # 大端模式讀取,***字節(jié)在前(MSB first
  3.     return numpy.frombuffer(bytestream.read(4), dtype=dt)[0] 

讀出后是(N, 1, 28, 28)的tensor,每個像素是0-255的值,首先做一下歸一化,將所有值除以255,得到一個0-1的值,然后再Normalize,訓(xùn)練集和測試集的均值方差都已知,直接做即可。由于訓(xùn)練集和測試集的均值方差都是針對歸一化后的數(shù)據(jù)來說的,所以剛開始沒做歸一化,所以forward輸出和grad很離譜,后來才發(fā)現(xiàn)是這里出了問題。

這部分代碼見 preprocessing.py 。

問題B:BASE模型

利用Pytorch進行CNN詳細(xì)剖析

將random seed設(shè)置為0,在前10000個訓(xùn)練樣本上學(xué)習(xí)參數(shù),***看20個epochs之后的測試集錯誤率。***結(jié)果為:

  1. Test set: Average loss: 0.0014, Accuracy: 9732/10000 (97.3%) 

可以看到,BASE模型準(zhǔn)確率并不是那么的高。

問題C:Batch Normalization v.s BASE

利用Pytorch進行CNN詳細(xì)剖析

在前三個block的卷積層之后加上Batch Normalization層,簡單修改網(wǎng)絡(luò)結(jié)構(gòu)如下即可:

 

  1. class Net(nn.Module): 
  2.     def __init__(self): 
  3.         super(Net, self).__init__() 
  4.         self.conv1 = nn.Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1), padding=0) 
  5.         self.conv2 = nn.Conv2d(20, 50, kernel_size=(5, 5), stride=(1, 1), padding=0) 
  6.         self.fc1 = nn.Linear(4*4*50, 500) 
  7.         self.fc2 = nn.Linear(500, 10) 
  8.         self.bn1 = nn.BatchNorm2d(20) 
  9.         self.bn2 = nn.BatchNorm2d(50) 
  10.         self.bn3 = nn.BatchNorm1d(500) 
  11.  
  12.     def forward(self, x): 
  13.         x = self.conv1(x) 
  14.         x = F.max_pool2d(self.bn1(x), 2) 
  15.         x = self.conv2(x) 
  16.         x = F.max_pool2d(self.bn2(x), 2) 
  17.         x = x.view(-1, 4*4*50) 
  18.         x = self.fc1(x) 
  19.         x = F.relu(self.bn3(x)) 
  20.         x = self.fc2(x) 
  21.         return F.log_softmax(x) 

同樣的參數(shù)run一下,得出加了BN的結(jié)果為:

  1. Test set: Average loss: 0.0009, Accuracy: 9817/10000 (98.2%) 

由此可見,有明顯的效果提升。

關(guān)于Batch Normalization的更多資料參見[2],[5]。

問題D: Dropout Layer

利用Pytorch進行CNN詳細(xì)剖析

在***一層即 fc2 層后加一個 Dropout(p=0.5) 后,在BASE和BN上的結(jié)果分別為:

 

  1. BASE:Test set: Average loss: 0.0011, Accuracy: 9769/10000 (97.7%) 
  2. BN:  Test set: Average loss: 0.0014, Accuracy: 9789/10000 (97.9%) 

觀察得知,dropout能夠?qū)ASE模型起到一定提升作用,但是對BN模型卻效果不明顯反而降低了。

原因可能在于,BN模型中本身即包含了正則化的效果,再加一層Dropout顯得沒有必要反而可能影響結(jié)果。

問題E:SK model

SK model: Stacking two 3x3 conv. layers to replace 5x5 conv. layer

利用Pytorch進行CNN詳細(xì)剖析

利用Pytorch進行CNN詳細(xì)剖析

如此一番改動后,搭建的SK模型如下:

 

  1. class Net(nn.Module): 
  2.     def __init__(self): 
  3.         super(Net, self).__init__() 
  4.         self.conv1_1 = nn.Conv2d(1, 20, kernel_size=(3, 3), stride=(1, 1), padding=0) 
  5.         self.conv1_2 = nn.Conv2d(20, 20, kernel_size=(3, 3), stride=(1, 1), padding=0) 
  6.         self.conv2 = nn.Conv2d(20, 50, kernel_size=(3, 3), stride=(1, 1), padding=0) 
  7.         self.fc1 = nn.Linear(5*5*50, 500) 
  8.         self.fc2 = nn.Linear(500, 10) 
  9.         self.bn1_1 = nn.BatchNorm2d(20) 
  10.         self.bn1_2 = nn.BatchNorm2d(20) 
  11.         self.bn2 = nn.BatchNorm2d(50) 
  12.         self.bn3 = nn.BatchNorm1d(500) 
  13.         self.drop = nn.Dropout(p=0.5) 
  14.  
  15.     def forward(self, x): 
  16.         x = F.relu(self.bn1_1(self.conv1_1(x))) 
  17.         x = F.relu(self.bn1_2(self.conv1_2(x))) 
  18.         x = F.max_pool2d(x, 2) 
  19.         x = self.conv2(x) 
  20.         x = F.max_pool2d(self.bn2(x), 2) 
  21.         x = x.view(-1, 5*5*50) 
  22.         x = self.fc1(x) 
  23.         x = F.relu(self.bn3(x)) 
  24.         x = self.fc2(x) 
  25.         return F.log_softmax(x) 

在20個epoch后,結(jié)果如下,

  1. SK: Test set: Average loss: 0.0008, Accuracy: 9848/10000 (98.5%) 

測試集準(zhǔn)確率得到了少許的提高。

這里利用2個3x3的卷積核來代替大的5x5卷積核,參數(shù)個數(shù)由5x5=25變?yōu)榱?x3x3=18。實踐表明,這樣使得計算更快了,并且小的卷積層之間的ReLU也很有幫助。

VGG中就使用了這種方法。

問題F:Change Number of channels

利用Pytorch進行CNN詳細(xì)剖析

通過將特征圖大小乘上一個倍數(shù),再通過shell程序執(zhí)行,得到如下結(jié)果:

 

  1. SK0.2:  97.7% 
  2. SK0.5:  98.2% 
  3. SK1:    98.5% 
  4. SK1.5:  98.6% 
  5. SK2:    98.5%  (max 98.7%) 

在特征圖分別為4,10, 30, 40時,最終的準(zhǔn)確度基本是往上提升的。這在一定程度上說明,在沒有達到過擬合前,增大特征圖的個數(shù),即相當(dāng)于提取了更多的特征,提取特征數(shù)的增加有助于精度的提高。

這部分代碼見 SK_s.py 和 runSK.sh 。

問題G:Use different training set sizes

利用Pytorch進行CNN詳細(xì)剖析

同樣通過腳本運行,增加參數(shù)

 

  1. parser.add_argument('--usedatasize', type=intdefault=60000, metavar='SZ'
  2.                     help='use how many training data to train network'

表示使用的數(shù)據(jù)大小,從前往后取 usebatchsize 個數(shù)據(jù)。

這部分程序見 SK_s.py 和 runTrainingSize.sh 。

運行的結(jié)果如下:

 

  1. 500:   84.2% 
  2. 1000:  92.0% 
  3. 2000:  94.3% 
  4. 5000:  95.5% 
  5. 10000: 96.6% 
  6. 20000: 98.4% 
  7. 60000: 99.1% 

由此可以明顯地看出,數(shù)據(jù)越多,結(jié)果的精度越大。

太少的數(shù)據(jù)無法準(zhǔn)確反映數(shù)據(jù)的整體分布情況,而且容易過擬合,數(shù)據(jù)多到一定程度效果也會不明顯,不過,大多數(shù)時候我們總還是嫌數(shù)據(jù)太少,而且更多的數(shù)據(jù)獲取起來也有一定難度。

問題H:Use different training sets

利用Pytorch進行CNN詳細(xì)剖析

采用腳本完成,這部分程序見 SK_0.2.py 和 diffTrainingSets.sh 。

運行結(jié)果如下:

 

  1.  0-10000: 98.0% 
  2. 10000-20000: 97.8% 
  3. 20000-30000: 97.8% 
  4. 30000-40000: 97.4% 
  5. 40000-50000: 97.5% 
  6. 50000-60000: 97.7% 

由此可見,采用不同的訓(xùn)練樣本集合訓(xùn)練出來的網(wǎng)絡(luò)有一定的差異,雖不是很大,但是畢竟顯示出了不穩(wěn)定的結(jié)果。

問題I:Random Seed’s effects

利用Pytorch進行CNN詳細(xì)剖析

采用 runSeed.sh 腳本完成,用到了全部60000個訓(xùn)練集。

運行的結(jié)果如下:

 

  1. Seed      0:  98.9% 
  2. Seed      1:  99.0% 
  3. Seed     12:  99.1% 
  4. Seed    123:  99.0% 
  5. Seed   1234:  99.1% 
  6. Seed  12345:  99.0% 
  7. Seed 123456:  98.9% 

事實上在用上整個訓(xùn)練集的時候,隨機數(shù)生成器的種子設(shè)置對于***結(jié)果的影響不大。

問題J:ReLU or Sigmoid?

利用Pytorch進行CNN詳細(xì)剖析

將ReLU全部換成Sigmoid后,用全部60000個訓(xùn)練集訓(xùn)練,有對比結(jié)果如下:

 

  1. ReLU SK_0.2:  99.0% 
  2. igmoid SK_0.2:  98.6% 

由此可以看出,在訓(xùn)練CNN時,使用ReLU激活單元比Sigmoid激活單元要更好一些。原因可能在于二者機制的差別,sigmoid在神經(jīng)元輸入值較大或者較小時,輸出值會近乎0或者1,這使得許多地方的梯度幾乎為0,權(quán)重幾乎得不到更新。而ReLU雖然增加了計算的負(fù)擔(dān),但是它能夠顯著加速收斂過程,并且也不會有梯度飽和問題。

 

責(zé)任編輯:未麗燕 來源: Whatbeg's blog
相關(guān)推薦

2009-12-30 10:02:37

ADO.NET Ent

2009-12-01 18:07:12

VS 2003工具

2009-12-28 13:53:01

ADO.NET記錄集

2024-01-03 10:23:11

卷積神經(jīng)網(wǎng)絡(luò)CNNpytorch

2009-09-29 10:00:40

Spring AOP框

2011-06-15 12:36:58

JSPBEAN

2009-08-27 17:14:36

C# Socket

2009-09-02 10:26:23

JSP和BEAN

2010-02-23 10:32:20

Python 腳本

2010-03-15 14:58:58

交換技術(shù)

2010-03-04 17:36:01

Linux系統(tǒng)分區(qū)

2009-09-11 11:17:04

C#引用類型

2009-12-16 11:16:03

VS 2005開發(fā)環(huán)境

2009-09-18 10:00:17

C#數(shù)組操作

2010-03-03 14:30:35

Linux睡眠休眠

2009-08-31 17:26:32

C#異常處理

2010-03-08 14:40:27

Linux進程調(diào)度

2009-09-03 16:58:49

C#內(nèi)存管理

2009-08-27 17:51:34

C#匿名方法

2020-03-26 15:16:26

EdgeBoard
點贊
收藏

51CTO技術(shù)棧公眾號