什麼是pytorch(3神經網路)(翻譯)
神經網路
torch.nn
包可以用來構建神經網路。
前面介紹了 autograd包,
nn
依賴於 autograd
用於定義和求導模型。 nn.Module
包括layers(神經網路層), 以及forward函式 forward(input),其返回結果
output
.
例如我們來看一個手寫數字的網路:
這是一個簡單的前饋神經網路。接受輸入,向前傳幾層,然後輸出結果。
一個神經網路訓練的簡單過程是:
- 定義一個具有可學習引數的神經網路。
- 輸入資料集迭代
- 網路運算資料輸入的計算結果
- 計算損失 (how far is the output from being correct)
- 傳播梯度
- 跟新權值,通常可以簡單的使用梯度下降:
weight = weight - learning_rate * gradient
定義網路
先來頂一個網路:
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 input image channel, 6 output channels, 5x5 square convolution # kernel self.conv1 = nn.Conv2d(1, 6, 5) self.conv2 = nn.Conv2d(6, 16, 5) # an affine operation: 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): # Max pooling over a (2, 2) window x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # If the size is a square you can only specify a single number x = F.max_pool2d(F.relu(self.conv2(x)), 2) 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:] # all dimensions except the batch dimension num_features = 1 for s in size: num_features *= s return num_features net = Net() print(net)
Out:
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) )
你只需要定義前向傳播函式 forward
, 後向傳播函式 backward
(梯度的計算) 就會使用autograd自動定義。你可以在forward函式裡使用任何Tensor的運算。
網路的學習到的引數可以通過net.parameters()獲取。
params = list(net.parameters()) print(len(params)) print(params[0].size()) # conv1's .weight
輸出:
10 torch.Size([6, 1, 5, 5])
讓我們隨機輸入一個 32x32 的資料。Note: Expected input size to this net(LeNet) is 32x32.
要把MNIST dataset作為該網路的資料集,需要把資料 resize到32x32.
input = torch.randn(1, 1, 32, 32) out = net(input) print(out)
輸出:
tensor([[ 0.1246, -0.0511, 0.0235, 0.1766, -0.0359, -0.0334, 0.1161, 0.0534, 0.0282, -0.0202]], grad_fn=<ThAddmmBackward>)
使所有引數的梯度恢復為0,然後使用隨機梯度後向傳播:
net.zero_grad()
out.backward(torch.randn(1, 10))
注意:
torch.nn
只支援mini-batches. 整個 torch.nn
包只接受批樣本,不接受單個樣本。
例如, nn.Conv2d
接受一個4D的張量形如: nSamples x nChannels x Height x Width
.
如果你只有一個樣本,那就使用 input.unsqueeze(0)
創造一個假的mini-batch。
在進一步之前,我們來回顧目前你所見到的所有類。
- 回顧:
-
torch.Tensor
- 一個多維度的陣列,支援自動梯度backward()。其梯度任然儲存在張量裡。
nn.Module
- 神經網路模型。方便的封裝引數,可以匯出模型到GPU,載入模型,匯出模型等。nn.Parameter
- 一種張量, 自動註冊為paramter當賦給Module作為屬性
。autograd.Function
- 實現 forward and backward 的定義,包括autograd. EveryTensor
operation, creates at least a singleFunction
node, that connects to functions that created aTensor
and encodes its history.
- 到此, 我們覆蓋了:
-
- 定義一個網路
- 處理輸入和反向傳播。
- 剩餘的內容:
-
- 計算損失
- 更新網路的引數
損失函式
一個損失函式接受(output,targe)對作為輸入,計算output和target相差的程度。
nn包裡有多種不同的 loss functions 。最簡單的損失函式是: nn.MSELoss
,計算(output,target)間的均方誤差損失函式。
For example:
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)
輸出:
tensor(1.3638, grad_fn=<MseLossBackward>)
Now, if you follow loss
in the backward direction, using its .grad_fn
attribute, you will see a graph of computations that looks like this:
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d -> view -> linear -> relu -> linear -> relu -> linear -> MSELoss -> loss
現在我們使用 loss.backward()
,就會被 loss所微分, 所有計算圖裡引數屬性為 requires_grad=True
將會使 .grad
Tensor 和gradient累加起來。
For illustration, let us follow a few steps backward:
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
Out:
<MseLossBackward object at 0x7f0e86396a90> <ThAddmmBackward object at 0x7f0e863967b8> <ExpandBackward object at 0x7f0e863967b8>
反向傳播
為了反向傳播誤差,我們必須使用loss.backward()
. 首先需要清除已存在的梯度,然後把梯度累加起來。
現在我們就可以呼叫:loss.backward()
, 我們來看看 conv1’s bias gradients 在反向傳播前後。
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)
輸出:
conv1.bias.grad before backward tensor([0., 0., 0., 0., 0., 0.]) conv1.bias.grad after backward tensor([ 0.0181, -0.0048, -0.0229, -0.0138, -0.0088, -0.0107])
現在,我們來看如何使用損失函式。
進一步閱讀:
nn包包括了各種型別的模型和損失函式,可以用來構建深度神經網路的block,詳細參閱nn的文件: here.
最後一步需要學習的是:
- 跟新網路的引數
跟新權重Update the weights
最簡單方式就是使用隨機梯度下降(SGD):
weight = weight - learning_rate * gradient
可以使用以下程式碼:
learning_rate = 0.01
for f in net.parameters(): f.data.sub_(f.grad.data * learning_rate)
神經網路裡可以使用各種跟新權重的方法, 比如:SGD, Nesterov-SGD, Adam, RMSProp, etc等,為了使用這些方法,有一個小包 : torch.optim
實現了這些方法。
用起來非常的容易:
import torch.optim as optim
# create your optimizer
optimizer = optim.SGD(net.parameters(), lr=0.01) # in your training loop: optimizer.zero_grad() # zero the gradient buffers output = net(input) loss = criterion(output, target) loss.backward() optimizer.step() # Does the update
注意:
使用optimizer.zero_grad()把網路的引數梯度手動設定為0.前面在Backprop說了,梯度會累加起來的
。