第 12 章 神经网络基础

第 9 章的线性模型只能画一张超平面;本章回答:非线性从哪里进入模型、梯度如何沿计算图流回每个参数、怎样用"维度账本"在编码前消灭形状错误。

学习目标

读完本章,你应当能够:

  1. 用"线性映射的复合仍是线性映射"证明单层感知机无法表示 XOR,并说明隐层的作用;
  2. 计算任意 MLP 的参数量,对"加宽还是加深"给出定量判断;
  3. 写出 8 种激活函数的公式与导数,指出各自的失效场景与典型位置;
  4. 复述通用近似定理的四个限定词,区分它保证的与不保证的;
  5. 手推两层 MLP + 交叉熵的全部梯度,并为任意前向网络写出维度账本。

前置知识检查

你需要知道在哪一节补齐
矩阵乘法、转置、Wx 的维度关系第 1 章(向量空间与矩阵运算)
偏导数与链式法则第 6 章引入,本章 12.5、12.6 节完整重推
Softmax、交叉熵、one-hot 标签第 4 章(信息论与交叉熵)
期望与方差的可加性第 4 章;12.7 节与第 13 章 13.1 节反复使用
浮点上溢/下溢与 EPS第 5 章(IEEE 754 与数值稳定性)

12.1 从线性模型到感知机

12.1.1 线性映射的复合仍是线性映射

第 9 章的线性回归与逻辑回归共享同一形状:先算 z = wᵀx + b,再(或不)用单调函数映到输出,几何上是一张超平面。根源在于线性映射对复合封闭:

1
h = W₁x + b₁,  y = W₂h + b₂  ⟹  y = (W₂W₁)x + (W₂b₁ + b₂) = Wx + b

无论堆多少层、每层多宽,只要层间没有非线性,网络在数学上就等价于一次矩阵乘法:参数量上去了,假设空间一点没变大。这正是 【2026-09-02 选择 Q7】 选项 B(“只需激活函数是线性的,含隐层的网络就能逼近任意连续函数”)错误的原因。

12.1.2 感知机与 XOR

感知机是最小的非线性单元:z = wᵀx + b,y = 1[z ≥ 0],决策边界仍是 wᵀx + b = 0。

x₁x₂y = x₁ XOR x₂
000
011
101
110

四个点呈对角分布:(0,1)、(1,0) 属于类别 1,(0,0)、(1,1) 属于类别 0,任何一条直线都分不开。

Minsky 与 Papert(1969)用这个反例指出单层感知机的局限。出路是让网络自己学中间特征:取 h₁ = 1[x₁ + x₂ ≥ 1](“至少一个 1”)、h₂ = 1[x₁ + x₂ ≥ 2](“两个都是 1”),则 y = 1[h₁ − 2h₂ ≥ 1] 恰好给出 XOR。两个隐单元把输入空间重新映射到新空间,在那里 XOR 变成线性可分——整个深度学习都在做这件事。

重要

判断"某函数能否被表示"先问两件事:有没有非线性(没有就只能表示线性映射);需要几个折点(每个隐单元最多贡献一个折点,宽度决定折点数上界)。XOR 需要 2 个折点,故至少 2 个隐单元。

12.2 多层感知机:结构与参数量

12.2.1 前向公式

L 层 MLP(L−1 个隐层 + 输出层)的前向过程,每层都是"仿射变换 + 逐元素非线性",σ 不混合通道:

1
2
3
z^(l) = W^(l) a^(l−1) + b^(l),   W^(l) ∈ R^{m_l × m_{l−1}},  a^(0) = x
a^(l) = σ(z^(l))   (l = 1 … L−1),   ŷ = softmax(z^(L))
m_0 = d(输入维),  m_L = K(类别数)

12.2.2 参数量账本

层 l 的参数量是权重 m_l × m_{l−1} 加偏置 m_l。以 d = 768、隐层 m = 3072、K = 10 为例:

层权重形状权重数偏置数该层合计
隐层3072 × 7682 359 2963 0722 362 368
输出层10 × 307230 7201030 730
总计2 393 098

参数量由相邻两层维度的乘积主导:再加一个 3072 维隐层只增加 3072×3072 + 3072 ≈ 9.44M(约原量的 3.9 倍),而把隐层加宽一倍会让现有隐层参数直接翻倍。

12.2.3 单隐层 vs 深层:存在性与效率是两件事

问题答案依据
单隐层能表示任意连续函数吗?能通用近似定理(12.4 节)
单隐层表示某函数代价小吗?不一定深度分离(depth separation)

深度优势是参数效率而非"能或不能":存在一族函数,L 层深网只需 O(poly(d)) 参数即可逼近,而多项式宽度的浅网需要指数级参数。直觉是组合性——目标若形如 h(h(h(x))),深网共享同一套 h 逐层复用,浅网必须为所有嵌套组合分别准备单元。所以 【2026-09-02 选择 Q7】 选项 A(“增加深度一定比增加宽度更好”)被排除:那是效率层面的结论,不是定理内容,且"一定"过于绝对。

12.3 激活函数谱系

12.3.1 全景表

激活公式导数优点缺点典型位置
Sigmoidσ(z) = 1/(1+e^(−z))σ(1−σ),最大 0.25输出有界 (0,1),可读作概率两端饱和致梯度消失;非零中心二分类输出层
Tanh(e^z−e^(−z))/(e^z+e^(−z))1 − tanh²(z),最大 1零中心,比 Sigmoid 易收敛仍会饱和RNN 候选状态
ReLUmax(0, z)1 (z>0);0 (z<0)正区间梯度恒 1;便宜;稀疏非零中心;负区间硬零CNN / MLP 隐层默认
Leaky ReLUmax(αz, z),α≈0.011 (z>0);α (z<0)负区间保留斜率多一个超参易死网络、判别器
ELUz (z>0);α(e^z−1) (z≤0)1 (z>0);αe^z (z<0)负区间饱和到 −α,均值近 0含 exp,贵早期 CNN
GELUz·Φ(z)(Φ 为标准正态 CDF)Φ(z) + z·φ(z)处处可导、平滑比 ReLU 贵BERT / GPT 系 FFN
SiLU / Swishz·σ(z)σ(z) + zσ(z)(1−σ(z))平滑、非单调、上无界略贵视觉骨干、部分 LLM
Softmaxe^(z_i)/Σ_j e^(z_j)∂ŷ_i/∂z_j = ŷ_i(δ_ij − ŷ_j)输出为概率分布,配交叉熵导数是 ŷ−y需减最大值防上溢多分类输出层、注意力

注意

Softmax 与前七个不同类:前七个逐元素作用,Softmax 是向量到向量的归一化,雅可比是满矩阵而非对角阵——这是 12.6 节唯一要小心的地方。

12.3.2 Sigmoid / Tanh 的饱和,ReLU 的补救与代价

Sigmoid 导数最大只有 0.25(在 z = 0),|z| > 4 时小于 0.018,而这正是输入的常态;深层连乘时每层因子不超过 0.25,20 层后不足 9.1×10⁻¹³(完整推导见 12.7.1)。ReLU 在正区间导数恒为 1,不随 |z| 增大而衰减,连乘中不再有结构性衰减;能否传到第 1 层改由权重尺度决定(初始化问题,见 13.1 节)。代价是 Dead ReLU:若某神经元对所有样本都满足 z < 0,则 a = 0、∂L/∂w = ∂L/∂b = 0,权重不再更新,条件自我锁定,该单元永久失效。

诱因机制对策
学习率过大一次更新把 b 推向很负降学习率、warmup(13.5、13.6 节)
初始化方差过大、深层输入漂移z 尺度偏大且偏负,或均值长期偏移He 初始化(13.1 节)、归一化层(13.2 节)
负区间梯度硬零梯度严格为 0Leaky ReLU / ELU / GELU

12.3.3 GELU 与 SiLU:把"门"做成平滑的

设每个输入乘一个 0/1 门 m,门以概率 Φ(z) 打开(z 越大越可能打开),则 E[z·m] = z·Φ(z)。GELU 正是"按输入大小自适应决定放行比例"的平滑版本:z 很大时 Φ(z) → 1(近似恒等),z 很负时 Φ(z) → 0(近似关闭),z ≈ 0 附近平滑过渡。相比 ReLU 的硬折点它处处可导,对优化更友好;工程上用 0.5z(1 + tanh(√(2/π)(z + 0.044715z³))) 近似。SiLU 是更便宜的同类形式 z·σ(z),非单调(z ≈ −1.28 处取极小)。二者与 ReLU 的共同结构是"门 × 值":ReLU 是硬门 1[z>0]·z,GELU 是概率门 Φ(z)·z,SiLU 是逻辑门 σ(z)·z。

12.4 通用近似定理:它保证了什么

12.4.1 准确表述

设 σ 是非常数、有界、单调递增的连续函数(“挤压型” sigmoid 型激活),K ⊂ R^n 是紧致集,f: K → R 连续。则对任意 ε > 0,存在 N 与参数 w_i ∈ R^n、v_i, b_i, b ∈ R,使

1
sup_{x∈K} | Σ_{i=1}^{N} v_i σ(w_iᵀx + b_i) + b − f(x) | < ε

四个限定词一个都不能丢:紧致集(只在有界闭区域上承诺逼近)、非线性挤压型激活、单隐层(定理恰恰说明宽度就够)、隐藏单元足够多(N 通常极大)。

12.4.2 它没有保证什么

定理保证定理不保证
存在性:存在一组参数使误差 < ε可求性:不保证宽度有限可达,N 可能随 ε → 0 指数增长
表达能力:目标函数在假设空间内优化可达性:损失面非凸,梯度下降能否找到那组参数是另一个问题
单隐层理论上足够泛化与效率:泛化由数据与正则化决定(第 7、8 章);定理也不说浅层需要多少参数,不否认某些函数必须很深才划算

对应 【2026-09-02 选择 Q7】:选项 A(“增加深度一定优于增加宽度”)错在把效率结论当成定理内容且表述过绝对;B(“只需线性激活”)错在线性激活下网络塌缩为一次矩阵乘法(12.1.1 节);D(“总能找到全局最优”)混淆了表达能力与优化可达性;只有 C(非线性激活 + 足够多隐藏单元 + 单隐层)成立。

警告

拿这个定理论证"网络越大越好"或"一定能训到最优"是典型误用:定理一端连着表示能力,另一端不连着随机梯度下降,也不连着测试集表现。选项里出现"总能"“一定"“保证收敛”,先怀疑。

12.5 计算图与自动微分

前向计算就是一张有向无环图:节点是张量,边是基本运算。以 L = ½(wx + b − t)² 为例,计算路径是 w, x ─(×)─ m, b ─(+)─ y, t ─(−)─ e ─(²)─ s ─(×½)─ L。自动微分既不是数值差分也不是符号推导,而是在图上机械地套链式法则:每个算子只需把局部导数交给上游,结果与解析导数在浮点意义下一致。

12.5.1 前向模式 vs 反向模式

设 f: R^n → R^m,一次前向代价为 C。两种模式做的事完全不同:

模式一次传播算出的量完整雅可比 ∂f/∂x 需要适合形状典型场景
前向模式雅可比-向量积 Jv(一个方向导数)n 次传播,代价 n·C输入少、输出多 n ≪ m少量参数求导、ODE 灵敏度
反向模式向量-雅可比积 vᵀJ(上游梯度乘回来)m 次传播,代价 m·C输入多、输出少 n ≫ m神经网络训练

神经网络的形状极极端:参数 n 达 10⁹ 量级,而损失是一个标量(m = 1)。反向模式一次反向就得到全部 n 个偏导,代价约为前向的 2~3 倍;前向模式要 10⁹ 次传播,完全不可行。这就是"神经网络必须用反向传播"的定量原因。

12.5.2 图上的链式法则与局部规则

反向传播的实现只需一张局部导数表:每个算子拿到上游梯度 g,就知道该往每个输入回传什么。

算子前向反向(给定上游梯度 g)
z = x + yz = x + yx̄ += g;ȳ += g
z = x·yz = x·yx̄ += g·y;ȳ += g·x
z = σ(x)Sigmoidx̄ += g·z(1−z)(复用前向输出)
z = exp(x)、z = log(x)e^x、ln xx̄ += g·z;x̄ += g/x
Z = XW(B×d)(d×m)X̄ += G Wᵀ;W̄ += Xᵀ G
Z = softmax(X)逐行归一化X̄ += Ŷ ⊙ (G − (G ⊙ Ŷ 的行和))

关键工程性质:反向传播是”加“的传播。一个张量被多处使用时(如残差里的 x),梯度要把所有路径的贡献求和;用赋值代替 += 是手写自动微分最常见的 bug。下面这个标量引擎可以直接跑出 【2026-08-05 选择 Q5】 的答案:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Val:
    """标量节点:存 data/grad,记录父节点与各处的局部导数 ∂self/∂parent"""

    def __init__(self, data, parents=(), local_grads=()):
        self.data, self.grad, self._p, self._d = data, 0.0, parents, local_grads

    def __add__(self, o):
        o = o if isinstance(o, Val) else Val(o)
        return Val(self.data + o.data, (self, o), (1.0, 1.0))     # 加法局部导数均为 1

    def __mul__(self, o):
        o = o if isinstance(o, Val) else Val(o)
        return Val(self.data * o.data, (self, o), (o.data, self.data))

    def __sub__(self, o):
        return self + (o * -1.0 if isinstance(o, Val) else Val(-o))   # 减法 = 加负数

    def backward(self):
        topo, seen = [], set()

        def build(n):                      # 拓扑序:保证用到的梯度已算完
            if id(n) in seen:
                return
            seen.add(id(n))
            for p in n._p:
                build(p)
            topo.append(n)

        build(self)
        self.grad = 1.0                    # ∂L/∂L = 1
        for n in reversed(topo):
            for p, d in zip(n._p, n._d):
                p.grad += n.grad * d       # 上游梯度 × 局部导数,累加


x, w, b, t = Val(2.0), Val(1.0), Val(0.0), Val(5.0)
y = w * x + b                              # y = 2
loss = (y - t) * (y - t) * Val(0.5)        # L = ½(y−t)² = 4.5
loss.backward()
print(y.data, loss.data, w.grad, b.grad)   # 2.0 4.5 -6.0 -3.0

w.grad = −6 与真题答案一致:(∂L/∂y)·(∂y/∂w) = (y−t)·x = (−3)×2。梯度结构自检法:平方误差的梯度必须含残差因子 (y−t)——残差为零时梯度必须为零。【2026-09-02 选择 Q2】 中 L = (wx+b−y)²,正确答案是 2(wx+b−y)·x;选项 C 的 2(wx+b−y) 只求到外层,漏掉内层因子 ∂(wx+b)/∂w = x。对偏置的梯度才是 2(wx+b−y),因为 ∂(wx+b)/∂b = 1。

12.6 反向传播的完整矩阵推导

12.6.1 设定与前向(单隐层 + Softmax + 交叉熵,单样本、列向量约定)

1
2
3
4
5
x ∈ R^d,y ∈ R^K 为 one-hot
z^(1) = W^(1)x + b^(1)      W^(1) ∈ R^{m×d},  b^(1) ∈ R^m
a^(1) = σ(z^(1))
z^(2) = W^(2)a^(1) + b^(2)  W^(2) ∈ R^{K×m},  b^(2) ∈ R^K
ŷ = softmax(z^(2)),   L = −Σ_{k=1}^{K} y_k log ŷ_k

12.6.2 第一步:损失对输出层激活前值的梯度

先求 ∂L/∂ŷ_k = −y_k/ŷ_k,再乘 Softmax 的雅可比 ∂ŷ_k/∂z_j = ŷ_k(δ_kj − ŷ_j):

1
2
3
4
5
∂L/∂z_j = Σ_k (∂L/∂ŷ_k)·(∂ŷ_k/∂z_j)
        = Σ_k (−y_k/ŷ_k)·ŷ_k(δ_kj − ŷ_j)
        = −Σ_k y_k δ_kj + ŷ_j Σ_k y_k
        = −y_j + ŷ_j · 1        (one-hot 使 Σ_k y_k = 1)
        = ŷ_j − y_j

即 ∂L/∂z^(2) = ŷ − y:Softmax 的满雅可比与交叉熵的对数正好抵消,只留下"预测减真值”。这是交叉熵配 Softmax 而非 MSE 的核心原因(第 9 章)。

12.6.3 第二步:逐层回传

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
∂L/∂W^(2) = (ŷ − y)·a^(1)ᵀ                    (K×m)  ← 与 W^(2) 同形
∂L/∂b^(2) = ŷ − y                              (K)
∂L/∂a^(1) = W^(2)ᵀ(ŷ − y)                      (m)

∂L/∂z^(1) = (∂z^(2)/∂z^(1))ᵀ(ŷ − y)
          = (W^(2) diag(σ′(z^(1))))ᵀ(ŷ − y)
          = diag(σ′(z^(1))) W^(2)ᵀ(ŷ − y)      ← 转置把对角阵挪到左边
          = (W^(2)ᵀ(ŷ − y)) ⊙ σ′(z^(1))        (m)   ⊙ 为逐元素乘

∂L/∂W^(1) = ∂L/∂z^(1)·xᵀ                       (m×d)  ← 与 W^(1) 同形
∂L/∂b^(1) = ∂L/∂z^(1)                           (m)
∂L/∂x     = W^(1)ᵀ ∂L/∂z^(1)                    (d)

第三步的"雅可比转置"是常见卡点:z^(2) = W^(2)σ(z^(1)) 的雅可比是 W^(2)diag(σ′),转置后 diag(σ′) 到左边,于是每一维乘自己的导数,写成 ⊙,无需构造 m×m 矩阵。

12.6.4 维度账本

步骤表达式形状形状自检
前向z^(1) = W^(1)x + b^(1)、z^(2) = W^(2)a^(1) + b^(2)(m)、(K)内维分别对齐 d、m
损失L = −yᵀ log ŷ标量两个 (K) 内积
反向∂L/∂z^(2) = ŷ − y(K)与 z^(2) 同形
反向∂L/∂W^(2) = (ŷ−y)a^(1)ᵀ(K)(m)ᵀ → (K×m)与 W^(2) 同形
反向∂L/∂a^(1) = W^(2)ᵀ(ŷ−y)(m×K)(K) → (m)与 a^(1) 同形
反向∂L/∂z^(1) = (…) ⊙ σ′(z^(1))(m)与 z^(1) 同形
反向∂L/∂W^(1) = ∂L/∂z^(1)xᵀ(m)(d)ᵀ → (m×d)与 W^(1) 同形

提示

“梯度与参数同形"是最好用的一条形状检查:∂L/∂W^(l) 必须与 W^(l) 形状完全一致,∂L/∂b^(l) 与 b^(l) 一致。若把 ∂L/∂W^(2) 写成 a^(1)(ŷ−y)ᵀ,形状会变成 (m×K),与 (K×m) 相反,一眼可见。批处理时样本按行堆叠(X ∈ R^{B×d}),只需把外积换矩阵乘:∂L/∂W^(2) = (∂L/∂Z^(2))ᵀA^(1)、∂L/∂W^(1) = ((∂L/∂A^(1)) ⊙ σ′(Z^(1)))ᵀX,形状分别 (K×B)(B×m)、(m×B)(B×d)。

12.7 梯度消失与梯度爆炸

12.7.1 成因:连乘的谱半径

把第 l 层的梯度写成逐层雅可比的连乘,并看每层因子的谱范数:

1
2
3
4
5
∂L/∂h^(l) = (Π_{k=l}^{L−1} ∂h^(k+1)/∂h^(k)) · ∂L/∂h^(L)
∂h^(k+1)/∂h^(k) = diag(σ′(z^(k)))·W^(k)ᵀ,   记每层谱范数为 ρ
ρ < 1 :  ρ^(L−l) 指数衰减 → 梯度消失(Sigmoid:ρ ≤ 0.25‖W‖,几乎必然 < 1)
ρ > 1 :  指数放大 → 梯度爆炸(1.5²⁰ ≈ 3325)
ρ = 1 :  尺度跨层保持 —— ReLU + He 初始化追求的目标

RNN 是最极端的形态:同一个 V 被反复相乘 N 次,“记住 100 步前的信息"要求特征值都接近 1,实际很难。LSTM/GRU 用门控把梯度通道近似变加法;Transformer 用注意力把任意两位置的路径长度压到 O(1)(第 15 章)。

12.7.2 缓解手段总览

手段针对的机制生效原理
ReLU 族激活Sigmoid 导数上限 0.25 的结构性衰减正区间导数恒为 1
Xavier / He 初始化每层因子尺度失控让前向激活与反向梯度方差跨层守恒(13.1 节)
归一化层(BN/LN/RMSNorm)层输入分布漂移每层把激活重新标准化(13.2 节)
残差连接连乘路径太长提供各层因子为 1 的恒等捷径(13.3 节)
梯度裁剪偶发尖峰导致爆炸给梯度范数设上限(13.5 节)
学习率 warmup初期尺度剧烈波动小步起步,等二阶矩估计稳定(13.6 节)

12.8 计算复杂度与显存:激活值为什么必须保存

每层的反向公式都引用前向的量(∂L/∂W^(l) 需要 a^(l−1),∂L/∂z^(l) 需要 σ′(z^(l))),所以框架默认把前向激活全部留在显存中,用显存换掉一次重复前向:

1
2
3
训练显存 ≈ 参数 + 梯度 + 优化器状态 + 激活值
    参数:P;梯度:P;Adam 的动量与二阶矩:2P(FP32 下合计约 16P 字节量级)
    激活值:∝ B × N × d × L;注意力模块另有 ∝ B × H × N² 的分数矩阵

小模型由前三项主导;大 batch、长序列时激活值迅速成为第一大户。**梯度检查点(gradient checkpointing)**是标准折中:只存每 k 层的边界激活,反向走到该段时从边界重算段内激活,显存从 O(L) 降到 O(√L)(k ≈ √L 最优),代价是多一次前向、训练时间约增 1/3。

推理不保存激活,但峰值显存仍远超模型文件大小,这正是 【2026-08-05 选择 Q13】 的考点:

显存来源与模型文件同量级?说明
权重✓(就是模型文件本身)静态占用
中间激活、临时 buffer / 工作区✓ 常数倍算子之间要传递,多分支并发时并存多份;卷积、归约、注意力的 scratch space
输出类别数、标签类别数、训练集规模✗只影响输出层极小一部分,或推理根本不加载

12.9 前向传播的维度账本

12.9.1 方法与 【2026-08-26 编程题 2】 示例

“公式照抄"型编程题(【2026-08-26 编程题 2】、【2026-09-02 编程题 1】)没有算法难点,失分几乎全部来自维度与约定。可复用流程:① 从输入开始为每个可变量写一行"名字 + 形状”;② 每写一个式子同时写出输出形状,检查内维是否对齐;③ “拼接、投影、残差"三处必须画箭头;④ 把账本翻译成 assert,让程序在第一处错误就报错,而不是静默算完一组合法但错误的数。

题目要求实现"多层双向 RNN → 多头自注意力 → 残差 → 线性输出"的前向,全程在 mod MOD 下进行;约定所有向量为行向量,乘法一律"行向量 × 矩阵”。参数为 N(序列长)、F(输入维)、R(单向隐状态维)、C(输出维)、S(层数)、A(头数)、Q(单头维)。

张量产生方式形状形状自检要点
x_t输入1×F行向量约定
a_t^(l)l=1 时为 x_t1×F(首层)、1×2R(其后)层间维度 d_l = F (l=1),2R (l>1)
p_t^(l)a_t U_f + p_{t−1} V_f + c_f(1×d_l)(d_l×R) → 1×R依赖 t−1;初值 p^(0) 由输入给出
r_t^(l)a_t U_b + r_{t+1} V_b + c_b1×R依赖 t+1;初值是题面给的 r^(N+1),不是 p^(0)
a_t^(l+1)[p_t ‖ r_t]1×2R拼接后正好是下一层输入维
e_t第 S 层输出N×2R后续所有模块共用
q_h^t, k_h^t, v_h^te Q_h、e K_h、e V_h(N×2R)(2R×Q) → N×Q三个投影共用同一个 e
β_hq_h k_hᵀ(N×Q)(Q×N) → N×N题面要求 β 单独取模后再乘 v
c_h、c_tβ_h v_h 后按头拼接N×Q → N×(A·Q)无 softmax、无缩放
u_tc_t W_p + c_p + e_t(N×AQ)(AQ×2R) → N×2RW_p 形状 AQ×2R 正是为压回 2R 才能与 e_t 相加
y_tu_t W_y + c_y(N×2R)(2R×C) → N×C输出 N 行、每行 C 个数

样例(N=2, F=1, R=1, C=1, S=1, A=1, Q=1, MOD=11)给出 e₁ = [1,3]、e₂ = [3,2],注意力输出 c₁ = [10]、c₂ = [8],残差后 u₁ = [0,3]、u₂ = [0,2],最终输出 3、2:每一步都能在账本中对上,数值被 mod 11 折叠。

12.9.2 高发错误、模运算纪律与形状检查代码

坑后果检查方式
层间维度写成"每层都收 F 维”U_f/U_b 行数逐层取错,后面全部错位账本首行写明 d_l 的分段定义
反向 RNN 也初始化成 p^(0)数值合法但全错p^(0) 与 r^(N+1) 各读一次并断言
把行向量当列向量、写成矩阵左乘维度对不上统一"行向量 × 矩阵"并保持到底
中间结果不取模、最后一次性取模结果数学上不变,但定长整型会溢出每个中间量算完立刻 % MOD
1
2
3
4
5
模运算纪律:mod 对加乘封闭(是同态)
(a + b) mod M = ((a mod M) + (b mod M)) mod M
(a × b) mod M = ((a mod M) × (b mod M)) mod M
⟹ 先模后乘不改变结果,只压低中间量的上界
⟹ 对 β 单独取模是工程上的溢出防御,不是数学必需

警告

反直觉点:因为 mod 对加乘可交换,漏取模不会改变最终输出(Python 大整数也不溢出)。真正改变结果的是运算顺序——q、k 写反、漏转置、把反向初值读成正向初值,都会静默算出一组合法但错误的数。定长整型下仍应逐项取模,把中间量压在 MOD² 以内。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import numpy as np


def mm(name, lhs, rhs):
    """行向量约定下的矩阵乘:内维不匹配立刻报错,而不是静默算出错误结果"""
    assert lhs.shape[-1] == rhs.shape[0], f'{name}: 内维不匹配 {lhs.shape} x {rhs.shape}'
    return lhs @ rhs


def layer_dims(feat, hid_dim, n_layers):
    """多层双向 RNN 各层输入维度:首层收 F 维,其后每层收 2R 维"""
    return [feat] + [2 * hid_dim] * (n_layers - 1)

复杂度速查:RNN 部分 O(S·N·R·(d+R)),注意力部分 O(A·N²·Q),投影与输出 O(N·A·Q·R + N·R·C);本题 N ≤ 10、各维 ≤ 5,总运算量不足 10⁵,照公式直写即可,不要引入任何效率技巧。

本章小结

关键结论一句话表述常见错误
非线性的必要性线性层的复合仍是线性映射,堆层数不扩大假设空间以为"层更多"自动等于"表达更强”
XOR 的启示单层感知机只能画一张超平面,隐层把问题重新映射到线性可分空间把 XOR 归因于"数据太少"
参数量由相邻两层维度乘积主导漏偏置;把 d×m 写成 d+m
激活函数Sigmoid/Tanh 饱和;ReLU 正区间导数为 1 故缓解梯度消失,代价是 Dead ReLU深层隐层用 Sigmoid
通用近似定理紧致集 + 非线性挤压型 + 单隐层 + 足够多单元 ⟹ 逼近任意连续函数用它论证"一定能训到最优"
反向传播∂L/∂z^(2) = ŷ − y、∂L/∂W^(2) = (ŷ−y)a^(1)ᵀ,梯度与参数同形漏内层因子;忘记梯度累加
梯度消失/爆炸逐层雅可比连乘,谱半径 <1 消失、>1 爆炸只说"连乘"不解释尺度来源
激活值显存反向需要前向中间量故默认全存;checkpointing 用时间换显存用模型文件大小估算推理峰值显存
维度账本每个张量一行,写形状并检查内维,形状错误要在编码前消灭靠调试器事后找形状 bug

自测题

Q1(计算)某单隐层分类网络 d = 768、隐层 m = 3072、K = 10,各层均带偏置。求总参数量;若再加一个 3072 维隐层,参数量增加多少?

答案与解析

隐层 3072×768 + 3072 = 2 362 368,输出层 10×3072 + 10 = 30 730,总计 2 393 098 ≈ 2.39M;再加一个隐层新增 3072×3072 + 3072 = 9 440 064,约原量的 3.9 倍。易错点:忘记偏置;把 m×d 写成 m+d;把输出层写成 m×K(数量相同,但写反说明维度直觉有问题)。

Q2(推导)证明"Softmax + 交叉熵"对输出层激活前值的梯度就是 ŷ − y。

答案与解析

∂L/∂ŷ_k = −y_k/ŷ_k,∂ŷ_k/∂z_j = ŷ_k(δ_kj − ŷ_j),于是 ∂L/∂z_j = Σ_k (−y_k/ŷ_k)·ŷ_k(δ_kj − ŷ_j) = −Σ_k y_k δ_kj + ŷ_j Σ_k y_k = −y_j + ŷ_j = ŷ_j − y_j(用了 one-hot 的 Σ_k y_k = 1)。若把 Softmax 误当逐元素激活(认为 k ≠ j 时偏导为 0),会得到只有对角项的 −y_j(1−ŷ_j),梯度完全错——这正是"Softmax 雅可比是满矩阵"这个提醒的用途。

Q3(辨析)判断并说明依据:① 通用近似定理说明加深一定比加宽好;② 它保证梯度下降收敛到全局最优;③ 它只对紧致集上的连续函数成立;④ 它要求激活函数非线性。

答案与解析

① 错:深度更省参数是 depth separation 的效率结论,非定理内容,且"一定"过绝对。② 错:定理只保证存在一组参数,不含优化过程信息。③ 对:紧致集是四个限定词之一,定理不对整个 R^n 承诺一致逼近。④ 对但不完整:准确说法是"非常数、有界、单调递增的连续函数"(挤压型);仅线性激活时整网塌缩为一次矩阵乘法。对应 【2026-09-02 选择 Q7】:正确项必须同时具备"非线性挤压型 + 足够多隐藏单元 + 单隐层"。

Q4(判断 + 辨析)【2026-08-26 编程题 2】 中若省略 β 的中间取模,最终输出会变吗?训练时为什么必须保存前向激活,推理却可以释放?

答案与解析

取模:不会变。mod 对加乘封闭,(β mod M) @ v mod M = (β @ v) mod M;题面单独取模是工程纪律(本题上界约 3.5×10⁷ 尚在 32 位内,维度放大后会越界)。真正改变结果的是 q、k 写反、漏转置、把 r^(N+1) 读成 p^(0) 这类错误——它们会静默产出合法但错误的数。

激活值:训练中每层反向都引用前向量(∂L/∂W^(l) 需要 a^(l−1),∂L/∂z^(l) 需要 σ′(z^(l))),故默认全存;检查点只保留每 k 层边界激活、反向时重算段内激活,显存 O(L) → O(√L)(k ≈ √L 最优),代价约 +1/3 时间且不改梯度数值。推理只做前向、无反向依赖,算完一层即可释放;但峰值显存仍远超模型文件,对应 【2026-08-05 选择 Q13】。

与真题的关联

真题考查角度对应小节
【2026-08-05 选择 Q5】单神经元 + 平方误差的反向传播:∂L/∂w = (y−t)x = −6;干扰项为漏内层因子与符号取反12.5.2、12.6.3
【2026-09-02 选择 Q2】L = (wx+b−y)² 对 w 的梯度必须带内层因子 x12.6.1、12.6.4
【2026-09-02 选择 Q7】通用近似定理的四个限定词;表达能力 ≠ 优化可达性12.4.1、12.4.2
【2026-08-05 选择 Q13】推理峰值显存来源:中间激活 + 临时 buffer + 多分支并发12.8
【2026-08-26 编程题 2】前向维度账本、行向量约定、模运算纪律12.9.1、12.9.2
【2026-09-02 编程题 1】同类"公式照抄 + 形状对齐"能力(滑动窗口掩码)12.9.1(方法迁移)

延伸阅读

  • Cybenko (1989)、Hornik (1991):通用近似定理的原始文献;Telgarsky (2016)、Eldan & Shamir (2016):深度分离。
  • Nair & Hinton (2010):ReLU 的来源;Hendrycks & Gimpel (2016):GELU 的动机。
  • Baydin 等 (2018):Automatic differentiation in machine learning: a survey;Chen 等 (2016):梯度检查点;Goodfellow 等《深度学习》第 6、8 章;Minsky & Papert (1969)《Perceptrons》。