跳到正文
格致开物MATHWIKI

胡贝尔损失

胡贝尔损失(Huber loss)在小残差处取二次形式,在大残差处改为线性增长,使梯度的绝对值保持有界。它既用于稳健拟合,也作为凸优化中的一个分段光滑函数;阈值必须和残差的尺度一起说明。

本文采用带二分之一的标准形式,给定 δ>0: ρδ(r)={r2/2,|r|≤δ,δ|r|−δ2/2,|r|>δ. 例如 δ=1,残差 1/2 的损失为 1/8,残差三的损失为 5/2;相比之下半平方损失在三处为 9/2。外侧损失仍随偏差增大,只是增长率不再继续增大。SciPy官方文档采用同样的归一化。[1]

阈值一的胡贝尔损失在正负一内与半平方重合,外侧沿切线线性增长
金色半平方在尾部高于胡贝尔曲线。阈值按横轴残差单位解释,不能不经缩放搬到另一组量纲不同的数据。

一阶连续与凸性

在 r=δ 处,两段函数都等于 δ2/2,导数也同为 δ;负端同理。因此它处处一阶连续可微,导数为 ρδ′(r)=clip⁡(r,−δ,δ). 导数单调不减,所以函数凸;导数还是一利普希茨的,因为把实数投影到闭区间不会扩大距离。但二阶导数从内部的一跳到外部的零,因此在两阈值处通常不是二阶可微。线性尾部也使函数不是全局严格凸。

若残差除以已知尺度 s 再计算,损失 s2ρδ(r/s) 的实际阈值是 sδ。一些库把函数整体乘二,或同时优化尺度、加上参数惩罚;比较软件输出前应先对齐目标定义。

一个可手解的近端步骤

考虑优化中的标量问题 minz{12(z−r)2+λρδ(z)},λ>0. 前一项希望输出 z 接近输入 r,后一项惩罚 z 的大小。平方项严格凸,故总目标具有唯一最小点。令导数为零: z−r+λclip⁡(z,−δ,δ)=0. 若 |z|≤δ,方程给 z=r/(1+λ),该区域条件恰为 |r|≤(1+λ)δ。若 z>δ,得 z=r−λδ;负侧对称。合并得到 p:=proxλρδ(r),p={r/(1+λ),|r|≤(1+λ)δ,r−λδsign⁡(r),|r|>(1+λ)δ. 阈值处两式给出同一个输出。这里的近端变量 z 本身被惩罚,和拟合 ρ(y−x𝖳β) 时的回归系数不是同一个对象。

阈值一和lambda二时近端映射在输入正负三内斜率三分之一,外侧斜率一并平移二
映射连续,在输入三处输出一。它让小值按比例收缩、大值减少固定量,没有把一段输入直接截成零。

取 δ=1,λ=2,r=5,输出为三,目标值为 (3−5)2/2+2(3−1/2)=7;不移动的 z=5 则给九。变式取 r=2,落在内部,输出 2/3,目标为 8/9+4/9=4/3。

与定义一致的Python计算

下面函数接收有限实数和正阈值、正惩罚系数,返回近端最小点,不修改输入。两个区域的验证已证明其全局正确性;每次调用只做常数次算术,时间与额外空间均为 O(1)。

Python 3
import math

def huber_prox(r, delta, penalty):
    r, delta, penalty = float(r), float(delta), float(penalty)
    if not all(math.isfinite(v) for v in (r, delta, penalty)):
        raise ValueError("finite numbers required")
    if delta <= 0 or penalty <= 0:
        raise ValueError("positive delta and penalty required")
    # Scaled comparison avoids overflowing (1+penalty)*delta.
    if abs(r) / (1 + penalty) <= delta:
        return r / (1 + penalty)
    return r - math.copysign(penalty * delta, r)

print(huber_prox(5, 1, 2)) # 3.0
print(huber_prox(2, 1, 2)) # 0.6666666666666666
assert huber_prox(3, 1, 2) == 1
assert huber_prox(-5, 1, 2) == -3

胡贝尔梯度限幅限制的是残差方向的局部拉动。回归中仍须考虑设计点杠杆和尺度估计;单凭选择这项损失,不能断言模型没有偏差,或异常观测已经被识别并删除。位置估计的完整统计解释见稳健M估计。

参考文献

  1. ↑ SciPy,scipy.special.huber,分段定义与Notes;本文取正阈值,避免阈值零造成退化损失。