记录一下自己学 pytorch,学习的资料为 pytorch 的中文文档,传送门:https://pytorch.apachecn.org/docs/1.4/blitz/neural_networks_tutorial.html
# 可以使用 torch.nn 包来构建神经网络
# 已经介绍了 autograd 包, nn 包则依赖于 autograd 包来定义模型并对它们求导。
# 一个 nn.Module 包含各个层和一个 forward(input) 方法,该方法返回 output。
# 一个神经网络的典型训练过程如下:
# 1. 定义包含一些可学习参数(或者叫做权重)的神经网络
# 2. 在输入数据集上迭代
# 3. 通过网络处理输入
# 4. 计算 loss(输出和正确答案的距离)
# 5. 将梯度反向传播给网络的参数
# 6. 更新网络的权重,一般使用一个简单的规则: weight = weight - learning_rate * gradient
# 定义网络
# 让我们定义一个这样的网络:
import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 输入图像 channel: 1;输出 channel: 6; 5 x 5 卷积核
self.conv1 = nn.Conv2d(1, 6, 5)
self.conv2 = nn.Conv2d(6, 16, 5)
# an affine operation: y = Wx + b
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# 2 x 2 Max pooling
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
# 如果是方阵,则可以只使用一个数字进行定义
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:] # 除去批处理维度的其他所有维度
num_features = 1
for s in size:
num_features *= s
return num_features
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)
)
# 只需要定义 forward 函数, backward 函数会使用 autograd 时自动定义, backward 函数用来计算导数。
# 可以在 forward 函数中使用任何针对张量的操作和计算
# 一个模型的可学习参数可以通过 net.parameters() 返回
params = list(net.parameters())
print(len(params))
print(params[0].size()) # conv1's .weight
#输出为:
10
torch.Size([6, 1, 5, 5])
for i in range(len(params)):
print(params[i].size())
#输出为:
torch.Size([6, 1, 5, 5])
torch.Size([6])
torch.Size([16, 6, 5, 5])
torch.Size([16])
torch.Size([120, 400])
torch.Size([120])
torch.Size([84, 120])
torch.Size([84])
torch.Size([10, 84])
torch.Size([10])
# 尝试一个随机的 32 x 32 的输入。注意这个网络(LeNet)的期待输入是 32 x 32 的张量。
# 如果使用 MNIST 数据集来训练这个网络,要把图片大小重新调整到 32 x 32。
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
# 输出为:
tensor([[-0.0884, -0.0955, -0.1157, -0.0185, -0.0328, 0.0188, 0.0193, -0.1154,
0.0448, -0.0642]], grad_fn=<AddmmBackward>)
# 清零所有参数的梯度缓存,然后进行随机梯度反向传播:
net.zero_grad()
out.backward(torch.randn(1, 10))
# 损失函数
# 一个损失函数接受一对(output,target)作为输入,计算一个值来估计网络的输出和目标值相差多少。
# nn 包中有很多不同的损失函数。 nn.MSELoss 是比较简单的一种,它计算输出和目标的均方误差
output = net(input)
target = torch.randn(10)
target = target.view(1, -1)
criterion = nn.MSELoss()
loss = criterion(output, target)
print(loss)
#输出为:
tensor(1.3201, grad_fn=<MseLossBackward>)
# 现在,如果使用 loss 的 .grad_fn 属性跟踪反向传播过程,会看到计算图如下:
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
-> view -> linear -> relu -> linear -> relu -> linear
-> MSELoss
-> loss
# 所以,当调用 loss.backward(),整张图开始关于 loss 微分,图中所有设置了 requires_grad=True 的张量 .grad 属性累积着张量梯度。
print(loss.grad_fn)
print(loss.grad_fn.next_functions[0][0])
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])
#输出为:
<MseLossBackward object at 0x7f4d00808908>
<AddmmBackward object at 0x7f4d008089b0>
<AccumulateGrad object at 0x7f4d00808908>
# 反向传播
# 只需要调用 loss.backward() 来反向传播误差。需要清零现有的梯度,否则梯度将会与已有的梯度累加。
# 现在,将调用 loss.backward(),并且查看 conv1 层的偏置在反向传播前后的梯度。
net.zero_grad()
print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)
loss.backward()
print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)
#输出为:
conv1.bias.grad before backward
tensor([0., 0., 0., 0., 0., 0.])
conv1.bias.grad after backward
tensor([ 0.0120, -0.0098, -0.0056, 0.0060, 0.0059, -0.0120])
# 更新权重
# 最简单的更新规则是随机梯度下降法(SGD)
# weight = weight - learning_rate * gradient
learning_rate = 0
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
# 然而,在使用神经网络时,可能希望使用各种不同的更新规则,如 SGD,Nesterov-SGA、Adam、RMSProp 等。
# 为此,可以使用 torch.optim
import torch.optim as optim
# 创建优化器(optimizer)
optimizer = optim.SGD(net.parameters(), lr=0.01)
# 在训练的迭代中:
optimizer.zero_grad() # 清零梯度缓存
print(net.conv1.weight.grad)
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()
print(net.conv1.weight.grad)
#输出为:
tensor([[[[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]]],
[[[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]]],
[[[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]]],
[[[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]]],
[[[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]]],
[[[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]]]])
tensor([[[[ 1.4132e-03, 3.0524e-03, 1.4387e-02, -6.9879e-05, 5.0496e-03],
[ 6.2602e-03, 7.7174e-04, 7.7477e-03, 4.8251e-03, -6.2586e-03],
[-1.1347e-02, 1.7323e-02, 1.4601e-03, 4.7047e-03, 4.5172e-04],
[ 1.5339e-03, 6.5314e-03, 3.5240e-03, -1.6078e-04, 2.6001e-02],
[-4.3787e-03, 2.5129e-02, -4.8452e-03, 1.7136e-02, -2.2656e-03]]],
[[[ 1.1603e-02, 2.5870e-04, -4.7882e-04, -1.2974e-02, -7.0833e-03],
[ 9.1224e-03, -2.7099e-02, -7.2172e-03, 6.0094e-03, -1.9354e-03],
[ 8.9487e-03, 1.0132e-03, -1.2599e-02, 6.6889e-04, 1.2481e-02],
[ 1.9308e-02, 1.1304e-02, -2.6835e-02, -5.0302e-03, -1.2123e-02],
[-8.6779e-03, 2.4515e-03, -1.5991e-03, 3.2772e-03, 1.5057e-03]]],
[[[ 2.9538e-03, 3.2182e-03, 2.1735e-02, -4.1001e-03, 7.3709e-03],
[-7.8341e-03, 8.6530e-03, 1.2804e-02, 4.7380e-03, 2.7090e-02],
[ 2.3400e-02, -9.9183e-03, -2.7806e-03, -5.3960e-03, 6.5356e-03],
[-9.2149e-03, 6.3300e-03, -9.1231e-03, -3.1583e-03, -2.5313e-02],
[-6.8671e-03, 8.7669e-03, 2.8738e-02, -4.0501e-04, 1.3954e-02]]],
[[[-2.8224e-02, 3.6240e-03, -3.5161e-03, -1.1865e-02, 5.3318e-03],
[-3.4220e-03, -9.4413e-03, -8.9566e-03, -9.7369e-03, 9.6336e-03],
[ 1.0341e-02, -1.8074e-02, 5.9631e-03, 6.8791e-03, -1.7632e-02],
[ 6.7529e-03, 1.5338e-02, 6.8727e-03, 8.8999e-03, -5.4561e-03],
[ 9.2013e-03, 4.1394e-03, -1.4813e-02, 1.5590e-02, -9.7826e-03]]],
[[[-9.2427e-03, 1.0145e-02, -1.0158e-03, 6.6471e-03, -8.1966e-03],
[-1.4890e-02, -3.3134e-02, -1.8499e-02, 2.5454e-03, 1.2673e-02],
[-7.3737e-03, -2.1420e-02, -1.0963e-02, -1.5361e-02, -1.0578e-03],
[-1.4120e-03, 6.1323e-04, -1.1165e-02, 4.9900e-03, -1.1872e-02],
[-2.7640e-03, 2.2880e-02, -1.1687e-03, -5.3693e-03, 3.2699e-03]]],
[[[ 6.0525e-03, -3.7511e-03, -5.7904e-03, -1.8990e-02, 7.1018e-03],
[-1.3982e-02, 4.2345e-03, -1.7800e-02, -6.0713e-03, -4.9168e-03],
[-7.9266e-03, -2.8650e-03, 1.9363e-02, -9.5297e-03, -2.8823e-03],
[ 1.6598e-03, -8.0634e-04, 3.9225e-03, 1.4599e-02, 1.4768e-03],
[ 1.2664e-04, 1.2907e-02, -6.1437e-03, -4.5010e-03, 1.0548e-02]]]])
网友评论