凸优化中的瑞士军刀:次梯度方法在不可微场景下的5种步长选择策略

凸优化中的瑞士军刀:次梯度方法在不可微场景下的5种步长选择策略

在机器学习和运筹优化的世界里,我们常常被那些光滑、可微的函数所包围,梯度下降法也因此成为了工程师和研究者手中的“标准答案”。然而,现实世界远非处处光滑。当我们处理带有L1正则项的稀疏模型、ReLU激活的神经网络,或是某些特定的损失函数时,函数的“尖角”和“棱线”让经典的梯度无处可寻。此时,次梯度方法便从工具箱的角落里被重新拾起,它像一把瑞士军刀,虽不似专用工具那般精致高效,却能以惊人的鲁棒性应对各种非光滑的复杂地形。

次梯度方法的核心思想优雅而直接:既然梯度不存在,我们就找一个能“支撑”住函数图像的线性近似——次梯度。但这份优雅背后藏着一个棘手的难题:步长。与梯度下降不同,负次梯度方向不一定是下降方向,这意味着我们无法依赖线搜索来动态确定步长。步长的选择,从自适应计算退化为预先设定,这直接决定了算法是收敛于最优解附近,还是在解空间里漫无目的地徘徊。对于运筹学研究者、算法工程师以及任何需要处理非光滑凸优化问题的人来说,理解并驾驭这五种经典的步长策略,是从理论走向实践的关键一步。本文将深入剖析固定步长、固定步长范数、平方可和但不可和、不可和的递减步长以及不可和的递减步长范数这五种策略,结合收敛性理论与数值实验的洞察,为你揭示在不同场景下如何做出明智的选择。

1. 次梯度方法:当梯度“缺席”时的替补队员

在光滑函数的优化中,梯度指向了函数局部上升最快的方向,其反方向则是下降方向。这个性质是梯度下降法及其变种(如动量法、Adam)能够有效工作的基石。然而,对于凸但不可微的函数,比如在零点不可微的绝对值函数 f(x)=|x|,我们无法定义唯一的梯度。次梯度的概念应运而生,它本质上是所有可能“支撑”函数图像的直线斜率的集合。

次梯度 g 在点 x 处的正式定义是,对于定义域内所有的 y,都满足: f(y) ≥ f(x) + g^T (y - x) 这个不等式意味着,以 g 为斜率的线性函数在 x 处是 f 的一个全局下界估计。对于可微点,次微分集合 ∂f(x) 就是梯度 {∇f(x)};对于不可微点,它是一个集合。以 f(x)=|x| 为例:

  • x > 0 时, ∂f(x) = {1}
  • x < 0 时, ∂f(x) = {-1}
  • x = 0 时, ∂f(x) = [-1, 1](整个区间)

次梯度方法的形式与梯度下降惊人地相似: x^{(k+1)} = x^{(k)} - α_k * g^{(k)} 其中 g^{(k)}fx^{(k)} 处的任意一个次梯度,α_k > 0 是第 k 步的步长。正是这个“任意一个”带来了根本性的不同。由于 g^{(k)} 可能并非指向下降方向,迭代过程中目标函数值 f(x^{(k)}) 并非单调递减。因此,算法必须额外维护一个“历史最佳点” x_best,记录迭代过程中遇到的最小函数值对应的解。

注意:次梯度方法通常只能保证收敛到最优值的一个邻域内,且收敛速率一般为 O(1/ε²),这比梯度下降在光滑凸函数上的 O(1/ε) 速率要慢。这是处理非光滑性所付出的代价。

1.1 一个简单的Python示例:感受非单调性

让我们用绝对值函数这个最简单的例子,直观感受次梯度方法的非单调性。我们采用一个固定的次梯度选择规则:在 x=0 时,随机从 [-1,1] 中选取一个值。

import numpy as np
import matplotlib.pyplot as plt

def f(x):
    """目标函数:绝对值函数"""
    return np.abs(x)

def subgradient_f(x):
    """次梯度。在x=0处,我们随机返回-1或1来模拟从集合中选取。"""
    if x > 0:
        return 1.0
    elif x < 0:
        return -1.0
    else:
        # 在零点,从次微分[-1,1]中随机选一个。这里简化为以相等概率选-1或1。
        return np.random.choice([-1.0, 1.0])

def subgradient_descent(x0, stepsize, max_iter=50):
    """次梯度下降算法"""
    x = x0
    history = {'x': [x], 'f': [f(x)], 'best_f': [f(x)], 'best_x': [x]}
    
    for k in range(max_iter):
        g = subgradient_f(x)
        x = x - stepsize * g  # 更新
        
        current_f = f(x)
        history['x'].append(x)
        history['f'].append(current_f)
        
        # 更新历史最佳
        if current_f < history['best_f'][-1]:
            history['best_f'].append(current_f)
            history['best_x'].append(x)
        else:
            history['best_f'].append(history['best_f'][-1])
            history['best_x'].append(history['best_x'][-1])
            
    return history

# 运行实验
x0 = 2.5
stepsize = 0.5
history = subgradient_descent(x0, stepsize, max_iter=30)

# 绘制结果
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
iterations = range(len(history['f']))

axes[0].plot(iterations, history['f'], 'b-o', label='f(x_k)', markersize=4)
axes[0].plot(iterations, history['best_f'], 'r--s', label='Best f so far', markersize=4)
axes[0].axhline(y=0, color='k', linestyle=':', alpha=0.5) # 最优值线
axes[0].set_xlabel('Iteration k')
axes[0].set_ylabel('Function Value')
axes[0].set_title('Non-monotonic Behavior o
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值