07 稀疏正则化剪枝:L1 正则如何诱导参数变稀疏?
一、为什么要讲稀疏正则化剪枝?
前面几篇文章中,我们已经介绍了几类经典剪枝思想:
OBD:利用 Hessian 对角项估计删除权重后的损失变化;
OBS:利用 Hessian 逆矩阵考虑参数之间的补偿;
Han Pruning:通过 Train-Prune-Retrain 流程删除小幅值连接;
Lottery Ticket Hypothesis:研究稀疏子网络能否从原始初始化重新训练。
这些方法大多有一个共同特点:
先训练一个网络,再根据某种重要性指标删除参数。
但是,还有一类方法不是等模型训练完之后再剪,而是在训练过程中就鼓励模型自己变稀疏。
这类方法通常叫做:
稀疏正则化剪枝。
其中最经典的思想就是:
在损失函数中加入 L1 正则项,让不重要的参数逐渐变成 0 或接近 0。
本文就来系统讲清楚:
什么是 L1 正则?
L1 正则为什么会诱导稀疏?
L1 正则和 L2 正则有什么区别?
L1 正则和模型剪枝是什么关系?
为什么 L1 正则不等于真正结构化剪枝?
在 CNN、Transformer 和大模型剪枝中如何理解这种思想?
二、什么是正则化?
在深度学习中,模型训练通常是最小化任务损失,例如分类任务中的交叉熵损失:
如果只优化任务损失,模型可能会过拟合训练数据,也可能学到很多冗余参数。因此,我们常常在损失函数中加入一个额外约束项:
其中:
是总损失;
是任务损失;
是正则项;
是正则强度;
表示模型参数。
正则化的作用是:
不仅要求模型在训练数据上表现好,还要求模型参数满足某种约束。
如果正则项鼓励参数变小,就可以抑制过拟合。如果正则项进一步鼓励参数变成 0,就可能产生稀疏性。
三、什么是 L1 正则?
L1 正则是最常见的稀疏正则化方法。
对于模型参数,L1 正则定义为所有参数绝对值之和:
加入 L1 正则后的训练目标为:
如果越大,模型越倾向于让参数变小,甚至让一部分参数变成 0。
因此,L1 正则的核心作用可以概括为:
在保证任务性能的同时,尽量减少参数绝对值之和,从而诱导模型产生稀疏参数。
这就是 L1 正则和模型剪枝之间的关系。
四、L1 正则为什么会诱导稀疏?
这是本文最核心的问题。为什么 L1 正则会让参数变稀疏?为什么不是所有正则项都能做到这一点?我们先从直觉解释开始。假设模型中有一个参数。如果加入 L1 正则,那么优化目标中会多出一项:
只要不等于 0,这一项就会给损失带来额外惩罚。因此,优化器在训练时不仅要降低任务损失,还要尽量降低参数绝对值。
五、为什么 L1 比 L2 更容易产生稀疏?
为了理解 L1 正则,必须把它和 L2 正则放在一起比较。
L2 正则定义为:
加入 L2 正则后的目标为:
L2 正则对 w_i 的梯度为:
这说明 L2 正则对参数的收缩强度和参数大小有关。
如果 w_i很大,L2 正则会强烈惩罚它;
如果 w_i 已经很小,L2 正则的梯度也会很小。
因此,L2 正则更像是:
把大权重压小,但不一定把小权重压成 0。
而 L1 正则不同。
L1 正则的梯度大小基本是常数:
只要参数不是 0,它就会受到持续的收缩作用。
所以,L1 正则更容易把一部分小权重真正推到 0 附近,甚至变成 0。
一句话概括:
L2 正则让权重变小,L1 正则更容易让权重变成 0。
这就是 L1 正则经常被用于稀疏化的原因。
六、L1 正则和剪枝是什么关系?
L1 正则本身不是剪枝操作,但它可以为剪枝创造条件。
在没有 L1 正则时,很多参数可能只是比较小,但并不明显接近 0。
加入 L1 正则后,不重要的参数会被持续压缩到 0 附近。
此时,如果我们再设置一个阈值:
然后把绝对值小于阈值的参数删除:
就可以得到一个稀疏网络。
所以,L1 正则剪枝通常可以理解为两步:
训练阶段:通过 L1 正则诱导参数接近 0;
剪枝阶段:通过阈值把接近 0 的参数真正删除。
这个流程可以表示为:
训练时加入 L1 正则 → 参数自然变稀疏 → 阈值剪枝 → 微调恢复性能
也就是说,L1 正则的作用不是直接“剪掉参数”,而是让参数更容易被剪。
七、L1 正则的优点
L1 正则剪枝有几个明显优点。
1. 思想简单
L1 正则只是在训练目标中增加一项:
实现起来非常直接。
2. 可以和训练过程自然结合
它不需要等模型训练完再剪,而是在训练过程中逐渐诱导稀疏。
这使得模型有机会在训练阶段主动适应稀疏性。
3. 可以作为剪枝前的稀疏诱导
L1 正则可以让不重要参数集中到 0 附近,使后续阈值剪枝更加稳定。
4. 可以扩展到结构化剪枝
如果对通道、head、neuron 等结构变量加 L1,就可以诱导结构级稀疏。
这比直接对单个权重加 L1 更容易获得实际加速。
八、L1 正则的局限性
L1 正则虽然经典,但也有不少局限。
1. 正则强度难以选择
L1 正则强度 $\lambda$ 太小,稀疏效果不明显;
$\lambda$ 太大,模型性能可能明显下降。
因此,$\lambda$ 是一个非常关键的超参数。
2. 不一定自动产生精确 0
在深度学习优化中,L1 正则通常让参数接近 0,但未必严格等于 0。
因此,仍然需要阈值剪枝。
3. 对所有权重加 L1 可能伤害性能
如果简单粗暴地对所有权重加 L1,可能会过度压缩重要参数,导致模型表达能力下降。
4. 非结构化稀疏不一定带来加速
如果 L1 正则作用于单个权重,得到的通常是不规则稀疏。
这种稀疏形式在普通 GPU 上不一定能显著减少推理延迟。
5. L1 正则不能准确刻画参数重要性
权重小不一定不重要。
某些小权重可能对损失函数很敏感。
L1 正则只是提供一种稀疏诱导,并不能精确估计剪枝后的损失变化。
这也是为什么后续会出现敏感度剪枝、二阶剪枝、梯度剪枝、激活剪枝等方法。
九、L1 正则和模型压缩的真实关系
需要强调一点:
L1 正则本身只是稀疏诱导,不等于模型压缩完成。
要真正实现模型压缩,通常还需要后续步骤:
根据权重或结构变量选择剪枝对象;
删除参数、通道、head 或 neuron;
重建模型结构;
微调恢复精度;
测量真实延迟、显存和吞吐。
如果只是在训练时加入 L1 正则,但没有真正删除参数,那么模型文件大小和推理速度可能不会明显变化。
尤其是在非结构化稀疏中,即使很多权重接近 0,只要矩阵仍然是 dense 存储和 dense 计算,推理速度就不会明显提升。
因此,L1 正则更准确的定位是:
剪枝前的稀疏诱导机制,而不是完整剪枝算法本身。
十、一个简单的 PyTorch 实现思路
如果对所有权重加 L1 正则,训练时可以在任务损失上加一项 L1 penalty。
示意如下:
l1_lambda = 1e-5 task_loss = criterion(outputs, targets) l1_penalty = 0.0 for name, param in model.named_parameters(): if "weight" in name: l1_penalty = l1_penalty + param.abs().sum() loss = task_loss + l1_lambda * l1_penalty十一、L1 正则剪枝适合放在哪里?
在模型剪枝流程中,L1 正则通常有几种使用方式。
1. 从头训练时加入 L1
这种方式希望模型在训练过程中自然形成稀疏性。
流程为:
随机初始化 → 带 L1 正则训练 → 阈值剪枝 → 微调
2. 在预训练模型上稀疏微调
这种方式更常见于已有预训练模型的场景。
流程为:
加载预训练模型 → 加 L1 正则微调 → 产生稀疏结构 → 剪枝 → 再微调
这种方式比从头训练更省成本,也更适合迁移学习和大模型压缩。
3. 对结构 gate 做稀疏化
如果目标是结构化剪枝,可以引入 gate,并对 gate 加 L1。
流程为:
引入结构 gate → 对 gate 加 L1 正则 → 删除小 gate 对应结构 → 微调
这类方法更适合实际部署,因为它能删除完整结构单元。