2、Transformer基础回顾:多头注意力机制、前馈神经网络、层归一化与残差连接

好,咱们正式开始。在动手剪枝之前,我强烈建议先把Transformer的“骨架”摸清楚。你想想看,如果连模型哪部分最耗算力、哪部分容易冗余都不知道,剪枝就成瞎剪了。

这一节,我会带你快速过一遍Transformer的四个核心组件:多头注意力机制前馈神经网络层归一化残差连接。嗯,都是老面孔了,但咱们这次换个角度——从“哪里能剪”的视角来审视它们。

2.1 多头注意力机制:模型的核心“搜索引擎”

说白了,注意力机制就是让模型学会“看哪里”。它给输入序列里的每个位置分配一个权重,权重越高,说明这个位置对当前输出越重要。

公式长这样:

Attention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V

Q是查询,K是键,V是值。d_k是键的维度,除以它的平方根是为了防止内积过大,把softmax推向梯度饱和区。我在项目中遇到过,如果不做这个缩放,训练初期loss直接炸掉,梯度全变成0。

多头注意力呢?就是把Q、K、V分别投影到h个不同的子空间,每个子空间独立做注意力计算,最后再拼起来。这样做的好处是:模型可以在不同的表示子空间里学到不同的关注模式。

MultiHead(Q, K, V) = Concat(head_1, ..., head_h) * W_O
其中 head_i = Attention(Q * W_Q_i, K * W_K_i, V * W_V_i)

这里W_Q_i、W_K_i、W_V_i是投影矩阵,W_O是输出投影矩阵。每个头的维度通常是d_model / h。

剪枝视角:多头注意力是剪枝的“富矿”。每个头学到的模式往往有冗余,很多头其实贡献很小。我曾经在BERT上做过实验,直接剪掉30%的头,下游任务指标几乎不掉。所以,头剪枝是入门级操作。

我的习惯:在剪枝前,我会先跑一个“头重要性评估”。方法是:随机mask掉一个头,看loss变化有多大。变化小的,优先剪掉。

2.2 前馈神经网络:非线性变换的“加工厂”

注意力层负责“聚合信息”,FFN层负责“加工信息”。每个Transformer块里,注意力后面都跟着一个FFN。

标准的FFN包含两个线性变换,中间夹一个ReLU激活:

FFN(x) = max(0, x * W_1 + b_1) * W_2 + b_2

中间隐藏层的维度d_ff通常是d_model的4倍。比如BERT-base里d_model=768,d_ff=3072。你看,FFN的参数占了模型总参数的大头,大概2/3左右。

为什么会这样?因为注意力层的参数跟序列长度无关,而FFN的参数跟d_model和d_ff直接挂钩。d_ff一放大,参数量就上去了。

剪枝视角:FFN是剪枝的“主战场”。参数多,冗余也大。我常用的做法是:对W_1和W_2做结构化剪枝,直接剪掉整行或整列。比如把d_ff从3072剪到1536,参数量直接减半。

注意:剪FFN时,要同时剪W_1的行和W_2的列,保持维度匹配。我曾经犯过这个错,只剪了W_1没剪W_2,结果矩阵乘法报错,排查了半天才发现。

2.3 层归一化:训练的“稳定器”

层归一化,简称LayerNorm。它的作用是对每个样本的所有特征做归一化,让数据分布更稳定。

公式如下:

LayerNorm(x) = gamma * (x - mu) / sqrt(sigma^2 + epsilon) + beta

mu和sigma是均值和标准差,gamma和beta是可学习的缩放和平移参数。epsilon是个小常数,防止除零。

跟BatchNorm不同,LayerNorm不依赖batch size,所以在NLP任务里更常用。你想想看,文本序列长度不一,用BatchNorm会出问题。

剪枝视角:LayerNorm本身参数很少(就gamma和beta两个向量),剪枝收益不大。但它的位置很关键——通常在注意力层和FFN层之前(Pre-LN)或之后(Post-LN)。我个人习惯用Pre-LN,训练更稳定,剪枝后微调也更容易收敛。

避坑指南:我曾经在剪枝后忘记重新计算LayerNorm的统计量,结果推理时输出全是NaN。记住,剪枝改变了特征分布,一定要重新跑一下forward,更新mu和sigma。

2.4 残差连接:梯度流动的“高速公路”

残差连接,就是让输入直接加到输出上。公式简单:

output = LayerNorm(x + Sublayer(x))

这里Sublayer可以是注意力层,也可以是FFN层。残差连接解决了深层网络的梯度消失问题。没有它,Transformer根本堆不到12层、24层。

为什么有效?因为梯度可以直接通过残差路径回传,绕过了Sublayer里的复杂变换。即使Sublayer的梯度很小,残差路径也能保证梯度不消失。

剪枝视角:残差连接本身没有参数,不需要剪。但剪枝后,残差路径的“信号质量”会受影响。如果剪掉太多头或神经元,残差路径里传的可能就是噪声了。所以,剪枝后一定要做微调,让模型重新适应。

好,四个组件都过了一遍。总结一下:

组件 参数量占比 剪枝潜力 我的建议
多头注意力 约30% 高(头剪枝) 先做头重要性评估,再剪
前馈神经网络 约65% 非常高(神经元剪枝) 结构化剪枝,同时剪W_1和W_2
层归一化 约1% 保留,但需重新计算统计量
残差连接 0% 保留,剪枝后微调

嗯,基础就复习到这儿。下一节,咱们会正式进入剪枝方法,从最简单的“权重剪枝”开始。到时候我会拿实际代码演示,你准备好IDE就行。