訂閱
糾錯(cuò)
加入自媒體

用 Python 從零開始構(gòu)建 Inception Network

介紹

隨著越來越多的高效體系結(jié)構(gòu)出現(xiàn)在世界各地的研究論文中,深度學(xué)習(xí)體系結(jié)構(gòu)正在迅速發(fā)展。這些研究論文不僅包含了大量的信息,而且為新的深度學(xué)習(xí)體系結(jié)構(gòu)的誕生提供了一條新的途徑,它們通常難以解析。為了理解這些論文,人們可能需要多次閱讀那篇論文,甚至可能需要閱讀其他相關(guān)論文。Inception 就是其中之一。

Inception 網(wǎng)絡(luò)是 CNN 圖像分類器發(fā)展過程中的一個(gè)重要里程碑。在此架構(gòu)之前,大多數(shù)流行的 CNN 或分類器只是使用越來越深的堆疊卷積層以獲得更好的性能。

另一方面,Inception 網(wǎng)絡(luò)經(jīng)過精心設(shè)計(jì),非常深入和復(fù)雜。它使用了許多不同的技術(shù)來推動(dòng)其性能;無論是速度還是準(zhǔn)確性。

什么是Inception?

Inception Network(ResNet)是Christian Szegedy、Wei Liu、Yangqing Jia介紹的著名深度學(xué)習(xí)模型之一。Pierre Sermanet、Scott Reed、Dragomir Anguelov、Dumitru Erhan、Vincent Vanhoucke 和 Andrew Rabinovich在 2014 年的論文“Going deeper with convolutions” [1]中。

后來演化出了不同版本的 Inception 網(wǎng)絡(luò)。這是 Sergey Ioffe、Christian Szegedy、Jonathon Shlens、Vincent Vanhouck 和 Zbigniew Wojna在 2015 年題為“Rethinking the Inception Architecture for Computer Vision” [2] 的論文中提出的。Inception模型被歸類為最受歡迎和最常用的深度學(xué)習(xí)模型之一。

設(shè)計(jì)原則

–少數(shù)通用設(shè)計(jì)原則和優(yōu)化技術(shù)的提議被證明對有效地?cái)U(kuò)展卷積網(wǎng)絡(luò)很有用。

–在網(wǎng)絡(luò)體系結(jié)構(gòu)的早期,避免代表性瓶頸。

–如果網(wǎng)絡(luò)具有更多不同的過濾器,這些過濾器將具有更多不同的特征圖,則網(wǎng)絡(luò)將學(xué)習(xí)得更快。

–降維的空間聚合可以在低維嵌入上完成,而不會(huì)損失太多表示能力。

–通過寬度和深度之間的平衡,可以實(shí)現(xiàn)網(wǎng)絡(luò)的最佳性能。

初始模塊

初始模塊(naive)

資料來源:'Going Deeper with Convolution ' 論文

最優(yōu)局部稀疏結(jié)構(gòu)的近似

處理各種尺度的視覺/空間信息,然后聚合

從計(jì)算上看,這有點(diǎn)樂觀

5×5 卷積非;ㄙM(fèi)開銷

Inception 模塊(降維)

來源:'Going Deeper with Convolution' 論文

降維是必要和有動(dòng)力的(網(wǎng)絡(luò)中的網(wǎng)絡(luò))

通過 1×1 卷積實(shí)現(xiàn)

深入思考學(xué)習(xí)池化,而不是高度/寬度的最大/平均池化。

初始架構(gòu)

使用降維的inception模塊,構(gòu)建了深度神經(jīng)網(wǎng)絡(luò)架構(gòu)(Inception v1)。架構(gòu)如下圖所示:

Inception 網(wǎng)絡(luò)線性堆疊了 9 個(gè)這樣的 Inception 模塊。它有 22 層深(如果包括池化層,則為 27 層)。在最后一個(gè) inception 模塊的最后,它使用了全局平均池化。

對于降維和修正線性激活,使用了 128 個(gè)濾波器的 1×1 卷積。

具有 1024 個(gè)單元的全連接層的修正線性激活。

使用 dropout 層丟棄輸出的比例為 70%。

使用線性層作為分類器的 softmax 損失。

Inception 網(wǎng)絡(luò)的流行版本如下:

Inception v1

Inception v2

Inception v3

Inception v4

Inception-ResNet

讓我們從頭開始構(gòu)建 Inception v1(GoogLeNet):

Inception 架構(gòu)多次使用 CNN 塊和 1×1、3×3、5×5 等不同的過濾器,所以讓我們?yōu)?CNN 塊創(chuàng)建一個(gè)類,它采用輸入通道和輸出通道以及 batchnorm2d 和 ReLu 激活.

class conv_block(nn.Module):
   def __init__(self, in_channels, out_channels, **kwargs):
       super(conv_block, self).__init__()
       self.relu = nn.ReLU()
       self.conv = nn.Conv2d(in_channels, out_channels, **kwargs)
       self.batchnorm = nn.BatchNorm2d(out_channels)
  def forward(self, x):
      return self.relu(self.batchnorm(self.conv(x)))

然后為inception module創(chuàng)建一個(gè)降維的類,參考上圖,從1×1 filter輸出,reduction 3×3,然后從3×3 filter輸出,reduction 5×5,然后從5×5輸出 和 1×1 池中輸出。

class Inception_block(nn.Module):
   def __init__(
       self, in_channels, out_1x1, red_3x3, out_3x3, red_5x5, out_5x5, out_1x1pool
   ):
       super(Inception_block, self).__init__()
       self.branch1 = conv_block(in_channels, out_1x1, kernel_size=(1, 1))
self.branch2 = nn.Sequential(
conv_block(in_channels, red_3x3, kernel_size=(1, 1)),
conv_block(red_3x3, out_3x3, kernel_size=(3, 3), padding=(1, 1)),

self.branch3 = nn.Sequential(
conv_block(in_channels, red_5x5, kernel_size=(1, 1)),
conv_block(red_5x5, out_5x5, kernel_size=(5, 5), padding=(2, 2)),

self.branch4 = nn.Sequential(
nn.MaxPool2d(kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),
conv_block(in_channels, out_1x1pool, kernel_size=(1, 1)),

def forward(self, x):
return torch.cat(
[self.branch1(x), self.branch2(x), self.branch3(x), self.branch4(x)], 1

讓我們保留下圖作為參考并開始構(gòu)建網(wǎng)絡(luò)。

來源:'Going Deeper with Convolution' 論文

創(chuàng)建一個(gè)類作為 GoogLeNet

class GoogLeNet(nn.Module):
   def __init__(self, aux_logits=True, num_classes=1000):
       super(GoogLeNet, self).__init__()
       assert aux_logits == True or aux_logits == False
       self.a(chǎn)ux_logits = aux_logits
# Write in_channels, etc, all explicit in self.conv1, rest will write to
# make everything as compact as possible, kernel_size=3 instead of (3,3)
self.conv1 = conv_block(
in_channels=3,
out_channels=64,
kernel_size=(7, 7),
stride=(2, 2),
padding=(3, 3),

self.maxpool1 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
self.conv2 = conv_block(64, 192, kernel_size=3, stride=1, padding=1)
self.maxpool2 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
# In this order: in_channels, out_1x1, red_3x3, out_3x3, red_5x5, out_5x5, out_1x1pool
self.inception3a = Inception_block(192, 64, 96, 128, 16, 32, 32)
self.inception3b = Inception_block(256, 128, 128, 192, 32, 96, 64)
self.maxpool3 = nn.MaxPool2d(kernel_size=(3, 3), stride=2, padding=1)
self.inception4a = Inception_block(480, 192, 96, 208, 16, 48, 64)
self.inception4b = Inception_block(512, 160, 112, 224, 24, 64, 64)
self.inception4c = Inception_block(512, 128, 128, 256, 24, 64, 64)
self.inception4d = Inception_block(512, 112, 144, 288, 32, 64, 64)
self.inception4e = Inception_block(528, 256, 160, 320, 32, 128, 128)
self.maxpool4 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
self.inception5a = Inception_block(832, 256, 160, 320, 32, 128, 128)
self.inception5b = Inception_block(832, 384, 192, 384, 48, 128, 128)
self.a(chǎn)vgpool = nn.AvgPool2d(kernel_size=7, stride=1)
self.dropout = nn.Dropout(p=0.4)
self.fc1 = nn.Linear(1024, num_classes)
if self.a(chǎn)ux_logits:
self.a(chǎn)ux1 = InceptionAux(512, num_classes)
self.a(chǎn)ux2 = InceptionAux(528, num_classes)
else:
self.a(chǎn)ux1 = self.a(chǎn)ux2 = None
def forward(self, x):
x = self.conv1(x)
x = self.maxpool1(x)
x = self.conv2(x)
# x = self.conv3(x)
x = self.maxpool2(x)
x = self.inception3a(x)
x = self.inception3b(x)
x = self.maxpool3(x)
x = self.inception4a(x)
# Auxiliary Softmax classifier 1
if self.a(chǎn)ux_logits and self.training:
aux1 = self.a(chǎn)ux1(x)
x = self.inception4b(x)
x = self.inception4c(x)
x = self.inception4d(x)
# Auxiliary Softmax classifier 2
if self.a(chǎn)ux_logits and self.training:
aux2 = self.a(chǎn)ux2(x)
x = self.inception4e(x)
x = self.maxpool4(x)
x = self.inception5a(x)
x = self.inception5b(x)
x = self.a(chǎn)vgpool(x)
x = x.reshape(x.shape[0], -1)
x = self.dropout(x)
x = self.fc1(x)
if self.a(chǎn)ux_logits and self.training:
return aux1, aux2, x
else:
return x

然后為輸出層定義一個(gè)類,如論文中提到的 dropout=0.7 和一個(gè)帶有 softmax 的線性層來輸出 n_classes。

class InceptionAux(nn.Module):
   def __init__(self, in_channels, num_classes):
       super(InceptionAux, self).__init__()
       self.relu = nn.ReLU()
       self.dropout = nn.Dropout(p=0.7)
       self.pool = nn.AvgPool2d(kernel_size=5, stride=3)
       self.conv = conv_block(in_channels, 128, kernel_size=1)
       self.fc1 = nn.Linear(2048, 1024)
       self.fc2 = nn.Linear(1024, num_classes)

   def forward(self, x):
       x = self.pool(x)
       x = self.conv(x)
       x = x.reshape(x.shape[0], -1)
       x = self.relu(self.fc1(x))
       x = self.dropout(x)
       x = self.fc2(x)
       return x

然后程序應(yīng)該如下所示對齊。

– Class GoogLeNet

– Class Inception_block

– Class InceptionAux

– Class conv_block

然后最后讓我們寫一小段測試代碼來檢查我們的模型是否工作正常。

if __name__ == "__main__":
   # N = 3 (Mini batch size)
   x = torch.randn(3, 3, 224, 224)
   model = GoogLeNet(aux_logits=True, num_classes=1000)
   print(model(x)[2].shape)

輸出應(yīng)如下所示

聲明: 本文由入駐維科號(hào)的作者撰寫,觀點(diǎn)僅代表作者本人,不代表OFweek立場。如有侵權(quán)或其他問題,請聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請輸入評(píng)論內(nèi)容...

請輸入評(píng)論/評(píng)論長度6~500個(gè)字

您提交的評(píng)論過于頻繁,請輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無評(píng)論

暫無評(píng)論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號(hào)
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯(cuò)
x
*文字標(biāo)題:
*糾錯(cuò)內(nèi)容:
聯(lián)系郵箱:
*驗(yàn) 證 碼:

粵公網(wǎng)安備 44030502002758號(hào)