单变量梯度下降
梯度下降迭代寻找极小值;若要最大化 ,可改为最小化 。它适用于难以解析求解的优化问题。
梯度下降的概念
- 先从单变量情形入手,再推广到更复杂的多变量梯度下降。
- 根据函数的导数系统地更新当前点,以迭代逼近函数最小值。
数学形式
对于 :
- 计算导数: 。
- 迭代更新: 从 开始,令 ,其中 是学习率。
导数的符号指示单变量情形下应向左还是向右移动。
挑战与对策
解析求解困难
方程 难以直接解析求解,正是梯度下降适用的场景。
学习率
- 学习率决定迭代步长,过大会越过最小值,过小则收敛缓慢。
- 自适应学习率尝试根据优化进度动态调整 ,但不存在通用的最优策略。
局部极小值
- 梯度下降可能收敛到局部而非全局极小值。
- 从多个初始点分别运行可以提高接近全局极小值的概率。
实际实现
- 选择起点与学习率。
- 反复应用 。
- 检查导数大小、目标值下降、定义域和迭代上限。仅凭 变化很小,不能判断已接近最优解。
对于 ,每轮在当前点计算导数并按学习率更新, 无需直接解出导数等于零的位置。
在定义域内安全计算
这里 是自然对数,定义域为 。由于 ,函数严格凸;而且当 或 时,函数都趋于无穷大,所以它有唯一全局最小点。解 得 ,也记作 。这个例子不存在多个局部极小值之间的竞争。
从 出发,取 ,有 、,函数值从 降至 。但若从 出发取 ,下一点为负数,对数无定义。因此要先检查候选点是否可行,再计算目标值。下面的回溯线搜索不断将步长减半,直到满足 Armijo 下降条件;达到迭代或试探上限时报告失败,不冒充收敛。
from math import exp, log, isfinite
def f(x):
return exp(x) - log(x)
x = 1.0
for iteration in range(10000):
g = exp(x) - 1 / x
if abs(g) <= 1e-7:
break
alpha = 1.0
for trial in range(60):
candidate = x - alpha * g
if candidate > 0 and isfinite(candidate):
try:
value = f(candidate)
except OverflowError:
value = float("inf")
if isfinite(value) and value <= f(x) - 1e-4 * alpha * g * g:
break
alpha *= 0.5
else:
raise RuntimeError("line search failed")
x = candidate
else:
raise RuntimeError("iteration limit reached")
print(round(x, 6), round(f(x), 6))
输出为 0.567143 2.330366。导数容差在这里表明近似驻点;严格凸性进一步说明唯一驻点就是全局最小点。非凸问题中的小导数也可能对应鞍点或极大点。
可用 检验步长:。从非零点出发,收敛要求 ; 时振荡,大于 时发散。反过来, 极小时,即使 很大,迭代变化也可能很小。若包含这一步的区间内满足 ,即梯度为 -Lipschitz,则 ,所以 可在 时保证下降。对数例子在整个 上没有统一的有限 ;回溯法无需假定这样的全局常数。