跳到内容

第 13 卷 / 第 9 章 / 第 1 课

9.1 仿射层、激活与 Logits:深度来自函数复合,不来自“神经元”这个名字 ​

线性分类器完全能接收 28×28 图像的 784 个像素,并输出十类 logits。它的限制在仿射分数函数:每对类别之间的边界是线性的,像素邻接和平移结构也没有写进模型。

复杂函数可以拆成一连串局部运算。神经网络用可学习的仿射变换和非线性函数构造表示,再由同一个损失端到端调整参数。圆圈画得再像神经元,也不改变这套计算。

本课目标 ​

  • 用张量形状写清 affine layer 与 batch 计算;
  • 解释为什么连续线性层会退化为一个线性层;
  • 用 XOR 看隐藏表示,而不是背“多一层就行”;
  • 区分 logits、probabilities、predictions 和 loss;
  • 理解 MLP 的容量、归纳偏置与适用边界。

1. 一个 Layer 是批量仿射变换 ​

对单个输入 x∈Rdin:

z=Wx+b,

其中 W∈Rdout×din,b∈Rdout。

对 batch X∈RB×din,常按行存样本:

Z=XWT+b,Z∈RB×dout.

PyTorch 的 nn.Linear(in_features, out_features) 正是 y=xWT+b;weight.shape 是 [out_features, in_features],不是反过来。参数数:

doutdin+dout.

下面是可直接运行的 Python 3 / PyTorch 例子,用断言核对 batch 与参数形状,通过时无输出:

python
import torch
from torch import nn

layer = nn.Linear(in_features=784, out_features=128)
assert layer.weight.shape == (128, 784)
assert layer.bias.shape == (128,)

x = torch.randn(32, 784)
z = layer(x)
assert z.shape == (32, 128)

广播让同一个 bias 加到 batch 每一行。理解 shape 比把每个标量画成圆圈更重要:卷积、attention 和并行训练最终都依赖张量维度契约。

2. 只堆线性层不会增加表达能力 ​

两个仿射层:

h=W1x+b1,y=W2h+b2,

可合并为:

y=(W2W1)x+(W2b1+b2).

无论堆多少层,只要中间没有非线性,整体仍是一个 affine map。深度只增加了参数化方式,没有让决策边界变成非线性。

窄隐藏层还可能限制合并矩阵的秩。因此分解形式会改变优化与容量约束,只是不会把整体变成非线性。

激活函数 ϕ 打破合并:

h=ϕ(W1x+b1),y=W2h+b2.

3. XOR 展示的是表示变换 ​

Binary XOR:

text
(0, 0) -> 0
(0, 1) -> 1
(1, 0) -> 1
(1, 1) -> 0

原输入空间不存在一条直线分开两类。令 s=x1+x2,构造两个 ReLU hidden features:

h1=ReLU(s),h2=ReLU(s−1).

则在四个 binary 点上:

f(x)=h1−2h2

恰为 XOR 的 0/1 输出。网络不是神秘地“学会相等与不等”,而是把输入映射到一个可由输出层组合的 piecewise-linear 表示。训练是否真的找到这个解,仍取决于数据、初始化、loss 和优化。

4. 常见激活函数在做什么 ​

ReLU ​

ReLU(z)=max(0,z).

正半轴导数 1、计算简单,使 MLP 成为分段线性函数。负半轴梯度 0 可能使某些单元长期不激活;但“正半轴导数为 1”不能保证深层梯度不消失,因为梯度还要连续乘权重矩阵/Jacobian。

Leaky ReLU / PReLU ​

负半轴保留小斜率,降低永久零梯度风险,但不自动解决坏初始化、学习率或激活分布问题。

Sigmoid / Tanh ​

Sigmoid 把值映射到 (0,1),tanh 映射到 (−1,1)。大绝对值区域导数接近 0,深层反向时容易饱和。它们仍适合 gate、概率链接或有界状态,不等于“已经淘汰”。

GELU / SiLU ​

平滑、非单纯 hard gate,常见于现代架构。哪个更好依赖模型、初始化、归一化和算力;“Transformer 标准激活”不是跨所有实现的固定事实。

不可导点(如 ReLU 的 0)由框架选择一个 subgradient/convention,几乎处处可导已足以使用 gradient-based optimization。

5. MLP 输出的是 Logits ​

十分类模型最后一层通常输出 K=10 个 raw scores:

z=(z1,…,zK).

这些 logits 不是概率。Softmax:

pk=ezk∑jezj

把它们归一化为互斥类别概率。训练时不要手工 softmax 后再交给 PyTorch CrossEntropyLoss;该 loss 直接接收 logits,并用数值稳定方式组合 log-softmax 与 negative log-likelihood。

下例接续上面的 torch、nn 导入,用随机输入和标签检查 loss 接口,不代表已训练出有效分类器:

python
class MLP(nn.Module):
    def __init__(self, input_dim=784, hidden_dim=128, classes=10):
        super().__init__()
        self.network = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, classes),
        )

    def forward(self, x):
        return self.network(x)  # logits, shape [batch, classes]

model = MLP()
x = torch.randn(32, 784)
target = torch.randint(0, 10, (32,), dtype=torch.long)

logits = model(x)
loss = nn.CrossEntropyLoss()(logits, target)
probability = logits.softmax(dim=1)  # 用于解释/评估,不送回同一个 loss
prediction = logits.argmax(dim=1)

CrossEntropyLoss 也支持 soft/probability targets 等模式,shape 和 dtype 规则不同。先明确标签语义,不要靠广播“恰好能跑”。

6. Binary、Multiclass 与 Multilabel 不要混用 ​

Single-label binary ​

可输出一个 logit [B] 或 [B,1],配 BCEWithLogitsLoss 与 float targets 0/1。它把 sigmoid 与 BCE 合并以改善数值稳定。

Single-label multiclass ​

输出 [B,K] logits,配 CrossEntropyLoss 与 long class indices [B]。各类互斥。

Multilabel ​

输出 [B,K] separate logits,配 BCEWithLogitsLoss 与 [B,K] multi-hot/soft targets。每类分别 sigmoid,不使用互斥 softmax。

逐类 sigmoid 不意味着标签在统计上独立,它们仍可共享隐藏表示。BCE 的 target 必须与 logits 形状完全一致,不能把 [B] 和 [B,1] 混用。

pos_weight、class weights 会改变训练 objective,不保证原总体概率仍校准;第 8 章的 calibration/threshold 原则仍适用。

7. 宽度、深度与 Piecewise-linear Regions ​

ReLU MLP 通过多层分段线性映射形成复杂区域。宽度增加每层可用 features,深度复用前层表示,某些函数能以更少单元表达。

Universal approximation theorem 只说明在条件满足、容量足够时存在近似,不保证:

  • 有限数据能识别目标函数;
  • SGD 找得到那个参数;
  • 所需网络/样本/计算量可接受;
  • 分布外仍正确;
  • 预测可校准或因果。

表达能力、可优化性和泛化是三个不同问题。

8. MLP 没有自动理解结构 ​

把 28×28 图片 flatten 成 784 维后,普通 MLP 不知道相邻像素比远处像素更相关,也没有平移 equivariance。它能从数据学习一部分模式,但参数与样本效率可能差。

架构是一种 inductive bias:

  • CNN 偏向局部连接与权重共享;
  • RNN/state-space 偏向序列递推;
  • attention 允许内容相关的跨位置交互;
  • graph network 偏向节点与边关系。

不能因为 MLP 理论上能拟合就忽略数据结构。下一章会把这些 bias 展开。

9. 输入、输出与单位边界 ​

神经网络仍需要数据契约:

  • 数值输入尺度会影响初始化和优化;
  • 类别需要 embedding/编码,ID 数字大小通常没有顺序意义;
  • 缺失值要显式表示;
  • target transform 与 inverse transform 要一致;
  • padding/mask 不能误当真实 token;
  • 训练与部署 normalization statistics 要冻结。

网络并不会自动修复泄漏、错误标签或时间穿越。

常见误区 ​

  • 线性模型不能处理 784 像素:能处理;限制是边界与 inductive bias,不是输入数本身。
  • 多加一层就能学会 XOR:存在解不等于优化一定找到。
  • ReLU 解决了梯度消失:它缓解某些饱和问题,Jacobian 链仍可能消失/爆炸。
  • Softmax 要写进模型再用 CrossEntropyLoss:训练时传 raw logits。
  • 神经网络会自动发现局部结构:架构与数据增强决定许多先验。

练习 ​

  1. 写出 Linear(12, 5) 的 weight/bias/output shape 与参数数。
  2. 用两个 ReLU hidden units 手算四个 XOR 点。
  3. 分别为 binary、multiclass、multilabel 写出 logits/target shape 和 loss。
  4. 删除 MLP 中间 ReLU,代数合并两层并验证输出等价。
  5. 比较 flatten MLP 与具有局部权重共享的模型需要哪些先验。

小结 ​

神经网络是可微函数的组合。Affine layer 变换坐标,激活函数引入非线性,最后一层产生与任务 loss 匹配的 logits。隐藏表示扩大表达能力,但不保证可训练、泛化或理解数据结构。

下一课沿计算图反向走一遍:backpropagation 不是模糊的“分摊责任”,而是 reverse-mode automatic differentiation 对链式法则的高效复用。

Built with VitePress | Software Systems Atlas