三分钟入门了解什么是梯度下降

梯度下降学习可观看以下视频:
吴恩达机器学习 - 网易云课堂

前言

在开始探讨梯度下降之前,先引入一个实际问题:工厂成本最优化,即工厂如何做决策(控制决策变量)使总成本最低?
当问题中只包含一个决策变量(比如产量 \(x\))时,我们可以画出二维平面图——横轴是产量,纵轴是总成本,通过对曲线上的点求导或观察曲线最低点就能找到最优解。
但现实中的优化问题往往有多个变量,例如:

  • 二维参数问题:成本函数同时依赖于产量 \(x\) 和原材料采购价 \(y\),记作 \(C(x,y)\)
    这时可以在三维空间画图(\(x\) 轴、\(y\) 轴、\(C\) 轴),图形像一个山谷。我们要找的是“谷底” (\(x^∗\),\(y^∗\)),使成本最低。

  • 三维参数问题:假如再增加一个变量 \(z\)(比如设备运行时间),成本函数变成 \(C(x,y,z)\)
    我们无法在四维空间中直观作图,但数学上依然可以形象的定义“梯度”并搜索最小值。

当参数数量过大,无法绘制直观的图像,该如何找到最优解呢?这就需要梯度下降法这类数值优化算法。下面用几个简单例子说明它如何解决问题。


1.一维参数问题

假设总成本 \(C(x)\) 只取决于产量 \(x\)(单位:千件),且函数形式为:

\[C(x) = x^2 - 4x + 7 \]

其中 \(C\) 的单位是万元。我们想找到使总成本最低的产量 \(x^*\)


(1) 解析求解(求导法)

\(C(x)\) 求导:\(C'(x) = 2x - 4\)
令导数为零:\(2x - 4 = 0 \quad \Rightarrow \quad x = 2\)
二阶导数 \(C''(x) = 2 > 0\),说明 \(x=2\) 是极小值点。
最优产量\(x^* = 2\)(千件),最低成本:

\[C(2) = 2^2 - 4\times 2 + 7 = 4 - 8 + 7 = 3 \text{ 万元} \]


(2) 图形示意(二维平面)

横轴为产量 \(x\),纵轴为总成本 \(C(x)\)。曲线是一个开口向上的抛物线,最低点在 \((2, 3)\)

image

绘图代码如下:

点击查看代码
import numpy as np
import matplotlib.pyplot as plt

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']        # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False          # 用来正常显示负号

def C(x):
    return x**2 - 4*x + 7

x = np.linspace(0, 4, 200)
y = C(x)

plt.figure(figsize=(8, 5))
plt.plot(x, y, 'b-', linewidth=2, label=r'$C(x)=x^2-4x+7$')

x_min = 2
y_min = C(x_min)
plt.plot(x_min, y_min, 'ro', markersize=8, label=f'最低点 ({x_min}, {y_min})')
plt.annotate(f'({x_min}, {y_min})', 
             xy=(x_min, y_min), 
             xytext=(x_min+0.3, y_min+0.5),
             arrowprops=dict(arrowstyle='->', color='gray'))

plt.xlabel('产量 x (千件)', fontsize=12)
plt.ylabel('总成本 C(x) (万元)', fontsize=12)
plt.title('工厂成本最优化:一维成本函数曲线', fontsize=14)
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend()
plt.show()

(3) 用梯度下降(一维情况就是“导数下降”)求解

在多元问题中,梯度是一个向量,指向函数值上升最快的方向;负梯度方向则是下降最快的方向。
虽然一维问题不需要梯度下降,但为了统一思想,我们可以模拟。
在一维情况下,“梯度”退化为导数 \(C'(x)\)。若 \(C'(x)>0\),函数在 \(x\) 处递增,要减小 \(C(x)\) 应向左移动(减小 \(x\));若 \(C'(x)<0\),应向右移动。

我们假设:

  • 初始点 \(x_0 = 4\),学习率 \(\eta = 0.1\)
  • 梯度(即导数)\(C'(x) = 2x - 4\)
  • 更新规则:$$x_{\text{new}} = x_0 - \eta \cdot C'(x_0)$$
    其中 \(η>0\) 称为学习率,控制每一步的步长。

第一次迭代:

\[x_{\text{new}} = 4 - 0.1 \times (2\times 4 - 4) = 4 - 0.1 \times 4 = 3.6 \]

计算过程:\(C'(4)=4\)(正值),所以负梯度方向为负,\(x\) 减小,从 4 降至 3.6。

第二次:

\[x_{\text{new}} = 3.6 - 0.1 \times (2\times 3.6 - 4) = 3.6 - 0.1 \times 3.2 = 3.28 \]

此时 \(C'(3.6)=3.2>0\),继续向左移动。

多次迭代后逐渐逼近 \(x=2\)。这就是梯度下降在一维问题中的体现。

关键思想

  • 方向由导数符号决定:若导数为正,说明当前点位于最优解右侧,需要减小 \(x\);若导数为负,则需要增大 \(x\)
  • 步长受学习率控制\(η\) 太大可能导致跳过最优点(震荡),太小则收敛缓慢。

2. 二维参数问题举例

假设成本函数为

\[C(x,y) = x^2 + y^2 \]

这是一个开口向上的抛物面,最低点在 \((0,0)\),最小成本为 \(0\)

(1) 计算梯度

\(C(x,y)=x^{2}+y^{2}\)
\(\frac{\partial C}{\partial x} = 2x,\qquad \frac{\partial C}{\partial y} = 2y\)

\[\nabla C(x,y) = (2x,\; 2y) \]

(2) 初始化参数

选取初始点 \((x_0, y_0) = (3, 2)\)
学习率 \(\eta = 0.1\)

(3) 第一次迭代(手工模拟)

更新规则:

\[x_{\text{new}} = x_0 - \eta \cdot 2x_0 = 3 - 0.1 \times 6 = 2.4 \]

\[y_{\text{new}} = y_0 - \eta \cdot 2y_0 = 2 - 0.1 \times 4 = 1.6 \]

得到新点

\[(2.4,\; 1.6) \]

比较两次的成本:

\[C(3,2)=3^{2}+2^{2}=9+4=13,\qquad C(2.4,1.6)=2.4^{2}+1.6^{2}=5.76+2.56=8.32 \]

成本从 \(13\) 下降到 \(8.32\),并且新点 \((2.4,1.6)\) 到原点的距离更短,说明确实在向最小值靠近。

(4) 多次迭代的效果

如果继续迭代,点列将沿着一条直线逼近原点 $$(0,0)$$。例如第二次迭代:

\[x_{2}=2.4-0.1\times(2\times2.4)=2.4-0.48=1.92 \]

\[y_{2}=1.6-0.1\times(2\times1.6)=1.6-0.32=1.28 \]

成本降至 $$1.92{2}+1.28=3.6864+1.6384=5.3248$$依此类推,随着迭代次数增加,\((x_k, y_k) \to (0,0)\),成本趋近于 \(0\)

image

说明

  • 左侧三维图:彩色曲面代表成本函数,红色点线表示从 (3,2) 出发,沿最陡下降方向(负梯度)逐步走向谷底 (0,0)。
  • 右侧等高线图:圆圈代表成本值相同的等高线,下降路径垂直于等高线(梯度方向),最终收敛到中心。

绘图代码如下:

点击查看代码
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# 设置中文字体(避免字体缺失问题)
plt.rcParams['font.sans-serif'] = ['SimHei']        # Windows
# plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei']  # Linux
plt.rcParams['axes.unicode_minus'] = False

# 定义成本函数
def C(x, y):
    return x**2 + y**2

# 梯度函数
def grad_C(x, y):
    return np.array([2*x, 2*y])

# 梯度下降迭代(手动模拟多步)
def gradient_descent(start, learning_rate, steps):
    path = [start]
    for _ in range(steps):
        g = grad_C(path[-1][0], path[-1][1])
        new_point = path[-1] - learning_rate * g
        path.append(new_point)
    return np.array(path)

# 参数设置
start = (3, 2)
eta = 0.1
steps = 5  # 迭代5步
path = gradient_descent(start, eta, steps)

# ------------------ 1. 绘制三维曲面 + 下降路径 ------------------
fig = plt.figure(figsize=(12, 5))

# 子图1:3D曲面
ax1 = fig.add_subplot(121, projection='3d')
x_vals = np.linspace(-1, 4, 100)
y_vals = np.linspace(-1, 3, 100)
X, Y = np.meshgrid(x_vals, y_vals)
Z = C(X, Y)

ax1.plot_surface(X, Y, Z, cmap='viridis', alpha=0.7, edgecolor='none')
ax1.scatter(path[:,0], path[:,1], C(path[:,0], path[:,1]), 
            c='red', s=50, label='梯度下降路径点')
ax1.plot(path[:,0], path[:,1], C(path[:,0], path[:,1]), 
         'r--', linewidth=2, label='下降轨迹')
ax1.scatter(*start, C(*start), color='blue', s=80, label='起始点 (3,2)')
ax1.scatter(0, 0, 0, color='green', s=100, label='最优解 (0,0)')

ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.set_zlabel('成本 C(x,y)')
ax1.set_title('三维山谷图与梯度下降路径')
ax1.legend()

# 子图2:等高线图 + 下降路径
ax2 = fig.add_subplot(122)
contour = ax2.contour(X, Y, Z, levels=20, cmap='viridis')
ax2.clabel(contour, inline=True, fontsize=8)
ax2.plot(path[:,0], path[:,1], 'ro-', markersize=6, linewidth=2, label='下降路径')
ax2.scatter(*start, color='blue', s=80, label='起始点 (3,2)')
ax2.scatter(0, 0, color='green', s=100, label='最优解 (0,0)')
ax2.set_xlabel('x')
ax2.set_ylabel('y')
ax2.set_title('等高线图(山谷投影)')
ax2.legend()
ax2.grid(True, linestyle='--', alpha=0.5)

plt.tight_layout()
plt.show()

# 打印各步坐标
print("梯度下降迭代过程:")
for i, point in enumerate(path):
    print(f"第{i}步: ({point[0]:.4f}, {point[1]:.4f}), 成本 = {C(*point):.4f}")

3. 三维参数问题举例

设成本函数为
\(C(x,y,z) = (x-1)^2 + (y+2)^2 + z^2\)
三个变量独立,理论最优解是 \(x=1, y=-2, z=0\),最小成本 \(0\)

梯度
\(\nabla C = \left( 2(x-1),\; 2(y+2),\; 2z \right)\)

从初始点 \((0,0,0)\) 开始,学习率 \(\eta=0.2\),一次更新:

\[\begin{aligned} x_{\text{new}} &= 0 - 0.2 \times 2(0-1) = 0 - 0.2 \times (-2) = 0.4 \\ y_{\text{new}} &= 0 - 0.2 \times 2(0+2) = 0 - 0.2 \times 4 = -0.8 \\ z_{\text{new}} &= 0 - 0.2 \times 2\times 0 = 0 \end{aligned} \]

新点 \((0.4, -0.8, 0)\) 更靠近 \((1,-2,0)\)。继续迭代最终收敛。

关键点:即使有 3 个参数,我们无法画出四维图像,但梯度下降的计算过程与二维参数时完全一样——只需把梯度向量的长度扩展到 3(或任意维度 \(n\)),每次沿负梯度方向走一小步即可。


总结

参数个数 可视化可能性 寻找最优解的方法
1 二维平面曲线 求导或观察图形
2 三维曲面(山谷形) 梯度下降 / 求偏导方程组
3 及以上 无法直接画图 梯度下降(或其它数值优化算法)
核心概念 说明
梯度方向 函数值上升最快的方向,负梯度即下降最快方向
学习率 控制每步步长,太大震荡,太小收敛慢
更新规则 \(x_{\text{new}} = x_0 - \eta \cdot \nabla C(x_0)\)

梯度下降的核心思想不依赖于维度——只要知道每个参数对应的偏导数(梯度分量),就能一步步“走下山谷”。这就是它在机器学习和复杂工程优化中被广泛使用的原因。

📢 声明:本文借助AI辅助工具进行资料整理与初稿生成,所有内容均经过作者本人的详细核对、修改与编排,文责自负。

posted @ 2026-04-12 12:02  Lyn_Li  阅读(16)  评论(0)    收藏  举报