对于小型的网络而言,手动实施反向传播很简单,但对于大型的复杂网络而言,会变得非常麻烦。
而在pytorch中,我们可以使autograd包自动微分来自动计算神经网络中的反向传播。 使autograd时,网络的正向传递将定义一个计算图; 图中的节点为张量,边为从输入张量产生输出张量的函数。 然后通过该图进行反向传播,可以轻松计算梯度。话不多说,贴代码:
import torch
import math
dtype = torch.float
device = torch.device("cuda:0") # 指定设备为GPU
# 声明两个张量接收输入和输出
# 默认反向传播不需要保存梯度(requires_grad=False)
x = torch.linspace(-math.pi, math.pi, 2000, device=device, dtype=dtype)
y = torch.sin(x)
# 为四个权重创建张量
# 设置requires_grad=True,因为在反向传播中我们需要计算并保存这些张量的梯度
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)
learning_rate = 1e-6
for t in range(2000):
y_pred = a + b * x + c * x ** 2 + d * x ** 3
# 用Tensor计算和打印loss
# loss是一个一维Tensor,loss.item() 用于获取loss的标量值
loss = (y_pred - y).pow(2).sum()
if t % 100 == 100:
print(t, loss.item())
# 使用自动求导进行反向传播,调用过程中将会计算所有requires_grad=True的张 量损失梯度在调用过程中a.grad,b.grad,c.grad,d.grad 将保存abcd的损失梯度.
loss.backward()
# 对于tensor的计算操作,默认是要进行梯度计算,在这种情况下,可以使用with torch.no_grad():,强制之后的内容不进行梯度计算。
with torch.no_grad():
a -= learning_rate * a.grad
b -= learning_rate * b.grad
c -= learning_rate * c.grad
d -= learning_rate * d.grad
# 在更新权重后手动将梯度置0
a.grad = None
b.grad = None
c.grad = None
d.grad = None
print(f'Result: y = {a.item()} + {b.item()} x + {c.item()} x^2 + {d.item()} x^3')