本文將介紹:
- torch.nn包
- 定義一個簡單的nn架構
- 定義優化器、損失函數
- 梯度的反向傳播
將使用LeNet-5架構進行說明
一、torch.nn包
torch.nn包來構建網絡;
torch.nn.Module類作為自定義類的基類;
nn.Module,包含了所有神經網絡層,比如卷積層或者是線性層;
torch.nn.Functional包,可以定義在前向傳播的時候的運算;比如,卷積、dropout以及激活函數
二、定義NN
我們將使用上述的類和包來定義NN
1 import torch 2 import torch.nn as nn 3 import torch.nn.functional as F
接下來,我們將使用torch.nn.Module來構建我們的NN
請記住,我們將嘗試構造出Lenet-5架構,代碼如下:
代碼詳解:
line3 在__init__函數中,我們首先調用了super()函數。這確保了我們繼承了nn.Module中的所有方法。現在我們就可以使用nn.Module中所有的方法和層。
從line4開始,網絡開始構建。
原始數據輸入 1, 32*32
首先有一個Conv2d(1, 6, (5, 5))卷基層;Conv2d參數為(輸入的通道,輸出通道,(核*核));6, 28*28
池化后:6,14*14
ConvConv2d(6, 16, (5, 5)):輸出: 16,10*10
池化后:16, 5*5
拉平:16*5*5=400
最后經過三個線性層,輸出10個維度的特征
需要注意的是:我們旨在__init__()中定義層,所有的操作都是在forward中進行的。
1 class Net(nn.Module): 2 def __init__(self): 3 super(Net, self).__init__() 4 self.conv1 = nn.Conv2d(1, 6, (5, 5)) # (input image channel, output channels, kernel size) 5 self.conv2 = nn.Conv2d(6, 16, (5, 5)) 6 # in linear layer (output channels from conv2d x width x height) 7 self.fc1 = nn.Linear(16 * 5 * 5, 120) # (in_features, out_features) 8 self.fc2 = nn.Linear(120, 84) 9 self.fc3 = nn.Linear(84, 10) 10 def forward(self, x): 11 x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) 12 x = F.max_pool2d(F.relu(self.conv2(x)), (2, 2)) 13 x = x.view(x.size(0), -1) ##這里卷積完成后,需要對其展平 14 x = F.relu(self.fc1(x)) #調用激活函數 15 x = F.relu(self.fc2(x)) 16 x = self.fc3(x) 17 return x 18 model = Net() #實例化一個NN類 19 print(model)
output:
1 Net( 2 (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1)) 3 (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1)) 4 (fc1): Linear(in_features=400, out_features=120, bias=True) 5 (fc2): Linear(in_features=120, out_features=84, bias=True) 6 (fc3): Linear(in_features=84, out_features=10, bias=True) 7 )
三、定義優化器和損失函數
為了定義優化器,我們需要輸入torch.optim,
優化器具有很多選擇,如RMSprop, Adam, SGD, Adadelta等
1 # loss function and optimizer 2 import torch.optim as optim 3 loss_function = nn.MSELoss() 4 optimizer = optim.RMSprop(model.parameters(), lr=0.001)
optmizer接收兩個參數,第一個是我們定義的模型參數,第二個是學習率。
四、輸入的數據和反向傳播
在此,我們生成隨機數據對網絡進行實現。
1 input = torch.rand(1, 1, 32, 32) 2 out = model(input) 3 print(out, out.shape)
輸出:
1 tensor([[-0.0265, -0.0181, 0.1301, 0.0465, 0.0697, 0.0765, -0.0022, 0.0215, 0.0908, -0.1489]], grad_fn=AddmmBackward) torch.Size([1, 10])
同樣的,如果我們需要定義一個真實的目標(label),因為我們需要計算損失。
在我們定義好我們的真實目標數據后,我們需要將其reshape成為[1,10]。
這是因為必須和輸出的形狀是相同的才可以計算損失。
1 # dummy targets 2 labels = torch.rand(10) 3 labels = labels.view(1, -1) # resize for the same shape as output 4 print(labels, labels.shape)
輸出:
1 tensor([[0.7737, 0.7730, 0.1154, 0.4876, 0.5071, 0.3506, 0.3078, 0.4576, 0.0926, 2 0.1268]]) torch.Size([1, 10])
五、反向傳播
1 loss = loss_function(out, labels) 2 loss.backward() 3 print(loss)
輸出:
tensor(0.2090, grad_fn=MseLossBackward)
需要注意的是,我們現在只有一個輸入。
實際上,我們將在train循環使用上面的代碼。每次循環的時候需要將梯度設為0.
梯度設為0的操作,可以通過optimizer.zero_grad()來實現;