多层感知机:结构、BatchNorm、Dropout,附 PyTorch 代码
多层感知机(Multi-Layer Perceptron,简称 MLP )是最基础、最常用的前馈神经网络结构之一。它的核心就是把若干个“线性层(全连接)+ 非线性激活函数”堆叠起来,让网络能够拟合复杂的非线性映射。
1. 多层感知机的基本结构
典型的 MLP 由三部分组成:
- 输入层(\(l = 0\)):接收特征 \(\mathbf{p}_i \in \mathbb{R}^{d_0}\),其中 \(d_0\) 为特征维度。即 \(a^{(0)}_i = \mathbf{p}_i\)(单个样本 \(i\))。
- 若干隐藏层(\(l = 1, \cdots, {L-1}\)):
- 一个典型的“层”包含两步:
- 线性变换: \[ z^{(l)}_i = W^{(l)}a^{(l-1)}_i + b^{(l)},\quad i = 1, \cdots, B \]
- 非线性激活: \[ a^{(l)}_i \leftarrow f^{(l)}(z^{(l)}_i) \]
- 其中:
- \(B\) 为 batch size
- \(z^{(l)}_i,a^{(l)}_i \in \mathbb{R}^{d_l}\)
- \(W^{(l)}\) :第 \(l\) 层的权重矩阵,\(W^{(l)} \in \mathbb{R}^{d_l \times d_{l-1}}\)
- \(b^{(l)}\) :偏置向量,\(b^{(l)} \in \mathbb{R}^{d_l}\)
- \(f^{(l)}(\cdot)\) :非线性激活函数,\(\mathbb{R}^{d_l} \rightarrow \mathbb{R}^{d_l}\)
- 通过多层堆叠\[a^{(l)}_i = f^{(l)}(W^{(l)}a^{(l-1)}_i + b^{(l)})\]实现特征变换,通常包含多个全连接层和非线性激活函数。
- 隐藏层输出维度为 \(d_1, \cdots, d_{L-1}\)
- 一个典型的“层”包含两步:
- 输出层:
- 得到预测 \(\hat y\),通常为一个全连接层。
- 输出维度为 \(d_L\)。
- 分类/回归会用不同输出形式。
如果没有非线性激活(全是线性层),那再多层也等价于“一层线性变换”,表达能力不会变强;非线性是 MLP 能拟合复杂函数的关键。
对一个 batch 输入 \(\mathbf{a}^{(0)} \in \mathbb{R}^{B \times d_0}\),等价于同一个 MLP 被并行地作用在每个样本上。
2. 常见非线性激活函数
\[ \mathrm{ReLU}(x)=\max(0,x) \] 优点:简单、收敛快、缓解梯度消失(相对 Sigmoid/Tanh)。
\[ \mathrm{LeakyReLU}(x)=\max(\alpha x,x),\quad \alpha\in(0,1) \] 特点:负半轴保留小斜率,减少“神经元死亡”。
\[ \sigma(x)=\frac{1}{1+e^{-x}} \] 特点:输出在 \((0,1)\) 区间,常用于二分类输出层;隐藏层使用时更容易梯度消失。
\[ \tanh(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}} \] 特点:输出在 \((-1,1)\),比 Sigmoid 零均值,但仍可能梯度消失。
\[ \mathrm{GELU}(x)=x\Phi(x) \] 其中 \(\Phi(x)\) 为标准正态分布的累积分布函数。特点:比 ReLU 更“平滑”。
3. BatchNorm
实现中最常见顺序:
Linear -> BN -> ReLU
BatchNorm(批归一化)一般作用在每个隐藏层的线性输出上 \[ \mathbf{z}^{(l)} = \begin{bmatrix} (z^{(l)}_{1})^\top\\ \vdots\\ (z^{(l)}_{B})^\top \end{bmatrix} = \begin{bmatrix} \big(W^{(l)} a^{(l-1)}_{1}+b^{(l)}\big)^\top\\ \vdots\\ \big(W^{(l)} a^{(l-1)}_{B}+b^{(l)}\big)^\top \end{bmatrix} \in \mathbb{R}^{B\times d_l}. \]
先对每个特征维度 \(j\)(也就是每个神经元通道)在一个 batch 上计算均值和方差: \[ \mu_j^{(l)}=\frac{1}{B}\sum_{i=1}^B z_{i,j}^{(l)},\qquad (\sigma_j^{(l)})^2=\frac{1}{B}\sum_{i=1}^B(z_{i,j}^{(l)}-\mu_j^{(l)})^2 \] 定义标准化: \[ \hat z^{(l)}_{i,j}=\frac{z^{(l)}_{i,j}-\mu_j^{(l)}}{\sqrt{(\sigma_j^{(l)})^2+\varepsilon}}, \] 其中,\(\varepsilon\) 是一个小常数,用于防止除零错误。
再做可学习缩放平移(\(\gamma^{(l)},\beta^{(l)} \in \mathbb{R}^{d_l}\)): \[ \tilde{z}_{i,j}^{(l)} = \gamma_j^{(l)} \hat z^{(l)}_{i,j}+\beta_j^{(l)}, \] 然后再激活: \[ \tilde{a}_i^{(l)} = f^{(l)}(\tilde{z}_i^{(l)}). \]
BatchNorm 的常见作用:
- 稳定训练、加速收敛
- 对不同 batch 的统计量带来一定“噪声”,具有一定正则化效果
BatchNorm 对 batch size 较敏感,batch 太小(甚至为 1)时效果会明显变差;这时常用 LayerNorm / GroupNorm。
4. Dropout
实现中最常见顺序:
Linear -> BN -> ReLU -> Dropout
Dropout 在训练时随机把一部分样本的一部分神经元激活输出置零,避免网络过度依赖少数神经元,从而抑制过拟合。
比如隐藏层激活为: \[ \mathbf{a}^{(l)} = \begin{bmatrix} (a_1^{(l)})^\top\\ \vdots\\ (a_B^{(l)})^\top \end{bmatrix} = \begin{bmatrix} (f(z_1^{(l)}))^\top\\ \vdots\\ (f(z_B^{(l)}))^\top \end{bmatrix} \in\mathbb{R}^{B\times d_l}. \]
Dropout 产生 mask \(m^{(l)}\in \{0,1\}^{B\times d_l}\),然后 \[ h^{(l)}=\frac{m^{(l)}\odot \mathbf{a}^{(l)}}{1-p}. \] 也就是说:被 mask 为 0 的那些元素(某些样本的某些神经元输出)在这一轮前向里直接变成 0。
- \(m\)(mask)是一个随机 0/1 矩阵(或向量),和 \(\mathbf{a}^{(l)}\) 同形状。
- 其中,\(m_{i,j}\sim \mathrm{Bernoulli}(1-p)\): 每个 \(m_{i,j}\) 独立地取值 \[ m_{i,j}=\begin{cases} 1,&\text{概率 }1-p \\ 0,&\text{概率 }p \end{cases} \] 这就是伯努利分布(Bernoulli distribution),只有 \(0/1\) 两种结果的最基本随机分布。
为什么要除以 \(1-p\)?这是 “inverted dropout” 的写法:
- 训练时:把保留下来的激活放大,使得期望不变;
- 推理时:直接关掉 Dropout(不再随机置零,也不需要缩放,直接使用 \(\mathbf{a}^{(l)}\))。
5. PyTorch 三种结构的初始化代码
下面给出 PyTorch 三种结构的初始化代码。
1 | |
1 | |
1 | |
6. 小结:三者区别一句话
- 经典多层感知机(MLP):Linear + 激活,最基础的非线性拟合器
- MLP + BatchNorm:在层间加入归一化,训练更稳定、收敛更快
- MLP + BatchNorm + Dropout:再加随机丢弃,进一步抑制过拟合(但训练噪声更大)