注意:在观看本笔记前,你应该对Python、神经网络有基本的概念上的了解
神经网络可以用torch.nn创建
例子:手写数字识别神经网络
定义神经网络
定义类
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个输入图像通道,6个输出通道,5×5方形卷积
# kernel
self.conv1 = nn.Conv2d(1, 6, 5)
self.conv2 = nn.Conv2d(6, 16, 5)
# 一个仿射变换:y = Wx + b
self.fc1 = nn.Linear(16 * 5 * 5, 120) # 5*5:图像维度
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# 通过(2, 2)窗口的最大池化
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
# 如果size是方形,可以用1个数字指定
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
x = torch.flatten(x, 1) # 扁平化除了batch维之外的维度
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
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, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)
(backward函数会自动由autograd生成)
参数
params = list(net.parameters())
print(len(params))
print(params[0].size()) # conv1的权重
(可学习的参数由net.parameters()返回)
输出:
10
torch.Size([6, 1, 5, 5])
获取随机的32×32输入并得到输出
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
(这个网络的输入必须是32×32)
输出:
tensor([[-0.0013, -0.0198, -0.0745, -0.0067, -0.0456, 0.0398, -0.0620, 0.0607,
0.0924, 0.0445]], grad_fn=<AddmmBackward0>)
反向传播
net.zero_grad()
out.backward(torch.randn(1, 10)) # 用随机梯度反向传播
损失函数
MSE损失函数
output = net(input)
target = torch.randn(10) # 简单的一个示例target
target = target.view(1, -1) # 使维度和output一样
criterion = nn.MSELoss()
loss = criterion(output, target)
print(loss)
输出:
tensor(0.9642, grad_fn=<MseLossBackward0>)
反向传播
一旦调用loss.backward(),所有参数的梯度将会被累积。
net.zero_grad() # 把所有的梯度缓存清零
print('反向传播之前的conv1.bias.grad')
print(net.conv1.bias.grad)
loss.backward() # 反向传播
print('反向传播之后的conv1.bias.grad')
print(net.conv1.bias.grad)
输出:
反向传播之前的conv1.bias.grad
tensor([0., 0., 0., 0., 0., 0.])
反向传播之后的conv1.bias.grad
tensor([ 0.0032, 0.0048, -0.0005, -0.0062, 0.0045, 0.0166])
(有关nn中的模型和损失函数的文档)
更新权重
最简单的更新方法是随机梯度下降(Stochastic Gradient Descent, SGD)
weight = weight - learning_rate * gradient
使用Python实现SGD:
learning_rate = 0.01
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
实际编程中,可以使用torch.optim:
import torch.optim as optim
# 创建优化器
optimizer = optim.SGD(net.parameters(), lr=0.01)
# 在训练循环中:
optimizer.zero_grad() # 清空梯度缓存
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step() # 更新参数