书接上回:
02.PyTorch张量_江湖人称桂某人的博客-CSDN博客PyTorch官方文档教程详解第二节,适合新手入门,非常详细https://blog.csdn.net/qq_39837305/article/details/128645166
在上一篇文章中,我们学习了如何使用pytorch网络的tensor实现正向传播以及用loss实现反向传播。今天继续来看看自动求导Autograd如何进行实现。
解决的问题还是一样:我们准备一个三阶多项式,通过最小化平方欧几里得距离来训练,并预测函数 y = sin(x)
在-pi
到pi
上的值。
import torch
import math
dtype = torch.float
device = torch.device("cpu")
x = torch.linspace(-math.pi, math.pi, 2000, device=device, dtype=dtype)
y = torch.sin(x)
和上一篇文章一样,不多说,造就完了。
a = torch.randn((), device=device, dtype=dtype, requires_grad=True)
b = torch.randn((), device=device, dtype=dtype, requires_grad=True)
c = torch.randn((), device=device, dtype=dtype, requires_grad=True)
d = torch.randn((), device=device, dtype=dtype, requires_grad=True)
这里就有所不同了,回忆一下上篇文章的写法:
a = torch.randn((), device=device, dtype=dtype)
b = torch.randn((), device=device, dtype=dtype)
c = torch.randn((), device=device, dtype=dtype)
d = torch.randn((), device=device, dtype=dtype)
发现:多了一个参数,requires_grad=True,这个参数就是用于自动求导的参数。
leatning_rate = 1e-6
for t in range(2000):
# 正向传递:使用张量运算计算预测的y。
y_pred = a + b * x + c * x ** 2 + d * x ** 3
# 使用Tensors上的操作计算和打印损失。
# 现在损失是形状(1,)的张量
# loss.item()获取损失中保存的标量值。
loss = (y_pred - y).pow(2).sum()
if t % 100 == 99:
print(t, loss.item())
# 使用autograd计算反向通过。
# 此调用将计算所有张量的损失梯度,其中requires_grad=True。
# 在这一调用之后,a.grad、b.grad、c.grad和d.grad将分别是张量,
# 分别保持损失相对于a、b、c、d的梯度。
loss.backward()
with torch.no_grad():
a -= leatning_rate * a.grad
b -= leatning_rate * b.grad
c -= leatning_rate * c.grad
d -= leatning_rate * d.grad
# 更新权重后手动归零梯度
a.grad = None
b.grad = None
c.grad = None
d.grad = None
代码的注释我写的很详细,大家看一下就明白了。
这里我们再和上篇手动实现前向传播的过程进行对比:
learning_rate = 1e-6
for t in range(2000):
# 正向传递:计算预测y
y_pred = a + b * x + c * x ** 2 + d * x ** 3
# 计算输出loss
loss = (y_pred - y).pow(2).sum().item()
if t % 100 == 99:
print(t, loss)
# 反向传播计算a,b,c,d的梯度损失
grad_y_pred = 2.0 * (y_pred - y)
grad_a = grad_y_pred.sum()
grad_b = (grad_y_pred * x).sum()
grad_c = (grad_y_pred * x ** 2).sum()
grad_d = (grad_y_pred * x ** 3).sum()
# 使用梯度下降更新权重
a -= learning_rate * grad_a
b -= learning_rate * grad_b
c -= learning_rate * grad_c
d -= learning_rate * grad_d
区别一目了然:
手动的过程中需要自己计算四个权重不断变化的值,而使用了自动求导,直接更新权重就可以了。
但是一定要注意的是:
在梯度计算前要加上loss.backward(),反向传播。
pytorch进行自动求导后的梯度是不会自动清零的,如果不手动清零会不断的叠加。
所以一定要在梯度更新后手动清零:a.grad=None或zero_grad()。