神经网络的搭建
Pytorch搭建神经网络的核心包是torch.nn,训练神经网络的典型过程如下:
定义具有一些可学习参数(或权重)的神经网络;
遍历输入数据集;
进行正向传播;
计算损失;
进行反向传播,计算参数的梯度;
更新参数(权重)。
在Pytorch中,各部分的操作如下。
导入包
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
神经网络的定义与正向传播
这里定义一个包含两个卷积层、两个最大池化层的网络,具体结构为:
conv —> relu —> max_pool —> conv —> relu —> max_pool —> linear —> relu —> linear
—> relu —> linear
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 1 input image channel, 6 output channels, 3x3 square convolution kernel
self.conv1 = nn.Conv2d(1, 6, 3)
self.conv2 = nn.Conv2d(6, 16, 3)
# an affine operation: y = Wx + b
self.fc1 = nn.Linear(16 * 6 * 6, 120) # 6*6 from image dimension
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
定义完成后可以使用print函数查看定义的网络:
net = Net()
print(net)
结果如下:
损失函数
损失函数反映了输出值与目标值之间的差距,是机器学习的过程中的重要部分,Pytorch提供了许多不同的损失函数,如MSELoss计算均方差。损失函数定义方法如下:
# 随机产生一个输入,本神经网络期待的输入为32x32
input = torch.randn(1, 1, 32, 32)
target = torch.randn(10) # a dummy target, for example
target = target.view(1, -1) # make it the same shape as output
criterion = nn.MSELoss() # use MSELoss
loss = criterion(output, target)
print(loss)
反向传播
反向传播是机器学习的精髓所在,在进行反向传播的过程中计算出损失函数对于各参数的梯度,为参数的更新做准备。现在的神经网络框架几乎都支持自动计算反向传播,从而简化了复杂的数学运算。对Pytorch来说,它会动态构建一张操作图,对需要求梯度的张量进行追踪,进行反向传播时,根据构建的操作图从叶节点开始根据链式法则求梯度,并将对应结果保存在相应叶节点的grad变量中。
反向传播的执行通常只需要一行代码:
loss.backward() # 进行反向传播
Note:由于链式法则,Pytorch会自动将各梯度结果相乘,因此进行反向传播前,需要将梯度缓冲区的所有参数清零,使用成员方法zero_grad()即可。
更新参数
更新参数最简单最常用的方法是随机梯度下降(SGD),公式是W = W - learning_rate * dW。
除了SGD外,Pytorch还提供了Nesterov-SGD, Adam, RMSProp等不同的参数更新方法,这些都封装在torch.optim包中,使用方法也很简单:
optimizer = optim.SGD(net.parameters(), lr=0.01) # use SGD, learning_rate=0.01
optimizer.zero_grad() # 梯度缓冲区清零
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step() # 更新参数
至此,训练神经网络的各部分操作已经介绍完毕。下一篇中将会结合数据集进行神经网络的训练。