BasicModule
程序實現的時候所有模型繼承自定義的basicmoudle,主要重寫了模型加載和保存等方法

1 import torch 2 from config import opt 3 class BasicModule(torch.nn.Module): 4 def __init__(self): 5 super(BasicModule,self).__init__() 6 #self.model_name = str(type(self)) 7 8 def save(self,path=None): 9 if path is None: 10 path = 'checkpoints/'+opt.model+'_'+'model.pth' 11 torch.save(self.state_dict(),path) 12 def load(self,path): 13 self.load_state_dict(torch.load(path),strict = False)
Lenet5
這個是n多年前就有的一個CNN的經典結構,主要是用於手寫字體的識別,也是剛入門需要學習熟悉的一個網絡,引入cnn做圖像處理,使用全連接做分類。
- 輸入尺寸:32*32
- 卷積層:2個
- 降采樣層:2個
- 全連接層:3個
- 輸出:10個類別(數字0-9的概率
- 總參數:122304

1 class LeNet5(nn.Module): 2 def __init__(self): 3 super(LeNet5,self).__init__() 4 self.conv1 = nn.Sequential(nn.Conv2d(3,6,5,1,0),nn.ReLU(),nn.MaxPool2d(2,2)) 5 self.conv2 = nn.Sequential(nn.Conv2d(6,16,5,1,0),nn.ReLU(),nn.MaxPool2d(2,2)) 6 self.fc1 = nn.Sequential(nn.Linear(400,120),nn.BatchNorm1d(120),nn.ReLU()) 7 self.fc2 = nn.Sequential(nn.Linear(120,84),nn.BatchNorm1d(84),nn.ReLU()) 8 self.fc3 = nn.Sequential(nn.Linear(84,10),nn.BatchNorm1d(10),nn.ReLU()) 9 10 def forward(self,x): 11 x = self.conv1(x) 12 x = self.conv2(x) 13 x = x.view(x.size(0),-1) 14 #print(x.size()) 15 x = self.fc1(x) 16 x = self.fc2(x) 17 x = self.fc3(x) 18 return x
AlexNet
AlexNet可以說是LeNet的繼承和發展,AlexNet具有6000萬個參數和65萬個神經元的神經網絡由五個卷積層和三個全連接層,以及最后的1000維的softmax層組成. ImageNet上測試的結果表明,AlexNet比(論文發表時的)以前所有的網絡的性能都要高,而且需要的訓練時間更少。下面簡單分析AlexNet的創新點,並探討它們是如何影響性能的: 1)將ReLU代替sigmoid作為CNN的激活函數,並驗證了ReLU在較深的網絡里性能優於sigmoid,有效解決了sigmoid引起的梯度彌散的問題。而且ReLU比sigmoid的學習速度更快,節省訓練時間。 2)多GPU訓練,由於以前的GPU內存(GTX580內存為3G)較小,這限制了可以在其上訓練的網絡的最大尺寸。AlexNet將網絡分布在兩個GPU上,而在訓練時GPU僅在特定的層間進行通信,從而減少性能消耗。
與在單個GPU上訓練且每個卷積層的內核數量少一半的網絡相比,這個方案分別將top-1和top-5的錯誤率分別降低了1.7%和1.2%。雙GPU網絡的訓練時間比單GPU網絡的訓練時間少一點。 3)提出LRN局部響應歸一化(用於ReLU后),不同的內核計算的神經元輸出之間產生對大激活度的競爭,使得局部較大的響應值更大,而小的會變得更小,從而抑制了小的神經元,增強模型的泛化能力。
響應歸一化將top-1和top-5的錯誤率分別降低了1.4%和1.2%。 4)使用重疊的最大池化代替平均池化,避免平均池化造成的模糊化效果。而且Alexnet中的步長比池化核的尺寸要小,池化層的輸出間會有重疊,這樣使特征能表現更多的內容,提高識別性能。
這個方案將top-1和top-5的錯誤率分別降低了0.4%和0.3%。通常在訓練期間觀察到重疊池模型稍微難以過度擬合。
5)Dropout即以0.5的概率把每個隱藏的神經元的輸出設置為零。以這種方式“dropout”的神經元不參與正向傳遞,也不參與反向傳遞。所以每次提交輸入時,神經網絡都采樣不同的體系結構,但是所有這些體系結構共享權重。
這種技術減少了神經元的復雜的共同適應,因為神經元不能依賴於特定的其他神經元的存在。注意dropout大致使收斂所需的迭代次數翻倍。 6)數據增強。因為Alexnet的參數量巨多,容易造成過擬合,通過截取,平移,翻轉還有RGB像素值集上做PCA(對於每個訓練圖像,成倍增加已有的主成分)等方法使得數據集更豐富,從而提高泛化能力。
從原始圖像生成變換的圖像是在CPU上的Python代碼中生成的,而GPU正在訓練上一批圖像,這節約了時間。
- 輸入尺寸:224*224
- 卷積層:5個
- 降采樣層:3個
- 全連接層:3個
- 輸出:10個類別(數字0-9的概率
1 #coding:utf8 2 from torch import nn 3 from .BasicModule import BasicModule 4 5 class AlexNet(BasicModule): 6 ''' 7 code from torchvision/models/alexnet.py 8 結構參考 <https://arxiv.org/abs/1404.5997> 9 ''' 10 def __init__(self, num_classes=2): 11 12 super(AlexNet, self).__init__() 13 14 self.model_name = 'alexnet' 15 16 self.features = nn.Sequential( 17 nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2), 18 nn.ReLU(inplace=True), 19 nn.MaxPool2d(kernel_size=3, stride=2), 20 nn.Conv2d(64, 192, kernel_size=5, padding=2), 21 nn.ReLU(inplace=True), 22 nn.MaxPool2d(kernel_size=3, stride=2), 23 nn.Conv2d(192, 384, kernel_size=3, padding=1), 24 nn.ReLU(inplace=True), 25 nn.Conv2d(384, 256, kernel_size=3, padding=1), 26 nn.ReLU(inplace=True), 27 nn.Conv2d(256, 256, kernel_size=3, padding=1), 28 nn.ReLU(inplace=True), 29 nn.MaxPool2d(kernel_size=3, stride=2), 30 ) 31 self.classifier = nn.Sequential( 32 nn.Dropout(), 33 nn.Linear(256 * 6 * 6, 4096), 34 nn.ReLU(inplace=True), 35 nn.Dropout(), 36 nn.Linear(4096, 4096), 37 nn.ReLU(inplace=True), 38 nn.Linear(4096, num_classes), 39 ) 40 41 def forward(self, x): 42 x = self.features(x) 43 x = x.view(x.size(0), 256 * 6 * 6) 44 x = self.classifier(x) 45 return x
VGG16
一、簡述
VGG卷積神經網絡是牛津大學計算機視覺實驗室參加2014年ILSVRC(ImageNet Large Scale Visual Recognition Challenge)比賽的網絡結構,為了解決ImageNet中的1000類圖像分類和定位問題。實驗結果是VGGNet斬獲了2014年ILSVRC分類第二,定位第一,分類第一是GoogleNet模型。
想要更好的理解和掌握VGG系列的模型,建議閱讀原論文:VGG論文鏈接
二、模型結構
下圖是VGGNet系列的結構說明,其中最著名的是VGG16模型,下圖就是VGGNet系列,從11層到19層
VGG16總參數為總計:138357544個
上圖是VGGNet系列的結構說明,其中最著名的是VGG16模型,也就是上圖中的D結構。
VGG16輸入尺寸變化具體如下圖所示:
從上述兩個圖可以得到,VGG16共有16個層,這也是VGG16名稱的由來,是一個相當深的卷積神經網絡。VGG各種級別的結構都采用了5段卷積,每一段有一個或多個卷積層。同時每一段的尾部都接着一個最大池化層來縮小圖片尺寸。每一段內的卷積核數量一致,越靠后的卷積核數量越多 64-128-256-512-512。經常出現多個完全一樣的卷積層堆疊在一起的情況。
三、深入理解VGG16模型 作者在學習VGG16模型的時候,上網查找了很多關於VGG16模型的文章,但是感覺大家都只是在介紹VGG16模型本身的結構而已,至於為什么要這樣設計似乎很少有人提及,所以作者一直都是一知半解的,對於想要更好的理解和掌握VGG16,甚至去改進它,
就需要深入理解隱藏在模型結構背后的直覺和原理,后來在不經意間,看到一篇不錯的文章,感覺很有幫助~,在這里分享給大家:卷積神經網絡VGG 論文細讀 要理解VGG16模型的設計原理,首先要理解卷積神經網絡兩大特點: 1:局部連接 2:權值共享 在這里作者就不再詳細的介紹這兩大特點了,如果對這兩個特點還不了解的或者了解地不透徹可以移步到:CNN初步認識(局部感知、權值共享) 深度:對於局部連接來說,每個神經元的輸出就只和該神經元上一層周圍的局部神經元有關,這樣就可以使得網絡的參數大大降低,可以設計更深的網絡模型,這樣做肯定有壞處,可能會丟失一些全局信息,但如果我們設計的網絡結構很深,
那么可以在高層對網絡低層的局部特征進行組合,最終得到全局特征。所以這似乎是一個很巧妙的特點,一方面局部連接可能會丟失全局特征,但另一方面它又可以設計出更深的網絡模型,從而得到全局特征。深度對網絡的性能極其重要,
一般來說越深的深度網絡性能也就越好,深度網絡自然集成了低、中、高層特征,可以表達出更豐富的特征和含義。在VGG系列模型中,網絡深度達到16-19層,是當時在論文發表前最深的深度網絡,所以它表現出了極佳的性能。 寬度:對於權值共享來說,這里的權值指的是卷積核的權值,所謂共享指的是從一個局部區域學習到的信息,應用到圖像的其它地方去,即用一個相同的卷積核去卷積整幅圖像。通過權值共享,使得網絡中訓練的參數大大減少,
可以幫助我們訓練更深的模型。其次,也由於權值共享,一個卷積核也就只能學到相應的某個特征,所以我們需要設計多個不同的卷積核來提取圖像中不同的特征,卷積核的數量也成為卷積神經網絡的寬度,在VGG16模型中,最開始是64個卷積核,
隨着網絡的加深,卷積核數量一直增加到512,是一個很寬的網絡,所以它最后的性能如此之強大也不足為奇了。 卷積核:同時我們可以發現,VGG模型中所有的卷積核大小均為3×3,使用3×3的小卷積核堆疊代替大卷積核,主要有以下幾個原因: (1)3x3是最小的能夠捕獲像素八鄰域信息的尺寸。
(2)兩個3x3的堆疊卷基層的有限感受野是5x5;三個3x3的堆疊卷基層的感受野是7x7,故可以通過小尺寸卷積層的堆疊替代大尺寸卷積層,並且感受野大小不變。所以可以把三個3x3的filter看成是一個7x7filter的分解中間層有非線性的分解,
並且起到隱式正則化的作用。 (3)多個3x3的卷基層比一個大尺寸filter卷基層有更多的非線性(更多層的非線性函數,使用了3個非線性激活函數),使得判決函數更加具有判決性。 (4)多個3x3的卷積層比一個大尺寸的filter有更少的參數,假設卷積層的輸入和輸出的特征圖大小相同為C,那么三個3x3的卷積層參數個數3x((3x3xC)xC)=27C²;一個(7x7xC)xC的卷積層參數為49C²。前者可以表達出輸入數據中更多個強力特征,使用的參數也更少。 唯一的不足是,在進行反向傳播時,中間的卷積層可能會導致占用更多的內存。 池化核:相比AlexNet的3x3的池化核,VGG全部采用2x2的池化核,可以保留更多的圖像信息。 全連接轉卷積(測試階段):這也是VGG的一個特點,在網絡測試階段將訓練階段的三個全連接層替換為三個卷積層,使得測試得到的全卷積網絡因為沒有全連接的限制,因而可以接收任意寬或高為的輸入,這在測試階段很重要。 卷積層和全連接層的唯一區別在於卷積層的神經元對輸入是局部連接的,並且同一個通道(channel)內不同神經元共享權值(weights). 卷積層和全連接層都是進行了一個點乘操作, 它們的函數形式相同. 因此卷積層可以轉化為對應的全連接層,
全連接層也可以轉化為對應的卷積層。 比如VGGNet[1]中, 第一個全連接層的輸入是7*7*512, 輸出是4096. 這可以用一個卷積核大小7*7, 步長(stride)為1, 沒有填補(padding), 輸出通道數4096的卷積層等效表示, 其輸出為11*4096, 和全連接層等價.
后續的全連接層可以用1x1卷積等效替代。 簡而言之, 全連接層轉化為卷積層的規則是: 將卷積核大小設置為輸入的空間大小.這樣做的好處在於卷 積層對輸入大小沒有限制, 因此可以高效地對測試圖像做滑動窗式的預測. 總結: 1、通過增加深度和寬度能有效地提升性能; 2、最佳模型:VGG16,從頭到尾只有3x3卷積與2x2池化,簡潔優美; 3、卷積可代替全連接,測試階段可適應各種尺寸的圖片。

import torch import torch.nn as nn import torch.nn.functional as F class VGG16(nn.Module): def __init__(self): super(VGG16, self).__init__() # 3 * 224 * 224 self.conv1_1 = nn.Conv2d(3, 64, 3) # 64 * 222 * 222 self.conv1_2 = nn.Conv2d(64, 64, 3, padding=(1, 1)) # 64 * 222* 222 self.maxpool1 = nn.MaxPool2d((2, 2), padding=(1, 1)) # pooling 64 * 112 * 112 self.conv2_1 = nn.Conv2d(64, 128, 3) # 128 * 110 * 110 self.conv2_2 = nn.Conv2d(128, 128, 3, padding=(1, 1)) # 128 * 110 * 110 self.maxpool2 = nn.MaxPool2d((2, 2), padding=(1, 1)) # pooling 128 * 56 * 56 self.conv3_1 = nn.Conv2d(128, 256, 3) # 256 * 54 * 54 self.conv3_2 = nn.Conv2d(256, 256, 3, padding=(1, 1)) # 256 * 54 * 54 self.conv3_3 = nn.Conv2d(256, 256, 3, padding=(1, 1)) # 256 * 54 * 54 self.maxpool3 = nn.MaxPool2d((2, 2), padding=(1, 1)) # pooling 256 * 28 * 28 self.conv4_1 = nn.Conv2d(256, 512, 3) # 512 * 26 * 26 self.conv4_2 = nn.Conv2d(512, 512, 3, padding=(1, 1)) # 512 * 26 * 26 self.conv4_3 = nn.Conv2d(512, 512, 3, padding=(1, 1)) # 512 * 26 * 26 self.maxpool4 = nn.MaxPool2d((2, 2), padding=(1, 1)) # pooling 512 * 14 * 14 self.conv5_1 = nn.Conv2d(512, 512, 3) # 512 * 12 * 12 self.conv5_2 = nn.Conv2d(512, 512, 3, padding=(1, 1)) # 512 * 12 * 12 self.conv5_3 = nn.Conv2d(512, 512, 3, padding=(1, 1)) # 512 * 12 * 12 self.maxpool5 = nn.MaxPool2d((2, 2), padding=(1, 1)) # pooling 512 * 7 * 7 # view self.fc1 = nn.Linear(512 * 7 * 7, 4096) self.fc2 = nn.Linear(4096, 4096) self.fc3 = nn.Linear(4096, 1000) # softmax 1 * 1 * 1000 def forward(self, x): # x.size(0)即為batch_size in_size = x.size(0) out = self.conv1_1(x) # 222 out = F.relu(out) out = self.conv1_2(out) # 222 out = F.relu(out) out = self.maxpool1(out) # 112 out = self.conv2_1(out) # 110 out = F.relu(out) out = self.conv2_2(out) # 110 out = F.relu(out) out = self.maxpool2(out) # 56 out = self.conv3_1(out) # 54 out = F.relu(out) out = self.conv3_2(out) # 54 out = F.relu(out) out = self.conv3_3(out) # 54 out = F.relu(out) out = self.maxpool3(out) # 28 out = self.conv4_1(out) # 26 out = F.relu(out) out = self.conv4_2(out) # 26 out = F.relu(out) out = self.conv4_3(out) # 26 out = F.relu(out) out = self.maxpool4(out) # 14 out = self.conv5_1(out) # 12 out = F.relu(out) out = self.conv5_2(out) # 12 out = F.relu(out) out = self.conv5_3(out) # 12 out = F.relu(out) out = self.maxpool5(out) # 7 # 展平 out = out.view(in_size, -1) out = self.fc1(out) out = F.relu(out) out = self.fc2(out) out = F.relu(out) out = self.fc3(out) out = F.log_softmax(out, dim=1) return out
Inception V1
1 版本主要思想詳述
1.1 Inception v1
Inception V1 在ILSVRC 2014的比賽中,以較大優勢取得了第一名,top-5錯誤率6.67%。Inception V1降低參數量的目的有兩點,第一,參數越多模型越龐大,需要供模型學習的數據量就越大,而目前高質量的數據非常昂貴;第二,參數越多,耗費的計算資源也會更大。Inception V1參數少但效果好的原因除了模型層數更深、表達能力更強外,還有兩點:一是去除了最后的全連接層,用全局平均池化層(即將圖片尺寸變為1*1)來取代它(用全局平均池化層取代全連接層的做法借鑒了NetworkI n Network(以下簡稱NIN)論文)。在相同尺寸的感受野中疊加更多的卷積,能提取到更加豐富的特征,也采用了 NIN 中的觀點。
這里對傳統的卷積層結構做個介紹,原理如下所示:
左側是是傳統的卷積層結構(線性卷積),在一個尺度上只有一次卷積;右圖是Network in Network結構(NIN結構),先進行一次普通的卷積(比如3x3),緊跟再進行一次1x1的卷積,對於某個像素點來說1x1卷積等效於該像素點在所有特征上進行一次全連接的計算,所以右側圖的1x1卷積畫成了全連接層的形式,需要注意的是NIN結構中無論是第一個3x3卷積還是新增的1x1卷積,后面都緊跟着激活函數(比如relu)。將兩個卷積串聯,就能組合出更多的非線性特征。舉個例子,假設第1個3x3卷積+激活函數近似於f1(x)=ax2+bx+c,第二個1x1卷積+激活函數近似於f2(x)=mx2+nx+q,那f1(x)和f2(f1(x))比哪個非線性更強,更能模擬非線性的特征?答案是顯而易見的。參數量只有Alexnet的12分之一約500w.
1.1.1 結構原理
Inception架構的主要想法是考慮怎樣近似卷積視覺網絡的最優稀疏結構並用容易獲得的密集組件進行覆蓋。注意假設轉換不變性,這意味着我們的網絡將以卷積構建塊為基礎。我們所需要做的是找到最優的局部構造並在空間上重復它。
為了避免塊校正的問題,目前Inception架構形式的濾波器的尺寸僅限於1×1、3×3、5×5,這個決定更多的是基於便易性而不是必要性。另外,由於池化操作對於目前卷積網絡的成功至關重要,因此建議在每個這樣的階段添加一個替代的並行池化路徑應該也應該具有額外的有益效果。其原理如下圖所示:
第一個分支對輸入進行1*1的卷積,它可以進行跨通道的特征變換,提高網絡的表達能力,同時可以對輸出通道升維和降維;
第二個分支先使用了1*1卷積,然后連接3*3卷積,相當於進行了兩次特征變換;
第三個分支先是1*1的卷積,然后連接5*5卷積;
第四個分支則是3*3最大池化后直接使用1*1卷積;
Inception Module的4個分支在最后通過一個聚合操作合並(在輸出通道數這個維度上聚合)。
其中:
在圖片數據中,天然的就是臨近區域的數據相關性高,因此相鄰的像素點被卷積操作連接在一起。而我們可能有多個卷積核,在同一空間位置但在不同通道的卷積核的輸出結果相關性極高。
1*1的卷積作用:
- 可以進行跨通道的特征變換,把這些相關性很高的、在同一個空間位置但是不同通道的特征連接在一起,提高網絡的表達能力;
- 同時可以對輸出通道升維(拉伸)和降維(壓縮),計算量小。
多尺度卷積再聚合的作用:
- 直觀感覺上在多個尺度上同時進行卷積,能提取到不同尺度的特征。
- 利用稀疏矩陣分解成密集矩陣計算的原理來加快收斂速度。
- Hebbin赫布原理。用在inception結構中就是要把相關性強的特征匯聚到一起。有點像上面提到的這點。
總的來說,Inception Module中包含了3種不同尺寸的卷積和1個最大池化,增加了網絡對不同尺度的適應性,讓網絡的深度和寬度高效率地擴充,提升准確率且不致於過擬合。
1.1.2 網絡結構
Inception Net有22層深,除了最后一層的輸出,其中間節點的分類效果也很好。因此在Inception Net中,還使用到了輔助分類節點(auxiliary classifiers),即將中間某一層的輸出用作分類,並按一個較小的權重(0.3)加到最終分類結果中。這樣相當於做了模型融合,同時給網絡增加了反向傳播的梯度信號,也提供了額外的正則化(實際上這在低級的層級上處理用處不大),對於整個Inception Net的訓練很有裨益。其完整結構如下所示:
在較低的層(靠近輸入的層)中,相關單元更側重提取局部區域的信息。因此使用1x1的特征可以保存這些特征,從而與其他支路提取的特征進行融合。
3x3和5x5的卷積是想要提取不同尺度的特征,3x3卷積和5x5卷積之前的1x1的卷積作用是減少channel,從而降低參數量。
論文中說到之所以使用pooling,是因為pooling操作在目前最好的卷積網絡中是必要的,個人理解是pooling操作可以增強網絡的平移不變性。
GoogLeNet結構(Inception V1)
輸入為224x224的RGB圖像,‘#3x3 reduce’和‘#5x5 reduce’表示3x3和5x5卷積之前1x1的卷積核的個數。
為了阻止該網絡中間部分梯度消失,作者引入了兩個輔助分類器。它們對其中兩個 Inception 模塊的輸出執行 softmax 操作,然后在同樣的標簽上計算輔助損失。總損失即輔助損失和真實損失的加權和。輔助損失只是用於訓練,在推斷過程中並不使用。

1 import torch 2 import torch.nn as nn 3 4 # Inception模塊 5 class Block(nn.Module): 6 def __init__(self, in_channels, out_chanel_1, out_channel_3_reduce, out_channel_3, 7 out_channel_5_reduce, out_channel_5, out_channel_pool): 8 super(Block, self).__init__() 9 10 block = [] 11 self.block1 = nn.Conv2d(in_channels=in_channels, out_channels=out_chanel_1, kernel_size=1) 12 block.append(self.block1) 13 self.block2_1 = nn.Conv2d(in_channels=in_channels, out_channels=out_channel_3_reduce, kernel_size=1) 14 self.block2 = nn.Conv2d(in_channels=out_channel_3_reduce, out_channels=out_channel_3, kernel_size=3, padding=1) 15 block.append(self.block2) 16 self.block3_1 = nn.Conv2d(in_channels=in_channels, out_channels=out_channel_5_reduce, kernel_size=1) 17 self.block3 = nn.Conv2d(in_channels=out_channel_5_reduce, out_channels=out_channel_5, kernel_size=3, padding=1) 18 block.append(self.block3) 19 self.block4_1 = nn.MaxPool2d(kernel_size=3,stride=1,padding=1) 20 self.block4 = nn.Conv2d(in_channels=in_channels, out_channels=out_channel_pool, kernel_size=1) 21 block.append(self.block4) 22 23 # self.incep = nn.Sequential(*block) 24 25 def forward(self, x): 26 out1 = self.block1(x) 27 out2 = self.block2(self.block2_1(x)) 28 out3 = self.block3(self.block3_1(x)) 29 out4 = self.block4(self.block4_1(x)) 30 out = torch.cat([out1, out2, out3, out4], dim=1) 31 print(out.shape) 32 return out 33 34 # 在完整網絡中間某層輸出結果以一定的比例添加到最終結果分類 35 class InceptionClassifiction(nn.Module): 36 def __init__(self, in_channels,out_channels): 37 super(InceptionClassifiction, self).__init__() 38 39 self.avgpool = nn.AvgPool2d(kernel_size=5, stride=3) 40 self.conv1 = nn.Conv2d(in_channels=in_channels, out_channels=128, kernel_size=1) 41 self.linear1 = nn.Linear(in_features=128 * 4 * 4, out_features=1024) 42 self.relu = nn.ReLU(inplace=True) 43 self.dropout = nn.Dropout(p=0.7) 44 self.linear2 = nn.Linear(in_features=1024, out_features=out_channels) 45 46 def forward(self, x): 47 x = self.conv1(self.avgpool(x)) 48 x = x.view(x.size(0), -1) 49 x= self.relu(self.linear1(x)) 50 out = self.linear2(self.dropout(x)) 51 return out 52 53 class InceptionV1(nn.Module): 54 def __init__(self, num_classes=1000, stage='train'): 55 super(InceptionV1, self).__init__() 56 self.stage = stage 57 58 self.blockA = nn.Sequential( 59 nn.Conv2d(in_channels=3,out_channels=64,kernel_size=7,stride=2,padding=3), 60 nn.MaxPool2d(kernel_size=3,stride=2, padding=1), 61 nn.LocalResponseNorm(64), 62 63 ) 64 self.blockB = nn.Sequential( 65 nn.Conv2d(in_channels=64, out_channels=64, kernel_size=1, stride=1), 66 nn.Conv2d(in_channels=64, out_channels=192, kernel_size=3, stride=1, padding=1), 67 nn.LocalResponseNorm(192), 68 nn.MaxPool2d(kernel_size=3, stride=2, padding=1), 69 ) 70 71 self.blockC = nn.Sequential( 72 Block(in_channels=192,out_chanel_1=64, out_channel_3_reduce=96, out_channel_3=128, 73 out_channel_5_reduce = 16, out_channel_5=32, out_channel_pool=32), 74 Block(in_channels=256, out_chanel_1=128, out_channel_3_reduce=128, out_channel_3=192, 75 out_channel_5_reduce=32, out_channel_5=96, out_channel_pool=64), 76 nn.MaxPool2d(kernel_size=3, stride=2, padding=1), 77 ) 78 79 self.blockD_1 = Block(in_channels=480, out_chanel_1=192, out_channel_3_reduce=96, out_channel_3=208, 80 out_channel_5_reduce=16, out_channel_5=48, out_channel_pool=64) 81 82 if self.stage == 'train': 83 self.Classifiction_logits1 = InceptionClassifiction(in_channels=512,out_channels=num_classes) 84 85 self.blockD_2 = nn.Sequential( 86 Block(in_channels=512, out_chanel_1=160, out_channel_3_reduce=112, out_channel_3=224, 87 out_channel_5_reduce=24, out_channel_5=64, out_channel_pool=64), 88 Block(in_channels=512, out_chanel_1=128, out_channel_3_reduce=128, out_channel_3=256, 89 out_channel_5_reduce=24, out_channel_5=64, out_channel_pool=64), 90 Block(in_channels=512, out_chanel_1=112, out_channel_3_reduce=144, out_channel_3=288, 91 out_channel_5_reduce=32, out_channel_5=64, out_channel_pool=64), 92 ) 93 94 if self.stage == 'train': 95 self.Classifiction_logits2 = InceptionClassifiction(in_channels=528,out_channels=num_classes) 96 97 self.blockD_3 = nn.Sequential( 98 Block(in_channels=528, out_chanel_1=256, out_channel_3_reduce=160, out_channel_3=320, 99 out_channel_5_reduce=32, out_channel_5=128, out_channel_pool=128), 100 nn.MaxPool2d(kernel_size=3, stride=2, padding=1), 101 ) 102 103 self.blockE = nn.Sequential( 104 Block(in_channels=832, out_chanel_1=256, out_channel_3_reduce=160, out_channel_3=320, 105 out_channel_5_reduce=32, out_channel_5=128, out_channel_pool=128), 106 Block(in_channels=832, out_chanel_1=384, out_channel_3_reduce=192, out_channel_3=384, 107 out_channel_5_reduce=48, out_channel_5=128, out_channel_pool=128), 108 ) 109 110 self.avgpool = nn.AvgPool2d(kernel_size=7,stride=1) 111 self.dropout = nn.Dropout(p=0.4) 112 self.linear = nn.Linear(in_features=1024,out_features=num_classes) 113 114 def forward(self, x): 115 x = self.blockA(x) 116 x = self.blockB(x) 117 x = self.blockC(x) 118 Classifiction1 = x = self.blockD_1(x) 119 Classifiction2 = x = self.blockD_2(x) 120 x = self.blockD_3(x) 121 out = self.blockE(x) 122 out = self.avgpool(out) 123 out = self.dropout(out) 124 out = out.view(out.size(0), -1) 125 out = self.linear(out) 126 if self.stage == 'train': 127 Classifiction1 = self.Classifiction_logits1(Classifiction1) 128 Classifiction2 = self.Classifiction_logits2(Classifiction2) 129 return Classifiction1, Classifiction2, out 130 else: 131 return out 132 133 134 model = InceptionV1() 135 print(model) 136 137 input = torch.randn(8, 3, 224, 224) 138 Classifiction1, Classifiction2, out = model(input)