刘二大人第4讲-反向传播-有代码

1 阅读2分钟

4. 反向传播

4.1 概念

概念详见李宏毅笔记-反向传播

image.png

上述红色的线这个往回传的过程就叫反向传播

举一个简单的小例子

image.png

如此就可以轻松算出要求的LxLw\frac {\partial L}{\partial x}和\frac {\partial L}{\partial w}

4.2 代码介绍

在PyTorch中数据的基本单元是tensor(多维数组),他有两个重要的成员变量:data(存数据)和grad(存梯度)

image.png

如果需要自动求梯度,就将tensor的成员变量requires_grad置True,设为 True 时会跟踪所有操作,用于构建计算图

image.png

由于w是一个tensor,所以x也要被自动转为tensor计算,loss同样。

由于w的成员变量requires_grad置True,被调用时会自动构建如上右侧刘二大人老师手绘的计算图

image.png

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,会构建计算图,会吃内存

image.png

正确改为: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图像如下

image.png