零基礎入門深度學習(七):圖像分類任務之VGG、GoogLeNet和ResNet

2021-02-13 飛槳PaddlePaddle
授課講師 | 孫高峰 百度深度學習技術平臺部資深研發工程師授課時間 | 每周二、周四晚20:00-21:00本課程是百度官方開設的零基礎入門深度學習課程,主要面向沒有深度學習技術基礎或者基礎薄弱的同學,幫助大家在深度學習領域實現從0到1+的跨越。從本課程中,你將學習到:本周為開講第四周,百度深度學習技術平臺部資深研發工程師孫高峰,開始講解計算機視覺中圖像分類任務。在上一節課中,我們為大家介紹了經典的LeNet和AlexNet神經網絡結構在眼疾識別任務中的應用,本節將繼續為大家帶來更多精彩內容。VGG是當前最流行的CNN模型之一,2014年由Simonyan和Zisserman提出,其命名來源於論文作者所在的實驗室Visual Geometry Group。AlexNet模型通過構造多層網絡,取得了較好的效果,但是並沒有給出深度神經網絡設計的方向。VGG通過使用一系列大小為3x3的小尺寸卷積核和pooling層構造深度卷積神經網絡,並取得了較好的效果。VGG模型因為結構簡單、應用性極強而廣受研究者歡迎,尤其是它的網絡結構設計方法,為構建深度神經網絡提供了方向。圖3 是VGG-16的網絡結構示意圖,有13層卷積和3層全連接層。VGG網絡的設計嚴格使用的卷積層和池化層來提取特徵,並在網絡的最後面使用三層全連接層,將最後一層全連接層的輸出作為分類的預測。在VGG中每層卷積將使用ReLU作為激活函數,在全連接層之後添加dropout來抑制過擬合。使用小的卷積核能夠有效地減少參數的個數,使得訓練和測試變得更加有效。比如使用兩層卷積層,可以得到感受野為5的特徵圖,而比使用的卷積層需要更少的參數。由於卷積核比較小,可以堆疊更多的卷積層,加深網絡的深度,這對於圖像分類任務來說是有利的。VGG模型的成功證明了增加網絡的深度,可以更好的學習圖像中的特徵模式。VGG在眼疾識別數據集iChallenge-PM上的具體實現如下代碼所示:
# -*- coding:utf-8 -*-
# VGG模型代碼import numpy as npimport paddleimport paddle.fluid as fluidfrom paddle.fluid.layer_helper import LayerHelperfrom paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, FCfrom paddle.fluid.dygraph.base import to_variable
# 定義vgg塊,包含多層卷積和1層2x2的最大池化層class vgg_block(fluid.dygraph.Layer): def __init__(self, name_scope, num_convs, num_channels): """ num_convs, 卷積層的數目 num_channels, 卷積層的輸出通道數,在同一個Incepition塊內,卷積層輸出通道數是一樣的 """ super(vgg_block, self).__init__(name_scope) self.conv_list = [] for i in range(num_convs): conv_layer = self.add_sublayer('conv_' + str(i), Conv2D(self.full_name(), num_filters=num_channels, filter_size=3, padding=1, act='relu')) self.conv_list.append(conv_layer) self.pool = Pool2D(self.full_name(), pool_stride=2, pool_size = 2, pool_type='max') def forward(self, x): for item in self.conv_list: x = item(x) return self.pool(x)
class VGG(fluid.dygraph.Layer): def __init__(self, name_scope, conv_arch=((2, 64), (2, 128), (3, 256), (3, 512), (3, 512))): super(VGG, self).__init__(name_scope) self.vgg_blocks=[] iter_id = 0 # 添加vgg_block # 這裡一共5個vgg_block,每個block裡面的卷積層數目和輸出通道數由conv_arch指定 for (num_convs, num_channels) in conv_arch: block = self.add_sublayer('block_' + str(iter_id), vgg_block(self.full_name(), num_convs, num_channels)) self.vgg_blocks.append(block) iter_id += 1 self.fc1 = FC(self.full_name(), size=4096, act='relu') self.drop1_ratio = 0.5 self.fc2= FC(self.full_name(), size=4096, act='relu') self.drop2_ratio = 0.5 self.fc3 = FC(self.full_name(), size=1, ) def forward(self, x): for item in self.vgg_blocks: x = item(x) x = fluid.layers.dropout(self.fc1(x), self.drop1_ratio) x = fluid.layers.dropout(self.fc2(x), self.drop2_ratio) x = self.fc3(x) return x

with fluid.dygraph.guard():    model = VGG("VGG")
train(model)

通過運行結果可以發現,在眼疾篩查數據集iChallenge-PM上使用VGG,loss能有效的下降,經過5個epoch的訓練,在驗證集上的準確率可以達到94%左右。GoogLeNet是2014年ImageNet比賽的冠軍,它的主要特點是網絡不僅有深度,還在橫向上具有「寬度」。由於圖像信息在空間尺寸上的巨大差異,如何選擇合適的卷積核大小來提取特徵就顯得比較困難了。空間分布範圍更廣的圖像信息適合用較大的卷積核來提取其特徵,而空間分布範圍較小的圖像信息則適合用較小的卷積核來提取其特徵。為了解決這個問題,GoogLeNet提出了一種被稱為Inception模塊的方案。如 圖4 所示:Google的研究人員為了向LeNet致敬,特地將模型命名為GoogLeNetInception一詞來源於電影《盜夢空間》(Inception)
圖4(a)是Inception模塊的設計思想,使用3個不同大小的卷積核對輸入圖片進行卷積操作,並附加最大池化,將這4個操作的輸出沿著通道這一維度進行拼接,構成的輸出特徵圖將會包含經過不同大小的卷積核提取出來的特徵。Inception模塊採用多通路(multi-path)的設計形式,每個支路使用不同大小的卷積核,最終輸出特徵圖的通道數是每個支路輸出通道數的總和,這將會導致輸出通道數變得很大,尤其是使用多個Inception模塊串聯操作的時候,模型參數量會變得非常巨大。為了減小參數量,Inception模塊使用了圖(b)中的設計方式,在每個3x3和5x5的卷積層之前,增加1x1的卷積層來控制輸出通道數;在最大池化層後面增加1x1卷積層減小輸出通道數。基於這一設計思想,形成了上圖(b)中所示的結構。下面這段程序是Inception塊的具體實現方式,可以對照圖(b)和代碼一起閱讀。可能有讀者會問,經過3x3的最大池化之後圖像尺寸不會減小嗎,為什麼還能跟另外3個卷積輸出的特徵圖進行拼接?這是因為池化操作可以指定窗口大小,pool_stride=1和pool_padding=1,輸出特徵圖尺寸可以保持不變。
class Inception(fluid.dygraph.Layer):    def __init__(self, name_scope, c1, c2, c3, c4, **kwargs):        '''        Inception模塊的實現代碼,        name_scope, 模塊名稱,數據類型為string        c1,  圖(b)中第一條支路1x1卷積的輸出通道數,數據類型是整數        c2,圖(b)中第二條支路卷積的輸出通道數,數據類型是tuple或list,                其中c2[0]是1x1卷積的輸出通道數,c2[1]是3x3        c3,圖(b)中第三條支路卷積的輸出通道數,數據類型是tuple或list,                其中c3[0]是1x1卷積的輸出通道數,c3[1]是3x3        c4,  圖(b)中第一條支路1x1卷積的輸出通道數,數據類型是整數        '''        super(Inception, self).__init__(name_scope)                self.p1_1 = Conv2D(self.full_name(), num_filters=c1,                            filter_size=1, act='relu')        self.p2_1 = Conv2D(self.full_name(), num_filters=c2[0],                            filter_size=1, act='relu')        self.p2_2 = Conv2D(self.full_name(), num_filters=c2[1],                            filter_size=3, padding=1, act='relu')        self.p3_1 = Conv2D(self.full_name(), num_filters=c3[0],                            filter_size=1, act='relu')        self.p3_2 = Conv2D(self.full_name(), num_filters=c3[1],                            filter_size=5, padding=2, act='relu')        self.p4_1 = Pool2D(self.full_name(), pool_size=3,                            pool_stride=1,  pool_padding=1,                            pool_type='max')        self.p4_2 = Conv2D(self.full_name(), num_filters=c4,                            filter_size=1, act='relu')
def forward(self, x): p1 = self.p1_1(x) p2 = self.p2_2(self.p2_1(x)) p3 = self.p3_2(self.p3_1(x)) p4 = self.p4_2(self.p4_1(x)) return fluid.layers.concat([p1, p2, p3, p4], axis=1)

GoogLeNet的架構如 圖5 所示,在主體卷積部分中使用5個模塊(block),每個模塊之間使用步幅為2的3 ×3最大池化層來減小輸出高寬。第二模塊使用2個卷積層:首先是64通道的1 × 1卷積層,然後是將通道增大3倍的3 × 3卷積層。第五模塊的後面緊跟輸出層,使用全局平均池化 層來將每個通道的高和寬變成1,最後接上一個輸出個數為標籤類別數的全連接層。說明:在原作者的論文中添加了圖中所示的softmax1和softmax2兩個輔助分類器,如下圖所示,訓練時將三個分類器的損失函數進行加權求和,以緩解梯度消失現象。這裡的程序作了簡化,沒有加入輔助分類器。
# -*- coding:utf-8 -*-
# GoogLeNet模型代碼import numpy as npimport paddleimport paddle.fluid as fluidfrom paddle.fluid.layer_helper import LayerHelperfrom paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, FCfrom paddle.fluid.dygraph.base import to_variable
# 定義Inception塊class Inception(fluid.dygraph.Layer): def __init__(self, name_scope, c1, c2, c3, c4, **kwargs): ''' Inception模塊的實現代碼, name_scope, 模塊名稱,數據類型為string c1, 圖(b)中第一條支路1x1卷積的輸出通道數,數據類型是整數 c2,圖(b)中第二條支路卷積的輸出通道數,數據類型是tuple或list, 其中c2[0]是1x1卷積的輸出通道數,c2[1]是3x3 c3,圖(b)中第三條支路卷積的輸出通道數,數據類型是tuple或list, 其中c3[0]是1x1卷積的輸出通道數,c3[1]是3x3 c4, 圖(b)中第一條支路1x1卷積的輸出通道數,數據類型是整數 ''' super(Inception, self).__init__(name_scope) # 依次創建Inception塊每條支路上使用到的操作 self.p1_1 = Conv2D(self.full_name(), num_filters=c1, filter_size=1, act='relu') self.p2_1 = Conv2D(self.full_name(), num_filters=c2[0], filter_size=1, act='relu') self.p2_2 = Conv2D(self.full_name(), num_filters=c2[1], filter_size=3, padding=1, act='relu') self.p3_1 = Conv2D(self.full_name(), num_filters=c3[0], filter_size=1, act='relu') self.p3_2 = Conv2D(self.full_name(), num_filters=c3[1], filter_size=5, padding=2, act='relu') self.p4_1 = Pool2D(self.full_name(), pool_size=3, pool_stride=1, pool_padding=1, pool_type='max') self.p4_2 = Conv2D(self.full_name(), num_filters=c4, filter_size=1, act='relu')
def forward(self, x): # 支路1隻包含一個1x1卷積 p1 = self.p1_1(x) # 支路2包含 1x1卷積 + 3x3卷積 p2 = self.p2_2(self.p2_1(x)) # 支路3包含 1x1卷積 + 5x5卷積 p3 = self.p3_2(self.p3_1(x)) # 支路4包含 最大池化和1x1卷積 p4 = self.p4_2(self.p4_1(x)) # 將每個支路的輸出特徵圖拼接在一起作為最終的輸出結果 return fluid.layers.concat([p1, p2, p3, p4], axis=1)
class GoogLeNet(fluid.dygraph.Layer): def __init__(self, name_scope): super(GoogLeNet, self).__init__(name_scope) # GoogLeNet包含五個模塊,每個模塊後面緊跟一個池化層 # 第一個模塊包含1個卷積層 self.conv1 = Conv2D(self.full_name(), num_filters=64, filter_size=7, padding=3, act='relu') # 3x3最大池化 self.pool1 = Pool2D(self.full_name(), pool_size=3, pool_stride=2, pool_padding=1, pool_type='max') # 第二個模塊包含2個卷積層 self.conv2_1 = Conv2D(self.full_name(), num_filters=64, filter_size=1, act='relu') self.conv2_2 = Conv2D(self.full_name(), num_filters=192, filter_size=3, padding=1, act='relu') # 3x3最大池化 self.pool2 = Pool2D(self.full_name(), pool_size=3, pool_stride=2, pool_padding=1, pool_type='max') # 第三個模塊包含2個Inception塊 self.block3_1 = Inception(self.full_name(), 64, (96, 128), (16, 32), 32) self.block3_2 = Inception(self.full_name(), 128, (128, 192), (32, 96), 64) # 3x3最大池化 self.pool3 = Pool2D(self.full_name(), pool_size=3, pool_stride=2, pool_padding=1, pool_type='max') # 第四個模塊包含5個Inception塊 self.block4_1 = Inception(self.full_name(), 192, (96, 208), (16, 48), 64) self.block4_2 = Inception(self.full_name(), 160, (112, 224), (24, 64), 64) self.block4_3 = Inception(self.full_name(), 128, (128, 256), (24, 64), 64) self.block4_4 = Inception(self.full_name(), 112, (144, 288), (32, 64), 64) self.block4_5 = Inception(self.full_name(), 256, (160, 320), (32, 128), 128) # 3x3最大池化 self.pool4 = Pool2D(self.full_name(), pool_size=3, pool_stride=2, pool_padding=1, pool_type='max') # 第五個模塊包含2個Inception塊 self.block5_1 = Inception(self.full_name(), 256, (160, 320), (32, 128), 128) self.block5_2 = Inception(self.full_name(), 384, (192, 384), (48, 128), 128) # 全局池化,尺寸用的是global_pooling,pool_stride不起作用 self.pool5 = Pool2D(self.full_name(), pool_stride=1, global_pooling=True, pool_type='avg') self.fc = FC(self.full_name(), size=1)
def forward(self, x): x = self.pool1(self.conv1(x)) x = self.pool2(self.conv2_2(self.conv2_1(x))) x = self.pool3(self.block3_2(self.block3_1(x))) x = self.block4_3(self.block4_2(self.block4_1(x))) x = self.pool4(self.block4_5(self.block4_4(x))) x = self.pool5(self.block5_2(self.block5_1(x))) x = self.fc(x) return x

with fluid.dygraph.guard():    model = GoogLeNet("GoogLeNet")
train(model)

通過運行結果可以發現,使用GoogLeNet在眼疾篩查數據集iChallenge-PM上,loss能有效的下降,經過5個epoch的訓練,在驗證集上的準確率可以達到95%左右。ResNet是2015年ImageNet比賽的冠軍,將識別錯誤率降低到了3.6%,這個結果甚至超出了正常人眼識別的精度。通過前面幾個經典模型學習,我們可以發現隨著深度學習的不斷發展,模型的層數越來越多,網絡結構也越來越複雜。那麼是否加深網絡結構,就一定會得到更好的效果呢?從理論上來說,假設新增加的層都是恆等映射,只要原有的層學出跟原模型一樣的參數,那麼深模型結構就能達到原模型結構的效果。換句話說,原模型的解只是新模型的解的子空間,在新模型解的空間裡應該能找到比原模型解對應的子空間更好的結果。但是實踐表明,增加網絡的層數之後,訓練誤差往往不降反升。Kaiming He等人提出了殘差網絡ResNet來解決上述問題,其基本思想如 圖6所示。圖6(b):對圖6(a)作了改進,輸出。這時不是直接學習輸出特徵y的表示,而是學習。如果想學習出原模型的表示,只需將F(x)的參數全部設置為0,則是恆等映射。也叫做殘差項,如果的映射接近恆等映射,圖6(b)中通過學習殘差項也比圖6(a)學習完整映射形式更加容易。圖6(b)的結構是殘差網絡的基礎,這種結構也叫做殘差塊(residual block)。輸入x通過跨層連接,能更快的向前傳播數據,或者向後傳播梯度。殘差塊的具體設計方案如 7 所示,這種設計方案也成稱作瓶頸結構(BottleNeck)。

下圖表示出了ResNet-50的結構,一共包含49層卷積和1層全連接,所以被稱為ResNet-50。
with fluid.dygraph.guard():    model = ResNet("ResNet")
train(model)

通過運行結果可以發現,使用ResNet在眼疾篩查數據集iChallenge-PM上,loss能有效的下降,經過5個epoch的訓練,在驗證集上的準確率可以達到95%左右。本周課程中孫老師主要為大家講解了計算機視覺中分類任務的主要內容,以眼疾識別任務為例,講解了經典卷積神經網絡VGG、GoogLeNet和ResNet。在後期課程中,將繼續為大家帶來內容更豐富的課程,幫助學員快速掌握深度學習方法。視頻+代碼已經發布在AI Studio實踐平臺上,視頻支持PC端/手機端同步觀看,也鼓勵大家親手體驗運行代碼哦。打開以下連結:https://aistudio.baidu.com/aistudio/course/introduce/888加入深度學習集訓營QQ群:726887660,班主任與飛槳研發會在群裡進行答疑與學習資料發放。百度飛槳將通過飛槳深度學習集訓營的形式,繼續更新《零基礎入門深度學習》課程,由百度深度學習高級研發工程師親自授課,每周二、每周四8:00-9:00不見不散,採用直播+錄播+實踐+答疑的形式,歡迎關注~請搜索AI Studio,點擊課程-百度架構師手把手教深度學習,或者點擊文末「閱讀原文」收看。

相關焦點

  • VGGNet、ResNet、Inception和Xception圖像分類及對比
    圖像分類任務是一個典型的深度學習應用。
  • 【深度學習系列】用PaddlePaddle和Tensorflow實現經典CNN網絡GoogLeNet
    點擊上圖,立即開啟AI急速修煉作者:Charlotte    高級算法工程師 ,博客專家;擅長用通俗易懂的方式講解深度學習和機器學習算法
  • 零基礎入門深度學習(六):圖像分類任務之LeNet和AlexNet
    :0001 導讀本課程是百度官方開設的零基礎入門深度學習課程,主要面向沒有深度學習技術基礎或者基礎薄弱的同學,幫助大家在深度學習領域實現從0到1+的跨越。>個性化推薦算法的原理、實踐本周為開講第四周,百度深度學習技術平臺部資深研發工程師孫高峰,開始講解計算機視覺中圖像分類任務。
  • 基礎入門,怎樣用PaddlePaddle優雅地寫VGG與ResNet
    綜述圖像相比文字能夠提供更加生動、容易理解及更具藝術感的信息,圖像分類是根據圖像的語義信息將不同類別圖像區分開來,是圖像檢測、圖像分割、物體跟蹤、行為分析等其他高層視覺任務的基礎。圖像分類在安防、交通、網際網路、醫學等領域有著廣泛的應用。
  • 用PaddlePaddle 和 Tensorflow 實現經典 CNN 網絡 GoogLeNet
    前面講了 LeNet、AlexNet 和 Vgg,這周來講講 GoogLeNet。GoogLeNet 是由 google 的 Christian Szegedy 等人在 2014 年的論文《Going Deeper with Convolutions》提出,其最大的亮點是提出一種叫 Inception 的結構,以此為基礎構建 GoogLeNet,並在當年的 ImageNet 分類和檢測任務中獲得第一,ps:GoogLeNet 的取名是為了向 YannLeCun 的 LeNet 系列致敬
  • DL經典論文系列(二) AlexNet、VGG、GoogLeNet/Inception、ResNet
    對於給定的感受野(與輸出有關的輸入圖片的局部大小),採用堆積的小卷積核是優於採用大的卷積核,因為多層非線性層可以增加網絡深度來保證學習更複雜的模式,而且代價還比較小(參數更少)。簡單來說,在VGG中,使用了3個3x3卷積核來代替7x7卷積核,使用了2個3x3卷積核來代替5*5卷積核,這樣做的主要目的是在保證具有相同感知野的條件下,提升了網絡的深度,在一定程度上提升了神經網絡的效果。
  • 圖像分類-卷積網絡閱讀筆記(二)VGG
    Deep Convolutional Networks for Large-Scale Image Recognition2014年,Karen Simonyan(Visual Geometry Group,University of Oxford)Abstract在本文中我們說明在大尺度圖像識別數據集上卷積網絡深度對精度的影響
  • 經典CNN網絡(Lenet、Alexnet、GooleNet、VGG、ResNet、DenseNet)
    每一個group對應N/M個channel,與之獨立連接。然後各個group卷積完成後將輸出疊在一起(concatenate),作為這一層的輸出channel。局部響應歸一化LRN:利用前後幾層(對應位置的點)對中間這一層做一下平滑約束,增加泛化能力,公式為:
  • 深度學習: 細粒度圖像分類 (fine-grained image recognition)
    其目的是對粗粒度的大類別 進行更加細緻的子類劃分, 但由於子類別間細微的 類間差異和較大的類內差異, 較之普通的圖像分類 任務, 細粒度圖像分類難度更大.目前, 絕大多數的分類算法都遵循這樣的流程框架:首先找到前景對象(鳥)及其局部區域(頭、腳、翅膀等), 之後分別對這些區域提取特徵.
  • 深度學習的學習歷程
    alexnet、vgg、googlenet、resnet等網絡就像樂高一樣,把這些模塊當積木一樣組合起來,好像也沒啥特別的。又好像什麼都不懂,學會這些模塊的公式就算會深度學習了嗎?整個深度學習的學習周期是怎樣的,我下一步應該幹啥?這些模塊看起來平平無奇,為什麼組合在一起就能發揮這麼大威力?為什麼drop out能起到正則作用?L1正則和L2正則有什麼區別?
  • 基於PaddlePaddle的圖片分類實戰 | 深度學習基礎任務教程系列
    圖像相比文字能夠提供更加生動、容易理解及更具藝術感的信息,圖像分類是根據圖像的語義信息將不同類別圖像區分開來,是圖像檢測、圖像分割、物體跟蹤、行為分析等其他高層視覺任務的基礎。圖像分類在安防、交通、網際網路、醫學等領域有著廣泛的應用。
  • 快速訓練殘差網絡 ResNet-101,完成圖像分類與預測,精度高達 98%|...
    出於這個原因,這一次,我將採用一種巧妙的方法——遷移學習來實現。即在預訓練模型的基礎上,採用101層的深度殘差網絡ResNet-101,對如下圖所示的花數據集進行訓練,快速實現了對原始圖像的分類和預測,最終預測精確度達到了驚人的98%。
  • 深度理論VGG-NET 網絡
    深度學習VGG-NET 網絡概述VGG名字來源於Visual Geometry Group, Department of Engineering
  • 圖像分類 | 深度學習PK傳統機器學習
    圖像分類的傳統方法是特徵描述及檢測,這類傳統方法可能對於一些簡單的圖像分類是有效的,但由於實際情況非常複雜,傳統的分類方法不堪重負。現在,我們不再試圖用代碼來描述每一個圖像類別,決定轉而使用機器學習的方法處理圖像分類問題。目前,許多研究者使用CNN等深度學習模型進行圖像分類;另外,經典的KNN和SVM算法也取得不錯的結果。
  • 深度學習算法優化:VGG,ResNet,DenseNe 模型剪枝代碼實戰
    深度學習算法優化系列七 | ICCV 2017的一篇模型剪枝論文,也是2019年眾多開源剪枝項目的理論基礎 。這篇文章是從源碼實戰的角度來解釋模型剪枝,源碼來自:https://github.com/Eric-mingjie/network-slimming 。我這裡主要是結合源碼來分析每個模型的具體剪枝過程,希望能給你剪枝自己的模型一些啟發。
  • ResNet - 2015年 ILSVRC 的贏家(圖像分類,定位及檢測)
    通過學習殘差表徵函數而不是直接學習目標表徵,ResNet可以擁有多達152層的非常深的網絡。ResNet引入了跳過連接(或快捷方式連接)以適應從前一層到下一層的輸入,而無需修改輸入。跳過連接可以實現更深入的網絡,最終ResNet成為ILSVRC 2015在圖像分類,檢測和定位方面的贏家,和MS COCO 2015檢測和分割的獲勝者。
  • 6000星人氣深度學習資源!架構模型技巧全都有,大牛LeCun推薦
    銅靈 發自 凹非寺量子位 出品 | 公眾號 QbitAI暑假即將到來,不用來充電學習豈不是虧大了。有這麼一份乾貨,匯集了機器學習架構和模型的經典知識點,還有各種TensorFlow和PyTorch的Jupyter Notebook筆記資源,地址都在,無需等待即可取用。
  • Deep CARs:使用Pytorch學習框架實現遷移學習
    更準確地說,是使用一個深度神經網絡,因此得名Deep CARs(深度計算機自動額定值系統)。想要實現這一目標,需要完成兩部分的學習,第1部分:構建汽車分類器;第2部分:部署分類器。本文將著重論述第1部分內容。我們將使用一種叫做遷移學習的方法來訓練分類器。
  • GitHub趨勢榜第一:TensorFlow+PyTorch深度學習資源大匯總
    的各種深度學習架構,模型和技巧的集合。本文搜集整理了Jupyter Notebook中TensorFlow和PyTorch的各種深度學習架構,模型和技巧,內容非常豐富,適用於Python 3.7,適合當做工具書。大家可以將內容按照需要進行分割,列印出來,或者做成電子書等,隨時查閱。