面向對象編程的方式搭建CNN網絡 | PyTorch系列(十三)

點擊上方AI算法與圖像處理”,選擇加"星標"或“置頂”

重磅乾貨,第一時間送達

文 |AI_study

從我們深度學習項目的高層視角或概括的角度來看,我們準備了數據,現在,我們準備構建我們的模型。

  • 準備數據

  • 構建模型

  • 訓練模型

  • 分析模型的結果

說到模型,我們指的是我們的網絡。“模型”和“網絡”是同一個意思。我們希望我們的網絡最終做的是建模或近似一個將圖像輸入映射到正確輸出類的函數。


一、前提

爲了在PyTorch中構建神經網絡,我們擴展了PyTorch類 torch.nn.Module。這意味着我們需要在Python中利用一點面向對象編程(OOP)。

在這篇文章中,我們將快速回顧一下使用PyTorch神經網絡所需的細節,但是如果您發現還需要更多,Python文檔中有一個概述教程。

https://docs.python.org/3/tutorial/classes.html

要構建卷積神經網絡,我們需要對CNN的工作原理以及用於構建CNN的組件有一個大致的瞭解。 這個深度學習基礎知識系列是該系列的一個很好的先決條件,因此,我強烈建議您(如果尚未)涵蓋該系列。 如果您只想使用CNN速成班,可以查看以下特定文章:

  • 卷積神經網絡(CNN)的解釋

  • 可視化來自CNN的卷積濾波器

  • 卷積神經網絡中的零填充解釋

  • 卷積神經網絡中的最大池解釋

  • 卷積神經網絡(CNN)中的可學習參數解釋

現在讓我們快速進行面向對象的編程回顧。

https://deeplizard.com/learn/video/YRhxdVk_sIs https://deeplizard.com/learn/video/cNBBNAxC8l4 https://deeplizard.com/learn/video/qSTv_m-KFk0 https://deeplizard.com/learn/video/ZjM_XQa5s6s https://deeplizard.com/learn/video/gmBfb6LNnZs

二、快速回顧面向對象編程


當我們編寫程序或構建軟件時,有兩個關鍵組件:代碼和數據。有了面向對象編程,我們就可以圍繞對象來確定程序設計和結構的方向

使用類在代碼中定義對象。類定義了對象的規範,它指定了類的每個對象應該具有的數據和代碼。

當我們創建一個類的對象時,我們稱這個對象爲類的一個實例,並且一個給定類的所有實例都有兩個核心組件:

  • Methods(代碼)

  • Attributes(數據)

方法表示代碼,而屬性表示數據,因此方法和屬性是由類定義的。

在一個給定的程序中,有許多對象。給定類的一個實例可以同時存在,所有實例都具有相同的可用屬性和相同的可用方法。從這個角度來看,它們是一致的。

相同類的對象之間的區別在於每個屬性的對象中包含的值。每個對象都有自己的屬性值。這些值決定了對象的內部狀態。每個對象的代碼和數據都被封裝在對象中。

讓我們構建一個簡單的Lizard 類來演示類如何封裝數據和代碼:

class Lizard: #class declaration
    def __init__(self, name): #class constructor (code)
        self.name = name #attribute (data)
    
    def set_name(self, name): #method declaration (code)
        self.name = name #method implementation (code)

第一行聲明類並指定類名,在本例中是Lizard。

第二行定義了一個稱爲類構造函數的特殊方法。在創建類的新實例時調用類構造函數。作爲參數,我們有self和name。

self參數使我們能夠創建存儲或封裝在對象中的屬性值。當我們調用這個構造函數或任何其他方法時,我們不會傳遞self參數。Python自動爲我們做這些。

任何其他參數的參數值都是由調用者任意傳遞的,這些傳入方法的傳遞值可以在計算中使用,也可以在以後使用self保存和訪問。

完成構造函數之後,我們可以創建任意數量的專用方法,比如這裏的這個方法,它允許調用者更改存儲在self中的name值。我們在這裏所要做的就是調用該方法併爲名稱傳遞一個新值。讓我們看看它是如何運作的。

> lizard = Lizard('deep')
> print(lizard.name)
deep


> lizard.set_name('lizard')
> print(lizard.name)
lizard

我們通過指定類名並傳遞構造函數參數來創建類的對象實例。構造函數將接收這些參數,構造函數代碼將運行並保存傳遞的名稱。

然後,我們可以訪問名稱並打印它,還可以調用set_name()方法來更改名稱。一個程序中可以存在多個這樣的Lizard 實例,每個實例都包含自己的數據。

從面向對象的角度來看,這種設置的重要部分是將屬性和方法組合起來幷包含在對象中。

現在讓我們轉換一下,看看面向對象編程如何適合PyTorch。

PyTorch 的torch .nn 包

爲了在PyTorch中構建神經網絡,我們使用了torch.nn包,這是PyTorch的神經網絡(nn)庫。我們通常是這樣導入包的:

import torch.nn as nn

這允許我們使用nn別名訪問神經網絡包。所以從現在開始,如果我們說nn,就是指torch.nn 。PyTorch的神經網絡庫包含構建神經網絡所需的所有典型組件。

構建神經網絡所需的主要組件是一個層,因此,正如我們所期望的那樣,PyTorch的神經網絡庫包含一些類,可以幫助我們構建層。

PyTorch的nn.Module類

衆所周知,深層神經網絡是由多層結構構成的。這就是網絡 深 的原因。神經網絡中的每一層都有兩個主要的組成部分:

  • 轉換(代碼)

  • 一組權重(數據)

與生活中的許多事情一樣,這一事實使得層成爲使用OOP表示對象的最佳候選對象。OOP是面向對象編程的簡稱。

實際上,PyTorch就是這種情況。在神經網絡包中,有一個類叫做Module,它是所有神經網絡模塊的基類,包括層。

這意味着PyTorch中的所有層都擴展了nn.Module類,並繼承了PyTorch在nn.Module 中的所有內置功能。在面向對象編程中,這個概念被稱爲繼承。

甚至神經網絡也會擴展nn.Module的類。這是有道理的,因爲神經網絡本身可以被認爲是一個大的層(如果需要,讓它隨着時間的推移而下沉)。

PyTorch中的神經網絡和層擴展了nn.Module類。這意味着在PyTorch中構建新層或神經網絡時,我們必須擴展nn.Module類。

PyTorch的nn.Modules 有一個forward()方法

當我們把一個張量作爲輸入傳遞給網絡時,張量通過每一層變換向前流動,直到張量到達輸出層。這個張量通過網絡向前流動的過程被稱爲前向傳遞

The tensor input is passed forward though the network.


PyTorch的nn.functional包

當我們實現nn.Module子類的forward() 方法時,通常將使用nn.functional包中的函數。 該軟件包爲我們提供了許多可用於構建層的神經網絡操作。 實際上,許多nn.Module層類都使用nn.functional函數來執行其操作。

nn.functional軟件包中包含nn.Module子類用於實現其forward() 函數的方法。 稍後,通過查看nn.Conv2d卷積層類的PyTorch源代碼,來觀察一個示例。

在PyTorch中建立神經網絡

現在,我們有足夠的信息來提供在PyTorch中構建神經網絡的概述。 步驟如下:

精簡版:

  1. 擴展nn.Module基類。

  2. 將層定義爲類屬性。

  3. 實現forward() 方法。

更詳細的版本:

  1. 創建一個擴展nn.Module基類的神經網絡類。

  2. 在類構造函數中,使用torch.nn中的預構建層將網絡的圖層定義爲類屬性。

  3. 使用網絡的層屬性以及nn.functional API中的操作來定義網絡的前向傳播。

(1)擴展PyTorch的nn.Module類

就像我們在lizard 類示例中所做的一樣,讓我們創建一個簡單的類來表示神經網絡。

class Network:
    def __init__(self):
        self.layer = None


    def forward(self, t):
        t = self.layer(t)
        return t

這爲我們提供了一個簡單的網絡類,該類在構造函數內部具有單個虛擬層,並且對forward函數具有虛擬實現。

forward() 函數的實現採用張量t 並使用虛擬層對其進行轉換。 張量轉換後,將返回新的張量。

這是一個好的開始,但是該類尚未擴展nn.Module類。 爲了使我們的Network類擴展nn.Module,我們必須做另外兩件事:

  1. 在第1行的括號中指定nn.Module類。

  2. 在構造函數內部的第3行上插入對super 類構造函數的調用。

這給了我們:

class Network(nn.Module): # line 1
    def __init__(self):
        super().__init__() # line 3
        self.layer = None


    def forward(self, t):
        t = self.layer(t)
        return t

這些更改將我們的簡單神經網絡轉換爲PyTorch神經網絡,因爲我們現在正在擴展PyTorch的nn.Module基類。

這樣,我們就完成了! 現在我們有了一個Network類,它具有PyTorch nn.Module類的所有功能。

(2)將網絡的層定義爲類屬性

目前,我們的Network類具有單個虛擬層作爲屬性。 現在,讓我們用PyTorch的nn庫中爲我們預先構建的一些真實層替換它。 我們正在構建CNN,因此我們將使用的兩種類型的層是線性層和卷積層。

class Network(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)
        self.conv2 = nn.Conv2d(in_channels=6, out_channels=12, kernel_size=5)
        
        self.fc1 = nn.Linear(in_features=12 * 4 * 4, out_features=120)
        self.fc2 = nn.Linear(in_features=120, out_features=60)
        self.out = nn.Linear(in_features=60, out_features=10)
        
    def forward(self, t):
        # implement the forward pass
        return t

好的。 至此,我們有了一個名爲Network的Python類,該類擴展了PyTorch的nn.Module類。 在Network類內部,我們有五個定義爲屬性的層。 我們有兩個卷積層,self.conv1和self.conv2,以及三個線性層,self.fc1,self.fc2,self.out。

我們在fc1和fc2中使用了縮寫fc,因爲線性層也稱爲完全連接層。 它們也有一個我們可能會聽到的叫做 “dense” 的名字。 因此,linear, dense, 和 fully connected 都是指同一類型的層的所有方法。 PyTorch使用線性這個詞,因此使用nn.Linear類名。

我們將名稱out用作最後一個線性層,因爲網絡中的最後一層是輸出層。

總結

現在,我們應該對如何使用torch.nn庫開始在PyTorch中構建神經網絡有一個好主意。 在下一篇文章中,我們將研究層的不同類型的參數,並瞭解如何選擇它們。 下一個見。

文章中內容都是經過仔細研究的,本人水平有限,翻譯無法做到完美,但是真的是費了很大功夫,希望小夥伴能動動你性感的小手,分享朋友圈或點個“在看”,支持一下我 ^_^

英文原文鏈接是:

https://deeplizard.com/learn/video/k4jY9L8H89U

加羣交流

歡迎小夥伴加羣交流,目前已有交流羣的方向包括:AI學習交流羣,目標檢測,秋招互助,資料下載等等;加羣可掃描並回復感興趣方向即可(註明:地區+學校/企業+研究方向+暱稱)

 謝謝你看到這裏! ????

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章