07_利用pytorch的nn工具箱實作LeNet網路
目錄- 一、引言
- 二、定義網路
- 三、損失函式
- 四、優化器
- 五、資料加載和預處理
- 六、Hub模塊簡介
- 七、總結
pytorch完整教程目錄:https://www.cnblogs.com/nickchen121/p/14662511.html
一、引言
首先再次安利一篇文章,這篇文章詳細介紹了如果使用一個深度神經網路去實作人臉識別,這里面對卷積、池化、全連接、激活函式都有一個較為詳細的解釋,看完這篇文章,再來看這篇文章,相信會有一種醍醐灌頂之效:06-01 DeepLearning-影像識別
上一篇文章我們介紹了實作反向傳播的 autograd 這個工具,但是如果直接用這個來寫深度學習的代碼,對于神經網路中各種層的定義就足夠讓人頭疼了,所以還是有一點復雜,
因此在 torch 中,torch.nn 的出現就是專門為神經網路設計的模塊化介面,nn 構建與 autograd 之上,可以用來定義和運行神經網路,其中 nn.Module 是 nn 中最重要的類,可以把它看作是一個網路的封裝,包含網路中各層的定義和 forward 方法,呼叫 forward(input) 方法,可以輕松的實作前向傳播,
接下來我們將以卷積神經網路 LeNet 網路為例,看看如何用 nn.Module 實作,其中 LeNet 網路架構如下圖所示:
上述圖示是一個基礎的前向傳播網路:接收輸入,經過層層傳遞運算,得到一個輸出,
當然,這篇文章的重心是告訴我們如何利用 nn 這個工具箱搭建一個基礎的神經網路架構,至于 nn 的具體用法將在未來的分享中詳細介紹,也就是說這一篇文章只是籠統的介紹 nn,只要看清楚本篇文章的大體脈絡即可,至于細節未來都會一一介紹,
二、定義網路
定義網路的時候需要繼承 nn.Module,并實作它的的 forward 方法,把網路中具有可學習引數的層放到建構式 __init__ 中,如果某一層不具有可學習的引數,則即可以放在建構式中,也可以不放入,
import torch as t
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable as V
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__() # nn.Module 子類的函式必須在建構式中執行父類的建構式
# 卷積層
self.conv1 = nn.Conv2d(1, 6,
5) # '1'表示輸入圖片為單通道,‘6’表示輸出通道數,‘5’表示卷積核為 5*5
self.conv2 = nn.Conv2d(6, 16, 5)
# 仿射層/全連接層,y = Wx + b
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# 卷積-》激活-》池化
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
# reshape,‘-1’表示自適應
x = x.view(x.size()[0], -1)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
net
Net(
(conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear(in_features=400, out_features=120, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)
通過 nn.module 成功定義網路結構后,有3個點需要注意:
- 只要在
nn.Module的子類中定義了 forward 函式,backward 函式就會自動實作 - 網路的可學習引數通過
net.parameters()回傳,net.named_parameters可同時回傳可學習的引數和名稱 - 只有 Variable 才有自動求導功能,因此forward 函式的輸入和輸出都是 Variable,所以在輸入時,需要把 Tensor 封裝成 Variable
params = list(net.parameters())
len(params)
10
for name, parameters in net.named_parameters():
print(f'{name}: {parameters.size()}')
conv1.weight: torch.Size([6, 1, 5, 5])
conv1.bias: torch.Size([6])
conv2.weight: torch.Size([16, 6, 5, 5])
conv2.bias: torch.Size([16])
fc1.weight: torch.Size([120, 400])
fc1.bias: torch.Size([120])
fc2.weight: torch.Size([84, 120])
fc2.bias: torch.Size([84])
fc3.weight: torch.Size([10, 84])
fc3.bias: torch.Size([10])
input = V(t.randn(1, 1, 32, 32)) # 定義輸入
out = net(input)
out.size() # 輸出的形狀
torch.Size([1, 10])
net.zero_grad() # 所有引數的梯度清零
out.backward(V(t.ones(1, 10))) # 反向傳播
注:torch.nn只支持 mini-batches,不支持一次輸入一個樣本,如果想一次輸入一個樣本,可以用 input.unsqueeze(0) 把 batch_size 設定為 1,例如,nn.Conv2d輸入必須是 4 維的,形如nSamples × nChannels × Height × Width,可以讓 nSample 設為 1,也就是 1 × nChannels × Height × Width`
三、損失函式
nn 實作了神經網路中大多數的損失函式,例如 nn.MSELoss 計算均方誤差,nn.CrossEntropyLoss 計算交叉熵損失,
output = net(input) # net(input)的輸出的形狀是(1,10)
target = V(t.arange(0, 10)).view(1, 10).float()
criterion = nn.MSELoss()
loss = criterion(output, target)
loss
tensor(28.5546, grad_fn=<MseLossBackward>)
如果對 loss 進行反向傳播溯源(使用 grad_fn 屬性),可以看到它的計算圖如下:
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
-> view -> linear -> relu -> linear -> relu -> linear
-> MSELoss
-> loss
當呼叫 loss.backward() 時,該圖會動態生成并自動微分,也會自動計算圖中引數的導數
# 運行.backward,觀察呼叫之前和呼叫之后的 grad
net.zero_grad() # 把 net 中所有可學習引數的梯度清零
print(f'反向傳播之前conv1.bias 的梯度:{net.conv1.bias.grad}')
loss.backward()
print(f'反向傳播之后conv1.bias 的梯度:{net.conv1.bias.grad}')
反向傳播之前conv1.bias 的梯度:tensor([0., 0., 0., 0., 0., 0.])
反向傳播之后conv1.bias 的梯度:tensor([ 0.1055, 0.0943, -0.1617, 0.0416, -0.0787, 0.0285])
四、優化器
在反向傳播完成所有引數的梯度計算后,還需要使用優化方法更新網路的權重和引數,在 torch.optim 中實作了深度學習中絕大多數的優化方法,這里不詳解介紹,未來會詳細介紹,目前能成為一個合格的調包俠即可,
import torch.optim as optim
# 新建一個優化器,指定要調整的引數和學習率
optimizer = optim.SGD(net.parameters(), lr=0.01)
# 在訓練程序中,先將梯度清零(和 net.zero_grad()效果一樣)
optimizer.zero_grad()
# 計算損失
output = net(input)
loss = criterion(output, target)
# 反向傳播
loss.backward()
# 更新引數
optimizer.step()
五、資料加載和預處理
在深度學習中資料加載和預處理是非常麻煩的,但是 torch 提供了一些列簡化和加快處理資料的工具,未來我們也都會詳解介紹,并且torch 也把一些常用的資料集都保存在了 torchvision 中,
六、Hub模塊簡介
上面給出了定義一個完整的神經網路的流程,但是還是太復雜了,如果你僅僅只是想使用一個神經網路模型完成自己的一個小demo,而不是自己費盡心思的寫一個模型出來,那么hub模塊就可以滿足你的要求,你可以從hub模塊官網獲取任何一個已存的模塊,然后丟入你的資料就可以獲得結果,而不需要自己巴拉巴拉寫一堆代碼,也就是說,別人用輪子造航母,你直接把航母拿來用,
以下就是hub模塊的大概用法,當然,更詳細的內容可以去官網查詢:
import torch
model = torch.hub.load('pytorch/vision:v0.4.2', 'deeplabv3_resnet101', pretrained=True) # 加載模型,第一次加載需要一點點時間
model.eval() # 釋放模型
七、總結
上面籠統的介紹了如何利用 nn 這個工具箱去搭建一個神經網路,但是只給出了一個流程,很多細節我們還沒有詳細解釋,但這已經足夠了,
下一篇文章我們就將詳細介紹 nn 工具箱的各種細節方面的東西,等你看完下一篇文章如果再跳回來看這篇文章,相信定會有醍醐灌頂之效,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/279208.html
標籤:其他
上一篇:07_利用pytorch的nn工具箱實作LeNet網路
下一篇:擴展CRT(擴展中國剩余定理)
