概述

在机器学习中,许多损失函数(如 正则化、hinge loss)是非光滑的,传统的梯度下降法不再适用。次梯度(Subgradient)和近端方法(Proximal Methods)提供了处理非光滑优化问题的强大框架。1

核心问题:当函数在某点不可微时,如何定义”下降方向”?如何高效地优化包含非光滑项的目标函数?


次微分(Subdifferential)

不可微函数示例

在机器学习中常见的非光滑函数:

函数定义不可微点
绝对值$x
范数
ReLU
Hinge Loss
范数

次梯度的定义

定义:设 是凸函数。点 处的次梯度(Subgradient)是满足以下条件的向量

所有次梯度的集合称为次微分(Subdifferential),记作

几何直观

         f(y)
          │
     f(y) │      ╱
          │     ╱  ← 支撑超平面
          │    ╱
          │   ╱
          │  ╱
     f(x) │ ╱_________________
          │x
          └──────────────────── y
          
          切线在不可微点变成一族支撑超平面

一维示例:绝对值函数

次微分

Python验证

import numpy as np
 
def subdiff_abs(x):
    """绝对值函数的次微分"""
    if x < 0:
        return np.array([-1.0])
    elif x > 0:
        return np.array([1.0])
    else:
        return np.array([-1.0, 1.0])  # 区间
 
for x in [-1, 0, 1]:
    print(f"∂|x| at x={x}: {subdiff_abs(x)}")

次梯度的性质

性质描述
存在性凸函数在内部点次梯度存在
唯一性函数光滑点次梯度唯一
极值条件 最优
链式法则

次梯度下降法

算法

次梯度下降法(Subgradient Method):

其中 是任意次梯度, 是步长。

与梯度下降的区别

特性梯度下降次梯度下降
收敛性保证收敛到驻点不保证单调下降
步长选择线搜索可用需要预定义步长序列
收敛速度
实用性光滑问题非光滑问题

收敛性分析

定理:设步长满足 (例如 ),则次梯度方法收敛:

但收敛速度较慢:

固定步长次梯度法

对于有界域问题,使用固定步长

其中 是次梯度的界。第二项是”噪声底”,存在最优步长


近端算子(Proximal Operator)

定义

对于凸函数 近端算子(Proximal Operator)定义为:

直观理解 的”软投影”——在最小化 的同时保持与 的接近。

几何直观

                    约束可行域 {y: g(y) ≤ c}
                         ╱╲
                        ╱  ╲
                       ╱    ╲
                      ╱      ╲
                     ╱        ╲
                    ╱    x    ╲ ← 当前点
                   ╱      ↓    ╲
                  ╱        ↓    ╲
                 ╱          ↓    ╲
                ╱          prox_g(x) ← 软投影点
               ╱            ↗    ╲
              ╱                      ╲
             ─────────────────────────────

近端算子的性质

性质公式说明
幂等性投影两次等于一次
对偶性与次梯度联系
组合一般不能分离
线性组合缩放性质

常见近端算子

函数 近端算子 形式
范数
范数
指示函数(欧氏投影)
二次函数

软阈值算子(Soft-Thresholding)

对于 正则化,近端算子就是软阈值(Soft-Thresholding)或收缩算子

import numpy as np
 
def soft_threshold(x, threshold):
    """软阈值算子( shrinkage operator)"""
    return np.sign(x) * np.maximum(np.abs(x) - threshold, 0)
 
# 示例
x = np.array([3.0, -2.0, 0.5, -0.3])
threshold = 1.0
print(f"原向量: {x}")
print(f"软阈值(λ={threshold}): {soft_threshold(x, threshold)}")

近端梯度法(Proximal Gradient Method)

问题形式

考虑复合优化问题

其中:

  • 光滑凸函数,可微分,梯度 Lipschitz 连续(常数
  • 非光滑凸函数,近端算子 易计算

典型应用

应用
LASSO
弹性网
Group LASSO
约束优化

算法

近端梯度法(Proximal Gradient Method, PGM):

其中 是步长。

收敛速度

定理:对于 -Lipschitz 连续梯度,使用固定步长

加速近端梯度法(Accelerated Proximal Gradient Method, APGM)达到

Python实现

import numpy as np
 
def proximal_gradient_method(f, grad_f, prox_g, x0, alpha, max_iter=1000, tol=1e-6):
    """
    近端梯度法
    
    Args:
        f: 目标函数
        grad_f: f的梯度
        prox_g: g的近端算子
        x0: 初始点
        alpha: 步长
        max_iter: 最大迭代次数
        tol: 收敛容差
    
    Returns:
        x: 最优解
        losses: 损失历史
    """
    x = x0.copy()
    losses = [f(x)]
    
    for k in range(max_iter):
        # 近端梯度步
        x_new = prox_g(x - alpha * grad_f(x), alpha)
        
        # 记录损失
        losses.append(f(x_new))
        
        # 收敛检查
        if np.linalg.norm(x_new - x) < tol:
            print(f"在第 {k+1} 步收敛")
            break
        
        x = x_new
    
    return x, losses
 
def accelerated_pgm(f, grad_f, prox_g, x0, alpha, max_iter=1000, tol=1e-6):
    """
    加速近端梯度法 (FISTA)
    """
    x = x0.copy()
    y = x0.copy()
    t = 1.0
    losses = [f(x)]
    
    for k in range(max_iter):
        # 保存上一步
        x_old = x.copy()
        
        # 近端梯度步
        x = prox_g(y - alpha * grad_f(y), alpha)
        
        # 加速项
        t_new = (1 + np.sqrt(1 + 4 * t**2)) / 2
        y = x + (t - 1) / t_new * (x - x_old)
        t = t_new
        
        losses.append(f(x))
        
        if np.linalg.norm(x - x_old) < tol:
            print(f"在第 {k+1} 步收敛")
            break
    
    return x, losses
 
# 示例:LASSO
from scipy.linalg import lstsq
 
def lasso_prox(A, b, lambda_reg, x0, alpha, max_iter=1000):
    """LASSO: min 1/2||Ax - b||^2 + λ||x||_1"""
    m, n = A.shape
    
    def f(x):
        r = A @ x - b
        return 0.5 * np.sum(r**2)
    
    def grad_f(x):
        return A.T @ (A @ x - b)
    
    def prox_g(x, alpha):
        # soft_threshold
        return np.sign(x) * np.maximum(np.abs(x) - alpha * lambda_reg, 0)
    
    return proximal_gradient_method(f, grad_f, prox_g, x0, alpha, max_iter)
 
# 测试
np.random.seed(42)
m, n, k = 100, 50, 10
A = np.random.randn(m, n)
x_true = np.zeros(n)
x_true[:k] = np.random.randn(k)
b = A @ x_true + 0.1 * np.random.randn(m)
 
x0 = np.zeros(n)
alpha = 1.0 / (np.linalg.norm(A, ord=2)**2)  # 步长上界
 
x_opt, losses = lasso_prox(A, b, 0.1, x0, alpha)
print(f"非零分量数量: {np.sum(np.abs(x_opt) > 1e-4)}")

ADMM(交替方向乘子法)

形式

ADMM用于可分离的约束优化问题:

算法

其中 缩放对偶变量

与近端方法的关系

ADMM可以看作近端方法的扩展:

  • 交替优化
  • 用增广拉格朗日惩罚约束

ADMM的收敛

ADMM在以下条件下收敛:

  1. 是闭凸函数
  2. 拉格朗日函数有鞍点
  3. 列满秩(某种形式)

收敛速度:(原始-对偶残差)。


近端方法在机器学习中的应用

1. LASSO回归

def lasso_admm(A, b, lambda_reg, rho=1.0, max_iter=1000, tol=1e-4):
    """
    ADMM求解LASSO: min 1/2||Ax - b||^2 + λ||z||_1
    s.t. x = z
    """
    m, n = A.shape
    x = np.zeros(n)
    z = np.zeros(n)
    u = np.zeros(n)  # 对偶变量
    
    # 预计算
    Atb = A.T @ b
    # (A^T A + ρI)^{-1} 缓存
    Q = A.T @ A + rho * np.eye(n)
    
    for k in range(max_iter):
        # x-更新(线性求解)
        x_new = np.linalg.solve(Q, Atb + rho * (z - u))
        
        # z-更新(近端算子)
        z_new = soft_threshold(x_new + u, lambda_reg / rho)
        
        # 对偶更新
        u_new = u + x_new - z_new
        
        # 收敛检查
        primal_res = np.linalg.norm(x_new - z_new)
        dual_res = np.linalg.norm(rho * (z_new - z))
        
        if primal_res < tol and dual_res < tol:
            print(f"ADMM在第{k+1}步收敛")
            break
        
        x, z, u = x_new, z_new, u_new
    
    return x

2. Group LASSO

def group_lasso_prox(x, groups, lambda_reg):
    """
    Group LASSO近端算子
    min λ∑_g ||z_g||_2 + 1/2||z - x||^2
    """
    z = np.zeros_like(x)
    for g_idx, group in enumerate(groups):
        x_g = x[group]
        norm_g = np.linalg.norm(x_g)
        if norm_g > 0:
            z[group] = x_g * max(0, 1 - lambda_reg / norm_g)
    return z

3. 总变差(Total Variation)正则化

def tv_prox_1d(x, lambda_reg):
    """
    一维总变差近端算子
    min λ||Dz||_1 + 1/2||z - x||^2
    其中 D 是差分算子
    """
    n = len(x)
    
    # 构建差分矩阵
    D = np.zeros((n-1, n))
    for i in range(n-1):
        D[i, i] = -1
        D[i, i+1] = 1
    
    # 使用闭式解: isotonic regression
    # 实际上 TV prox 可以通过 pool adjacent violators 算法求解
    y = x.copy()
    n = len(y)
    
    # 简化实现
    for _ in range(100):  # 迭代
        for i in range(n-1):
            if abs(y[i] - y[i+1]) > lambda_reg:
                # 需要合并区间
                pass
    
    return y  # 简化版本

总结

方法适用场景收敛速度
次梯度法非光滑凸函数
近端梯度法光滑+非光滑复合
加速PGM (FISTA)同上
ADMM可分离约束问题

近端方法是现代优化算法的基石:

  • LASSO/弹性网的快速求解
  • 图像处理中的TV正则化
  • 联邦学习中的分布式优化

理解次梯度和近端算子对于设计高效的机器学习优化算法至关重要。


参考

Footnotes

  1. Beck, A. (2017). First-Order Methods in Optimization. SIAM.