一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - 利用Pytorch進行CNN詳細剖析

利用Pytorch進行CNN詳細剖析

2022-02-23 22:29Whatbeg's blog Python

本文緣起于一次CNN作業中的一道題,這道題涉及到了基本的CNN網絡搭建,能夠讓人比較全面地對CNN有一個了解,所以想做一下,于是有了本文。

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

工具

開源深度學習庫: PyTorch

數據集: MNIST

實現

初始要求

利用Pytorch進行CNN詳細剖析

首先建立基本的BASE網絡,在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:預處理

利用Pytorch進行CNN詳細剖析

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

 

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

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

這部分代碼見 preprocessing.py 。

問題B:BASE模型

利用Pytorch進行CNN詳細剖析

將random seed設置為0,在前10000個訓練樣本上學習參數,***看20個epochs之后的測試集錯誤率。***結果為:

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

可以看到,BASE模型準確率并不是那么的高。

問題C:Batch Normalization v.s BASE

利用Pytorch進行CNN詳細剖析

在前三個block的卷積層之后加上Batch Normalization層,簡單修改網絡結構如下即可:

 

																				
  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)

同樣的參數run一下,得出加了BN的結果為:

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

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

關于Batch Normalization的更多資料參見[2],[5]。

問題D: Dropout Layer

利用Pytorch進行CNN詳細剖析

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

 

																																										
  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能夠對BASE模型起到一定提升作用,但是對BN模型卻效果不明顯反而降低了。

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

問題E:SK model

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

利用Pytorch進行CNN詳細剖析

利用Pytorch進行CNN詳細剖析

如此一番改動后,搭建的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后,結果如下,

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

測試集準確率得到了少許的提高。

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

VGG中就使用了這種方法。

問題F:Change Number of channels

利用Pytorch進行CNN詳細剖析

通過將特征圖大小乘上一個倍數,再通過shell程序執行,得到如下結果:

 

																																																																							
  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時,最終的準確度基本是往上提升的。這在一定程度上說明,在沒有達到過擬合前,增大特征圖的個數,即相當于提取了更多的特征,提取特征數的增加有助于精度的提高。

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

問題G:Use different training set sizes

利用Pytorch進行CNN詳細剖析

同樣通過腳本運行,增加參數

 

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

表示使用的數據大小,從前往后取 usebatchsize 個數據。

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

運行的結果如下:

 

																																																																																
  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%

由此可以明顯地看出,數據越多,結果的精度越大。

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

問題H:Use different training sets

利用Pytorch進行CNN詳細剖析

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

運行結果如下:

 

																																																																																								
  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%

由此可見,采用不同的訓練樣本集合訓練出來的網絡有一定的差異,雖不是很大,但是畢竟顯示出了不穩定的結果。

問題I:Random Seed’s effects

利用Pytorch進行CNN詳細剖析

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

運行的結果如下:

 

																																																																																															
  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%

事實上在用上整個訓練集的時候,隨機數生成器的種子設置對于***結果的影響不大。

問題J:ReLU or Sigmoid?

利用Pytorch進行CNN詳細剖析

將ReLU全部換成Sigmoid后,用全部60000個訓練集訓練,有對比結果如下:

 

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

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 教师系列 大桥未久在线 | 毛片网站免费观看 | 青草草产国视频 | 91在线视频播放 | 国产亚洲精aa在线观看不卡 | 美女被上漫画 | 无码国产成人777爽死 | 国产精品视频免费看 | 精品无码国产AV一区二区三区 | 精品免费看 | 国产一区私人高清影院 | 成年性生交大片免费看 | xxxxxx日本处大片免费看 | 欧美午夜视频一区二区三区 | 日韩成人一级 | 热辣小秘书办公室 | 91制片厂制作果冻传媒123 | 天天爱综合 | 欧美一级片在线看 | 美女扒开胸罩露出奶 | 小早川怜子息梦精在线播放 | 红楼影视h38bar在线线播放 | 国产高清一区二区三区免费视频 | 欧美另类老女人 | 九九99在线视频 | 1024日韩基地| 日本欧美大码a在线视频播放 | www四虎| 魔法满屋免费观看完整版中文 | 全肉一女n男np高h双龙养成 | 国产精品久久免费 | 精品久久久久久久久久香蕉 | 高h喷水荡肉爽文np肉色文 | 女人日男人 | 国产成人夜色影视视频 | 亚洲是图你懂的 | 国产精品99久久免费观看 | 天天欲色成人综合网站 | 午夜神器18以下不能进免费 | 99精品国产自在现线观看 | 99久久伊人精品波多野结衣 |