使用PyTorch構建神經網絡十分的簡單,下面是我總結的PyTorch構建神經網絡的一般過程以及我在學習當中遇到的一些問題,期望對你有所幫助。
PyTorch構建神經網絡的一般過程
下面的程序是PyTorch官網60分鍾教程上面構建神經網絡的例子,版本0.4.1:
import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
# 第一步:准備數據
# Compose是將兩個轉換的過程組合起來,ToTensor將numpy等數據類型轉換為Tensor,將值變為0到1之間
# Normalize用公式(input-mean)/std 將值進行變換。這里mean=0.5,std=0.5,是將[0,1]區間轉換為[-1,1]區間
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
# trainloader 是一個將數據集和采樣策略結合起來的,並提供在數據集上面迭代的方法
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
shuffle=True, num_workers=0)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
shuffle=False, num_workers=0)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# 第二步:構建神經網絡框架,繼承nn.Module類
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
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 = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
# 第三步:進行訓練
# 定義損失策略和優化方法
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# 訓練神經網絡
for epoch in range(4):
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data
optimizer.zero_grad()
# 訓練過程1:前向過程,計算輸入到輸出的結果
outputs = net(inputs)
# 訓練過程2:由結果和label計算損失
loss = criterion(outputs, labels)
# 訓練過程3:在圖的層次上面計算所有變量的梯度
# 每次計算梯度的時候,其實是有一個動態的圖在里面的,求導數就是對圖中的參數w進行求導的過程
# 每個參數計算的梯度值保存在w.grad.data上面,在參數更新時使用
loss.backward()
# 訓練過程4:進行參數的更新
# optimizer不計算梯度,它利用已經計算好的梯度值對參數進行更新
optimizer.step()
running_loss += loss.item() # item 返回的是一個數字
if i % 2000 == 1999:
print('[%d, %5d] loss: %.3f' %
(epoch+1, i+1, running_loss/2000))
running_loss = 0.0
print('Finished Training')
# 第四步:在測試集上面進行測試
total = 0
correct = 0
with torch.no_grad():
for data in testloader:
images, label = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == label).sum().item()
print("Accuracy of networkd on the 10000 test images: %d %%" % (100*correct/total))
這個例子說明了構建神經網絡的四個步驟:1:准備數據集 。2:構建神經網絡框架,實現神經網絡的類。 3:在訓練集上進行訓練。 4:在測試集上面進行測試。
而在第三步的訓練階段,也可以分為四個步驟:1:前向過程,計算輸入到輸出的結果。2:由結果和labels計算損失。3:后向過程,由損失計算各個變量的梯度。4:優化器根據梯度進行參數的更新。
訓練過程中第loss和optim是怎么聯系在一起的
loss是訓練階段的第三步,計算參數的梯度。optim是訓練階段的第四步,對參數進行更新。在optimizer初始化的時候,optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9),獲取了參數的指針,可以對參數進行修改。當loss計算好參數的梯度以后,把值放在參數w.grad.data上面,然后optimizer直接利用這個值對參數進行更新。
以SGD為例,它進行step的時候的基本操作是這樣的: p.data.add_(-group['lr'], d_p),其中 d_p = p.grad.data
為什么要進行梯度清零
在backward每次計算梯度的時候,會將新的梯度值加到原來舊的梯度值上面,這叫做梯度累加。下面的程序可以說明什么是梯度累加:
import torch
x = torch.rand(2, requires_grad=True)
y = x.mean() # y = (x_1 + x_2) / 2 所以求梯度后應是0.5
y.backward()
print(x.grad.data) # 輸出結果:tensor([0.5000, 0.5000])
y.backward()
print(x.grad.data) # 輸出結果:tensor([1., 1.]) 說明進行了梯度累積
求解梯度過程和參數更新過程是分開的,這對於那些需要多次求導累計梯度,然后一次更新的神經網絡可能是有幫助的,比如RNN,對於DNN和CNN不需要進行梯度累加,所以需要進行梯度清零。
如何使用GPU進行訓練
舊版本:
use_cuda = True if torch.cuda.is_available() else False # 是否使用cuda
if use_cuda:
model = model.cuda() # 將模型的參數放入GPU
if use_cuda:
inputs, labels = inputs.cuda(), labels.cuda() # 將數據放入到GPU
0.4版本以后推薦新方法 to(device),
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
net.to(device) #將模型的參數放入GPU中
inputs, labels = inputs.to(device), labels.to(device) # 將數據放入到GPU中
參考:
Pytorch內部中optim和loss是如何交互的? - 羅若天的回答 - 知乎
pytorch學習筆記(二):gradient
