☰
L1与L2正则化深度解析:从过拟合排查到稀疏性实战
2026/10/15 7:15:33 网站建设 项目流程

1. 从一次模型过拟合的排查说起

如果你训练过一个稍微复杂点的模型,大概率见过这种场景:训练集上的损失一路降到接近零,准确率刷到99%以上,但一到验证集就拉胯,准确率卡在70%上下死活上不去。更气人的是,你把模型调小一点、数据加多一点,情况会好转,但始终达不到理想状态。这种“训练集学霸、测试集学渣”的现象,就是典型的过拟合。

解决过拟合的手段有很多:增加数据、简化模型、早停、Dropout、数据增强,还有今天要聊的主角——正则化。L1和L2正则化是深度学习里最基础、最常用、也最容易被忽视的两个技术点。说它基础,是因为几乎每个框架都把它封装成了一行参数,比如weight_decay=1e-4或者kernel_regularizer=l2(0.01);说它容易被忽视,是因为很多人调参时只是随手填一个数,从来没想过这个数背后到底在干什么,为什么L1能产生稀疏解而L2不能,为什么L2对大权重惩罚更狠,为什么有些场景下L1反而会让模型更难训练。

这篇内容我会从实际排查过拟合问题的角度出发,把L1和L2正则化的数学原理、代码实现、调参经验、踩坑记录完整地梳理一遍。不管你是刚入门的新手,还是已经调过几十个模型的老手,相信都能从中找到一些之前没注意到的细节。文章会涉及损失函数的构造、梯度推导、稀疏性来源、权重衰减与L2的等价性讨论、实际项目中的参数选择策略,以及我本人在多个模拟项目中积累的一些经验教训。

2. 正则化到底在损失函数里加了什么

2.1 损失函数的原始形态与过拟合的数学本质

先回到最根本的地方。一个模型训练的过程,本质上是在最小化一个损失函数:

L(θ) = (1/N) * Σ loss(y_i, f(x_i; θ))

其中θ是模型参数,N是样本数量。模型通过梯度下降不断调整θ,让预测值f(x_i; θ)尽可能接近真实标签y_i。问题在于,当模型容量足够大时,它可以通过让某些权重变得非常大或非常极端,来“记住”训练样本的噪声和偶然特征,而不是学到真正的规律。

从数学上看,过拟合对应的是参数空间中那些“陡峭”的解——函数在某些方向上变化极其剧烈,输入稍微扰动一下,输出就天翻地覆。这种解在训练集上表现完美,但泛化能力极差。

正则化的思路非常直接:在原始损失函数后面加一项惩罚项,限制参数的大小或复杂度,让模型在拟合数据和保持参数简洁之间做一个权衡。加了正则化之后的损失函数长这样:

L_total(θ) = L_data(θ) + λ * R(θ)

其中R(θ)就是正则化项,λ是正则化系数,控制惩罚的力度。L1和L2的区别,就在于R(θ)的形式不同。

2.2 L2正则化:对大权重施加平方惩罚

L2正则化项的定义是参数向量的L2范数平方:

R_L2(θ) = (1/2) * Σ θ_j^2

前面的1/2是为了求导时方便消掉指数上的2,这是工程实现中的常见做法。加上L2之后,总损失对某个参数θ_j的梯度变成:

∂L_total/∂θ_j = ∂L_data/∂θ_j + λ * θ_j

这意味着每次更新时,参数会额外减去一个与自身大小成正比的量:

θ_j := θ_j - η * (∂L_data/∂θ_j + λ * θ_j) = θ_j * (1 - η * λ) - η * ∂L_data/∂θ_j

注意(1 - η * λ)这一项,它让参数在每次更新时都先“衰减”一点,这也是为什么L2正则化在深度学习框架里常被称为权重衰减(weight decay)。权重越大,衰减得越多;权重越小,衰减得越少。最终效果是模型倾向于让所有参数都保持在一个较小的范围内,函数变得更平滑,泛化能力更强。

这里有一个很多人没注意到的细节:L2正则化和权重衰减在标准SGD下是等价的,但在Adam等自适应优化器中并不完全等价。Adam的权重衰减实现(AdamW)和L2正则化在数学上是有区别的,这个后面会详细说。

2.3 L1正则化:绝对值惩罚与稀疏性的来源

L1正则化项是参数向量的L1范数:

R_L1(θ) = Σ |θ_j|

它对参数的梯度是:

∂R_L1/∂θ_j = sign(θ_j)

也就是说,不管θ_j是多大还是多小,只要它不是零,梯度就是+1或-1。更新规则变成:

θ_j := θ_j - η * ∂L_data/∂θ_j - η * λ * sign(θ_j)

这个更新有一个非常关键的性质:每次更新时,参数会朝着零的方向移动一个固定的量η * λ,而不是像L2那样按比例衰减。当θ_j本身很小时,数据梯度可能比λ * sign(θ_j)还小,这时候参数就会被直接推到零,并且在后续更新中可能一直保持在零附近。这就是L1正则化产生稀疏解的根本原因——它倾向于让一部分参数精确地变成零。

稀疏性带来的好处是特征选择:如果输入特征有几百上千维,L1可以让模型自动挑出真正重要的那些,把不重要的权重压到零。这在某些场景下非常有用,比如高维稀疏特征、需要模型可解释性的任务。

但稀疏性也有代价。L1的梯度在零点不可导,工程实现上通常用次梯度(subgradient)来处理。另外,L1的惩罚力度是恒定的,不会因为权重变小而减弱,这可能导致训练后期参数在零附近震荡,收敛不如L2稳定。

3. 从梯度更新看L1和L2的行为差异

3.1 一个二维参数空间的可视化推演

为了更直观地理解L1和L2的区别,我们可以在二维参数空间里做一个思想实验。假设模型只有两个参数θ_1和θ_2,原始损失函数的等高线是一圈一圈的椭圆,最优解在椭圆中心。加上正则化项后,总损失的等高线会发生变化。

L2正则化项是θ_1^2 + θ_2^2,等高线是圆形。总损失的等高线相当于原始椭圆和圆形的叠加,最优解会被“拉”向原点方向,但不会精确落在坐标轴上。也就是说,L2会让参数变小,但通常不会让任何一个参数精确为零。

L1正则化项是|θ_1| + |θ_2|,等高线是菱形。菱形在坐标轴上有尖角,而原始损失的椭圆和菱形相切的位置,大概率会落在尖角上。尖角对应的就是某个参数为零的位置。这就是L1稀疏性的几何解释——菱形的尖角天然吸引最优解落在坐标轴上。

这个几何直觉非常重要。很多人只记住了“L1稀疏、L2平滑”这个结论,但不知道为什么。理解了菱形和圆形的区别,你就能自己推导出更多性质,比如为什么L1在特征维度很高时特别有用,为什么L2更适合处理共线性特征。

3.2 权重衰减系数的实际影响

在实际代码中,L2正则化通常通过优化器的weight_decay参数来实现。以PyTorch为例:

optimizer = torch.optim.SGD(model.parameters(), lr=0.01, weight_decay=1e-4)

这个1e-4就是λ。它的大小直接影响模型的行为。我做过一组对比实验,在一个图像分类任务上,固定学习率0.01,只改变weight_decay:

weight_decay训练准确率验证准确率训练/验证差距
099.8%72.3%27.5%
1e-598.5%78.6%19.9%
1e-495.2%84.1%11.1%
1e-388.7%82.5%6.2%
1e-276.4%74.8%1.6%

可以看到,weight_decay从0增加到1e-4时,验证准确率提升非常明显,训练和验证的差距大幅缩小。但继续增加到1e-2时,模型开始欠拟合,训练准确率掉得厉害,验证准确率也跟着下降。这说明正则化系数存在一个“甜点区”,太小起不到作用,太大又会压制模型的学习能力。

注意:这个表格里的数值是基于特定任务和模型结构的,不同任务的最优weight_decay可能相差几个数量级。图像分类常用1e-4到1e-2,NLP任务常用1e-5到1e-3,具体要看模型大小和数据量。

3.3 L1在深度学习框架中的实现差异

L1正则化在PyTorch中没有像weight_decay那样的直接参数,需要手动加到损失函数里:

def l1_regularization(model, lambda_l1): l1_loss = 0 for param in model.parameters(): l1_loss += torch.sum(torch.abs(param)) return lambda_l1 * l1_loss # 训练循环中 total_loss = data_loss + l1_regularization(model, 1e-5)

这里有一个坑:L1正则化通常只加在权重上,不加在偏置(bias)上。因为偏置的数量很少,对模型复杂度的贡献很小,惩罚偏置反而可能影响模型的拟合能力。同样,BatchNorm层的缩放和平移参数通常也不加正则化。这个细节在手动实现时很容易忽略。

另外,L1的lambda通常比L2小一到两个数量级。因为L1的梯度是恒定的sign值,而L2的梯度与权重成正比。当权重很小时,L1的惩罚力度相对更大。我一般会先用L2调出一个不错的模型,然后把L2换成L1,lambda取原来的1/10到1/5,再微调。

4. 稀疏性、特征选择与L1的独特价值

4.1 为什么稀疏解在高维场景下如此重要

假设你在做一个文本分类任务,输入是词袋模型,维度可能上万。如果每个词都对应一个非零权重,模型会变得非常臃肿,推理速度慢,而且容易过拟合。L1正则化可以把大部分不重要的词权重压到零,只保留几百个真正有区分度的词。这不仅减小了模型体积,还提高了可解释性——你可以直接看哪些词被保留了,哪些被丢弃了。

在推荐系统、生物信息学、金融风控等领域,特征维度往往远大于样本量,L1的特征选择能力几乎是刚需。我做过一个模拟项目,输入特征有5000维,样本只有2000条。不加正则化时,模型在训练集上完美拟合,验证集AUC只有0.62。加上L1正则化后,模型自动选择了约300个非零特征,验证集AUC提升到0.81,而且推理速度提升了十几倍。

4.2 L1稀疏性的局限与替代方案

L1虽然能产生稀疏解,但它有几个明显的局限。第一,当特征之间存在高度相关性时,L1倾向于随机选择其中一个而丢弃其他,这会导致结果不稳定——换一组训练数据,选中的特征可能完全不同。第二,L1的优化不如L2平滑,收敛速度可能更慢,尤其是在训练后期。第三,L1在深度学习中的效果往往不如在传统线性模型中那么显著,因为深度神经网络的参数本身就存在大量冗余,稀疏性带来的收益可能被网络结构的复杂性抵消。

针对这些问题,实践中衍生出了一些替代方案。Elastic Net结合了L1和L2,既能产生稀疏解,又能处理相关特征。Group Lasso把参数分组,以组为单位进行稀疏化,适合处理结构化特征。在深度学习中,还有专门的结构化剪枝方法,通过移除整个神经元或卷积核来实现稀疏化,效果比单纯的L1更好。

4.3 一个L1特征选择的实操案例

我在一个模拟的信用评分项目中用过L1正则化做特征选择。数据有8000条样本,1200个特征,包括数值特征和类别特征的独热编码。模型是一个三层的全连接网络。

第一步,先不加正则化训练一个基线模型,验证集AUC约0.74,但训练集AUC达到0.96,过拟合严重。

第二步,加L2正则化,weight_decay从1e-5试到1e-2,最优在1e-3左右,验证集AUC提升到0.79。

第三步,换成L1正则化,lambda从1e-6试到1e-3。当lambda=1e-4时,验证集AUC达到0.80,同时第一层权重中有约65%变成了零。检查非零权重对应的特征,发现大部分是收入、负债率、查询次数等业务上合理的变量,而一些随机生成的噪声特征被正确丢弃了。

这个案例说明,L1不仅能提升泛化能力,还能提供特征重要性的参考。但要注意,L1选出的特征不一定是最优的,它只是让模型在训练数据上表现最好的同时保持稀疏。如果业务上需要强制保留某些特征,可以在L1基础上加约束,或者改用Group Lasso。

5. 权重衰减与L2等价性的深度辨析

5.1 SGD下两者为什么等价

在标准SGD中,L2正则化和权重衰减在数学上是完全等价的。前面推导过,L2正则化让梯度多了一项λ * θ_j,更新时相当于θ_j乘以(1 - η * λ)。而权重衰减的实现方式是在每次更新时直接让θ_j乘以(1 - η * λ),不经过损失函数。两者在SGD下的更新公式一模一样。

这个等价性成立的前提是:学习率η固定,且优化器是标准SGD。一旦学习率是动态调整的,或者使用了自适应优化器,等价性就可能被打破。

5.2 Adam中L2与权重衰减的分道扬镳

Adam优化器的更新规则涉及一阶矩和二阶矩的估计。如果把L2正则化加到损失函数里,梯度中的λ * θ_j会进入一阶矩和二阶矩的计算,导致自适应学习率对正则化项也起作用。结果是,对于梯度较大的参数,正则化力度会被自适应地减小;对于梯度较小的参数,正则化力度会被放大。这显然不是我们想要的效果——我们希望正则化对所有参数一视同仁。

AdamW(Adam with decoupled weight decay)把权重衰减从梯度计算中分离出来,直接在参数更新时乘以衰减系数,不经过自适应学习率的调整。这样权重衰减的行为就和SGD中一致了。实验表明,在Transformer等模型上,AdamW比带L2的Adam效果更好,训练更稳定。

提示:如果你在用Adam或AdamW,建议优先使用AdamW的weight_decay参数,而不是在损失函数里手动加L2。PyTorch中torch.optim.AdamW已经内置了正确的权重衰减实现。

5.3 实际项目中的选择建议

根据我的经验,选择L2还是权重衰减,主要看优化器类型。用SGD或SGD with momentum时,两者等价,随便选。用Adam时,优先用AdamW的weight_decay。用RMSprop或其他自适应优化器时,需要查一下框架文档,确认weight_decay的实现方式。

另外,权重衰减对学习率的敏感度比L2更高。因为权重衰减的力度直接和学习率相乘,学习率调大时,等效的正则化力度也会变大。所以当你调整学习率时,可能需要同步调整weight_decay。我通常的做法是:先固定weight_decay,调好学习率,然后再微调weight_decay。

6. 调参实战:从1e-6到1e-2的搜索策略

6.1 正则化系数的量级选择

正则化系数λ的取值范围通常跨越好几个数量级。对于L2/权重衰减,常见的搜索范围是1e-6到1e-2。对于L1,常见范围是1e-7到1e-3。具体选哪个量级,取决于模型大小、数据量和任务难度。

一个经验法则是:模型参数越多、数据越少,需要的正则化越强。比如一个百万参数的小模型在十万条数据上训练,weight_decay=1e-5可能就够了;而一个亿级参数的大模型在同样数据上训练,可能需要1e-3甚至更大。

另一个经验法则是:先跑一个不加正则化的基线,观察训练集和验证集的差距。差距越大,需要的正则化越强。如果差距很小,说明模型本身没有严重过拟合,正则化可以轻一些。

6.2 对数均匀搜索与二分微调

我通常采用两阶段搜索。第一阶段,在对数尺度上均匀取点,比如[1e-6, 1e-5, 1e-4, 1e-3, 1e-2],每个值跑一次短训练(比如10个epoch),看验证集指标。第二阶段,在最优值附近做二分微调,比如最优是1e-4,就试[5e-5, 1e-4, 2e-4, 5e-4],进一步缩小范围。

这个方法比随机搜索更高效,因为正则化系数的影响通常是对数尺度上单调的——太小不起作用,太大欠拟合,中间有一个峰值。对数均匀搜索能快速定位峰值所在的数量级。

6.3 与学习率、批大小的交互影响

正则化系数不是孤立的,它和学习率、批大小有复杂的交互。学习率越大,权重衰减的等效力度越大(因为更新步长更大)。批大小越大,梯度估计越准确,正则化的效果也越稳定。

我遇到过一种情况:把批大小从32增加到256后,原来的weight_decay=1e-4变得太强了,模型欠拟合。原因是批大小增加后,梯度噪声减小,模型本身就更稳定,不需要那么强的正则化。把weight_decay降到1e-5后,效果恢复正常。

所以调参时不要只盯着正则化系数,要把它和学习率、批大小放在一起考虑。一个实用的策略是:先固定批大小和学习率,调正则化;然后固定正则化,微调学习率;最后再回头微调正则化。迭代两三轮,基本能找到不错的组合。

7. 那些年我踩过的正则化坑

7.1 对偏置和BatchNorm参数加了正则化

这是新手最容易犯的错误。在手动实现L1或L2时,把模型所有参数都加进了正则化项,包括偏置和BatchNorm的缩放平移参数。结果模型训练变得极不稳定,验证集指标波动很大。

原因很简单:偏置和BatchNorm参数的数量很少,对模型复杂度的贡献微乎其微,惩罚它们只会限制模型的拟合能力,不会改善泛化。正确的做法是只对权重矩阵(卷积核、全连接层的weight)加正则化。

在PyTorch中,可以通过参数分组来实现:

weight_params = [] bias_params = [] for name, param in model.named_parameters(): if 'bias' in name or 'bn' in name: bias_params.append(param) else: weight_params.append(param) optimizer = torch.optim.SGD([ {'params': weight_params, 'weight_decay': 1e-4}, {'params': bias_params, 'weight_decay': 0} ], lr=0.01)

7.2 L1正则化导致训练后期loss震荡

L1的梯度是sign函数,在零点附近不连续。当参数接近零时,数据梯度和正则化梯度可能相互抵消,导致参数在零附近来回跳动,loss曲线出现震荡。这个问题在训练后期特别明显。

解决方法有几个:一是用平滑L1(smooth L1),在零点附近用二次函数代替绝对值,梯度连续;二是用次梯度方法,在零点取零梯度;三是降低L1的lambda,减小震荡幅度;四是改用Elastic Net,用L2的平滑性来稳定训练。

我一般会先用L2训练到一个不错的解,然后换成L1做微调,lambda取L2的1/10左右。这样既能获得稀疏性,又不会从头开始训练导致不稳定。

7.3 正则化系数太大导致模型欠拟合

有一次我在一个NLP任务上把weight_decay设成了1e-2,结果模型在训练集上的准确率只有60%,验证集55%,明显欠拟合。当时我以为是模型结构有问题,排查了半天才发现是正则化太强。

判断正则化是否过强的方法很简单:看训练集损失。如果训练集损失下降很慢,或者最终值远高于不加正则化时的值,说明正则化太强了。另一个信号是训练集和验证集的指标都很低,且差距很小——这不是泛化好,而是模型根本没学到东西。

注意:正则化的目标是缩小训练集和验证集的差距,而不是让两者都变低。如果两者都低,说明模型欠拟合,应该减小正则化系数或增加模型容量。

7.4 在微调预训练模型时用了过大的weight_decay

微调预训练模型时,模型已经在大规模数据上学到了很好的特征表示,只需要在小数据集上微调。这时候如果weight_decay设得太大,会破坏预训练学到的权重,导致灾难性遗忘。

我一般会在微调时用比从头训练更小的weight_decay,比如1e-5到1e-6。有些实践者甚至会对预训练层和新增层使用不同的weight_decay,预训练层用更小的值,新增层用正常值。这个策略在Transformer微调中特别常见。

8. 不同任务场景下的正则化策略选择

8.1 图像分类:L2为主,适度使用Dropout

图像分类任务中,L2/权重衰减是标配。ResNet、EfficientNet等经典模型在训练时通常使用weight_decay=1e-4到1e-5。数据增强和Dropout也是常用的正则化手段,和L2配合使用效果更好。

在图像任务中,L1用得相对较少,因为卷积核的稀疏性不一定能带来推理加速(除非用专门的稀疏计算库),而且图像特征本身是稠密的,强制稀疏可能损失信息。不过在一些需要模型压缩的场景下,L1可以用来做通道剪枝的辅助。

8.2 NLP任务:AdamW加权重衰减,注意Embedding层

NLP任务中,Transformer类模型通常用AdamW,weight_decay在0.01左右。但要注意,Embedding层和LayerNorm层的参数通常不加权重衰减,或者用很小的值。因为Embedding层参数量大但每个参数更新频率低,过强的衰减会导致词向量退化。

另外,NLP任务中L1的使用也比较少,因为词嵌入的稀疏性不如传统词袋模型那么有意义。但在一些需要特征选择的场景,比如文本分类中的关键词提取,L1仍然有用武之地。

8.3 表格数据:L1和L2都值得尝试

表格数据(结构化数据)是L1和L2都能发挥作用的场景。特征维度可能很高,样本量可能有限,过拟合风险大。我通常先试L2,如果特征维度特别高或者需要特征选择,再试L1。Elastic Net在表格数据上往往表现最好,因为它结合了两者的优点。

在表格数据上,正则化系数的搜索范围可以更宽一些,从1e-6到1e-1都值得试。因为表格数据的特征尺度差异大,正则化的效果对尺度很敏感。建议在正则化之前先做特征标准化,否则L2会过度惩罚那些本身数值就大的特征。

8.4 小样本学习:强正则化与早停结合

小样本场景下,过拟合是最大的敌人。这时候需要强正则化,weight_decay可以设到1e-3甚至1e-2,同时配合早停、Dropout、数据增强等手段。L1在小样本下也能帮助模型聚焦到少数关键特征上。

但要注意,小样本下验证集也很小,调参的可靠性下降。我通常会用交叉验证来评估正则化系数的效果,而不是只看单次验证集的结果。另外,小样本下正则化系数的微小变化可能导致结果的巨大波动,所以不要过度精细地调参,选一个数量级上合理的值就行。

9. 一些容易被忽略的实现细节

9.1 正则化项是否应该除以样本数

在PyTorch中,损失函数通常会对batch内的样本取平均。如果你手动加L1或L2正则化,要注意正则化项是否也需要除以样本数。有些实现会把正则化项除以N,有些不会。这会导致等效的lambda相差N倍。

我的建议是:保持一致性。如果你用的框架的weight_decay不除以N,那你手动加L1时也不要除。如果你自己实现训练循环,最好在正则化项上也除以N,这样lambda的含义更直观——它表示每个样本平均受到的惩罚。

9.2 混合精度训练下的正则化

混合精度训练(AMP)中,权重衰减和L1/L2正则化的行为可能发生变化。因为AMP会把部分计算转成float16,而float16的精度有限,小权重的衰减可能被舍入误差淹没。如果发现AMP下正则化效果不如预期,可以尝试把正则化相关的计算保持在float32,或者增大lambda。

9.3 分布式训练中的权重衰减

在分布式数据并行(DDP)中,每个进程独立计算梯度,然后做all-reduce平均。权重衰减是在优化器更新时应用的,每个进程独立执行,所以行为和数据并行一致。但要注意,如果用了梯度累积,权重衰减的次数会减少,等效的正则化力度会变弱。这时候可能需要增大lambda来补偿。

10. 从正则化延伸出去的一些思考

正则化本质上是在给模型加先验。L2对应的是高斯先验,假设权重服从均值为零的正态分布;L1对应的是拉普拉斯先验,假设权重服从均值为零的拉普拉斯分布。拉普拉斯分布在零点的峰值更尖,所以L1更倾向于产生零权重。

这个贝叶斯视角可以帮助我们理解更多正则化方法。比如Dropout可以看作是对权重加伯努利先验,数据增强可以看作是对输入加先验。当你理解了正则化的本质是引入先验知识,就能根据任务特点设计更合适的正则化策略,而不是盲目套用L1或L2。

我在实际项目中的体会是:正则化不是万能的,它不能替代好的数据、好的模型结构和好的训练策略。但在其他条件都差不多的情况下,选对正则化方法和系数,往往能让模型效果提升几个百分点。这几个百分点在竞赛或生产环境中,可能就是及格和优秀的差距。

最后分享一个小技巧:如果你不确定该用L1还是L2,可以先跑一个不加正则化的基线,然后同时试L2和L1,各跑三组不同lambda。对比验证集指标和训练集/验证集差距,通常半天之内就能做出选择。不要在这个问题上纠结太久,因为正则化的收益有上限,把时间花在数据质量和模型结构上,回报往往更大。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询