胡贝尔损失
胡贝尔损失(Huber loss)在小残差处取二次形式,在大残差处改为线性增长,使梯度的绝对值保持有界。它既用于稳健拟合,也作为凸优化中的一个分段光滑函数;阈值必须和残差的尺度一起说明。
本文采用带二分之一的标准形式,给定 : 例如 ,残差 的损失为 ,残差三的损失为 ;相比之下半平方损失在三处为 。外侧损失仍随偏差增大,只是增长率不再继续增大。SciPy官方文档采用同样的归一化。[1]
一阶连续与凸性
在 处,两段函数都等于 ,导数也同为 ;负端同理。因此它处处一阶连续可微,导数为 导数单调不减,所以函数凸;导数还是一利普希茨的,因为把实数投影到闭区间不会扩大距离。但二阶导数从内部的一跳到外部的零,因此在两阈值处通常不是二阶可微。线性尾部也使函数不是全局严格凸。
若残差除以已知尺度 再计算,损失 的实际阈值是 。一些库把函数整体乘二,或同时优化尺度、加上参数惩罚;比较软件输出前应先对齐目标定义。
一个可手解的近端步骤
考虑优化中的标量问题 前一项希望输出 接近输入 ,后一项惩罚 的大小。平方项严格凸,故总目标具有唯一最小点。令导数为零: 若 ,方程给 ,该区域条件恰为 。若 ,得 ;负侧对称。合并得到 阈值处两式给出同一个输出。这里的近端变量 本身被惩罚,和拟合 时的回归系数不是同一个对象。
取 ,输出为三,目标值为 ;不移动的 则给九。变式取 ,落在内部,输出 ,目标为 。
与定义一致的Python计算
下面函数接收有限实数和正阈值、正惩罚系数,返回近端最小点,不修改输入。两个区域的验证已证明其全局正确性;每次调用只做常数次算术,时间与额外空间均为 。
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估计。
参考文献
- ↑ SciPy,scipy.special.huber,分段定义与Notes;本文取正阈值,避免阈值零造成退化损失。