3.9 Chapter 3 练习题:多层感知机

Author

xcherry9988-code

Published

2026-09-21

Modified

2026-09-21

练习题

1. 如果连续堆叠多个线性层,但层与层之间没有加入任何非线性操作,那么整个模型最终仍然等价于一个 ______ 模型。因此,MLP 会在线性层之间加入 ______,使模型能够表示更加复杂的非线性关系。

2. 在 PyTorch 中使用 nn.CrossEntropyLoss() 完成多分类任务时,模型最后一层应该传给损失函数什么?

A. 已经经过 softmax 的类别概率。
B. 模型直接输出的 logits。
C. torch.argmax 得到的类别编号。
D. 转换成 one-hot 形式的预测结果。

3. 按照本章 NumPy 实现采用的矩阵形式,线性层前向传播为:

\[ Y = XW + b \]

如果上游梯度为:

\[ G = \frac{\partial L}{\partial Y} \]

则反向传播中的三个梯度分别为:

\[ \begin{align} \frac{\partial L}{\partial X} &= \underline{\hspace{2cm}} \\ \frac{\partial L}{\partial W} &= \underline{\hspace{2cm}} \\ \frac{\partial L}{\partial b} &= \underline{\hspace{2cm}} \end{align} \]

4. 关于数值梯度检查,下列说法正确的是:

A. 常用中心差分近似梯度,并与手写 backward 得到的解析梯度比较。
B. 数值梯度检查比反向传播快,因此应该在每个训练 step 都执行。
C. 数值梯度检查可以严格证明模型在所有输入下的 backward 都绝对正确。
D. ReLU 在 0 附近最适合做梯度检查,因为该位置的导数最稳定。

5. 运行下面的代码:

import torch
import torch.nn as nn


model = nn.Sequential(
    nn.Flatten(),
    nn.Linear(28 * 28, 128),
    nn.ReLU(),
    nn.Linear(128, 10),
)

x = torch.randn(32, 1, 28, 28)
logits = model(x)

print('logits.shape:', logits.shape)
print('weight.shape:', model[1].weight.shape)

写出两个输出的形状,并解释它们分别代表什么。

参考答案

1. 答案:线性;激活函数

如果两个线性层连续连接:

\[ \begin{align} H &= XW_1 + b_1 \\ Z &= HW_2 + b_2 \end{align} \]

把前一个式子代入后,仍然可以整理成一次线性变换。因此只有在线性层之间加入非线性激活函数,模型的表达能力才会发生本质变化。

2. 答案:B

nn.CrossEntropyLoss() 接收的是模型直接输出的 logits,而不是已经经过 softmax 的概率。PyTorch 会在内部以数值稳定的方式完成 log-softmax 和对应的分类损失计算,因此通常不应该在调用 CrossEntropyLoss 前手动执行 softmax。

3. 答案:

\[ \begin{align} \frac{\partial L}{\partial X} &= GW^\top \\ \frac{\partial L}{\partial W} &= X^\top G \\ \frac{\partial L}{\partial b} &= \sum_{i=1}^{B}G_i \end{align} \]

其中,输入梯度的形状与 \(X\) 一致,权重梯度的形状与 \(W\) 一致,偏置梯度则需要沿 batch 维度求和。

4. 答案:A

中心差分通过分别对参数增加和减小一个很小的 \(\epsilon\),利用两次前向计算近似真实导数。它通常只适合小模型和少量参数的调试,因为如果有 \(N\) 个参数,就可能需要大约 \(2N\) 次前向传播,计算成本远高于普通反向传播。

5. 答案:

torch.Size([32, 10])
torch.Size([128, 784])

输入共有 32 张图片,每张图片的形状为 \(1\times 28\times 28\),nn.Flatten() 会把每张图片展平成 784 维向量。最后一个线性层输出 10 个类别的 logits,因此整个 batch 的输出形状为 \(32\times 10\)。

网络第一层为:

nn.Linear(784, 128)

PyTorch 中 nn.Linear 的权重形状按照 (out_features, in_features) 保存,所以:

model[1].weight.shape == (128, 784)