4. 反向传播
4.1 概念
概念详见李宏毅笔记-反向传播
上述红色的线这个往回传的过程就叫反向传播
举一个简单的小例子
如此就可以轻松算出要求的
4.2 代码介绍
在PyTorch中数据的基本单元是tensor(多维数组),他有两个重要的成员变量:data(存数据)和grad(存梯度)
如果需要自动求梯度,就将tensor的成员变量requires_grad置True,设为 True 时会跟踪所有操作,用于构建计算图。
由于w是一个tensor,所以x也要被自动转为tensor计算,loss同样。
由于w的成员变量requires_grad置True,被调用时会自动构建如上右侧刘二大人老师手绘的计算图
l.backward()会将刚刚设置需要梯度的地方的梯度都求出来存到grad属性中,并释放计算图以便下一次调用loss函数生成新的计算图
可以使用grad属性的item()方法提取标量值(如 Python 的 int、float 等),不会建立计算图
可以使用grad属性的data属性拿到梯度值,data属性虽然是tensor,但是不会建立计算图
注意:data返回的是tensor,item()返回的是数值
4.3 注意点
4.3.1 tensor
以下为错误示例,本想求总体样本的平均误差,但是l是关于w的运算,l是一个tensor,会构建计算图,会吃内存
正确改为:sum += l.item()
4.3.2 zero_()
使用backward()会累计grad,优化后应当调用.grad.data.zero_()把grad清零
4.4 完整代码
import matplotlib
# 设置后端
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import torch
# 1.定义训练数据集
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
# 2.定义模型参数
w = torch.tensor([1.0], requires_grad=True)
# 3.定义模型
def forward(x):
return x * w
# 4.定义损失函数
def loss(x, y):
y_pred = forward(x)
return (y_pred - y) ** 2
# 5. 训练
w_list = []
l_list = []
for epoch in range(100):
for x, y in zip(x_data, y_data):
l = loss(x, y)
l.backward()
print("\tgrad: ", x, y, w.grad.item())
w.data = w.data - 0.01 * w.grad.item()
w.grad.data.zero_()
print(f"progress: {epoch}, w: {w.item()}, loss: {l.item()}")
w_list.append(w.item())
l_list.append(l.item())
# 画图
plt.plot(w_list, l_list)
plt.show()
Loss图像如下