第 5 章 导数
学习目标
- 由平均变化率取极限,得到导数的定义
- 理解导数的几何意义(切线斜率)与物理意义(瞬时速度)
- 掌握常数、幂函数的求导公式
- 掌握和差、乘积、商与链式法则
- 会用 PyTorch 自动求导验证
5.1 导数的定义
第 2 章和第 3 章铺垫了完整的工具链:平均变化率 极限 瞬时变化率。现在正式命名。
导数(derivative):函数 在点 处的导数定义为
如果这个极限存在,就说 在 处可导。记号:除了 ,也写作 (读作「d y 比 d x」),其中 。两种记号含义相同:
几何意义:切线斜率。 就是曲线 在点 处切线的斜率。
物理意义:瞬时变化率。若 是路程、 是时间, 就是瞬时速度。
把定义用起来,求 在任意点 的导数:
每一步都有依据:展开平方;同类项 相消;提取公因式 后约分();最后 时 。结论:
验证:在 处,,与第 2 章数值表一致。
def f(x):
return x ** 2
for h in [1.0, 0.1, 0.01, 0.001]:
avg_rate = (f(2 + h) - f(2)) / h
print(f"h = {h:<6} 平均变化率 = {avg_rate:.4f}")h = 1.0 平均变化率 = 5.0000
h = 0.1 平均变化率 = 4.1000
h = 0.01 平均变化率 = 4.0100
h = 0.001 平均变化率 = 4.0010
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, axes = plt.subplots(1, 2, figsize=(12, 4.6))
# 左图:f(x) = x² 及其切线
x = np.linspace(-2.4, 2.4, 400)
axes[0].plot(x, x**2, color="tab:blue", label="f(x) = x²")
for a in [-1.5, -0.5, 0.5, 1.5]:
slope = 2 * a
xt = np.array([a - 0.8, a + 0.8])
axes[0].plot(xt, a**2 + slope * (xt - a), color="tab:red", linewidth=1.4)
axes[0].annotate(f"斜率 {slope:.0f}", (a, a**2),
textcoords="offset points", xytext=(6, 8), fontsize=9, color="tab:red")
axes[0].set_title("切线斜率 = 导数")
axes[0].set_xlim(-2.6, 2.6)
axes[0].set_ylim(-0.8, 6.2)
# 右图:f'(x) = 2x
axes[1].plot(x, 2 * x, color="tab:green", label="f'(x) = 2x")
axes[1].set_title("导数函数:每一点的切线斜率")
axes[1].set_xlim(-2.6, 2.6)
axes[1].set_ylim(-5.5, 5.5)
for ax in axes:
ax.axhline(0, color="black", linewidth=0.8)
ax.axvline(0, color="black", linewidth=0.8)
ax.grid(True, linestyle=":", alpha=0.5)
ax.set_aspect("equal")
fig.savefig("book/public/figs/fig05-tangent_slopes.png", dpi=120, bbox_inches="tight")
plt.close(fig)5.2 可导与连续
可导和连续有确定的关系,先给结论:
定理:若 在 处可导,则 在 处连续。
证明:
当 时,第一项趋于 (可导的定义),第二项趋于 0,乘积趋于 。所以 ,即 ,连续成立。
反过来不成立:连续不一定可导。经典反例是绝对值函数 在 处。它连续(图像不断),但
左右分别是 1 和 ,极限不存在,所以不可导。图像上 处是一个尖角,切线「立不起来」。
for h in [0.1, 0.01, -0.01, -0.1]:
print(f"h = {h:7.3f} (|h| - 0)/h = {abs(h)/h:7.3f}")h = 0.100 (|h| - 0)/h = 1.000
h = 0.010 (|h| - 0)/h = 1.000
h = -0.010 (|h| - 0)/h = -1.000
h = -0.100 (|h| - 0)/h = -1.000
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(-2, 2, 400)
fig, ax = plt.subplots(figsize=(6, 4.5))
ax.plot(x, np.abs(x), color="tab:blue", label="f(x) = |x|")
ax.scatter([0], [0], color="tab:red", s=42, zorder=4)
ax.annotate("尖角:没有唯一切线", (0, 0), textcoords="offset points", xytext=(8, -18), color="tab:red")
ax.set_xlim(-2.2, 2.2)
ax.set_ylim(-0.3, 2.4)
ax.axhline(0, color="black", linewidth=0.8)
ax.axvline(0, color="black", linewidth=0.8)
ax.grid(True, linestyle=":", alpha=0.5)
ax.legend()
ax.set_title("连续但不可导:|x| 在 0 处")
fig.savefig("book/public/figs/fig05_abs.png", dpi=120, bbox_inches="tight")
plt.close(fig)5.3 常数与幂函数
常数函数的导数为 0:
因为常数函数的图像是水平线,斜率处处为 0。从定义验证:,。
幂函数求导公式:
以 为例推导。利用立方展开式:
当 ,后两项消失,得 。对一般的 ,展开 用二项式定理,第二项一定是 ,其余项都含 及以上,除以 取极限后全部消失,只剩 。
由此得到一组常用公式( 可推广到任意实数,第 6 章会验证):
5.4 和差与常数倍
和差法则:
常数倍法则:
推导(以加法为例):
两项分别趋于 、,由极限的加法法则,和趋于 。常数倍法则同理,把 提到分数线外即可。
用法:
5.5 乘法法则
加法法则很直观,乘法法则需要动点脑筋—— 不等于 。正确的法则是:
推导:
分子不太好直接化简,技巧是「加一项、减一项」::
当 : 中 ,(可导必连续); 中 。合起来就是 。
验证 、 在 处:
def f(x):
return x ** 3
def g(x):
return x ** 2 + 1
def fp(x):
return 3 * x ** 2
def gp(x):
return 2 * x
x = 1.5
product_rule = fp(x) * g(x) + f(x) * gp(x)
direct = 5 * x ** 4 + 3 * x ** 2 # (x^5 + x^3)' = 5x^4 + 3x^2
print("乘法法则:", product_rule)
print("直接展开:", direct)乘法法则: 32.0625
直接展开: 32.06255.6 商法则
记忆口诀:「上导乘下,减上乘下导,除以下的平方」。它是乘法法则的推论:把 看成 ,用乘法法则与幂函数求导推出。这一章直接给结论,重点是会用:
5.7 链式法则:函数的函数
考虑 。它先算 ,再算 ——一个函数套在另一个函数里面,叫复合函数。
链式法则(chain rule):
或者写成:
直觉:外层变化率 内层变化率。好比 每增加 1, 增加 ; 每增加 1, 增加 ;那么 每增加 1, 增加 。
算 :
验证:设 ,;外层 ,。两者相乘,。
def y(x):
return (x ** 2 + 1) ** 3
h = 1e-6
x = 2.0
numerical = (y(x + h) - y(x - h)) / (2 * h)
chain_rule = 6 * x * (x ** 2 + 1) ** 2
print("中心差商 ≈", numerical)
print("链式法则 =", chain_rule)中心差商 ≈ 300.00000000995897
链式法则 = 300.05.8 用 PyTorch 自动求导验证
PyTorch 的自动微分(autograd)能直接算出导数,它的原理就是链式法则:把每个基本运算的导数记下来,按复合结构逐层相乘。这正好验证我们手算的结果。
import torch
x = torch.tensor(2.0, requires_grad=True)
y = (x ** 2 + 1) ** 3
y.backward()
print("y =", y.item())
print("dy/dx 在 x=2 处 =", x.grad.item())y = 125.0
dy/dx 在 x=2 处 = 300.0与手算、差商三方一致。第 13、14 章会看到,深度学习训练的核心——反向传播——就是链式法则的大规模应用。
5.9 动手实践:求切线方程
求 在 处的切线方程。
斜率:。切点:。切线方程:
import numpy as np
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
x = np.linspace(0.5, 4.5, 300)
fig, ax = plt.subplots(figsize=(6.5, 5))
ax.plot(x, x**2, color="tab:blue", label="f(x) = x²")
ax.plot(x, 6 * x - 9, color="tab:red", label="切线 y = 6x - 9")
ax.scatter([3], [9], color="tab:red", s=40, zorder=4)
ax.annotate("(3, 9), 斜率 6", (3, 9), textcoords="offset points", xytext=(8, -14), color="tab:red")
ax.set_xlim(0.5, 4.5)
ax.set_ylim(-1, 20)
ax.grid(True, linestyle=":", alpha=0.5)
ax.legend()
ax.set_title("用导数求切线")
fig.savefig("book/public/figs/fig05_tangent_at_3.png", dpi=120, bbox_inches="tight")
plt.close(fig)常见错误
| 错误写法/理解 | 原因 |
|---|---|
| 认为 | 乘法法则是 ,少一项就错 |
| 认为 | 商法则是 |
| 链式法则漏乘内层导数 | 对 求导,必须乘 |
| 认为可导和连续等价 | 可导必连续,但连续不一定可导(如 在 0 处) |
| 求导时把常数当变量 | 常数导数为 0, 而不是 |
章末练习
基础
- 用定义求 在 处的导数(写出完整极限过程)。
- 求导:、、。
- 求 在 处的切线方程。
提高
- 用乘法法则求 (设 ),并写出每一步。
- 用链式法则求 的导数。
挑战
- 从定义出发,完整证明乘法法则 (包括「加一项减一项」的步骤)。
- 用 PyTorch 自动求导求 在 处的导数,并与手算结果 比较。
章末自测
每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。
- 导数的定义是?
- A.
- B.
- C.
- D.
- 等于?
- A.
- B.
- C.
- D.
- 常数函数的导数是?
- A.
- B. 常数本身
- C.
- D. 不存在
- 等于?
- A.
- B.
- C.
- D.
- 乘法法则 等于?
- A.
- B.
- C.
- D.
- 链式法则 等于?
- A.
- B.
- C.
- D.
- 在 处的导数 是?
- A.
- B.
- C.
- D.
- 在 处?
- A. 可导
- B. 连续但不可导
- C. 不连续
- D. 无定义
- 可导与连续的关系是?
- A. 可导必连续
- B. 连续必可导
- C. 两者无关
- D. 可导必不连续
- 在 处切线的斜率是?
- A.
- B.
- C.
- D.
