天天看點

神經網絡來襲!劃重點:60分鐘入門,這是最深入淺出的一次

神經網絡

神經網絡可以使用torch.nn包建構。

現在對PyTorch的自動求導機制(autograd)有所了解,nn 依賴autograd來定義模型和區分它們。一個nn.Module包括layers和傳回輸出值的forword(input)方法。

例如:下面的這個圖檔分類的神經網絡。

神經網絡來襲!劃重點:60分鐘入門,這是最深入淺出的一次

這是一個簡單的前饋神經網絡。

它接收輸入,一個接一個地通過幾個層饋送,然後最後給出輸出。

一個神經網絡的典型訓練程式如下:

定義具有可學習參數(或權重)的神經網絡

疊代輸入資料集

通過網絡進行過程輸入

計算損失(輸出的正确程度有多遠)

向神經網絡參數回傳梯度

更新網絡中的參數權重,通常使用簡單的更新規則:weight = weight - learning_rate* gradient

1.定義網絡

我們開始定義網絡:

import torch
import torch.nn as nn
import torch.nn.functional as F


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        #卷積層, '1'表示輸入圖檔的為單通道,'6'表示輸出通道數,'5'表示卷積核 5*5
        #核心
        self.conv1 = nn.Conv2d(1, 6, 5)
        # '6'表示輸入資料通道,16個輸出,'5'表示卷積核 5*5 
        self.conv2 = nn.Conv2d(6, 16, 5)
    
        #映射層/全連接配接層:y = Wx+b
        # 為什麼是16*5*5呢? 這是全連接配接層的第一個函數。
        # 經過卷積、池化後最後輸出的結果是16個大小為5*5的圖像.
        #第一次卷積:圖檔大小 = (32-5+1)/1 = 28
        #第一次池化:圖檔大小 = 28/2 = 14
        #第二次卷積:圖檔大小 = (14-5+1)/1 =10
        #第二次池化:圖檔大小 = 10/2 = 5
        self.fc1 = nn.Linear(16 * 5 * 5,120) 
        self.fc2 = nn.Linear(120,84)
        self.fc3 = nn.Linear(84,10)
        
    def forward(self,x):
        #在由多個輸入平面組成哦輸入信号上應用2D最大池化。
        #(2,2)表示的是池化操作的步幅
        x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
        #如果大小是正方形,則隻能指定一個數字
        x = F.max_pool2d(F.relu(self.conv2(x)),2)
        #将一個多元資料轉成N行一列的資料。
        x = x.view(-1,self.num_flat_features(x))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x =self.fc3(x)
        return x
            
        
    def num_flat_features(self,x):
        size = x.size()[1:]
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

net = Net()
print(net)           
神經網絡來襲!劃重點:60分鐘入門,這是最深入淺出的一次

隻定義了forward函數,backward函數(計算梯度的位置)通過使用autograd被自動定義了。你可以在forward函數中使用任何Tensor的運算操作。

模型中可學習的變量通過net.parameters()傳回。

params = list(net.parameters())
print(len(params))
print(params[0].size())   # conv1's.weight           
神經網絡來襲!劃重點:60分鐘入門,這是最深入淺出的一次

随機生成一個32 32的輸入。注意: 這個網絡(LeNet)的預期輸入大小是 32 32。為了在個網絡使用MNIST資料,請将資料集中的圖像調整到32 * 32。

input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)           

先将參數(parameters)的梯度緩存設定0,再随機生成一個梯度。

net.zero_grad()
out.backward(torch.randn(1,10))           

注意:

torch.nn 隻支援小批量資料。所有的torch.nn包都隻支援輸入樣本為總樣本的一小批,不支援單個樣本。

例如:nn.Conv2d的輸入必須是4維的張量,形如:nSamples x nChannels x Height x Width。

如果隻有一個樣本,必須使用input.unsqueeze(0)将batchsize設定為1

在繼續之前,讓我們來回顧一下之前見過的類

回顧:

torch.Tensor 多元數組支援自動求導操作與backward()類似。

nn.Module 神經網絡子產品。友善的方式封裝參數, 幫助将其移動到GPU, 導出, 加載等.

nn.Parameter Tensor的一種,在被指定為 Module 的屬性時,會自動被注冊為一個參數。

autograd.Function 實作 autograd 操作的向前和向後定義..每個 Tensor 操作, 至少建立一個 Function 節點, 連接配接到建立 Tensor的函數, 并編碼它的曆史

到這裡, 我們已完成:

定義一個神經網絡

處理輸入并反向傳播

還剩下:

計算損失函數

更新網絡的權重

2.損失函數

損失函數采用 (output,target) 輸入對, 并計算預測輸出結果與實際目标的距離。

在 nn 包下有幾種不同的損失函數. 一個簡單的損失函數是: nn.MSELoss 計算輸出和目标之間的均方誤差。

如下例:

output = net(input)
target = torch.randn(10)  # a dummy target, for example
target = target.view(1, -1)  # make it the same shape as output
criterion = nn.MSELoss()

loss = criterion(output, target)
print(loss)           
神經網絡來襲!劃重點:60分鐘入門,這是最深入淺出的一次

現在, 如果你沿着 loss 反向傳播的方向使用 .grad_fn 屬性, 你将會看到一個如下所示的計算圖:

input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d -> view -> linear -> relu -> linear -> relu -> linear -> MSELoss -> loss           

是以, 當我們調用 loss.backward(), 整個圖與損失是有差別的, 圖中的所有變量都将用 .grad 梯度累加它們的變量.

為了說明, 讓我們向後走幾步:

print(loss.grad_fn)  # MSELoss
print(loss.grad_fn.next_functions[0][0])  # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])  # ReLU           
神經網絡來襲!劃重點:60分鐘入門,這是最深入淺出的一次

3.反向傳播

為了反向傳播誤差, 我們所要做的就是 loss.backward(). 你需要清除現有的梯度, 否則梯度會累加之前的梯度。

現在我們使用 loss.backward(), 看看反向傳播之前和之後 conv1 的梯度。

net.zero_grad()     # zeroes the gradient buffers of all parameters

print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)

loss.backward()

print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)           
神經網絡來襲!劃重點:60分鐘入門,這是最深入淺出的一次

現在,我們已經知道怎麼使用損失函數了。

稍後閱讀:

神經網絡類庫中包含很多子產品和損失函數,形成深度神經網絡子產品。完整的檔案清單在

http://t.cn/EIPR3z1

接下來唯一要學習的是:

更新網絡的權重。

4.更新權重

時間中使用的最簡單的更新規則是随機梯度下降(SGD):

weight = weight - learning_rate * gradient

我們可以使用簡單的python代碼實作:

learning_rate = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learning_rate)           

但是,當你使用神經網絡時,你可能想使用SGD,Nesterov-SGD,Adam,RMSProp等不同的更新規則。為了實作這些,我們建立了一個包: torch.optim ,實作了以上所有的方法。使用非常的簡單:

import torch.optim as optim

#建構優化器
optimizer = optim.SGD(net.parameters(), lr=0.01)

#訓練時循環的語句:
optimizer.zero_grad()   # 将梯度緩存清零。
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()    # 更新權重           
觀察如何使用手動設定梯度清零 optimizer.zero_grad() . 需要手動清零的原因在 Backprop_ 中已經說明了(梯度會累加之前的梯度)。

Type Markdown and LaTeX: α2

繼續閱讀