背景
Numpy也可以实现神经网络(前向和后向传递都是手工实现),缺点是不Numpy能利用GPU加速,而且对于复杂的网络,反向传递环节很难编写。
Autograd
Pytorch的Autograd可以使用自动微分 来自动计算神经网络中的后向传递。使用autograd时,网络的正向传递将定义 计算图形 ; 图中的节点将是张量,边将是从输入张量产生输出张量的函数
1.设置requires_grad 为 True,那么将会追踪所有对于该张量的操作。
2.每个张量都有一个.grad_fn属性,这个属性引用了一个创建了Tensor的Function(除非这个张量是用户手动创建的,即,这个张量的 grad_fn 是 None)。
如果需要计算导数,你可以在Tensor上调用.backward()。 如果Tensor是一个标量(即它包含一个元素数据)则不需要为backward()指定任何参数, 但是如果它有更多的元素,你需要指定一个gradient 参数来匹配张量的形状。
3.为了防止跟踪历史记录(和使用内存),可以将代码块包装在with torch.no_grad():中。 在评估模型时特别有用,因为模型可能具有requires_grad = True的可训练参数,但是我们不需要梯度计算
神经网络
1.神经网络的典型训练过程如下:
定义包含一些可学习的参数(或者叫权重)神经网络模型;
在数据集上迭代;
通过神经网络处理输入;
计算损失(输出结果和正确值的差值大小);
将梯度反向传播回网络的参数;
更新网络的参数,主要使用如下简单的更新原则: weight = weight - learning_rate * gradient
2.重要的知识点:
1.nn.Module:神经网络模块。封装参数、移动到GPU上运行、导出、加载等。
#利用nn实现网络
model = torch.nn.Sequential(
torch.nn.Linear(D_in, H),
torch.nn.ReLU(),
torch.nn.Linear(H, D_out),
)
有时候需要需要指定比现有模块序列更复杂的模型,可以通过子类化nn.Module和定义forward接收输入Tensors并使用其他模块或Tensors上的其他autograd操作生成输出Tensors 来定义自己的模块
class TwoLayerNet(torch.nn.Module):
def __init__(self, D_in, H, D_out):
"""
In the constructor we instantiate two nn.Linear modules and assign them as
member variables.
"""
super(TwoLayerNet, self).__init__()
self.linear1 = torch.nn.Linear(D_in, H)
self.linear2 = torch.nn.Linear(H, D_out)
def forward(self, x):
"""
In the forward function we accept a Tensor of input data and we must return
a Tensor of output data. We can use Modules defined in the constructor as
well as arbitrary operators on Tensors.
"""
h_relu = self.linear1(x).clamp(min=0)
y_pred = self.linear2(h_relu)
return y_pred
model = TwoLayerNet(D_in, H, D_out)
2.nn.Parameter:一种变量,当把它赋值给一个Module时,被 自动 地注册为一个参数(返回可被学习的参数(权重)列表和值)。
3.将所有参数的梯度缓存清零,然后进行反向传播。
4.nn包里可以调用很多损失函数。
criterion = nn.MSELoss()
loss = criterion(output, target)
#follow loss in the backward direction, using its .grad_fn attribute
print(loss.grad_fn) # MSELoss
print(loss.grad_fn.next_functions[0][0]) # Linear
5.调用loss.backward()获得反向传播的误差。
从PyTorch的设计原理上来说,在每次进行前向计算得到pred时,会产生一个用于梯度回传的计算图,这张图储存了进行back propagation需要的中间结果,当调用了.backward()后,会从内存中将这张图进行释放。
注:在调用前需要清除已存在的梯度,否则梯度将被累加到已存在的梯度,也有少数不清楚的操作,一般用于内存不够等情况,慎用
有两种:net.zero_grad()和optimizer.zero_grad()
6.更新权重,常用的是SGD,optim提供了各种不同的更新规则,如Adam等
#weight = weight - learning_rate * gradient
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
*************************************************
import torch.optim as optim
# create your optimizer
optimizer = optim.SGD(net.parameters(), lr=0.01)
# in your training loop:
optimizer.zero_grad() # zero the gradient buffers
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step() # Does the update
参考文献
https://pytorch.org/tutorials/beginner/pytorch_with_examples.html
https://github.com/zergtant/pytorch-handbook