點擊上方“AI算法與圖像處理”,選擇加"星標"或“置頂”
重磅乾貨,第一時間送達
文 |AI_study
原標題:CNN Forward Method - PyTorch Deep Learning Implementation
神經網絡程序設計系列(綜述)
到目前爲止,在這個系列中,我們已經準備好了我們的數據,現在構建我們的模型。
我們通過擴展nn.Module PyTorch基類來創建網絡,然後在類構造函數中將網絡層定義爲類屬性。現在,我們需要實現網絡的 forward() 方法,最後,我們將準備訓練我們的模型。
準備數據
構建模型
創建一個擴展nn.Module基類的神經網絡類。
在類構造函數中,將網絡層定義爲類屬性。
使用網絡的層屬性以及nn.functional API操作來定義網絡的前向傳遞
訓練模型
分析模型的結果
回顧一下網絡
目前,我們知道forward()方法接受張量作爲輸入,然後返回張量作爲輸出。現在,返回的張量與傳遞的張量相同。
但是,在構建實現之後,返回的張量將是網絡的輸出。
這意味着forward 方法實現將使用我們在構造函數內部定義的所有層。這樣,前向方法顯式定義了網絡的轉換。
forward()方法是實際的網絡轉換。forward 方法是將輸入張量映射到預測輸出張量的映射。讓我們看看這是如何完成的。
回想一下,在網絡的構造函數中,我們可以看到定義了五層。
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
我們有兩個卷積層和三個Linear 層。如果算上輸入層,這將爲我們提供一個總共六層的網絡。
實現forward 方法
讓我們對此進行代碼編寫。我們將從輸入層開始。
輸入層#1
任何神經網絡的輸入層都由輸入數據確定。例如,如果我們的輸入張量包含三個元素,那麼我們的網絡將在其輸入層中包含三個節點。
因此,我們可以將輸入層視爲 identity transformation 。從數學上講,這是下面的函數
f(x)=x.
我們給任何x 作爲輸入,我們得到相同的結果 x 作爲輸出。無論我們使用的是具有三個元素的張量,還是表示具有三個通道的圖像的張量,此邏輯都是相同的。輸入是數據輸出!
這非常瑣碎,這就是使用神經網絡API時通常看不到輸入層的原因。輸入層隱式存在。
絕對不是必需的,但是爲了完整起見,我們將在forward方法中顯示標識操作。
# (1) input layer
t = t
隱藏的卷積層:第2層和第3層
就執行轉換而言,兩個隱藏的卷積層都將非常相似。在深度學習基礎知識系列中,我們在有關層的文章中解釋說,不是輸入或輸出層的所有層都稱爲隱藏層,這就是爲什麼我們將這些卷積層稱爲隱藏層。
深度學習基礎:https://deeplizard.com/learn/video/gZmobeGL0Yg
層的解釋:https://deeplizard.com/learn/video/FK77zZxaBoI
爲了執行卷積運算,我們將張量傳遞給第一卷積層self.conv1的forward 方法。我們已經瞭解了所有PyTorch神經網絡模塊如何具有forward() 方法,並且當我們調用nn.Module的forward() 方法時,有一種特殊的調用方法。
當要調用nn.Module實例的forward() 方法時,我們將調用實際實例,而不是直接調用forward() 方法。
代替執行此self.conv1.forward(tensor),我們執行此self.conv1(tensor)。確保您看到了本系列的上一篇文章,以瞭解有關此主題的所有詳細信息。
讓我們繼續並添加實現兩個卷積層所需的所有調用。
# (2) hidden conv layer
t = self.conv1(t)
t = F.relu(t)
t = F.max_pool2d(t, kernel_size=2, stride=2)
# (3) hidden conv layer
t = self.conv2(t)
t = F.relu(t)
t = F.max_pool2d(t, kernel_size=2, stride=2)
正如我們在這裏看到的那樣,當我們在卷積層中移動時,輸入張量將發生變換。第一卷積層具有卷積運算,然後是 relu 激活運算,其輸出隨後傳遞到kernel_size = 2和stride = 2的最大池化中。
然後將第一個卷積層的輸出張量 t 傳遞到下一個卷積層,除了我們調用self.conv2()而不是self.conv1()以外,其他卷積層均相同。
這些層中的每一個都由權重(數據)和收集操作(代碼)組成。權重封裝在nn.Conv2d() 類實例中。relu() 和max_pool2d() 調用只是純運算。這些都不具有權重,這就是爲什麼我們直接從nn.functional API調用它們的原因。
有時,我們可能會看到稱爲池化層的池化操作。有時我們甚至可能聽到稱爲激活層的激活操作。
但是,使層與操作區分開的原因在於層具有權重。由於池操作和激活功能沒有權重,因此我們將它們稱爲操作,並將其視爲已添加到層操作集合中。
例如,我們說網絡中的第二層是一個卷積層,其中包含權重的集合,並執行三個操作,即卷積操作,relu激活操作和最大池化操作。
請注意,此處的規則和術語並不嚴格。這只是描述網絡的一種方式。還有其他表達這些想法的方法。我們需要知道的主要事情是哪些操作是使用權重定義的,哪些操作不使用任何權重。
從歷史上看,使用權重定義的操作就是我們所說的層。後來,其他操作被添加到mix中,例如激活功能和池化操作,這引起了術語上的一些混亂。
從數學上來說,整個網絡只是函數的組合,函數的組合就是函數本身。因此,網絡只是一種函數。諸如層,激活函數和權重之類的所有術語僅用於幫助描述不同的部分。
不要讓這些術語混淆整個網絡只是函數的組合這一事實,而我們現在正在做的就是在forward()方法中定義這種組合。
隱藏的Linear層:第4層和第5層
在將輸入傳遞到第一個隱藏的Linear 層之前,我們必須reshape() 或展平我們的張量。每當我們將卷積層的輸出作爲Linear層的輸入傳遞時,都是這種情況。
由於第四層是第一個Linear層,因此我們將reshape操作作爲第四層的一部分。
# (4) hidden linear layer
t = t.reshape(-1, 12 * 4 * 4)
t = self.fc1(t)
t = F.relu(t)
# (5) hidden linear layer
t = self.fc2(t)
t = F.relu(t)
我們在CNN權重的文章中看到,reshape 操作中的數字 12 由來自前一個卷積層的輸出通道數確定。
然而,4 * 4仍然是一個懸而未決的問題。讓我們現在揭示答案。4 * 4實際上是12個輸出通道中每個通道的高度和寬度。
我們從1 x 28 x 28輸入張量開始。這樣就給出了一個單一的彩色通道,即28 x 28的圖像,並且在我們的張量到達第一 Linear 層時,尺寸已經改變。
通過卷積和池化操作,將高度和寬度尺寸從28 x 28減小到4 x 4。
卷積和池化操作是對高度和寬度尺寸的化簡操作。我們將在下一篇文章中看到這是如何工作的,並看到用於計算這些減少量的公式。現在,讓我們完成實現此forward() 方法。
張量重構後,我們將展平的張量傳遞給 Linear 層,並將此結果傳遞給relu() 激活函數。
輸出層#6
我們網絡的第六層也是最後一層是 Linear 層,我們稱爲輸出層。當我們將張量傳遞到輸出層時,結果將是預測張量。由於我們的數據具有十個預測類別,因此我們知道我們的輸出張量將具有十個元素。
# (6) output layer
t = self.out(t)
#t = F.softmax(t, dim=1)
十個組件中的每個組件內的值將對應於我們每個預測類的預測值。
在網絡內部,我們通常使用relu() 作爲我們的非線性激活函數,但是對於輸出層,每當我們嘗試預測一個類別時,我們就使用softmax()。softmax函數針對每個預測類返回正概率,並且概率之和爲1。
但是,在本例中,我們不會使用softmax(),因爲我們將使用的損失函數F.cross_entropy()在其輸入上隱式執行softmax()操作,因此我們只返回 最後的線性變換。
這意味着我們的網絡將使用softmax操作進行訓練,但是當訓練過程完成後將網絡用於推理時,無需計算額外的操作。
結論
很好!我們做到了。這就是我們在PyTorch中實現神經網絡forward方法的方式。
PyTorch在__ call __()方法中運行的額外代碼就是我們從不直接調用forward()方法的原因。如果我們這樣做,額外的PyTorch代碼將不會被執行。因此,每當我們想要調用forward()方法時,我們都會調用對象實例。這既適用於層,也適用於網絡,因爲它們都是PyTorch神經網絡模塊。
現在可以實現網絡的forward()方法了。
文章中內容都是經過仔細研究的,本人水平有限,翻譯無法做到完美,但是真的是費了很大功夫,希望小夥伴能動動你性感的小手,分享朋友圈或點個“在看”,支持一下我 ^_^
英文原文鏈接是:
https://deeplizard.com/learn/video/MasG7tZj-hw
加羣交流
歡迎小夥伴加羣交流,目前已有交流羣的方向包括:AI學習交流羣,目標檢測,秋招互助,資料下載等等;加羣可掃描並回復感興趣方向即可(註明:地區+學校/企業+研究方向+暱稱)
謝謝你看到這裏! ????