现在位置: 首页 > AI 数学基础 > 正文

用导数找函数最小值

用数值差分估计导数,沿着导数的反方向一步步移动,直观感受「导数指引搜索方向」。

学完本案例你将理解:导数告诉你往哪走函数值会上升,反方向走就会下降——这就是梯度下降的雏形。


生活引入

大雾天蒙眼下山

伸手不见五指的大雾天,你要从山顶走到山谷。你看不见整个山势,只能感受到脚下的坡度。你的策略很简单:感受坡度最陡的方向 → 往最陡下坡方向走一小步 → 停下来 → 重新感受 → 再走一小步。

「感受坡度」就是求导数,「走一小步」就是用导数的反方向更新位置。这个方法不需要知道整座山的形状,只需要知道脚下的坡度。


直观理解

对于函数 \(f(x) = (x-3)^2 + 2\),最小值在 \(x=3\) 处,最小值是 \(f(3) = 2\)。

从 \(x=10\) 出发,怎么走到 \(x=3\)?不需要解方程,只需要一个策略:

  • 如果导数 \(f'(x) > 0\)(函数在上升),就往左走(减小 x)
  • 如果导数 \(f'(x) < 0\)(函数在下降),就往右走(增大 x)
  • 导数的绝对值越大,说明坡越陡,可以走远一点

数学定义

数值导数(中心差分)

\[ f'(x) \approx \frac{f(x+h) - f(x-h)}{2h} \]

不需要推导求导公式。用两个非常接近的点的函数值差除以距离,就得到了导数的近似值。\(h\) 取一个极小的数,如 \(10^{-5}\)。

朴素下山算法

\[ x_{t+1} = x_t - \eta \cdot f'(x_t) \]

其中 \(\eta\) 是步长(学习率),控制每一步走多远。


Python 动手实践

实例

import numpy as np

# 目标函数:f(x) = (x-3)^2 + 2,最小值在 x=3
def f(x):
    return (x - 3) ** 2 + 2

# 数值导数——用中心差分,不依赖符号求导
def numerical_derivative(f, x, h=1e-5):
    """估计 f 在 x 处的导数值"""
    return (f(x + h) - f(x - h)) / (2 * h)

# 朴素下山算法:沿着导数的反方向移动
x = 10.0          # 起点,故意选得离最优点很远
step_size = 0.1   # 每次移动的步长
history = [x]

for i in range(50):
    grad = numerical_derivative(f, x)
    x = x - step_size * grad  # 导数为正就往左,为负就往右
    history.append(x)

print("RUNOOB 下山算法结果:")
print(f"起点 x = {history[0]:.1f}")
print(f"终点 x = {history[-1]:.4f}  (真实最小值点 x=3)")
print(f"终点 f(x) = {f(history[-1]):.4f}  (真实最小值 f(3)=2)")

print("\nRUNOOB 前 10 步移动轨迹:")
print(f"{'步数':<6} {'x':<10} {'f(x)':<10} {'导数':<10} {'方向'}")
for i, xi in enumerate(history[:10]):
    grad = numerical_derivative(f, xi)
    direction = "往左" if grad > 0 else "往右"
    print(f"{i:<6} {xi:<10.4f} {f(xi):<10.4f} {grad:<10.4f} {direction}")
RUNOOB 下山算法结果:
起点 x = 10.0
终点 x = 3.0000  (真实最小值点 x=3)
终点 f(x) = 2.0000  (真实最小值 f(3)=2)

RUNOOB 前 10 步移动轨迹:
步数   x          f(x)       导数       方向
0      10.0000    51.0000    14.0000    往左
1      8.6000     33.3600    11.2000    往左
2      7.4800     22.0704    8.9600     往左
3      6.5840     14.8042    7.1680     往左
4      5.8672     10.1942    5.7344     往左

AI 中的应用场景

场景与本案的联系
梯度下降训练神经网络训练的本质:用损失函数对每个参数的偏导数指引参数更新方向
数值梯度检查调试反向传播时,用数值梯度验证解析梯度的正确性——正是本案的中心差分法
超参数搜索贝叶斯优化等调参方法,也是在未知函数曲面上沿着「导数」方向搜索最小值