1、引言
首先再次安利一篇文章,這篇文章詳細介紹了若是使用一個深度神經網絡去實現人臉識別,這裏面對卷積、池化、全鏈接、激活函數都有一個較爲詳細的解釋,看完這篇文章,再來看這篇文章,相信會有一種醍醐灌頂之效:06-01 DeepLearning-圖像識別網絡
上一篇文章咱們介紹了實現反向傳播的 autograd 這個工具,可是若是直接用這個來寫深度學習的代碼,對於神經網絡中各類層的定義就足夠讓人頭疼了,因此仍是有一點複雜。架構
所以在 torch 中,torch.nn 的出現就是專門爲神經網絡設計的模塊化接口,nn 構建與 autograd 之上,能夠用來定義和運行神經網絡。其中 nn.Module 是 nn 中最重要的類,能夠把它看做是一個網絡的封裝,包含網絡中各層的定義和 forward 方法,調用 forward(input) 方法,能夠輕鬆的實現前向傳播。ide
接下來咱們將以卷積神經網絡 LeNet 網絡爲例,看看如何用 nn.Module 實現,其中 LeNet 網絡架構以下圖所示:模塊化
上述圖示是一個基礎的前向傳播網絡:接收輸入,通過層層傳遞運算,獲得一個輸出。函數
固然,這篇文章的重心是告訴咱們如何利用 nn 這個工具箱搭建一個基礎的神經網絡架構,至於 nn 的具體用法將在將來的分享中詳細介紹,也就是說這一篇文章只是籠統的介紹 nn,只要看清楚本篇文章的大致脈絡便可,至於細節將來都會一一介紹。工具
2、定義網絡定義網絡的時候須要繼承 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個點須要注意:優化
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`設計
3、損失函數nn 實現了神經網絡中大多數的損失函數,例如 nn.MSELoss 計算均方偏差,nn.CrossEntropyLoss 計算交叉熵損失。blog
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])4、優化器
在反向傳播完成全部參數的梯度計算後,還須要使用優化方法更新網絡的權重和參數。在 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()5、數據加載和預處理
在深度學習中數據加載和預處理是很是麻煩的,可是 torch 提供了一些列簡化和加快處理數據的工具,將來咱們也都會詳解介紹。而且torch 也把一些經常使用的數據集都保存在了 torchvision 中。
6、Hub模塊簡介上面給出了定義一個完整的神經網絡的流程,可是仍是太複雜了,若是你僅僅只是想使用一個神經網絡模型完成本身的一個小demo,而不是本身費盡心思的寫一個模型出來,那麼hub模塊就能夠知足你的要求,你能夠從hub模塊官網獲取任何一個已存的模塊,而後丟入你的數據就能夠得到結果,而不須要本身巴拉巴拉寫一堆代碼。也就是說,別人用輪子造航母,你直接把航母拿來用。
如下就是hub模塊的大概用法,固然,更詳細的內容能夠去官網查詢:
import torch model = torch.hub.load('pytorch/vision:v0.4.2', 'deeplabv3_resnet101', pretrained=True) # 加載模型,第一次加載須要一點點時間 model.eval() # 釋放模型7、總結
上面籠統的介紹瞭如何利用 nn 這個工具箱去搭建一個神經網絡,可是隻給出了一個流程,不少細節咱們尚未詳細解釋,但這已經足夠了。
下一篇文章咱們就將詳細介紹 nn 工具箱的各類細節方面的東西,等你看完下一篇文章若是再跳回來看這篇文章,相信定會有醍醐灌頂之效。