多层感知机
隐藏层先从输入中算出一些中间特征,再交给输出层。在下面的小网络里,两个神经元分别计算两个输入的差。关掉非线性激活,就能看到为什么光增加层数还不够。
XOR 为什么需要隐藏层?
XOR(异或):两个输入只有一个是 1 时,输出才是 1。切换输入,再关掉 ReLU,看看同一组权重为什么不管用了。
[0, 1] → h = [0, 1] → 输出 = 1
ReLU 保留正的差值,把负数变成 0。两个隐藏值相加,就能判断输入是否不同。
这里的权重是手工选好的,没有训练。它说明这样的表示确实存在,不保证训练一定能找到它。对照全部四种输入
| x₁ | x₂ | 目标 | 输出 |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 |
| 1 | 0 | 1 | 1 |
| 1 | 1 | 0 | 0 |
展开代码 · NumPy / JAX
上面的交互用 JavaScript 运行。下面的 Python 代码使用相同数据和公式,从默认值开始,不跟随当前滑块。JAX 的 jax.grad 可以自动计算损失的梯度。 JAX 自动微分文档
在新的本地项目中,把示例保存为 demo.py。CPU 环境: uv init ai-lab → cd ai-lab → uv add numpy jax → uv run demo.py
import jax.numpy as jnp
# NumPy: replace the import above with: import numpy as jnp
x = jnp.array([[0., 0.], [0., 1.], [1., 0.], [1., 1.]])
w1 = jnp.array([[1., -1.], [-1., 1.]])
w2 = jnp.array([1., 1.])
h = jnp.maximum(x @ w1, 0.)
print(h @ w2) # [0., 1., 1., 0.]
print((x @ w1) @ w2) # [0., 0., 0., 0.]: no ReLU
MLP 的核心结构是交替堆叠仿射变换(Affine Map)和逐元素非线性激活(Elementwise Nonlinearity)。对于输入 ,隐藏层宽度 和输出宽度 ,含一个隐藏层的结构可表示为:
其中 ,。注意,如果去掉激活函数 ,连续的仿射变换会坍缩为单个仿射变换。这意味着,仅靠增加层数(深度)而不引入非线性,无法扩展函数类的表达能力。
输出头、损失函数与假设
隐藏层的激活函数与输出层的语义承担不同职责。不要先选定库中的损失函数,再强行套用业务问题;应根据任务特性反向推导输出头设计。
反向传播的计算本质
设单样本损失为 ,定义 。根据链式法则,梯度计算如下:
自动微分(Autodiff)消除了手写导数的需求,但并未消除对张量形状、数值稳定性及目标函数假设的依赖。梯度为零可能意味着达到最优解,但也可能源于 Sigmoid/Tanh 饱和、ReLU 死亡、错误的 Mask 或计算图断开。
手算一次标量反向传播
取 、、、、,目标 ,损失 。前向计算得到 、、、。反向计算得到 、、、。两层偏置的梯度分别为 和 。所有导数都必须使用同一次前向传播的权重;若先更新 再算 ,求导的就不再是原来的计算。
反向传播负责算梯度,优化器负责更新参数。批次损失若取平均,梯度也应平均;下一次独立更新前要清除已累积的梯度。推理只需前向计算。若网络包含 dropout,训练时会随机屏蔽激活(inverted dropout 会在训练时补偿数值尺度),评估时关闭这种随机性。仅含仿射层和 ReLU 的 MLP 没有这种随模式变化的层。
实例:用两个 ReLU 表示 XOR
对于 ,定义:
当输入相等时( 或 ),输出为 0;当输入不等时( 或 ),输出为 1。单个线性边界无法分离 XOR 问题,而隐藏层首先构建了“输入是否不同”的中间表示。
此例仅证明该表示在数学上存在,并不保证 SGD 能从任意初始化中找到它,也不保证其在噪声数据下的泛化能力。
现代非线性激活
- ReLU:计算廉价,正半轴梯度不饱和,但负半轴单元可能永久失活。它仍是有效的基线,并非在所有架构中都过时。
- GELU 与 SiLU/Swish:平滑的逐元素函数,常见于现代 Transformer 及部分 ConvNet。
- GEGLU/SwiGLU:使用两条投影分支,改变了宽度、参数量和 Kernel 结构,并非简单的即插即用激活函数。
- Sigmoid/Tanh:尽管在大绝对值区域存在饱和问题,但在门控机制和有界状态表示中依然有用。
详见 激活函数与门控前馈网络。公平的性能对比必须控制参数量、FLOPs、训练预算及实现 Kernel。
容量不等于可学习性
Cybenko 定理指出:使用连续 sigmoid 型激活函数的有限个单元之和,可以在紧致立方体上一致逼近任意连续函数,达到任意给定的正误差容限。所需的有限宽度可随目标函数与容限增长,并没有一个固定宽度适用于所有目标。它还不保证:
- 训练数据足够;
- 存在参数或样本高效的表示;
- 优化算法能成功找到该表示;
- 输出概率经过校准;
- 因果有效性或分布外(OOD)泛化能力。
“万能逼近器”(Universal Approximator)是一个理论性质,而非模型选择的依据。
归纳偏置与反例
MLP 将输入视为扁平向量。平移不变性、序列顺序、图结构或置换不变性不会自动出现。CNN、RNN、注意力机制和图网络通过编码更强的参数共享或计算模式,通常能改变样本效率。
反之,在处理稳定的表格特征且数据量有限时,线性模型、树模型或小型 MLP 可能优于复杂的“时尚”架构。必须在相同的数据切分和预算下进行对比。
最小验收标准
- 断言 Batch、特征和输出的张量形状。
- 在极小样本上过拟合,以验证实现的可学习性。
- 与常数、线性或树模型基线进行对比。
- 仅在训练折内拟合预处理步骤。
- 报告多个随机种子、失败案例及资源消耗,而非仅展示最佳运行结果。
- 使用 分布偏移下的评估 测试部署假设。
本文聚焦于传统监督梯度训练,不将 MLP 视为生物模型,也不涵盖所有激活函数和优化器的细节。