ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

L1与L2正则化:原理、区别与实践,解决过拟合的利器

L1与L2正则化:原理、区别与实践,解决过拟合的利器 模型训练到一半验证集的loss怎么都降不下去训练集倒是画出了一条漂亮的下降曲线——这种场景我碰到过太多次了。老手一看就知道是过拟合新手往往要在尝试调大batch size、换优化器、调学习率一系列操作之后才想起来还有一个叫“正则化”的东西。而在深度学习里L1和L2正则化几乎是最基础、最常用的两个手段它们都在解决同一个问题——让模型在训练集之外的数据上也能表现好。这篇文章打算把L1和L2正则化讲透。不只是简单说两句“L1产生稀疏、L2防止过拟合”而是从原理、数学形式、梯度行为、应用场景、调参经验、代码实现到踩坑实录一次性讲清楚。不管你是刚接触神经网络的新手还是已经在跑模型但一直没搞明白setting里weight_decay该设多少的进阶玩家这篇都能给你一些实在的参考。1. 正则化到底在解决什么问题1.1 过拟合训练集上的“伪学霸”先看一个非常典型的场景。你拿到了一个二手房价格预测任务特征有面积、楼层、房龄、装修情况、距地铁站距离等等。训练的时候你的模型在训练集上的预测精确到个位数mae只有几千块结果一上测试集误差直接翻倍。这就好比一个学生把练习册的每一道题都背下来了但考试换了个问法他就不会了——他在练习册上是“学霸”在考场上就露馅了。过拟合的本质是模型把训练数据中的噪声也当成规律学进去了。真实世界里采集到的数据不可避免有测量误差、采样偏差、个案的运气成分。一个足够复杂的模型比如层数很深、每层神经元很多的神经网络有能力非常“仔细”地记下每一个训练样本的特异性导致对训练集拟合得几乎完美但这种完美并没有反映数据背后的真实规律。这时候你会看到一组典型的曲线随着训练进行训练集的loss持续走低但验证集的loss先降后升形成一个“V”字形的拐点。拐点之后模型就是在往过拟合方向跑了。1.2 模型复杂度与泛化能力的博弈那能不能直接把模型变简单一点呢比如减少层数、减少神经元数量可以但这有点“一刀切”的意思。模型太简单又会欠拟合连训练集都学不好更别提泛化了。你需要在“足够复杂以捕获真实规律”和“不要复杂到把噪声也学了”之间找一个平衡。正则化就是这个平衡调节器。它不改变网络结构给损失函数加一项“惩罚项”让模型在训练的过程中不光是降低预测误差还要付出“代价”去维持那些比较夸张、比较极端的参数配置。惩罚会迫使模型往更平滑、更简单、更保守的方向去学习。1.3 偏差与方差的权衡从统计机器学习的角度讲这就是经典的偏差-方差权衡。偏差衡量的是模型预测的“准不准”方差衡量的是模型在不同训练集之间预测的“稳不稳”。没有正则化的复杂模型方差通常很大——换一批训练数据得出的模型差异非常明显这就是过拟合的一种体现。加上合适的正则化后模型会牺牲一点点偏差训练集上的误差可能降不到那么低换取方差的大幅下降测试集上更稳定、更准确。实际在做模型的时候我们要的是测试集上的表现所以这种“用一点点偏差换大量方差下降”的交易几乎总是划算的。2. L1和L2正则化的原理到底差在哪2.1 L2正则化让权重整体变小L2正则化也叫Ridge正则化岭回归里的那个Ridge在神经网络里还有个常见的名字叫权重衰减。它的做法是在原始损失函数后面加上权重逐元素平方和的惩罚项J(W) Loss(W) λ · Σ(W_i²)这里的λ是正则化系数控制惩罚的强度。所有参数的平方和会被加进总损失里因此模型在梯度下降的时候不仅要降低预测损失还要避免让任何一个权重变得过大。L2正则化对梯度的作用效果很有意思。对损失函数求W的梯度你会发现L2项贡献了2λW这一项。参数更新时这一项相当于把当前的权重W按比例缩小了一点点所以叫“权重衰减”。它的效果是模型会倾向于使用把特征尽可能均匀地利用起来的方式去拟合而不是把某个特征的权重推到一个极端值上。2.2 L1正则化让一部分权重归零L1正则化也叫Lasso正则化。它在损失函数后面加的是权重绝对值之和J(W) Loss(W) λ · Σ|W_i|关键在于绝对值函数的特性。当权重W不为0时L1项的导数是λ·sign(W)它给梯度增加了一个恒定的推力把权重往0的方向推。这个推力大小是固定的λ不随权重大小变化。所以哪怕权重已经很小了L1项仍然在持续地“挤”它直到把它挤成0。而L2呢L2项的梯度是2λW权重越小推力就越小。当权重降到0附近的时候L2几乎不再推它了所以L2的结果是权重趋近于0但很少等于0。这就是L1和L2最本质的区别L1能把不重要的权重直接压成0产生稀疏解L2只能把权重压得很小但不会清零。2.3 从梯度角度来看两者对训练过程的影响把两个更新公式放在一起对比看会更清楚L2: W ← W - η·(∇Loss 2λW) L1: W ← W - η·(∇Loss λ·sign(W))差异最明显的地方就在那些“本来就无关紧要”的权重上。这类权重在数据中得到的梯度信号很弱∇Loss项很小。这时候加了L2更新公式里的2λW项会逐渐把W衰减到接近0的一个小值。它几乎不可能让W变成0因为越接近0衰减力度越小。加了L1不管W现在是多少只要不是0sign(W)就是固定1或-1推力恒定。最终权重会被稳定地推向0并在跨过0点之后震荡最后就停在了0上。这也是为什么L1适合做特征选择经过L1正则化训练之后大量特征的权重是精确的0剩下那些非零权重的特征就是模型认为真正有预测力的特征。这个特性在实际工程里非常有用。3. L1和L2实际应用中怎么选3.1 特征量大的场景优先考虑L1如果你面对的输入特征是上千维、甚至上万维而其中大部分特征其实没什么用那么L1正则化会是更好的选择。它天然就是一个“特征筛选器”训练完之后无关特征的权重会变成0你可以直接把这些维度删掉模型不仅更小推理还更快。我实测过一个场景网络上爬回来的文本数据做完TF-IDF和One-Hot之后特征维度到了两万多。直接用L2正则化训练模型效果还行但体积大特征怎么都精简不下来换成L1之后训练完统计一下非零权重的数量只剩几百个模型效果基本没有下降但推理耗时少了将近一半。3.2 特征间存在相关性的场景考虑L2L1的稀疏听起来很好用但它有个问题如果两个特征高度相关L1会随机选择其中一个把另一个权重压成0而保留的那个并非一定更重要。这在特征工程上并不是理想的行为。L2的好处是它会把权重均匀地分配给一组相关的特征不会出现“二选一”的情况。如果特征之间天然就有很强的相关性你的目标也是让模型综合使用这组特征L2会更稳妥。另外从优化稳定性角度看L2让训练过程更平滑因为那个2λW项总是起到稳定梯度方向的作用。3.3 弹性网正则化两者结合不是所有情况都非要二选一。弹性网就是L1和L2的线性组合J(W) Loss(W) λ₁·Σ|W_i| λ₂·Σ(W_i²)弹性网兼顾了两者优点L1部分负责产生稀疏性、做特征选择L2部分负责处理特征间的相关性让被选中的那组特征权重分配得更稳定。在处理高维且特征高度相关的场景时弹性网通常比单独用L1或L2效果更好。在神经网络里直接这样组合用的不多主要是因为超参数多了一个调起来麻烦。但在线性模型、逻辑回归这类模型上弹性网是很好的选择。scikit-learn里直接就有ElasticNet这个类参数l1_ratio就是用来控制L1和L2占比的。3.4 神经网络中L2的特殊形式权重衰减在深度学习框架里L2正则化有一个专门的名字叫权重衰减。PyTorch里的weight_decay参数、TensorFlow的l2_regularizer本质上都是在优化器里额外做了一步L2约束。这里的参数对应的是上面公式里的λ系数它的大小直接影响惩罚强度。有一点必须注意在经典实现里权重衰减通常不加在偏置bias上。偏置只是一个偏移量它对过拟合的影响很小。主流框架的weight_decay默认只作用于权重矩阵不作用于bias如果你手动把所有参数都塞进正则化项很可能把bias也一起惩罚了这会不必要地降低模型的拟合能力。实现的时候要留意一下。4. 正则化系数的选择与调参技巧4.1 λ太小和太大的表现正则化系数λ是整个方案里的核心超参数。它太小正则化不起作用过拟合照样发生它太大模型会被压得过于简单在训练集上的表现都变差这就是欠拟合。观察到的典型现象是λ接近0的时候训练曲线和没有正则化的版本几乎重合验证集loss还是会出现V形拐点。λ逐渐增大训练loss会稍稍升高但验证集loss的拐点会越来越晚出现、最低点也越来越低。λ再继续增大训练loss直线飙升验证集loss也跟着变差说明惩罚过头了。所以选λ的原理很简单在训练集表现还能接受的前提下选验证集表现最好的那个λ。4.2 如何确定合适的λ范围实操层面我一般这么选先用对数网格扫一下量级。λ分别取1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1配合交叉验证快速判断哪个区间最优。在最优区间附近再用等比细粒度的网格微调比如3e-4, 5e-4, 7e-4, 1e-3这样。所谓的“最优”参考指标优先看验证集上的目标度量值而不是loss本身。比如分类任务看F1或者AUC回归任务看MAE或者RMSE。有一个值得注意的经验如果训练数据量比较大λ可以适当小一点。因为大数据的噪声被平均稀释了过拟合风险本身就低不需要那么强的惩罚。反过来数据量少的任务λ要往大了调。4.3 与学习率、批大小的联动关系正则化系数的选择不是孤立的。它和学习率、batch size之间存在联动效应学习率大的时候参数每一步迈得大L2的权重衰减相对更容易把权重拉回来但一不留神正则化的效果就被“噪声梯度”给掩盖了。batch size太小时梯度噪声大训练不稳定这时候L2正则化能起到稳定训练的作用反过来batch size大时梯度比较准对正则化的依赖就小一些。如果用了Adam这类自适应学习率优化器L2的行为会和标准SGD不太一样。Adam内部有梯度缩放机制weight_decay项在Adam里的实际效应不等价于标准权重衰减。这也是为什么很多实战派推荐使用AdamW把权重衰减和梯度更新解耦。我自己做大模型训练的时候无脑选AdamW基本不会错。5. 代码实操在PyTorch中实现L1和L2正则化5.1 实现L2正则化的两种方式PyTorch里实现L2最方便的方式是用optimizer的weight_decay参数一条语句搞定import torch import torch.nn as nn import torch.optim as optim model nn.Sequential( nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, 32), nn.ReLU(), nn.Linear(32, 1) ) # 方式一直接在优化器里加 weight_decay optimizer optim.AdamW(model.parameters(), lr1e-3, weight_decay1e-4) # 方式二手动把惩罚项加到 loss 里 lambda_l2 1e-4 l2_reg torch.tensor(0.0, requires_gradTrue) for name, param in model.named_parameters(): # 只对权重做惩罚不惩罚偏置 if bias not in name: l2_reg l2_reg torch.norm(param, 2) ** 2 loss criterion(model(inputs), targets) lambda_l2 * l2_reg两种方式效果基本一致。但注意方式二里我特意加了if bias not in name的判断这就是上一节提到的细节——只对权重做L2惩罚不动偏置。5.2 实现L1正则化的两种方式PyTorch的优化器里没有现成的weight_decay对应L1逻辑所以L1正则化需要手动实现。常见做法是在计算loss的时候把各层参数绝对值求和加进去lambda_l1 1e-5 l1_reg torch.tensor(0.0, requires_gradTrue) for name, param in model.named_parameters(): if bias not in name: l1_reg l1_reg torch.norm(param, 1) loss criterion(model(inputs), targets) lambda_l1 * l1_reg如果你想同时用L1和L2就把两项都加上调整各自的系数即可。需要注意的是L1的惩罚项梯度是恒定的训练过程中权重被压缩到0的效率更高所以它的λ通常比L2的λ要小一个到两个数量级。我见过很多新手上来就把λ_l1设成和λ_l2一样大结果模型直接欠拟合了。5.3 对照实验加与不加正则化的训练曲线为了让你直观感受下L1和L2的区别我用一个简单的合成数据做了对照实验。数据生成方式是用三个真实特征加上三十个纯噪声特征然后训练一个单隐层网络分别设置不加正则化、加L2weight_decay1e-3、加L1lambda_l15e-5各跑100个epoch。实验结果是配置训练loss验证loss非零权重比例无正则化0.0120.148100%L2正则化0.0210.082100%L1正则化0.0620.091约8%需要注意的是这个“非零权重比例”是在训练结束后把绝对值小于1e-4的权重视为0来统计的。实验里L1把绝大部分噪声特征的权重压到了0附近特征选择效果非常明显。而L2正则化的验证loss表现最好因为它把所有权重都压小了模型整体更平滑。这个结果在特征维度高且大部分特征无用的场景下L1的优势会明显体现而在特征都比较有用、噪声在响应值层面的场景下L2的效果通常更稳。你可以在自己的数据集上跑同样的对比结论基本一致。6. 常见问题与排查技巧实录6.1 L1正则化真的会让所有特征稀疏吗实际运行L1的时候你会发现稀疏性并非一蹴而就。权重不是某一个epoch突然变成0的而是随着训练推进一步步被推向0。而且很多权重虽然在训练结束时很接近0但没有严格等于0——需要加一个极小阈值判断或者显式做一步“裁剪”。另外特征之间量纲不统一会严重影响L1的稀疏效果。如果特征A的取值范围是0到1特征B的取值范围是100到100000那么L1会更倾向于压缩B的权重因为B权重的一个单位变化对预测的影响太大了。实际使用L1做特征选择之前务必先做特征归一化。我踩过这个坑直接在原始量纲上跑L1最后保留下来的特征全是大数值特征小数值但真正有预测力的特征反而被压成了0。6.2 加入正则化后训练损失反而上升了怎么办很多人看到这个现象第一反应是“坏了我的正则化参数加错了”。其实这是正常的。加正则化意味着模型不再允许“完全自由地”降低训练损失它必须同时满足惩罚项的约束。所以训练loss比不加正则化的时候高一点是合理的只要验证loss在下降、最终测试结果有提升那就是有效的。判断正则化是否过重的标准应该是训练loss明显高于验证loss或者两者都久居高位不下这才是惩罚太强、模型欠拟合的信号。遇到这种情况就把λ往小了调。6.3 正则化和BatchNorm能一起用吗能但要注意行为变化。Batch Normalization本身就有隐式的正则化效果——它把每个batch的数据做归一化引入了数据噪声某种程度上和dropout的正则化效果类似。在加了BN的网络里你可能会发现不加L2正则化也能跑得不错甚至加了L2之后效果提升有限。这里有个实操经验如果网络里BN层较多weight_decay可以设置得比平时小一些比如从1e-4降到1e-5。另一方面既然BN自带正则化效果dropout的使用比例也可以适当降低。正则化手段之间不是简单的叠加关系用多了反而会压制模型的表达能力得不偿失。6.4 实际经验中的几个判断信号最后分享几个在实际训练中用来判断正则化效果的经验信号训练loss和验证loss一开始都下降后来训练loss继续降但验证loss开始反弹——这是过拟合信号赶紧上正则化。没加正则化时权重分布长尾严重有些权重的绝对值非常大——这是L2能发挥作用的场景加大weight_decay。发现模型对某些高维稀疏特征非常敏感换一批数据效果就崩——L1的稀疏性会让模型更稳。加了正则化之后验证loss确实更好了但训练loss明显掉不下来——只要验证集效果好训练loss高一点不用太纠结。我在实际项目里最后悔的一件事就是早期太迷信“模型效果不好就换结构”。调了两周的网络结构效果一直在原地打转后来静下心系统地调了一轮正则化参数验证集指标直接涨了两个多点。正则化是投入产出比极高的手段几乎是免费的性能提升空间。所以如果你现在正被过拟合困扰先别急着改网络把L1、L2这些正则化的参数好好扫一遍很多问题至少能缓解一大半。
返回列表