乐于分享
好东西不私藏

AI基础 | 前向传播与反向传播(2)

AI基础 | 前向传播与反向传播(2)

转自:runoob

反向传播:神经网络的学习引擎

反向传播是深度学习的学习算法核心。其本质是链式法则在神经网络中的高效应用。目标是计算损失函数 L 对每个参数(w1, b1, w2, b2)的偏导数(梯度),即 ∂L/∂w1∂L/∂b1 等。这些梯度指明了为了减小损失,每个参数应该朝哪个方向、以多大的幅度调整。

理解梯度:下山的方向与步幅

想象你蒙着眼站在一座山上(损失曲面),目标是找到山谷的最低点(最小损失)。你每走一步前,都需要用脚感受一下周围最陡的下坡方向。这个最陡的下坡方向就是梯度。反向传播就是帮你精确计算出脚下每一个点(对应每一组参数)的梯度。

反向传播计算步骤(链式求导)

我们继续沿用前面的微型网络,并假设真实房价 y_true = 2.5,损失函数为均方误差 L = (y_true - y_pred)^2

反向传播从输出层开始,反向逐层计算梯度:

计算输出层参数的梯度

  • 损失 L 对预测值 y_pred 的梯度: ∂L/∂y_pred = -2 * (y_true - y_pred)
  • 因为 y_pred = w2 * a1 + b2,所以: ∂L/∂w2 = (∂L/∂y_pred) * (∂y_pred/∂w2) = (∂L/∂y_pred) * a1∂L/∂b2 = (∂L/∂y_pred) * (∂y_pred/∂b2) = (∂L/∂y_pred) * 1

计算隐藏层参数的梯度

  • 首先,需要损失 L 对隐藏层输出 a1 的梯度。a1 通过 y_pred 影响 L: ∂L/∂a1 = (∂L/∂y_pred) * (∂y_pred/∂a1) = (∂L/∂y_pred) * w2
  • 然后,a1 = σ(z1),Sigmoid函数的导数 σ'(z) = σ(z)*(1-σ(z))
  • 最后,计算 L 对隐藏层参数 w1b1 的梯度: ∂L/∂w1 = (∂L/∂a1) * (∂a1/∂z1) * (∂z1/∂w1) = (∂L/∂a1) * σ'(z1) * x∂L/∂b1 = (∂L/∂a1) * (∂a1/∂z1) * (∂z1/∂b1) = (∂L/∂a1) * σ'(z1) * 1

代码示例:手动实现反向传播

# 接续前向传播的代码和结果y_true = 2.5y_pred = result['y_pred']a1 = result['a1']z1 = result['z1']x = x_inputprint(f"真实值 y_true = {y_true}")print(f"预测值 y_pred = {y_pred:.4f}")print(f"初始损失 Loss = {(y_true - y_pred)**2:.4f}")print("\n--- 开始反向传播计算梯度 ---")# 1. 计算损失对y_pred的梯度dL_dy_pred = -2 * (y_true - y_pred)print(f"梯度 ∂L/∂y_pred = -2*(y_true - y_pred) = {dL_dy_pred:.4f}")# 2. 计算输出层参数 w2, b2 的梯度dL_dw2 = dL_dy_pred * a1dL_db2 = dL_dy_pred * 1print(f"梯度 ∂L/∂w2 = (∂L/∂y_pred) * a1 = {dL_dw2:.4f}")print(f"梯度 ∂L/∂b2 = (∂L/∂y_pred) * 1 = {dL_db2:.4f}")# 3. 计算损失对隐藏层输出a1的梯度dL_da1 = dL_dy_pred * w2print(f"梯度 ∂L/∂a1 = (∂L/∂y_pred) * w2 = {dL_da1:.4f}")# 4. 计算Sigmoid函数的导数在z1处的值def sigmoid_derivative(x):    """Sigmoid函数的导数"""    s = sigmoid(x)    return s * (1 - s)sigma_prime_z1 = sigmoid_derivative(z1)print(f"Sigmoid导数 σ'(z1) = σ(z1)*(1-σ(z1)) = {sigma_prime_z1:.4f}")# 5. 计算隐藏层参数 w1, b1 的梯度dL_dw1 = dL_da1 * sigma_prime_z1 * xdL_db1 = dL_da1 * sigma_prime_z1 * 1print(f"梯度 ∂L/∂w1 = (∂L/∂a1) * σ'(z1) * x = {dL_dw1:.4f}")print(f"梯度 ∂L/∂b1 = (∂L/∂a1) * σ'(z1) * 1 = {dL_db1:.4f}")

输出示例:

真实值 y_true = 2.5预测值 y_pred = 1.9899初始损失 Loss = 0.2602--- 开始反向传播计算梯度 ---梯度 L/∂y_pred = -2*(y_true - y_pred) = -1.0202梯度 L/∂w2 = (∂L/y_pred) * a1 = -1.0134梯度 L/∂b2 = (∂L/y_pred) * 1 = -1.0202梯度 L/∂a1 = (∂L/y_pred) * w2 = -1.5303Sigmoid导数 σ'(z1) = σ(z1)*(1-σ(z1)) = 0.0066梯度 L/∂w1 = (∂L/a1) * σ'(z1) * x = -0.0304梯度 L/∂b1 = (∂L/a1) *σ'(z1) * 1 = -0.0101

现在,我们得到了所有参数的梯度。这些负值意味着,如果增加这些参数的值,损失会增大(因为梯度方向是上升方向)。为了减小损失,我们应该沿着梯度的反方向调整参数。


参数更新:梯度下降

拿到梯度后,我们使用梯度下降算法来更新参数:

参数 = 参数 - 学习率 * 该参数的梯度

其中,学习率是一个非常重要的超参数,它控制了每次参数更新的步长。步长太小,学习缓慢;步长太大,可能无法收敛甚至发散。

代码示例:应用梯度下降更新参数

learning_rate = 0.1# 更新参数w1_new = w1 - learning_rate * dL_dw1b1_new = b1 - learning_rate * dL_db1w2_new = w2 - learning_rate * dL_dw2b2_new = b2 - learning_rate * dL_db2print("--- 更新后的参数 ---")print(f"w1: {w1:.4f} -> {w1_new:.4f}")print(f"b1: {b1:.4f} -> {b1_new:.4f}")print(f"w2: {w2:.4f} -> {w2_new:.4f}")print(f"b2: {b2:.4f} -> {b2_new:.4f}")# 用新参数做一次前向传播,验证损失是否减小def forward_pass_with_params(x, w1, b1, w2, b2):    z1 = w1 * x + b1    a1 = sigmoid(z1)    y_pred = w2 * a1 + b2    return y_predy_pred_new = forward_pass_with_params(x_input, w1_new, b1_new, w2_new, b2_new)loss_new = (y_true - y_pred_new)**2print(f"\n用新参数预测: y_pred_new = {y_pred_new:.4f}")print(f"更新后的损失 New Loss = {loss_new:.4f}")print(f"损失变化: {loss_new - (y_true-y_pred)**2:.4f} (负值表示损失减小)")

太好了!经过一次前向传播 -> 计算损失 -> 反向传播 -> 梯度下降更新的完整循环,我们的预测值 y_pred 从 1.99 更接近真实值 2.5,损失也从 0.260 下降到了 0.094。将这个循环重复成千上万次(在大量数据上),神经网络就能学习到有效的参数,做出准确的预测。


实践练习:巩固你的理解

现在,是时候动手巩固所学知识了。

练习 1:扩展网络 修改上面的代码,将隐藏层神经元增加到2个。你需要初始化 w1 为一个形状为 (2,) 的数组(两个权重),b1 为 (2,) 的数组。相应地调整前向传播和反向传播的计算。观察网络能力的变化。

练习 2:更换激活函数 将Sigmoid激活函数替换为ReLU函数(f(x) = max(0, x))。你需要重新推导并实现ReLU的导数(f'(x) = 1 if x>0 else 0)。比较使用不同激活函数时,训练过程有何不同。

练习 3:实现一个训练循环 编写一个完整的训练循环,在某个简单数据集(例如,自己构造 y = 2x + 1 + 噪声 的数据)上,训练一个微型网络去拟合它。设置迭代次数(epoch),在每次迭代后打印损失,观察损失是否随着训练持续下降。

练习 4:理解学习率的影响 在练习3的基础上,尝试不同的 learning_rate(如 0.01, 0.1, 0.5, 1.0)。观察学习率过大或过小时,损失曲线的变化(是震荡、发散还是收敛缓慢),深刻理解学习率作为步幅的重要性。


总结

前向传播与反向传播是神经网络学习的核心动态:

  1. 前向传播
    推理路径,它利用当前参数将输入映射为输出,并计算当前表现的得分(损失)。
  2. 反向传播
    学习算法,它利用链式法则,高效地计算出损失函数对网络中每一个参数的梯度,指明了参数优化的方向。
  3. 梯度下降
    优化策略,它根据反向传播提供的梯度,以学习率为步长,实际更新参数,使网络的表现逐步改善。

https://www.runoob.com/ml/ml-forward-and-backward-propagation.html