模型复杂度与损失曲线:L2、早停与过拟合信号
文章目录
- 模型复杂度与损失曲线:L2、早停与过拟合信号
- 1. 复杂模型
- 2. 什么是模型复杂度
- 3. 两个目标:拟合好,又要尽量简单
- 4. L2 正则化:把权重往零拉
- 4.1 公式回顾与加深
- 4.2λ \lambdaλ与学习率的拉扯
- 4.3 训练损失上升不一定是坏事
- 5. 早停:另一种限制复杂度
- 6. 损失曲线怎么读:四种常见形态
- 6.1 震荡(Oscillating)
- 6.2 突然尖峰(Sharp spike)
- 6.3 训练降、验证升(Divergence)
- 6.4 中途变乱(Chaotic)
- 6.5 和分类指标一起看
- 7. 反过拟合工具箱
- 8. 动手:多项式阶数、Ridge 与损失曲线
- 9. 能力边界与常见误区
- 9.1 适用边界
- 9.2 常见误区
- 10. 关键术语速查
- 11. 延伸阅读
- 12. 小结
摘要:第 18 篇讲了泛化与三分法,上一篇(第 20 篇)讲了类别不平衡,但模型侧还有一个旋钮:复杂度。复杂模型往往在训练集上更漂亮,在测试集上却更差。本文讲清什么是模型复杂度、损失与复杂度的权衡、L2 正则化与早停如何压住过拟合,以及四种常见损失曲线该怎么读。与之前的第 7 篇衔接并加深,贯穿汽车重量–MPG 示例。
1. 复杂模型
第 18 篇用「弯弯曲曲的分界线」比喻过拟合:训练集上几乎全对,测试集上大面积翻车。反过来,一条过于简单的直线又可能欠拟合。
经验规律可以记成:
| 模型 | 训练集 | 测试 / 新数据 |
|---|---|---|
| 过于复杂 | 往往更好 | 往往更差(过拟合) |
| 恰到好处 | 够好 | 也够好 |
| 过于简单 | 也差 | 也差(欠拟合) |
奥卡姆剃刀在机器学习里的白话版:能解释数据的简单模型,优先于复杂模型——不是简单一定对,而是复杂要付出泛化代价。新项目上,之前写的第 14 篇也建议特征从 1~3 个强特征起步,正是为了避免一上来维度爆炸。
2. 什么是模型复杂度
复杂度不是抽象玄学,在权重模型里常落到:
| 来源 | 例子 | 效应 |
|---|---|---|
| 参数多 / 权重大 | 高次多项式、很多 One-Hot 维 | 决策边界更「扭」 |
| 特征多 | 重量 + 排量 + 交叉 + 平方项 | 维度诅咒:空间稀疏,难泛化 |
| 训练过久 | 迭代太多 | 开始背训练噪声 |
线性回归y ′ = b + w 1 x 1 + w 2 x 2 y' = b + w_1 x_1 + w_2 x_2y′=b+w1x1+w2x2里,∣ w ∣ |w|∣w∣很大意味着输入微小变化会引起输出剧烈变化——对训练点「贴得太紧」,对新点就不稳。
逻辑回归同理:第 07 篇无正则时w ≈ − 4.28 w \approx -4.28w≈−4.28,重车概率可贴到 0.02 附近;加 L2 后∣ w ∣ |w|∣w∣缩小,概率不再极端,是同一机制。
3. 两个目标:拟合好,又要尽量简单
训练其实在解一个矛盾:
min 损失 vs min 复杂度 \min \ \text{损失} \quad \text{vs} \quad \min \ \text{复杂度}min损失vsmin复杂度
只压损失,复杂度往往上升;只追求简单,损失又下不去。工程上要找折中点。
正则化(Regularization)就是把复杂度写进目标函数,强迫模型「别太复杂」:
min Loss ⏟ 拟合数据 + λ ⋅ Complexity ⏟ 惩罚复杂 \min \ \underbrace{\text{Loss}}_{\text{拟合数据}} + \underbrace{\lambda \cdot \text{Complexity}}_{\text{惩罚复杂}}min拟合数据Loss+惩罚复杂λ⋅Complexity
λ \lambdaλ(lambda)是正则化率:越大越偏向简单,越小越放任拟合训练集。第 07 篇在 Log Loss 上加λ ∑ w j 2 \lambda\sum w_j^2λ∑wj2,就是 L2 正则化的标准形式。
4. L2 正则化:把权重往零拉
4.1 公式回顾与加深
逻辑回归总损失:
L total = − 1 N ∑ i [ y i log p i + ( 1 − y i ) log ( 1 − p i ) ] ⏟ Log Loss + λ ∑ j w j 2 ⏟ L2 复杂度 L_{\text{total}} = \underbrace{-\frac{1}{N}\sum_i \left[y_i\log p_i + (1-y_i)\log(1-p_i)\right]}_{\text{Log Loss}} + \underbrace{\lambda \sum_j w_j^2}_{\text{L2 复杂度}}Ltotal=Log Loss−N1i∑[yilogpi+(1−yi)log(1−pi)]+L2复杂度λj∑wj2
| λ \lambdaλ | 权重典型形态 | 风险 |
|---|---|---|
| 0 | $ | w |
| 适中 | $ | w |
| 过大 | w → 0 w \to 0w→0,模型变钝 | 欠拟合 |
偏置b bb一般不正则化——它只平移决策边界,不放大输入波动。L1 正则λ ∑ ∣ w j ∣ \lambda\sum|w_j|λ∑∣wj∣倾向稀疏(部分w ww恰为 0),适合顺带做特征筛选;L2 更平滑,工程里更常见。第 07 篇已对比过,本篇放在「泛化单元」里强调:调λ \lambdaλ要在验证集上看,不是训练 Log Loss 越低越好。
4.2λ \lambdaλ与学习率的拉扯
学习率η \etaη大:梯度步长大,权重容易被推离 0。
λ \lambdaλ大:惩罚项把权重往 0 拽。
两者像拔河:
- λ \lambdaλ相对η \etaη太大→ 权重太弱,欠拟合
- λ \lambdaλ相对η \etaη太小→ 权重太强,过拟合
改学习率后,往往要重新搜λ \lambdaλ——第 04 篇的超参思维在这里仍然适用。
一个实用口诀:先固定学习率到能稳定下降,再在验证集上网格搜索λ \lambdaλ(或 sklearn 的C CC)。汽车 7 车玩具数据上λ = 0.01 \lambda=0.01λ=0.01让w ww从 -4.28 收到 -2.33,属于「边界形状变化不大、置信度不再贴死」——这种温和化往往就是 L2 在帮泛化。
4.3 训练损失上升不一定是坏事
加上 L2 后,训练 Log Loss 可能反而变高——因为你多了一项复杂度惩罚。课程里的 playground 练习也强调:关键看测试 / 验证损失是否下降。别为了把训练曲线压到最低而关掉正则,那常常是在用泛化换漂亮曲线。
5. 早停:另一种限制复杂度
早停(Early Stopping)不直接算复杂度,而是在验证损失开始变差时停止训练,相当于限制「能拟合多久」。
| 手段 | 控制什么 |
|---|---|
| L2 | 限制权重大小 |
| 早停 | 限制训练轮次 |
| 减特征 / 降阶 | 限制模型结构 |
第 18 篇泛化曲线里「训练降、验证升」的分叉点,就是早停的天然候选。实践里 L2 + 早停常一起用。
注意:早停监控的是验证集损失,不是训练集;训练损失还能继续降的时候,验证可能已经抬头了。
6. 损失曲线怎么读:四种常见形态
理想曲线是训练、验证损失平稳下降后收敛。现实里常遇到以下模式:
6.1 震荡(Oscillating)
损失上下剧烈抖动。常见原因:
- 学习率过大→ 先试减小η \etaη(第 04 篇)
- 数据里有坏样本、NaN → 对照第 19 篇做清洗
- 可先用极小可信子集试收敛,再逐步加数据
6.2 突然尖峰(Sharp spike)
某一步损失暴涨。优先查:
- 输入是否出现NaN(除零、log(0))
- 某个 batch 是否堆满离群点(第 16 篇)
- 一般不要靠加大学习率来「冲过去」
6.3 训练降、验证升(Divergence)
训练损失继续改善,验证损失掉头向上——过拟合的经典信号(第 18 篇)。可尝试:
- 减特征、降多项式阶数
- 增大λ \lambdaλ
- 加数据、检查训练/验证分布是否一致(第 19 篇)
- 早停
6.4 中途变乱(Chaotic)
一度正常,之后毫无规律。常见线索:
- 训练集未充分打乱(例如先 100 张狗再 100 张猫)
- batch 组成剧烈变化
划分后务必shuffle,时间序列任务则按时间切分而非乱切(第 19 篇边界)。
6.5 和分类指标一起看
损失曲线是优化过程的体温计;业务还要对照第 10、11 篇的 Precision / Recall / AUC。尤其第 20 篇的不平衡场景:验证 Log Loss 在降,少数类 Recall 仍可能不够——说明光盯一条损失曲线不够,要在工作阈值上再看混淆矩阵。
7. 反过拟合工具箱
把本单元串起来:
数据侧(18~20) 模型侧(本篇 + 第07篇) ───────────────── ───────────────────── 三分法 / 同分布 控制复杂度(特征数、阶数) 清洗 / 去重 / 标签可信 L2 调 lambda 不平衡用对指标与 class_weight 早停盯验证损失汽车示例:用重量预测 MPG,degree=8多项式在 7 个点上训练 MSE 可接近 0,验证却爆炸——第 18 篇代码已演示;加Ridge(线性回归的 L2)或降回degree=1,验证往往恢复正常。分类任务则在LogisticRegression(C=1/lambda)上调C CC或λ \lambdaλ,配合第 20 篇的class_weight。
若你只有一两个强特征(如重量),先把模型做简单,往往比堆十来个交叉特征更稳——这和第 17 篇「交叉维数爆炸」、本篇「维度诅咒」是同一条警告线的两面。
8. 动手:多项式阶数、Ridge 与损失曲线
importnumpyasnpimportmatplotlib.pyplotaspltfromsklearn.model_selectionimporttrain_test_splitfromsklearn.preprocessingimportPolynomialFeatures,StandardScalerfromsklearn.linear_modelimportLinearRegression,Ridgefromsklearn.pipelineimportPipelinefromsklearn.metricsimportmean_squared_error rng=np.random.default_rng(0)weight=rng.uniform(2.2,4.6,120)mpg=34-4.6*weight+rng.normal(0,1.5,120)X=weight.reshape(-1,1)y=mpg X_train,X_val,y_train,y_val=train_test_split(X,y,test_size=0.25,random_state=0)defmake_model(degree,alpha=0.0):lr=Ridge(alpha=alpha)ifalpha>0elseLinearRegression()returnPipeline([("poly",PolynomialFeatures(degree=degree,include_bias=False)),("scaler",StandardScaler()),("model",lr),])fordegin[1,5,12]:m=make_model(deg)m.fit(X_train,y_train)print(f"deg={deg:2d}train={mean_squared_error(y_train,m.predict(X_train)):.3f}"f" val={mean_squared_error(y_val,m.predict(X_val)):.3f}")# Ridge on high degreem_ridge=make_model(12,alpha=1.0)m_ridge.fit(X_train,y_train)print("deg=12 + Ridge alpha=1.0 val=",round(mean_squared_error(y_val,m_ridge.predict(X_val)),3))# 记录每轮不可直接用于 sklearn 的闭式解模型;逻辑回归可用 warm_start 画曲线:fromsklearn.linear_modelimportLogisticRegressionfromsklearn.datasetsimportmake_classification Xc,yc=make_classification(n_samples=800,n_features=12,random_state=1)Xt,Xv,yt,yv=train_test_split(Xc,yc,test_size=0.25,random_state=0)train_losses,val_losses=[],[]clf=LogisticRegression(max_iter=1,warm_start=True,C=0.1,solver="lbfgs")for_inrange(80):clf.fit(Xt,yt)fromsklearn.metricsimportlog_loss train_losses.append(log_loss(yt,clf.predict_proba(Xt)))val_losses.append(log_loss(yv,clf.predict_proba(Xv)))best_epoch=int(np.argmin(val_losses))print("best epoch by val log_loss:",best_epoch)预期:deg=12训练 MSE 很低、验证很高;deg=1或Ridge高压下验证更稳。best epoch给出早停参考——不必跑满 80 轮。
9. 能力边界与常见误区
9.1 适用边界
- L2 / 早停主要约束权重类模型;树模型用深度、叶子数等别的方式控复杂度。
- 正则化救不了「数据完全不代表真实世界」——第 19 篇的数据问题要先解决。
- 训练损失因加了正则项而上升是正常的;关键看验证 / 测试。
9.2 常见误区
| 误区 | 正解 |
|---|---|
| 训练损失越低越好 | 对照验证曲线 |
| λ \lambdaλ一次调好永久用 | 换学习率、换特征后要重调 |
| 早停 = 随便少训几轮 | 盯验证损失最低点 |
| 特征越多越好 | 维度诅咒,先小后大 |
| 只有模型复杂才会过拟合 | 数据泄漏、重复样本也会「假泛化」 |
| 验证升了只加数据 | 同时减复杂度、加正则 |
| 复杂度和数据泄漏无关 | 重复样本、全表标准化也会造成「假好」曲线 |
「曲线好看」的三问:训练/验证是否同步改善?测试集是否只用过一次?线上分布是否仍接近训练?
10. 关键术语速查
| 术语 | 一句话解释 |
|---|---|
| 模型复杂度 | 模型拟合数据的「弯曲/敏感」程度 |
| 正则化 | 训练时惩罚复杂模型 |
| L2 正则化 | 惩罚∑ w j 2 \sum w_j^2∑wj2,权重趋向变小 |
| λ \lambdaλ/ C | 正则强度;sklearn 里C ≈ 1 / λ C \approx 1/\lambdaC≈1/λ |
| 早停 | 验证损失变差前停止训练 |
| 损失曲线 | 损失随 epoch 变化的曲线 |
| 泛化曲线 | 训练与验证损失画在一起 |
| 维度诅咒 | 特征多时空间稀疏,难学习 |
11. 延伸阅读
| 资源 | 适合看什么 |
|---|---|
| sklearn Ridge | 线性回归 L2 |
| sklearn LogisticRegression C | 分类中的 L2 强度 |
| 专栏第 07 篇 | Log Loss + L2 公式与梯度 |
| 专栏第 18 篇 | 泛化曲线与三分法 |
| 专栏第 04 篇 | 学习率与调参流程 |
12. 小结
过拟合不只有「数据没弄好」一种原因,模型太复杂、训太久同样致命。记住两个旋钮:L2(λ \lambdaλ)限制权重大小,早停限制训练长度;用验证损失曲线决定何时停、λ \lambdaλ取多大。
看 train/val 曲线 → 判断过/欠拟合 → 调 lambda / 特征 / 早停 → 测试集终验本篇收束「数据集、泛化与过拟合」单元的模型侧主线;下一篇做本单元总复盘:从特征工程到划分、不平衡、正则化的一条检查清单,再衔接后续进阶主题。
系列导航:
- 上一篇:【机器学习】(20)—— 类别不平衡
- 下一篇(预告):数据集与泛化单元复盘:从特征到验收的检查清单
如果本篇对你有帮助,欢迎点赞、收藏、关注博主,机器学习专栏持续更新中,下次更新不迷路。