正则化

从过拟合的本质出发,系统引入参数正则化与结构正则化机制,并澄清其与归一化方法的根本区别

为什么需要正则化

  • 什么是正则化

    • 正则化就是给模型加约束,防止它过度拟合训练数据,提升泛化能力

    • 过拟合:模型把训练集里的噪声、细节都记住了,换新数据就表现很差

    • 正则化:惩罚过于复杂的模型,让模型学得更简单、更平滑、更通用

  • 直观上理解

    • 在原始的无约束优化问题中,给定训练数据,只要求训练损失越小越好

    • 只要在训练集上预测对,不管用了什么方式,不管参数长什么样,只要损失一样小,在优化器眼里这些解完全等价

    • 但在高维模型(尤其是神经网络)中,“训练损失很小” 的解不是一个点,而是一大片区域,里面可能有:

      • 参数很小、变化平滑的解

      • 参数巨大、极度敏感的解

      • 稍微扰动输入就崩掉的解

      • 非常稳定、抗噪声的解

    • 以上这些解在训练集上,损失几乎一样

  • 从数学角度理解

    • 监督学习的目标并非最小化训练误差,而是最小化泛化误差:

      R(θ)=E(x,y)∼D[L(fθ(x),y)]\mathcal {R}(\theta) = \mathbb {E}_{(x,y)\sim \mathcal {D}}[L (f_\theta (x), y)]
    • 但真实分布 D\mathcal {D} 不可得,只能通过有限样本 Dtrain\mathcal {D}_{train} 近似:

      Remp(θ)=1N∑i=1NL(fθ(xi),yi)\mathcal {R}_{emp}(\theta) = \frac {1}{N}\sum_{i=1}^N L (f_\theta (x_i), y_i)
  • 过拟合并不是指模型复杂,其本质而是:

    • 参数空间中存在大量对训练集低损失、但对分布扰动极不稳定的解
    • 梯度下降在高维空间中,极易滑向这些 “尖锐极小值”
  • 正则化的核心目标

    • 正则化不是直接提升训练精度,而是改变优化问题的几何结构,打破损失相近的不同解之间 “等价” 的假设,使 “稳定的解” 更容易被找到
    • 正则化不是在约束模型,而是在约束 “哪种解值得被相信”
  • 那么正则化约束如何进入优化问题

    • 原始无约束优化问题:

      min⁡θL(θ)\min_\theta L (\theta)
    • 正则化后的等价形式:

      min⁡θ  L(θ)+λ Ω(θ)\min_\theta \; L (\theta) + \lambda \, \Omega (\theta)
      • L(θ)L (\theta):数据一致性 ——“在训练集上做得怎么样?”
      • Ω(θ)\Omega (\theta):复杂度度量 ——“这个解,看起来靠谱吗?”
      • λ\lambda:在 “拟合” 与 “稳定” 之间的权衡系数 ——“到底有多在乎‘靠谱吗’这件事?”
  • 通过修改优化目标,正则化直接从目标函数层面作用于可行解空间 / 参数空间,从而限制 “不稳定的使用方式”

  • 在不同的解中,参数小往往意味着解更好,因为参数越大 → 输出对输入越敏感 → 一点点噪声就会放大

L2 正则化

  • L2 正则化(Ridge)的定义:

    Ω(θ)=12∥θ∥22\Omega (\theta) = \frac {1}{2}\|\theta\|_2^2
  • 带正则项的目标函数:

    Lreg(θ)=L(θ)+λ2∥θ∥22L_{reg}(\theta) = L (\theta) + \frac {\lambda}{2}\|\theta\|_2^2
  • 对参数求梯度:

    ∇θLreg=∇θL(θ)+λθ\nabla_\theta L_{reg} = \nabla_\theta L (\theta) + \lambda \theta
  • 梯度下降更新:

    θt+1=θt−η(∇L(θt)+λθt)=(1−ηλ)θt−η∇L(θt)\theta_{t+1} = \theta_t - \eta (\nabla L (\theta_t) + \lambda \theta_t) = (1 - \eta\lambda)\theta_t - \eta \nabla L (\theta_t)
  • 由梯度下降公式可以看出,每次更新前,权重先乘一个小于 1 的数 (1−ηλ)(1-\eta\lambda),这代表着权重被持续拉向 0】

  • 而权重越小,对输入的变化越不敏感,输出变化平滑、稳定,因此 L2 就是强制让所有权重都不能太大,让模型变 “温和”

  • 机制理解:

    • 通过 L2 正则,参数在每一步都会被整体向 0 拉回,并优先抑制那些仅靠放大参数幅值来降低损失的方向
    • 相当于持续地、温和地告诉模型:不要靠 “把某个参数拧得特别大” 来拟合数据
    • 从几何视角看,L2 正则倾向于选择损失盆地中更平坦、曲率更小的解,通过连续收缩,引导优化走向平坦解
  • L2 正则化让权重整体变小、更平滑,不会极端大,最常用

L1 正则化

  • L1 正则化(Lasso)的定义:

    Ω(θ)=∥θ∥1=∑i∣θi∣\Omega (\theta) = \|\theta\|_1 = \sum_i |\theta_i|
  • 正则化目标:

    Lreg(θ)=L(θ)+λ∑i∣θi∣L_{reg}(\theta) = L (\theta) + \lambda \sum_i |\theta_i|
  • 梯度(严格来说是次梯度):

    ∂∂θi∣θi∣={+1,θi>0−1,θi<0[−1,1],θi=0\frac {\partial}{\partial \theta_i} |\theta_i| = \begin {cases} +1, & \theta_i > 0 \\ -1, & \theta_i < 0 \\ [-1,1], & \theta_i = 0 \end {cases}
  • 机制理解:

    • 相比于 L2 正则限制参数的大小,L1 正则不是简单地缩小参数,而是主动制造精确为 0 的维度
    • 由于在 0 附近存在 “不可导拐角”,那么参数一旦足够小,就会被直接压到 0
    • 通过制造几何拐角,制造结构稀疏性,而模型自动完成 “特征选择”,仅保留少数关键方向
  • 让很多权重直接变成 0,实现特征选择

Dropout

  • Dropout 从参数正则化转向到结构正则化,Dropout 并不是在目标函数中显式加项,而是在训练阶段随机破坏网络结构

  • 训练时:

    h(l)=m(l)⊙f(W(l)h(l−1))h^{(l)} = m^{(l)} \odot f (W^{(l)} h^{(l-1)})
    • 其中,m(l)∼Bernoulli(p)m^{(l)} \sim \text{Bernoulli}(p)
    • 每一次前向传播,都是一个 “子网络”
  • 测试时:

    E[h(l)]≈p⋅f(W(l)h(l−1))\mathbb {E}[h^{(l)}] \approx p \cdot f (W^{(l)} h^{(l-1)})
  • 机制理解:

    • Dropout 从参数的正则化转向结构的正则化,不允许模型依赖任何一条固定通路

    • 每次训练随机砍掉一部分神经元,使网络结构不断变化

    • 保证只有在 “很多不同子网络中都好用的表示”,才能存活下来

    • 通过结构随机性,迫使表示具有鲁棒性

    • Dropout ≈ 对指数数量子模型的参数共享平均,是一种隐式的模型集成

Regularization ≠ Normalization

  • 正则化(Regularization):

    • 作用对象:解空间 / 参数空间
    • 改变的是:什么样的解被偏好
    • 目标:抑制过拟合、提升泛化
  • 归一化(Normalization,如 BatchNorm / LayerNorm):

    • 作用对象:中间激活分布
    • 改变的是:优化路径与梯度尺度
    • 目标:稳定训练、加速收敛
  • 虽然:Normalization 往往带来 “正则化效应”,但本质上它们解决的是完全不同层级的问题

维度归一化正则化
作用层级中间表示解空间
是否进入目标函数否是
主要目标稳定优化抑制过拟合
是否改变最优解集合通常不明确改变

梯度裁剪

  • 虽然像 AdamW 这样的优化器和合理的学习率调度策略能改善 Transformer 的训练稳定性,但由于模型层数深、计算路径长,仍可能出现另一个数值问题 —— 梯度爆炸

  • 为什么会出现梯度爆炸

    • 在反向传播过程中,梯度是逐层传递的

    • 若每层梯度的范数略大于 1,这种 “链式乘积” 可能随着层数增加呈指数增长,导致梯度幅度变得非常大,从而引发:

      • 参数更新剧烈跳动

      • 数值溢出甚至 NaN

      • 训练损失震荡或发散

    • 虽然像层归一化等结构能缓解一部分梯度问题,但在训练初期或遇到异常输入时仍可能发生大梯度爆发

  • 梯度裁剪(Gradient Clipping)是一种直接应对梯度爆炸的技术:

    • 在优化器根据梯度更新参数之前,对梯度的大小设置上限
    • 如果梯度的总范数超过阈值,则按比例缩小到该阈值,从而限制单次更新步长
  • 按全局范数裁剪(Transformer 训练中最常见的梯度裁剪方式)

    • 设所有可训练参数的梯度组成一个向量 GG,∣∣G∣∣2||G||_2 是其 L2 范数(即欧几里得范数)

    • 其中,L2 范数定义为:

      ∣∣G∣∣2=∑i(∂L∂θi)2||G||_2 = \sqrt {\sum_i \left (\frac {\partial \mathcal {L}}{\partial \theta_i}\right)^2}
    • 给定一个阈值 max_norm:

      • 若 ∣∣G∣∣2≤max_norm||G||_2 \leq \text{max\_norm}:梯度不变

      • 若 ∣∣G∣∣2>max_norm||G||_2 > \text{max\_norm}:则整体缩放为:

        Gclipped=G×max_norm∣∣G∣∣2G_{\text{clipped}} = G \times \frac {\text{max\_norm}}{||G||_2}
    • 这种方式保持梯度方向不变,只限制其整体幅度,有助于避免单次更新过大,同时保留优化方向不偏离

  • 在大多数深度学习框架中,梯度裁剪已被内置支持,并应在梯度计算之后、参数更新之前调用。典型的 PyTorch 调用方式如下:

    # 正常前向 + 计算损失
    outputs = model(inputs)
    loss = compute_loss(outputs, targets)
    
    # 反向传播计算梯度
    loss.backward()
    
    # 在 optimizer.step() 之前进行梯度裁剪
    gradient_threshold = 1.0
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=gradient_threshold)
    
    # 应用裁剪后的梯度更新参数
    optimizer.step()
    
    # 清零梯度以供下次迭代
    optimizer.zero_grad()
  • 选择 max_norm 阈值的经验

    • 常见范围:约在 [0.5, 5.0][0.5,\ 5.0]

    • 常用起点:1.01.0

    • 过低:可能过度限制梯度,从而减慢学习甚至阻碍模型收敛

    • 过高:会无法有效抑制异常大梯度

这篇文档有帮助吗?

On this page

页面信息