问题与思考
【问题】什么是反向传播?用于解决什么问题?
【回答】我们从头屡一下思路。为了找到权重w的值,我们一开始选择暴力枚举;后来通过梯度下降+更新权重的方案让程序自动找到合适的w值;但是在求梯度的时候,w可能会很复杂(比如是多维的)那此时如果在使用loss对w求导来求梯度就变得很麻烦(需要逐个求偏导数,在复杂神经网络中会相当复杂)。所以引入“反向传播”这个概念,生成一个计算图,“倒着”来,根据链式法则来求loss对w的偏导数(梯度),如下图所示:
蓝色线:正向过程(前馈),红色线:反向过程(反馈)。
正向过程,求出z对x的偏导数,求出z对w的偏导数。
反向过程,根据链式法则(此处假设L对z的偏导数的值为5),可以得到L(loss)对w和l对x的偏导数。
【注】只要拿到l对w的偏导数(梯度),就可以做更新了。
完整的线性模型计算图如下:
正向计算,一步一步计算往后走,直到获取loss的值。
得到loss值后反向计算,一步一步根据链式法则求梯度(loss对w的偏导数)
用pytorch实现反向传播
import torch x_data = [1.0, 2.0, 3.0] y_data = [2.0, 4.0, 6.0] # 定义w初始值 w = torch.tensor([1.0]) w.requires_grad = True # True代表需要计算梯度,tensor会自动求梯度的。 # 定义模型 def forward(x): return x * w # x是个张量、w是个张量, x和w进行矩阵乘法 # 定义loss损失 def loss(x, y): y_pred = forward(x) # 计算y_pred预测值 return (y_pred - y) ** 2 # 开始训练前,因为定义了初始w值,把x=4带入y=wx得到初始的预测值y_pred=4 print("predict before traning", 4, forward(4).item()) # 训练过程 for epoch in range(100): # 训练100次 for x, y in zip(x_data, y_data): l = loss(x, y) # 前馈过程,计算loss损失 l.backward() # 反向过程,计算梯度 print("\t grad:", x, y, w.grad.item()) w.data = w.data - 0.01 * w.grad.data # 更新梯度 w= w - α * 梯度 w.grad.data.zero_() # 梯度清零 print("progress:", epoch, l.item()) # 训练结束,测试数据,将x=4带入得到forward(4)的值 接近8 print("predict after training", 4, forward(4).item())