深度學(xué)習(xí)應(yīng)用篇-計算機(jī)視覺-圖像分類[2]:LeNet、AlexNet、VGG、GoogleNet、DarkNet模型結(jié)構(gòu)、實(shí)現(xiàn)、模型特點(diǎn)詳細(xì)介紹
1.LeNet(1998)
LeNet是最早的卷積神經(jīng)網(wǎng)絡(luò)之一[1],其被提出用于識別手寫數(shù)字和機(jī)器印刷字符。1998年,Yann LeCun第一次將LeNet卷積神經(jīng)網(wǎng)絡(luò)應(yīng)用到圖像分類上,在手寫數(shù)字識別任務(wù)中取得了巨大成功。算法中闡述了圖像中像素特征之間的相關(guān)性能夠由參數(shù)共享的卷積操作所提取,同時使用卷積、下采樣(池化)和非線性映射這樣的組合結(jié)構(gòu),是當(dāng)前流行的大多數(shù)深度圖像識別網(wǎng)絡(luò)的基礎(chǔ)。
1.1 LeNet模型結(jié)構(gòu)
LeNet通過連續(xù)使用卷積和池化層的組合提取圖像特征,其架構(gòu)如 圖1 所示,這里展示的是用于MNIST手寫體數(shù)字識別任務(wù)中的LeNet-5模型:
-
第一模塊:包含5×5的6通道卷積和2×2的池化。卷積提取圖像中包含的特征模式(激活函數(shù)使用Sigmoid),圖像尺寸從28減小到24。經(jīng)過池化層可以降低輸出特征圖對空間位置的敏感性,圖像尺寸減到12。
-
第二模塊:和第一模塊尺寸相同,通道數(shù)由6增加為16。卷積操作使圖像尺寸減小到8,經(jīng)過池化后變成4。
-
第三模塊:包含4×4的120通道卷積。卷積之后的圖像尺寸減小到1,但是通道數(shù)增加為120。將經(jīng)過第3次卷積提取到的特征圖輸入到全連接層。第一個全連接層的輸出神經(jīng)元的個數(shù)是64,第二個全連接層的輸出神經(jīng)元個數(shù)是分類標(biāo)簽的類別數(shù),對于手寫數(shù)字識別的類別數(shù)是10。然后使用Softmax激活函數(shù)即可計算出每個類別的預(yù)測概率。
提示:
卷積層的輸出特征圖如何當(dāng)作全連接層的輸入使用呢?
卷積層的輸出數(shù)據(jù)格式是$[N, C, H, W]$,在輸入全連接層的時候,會自動將數(shù)據(jù)拉平,
也就是對每個樣本,自動將其轉(zhuǎn)化為長度為$K$的向量,
其中$K = C \times H \times W$,一個mini-batch的數(shù)據(jù)維度變成了$N\times K$的二維向量。
1.2 LeNet模型實(shí)現(xiàn)
LeNet網(wǎng)絡(luò)的實(shí)現(xiàn)代碼如下:
#導(dǎo)入需要的包
import paddle
import numpy as np
from paddle.nn import Conv2D, MaxPool2D, Linear
##組網(wǎng)
import paddle.nn.functional as F
#定義 LeNet 網(wǎng)絡(luò)結(jié)構(gòu)
class LeNet(paddle.nn.Layer):
def __init__(self, num_classes=1):
super(LeNet, self).__init__()
# 創(chuàng)建卷積和池化層
# 創(chuàng)建第1個卷積層
self.conv1 = Conv2D(in_channels=1, out_channels=6, kernel_size=5)
self.max_pool1 = MaxPool2D(kernel_size=2, stride=2)
# 尺寸的邏輯:池化層未改變通道數(shù);當(dāng)前通道數(shù)為6
# 創(chuàng)建第2個卷積層
self.conv2 = Conv2D(in_channels=6, out_channels=16, kernel_size=5)
self.max_pool2 = MaxPool2D(kernel_size=2, stride=2)
# 創(chuàng)建第3個卷積層
self.conv3 = Conv2D(in_channels=16, out_channels=120, kernel_size=4)
# 尺寸的邏輯:輸入層將數(shù)據(jù)拉平[B,C,H,W] -> [B,C*H*W]
# 輸入size是[28,28],經(jīng)過三次卷積和兩次池化之后,C*H*W等于120
self.fc1 = Linear(in_features=120, out_features=64)
# 創(chuàng)建全連接層,第一個全連接層的輸出神經(jīng)元個數(shù)為64, 第二個全連接層輸出神經(jīng)元個數(shù)為分類標(biāo)簽的類別數(shù)
self.fc2 = Linear(in_features=64, out_features=num_classes)
#網(wǎng)絡(luò)的前向計算過程
def forward(self, x):
x = self.conv1(x)
# 每個卷積層使用Sigmoid激活函數(shù),后面跟著一個2x2的池化
x = F.sigmoid(x)
x = self.max_pool1(x)
x = F.sigmoid(x)
x = self.conv2(x)
x = self.max_pool2(x)
x = self.conv3(x)
#尺寸的邏輯:輸入層將數(shù)據(jù)拉平[B,C,H,W] -> [B,C*H*W]
x = paddle.reshape(x, [x.shape[0], -1])
x = self.fc1(x)
x = F.sigmoid(x)
x = self.fc2(x)
return x
1.3 LeNet模型特點(diǎn)
- 卷積網(wǎng)絡(luò)使用一個3層的序列組合:卷積、下采樣(池化)、非線性映射(LeNet-5最重要的特性,奠定了目前深層卷積網(wǎng)絡(luò)的基礎(chǔ));
- 使用卷積提取空間特征;
- 使用映射的空間均值進(jìn)行下采樣;
- 使用$tanh$或$sigmoid$進(jìn)行非線性映射;
- 多層神經(jīng)網(wǎng)絡(luò)(MLP)作為最終的分類器;
- 層間的稀疏連接矩陣以避免巨大的計算開銷。
1.4 LeNet模型指標(biāo)
LeNet-5在MNIST手寫數(shù)字識別任務(wù)上進(jìn)行了模型訓(xùn)練與測試,論文中提供的模型指標(biāo)如 圖2 所示。使用 distortions 方法處理后,error rate能夠達(dá)到0.8%。
- 參考文獻(xiàn)
[1] Gradient-based learn- ing applied to document recognition.
2.AlexNet(2012)
AlexNet[1]是2012年ImageNet競賽的冠軍模型,其作者是神經(jīng)網(wǎng)絡(luò)領(lǐng)域三巨頭之一的Hinton和他的學(xué)生Alex Krizhevsky。
AlexNet以極大的優(yōu)勢領(lǐng)先2012年ImageNet競賽的第二名,也因此給當(dāng)時的學(xué)術(shù)界和工業(yè)界帶來了很大的沖擊。此后,更多更深的神經(jīng)網(wǎng)絡(luò)相繼被提出,比如優(yōu)秀的VGG,GoogLeNet,ResNet等。
2.1 AlexNet模型結(jié)構(gòu)
AlexNet與此前的LeNet相比,具有更深的網(wǎng)絡(luò)結(jié)構(gòu),包含5層卷積和3層全連接,具體結(jié)構(gòu)如 圖1 所示。
1)第一模塊:對于$224\times 224$的彩色圖像,先用96個$11\times 11\times 3$的卷積核對其進(jìn)行卷積,提取圖像中包含的特征模式(步長為4,填充為2,得到96個$54\times 54$的卷積結(jié)果(特征圖);然后以$2\times 2$大小進(jìn)行池化,得到了96個$27\times 27$大小的特征圖;
2)第二模塊:包含256個$5\times 5$的卷積和$2\times 2$池化,卷積操作后圖像尺寸不變,經(jīng)過池化后,圖像尺寸變成$13\times 13$;
3)第三模塊:包含384個$3\times 3$的卷積,卷積操作后圖像尺寸不變;
4)第四模塊:包含384個$3\times 3$的卷積,卷積操作后圖像尺寸不變;
5)第五模塊:包含256個$3\times 3$的卷積和$2\times 2$的池化,卷積操作后圖像尺寸不變,經(jīng)過池化后變成256個$6\times 6$大小的特征圖。
將經(jīng)過第5次卷積提取到的特征圖輸入到全連接層,得到原始圖像的向量表達(dá)。前兩個全連接層的輸出神經(jīng)元的個數(shù)是4096,第三個全連接層的輸出神經(jīng)元個數(shù)是分類標(biāo)簽的類別數(shù)(ImageNet比賽的分類類別數(shù)是1000),然后使用Softmax激活函數(shù)即可計算出每個類別的預(yù)測概率。
2.2 AlexNet模型實(shí)現(xiàn)
基于Paddle框架,AlexNet的具體實(shí)現(xiàn)的代碼如下所示:
#-*- coding:utf-8 -*-
#導(dǎo)入需要的包
import paddle
import numpy as np
from paddle.nn import Conv2D, MaxPool2D, Linear, Dropout
##組網(wǎng)
import paddle.nn.functional as F
#定義 AlexNet 網(wǎng)絡(luò)結(jié)構(gòu)
class AlexNet(paddle.nn.Layer):
def __init__(self, num_classes=1):
super(AlexNet, self).__init__()
# AlexNet與LeNet一樣也會同時使用卷積和池化層提取圖像特征
# 與LeNet不同的是激活函數(shù)換成了‘relu’
self.conv1 = Conv2D(in_channels=3, out_channels=96, kernel_size=11, stride=4, padding=5)
self.max_pool1 = MaxPool2D(kernel_size=2, stride=2)
self.conv2 = Conv2D(in_channels=96, out_channels=256, kernel_size=5, stride=1, padding=2)
self.max_pool2 = MaxPool2D(kernel_size=2, stride=2)
self.conv3 = Conv2D(in_channels=256, out_channels=384, kernel_size=3, stride=1, padding=1)
self.conv4 = Conv2D(in_channels=384, out_channels=384, kernel_size=3, stride=1, padding=1)
self.conv5 = Conv2D(in_channels=384, out_channels=256, kernel_size=3, stride=1, padding=1)
self.max_pool5 = MaxPool2D(kernel_size=2, stride=2)
self.fc1 = Linear(in_features=12544, out_features=4096)
self.drop_ratio1 = 0.5
self.drop1 = Dropout(self.drop_ratio1)
self.fc2 = Linear(in_features=4096, out_features=4096)
self.drop_ratio2 = 0.5
self.drop2 = Dropout(self.drop_ratio2)
self.fc3 = Linear(in_features=4096, out_features=num_classes)
def forward(self, x):
x = self.conv1(x)
x = F.relu(x)
x = self.max_pool1(x)
x = self.conv2(x)
x = F.relu(x)
x = self.max_pool2(x)
x = self.conv3(x)
x = F.relu(x)
x = self.conv4(x)
x = F.relu(x)
x = self.conv5(x)
x = F.relu(x)
x = self.max_pool5(x)
x = paddle.reshape(x, [x.shape[0], -1])
x = self.fc1(x)
x = F.relu(x)
# 在全連接之后使用dropout抑制過擬合
x = self.drop1(x)
x = self.fc2(x)
x = F.relu(x)
# 在全連接之后使用dropout抑制過擬合
x = self.drop2(x)
x = self.fc3(x)
return x
2.3 AlexNet模型特點(diǎn)
AlexNet中包含了幾個比較新的技術(shù)點(diǎn),也首次在CNN中成功應(yīng)用了ReLU、Dropout和LRN等Trick。同時AlexNet也使用了GPU進(jìn)行運(yùn)算加速。
AlexNet將LeNet的思想發(fā)揚(yáng)光大,把CNN的基本原理應(yīng)用到了很深很寬的網(wǎng)絡(luò)中。AlexNet主要使用到的新技術(shù)點(diǎn)如下:
- 成功使用ReLU作為CNN的激活函數(shù),并驗(yàn)證其效果在較深的網(wǎng)絡(luò)超過了Sigmoid,成功解決了Sigmoid在網(wǎng)絡(luò)較深時的梯度彌散問題。雖然ReLU激活函數(shù)在很久之前就被提出了,但是直到AlexNet的出現(xiàn)才將其發(fā)揚(yáng)光大。
- 訓(xùn)練時使用Dropout隨機(jī)忽略一部分神經(jīng)元,以避免模型過擬合。Dropout雖有單獨(dú)的論文論述,但是AlexNet將其實(shí)用化,通過實(shí)踐證實(shí)了它的效果。在AlexNet中主要是最后幾個全連接層使用了Dropout。
- 在CNN中使用重疊的最大池化。此前CNN中普遍使用平均池化,AlexNet全部使用最大池化,避免平均池化的模糊化效果。并且AlexNet中提出讓步長比池化核的尺寸小的觀點(diǎn),這樣池化層的輸出之間會有重疊和覆蓋,提升了特征的豐富性。
- 提出了LRN局部響應(yīng)歸一化層,對局部神經(jīng)元的活動創(chuàng)建競爭機(jī)制,使得其中響應(yīng)比較大的值變得相對更大,并抑制其他反饋較小的神經(jīng)元,增強(qiáng)了模型的泛化能力。
- 使用CUDA加速深度卷積網(wǎng)絡(luò)的訓(xùn)練,利用GPU強(qiáng)大的并行計算能力,處理神經(jīng)網(wǎng)絡(luò)訓(xùn)練時大量的矩陣運(yùn)算。AlexNet使用了兩塊GTX?580?GPU進(jìn)行訓(xùn)練,單個GTX?580只有3GB顯存,這限制了可訓(xùn)練的網(wǎng)絡(luò)的最大規(guī)模。因此作者將AlexNet分布在兩個GPU上,在每個GPU的顯存中儲存一半的神經(jīng)元的參數(shù)。因?yàn)镚PU之間通信方便,可以互相訪問顯存,而不需要通過主機(jī)內(nèi)存,所以同時使用多塊GPU也是非常高效的。同時,AlexNet的設(shè)計讓GPU之間的通信只在網(wǎng)絡(luò)的某些層進(jìn)行,控制了通信的性能損耗。
- 使用數(shù)據(jù)增強(qiáng),隨機(jī)地從$256\times 256$ 大小的原始圖像中截取$224\times 224$大小的區(qū)域(以及水平翻轉(zhuǎn)的鏡像),相當(dāng)于增加了$2\times (256-224)^2=2048$倍的數(shù)據(jù)量。如果沒有數(shù)據(jù)增強(qiáng),僅靠原始的數(shù)據(jù)量,參數(shù)眾多的CNN會陷入過擬合中,使用了數(shù)據(jù)增強(qiáng)后可以大大減輕過擬合,提升泛化能力。進(jìn)行預(yù)測時,則是取圖片的四個角加中間共5個位置,并進(jìn)行左右翻轉(zhuǎn),一共獲得10張圖片,對他們進(jìn)行預(yù)測并對10次結(jié)果求均值。同時,AlexNet論文中提到了會對圖像的RGB數(shù)據(jù)進(jìn)行PCA處理,并對主成分做一個標(biāo)準(zhǔn)差為0.1的高斯擾動,增加一些噪聲,這個Trick可以讓錯誤率再下降1%。
2.4 AlexNet模型指標(biāo)
AlexNet 作為 ImageNet 2012比賽的冠軍算法,在 ImageNet 測試集上達(dá)到了 15.3% 的 top-5 error rate,遠(yuǎn)遠(yuǎn)超過第二名(SIFT+FVs)的 26.2% 。如 圖2 所示。
- 參考文獻(xiàn)
[1] Imagenet classification with deep convolutional neural networks.
3.VGG(2012)
隨著AlexNet在2012年的ImageNet大賽上大放異彩后,卷積神經(jīng)網(wǎng)絡(luò)進(jìn)入了飛速發(fā)展的階段。2014年,由Simonyan和Zisserman提出的VGG[1]網(wǎng)絡(luò)在ImageNet上取得了亞軍的成績。VGG的命名來源于論文作者所在的實(shí)驗(yàn)室Visual Geometry Group,其對卷積神經(jīng)網(wǎng)絡(luò)進(jìn)行了改良,探索了網(wǎng)絡(luò)深度與性能的關(guān)系,用更小的卷積核和更深的網(wǎng)絡(luò)結(jié)構(gòu),取得了較好的效果,成為了CNN發(fā)展史上較為重要的一個網(wǎng)絡(luò)。VGG中使用了一系列大小為3x3的小尺寸卷積核和池化層構(gòu)造深度卷積神經(jīng)網(wǎng)絡(luò),因?yàn)槠浣Y(jié)構(gòu)簡單、應(yīng)用性極強(qiáng)而廣受研究者歡迎,尤其是它的網(wǎng)絡(luò)結(jié)構(gòu)設(shè)計方法,為構(gòu)建深度神經(jīng)網(wǎng)絡(luò)提供了方向。
3.1 VGG模型結(jié)構(gòu)
圖1 是VGG-16的網(wǎng)絡(luò)結(jié)構(gòu)示意圖,有13層卷積和3層全連接層。VGG網(wǎng)絡(luò)的設(shè)計嚴(yán)格使用$3\times 3$的卷積層和池化層來提取特征,并在網(wǎng)絡(luò)的最后面使用三層全連接層,將最后一層全連接層的輸出作為分類的預(yù)測。
VGG中還有一個顯著特點(diǎn):每次經(jīng)過池化層(maxpooling)后特征圖的尺寸減小一倍,而通道數(shù)增加一倍(最后一個池化層除外)。
在VGG中每層卷積將使用ReLU作為激活函數(shù),在全連接層之后添加dropout來抑制過擬合。使用小的卷積核能夠有效地減少參數(shù)的個數(shù),使得訓(xùn)練和測試變得更加有效。比如使用兩層$3\times 3$ 卷積層,可以得到感受野為5的特征圖,而比使用$5 \times 5$的卷積層需要更少的參數(shù)。由于卷積核比較小,可以堆疊更多的卷積層,加深網(wǎng)絡(luò)的深度,這對于圖像分類任務(wù)來說是有利的。VGG模型的成功證明了增加網(wǎng)絡(luò)的深度,可以更好的學(xué)習(xí)圖像中的特征模式。
3.2 VGG模型實(shí)現(xiàn)
基于Paddle框架,VGG的具體實(shí)現(xiàn)如下代碼所示:
#-*- coding:utf-8 -*-
#VGG模型代碼
import numpy as np
import paddle
#from paddle.nn import Conv2D, MaxPool2D, BatchNorm, Linear
from paddle.nn import Conv2D, MaxPool2D, BatchNorm2D, Linear
#定義vgg網(wǎng)絡(luò)
class VGG(paddle.nn.Layer):
def __init__(self):
super(VGG, self).__init__()
in_channels = [3, 64, 128, 256, 512, 512]
# 定義第一個卷積塊,包含兩個卷積
self.conv1_1 = Conv2D(in_channels=in_channels[0], out_channels=in_channels[1], kernel_size=3, padding=1, stride=1)
self.conv1_2 = Conv2D(in_channels=in_channels[1], out_channels=in_channels[1], kernel_size=3, padding=1, stride=1)
# 定義第二個卷積塊,包含兩個卷積
self.conv2_1 = Conv2D(in_channels=in_channels[1], out_channels=in_channels[2], kernel_size=3, padding=1, stride=1)
self.conv2_2 = Conv2D(in_channels=in_channels[2], out_channels=in_channels[2], kernel_size=3, padding=1, stride=1)
# 定義第三個卷積塊,包含三個卷積
self.conv3_1 = Conv2D(in_channels=in_channels[2], out_channels=in_channels[3], kernel_size=3, padding=1, stride=1)
self.conv3_2 = Conv2D(in_channels=in_channels[3], out_channels=in_channels[3], kernel_size=3, padding=1, stride=1)
self.conv3_3 = Conv2D(in_channels=in_channels[3], out_channels=in_channels[3], kernel_size=3, padding=1, stride=1)
# 定義第四個卷積塊,包含三個卷積
self.conv4_1 = Conv2D(in_channels=in_channels[3], out_channels=in_channels[4], kernel_size=3, padding=1, stride=1)
self.conv4_2 = Conv2D(in_channels=in_channels[4], out_channels=in_channels[4], kernel_size=3, padding=1, stride=1)
self.conv4_3 = Conv2D(in_channels=in_channels[4], out_channels=in_channels[4], kernel_size=3, padding=1, stride=1)
# 定義第五個卷積塊,包含三個卷積
self.conv5_1 = Conv2D(in_channels=in_channels[4], out_channels=in_channels[5], kernel_size=3, padding=1, stride=1)
self.conv5_2 = Conv2D(in_channels=in_channels[5], out_channels=in_channels[5], kernel_size=3, padding=1, stride=1)
self.conv5_3 = Conv2D(in_channels=in_channels[5], out_channels=in_channels[5], kernel_size=3, padding=1, stride=1)
# 使用Sequential 將全連接層和relu組成一個線性結(jié)構(gòu)(fc + relu)
# 當(dāng)輸入為224x224時,經(jīng)過五個卷積塊和池化層后,特征維度變?yōu)閇512x7x7]
self.fc1 = paddle.nn.Sequential(paddle.nn.Linear(512 * 7 * 7, 4096), paddle.nn.ReLU())
self.drop1_ratio = 0.5
self.dropout1 = paddle.nn.Dropout(self.drop1_ratio, mode='upscale_in_train')
# 使用Sequential 將全連接層和relu組成一個線性結(jié)構(gòu)(fc + relu)
self.fc2 = paddle.nn.Sequential(paddle.nn.Linear(4096, 4096), paddle.nn.ReLU())
self.drop2_ratio = 0.5
self.dropout2 = paddle.nn.Dropout(self.drop2_ratio, mode='upscale_in_train')
self.fc3 = paddle.nn.Linear(4096, 1)
self.relu = paddle.nn.ReLU()
self.pool = MaxPool2D(stride=2, kernel_size=2)
def forward(self, x):
x = self.relu(self.conv1_1(x))
x = self.relu(self.conv1_2(x))
x = self.pool(x)
x = self.relu(self.conv2_1(x))
x = self.relu(self.conv2_2(x))
x = self.pool(x)
x = self.relu(self.conv3_1(x))
x = self.relu(self.conv3_2(x))
x = self.relu(self.conv3_3(x))
x = self.pool(x)
x = self.relu(self.conv4_1(x))
x = self.relu(self.conv4_2(x))
x = self.relu(self.conv4_3(x))
x = self.pool(x)
x = self.relu(self.conv5_1(x))
x = self.relu(self.conv5_2(x))
x = self.relu(self.conv5_3(x))
x = self.pool(x)
x = paddle.flatten(x, 1, -1)
x = self.dropout1(self.relu(self.fc1(x)))
x = self.dropout2(self.relu(self.fc2(x)))
x = self.fc3(x)
return x
3.3 VGG模型特點(diǎn)
- 整個網(wǎng)絡(luò)都使用了同樣大小的卷積核尺寸$3\times3$和最大池化尺寸$2\times2$。
- $1\times1$卷積的意義主要在于線性變換,而輸入通道數(shù)和輸出通道數(shù)不變,沒有發(fā)生降維。
- 兩個$3\times3$的卷積層串聯(lián)相當(dāng)于1個$5\times5$的卷積層,感受野大小為$5\times5$。同樣地,3個$3\times3$的卷積層串聯(lián)的效果則相當(dāng)于1個$7\times7$的卷積層。這樣的連接方式使得網(wǎng)絡(luò)參數(shù)量更小,而且多層的激活函數(shù)令網(wǎng)絡(luò)對特征的學(xué)習(xí)能力更強(qiáng)。
- VGGNet在訓(xùn)練時有一個小技巧,先訓(xùn)練淺層的的簡單網(wǎng)絡(luò)VGG11,再復(fù)用VGG11的權(quán)重來初始化VGG13,如此反復(fù)訓(xùn)練并初始化VGG19,能夠使訓(xùn)練時收斂的速度更快。
- 在訓(xùn)練過程中使用多尺度的變換對原始數(shù)據(jù)做數(shù)據(jù)增強(qiáng),使得模型不易過擬合。
3.4 VGG模型指標(biāo)
VGG 在 2014 年的 ImageNet 比賽上取得了亞軍的好成績,具體指標(biāo)如 圖2 所示。圖2 第一行為在 ImageNet 比賽中的指標(biāo),測試集的Error rate達(dá)到了7.3%,在論文中,作者對算法又進(jìn)行了一定的優(yōu)化,最終可以達(dá)到 6.8% 的Error rate。
- 參考文獻(xiàn)
[1] Very deep convolutional networks for large-scale image recognition.
4.GoogLeNet(2014)
GoogLeNet[1]是2014年ImageNet比賽的冠軍,它的主要特點(diǎn)是網(wǎng)絡(luò)不僅有深度,還在橫向上具有“寬度”。從名字GoogLeNet可以知道這是來自谷歌工程師所設(shè)計的網(wǎng)絡(luò)結(jié)構(gòu),而名字中GoogLeNet更是致敬了LeNet。GoogLeNet中最核心的部分是其內(nèi)部子網(wǎng)絡(luò)結(jié)構(gòu)Inception,該結(jié)構(gòu)靈感來源于NIN(Network In Network)。
4.1 GoogLeNet模型結(jié)構(gòu)
由于圖像信息在空間尺寸上的巨大差異,如何選擇合適的卷積核來提取特征就顯得比較困難了。空間分布范圍更廣的圖像信息適合用較大的卷積核來提取其特征;而空間分布范圍較小的圖像信息則適合用較小的卷積核來提取其特征。為了解決這個問題,GoogLeNet提出了一種被稱為Inception模塊的方案。如 圖1 所示:
說明:
-
Google的研究人員為了向LeNet致敬,特地將模型命名為GoogLeNet。
-
Inception一詞來源于電影《盜夢空間》(Inception)。
圖1(a)是Inception模塊的設(shè)計思想,使用3個不同大小的卷積核對輸入圖片進(jìn)行卷積操作,并附加最大池化,將這4個操作的輸出沿著通道這一維度進(jìn)行拼接,構(gòu)成的輸出特征圖將會包含經(jīng)過不同大小的卷積核提取出來的特征,從而達(dá)到捕捉不同尺度信息的效果。Inception模塊采用多通路(multi-path)的設(shè)計形式,每個支路使用不同大小的卷積核,最終輸出特征圖的通道數(shù)是每個支路輸出通道數(shù)的總和,這將會導(dǎo)致輸出通道數(shù)變得很大,尤其是使用多個Inception模塊串聯(lián)操作的時候,模型參數(shù)量會變得非常大。
為了減小參數(shù)量,Inception模塊使用了圖(b)中的設(shè)計方式,在每個3x3和5x5的卷積層之前,增加1x1的卷積層來控制輸出通道數(shù);在最大池化層后面增加1x1卷積層減小輸出通道數(shù)。基于這一設(shè)計思想,形成了上圖(b)中所示的結(jié)構(gòu)。下面這段程序是Inception塊的具體實(shí)現(xiàn)方式,可以對照圖(b)和代碼一起閱讀。
提示:
可能有讀者會問,經(jīng)過3x3的最大池化之后圖像尺寸不會減小嗎,為什么還能跟另外3個卷積輸出的特征圖進(jìn)行拼接?這是因?yàn)槌鼗僮骺梢灾付ù翱诖笮?k_h = k_w = 3$,stride=1和padding=1,輸出特征圖尺寸可以保持不變。
Inception模塊的具體實(shí)現(xiàn)如下代碼所示:
#GoogLeNet模型代碼
import numpy as np
import paddle
from paddle.nn import Conv2D, MaxPool2D, AdaptiveAvgPool2D, Linear
##組網(wǎng)
import paddle.nn.functional as F
#定義Inception塊
class Inception(paddle.nn.Layer):
def __init__(self, c0, c1, c2, c3, c4, **kwargs):
'''
Inception模塊的實(shí)現(xiàn)代碼,
c1,圖(b)中第一條支路1x1卷積的輸出通道數(shù),數(shù)據(jù)類型是整數(shù)
c2,圖(b)中第二條支路卷積的輸出通道數(shù),數(shù)據(jù)類型是tuple或list,
其中c2[0]是1x1卷積的輸出通道數(shù),c2[1]是3x3
c3,圖(b)中第三條支路卷積的輸出通道數(shù),數(shù)據(jù)類型是tuple或list,
其中c3[0]是1x1卷積的輸出通道數(shù),c3[1]是3x3
c4,圖(b)中第一條支路1x1卷積的輸出通道數(shù),數(shù)據(jù)類型是整數(shù)
'''
super(Inception, self).__init__()
# 依次創(chuàng)建Inception塊每條支路上使用到的操作
self.p1_1 = Conv2D(in_channels=c0,out_channels=c1, kernel_size=1)
self.p2_1 = Conv2D(in_channels=c0,out_channels=c2[0], kernel_size=1)
self.p2_2 = Conv2D(in_channels=c2[0],out_channels=c2[1], kernel_size=3, padding=1)
self.p3_1 = Conv2D(in_channels=c0,out_channels=c3[0], kernel_size=1)
self.p3_2 = Conv2D(in_channels=c3[0],out_channels=c3[1], kernel_size=5, padding=2)
self.p4_1 = MaxPool2D(kernel_size=3, stride=1, padding=1)
self.p4_2 = Conv2D(in_channels=c0,out_channels=c4, kernel_size=1)
def forward(self, x):
# 支路1只包含一個1x1卷積
p1 = F.relu(self.p1_1(x))
# 支路2包含 1x1卷積 + 3x3卷積
p2 = F.relu(self.p2_2(F.relu(self.p2_1(x))))
# 支路3包含 1x1卷積 + 5x5卷積
p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))
# 支路4包含 最大池化和1x1卷積
p4 = F.relu(self.p4_2(self.p4_1(x)))
# 將每個支路的輸出特征圖拼接在一起作為最終的輸出結(jié)果
return paddle.concat([p1, p2, p3, p4], axis=1)
GoogLeNet的架構(gòu)如 圖2 所示,在主體卷積部分中使用5個模塊(block),每個模塊之間使用步幅為2的3 ×3最大池化層來減小輸出高寬。
- 第一模塊使用一個64通道的7 × 7卷積層。
- 第二模塊使用2個卷積層:首先是64通道的1 × 1卷積層,然后是將通道增大3倍的3 × 3卷積層。
- 第三模塊串聯(lián)2個完整的Inception塊。
- 第四模塊串聯(lián)了5個Inception塊。
- 第五模塊串聯(lián)了2 個Inception塊。
- 第五模塊的后面緊跟輸出層,使用全局平均池化層來將每個通道的高和寬變成1,最后接上一個輸出個數(shù)為標(biāo)簽類別數(shù)的全連接層。
說明:
在原作者的論文中添加了圖中所示的softmax1和softmax2兩個輔助分類器,如下圖所示,訓(xùn)練時將三個分類器的損失函數(shù)進(jìn)行加權(quán)求和,以緩解梯度消失現(xiàn)象。
4.2 GoogLeNet模型實(shí)現(xiàn)
GoogLeNet的具體實(shí)現(xiàn)如下代碼所示:
#GoogLeNet模型代碼
import paddle
from paddle import ParamAttr
import paddle.nn as nn
import paddle.nn.functional as F
from paddle.nn import Conv2D, BatchNorm, Linear, Dropout
from paddle.nn import AdaptiveAvgPool2D, MaxPool2D, AvgPool2D
from paddle.nn.initializer import Uniform
import math
#全連接層參數(shù)初始化
def xavier(channels, filter_size, name):
stdv = (3.0 / (filter_size**2 * channels))**0.5
param_attr = ParamAttr(initializer=Uniform(-stdv, stdv), name=name + "_weights")
return param_attr
class ConvLayer(nn.Layer):
def __init__(self,
num_channels,
num_filters,
filter_size,
stride=1,
groups=1,
act=None,
name=None):
super(ConvLayer, self).__init__()
self._conv = Conv2D(
in_channels=num_channels,
out_channels=num_filters,
kernel_size=filter_size,
stride=stride,
padding=(filter_size - 1) // 2,
groups=groups,
weight_attr=ParamAttr(name=name + "_weights"),
bias_attr=False)
def forward(self, inputs):
y = self._conv(inputs)
return y
#定義Inception塊
class Inception(nn.Layer):
def __init__(self,
input_channels,
output_channels,
filter1,
filter3R,
filter3,
filter5R,
filter5,
proj,
name=None):
'''
Inception模塊的實(shí)現(xiàn)代碼,
c1,圖(b)中第一條支路1x1卷積的輸出通道數(shù),數(shù)據(jù)類型是整數(shù)
c2,圖(b)中第二條支路卷積的輸出通道數(shù),數(shù)據(jù)類型是tuple或list,
其中c2[0]是1x1卷積的輸出通道數(shù),c2[1]是3x3
c3,圖(b)中第三條支路卷積的輸出通道數(shù),數(shù)據(jù)類型是tuple或list,
其中c3[0]是1x1卷積的輸出通道數(shù),c3[1]是3x3
c4,圖(b)中第一條支路1x1卷積的輸出通道數(shù),數(shù)據(jù)類型是整數(shù)
'''
super(Inception, self).__init__()
# 依次創(chuàng)建Inception塊每條支路上使用到的操作
self._conv1 = ConvLayer(input_channels, filter1, 1, name="inception_" + name + "_1x1")
self._conv3r = ConvLayer(input_channels, filter3R, 1, name="inception_" + name + "_3x3_reduce")
self._conv3 = ConvLayer(filter3R, filter3, 3, name="inception_" + name + "_3x3")
self._conv5r = ConvLayer(input_channels, filter5R, 1, name="inception_" + name + "_5x5_reduce")
self._conv5 = ConvLayer(filter5R, filter5, 5, name="inception_" + name + "_5x5")
self._pool = MaxPool2D(kernel_size=3, stride=1, padding=1)
self._convprj = ConvLayer(input_channels, proj, 1, name="inception_" + name + "_3x3_proj")
def forward(self, inputs):
# 支路1只包含一個1x1卷積
conv1 = self._conv1(inputs)
# 支路2包含 1x1卷積 + 3x3卷積
conv3r = self._conv3r(inputs)
conv3 = self._conv3(conv3r)
# 支路3包含 1x1卷積 + 5x5卷積
conv5r = self._conv5r(inputs)
conv5 = self._conv5(conv5r)
# 支路4包含 最大池化和1x1卷積
pool = self._pool(inputs)
convprj = self._convprj(pool)
# 將每個支路的輸出特征圖拼接在一起作為最終的輸出結(jié)果
cat = paddle.concat([conv1, conv3, conv5, convprj], axis=1)
cat = F.relu(cat)
return cat
class GoogLeNet(nn.Layer):
def __init__(self, class_dim=1000):
super(GoogLeNetDY, self).__init__()
# GoogLeNet包含五個模塊,每個模塊后面緊跟一個池化層
# 第一個模塊包含1個卷積層
self._conv = ConvLayer(3, 64, 7, 2, name="conv1")
# 3x3最大池化
self._pool = MaxPool2D(kernel_size=3, stride=2)
# 第二個模塊包含2個卷積層
self._conv_1 = ConvLayer(64, 64, 1, name="conv2_1x1")
self._conv_2 = ConvLayer(64, 192, 3, name="conv2_3x3")
# 第三個模塊包含2個Inception塊
self._ince3a = Inception(192, 192, 64, 96, 128, 16, 32, 32, name="ince3a")
self._ince3b = Inception(256, 256, 128, 128, 192, 32, 96, 64, name="ince3b")
# 第四個模塊包含5個Inception塊
self._ince4a = Inception(480, 480, 192, 96, 208, 16, 48, 64, name="ince4a")
self._ince4b = Inception(512, 512, 160, 112, 224, 24, 64, 64, name="ince4b")
self._ince4c = Inception(512, 512, 128, 128, 256, 24, 64, 64, name="ince4c")
self._ince4d = Inception(512, 512, 112, 144, 288, 32, 64, 64, name="ince4d")
self._ince4e = Inception(528, 528, 256, 160, 320, 32, 128, 128, name="ince4e")
# 第五個模塊包含2個Inception塊
self._ince5a = Inception(832, 832, 256, 160, 320, 32, 128, 128, name="ince5a")
self._ince5b = Inception(832, 832, 384, 192, 384, 48, 128, 128, name="ince5b")
# 全局池化
self._pool_5 = AvgPool2D(kernel_size=7, stride=7)
self._drop = Dropout(p=0.4, mode="downscale_in_infer")
self._fc_out = Linear(
1024,
class_dim,
weight_attr=xavier(1024, 1, "out"),
bias_attr=ParamAttr(name="out_offset"))
self._pool_o1 = AvgPool2D(kernel_size=5, stride=3)
self._conv_o1 = ConvLayer(512, 128, 1, name="conv_o1")
self._fc_o1 = Linear(
1152,
1024,
weight_attr=xavier(2048, 1, "fc_o1"),
bias_attr=ParamAttr(name="fc_o1_offset"))
self._drop_o1 = Dropout(p=0.7, mode="downscale_in_infer")
self._out1 = Linear(
1024,
class_dim,
weight_attr=xavier(1024, 1, "out1"),
bias_attr=ParamAttr(name="out1_offset"))
self._pool_o2 = AvgPool2D(kernel_size=5, stride=3)
self._conv_o2 = ConvLayer(528, 128, 1, name="conv_o2")
self._fc_o2 = Linear(
1152,
1024,
weight_attr=xavier(2048, 1, "fc_o2"),
bias_attr=ParamAttr(name="fc_o2_offset"))
self._drop_o2 = Dropout(p=0.7, mode="downscale_in_infer")
self._out2 = Linear(
1024,
class_dim,
weight_attr=xavier(1024, 1, "out2"),
bias_attr=ParamAttr(name="out2_offset"))
def forward(self, inputs):
x = self._conv(inputs)
x = self._pool(x)
x = self._conv_1(x)
x = self._conv_2(x)
x = self._pool(x)
x = self._ince3a(x)
x = self._ince3b(x)
x = self._pool(x)
ince4a = self._ince4a(x)
x = self._ince4b(ince4a)
x = self._ince4c(x)
ince4d = self._ince4d(x)
x = self._ince4e(ince4d)
x = self._pool(x)
x = self._ince5a(x)
ince5b = self._ince5b(x)
x = self._pool_5(ince5b)
x = self._drop(x)
x = paddle.squeeze(x, axis=[2, 3])
out = self._fc_out(x)
x = self._pool_o1(ince4a)
x = self._conv_o1(x)
x = paddle.flatten(x, start_axis=1, stop_axis=-1)
x = self._fc_o1(x)
x = F.relu(x)
x = self._drop_o1(x)
out1 = self._out1(x)
x = self._pool_o2(ince4d)
x = self._conv_o2(x)
x = paddle.flatten(x, start_axis=1, stop_axis=-1)
x = self._fc_o2(x)
x = self._drop_o2(x)
out2 = self._out2(x)
return [out, out1, out2]
4.3 GoogLeNet模型特色
- 采用不同大小的卷積核意味著不同大小的感受野,最后通過拼接實(shí)現(xiàn)不同尺度特征的融合;
- 之所以卷積核大小采用1、3和5,主要是為了方便對齊。設(shè)定卷積步長stride=1之后,只要分別設(shè)定pad=0、1、2,那么卷積之后便可以得到相同維度的特征,然后這些特征就可以直接拼接在一起了;
- 網(wǎng)絡(luò)越到后面,特征越抽象,而且每個特征所涉及的感受野也更大了,因此隨著層數(shù)的增加,3x3和5x5卷積的比例也要增加。但是,使用5x5的卷積核仍然會帶來巨大的計算量。 為此,文章采用1x1卷積核來進(jìn)行降維。
4.4 GoogLeNet模型指標(biāo)
GoogLeNet 在 2014 年的 ImageNet 比賽上取得了冠軍的好成績,具體指標(biāo)如 圖3 所示。在測試集上Error rate 達(dá)到了6.67%。
- 參考文獻(xiàn)
[1] Going deeper with convolutions.
5.DarkNet(YOLOv2、3)
在目標(biāo)檢測領(lǐng)域的YOLO系列算法中,作者為了達(dá)到更好的分類效果,自己設(shè)置并訓(xùn)練了DarkNet網(wǎng)絡(luò)作為骨干網(wǎng)絡(luò)。其中,YOLOv2[1]首次提出DarkNet網(wǎng)絡(luò),由于其具有19個卷積層,所以也稱之為DarkNet19。后來在YOLOv3[2]中,作者繼續(xù)吸收了當(dāng)前優(yōu)秀算法的思想,如殘差網(wǎng)絡(luò)和特征融合等,提出了具有53個卷積層的骨干網(wǎng)絡(luò)DarkNet53。作者在ImageNet上進(jìn)行了實(shí)驗(yàn),發(fā)現(xiàn)相較于ResNet-152和ResNet-101,DarkNet53在分類精度差不多的前提下,計算速度取得了領(lǐng)先。
5.1 DarkNet模型結(jié)構(gòu)
5.1.1 DarkNet19
DarkNet19中,借鑒了許多優(yōu)秀算法的經(jīng)驗(yàn),比如:借鑒了VGG的思想,使用了較多的$3\times 3$卷積,在每一次池化操作后,將通道數(shù)翻倍;借鑒了network in network的思想,使用全局平均池化(global average pooling)做預(yù)測,并把$1\times 1$的卷積核置于$3\times 3$的卷積核之間,用來壓縮特征;同時,使用了批歸一化層穩(wěn)定模型訓(xùn)練,加速收斂,并且起到正則化作用。DarkNet19的網(wǎng)絡(luò)結(jié)構(gòu)如 圖1 所示。
DarkNet19精度與VGG網(wǎng)絡(luò)相當(dāng),但浮點(diǎn)運(yùn)算量只有其 $\frac{1}{5}$ 左右,因此運(yùn)算速度極快。
5.1.2 DarkNet53
DarkNet53在之前的基礎(chǔ)上,借鑒了ResNet的思想,在網(wǎng)絡(luò)中大量使用了殘差連接,因此網(wǎng)絡(luò)結(jié)構(gòu)可以設(shè)計的很深,并且緩解了訓(xùn)練中梯度消失的問題,使得模型更容易收斂。同時,使用步長為2的卷積層代替池化層實(shí)現(xiàn)降采樣。DarkNet53的網(wǎng)絡(luò)結(jié)構(gòu)如 圖2 所示。
考慮到當(dāng)前 Darknet19 網(wǎng)絡(luò)使用頻率較低,接下來主要針對Darknet53網(wǎng)絡(luò)進(jìn)行實(shí)現(xiàn)與講解。
5.2 DarkNet模型實(shí)現(xiàn)
基于Paddle框架,DarkNet53的具體實(shí)現(xiàn)的代碼如下所示:
import paddle
from paddle import ParamAttr
import paddle.nn as nn
import paddle.nn.functional as F
from paddle.nn import Conv2D, BatchNorm, Linear, Dropout
from paddle.nn import AdaptiveAvgPool2D, MaxPool2D, AvgPool2D
from paddle.nn.initializer import Uniform
import math
#將卷積和批歸一化封裝為ConvBNLayer,方便后續(xù)復(fù)用
class ConvBNLayer(nn.Layer):
def __init__(self,
input_channels,
output_channels,
filter_size,
stride,
padding,
name=None):
# 初始化函數(shù)
super(ConvBNLayer, self).__init__()
# 創(chuàng)建卷積層
self._conv = Conv2D(
in_channels=input_channels,
out_channels=output_channels,
kernel_size=filter_size,
stride=stride,
padding=padding,
weight_attr=ParamAttr(name=name + ".conv.weights"),
bias_attr=False)
# 創(chuàng)建批歸一化層
bn_name = name + ".bn"
self._bn = BatchNorm(
num_channels=output_channels,
act="relu",
param_attr=ParamAttr(name=bn_name + ".scale"),
bias_attr=ParamAttr(name=bn_name + ".offset"),
moving_mean_name=bn_name + ".mean",
moving_variance_name=bn_name + ".var")
def forward(self, inputs):
# 前向計算
x = self._conv(inputs)
x = self._bn(x)
return x
#定義殘差塊
class BasicBlock(nn.Layer):
def __init__(self, input_channels, output_channels, name=None):
# 初始化函數(shù)
super(BasicBlock, self).__init__()
# 定義兩個卷積層
self._conv1 = ConvBNLayer(
input_channels, output_channels, 1, 1, 0, name=name + ".0")
self._conv2 = ConvBNLayer(
output_channels, output_channels * 2, 3, 1, 1, name=name + ".1")
def forward(self, inputs):
# 前向計算
x = self._conv1(inputs)
x = self._conv2(x)
# 將第二個卷積層的輸出和最初的輸入值相加
return paddle.add(x=inputs, y=x)
class DarkNet53(nn.Layer):
def __init__(self, class_dim=1000):
# 初始化函數(shù)
super(DarkNet, self).__init__()
# DarkNet 每組殘差塊的個數(shù),來自DarkNet的網(wǎng)絡(luò)結(jié)構(gòu)圖
self.stages = [1, 2, 8, 8, 4]
# 第一層卷積
self._conv1 = ConvBNLayer(3, 32, 3, 1, 1, name="yolo_input")
# 下采樣,使用stride=2的卷積來實(shí)現(xiàn)
self._conv2 = ConvBNLayer(
32, 64, 3, 2, 1, name="yolo_input.downsample")
# 添加各個層級的實(shí)現(xiàn)
self._basic_block_01 = BasicBlock(64, 32, name="stage.0.0")
# 下采樣,使用stride=2的卷積來實(shí)現(xiàn)
self._downsample_0 = ConvBNLayer(
64, 128, 3, 2, 1, name="stage.0.downsample")
self._basic_block_11 = BasicBlock(128, 64, name="stage.1.0")
self._basic_block_12 = BasicBlock(128, 64, name="stage.1.1")
# 下采樣,使用stride=2的卷積來實(shí)現(xiàn)
self._downsample_1 = ConvBNLayer(
128, 256, 3, 2, 1, name="stage.1.downsample")
self._basic_block_21 = BasicBlock(256, 128, name="stage.2.0")
self._basic_block_22 = BasicBlock(256, 128, name="stage.2.1")
self._basic_block_23 = BasicBlock(256, 128, name="stage.2.2")
self._basic_block_24 = BasicBlock(256, 128, name="stage.2.3")
self._basic_block_25 = BasicBlock(256, 128, name="stage.2.4")
self._basic_block_26 = BasicBlock(256, 128, name="stage.2.5")
self._basic_block_27 = BasicBlock(256, 128, name="stage.2.6")
self._basic_block_28 = BasicBlock(256, 128, name="stage.2.7")
# 下采樣,使用stride=2的卷積來實(shí)現(xiàn)
self._downsample_2 = ConvBNLayer(
256, 512, 3, 2, 1, name="stage.2.downsample")
self._basic_block_31 = BasicBlock(512, 256, name="stage.3.0")
self._basic_block_32 = BasicBlock(512, 256, name="stage.3.1")
self._basic_block_33 = BasicBlock(512, 256, name="stage.3.2")
self._basic_block_34 = BasicBlock(512, 256, name="stage.3.3")
self._basic_block_35 = BasicBlock(512, 256, name="stage.3.4")
self._basic_block_36 = BasicBlock(512, 256, name="stage.3.5")
self._basic_block_37 = BasicBlock(512, 256, name="stage.3.6")
self._basic_block_38 = BasicBlock(512, 256, name="stage.3.7")
# 下采樣,使用stride=2的卷積來實(shí)現(xiàn)
self._downsample_3 = ConvBNLayer(
512, 1024, 3, 2, 1, name="stage.3.downsample")
self._basic_block_41 = BasicBlock(1024, 512, name="stage.4.0")
self._basic_block_42 = BasicBlock(1024, 512, name="stage.4.1")
self._basic_block_43 = BasicBlock(1024, 512, name="stage.4.2")
self._basic_block_44 = BasicBlock(1024, 512, name="stage.4.3")
# 自適應(yīng)平均池化
self._pool = AdaptiveAvgPool2D(1)
stdv = 1.0 / math.sqrt(1024.0)
# 分類層
self._out = Linear(
1024,
class_dim,
weight_attr=ParamAttr(
name="fc_weights", initializer=Uniform(-stdv, stdv)),
bias_attr=ParamAttr(name="fc_offset"))
def forward(self, inputs):
x = self._conv1(inputs)
x = self._conv2(x)
x = self._basic_block_01(x)
x = self._downsample_0(x)
x = self._basic_block_11(x)
x = self._basic_block_12(x)
x = self._downsample_1(x)
x = self._basic_block_21(x)
x = self._basic_block_22(x)
x = self._basic_block_23(x)
x = self._basic_block_24(x)
x = self._basic_block_25(x)
x = self._basic_block_26(x)
x = self._basic_block_27(x)
x = self._basic_block_28(x)
x = self._downsample_2(x)
x = self._basic_block_31(x)
x = self._basic_block_32(x)
x = self._basic_block_33(x)
x = self._basic_block_34(x)
x = self._basic_block_35(x)
x = self._basic_block_36(x)
x = self._basic_block_37(x)
x = self._basic_block_38(x)
x = self._downsample_3(x)
x = self._basic_block_41(x)
x = self._basic_block_42(x)
x = self._basic_block_43(x)
x = self._basic_block_44(x)
x = self._pool(x)
x = paddle.squeeze(x, axis=[2, 3])
x = self._out(x)
return x
5.3 DarkNet模型特點(diǎn)
- DarkNet53模型使用了大量的殘差連接,緩解了訓(xùn)練中梯度消失的問題,使得模型更容易收斂。
- DarkNet53模型使用步長為2的卷積層代替池化層實(shí)現(xiàn)降采樣。
5.4 DarkNet模型指標(biāo)
在 YOLOv3 論文中,作者在 ImageNet 數(shù)據(jù)集上對比了 DarkNet 網(wǎng)絡(luò)與ResNet 網(wǎng)絡(luò)的精度及速度,如圖3所示??梢钥吹紻arkNet53的top-5準(zhǔn)確率可以達(dá)到93.8%,同時速度也明顯超過了ResNet101和ResNet152。
更多文章請關(guān)注公重號:汀丶人工智能
- 參考文獻(xiàn)
[1] YOLO9000: Better, Faster, Stronger文章來源:http://www.zghlxwxcb.cn/news/detail-474313.html
[2] YOLOv3: An Incremental Improvement文章來源地址http://www.zghlxwxcb.cn/news/detail-474313.html
到了這里,關(guān)于深度學(xué)習(xí)應(yīng)用篇-計算機(jī)視覺-圖像分類[2]:LeNet、AlexNet、VGG、GoogleNet、DarkNet模型結(jié)構(gòu)、實(shí)現(xiàn)、模型特點(diǎn)詳細(xì)介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!