總結一下相關概念:
- torch.Tensor - 一個近似多維數組的數據結構
- autograd.Variable - 改變Tensor並且記錄下來操作的歷史記錄。和Tensor擁有相同的API,以及backward()的一些API。同時包含着和張量相關的梯度
- nn.Module - 神經網絡模塊,便捷的數據封裝,能夠將運算移往GPU,還包括一些輸入輸出的東西
- nn.Parameter - 一種變量(Variable),當將任何值賦予Module時自動注冊為一個參數
- autograd.Function - 實現了使用自動求導方法的前饋和后饋的定義。每個Variable的操作都會生成至少一個獨立的Function節點,與生成了Variable的函數相連之后記錄下操作歷史
導入庫:
# Author : Hellcat # Time : 2018/2/10 import torch as t import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torch.autograd import Variable
torch.nn:網絡層
torch.nn.functional:激活函數、池化函數歸於此模塊
pytorch中的網絡層是class,而tensorflow
print(t.nn.Conv2d)
<class 'torch.nn.modules.conv.Conv2d'>
print(tf.nn.conv2d)
<function conv2d at 0x000001A33CC44510>
網絡主體:
net網絡要使用class並繼承父類才行,因而有一些自帶的方法
net.parameters():返回全部的參數值,迭代器
net.named_parameters():返回參數名稱和值,迭代器
net.參數名:就是參數變量,Variable,可以直接查看data和grad等等
class Net(nn.Module):
def __init__(self):
# nn.Module子類的函數必須在構造函數中執行父類的構造函數
# 等價於nn.Model.__init__(self)
super(Net,self).__init__()
# 輸入1通道,輸出6通道,卷積核5*5
self.conv1 = nn.Conv2d(1, 6, 5)
# 定義卷積層:輸入6張特征圖,輸出16張特征圖,卷積核5x5
self.conv2 = nn.Conv2d(6,16,5)
# 定義全連接層:線性連接(y = Wx + b),16*5*5個節點連接到120個節點上
self.fc1 = nn.Linear(16*5*5,120)
# 定義全連接層:線性連接(y = Wx + b),120個節點連接到84個節點上
self.fc2 = nn.Linear(120,84)
# 定義全連接層:線性連接(y = Wx + b),84個節點連接到10個節點上
self.fc3 = nn.Linear(84,10)
# 定義向前傳播函數,並自動生成向后傳播函數(autograd)
def forward(self,x):
# 輸入x->conv1->relu->2x2窗口的最大池化->更新到x
x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
# 輸入x->conv2->relu->2x2窗口的最大池化->更新到x
x = F.max_pool2d(F.relu(self.conv2(x)),2)
# view函數將張量x變形成一維向量形式,總特征數不變,為全連接層做准備
x = x.view(x.size()[0], -1)
# 輸入x->fc1->relu,更新到x
x = F.relu(self.fc1(x))
# 輸入x->fc2->relu,更新到x
x = F.relu(self.fc2(x))
# 輸入x->fc3,更新到x
x = self.fc3(x)
return x
if __name__ == "__main__":
net = Net()
展示網絡參數:
# #########查看參數#########
print(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)
(fc2): Linear(in_features=120, out_features=84)
(fc3): Linear(in_features=84, out_features=10)
)
"""
# 返回參數值:順序和下面的named一致
params = list(net.parameters())
print(len(params))
"""
10
"""
# net.named_parameters(): ((參數名稱,參數屬性),……)
for name, parameters in net.named_parameters():
print(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])
"""
模擬單次向前&向后傳播:
# #########網絡傳播過程模擬#########
# 輸入如果沒有batch數,則少一維度,Tensor,unsqueeze()可以為張量擴維
input_ = Variable(t.randn(1, 1, 32, 32))
out = net(input_)
print(out.size())
"""
torch.Size([1, 10])
"""
# net.zero_grad()
# 輸出值為10個標量(一個向量),所以需要指定每個標量梯度的權重
# out.backward(t.ones(1,10))
注意: torch.nn 只接受小批量的數據
整個torch.nn包只接受那種小批量樣本的數據,而非單個樣本。 例如,nn.Conv2d能夠結構一個四維的TensornSamples x nChannels x Height x Width。
如果你拿的是單個樣本,使用input.unsqueeze(0)來加一個假維度就可以了。
維度是[batch,channel,height,width]。
Loss函數構建
# #########Loss設計#########
target = Variable(t.arange(0,10))
# Loss需要先實例化,然后是callable的實例
loss_fn = nn.MSELoss() # 均方誤差
loss = loss_fn(out, target)
print(loss)
net.zero_grad()
print("反向傳播之前:", net.conv1.bias.grad)
loss.backward()
print("反向傳播之后:", net.conv1.bias.grad)
反向傳播之前: None
反向傳播之后: Variable containing:
-0.1330
-0.0888
-0.0101
-0.0186
0.0462
0.0317
[torch.FloatTensor of size 6]
優化器構建
# #########優化器設計#########
print(net.parameters())
"""
<generator object Module.parameters at 0x0000021B525BE888>
"""
# 初始化優化器
optimizer = optim.SGD(net.parameters(), lr=0.01)
optimizer.zero_grad() # 效果等同net.zero_grad()
output = net(input_)
loss = loss_fn(output, target)
loss.backward()
print("反向傳播之前:", net.conv1.bias.data)
optimizer.step()
print("反向傳播之后:", net.conv1.bias.data)
反向傳播之前:
-0.1702
0.1192
0.1349
0.1307
-0.0141
-0.0558
[torch.FloatTensor of size 6]
反向傳播之后:
-0.1689
0.1201
0.1350
0.1309
-0.0146
-0.0561
[torch.FloatTensor of size 6]
