Skip to content

第 12 章 多元极值与最优化 ​

学习目标 ​

  • 掌握多元函数极值的必要条件(梯度为零)
  • 掌握二阶偏导数判别法(Hessian 判别)
  • 理解鞍点
  • 掌握拉格朗日乘子法求条件极值
  • 会用 PyTorch 与数值方法验证

12.1 多元极值问题 ​

一元函数有极值问题(第 7 章),二元函数也有。比如:

  • :碗形曲面,最低点在原点 ,函数值 0;
  • 成本函数 取决于原料 与工时 ,工厂想知道怎样组合最省钱;
  • 收益函数 取决于广告费与定价,企业想知道怎样组合收益最大。

极值的定义和一元情形类似:局部极大值/极小值 = 在某个小范围内函数值最大/最小的点。

12.2 必要条件:梯度为零 ​

定理:若 是 的极值点,且 在 可导,则

即 。这样的点叫驻点。

为什么? 在 处把 固定为 ,只沿 方向看,得到一个一元函数 ,它仍然在 处取得极值;由费马引理,。同理沿 方向,。所以两个偏导都为零。

和一元情形一样,这是必要条件:梯度为零的点可能是极大、极小,也可能是鞍点,需要进一步判别。

例:,、,联立 、,唯一驻点是 ,最小值点。

python
import numpy as np

x = np.linspace(-5, 5, 1001)
y = np.linspace(-5, 5, 1001)
X, Y = np.meshgrid(x, y)
Z = X ** 2 + Y ** 2

i = np.unravel_index(np.argmin(Z), Z.shape)
print("网格最小点: x =", X[i], " y =", Y[i], " 函数值 =", Z[i])
text
网格最小点: x = 0.0  y = 0.0  函数值 = 0.0

12.3 Hessian 判别法 ​

驻点是不是极值点?看二阶偏导数组成的Hessian 矩阵的判别式:

(其中 是先对 求导再对 求导的混合偏导,记号 。对「好」的函数,混合偏导与求导顺序无关:。)

判别规则:

  • 且 :极小值点;
  • 且 :极大值点;
  • :鞍点,不是极值点;
  • :判别法失效,需另想办法。

直觉:一元时用 的符号判断凹凸;二元时 综合了 方向、 方向与交叉项,判断曲面在驻点附近是「碗」(极值)还是「马鞍」(鞍点)。

12.4 鞍点:沿一个方向是谷,沿另一个方向是山 ​

在原点:沿 方向是 (向上弯的谷),沿 方向是 (向下弯的山)。原点既不是极大也不是极小,叫鞍点——像马鞍中间那个位置。

鞍点

python
import matplotlib.pyplot as plt
from matplotlib import font_manager
for f in font_manager.findSystemFonts():
    if any(k in f for k in ("NotoSansCJK", "NotoSansSC", "wqy", "SimHei", "msyh", "PingFang")):
        font_manager.fontManager.addfont(f)
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC", "WenQuanYi Zen Hei", "SimHei", "Microsoft YaHei", "PingFang SC"]
plt.rcParams["axes.unicode_minus"] = False

import numpy as np

fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection="3d")
x = np.linspace(-1.5, 1.5, 60)
y = np.linspace(-1.5, 1.5, 60)
X, Y = np.meshgrid(x, y)
Z = X ** 2 - Y ** 2
ax.plot_surface(X, Y, Z, cmap="coolwarm", alpha=0.9)
ax.scatter([0], [0], [0], color="tab:red", s=50, zorder=5)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
ax.set_title("鞍点:z = x² - y² 在原点")
fig.savefig("book/public/figs/fig12-saddle.png", dpi=120, bbox_inches="tight")
plt.close(fig)
python
fxx, fyy, fxy = 2.0, -2.0, 0.0
D = fxx * fyy - fxy ** 2
print("D =", D)
print("结论:", "鞍点" if D < 0 else "极值点")
text
D = -4.0
结论: 鞍点

12.5 条件极值与拉格朗日乘子法 ​

很多实际问题带约束:在满足某条件的前提下求极值。比如「两数之和为 10,乘积最大是多少」——约束 ,目标 。

拉格朗日乘子法(Lagrange multiplier):求 在约束 下的极值,构造拉格朗日函数

然后解方程组

三个方程,三个未知数 。第三个方程 恰好就是约束本身。

几何直觉:无条件极值要求梯度为零;有条件极值要求「沿约束曲线方向看,函数不再变化」,等价于梯度 与约束曲线(即 的等高线)的梯度 平行。平行条件正是 ,即前两个方程。

解「两数之和为 10,乘积最大」:设 ,

由前两个方程 、,所以 ,代入约束得 ,最大乘积 。

拉格朗日乘子

python
import matplotlib.pyplot as plt
from matplotlib import font_manager
for f in font_manager.findSystemFonts():
    if any(k in f for k in ("NotoSansCJK", "NotoSansSC", "wqy", "SimHei", "msyh", "PingFang")):
        font_manager.fontManager.addfont(f)
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC", "WenQuanYi Zen Hei", "SimHei", "Microsoft YaHei", "PingFang SC"]
plt.rcParams["axes.unicode_minus"] = False

import numpy as np

x = np.linspace(0, 10, 300)
y = np.linspace(0, 10, 300)
X, Y = np.meshgrid(x, y)
Z = X * Y

fig, ax = plt.subplots(figsize=(6.5, 5.5))
cs = ax.contour(X, Y, Z, levels=[5, 10, 15, 20, 24, 25], colors="tab:blue")
ax.clabel(cs, inline=True, fontsize=9)
ax.plot([0, 10], [10, 0], color="tab:red", linewidth=2, label="约束 x + y = 10")
ax.scatter([5], [5], color="tab:green", s=50, zorder=5)
ax.annotate("切点 (5, 5)", (5, 5), textcoords="offset points", xytext=(8, -14), color="tab:green")
ax.set_xlim(0, 10.5)
ax.set_ylim(0, 10.5)
ax.set_aspect("equal")
ax.grid(True, linestyle=":", alpha=0.5)
ax.legend()
ax.set_title("条件极值:等高线与约束相切处")
fig.savefig("book/public/figs/fig12-lagrange.png", dpi=120, bbox_inches="tight")
plt.close(fig)
python
import numpy as np

# 代入约束 y = 10 - x,最大化 f(x) = x(10 - x)
x = np.linspace(0, 10, 1001)
f = x * (10 - x)
i = np.argmax(f)
print("最大值点: x =", x[i], " y =", 10 - x[i], " f =", f[i])
text
最大值点: x = 5.0  y = 5.0  f = 25.0

12.6 用 PyTorch 验证驻点 ​

求 的驻点,并验证梯度:

python
import torch

x = torch.tensor(0.0, requires_grad=True)
y = torch.tensor(0.0, requires_grad=True)
z = x ** 2 + y ** 2 - x * y
z.backward()

print("驻点处梯度: ∂z/∂x =", x.grad.item(), " ∂z/∂y =", y.grad.item())

# Hessian 判别
fxx, fyy, fxy = 2.0, 2.0, -1.0
D = fxx * fyy - fxy ** 2
print("D =", D, " fxx =", fxx)
print("结论:", "极小值点" if D > 0 and fxx > 0 else "其他")
text
驻点处梯度: ∂z/∂x = 0.0  ∂z/∂y = 0.0
D = 3.0  fxx = 2.0
结论: 极小值点

常见错误 ​

错误写法/理解原因
只解 就完事驻点要求两个偏导同时为零,还要用 判别
认为驻点必是极值点鞍点()梯度也为零,但不是极值
判别时只信 符号必须结合 ; 时 符号没有决定意义
拉格朗日函数忘了写约束项, 是约束;三个方程缺一不可
约束极值与无条件极值混淆有约束时梯度不必为零,而是与约束梯度平行

章末练习 ​

基础

  1. 求 的驻点,并用 判别类型。
  2. 求 在 的类型。
  3. 在约束 下,求 的最大值。

提高

  1. 求 的驻点并判别类型(提示:联立 、)。
  2. 用拉格朗日乘子法求 在 下的最小值。

挑战

  1. 用拉格朗日乘子法证明:固定周长 的矩形中,正方形面积最大。
  2. 用 PyTorch 自动求导验证:对 ,从 出发沿负梯度方向迭代 100 步(学习率 0.1),能否收敛到 。

章末自测 ​

每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。

  1. 二元函数驻点的条件是?
    • A. 或
    • B. 且
    • C.
    • D.
  2. 的驻点是?
    • A.
    • B.
    • C.
    • D. 不存在
  3. 鞍点的判别特征是?
    • A.
    • B.
    • C.
    • D.
  4. 在原点是什么点?
    • A. 极小值点
    • B. 极大值点
    • C. 鞍点
    • D. 无法判断
  5. Hessian 判别中, 且 表示?
    • A. 极大值点
    • B. 极小值点
    • C. 鞍点
    • D. 无结论
  6. 拉格朗日函数 的形式是?
    • A.
    • B.
    • C.
    • D.
  7. 拉格朗日乘子法的第三个方程是?
    • A. ,即约束本身
    • B.
    • C.
    • D.
  8. 下 的最大值是?
    • A.
    • B.
    • C.
    • D.
  9. 有条件极值时,梯度 与约束梯度 的关系是?
    • A. 垂直
    • B. 平行
    • C. 相等
    • D. 无关
  10. 对「好」的函数,混合偏导 与 ?
    • A. 互为相反数
    • B. 相等
    • C. 无关
    • D. 乘积为 1