资讯动态

L1与L2正则化全解析:从数学原理到工程调参实战

发布时间:2026/9/8 7:08:02 来源:尧图企业网站定制
每次跟刚入行的朋友聊起正则化大家都习惯性回一句“哦防过拟合的”。这话没错但也就是个安慰自己“懂了”的说法。等你真去调模型L1和L2面对的根本是两个世界的问题一个在逼权重清零一个在把权重往零的方向按。差别这一字工程上的影响天差地别。这篇文章我把L1和L2的数学原理、代码实现、调参踩坑一次讲透不扯虚的。内容适合理清概念的学生、正在调不好模型的算法工程师以及所有想搞明白“正则化系数到底该往哪个方向调”的人。看完你能直接上手改自己的训练脚本也能在面试时把“为什么L1做特征选择、L2做权重衰减”这种问题答得明明白白。1. 为什么要管权重的“大小”过拟合的根源1.1 模型“背答案”和“会解题”的区别先想一个问题训练集上loss降到0.0001验证集loss却大到离谱这模型到底出了什么毛病我在实际项目里见过不少这种情况尤其在样本量小、特征维度高的场景。把神经网络想象成一个学生训练集就是模拟卷验证集是高考真题。这个学生如果记忆力超强能把100套模拟卷的题目和答案一字不差背下来那它在模拟卷上当然是满分。但高考真题一换说法它就傻眼。这就是过拟合的本质——模型把训练集里的噪声也当成规律记下来了。放到神经网络内部看这个“死记硬背”体现在哪里就是权重矩阵的数值变得极端。某些权重会变得非常大大到网络几乎只依赖某几个特征做判断。这不是在学规律这是在记答案。1.2 参数值失控的恶性循环我拆解一个具体例子。假设一个二分类任务输入特征有1000维训练样本只有200条。网络第一层某个神经元发现只要把第377号特征的权重视为12.8把第822号特征视为-15.3就能完美拟合训练集的那几个样本。这个“12.8和-15.3”是真实规律吗大概率不是它只是碰巧对当前样本适用。更麻烦的是一旦某些权重变得非常大梯度回传时这些“大权重”对应的梯度也会变得不稳定模型在下一轮会变本加厉地继续调大这些权重。这就是个恶性循环——权重越大越容易过拟合越过拟合越容易继续放大权重。所以正则化的思路很朴素我不直接限制模型复杂度而是在损失函数里对“权重大小”本身收一笔税让模型在“拟合数据”和“保持权重温和”之间做权衡。2. L1和L2的数学本质一个用绝对值收税一个用平方收税2.1 损失函数的“税务条款”先看广义的损失函数形式$$L_{total} L_{data}(y, \hat{y}) \lambda \cdot \Omega(W)$$其中 $L_{data}$ 是原本的任务损失交叉熵或MSE$\Omega(W)$ 就是正则化惩罚项$\lambda$ 是正则化系数。L1正则化的惩罚项是所有权重的绝对值之和$$\Omega_{L1} \sum_{i} |w_i|$$L2正则化的惩罚项是所有权重的平方和$$\Omega_{L2} \sum_{i} w_i^2$$就这一字之差——绝对值与平方造成了两种完全不同的行为。我反复强调这点因为很多人代码里改了一行API却不知道背后行为差异有多大。2.2 从梯度更新推导L1如何“硬清零”把L1惩罚项加入损失后对某个权重 $w_i$ 求梯度L1项贡献的梯度是 $\lambda \cdot \text{sign}(w_i)$也就是 $\lambda$ 或 $-\lambda$。梯度下降的更新公式变成$$w_i \leftarrow w_i - \eta \cdot \lambda \cdot \text{sign}(w_i) - \eta \cdot \frac{\partial L_{data}}{\partial w_i}$$注意关键点L1给权重的梯度惩罚是恒定值 $\lambda$跟权重本身的大小无关。哪怕权重已经接近0了它依然每轮被推着往0方向走。这个“往0方向”不是比喻——当权重经过0点时$\text{sign}(w_i)$ 会正负翻转权重会跨过0或在0附近震荡终至归零。所以L1的最终结果是大量权重变得严格等于0。这就是稀疏性。稀疏性的价值后面细说但先记住结论L1正则化输出的是稀疏权重矩阵。2.3 L2为什么只能“缩小”而不是“清零”再看L2。对 $w_i^2$ 求导得到 $2w_i$梯度下降的更新公式变成$$w_i \leftarrow w_i - 2\eta\lambda w_i - \eta \cdot \frac{\partial L_{data}}{\partial w_i}$$这个梯度和权重本身成正比——权重越大推力越猛权重越小推力越弱。当 $w_i$ 接近0时惩罚项梯度也趋近0权重只会被“压小”永远不会被“推成严格0”。所以L2得到的是一组“整体变小但都很非零”的权重。这就是L2叫“权重衰减”weight decay的原因在PyTorch里对应的参数直接就叫weight_decay。很多框架的代码里写weight_decay翻译过来就是L2正则化的等价实现。3. 稀疏性和权重衰减两种性格如何影响实战选择3.1 什么场景必须用L1特征选择一个我在项目中反复遇到的场景训练一个高维点击率预估模型原始特征几百万维里面大量特征是无效或近乎重复的。这时候L1就是杀器。因为L1会把不重要的特征权重压成严格0你在训练完之后看权重矩阵等于直接拿到了一份“哪些特征有用”的名单。特征维度自然收缩模型推理时的内存占用和耗时都降下来。我做过一个特征从几十万降到几千的实验模型精度几乎不掉推理速度快了20倍以上。L1本质上是把特征工程和模型训练合并到了一起。反过来说L2给不了你这份名单因为它的权重只是变小但都不会是0。你在高维场景用L2所有特征依然在模型里占着位置没有稀疏化效果。3.2 L2最擅长的地方数值稳定和泛化L2的价值场景是“特征都有点用但谁也别太出风头”。典型的例子是图像分类卷积神经网络提取的每个特征都有意义你要的不是删掉某些特征而是让模型别过度依赖少数特征。L2把所有权重统一缩小模型被迫分散注意力到更多特征上泛化能力自然提升。还有一个很多人没意识到的好处L2能改善优化稳定性。由于大权重对应更大的梯度惩罚L2变相抑制了权重爆炸训练过程不容易出现NaN或者震荡发散的情况。3.3 两个正则化能一起用弹性网正则化有些场景你既想要稀疏性又想要权重平滑这时候单独用L1可能太“暴力”单独用L2又不够“锋利”。业界早有方案弹性网正则化Elastic Net。它的惩罚项是L1和L2的线性组合$$\Omega \lambda_1 \sum |w_i| \lambda_2 \sum w_i^2$$实操中我的习惯是如果特征维度极高先用L1跑一版做特征筛选确定一个候选特征子集再用L2重训一版获得更好的泛化精度。当然弹性网可以一步到位但两个阶段的方案更容易定位问题哪一步效果不好直接换掉。3.4 回归到本质几何视角下的“为什么”从几何上理解L1和L2的区别我讲一个直观版本。在二维权重平面上L2正则化的可行域是个圆形区域L1是菱形区域。损失函数等值线碰到约束边界时菱形边界上的最优点大概率出现在坐标轴的角上——此时某个权重分量为0。而圆形边界上的最优点几乎不可能恰好落在坐标轴上。这就是L1“天然倾向坐标轴”导致稀疏的几何解释。我在团队分享时爱用这个图帮大家记比背公式好使多了。4. 工程实操PyTorch和TensorFlow手把手配置4.1 PyTorch中的weight_decay其实是L2PyTorch的优化器自带weight_decay参数但注意它是L2正则化的等价实现不是L1。我工作中写代码最常用的是SGD和Adam这两种优化器的weight_decay行为在PyTorch里略有差异需要留意。先看SGD常规用法import torch import torch.nn as nn model nn.Sequential( nn.Linear(784, 256), nn.ReLU(), nn.Linear(256, 10) ) optimizer torch.optim.SGD(model.parameters(), lr0.01, weight_decay1e-4)这行的效果等同于在原始损失函数后追加 $\lambda \sum w_i^2$ 惩罚项系数 $\lambda$ 等于weight_decay。但是用Adam时有个细节Adam自带一阶、二阶动量weight_decay的更新方式和SGD不完全等价。PyTorch给Adam单独留了一个参数叫decoupled_weight_decay建议当你用Adam时把weight_decay设为0改用decoupled_weight_decay梯度更新更符合“权重衰减”的本意。这个细节我踩过坑之后在第五部分细说。4.2 PyTorch手动实现L1正则化PyTorch官方没有直接给L1的weight_decay开关因为L1不是简单地在优化器层面做权重衰减它必须把惩罚项加入loss参与反向传播。我提供一个通用封装直接能抄def l1_penalty(model, lambda_l1): l1_loss torch.tensor(0.0, devicenext(model.parameters()).device) for param in model.parameters(): l1_loss torch.abs(param).sum() return lambda_l1 * l1_loss # 训练循环中 for x, y in train_loader: outputs model(x) loss criterion(outputs, y) l1_penalty(model, 1e-5) optimizer.zero_grad() loss.backward() optimizer.step()注意lambda_l1别设太大。我一般建议从1e-5到1e-4之间起步逐步调大。L1惩罚梯度恒定过大会导致几乎所有权重归零模型直接变成“啥都记不住”比过拟合更糟。4.3 Keras/TensorFlow的regularizers相比PyTorchKeras把L1和L2封装得更直观直接在层上挂regularizerimport tensorflow as tf from tensorflow.keras import regularizers model tf.keras.Sequential([ tf.keras.layers.Dense(128, activationrelu, kernel_regularizerregularizers.l2(1e-4)), tf.keras.layers.Dense(10, activationsoftmax, kernel_regularizerregularizers.l1_l2(l11e-5, l21e-4)) ]) model.compile(optimizeradam, losssparse_categorical_crossentropy)这里的kernel_regularizer作用于权重矩阵bias_regularizer作用于偏置activity_regularizer作用于激活输出。十五年来我做CNN相关项目几乎只对kernel做正则化bias一般不管因为bias对过拟合影响极小而且不参与特征的缩放。4.4 超参数怎么调正则化系数lambda的经验法则很多文章讲完理论就停真正上手调参时正则化系数的选择才是大头。我分享几条实战经验直接参考先说最粗暴也最有效的判断标准训练集loss和验证集loss的差距。如果训练集loss低、验证集loss高说明过拟合严重把lambda调大如果训练集和验证集loss都高说明模型欠拟合或正则化过强把lambda调小。经验区间参考场景L2的weight_decay建议L1的lambda建议经典CNN图像分类1e-4 到 5e-41e-6 到 1e-4Transformer类1e-5 到 1e-3一般不用高维稀疏特征5e-4 到 1e-31e-4 到 1e-2RNN/LSTM序列任务1e-5 到 5e-4很少用L1我的调参方法是先用对数轴撒点比如L2分别尝试1e-4、3e-4、1e-3、3e-3看验证集loss变化再做小范围精调。一次只改一个因子不要同时动学习率和正则化系数否则根本定位不到是谁起的作用。5. 踩坑指南正则化的常见问题与排查思路5.1 weight_decay和L2正则化不是永远等价前文提到PyTorch里Adam优化器的weight_decay实现有特殊之处。在PyTorch老版本中Adam的weight_decay是在动量更新后才叠加衰减这会导致大梯度对应更大衰减效果和“在loss里加L2项”不完全等价。尤其学习率较大时两者行为差异更明显。PyTorch后来加了decoupled_weight_decay参数解决这个问题。如果你要严格复现论文里的L2正则化逻辑在Adam下应该这样写optimizer torch.optim.Adam( model.parameters(), lr3e-4, weight_decay0.0, decoupled_weight_decay1e-4 )5.2 L1和BatchNorm的搭配问题这是我最想提醒的坑L1正则化批归一化BatchNorm很容易失效。原因是BatchNorm在训练时会对特征做归一化权重尺度本身被归一化操作“吸收”了。你对权重加L1惩罚网络很容易通过调整BatchNorm的gamma参数来对冲惩罚最终L1根本压不出稀疏性。我记得在某个项目里试过L1BatchNorm权重的稀疏比例跟不加L1几乎一样白白浪费了训练时间。解决办法有两种一是对BatchNorm层后的gamma系数也加上L1惩罚二是干脆在有BatchNorm的网络上改用L2或Dropout。我实测下来第二种更省心因为稀疏性主要场景本来就是高维稀疏MLP很少配合BatchNorm使用。5.3 Dropout和正则化的关系另一个高频疑问是我已经用了Dropout还需要L1/L2吗答案是要看冗余程度。Dropout是“训练时随机丢弃神经元”本质上是让模型学会不依赖特定神经元起集成学习的效果。L2是“限制单个权重的大小”约束的是解空间的范围。两者机制不同、可叠加使用。我见过用Dropout后过拟合还是不改善的情况加上L2立刻见效也见过L2调到很大但过拟合依旧换成Dropout好的情况。建议组合策略可以是先用Dropout控制前向传播的鲁棒性再用L2控制权重能量L1只在明确需要特征筛选时介入。5.4 正则化系数过大导致“欠拟合假象”我最早调L2时犯过一个错误验证集loss不降反增、训练集loss也高我第一反应是模型容量不够开始换更大的网络折腾了一周毫无进展。后来把weight_decay从1e-2降到1e-4模型立刻正常。这个现象说明正则化过强会让模型“什么都不记”表现和欠拟合一模一样。只从loss数字看很难区分是模型容量不足还是正则化过强。排查方法很简单把正则化系数调成0跑几个epoch如果训练loss能降下来说明模型本身容量没问题问题就出在正则化或优化参数上。5.5 L1和L2的调试技巧监控权重的分布实操中我建议在每个epoch结束后把第一层权重的绝对值分布打印出来。如果你用了L2权重分布应该整体向0收缩如果你用了L1权重直方图在0附近应该有一个明显的尖峰而且存在大量严格为0的权重。如果加了L1之后0值权重比例没有任何上升说明惩罚项根本没生效——这时检查是不是写了weight_decay而不是L1是不是把l1_penalty加到loss里但忘了backward前优化器清零或者是BatchNorm在作祟。我习惯写一个简单的TensorBoard钩子把权重L1范数、L2范数和稀疏率都记录下来。这个习惯帮我节省过无数次排查时间。6. 我的个人实战体会6.1 什么时候干脆不用正则化说了这么多最后分享一个看起来反直觉的经验个别场景下我会建议直接关掉正则化。比如用标准循环神经网络处理短序列时模型本身参数规模不大训练集和验证集loss差距很小这时加L2纯属多余。再比如模型处于欠拟合阶段早期训练连训练集都学不进去优化器学习率都没调对先别急着上正则化。正则化是在拟合与泛化之间找平衡不是替优化器擦屁股。我记得有一次训练一个深度神经网络做建材价格预测数据量少但特征都是精挑细选过的加L2反而把测试集效果拉低了。最后我把正则化系数设成0模型直接收敛得更快也更好。6.2 正则化永远不是银弹所有正则化手段L1、L2、Dropout、Early Stopping本质都在对“模型复杂度”做约束但没有一个能拯救垃圾数据。如果你的训练集和测试集分布完全不同或者特征质量太差加再强的正则化也只是让模型“少记一点”本质上还是在退化办法。数据质量、模型结构、训练策略的优先级永远排在正则化超参数之前。6.3 记住一句判断口诀我把自己多年的经验浓缩成一句话看到权重矩阵里有极端大值用L2压住它看到模型把所有特征都当成宝贝用L1逼它做选择。如果你还不确定选哪个先跑L2绝大多数情况下它不会出大问题然后再根据验证集表现决定是否引入L1或弹性网。这个话听起来简单但每个字都是我实际项目里调出来的。训练日志不会骗人权重分布说什么就信什么多盯几轮正则化这件事你很快就能形成自己的手感。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价