17-3 反向传播与模型训练

🎯 教学目标与重难点…

【三维目标】

  • 📚 知识目标:理解反向传播算法的核心思想——利用链式法则从输出端向输入端逐层计算梯度;掌握计算图的表示方法;熟悉回归任务和分类任务中输出层及隐藏层的梯度推导过程;理解参数初始化对训练收敛性的影响。
  • ⚙️ 能力目标:能够从零实现单隐藏层神经网络的反向传播与梯度下降训练;能够使用 NumPy 完成完整的训练循环(前向 → 损失计算 → 反向 → 参数更新);能够监控训练过程中的损失变化并诊断收敛问题。
  • 💡 素养目标:建立“自动微分”的基本概念,理解现代深度学习框架(PyTorch/TensorFlow)的底层原理;培养调试神经网络训练过程的系统性思维;理解梯度消失/爆炸问题的成因及应对策略。

【重点与难点】

  • 🟢 教学重点:反向传播的链式法则原理;计算图的前向与反向信息流;回归网络(MSE 损失 + 线性输出)的梯度推导;二分类网络(交叉熵损失 + Sigmoid 输出)的梯度推导;参数更新规则与训练循环的完整实现。
  • 🟡 教学难点:从输出层到隐藏层的逐层梯度反向传播推导;Sigmoid 导数 \( \sigma'(z) = \sigma(z)(1-\sigma(z)) \) 在梯度计算中的化简;理解梯度消失问题的成因;权重矩阵维度转置在反向传播中的作用。

📌 一、 课程导入(5 分钟)

主题:神经网络如何学习?

第 17-1 课学习了逻辑回归的梯度下降——单个神经元参数的更新方法。

第 17-2 课学习了神经网络的结构——多层的、包含隐藏层的复杂模型。

新的问题:对于一个包含隐藏层的多层网络,如何计算每一层参数的梯度?

1第17-1课:单个神经元 → 梯度公式 ∂J/∂w = (1/m)∑(ŷ-y)x
23第17-2课:多层网络 → 参数变多了,梯度怎么算?
45第17-3课:反向传播 → 从输出层向输入层逐层计算梯度

核心洞察:反向传播(Backpropagation)本质上只是链式法则(Chain Rule)的工程化应用。与其说是一个“新算法”,不如说是一种高效计算多层复合函数梯度的策略。

本课路径

1计算图(前向与反向的可视化)
23链式法则(反向传播的数学基础)
45输出层梯度推导(回归 + 分类)
67隐藏层梯度推导(逐层回传)
89完整训练循环的实现
  • 👨‍🏫 教师活动:回顾逻辑回归的梯度公式;点明多层网络的梯度计算需求;展示本课的结构图。
  • 🧑‍🎓 学生活动:回忆逻辑回归的梯度推导过程;思考“如果是两层网络,梯度如何从输出传到输入”。

从已知的单层梯度过渡到多层梯度计算,建立“反向传播本质是链式法则”这一核心认知,避免将反向传播视为某种“黑魔法”。


📖 二、 解决问题过程(一):计算图与链式法则(20 分钟)

2.1 计算图(Computational Graph)

计算图是一种将数学表达式表示为有向图的方法,节点表示操作或变量,边表示数据流向。

示例:计算 \( e = (a + b) \times (b + 1) \)

flowchart LR
    a["a"] --> add1["+"] --> mul["×"] --> e["e"]
    b["b"] --> add1
    b --> add2["+"] --> mul
    c["1"] --> add2

前向传播:从输入到输出,计算每个节点的值。

2.2 链式法则回顾

对于复合函数 \( y = f(g(x)) \):

\[ \frac{dy}{dx} = \frac{dy}{dg} \cdot \frac{dg}{dx} \]

对于多元复合函数:

\[ \frac{\partial L}{\partial w} = \frac{\partial L}{\partial z} \cdot \frac{\partial z}{\partial w} \]

2.3 计算图上的反向传播

反向传播的流程是从输出节点出发,沿反方向逐层计算梯度

对于表达式 \( e = (a + b) \times (b + 1) \),假设最终损失 \( L = e \):

  1. 前向计算各节点值(设 \( a = 2, b = 3 \))

    • \( c = a + b = 5 \)
    • \( d = b + 1 = 4 \)
    • \( e = c \times d = 20 \)
  2. 反向传播梯度:

    • \( \frac{\partial L}{\partial e} = 1 \)
    • \( \frac{\partial L}{\partial c} = \frac{\partial L}{\partial e} \cdot \frac{\partial e}{\partial c} = 1 \times d = 4 \)
    • \( \frac{\partial L}{\partial d} = \frac{\partial L}{\partial e} \cdot \frac{\partial e}{\partial d} = 1 \times c = 5 \)
    • \( \frac{\partial L}{\partial b} = \frac{\partial L}{\partial c} \cdot \frac{\partial c}{\partial b} + \frac{\partial L}{\partial d} \cdot \frac{\partial d}{\partial b} = 4 \times 1 + 5 \times 1 = 9 \)
    • \( \frac{\partial L}{\partial a} = \frac{\partial L}{\partial c} \cdot \frac{\partial c}{\partial a} = 4 \times 1 = 4 \)

关键观察:梯度在反向传播过程中是累加的(当节点有多个下游路径时),且每个节点只需要接收来自“上方”的梯度,乘以本地导数后传给“下方”。

2.4 神经网络的计算图视角

神经网络就是一个巨大的计算图:

flowchart LR
    x["x"] --> W1["W¹"] --> z1["z¹"] --> f1["f¹"] --> a1["a¹"]
    b1["b¹"] --> z1
    a1 --> W2["W²"] --> z2["z²"] --> f2["f²"] --> a2["ŷ"]
    b2["b²"] --> z2
    a2 --> L["损失"] --> J["J"]

反向传播就是沿着此图的反向路径,从 \( J \) 开始逐层计算所有参数(\( W^{[1]}, b^{[1]}, W^{[2]}, b^{[2]} \))的梯度。

  • 👨‍🏫 教师活动:在黑板上绘制简单表达式的计算图;逐节点演示前向计算与反向传播过程;过渡到神经网络的计算图表示。
  • 🧑‍🎓 学生活动:在笔记本上跟随教师绘制计算图并完成梯度计算;理解“梯度是反向传播的”。

通过简单的标量计算图建立反向传播的直觉理解,再推广到神经网络的张量计算,避免直接进入矩阵推导造成的认知跳跃。


📖 三、 解决问题过程(二):单隐藏层网络的梯度推导(35 分钟)

3.1 网络结构与符号定义

考虑一个单隐藏层神经网络:

  • 输入层:\( n_0 \) 个特征
  • 隐藏层:\( n_1 \) 个神经元,激活函数为 ReLU
  • 输出层:\( n_2 \) 个神经元(根据任务决定)

前向传播

\[ z^{[1]} = W^{[1]} x + b^{[1]}, \quad a^{[1]} = \text{ReLU}(z^{[1]}) \]\[ z^{[2]} = W^{[2]} a^{[1]} + b^{[2]}, \quad \hat{y} = f^{[2]}(z^{[2]}) \]

3.2 反向传播的统一框架

反向传播的核心是计算损失 \( J \) 对每一层线性输出 \( z^{[l]} \) 的偏导数 \( \delta^{[l]} = \frac{\partial J}{\partial z^{[l]}} \)。

一旦有了 \( \delta^{[l]} \),参数梯度可直接计算:

\[ \frac{\partial J}{\partial W^{[l]}} = \delta^{[l]} (a^{[l-1]})^T \]\[ \frac{\partial J}{\partial b^{[l]}} = \delta^{[l]} \]

关键公式(误差反向传播)

\[ \delta^{[l]} = (W^{[l+1]})^T \delta^{[l+1]} \odot f'^{[l]}(z^{[l]}) \]

其中 \( \odot \) 表示逐元素相乘(Hadamard 乘积)。

3.3 场景一:回归任务(MSE + 线性输出)

配置

  • 输出层激活:\( f^{[2]}(z) = z \)(线性)
  • 损失函数:\( J = \frac{1}{2m} \sum_{i=1}^{m} (\hat{y}^{(i)} - y^{(i)})^2 \)

单样本梯度

\[ \delta^{[2]} = \frac{\partial J}{\partial z^{[2]}} = \hat{y} - y \]\[ \frac{\partial J}{\partial W^{[2]}} = \delta^{[2]} (a^{[1]})^T \]\[ \frac{\partial J}{\partial b^{[2]}} = \delta^{[2]} \]

隐藏层误差(ReLU 的导数为 0/1):

\[ \delta^{[1]} = (W^{[2]})^T \delta^{[2]} \odot \mathbf{1}_{z^{[1]} > 0} \]

其中 \( \mathbf{1}_{z^{[1]} > 0} \) 表示 ReLU 的导数(输入大于 0 时为 1,否则为 0)。

隐藏层参数梯度

\[ \frac{\partial J}{\partial W^{[1]}} = \delta^{[1]} x^T \]\[ \frac{\partial J}{\partial b^{[1]}} = \delta^{[1]} \]

3.4 场景二:二分类任务(交叉熵 + Sigmoid)

配置

  • 输出层激活:\( f^{[2]}(z) = \sigma(z) = \frac{1}{1+e^{-z}} \)
  • 损失函数:\( J = -\frac{1}{m} \sum_{i=1}^{m} [y^{(i)} \log \hat{y}^{(i)} + (1-y^{(i)}) \log (1-\hat{y}^{(i)})] \)

单样本梯度

\[ \delta^{[2]} = \frac{\partial J}{\partial z^{[2]}} = \hat{y} - y \]

关键性质:交叉熵损失 + Sigmoid 激活的组合,使得输出层的误差表达式与回归任务完全相同(均为 \( \hat{y} - y \))。

💡 设计巧妙之处:无论输出层是线性+Sigmoid还是线性+MSE,只要损失函数与激活函数匹配,\( \delta^{[2]} \) 的形式统一为 \( \hat{y} - y \)。这正是逻辑回归和线性回归梯度表达式一致的根本原因。

隐藏层误差(与回归相同):

\[ \delta^{[1]} = (W^{[2]})^T \delta^{[2]} \odot \mathbf{1}_{z^{[1]} > 0} \]

3.5 批量形式

对于包含 \( m \) 个样本的批次,将向量扩展为矩阵:

变量 单样本维度 批量维度
\( X \) \( n_0 \times 1 \) \( n_0 \times m \)
\( z^{[1]} \) \( n_1 \times 1 \) \( n_1 \times m \)
\( a^{[1]} \) \( n_1 \times 1 \) \( n_1 \times m \)
\( z^{[2]} \) \( n_2 \times 1 \) \( n_2 \times m \)
\( \hat{y} \) \( n_2 \times 1 \) \( n_2 \times m \)

批量参数梯度(以回归为例):

\[ \frac{\partial J}{\partial W^{[2]}} = \frac{1}{m} (\hat{Y} - Y) (A^{[1]})^T \]\[ \frac{\partial J}{\partial b^{[2]}} = \frac{1}{m} \sum_{i=1}^{m} (\hat{y}^{(i)} - y^{(i)}) \]\[ \frac{\partial J}{\partial W^{[1]}} = \frac{1}{m} \delta^{[1]} X^T \]\[ \frac{\partial J}{\partial b^{[1]}} = \frac{1}{m} \sum_{i=1}^{m} \delta^{[1](i)} \]

3.6 权重初始化的重要性

梯度消失与梯度爆炸

若权重初始化过大,深层网络的输出趋向饱和区,梯度消失;若初始化过小,梯度逐层衰减。

常用的初始化策略

初始化方法 公式 适用激活函数
Xavier/Glorot \( W \sim \mathcal{N}(0, \frac{2}{n_{in} + n_{out}}) \) Sigmoid, Tanh
He \( W \sim \mathcal{N}(0, \frac{2}{n_{in}}) \) ReLU
  • 👨‍🏫 教师活动:在黑板上逐步推导输出层和隐藏层的误差反向传播公式;对比回归和二分类场景下的 \( \delta^{[2]} \);演示批量矩阵形式的梯度计算。
  • 🧑‍🎓 学生活动:跟随教师完成公式推导,特别关注维度匹配;理解 \( \delta^{[l]} \) 的递推关系;记录权重初始化策略。

反向传播是本课程数学强度最高的内容。通过分场景(回归/分类)、分层(输出/隐藏)、分形式(单样本/批量)的渐进式推导,确保学生理解每一步的来源,而非死记公式。


✍️ 四、 解决问题过程(三):完整训练循环的实现(20 分钟)

4.1 单隐藏层神经网络完整实现

  1import numpy as np
  2import matplotlib.pyplot as plt
  3from sklearn.datasets import make_classification
  4from sklearn.model_selection import train_test_split
  5from sklearn.preprocessing import StandardScaler
  6
  7class NeuralNetwork:
  8    def __init__(self, n_input, n_hidden, n_output, learning_rate=0.1, seed=42):
  9        self.lr = learning_rate
 10        np.random.seed(seed)
 11
 12        # He 初始化(用于 ReLU)
 13        self.W1 = np.random.randn(n_hidden, n_input) * np.sqrt(2.0 / n_input)
 14        self.b1 = np.zeros((n_hidden, 1))
 15        self.W2 = np.random.randn(n_output, n_hidden) * np.sqrt(2.0 / n_hidden)
 16        self.b2 = np.zeros((n_output, 1))
 17
 18        # 存储中间变量(用于反向传播)
 19        self.cache = {}
 20
 21    def _sigmoid(self, z):
 22        return 1 / (1 + np.exp(-z))
 23
 24    def _relu(self, z):
 25        return np.maximum(0, z)
 26
 27    def _relu_derivative(self, z):
 28        return (z > 0).astype(float)
 29
 30    def forward(self, X):
 31        """
 32        X: 维度 (n_input, m),m 为样本数
 33        返回: 预测值 (n_output, m)
 34        """
 35        Z1 = np.dot(self.W1, X) + self.b1
 36        A1 = self._relu(Z1)
 37        Z2 = np.dot(self.W2, A1) + self.b2
 38        A2 = self._sigmoid(Z2)
 39
 40        self.cache = {'Z1': Z1, 'A1': A1, 'Z2': Z2, 'A2': A2, 'X': X}
 41        return A2
 42
 43    def compute_loss(self, Y, A2, eps=1e-8):
 44        """
 45        Y: 真实标签,维度 (n_output, m)
 46        A2: 预测值,维度 (n_output, m)
 47        """
 48        m = Y.shape[1]
 49        loss = -np.mean(Y * np.log(A2 + eps) + (1 - Y) * np.log(1 - A2 + eps))
 50        return loss
 51
 52    def backward(self, Y):
 53        """
 54        执行反向传播,计算并存储梯度
 55        """
 56        m = Y.shape[1]
 57        X = self.cache['X']
 58        Z1 = self.cache['Z1']
 59        A1 = self.cache['A1']
 60        A2 = self.cache['A2']
 61
 62        # 输出层误差: δ2 = ŷ - y (交叉熵 + Sigmoid)
 63        dZ2 = A2 - Y
 64        dW2 = (1 / m) * np.dot(dZ2, A1.T)
 65        db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)
 66
 67        # 隐藏层误差: δ1 = W2^T · δ2 ⊙ ReLU'(Z1)
 68        dZ1 = np.dot(self.W2.T, dZ2) * self._relu_derivative(Z1)
 69        dW1 = (1 / m) * np.dot(dZ1, X.T)
 70        db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)
 71
 72        # 保存梯度
 73        self.grads = {'dW1': dW1, 'db1': db1, 'dW2': dW2, 'db2': db2}
 74
 75    def update(self):
 76        self.W1 -= self.lr * self.grads['dW1']
 77        self.b1 -= self.lr * self.grads['db1']
 78        self.W2 -= self.lr * self.grads['dW2']
 79        self.b2 -= self.lr * self.grads['db2']
 80
 81    def fit(self, X, Y, epochs=1000, verbose=True):
 82        losses = []
 83        for epoch in range(epochs):
 84            A2 = self.forward(X)
 85            loss = self.compute_loss(Y, A2)
 86            losses.append(loss)
 87
 88            self.backward(Y)
 89            self.update()
 90
 91            if verbose and epoch % 100 == 0:
 92                print(f"Epoch {epoch}: Loss = {loss:.4f}")
 93
 94        return losses
 95
 96    def predict(self, X):
 97        A2 = self.forward(X)
 98        return (A2 >= 0.5).astype(int)
 99
100    def score(self, X, Y):
101        pred = self.predict(X)
102        return np.mean(pred == Y)

4.2 在二分类数据集上训练

 1# 生成数据
 2X, y = make_classification(n_samples=2000, n_features=10, n_informative=8,
 3                           n_redundant=2, n_clusters_per_class=1,
 4                           random_state=42)
 5y = y.reshape(1, -1)  # 转为 (1, m) 形式
 6
 7# 数据标准化
 8scaler = StandardScaler()
 9X_scaled = scaler.fit_transform(X).T  # 转为 (n_features, m)
10
11# 划分训练集/测试集
12X_train = X_scaled[:, :1500]
13y_train = y[:, :1500]
14X_test = X_scaled[:, 1500:]
15y_test = y[:, 1500:]
16
17# 训练
18model = NeuralNetwork(n_input=10, n_hidden=32, n_output=1, learning_rate=0.1)
19losses = model.fit(X_train, y_train, epochs=1000, verbose=True)
20
21# 评估
22train_acc = model.score(X_train, y_train)
23test_acc = model.score(X_test, y_test)
24print(f"\n训练集准确率: {train_acc:.4f}")
25print(f"测试集准确率: {test_acc:.4f}")
26
27# 绘制损失曲线
28plt.figure(figsize=(8, 5))
29plt.plot(losses)
30plt.xlabel('Epoch')
31plt.ylabel('Loss')
32plt.title('训练损失下降曲线')
33plt.grid(True, alpha=0.3)
34plt.show()
  • 👨‍🏫 教师活动:逐段讲解代码中前向传播、反向传播、参数更新与训练循环的对应关系;运行训练过程并展示损失曲线;强调梯度形状与维度匹配的调试技巧。
  • 🧑‍🎓 学生活动:在 Jupyter 中运行完整的训练代码;调整学习率、隐藏层大小、迭代次数等超参数,观察对训练过程的影响。

将抽象的数学推导转化为可运行的代码,建立“推导 → 实现 → 验证”的完整闭环。通过实际操作理解超参数对训练过程的具体影响。


✍️ 五、 课堂练习与巩固(10 分钟)

📝 任务一:单样本梯度手动计算

题目

考虑一个极简网络:输入层 1 个神经元,隐藏层 2 个神经元(ReLU),输出层 1 个神经元(Sigmoid,二分类)。给定:

  • \( x = 2 \),\( y = 1 \)
  • \( W^{[1]} = \begin{bmatrix} 0.5 \\ -0.5 \end{bmatrix} \),\( b^{[1]} = \begin{bmatrix} 0 \\ 0 \end{bmatrix} \)
  • \( W^{[2]} = \begin{bmatrix} 0.8 & -0.3 \end{bmatrix} \),\( b^{[2]} = \begin{bmatrix} 0 \end{bmatrix} \)

计算:

  1. 前向传播:\( z^{[1]} \)、\( a^{[1]} \)、\( z^{[2]} \)、\( \hat{y} \)
  2. 单样本交叉熵损失 \( L \)
  3. 反向传播:\( \delta^{[2]} \)、\( \delta^{[1]} \)
  4. 参数梯度:\( \frac{\partial L}{\partial W^{[2]}} \)、\( \frac{\partial L}{\partial W^{[1]}} \)
答案与解析
  1. 前向传播: \( z^{[1]} = W^{[1]} x + b^{[1]} = \begin{bmatrix} 0.5 \times 2 \\ -0.5 \times 2 \end{bmatrix} = \begin{bmatrix} 1 \\ -1 \end{bmatrix} \) \( a^{[1]} = \text{ReLU}(z^{[1]}) = \begin{bmatrix} 1 \\ 0 \end{bmatrix} \) \( z^{[2]} = W^{[2]} a^{[1]} + b^{[2]} = 0.8 \times 1 + (-0.3) \times 0 = 0.8 \) \( \hat{y} = \sigma(0.8) = 0.6899 \)

  2. 交叉熵损失: \( L = -[y \log(\hat{y}) + (1-y)\log(1-\hat{y})] = -\log(0.6899) = 0.371 \)

  3. 反向传播: \( \delta^{[2]} = \hat{y} - y = 0.6899 - 1 = -0.3101 \) \( \delta^{[1]} = (W^{[2]})^T \delta^{[2]} \odot \text{ReLU}'(z^{[1]}) = \begin{bmatrix} 0.8 \\ -0.3 \end{bmatrix} \times (-0.3101) \odot \begin{bmatrix} 1 \\ 0 \end{bmatrix} = \begin{bmatrix} -0.2481 \\ 0 \end{bmatrix} \)

  4. 参数梯度: \( \frac{\partial L}{\partial W^{[2]}} = \delta^{[2]} (a^{[1]})^T = -0.3101 \times \begin{bmatrix} 1 & 0 \end{bmatrix} = \begin{bmatrix} -0.3101 & 0 \end{bmatrix} \) \( \frac{\partial L}{\partial W^{[1]}} = \delta^{[1]} x^T = \begin{bmatrix} -0.2481 \\ 0 \end{bmatrix} \times 2 = \begin{bmatrix} -0.4962 \\ 0 \end{bmatrix} \)

📝 任务二:训练超参数调试实验

题目

使用课堂提供的 NeuralNetwork 类,在二分类数据集上完成以下实验:

  1. 固定其他参数,分别设置学习率为 0.001、0.01、0.1、1.0,绘制损失曲线
  2. 观察学习率 1.0 时损失的表现,解释原因
  3. 固定学习率为 0.1,分别设置隐藏层神经元数为 4、16、64、256,记录训练集和测试集准确率
  4. 分析隐藏层神经元数对欠拟合/过拟合的影响
参考结果与解析
学习率 收敛情况 最终测试准确率
0.001 收敛极慢,1000 轮仍损失较高 ~0.82
0.01 正常收敛 ~0.91
0.1 快速收敛 ~0.93
1.0 损失震荡,无法收敛 ~0.50

解析:学习率过小导致梯度更新步长太短,收敛缓慢;学习率过大导致参数更新跳过最优点,损失震荡甚至发散。

隐藏层大小 训练准确率 测试准确率 判断
4 0.78 0.76 欠拟合
16 0.92 0.90 正常
64 0.98 0.91 轻微过拟合
256 1.00 0.85 过拟合严重

📝 六、 课堂小结(5 分钟)

flowchart TB
    root["17-3 反向传播与模型训练"]

    subgraph C1["📐 计算图与链式法则"]
        direction TB
        A1["表达式 → 有向图"]
        A2["前向: 计算节点值"]
        A3["反向: 从输出逐层求导"]
        A4["核心: 链式法则"]
    end

    subgraph C2["📉 反向传播公式"]
        direction TB
        B1["δ[l] = (W[l+1])ᵀ δ[l+1] ⊙ f' (z[l])"]
        B2["∂J/∂W[l] = δ[l] (a[l-1])ᵀ"]
        B3["∂J/∂b[l] = δ[l]"]
        B4["回归: δ[2] = ŷ - y"]
        B5["分类: δ[2] = ŷ - y (相同形式)"]
    end

    subgraph C3["⚠️ 训练关键技术"]
        direction TB
        C1["权重初始化: Xavier / He"]
        C2["学习率选择: 太大震荡/太小收敛慢"]
        C3["监控损失曲线诊断训练状态"]
    end

    subgraph C4["💻 代码实现"]
        direction TB
        D1["前向: 缓存中间变量"]
        D2["反向: 计算梯度"]
        D3["更新: 梯度下降"]
        D4["循环: epoch 迭代"]
    end

    root --> C1
    root --> C2
    root --> C3
    root --> C4

    style root fill:#4b6cb7,stroke:#253b6e,color:#fff,stroke-width:2px
    style C1 fill:#e3f2fd,stroke:#2196f3
    style C2 fill:#fff3e0,stroke:#ff9800
    style C3 fill:#e8f5e9,stroke:#4caf50
    style C4 fill:#f3e5f5,stroke:#9c27b0

✏️ 随堂检测与互动练习

点击展开:随堂测试题(带解析)

一、 单选题

  1. 反向传播算法本质上是:
  • A. 一种新的优化算法,与梯度下降不同
  • B. 链式法则在神经网络中的高效实现
  • C. 一种参数初始化方法
  • D. 一种激活函数的设计方案
【答案】

【解析】B。反向传播(Backpropagation)的核心就是应用链式法则,从输出层向输入层逐层计算复合函数的梯度,是一种高效的计算策略。

  1. 对于回归任务(MSE 损失 + 线性输出),输出层误差 \( \delta^{[2]} = \frac{\partial J}{\partial z^{[2]}} \) 为:
  • A. \( \hat{y}(1 - \hat{y}) \)
  • B. \( \hat{y} - y \)
  • C. \( - (y - \hat{y}) \)
  • D. \( \hat{y} - y \)(与 B 等价)
【答案】

【解析】D。\( J = \frac{1}{2}(\hat{y} - y)^2 \),\( \hat{y} = z^{[2]} \),所以 \( \frac{\partial J}{\partial z^{[2]}} = \hat{y} - y \)。

  1. 对于二分类任务(交叉熵损失 + Sigmoid 输出),输出层误差 \( \delta^{[2]} = \frac{\partial J}{\partial z^{[2]}} \) 为:
  • A. \( \hat{y} - y \)
  • B. \( - (y - \hat{y}) \)
  • C. \( \hat{y}(1 - \hat{y}) \)
  • D. 与回归任务不同,为 \( \frac{\hat{y} - y}{\hat{y}(1 - \hat{y})} \)
【答案】

【解析】A。交叉熵 + Sigmoid 的巧妙之处在于,其导数形式恰好化简为 \( \hat{y} - y \),与回归任务的输出层误差形式相同。

  1. 在反向传播中,误差信号从第 \( l+1 \) 层传递到第 \( l \) 层的公式为 \( \delta^{[l]} = (W^{[l+1]})^T \delta^{[l+1]} \odot f'^{[l]}(z^{[l]}) \),其中 \( \odot \) 表示:
  • A. 矩阵乘法
  • B. 逐元素相乘(Hadamard 乘积)
  • C. 向量加法
  • D. 逐元素除法
【答案】

【解析】B。\( \odot \) 表示逐元素相乘,因为激活函数的导数是逐元素作用于每个神经元,与误差向量的每个元素对应相乘。

  1. 关于权重初始化,以下说法正确的是:
  • A. 所有权重初始化为 0 是最佳策略
  • B. He 初始化适用于 Sigmoid 激活函数
  • C. Xavier 初始化适用于 ReLU 激活函数
  • D. 不恰当的初始化可能导致梯度消失或爆炸
【答案】

【解析】D。A 错误:所有权重为 0 会导致所有神经元对称,无法学习;B 错误:He 初始化适用于 ReLU;C 错误:Xavier 适用于 Sigmoid/Tanh。

二、 计算题

题目

给定单样本二分类网络的输出层信息:\( \hat{y} = 0.7 \),\( y = 1 \)。

(1)计算单样本交叉熵损失 \( L \) (2)计算输出层误差 \( \delta^{[2]} \) (3)若 \( a^{[1]} = \begin{bmatrix} 0.2 \\ 0.8 \\ -0.1 \end{bmatrix} \),\( W^{[2]} = \begin{bmatrix} 0.3 & -0.5 & 0.4 \end{bmatrix} \),计算 \( \frac{\partial L}{\partial W^{[2]}} \)

【答案】

(1)\( L = -[1 \cdot \log(0.7) + 0 \cdot \log(0.3)] = -\log(0.7) = 0.3567 \)

(2)\( \delta^{[2]} = \hat{y} - y = 0.7 - 1 = -0.3 \)

(3)\( \frac{\partial L}{\partial W^{[2]}} = \delta^{[2]} (a^{[1]})^T = -0.3 \times \begin{bmatrix} 0.2 & 0.8 & -0.1 \end{bmatrix} = \begin{bmatrix} -0.06 & -0.24 & 0.03 \end{bmatrix} \)

三、 简答题

题目:解释为什么交叉熵损失配合 Sigmoid 激活函数时,输出层误差 \( \delta^{[2]} = \hat{y} - y \) 的形式与回归任务(MSE + 线性输出)完全相同?这一性质有何实际意义?

【答案】

这一性质源于 Sigmoid 导数的特殊形式:\( \sigma'(z) = \sigma(z)(1 - \sigma(z)) \)。交叉熵损失 \( L = -[y\log \hat{y} + (1-y)\log(1-\hat{y})] \) 对 \( \hat{y} \) 求导得 \( \frac{\partial L}{\partial \hat{y}} = -\frac{y}{\hat{y}} + \frac{1-y}{1-\hat{y}} \),乘以 \( \hat{y}(1-\hat{y}) \) 后恰好化简为 \( \hat{y} - y \)。

实际意义:这使得实现代码时,无论回归还是分类,输出层反向传播的代码可以复用,降低了实现复杂度。同时也说明“损失函数与激活函数匹配”可以大幅简化梯度计算。


📮 七、 课后作业与拓展

📮 课后作业

作业一:反向传播手动推导(必做)

考虑一个单隐藏层回归网络:

  • 输入层:2 个特征
  • 隐藏层:2 个神经元,激活函数为 Sigmoid
  • 输出层:1 个神经元,线性激活
  • 损失函数:MSE

给定单样本 \( x = [1, 0]^T \),\( y = 2 \):

  • \( W^{[1]} = \begin{bmatrix} 0.5 & -0.2 \\ 0.3 & 0.1 \end{bmatrix} \),\( b^{[1]} = \begin{bmatrix} 0.1 \\ -0.1 \end{bmatrix} \)
  • \( W^{[2]} = \begin{bmatrix} 0.6 & -0.4 \end{bmatrix} \),\( b^{[2]} = \begin{bmatrix} 0.2 \end{bmatrix} \)
  1. 完成完整的前向传播,记录所有中间变量
  2. 计算单样本 MSE 损失
  3. 计算所有参数的梯度:\( \frac{\partial L}{\partial W^{[2]}}, \frac{\partial L}{\partial b^{[2]}}, \frac{\partial L}{\partial W^{[1]}}, \frac{\partial L}{\partial b^{[1]}} \)

💡 提示:Sigmoid 导数 \( \sigma'(z) = \sigma(z)(1 - \sigma(z)) \)

作业二:从零实现 MLP 训练(必做)

在 Jupyter Notebook 中完成:

  1. 复现课堂提供的 NeuralNetwork 类,确保能正常运行
  2. 生成 make_moons 数据集(非线性二分类),使用该网络进行训练
  3. 绘制决策边界,观察隐藏层如何将原始空间映射为线性可分
  4. 尝试不同隐藏层大小(5、20、100),对比决策边界的复杂度与泛化能力

作业三:超参数系统实验(必做)

使用课堂提供的代码框架,系统研究以下超参数对训练的影响:

  1. 学习率:[0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0]

    • 绘制各学习率下的损失曲线(叠加在同一张图上)
    • 标注哪个学习率收敛最快且稳定
  2. 隐藏层大小:[4, 8, 16, 32, 64, 128]

    • 记录各配置的训练集和测试集准确率
    • 绘制“隐藏层大小 vs 准确率”曲线
  3. 迭代次数:观察损失曲线的下降趋势,判断是否存在“过早停止”或“过拟合”

作业四:梯度消失实验(选做)

  1. 将隐藏层激活函数从 ReLU 改为 Sigmoid
  2. 构建一个 5 层网络(4 个隐藏层,每层 64 个神经元),在 MNIST 子集上训练
  3. 观察每层的梯度大小分布,验证 Sigmoid 深层网络的梯度消失现象
  4. 对比 ReLU 网络在同样深度下的梯度分布

📋 八、 板书设计

🛠️ 板书设计
 1┌───────────────────────────────────────────────────────────────────────────────┐
 2│                     17-3 反向传播与模型训练                                   │
 3├───────────────────────────────────────────────────────────────────────────────┤
 4│                                                                               │
 5│  一、核心思想:链式法则在神经网络中的高效实现                                  │
 6│                                                                               │
 7│      前向:   x → z¹ → a¹ → z² → ŷ → J                                       │
 8│      反向:   ∂J/∂z² → ∂J/∂a¹ → ∂J/∂z¹ → ∂J/∂x                              │
 9│                                                                               │
10│  二、误差传递公式                                                             │
11│                                                                               │
12│      δ[l] = ∂J/∂z[l]                                                         │
13│      δ[l] = (W[l+1])ᵀ · δ[l+1] ⊙ f'(z[l])                                   │
14│      ∂J/∂W[l] = δ[l] · (a[l-1])ᵀ                                             │
15│      ∂J/∂b[l] = δ[l]                                                         │
16│                                                                               │
17│  三、输出层误差(两种任务)                                                   │
18│                                                                               │
19│      回归:  MSE  + 线性  →  δ[2] = ŷ - y                                    │
20│      分类:  CE   + Sig   →  δ[2] = ŷ - y  ← 形式相同!                      │
21│                                                                               │
22│  四、训练关键技术                                                             │
23│                                                                               │
24│      1. 权重初始化:  He (ReLU) / Xavier (Sigmoid)                            │
25│      2. 学习率:      太大→震荡,太小→收敛慢                                  │
26│      3. 监控损失:    判断是否收敛                                            │
27│                                                                               │
28└───────────────────────────────────────────────────────────────────────────────┘

🔤 本课用到的单词

单词 发音(美式) 解释
Backpropagation /ˈbækˌprɑːpəˈɡeɪʃən/ 反向传播,通过链式法则从输出向输入逐层计算梯度的算法
Chain Rule /tʃeɪn ruːl/ 链式法则,复合函数求导的基本法则,反向传播的数学基础
Computational Graph /ˌkɑːmpjuˈteɪʃənl ɡræf/ 计算图,表示数学运算流程的有向图
Error Signal /ˈerər ˈsɪɡnəl/ 误差信号,即 \( \delta^{[l]} = \partial J/\partial z^{[l]} \)
Gradient Flow /ˈɡreɪdiənt floʊ/ 梯度流动,梯度在网络中反向传播的过程
Vanishing Gradient /ˈvænɪʃɪŋ ˈɡreɪdiənt/ 梯度消失,深层网络中误差信号逐层衰减到零
Exploding Gradient /ɪkˈsploʊdɪŋ ˈɡreɪdiənt/ 梯度爆炸,误差信号逐层增长到极大值
Weight Initialization /weɪt ˌɪnɪʃəlaɪˈzeɪʃən/ 权重初始化,训练开始前为参数赋初值的策略
Xavier Initialization /ˈzeɪviər ˌɪnɪʃəlaɪˈzeɪʃən/ Xavier/Glorot 初始化,适用于 Sigmoid/Tanh 的初始化方案
He Initialization /hiː ˌɪnɪʃəlaɪˈzeɪʃən/ He/Kaiming 初始化,适用于 ReLU 的初始化方案
Learning Rate /ˈlɜːrnɪŋ reɪt/ 学习率,梯度下降中控制参数更新步长的超参数
Convergence /kənˈvɜːrdʒəns/ 收敛,训练过程中损失函数趋于稳定的状态
Epoch /ˈiːpɑːk/ 轮次,训练过程中完整遍历一次全部训练数据
Batch /bætʃ/ 批次,训练时同时处理的一小部分样本集合
Gradient Descent /ˈɡreɪdiənt dɪˈsent/ 梯度下降,沿负梯度方向更新参数的优化算法