AI 数学课程 · 第 6 课,共 180

面向 AI 的求和记号:损失如何变成一个训练目标

学习求和与乘积记号,将上下界展开为循环,并使用 NumPy 的求和与平均把逐样本误差变成均方误差目标。

分享这篇文章

一个模型做出四个预测,并产生四个平方损失:11441199。一次训练步骤需要一个目标,而不是四个彼此分离的数字。把损失相加得到 1515,取平均得到 3.753.75。两种归约都有效,但它们回答的是不同的问题,并且在代码中会产生不同的尺度。

求和记号把重复的加法变成一个紧凑表达式。学完本课,你将能够从上下界展开求和或乘积,把它翻译成循环,在 NumPy 中计算均方误差(MSE),并发现上下界、分母或轴错误的归约。

本课建立在第 5 课的带索引值之上:一旦 i\ell_i 表示“示例 ii 的损失”,下一步就是组合所有带索引的损失。官方 Mathematics for Machine Learning 配套网站是本课程参考书的来源主页;它的导论章节说明了从数值数据走向模型和学习目标的路径。

上下界告诉求和从哪里开始、在哪里停止

希腊大写字母 sigma,\sum,表示“把一串项相加”。例如,

i=25ai\sum_{i=2}^{5} a_i

这个式子有四个部分需要阅读:

  • ii 是不断变化的索引
  • 22 是下界,即 ii 开始的位置;
  • 55 是上界,即 ii 停止的位置;以及
  • aia_i 是在每个索引处计算的项。

两个界都包含在内,因此展开为

i=25ai=a2+a3+a4+a5.\sum_{i=2}^{5} a_i=a_2+a_3+a_4+a_5.

展开式同时也是一个算法。累计和从零开始,一次吸收一项:

a = [10, 20, 30, 40, 50]
n = 5
total = 0

for i in range(1, n + 1):
    total += a[i - 1]

print(total)
150

数学索引从 11nn,而 Python 列表使用从 00n1n-1 的位置。Python 的停止值不包含在内,所以必须使用 range(1, n + 1) 才能包含 nn。写成 range(1, n) 会悄悄漏掉最后一项。表达式 a[i - 1] 把数学中的一基索引转换为第 5 课介绍的零基列表位置。

乘积记号改变起始值和运算

希腊大写字母 pi,\prod,表示“把一串项相乘”。它使用同样类型的索引和包含两端的上下界:

i=25ai=a2a3a4a5.\prod_{i=2}^{5} a_i=a_2a_3a_4a_5.

a2=2a_2=2a3=3a_3=3a4=1a_4=1a5=4a_5=4 时,

i=25ai=2×3×1×4=24.\prod_{i=2}^{5}a_i=2\times3\times1\times4=24.

对应的循环从 11 开始,因为乘以 11 不会改变数字:

values = [2, 3, 1, 4]
product = 1

for value in values:
    product *= value

print(product)
24

product0 开始会让之后的每个结果都为零。这个差异也解释了标准的空情况。没有项的和是 00,没有项的积是 11:二者都使用不会改变后续加法或乘法的中性起始值。NumPy 为 np.sumnp.prod 记录了同样的约定。

重复运算记号累加器起始值空结果
加法\sum0000
乘法\prod1111

当课程学习联合概率时,乘积会变得尤其重要。现在最关键的实现习惯,是让累加器及其起始值与记号相匹配。

四个预测误差变成一个均方误差

假设一个回归模型为四个示例分别预测一个数字:

y^=(2,0,4,5),y=(1,2,5,2).\hat{\boldsymbol{y}}=(2,0,4,5), \qquad \boldsymbol{y}=(1,2,5,2).

这里 y^i\hat y_i 是示例 ii 的预测值,yiy_i 是其目标值。把每个示例的平方损失定义为

i=(y^iyi)2.\ell_i=(\hat y_i-y_i)^2.

交互式累加器展示了 sigma 记号压缩掉的中间状态。它的表格仍然是完整的文本替代:第 ii 行列出 y^i\hat y_iyiy_i、平方损失,以及该损失是否已经进入累计和。

逐个示例构建训练目标。播放序列,或使用按钮逐步查看。
预测值、目标值、平方损失及其累加器状态
示例 预测值 目标值 平方损失累加器状态
1211 本步加入
2024 等待中
3451 等待中
4529 等待中
累计和1
已纳入的项
1
当前平均值
1 ÷ 1 = 1.00

第 1/4 步:部分和为 1。

四行全部进入累加器后,累计和为 1515。将它除以纳入的四行,得到 MSE 3.753.75。动画没有改变数学内容;它让重复更新 total = total + loss 变得可见。

NumPy 与公式相互对应

NumPy 可以在归约前保留每个示例的损失:

import numpy as np

y_true = np.array([1.0, 2.0, 5.0, 2.0])
y_pred = np.array([2.0, 0.0, 4.0, 5.0])

squared_losses = (y_pred - y_true) ** 2
total_squared_error = np.sum(squared_losses)
mse = np.mean(squared_losses)

print("per-example squared losses:", squared_losses)
print("sum:", total_squared_error)
print("mean squared error:", mse)
per-example squared losses: [1. 4. 1. 9.]
sum: 15.0
mean squared error: 3.75

np.sum 文档定义了对数组元素执行的归约。np.mean 文档定义了算术平均值,并说明默认情况下使用展平后的数组。在这个一维示例中,展平不会改变任何内容:四个条目都会被归约。

squared_losses 保留为命名数组有助于调试。它能显示某一个示例是否主导了目标,也让测试可以将实现与上面的四个手算结果进行比较。

轴决定哪些索引消失

对于多维损失数组,“取平均”在轴明确之前是不完整的。考虑两个示例,每个示例有三个输出损失:

L=[141904].L= \begin{bmatrix} 1 & 4 & 1\\ 9 & 0 & 4 \end{bmatrix}.

行是示例,列是输出。NumPy 的 axis 参数指定要归约的轴:

losses = np.array([
    [1.0, 4.0, 1.0],
    [9.0, 0.0, 4.0],
])

print("all six losses:", np.mean(losses))
print("one mean per example:", np.mean(losses, axis=1))
print("one mean per output:", np.mean(losses, axis=0))
all six losses: 3.1666666666666665
one mean per example: [2.         4.33333333]
one mean per output: [5.  2.  2.5]
表达式被归约的方向保留的结果
np.mean(losses)两个轴六个损失的一个标量
np.mean(losses, axis=1)每行中的列每个示例一个值
np.mean(losses, axis=0)每列中的行每个输出一个值

当模型需要每个示例一个损失时使用 axis=0 是语义错误。代码能够运行,数字看起来也合理,但留下的索引表示的是“输出”而不是“示例”。summean 的 NumPy 直接文档说明,axis=None 会归约整个数组,而整数则选择执行归约的轴。

和与平均值携带不同的尺度

对于固定的、非空的 nn 个损失集合,

mean(1,,n)=1nsum(1,,n).\operatorname{mean}(\ell_1,\ldots,\ell_n) =\frac{1}{n}\operatorname{sum}(\ell_1,\ldots,\ell_n).

平均值是重新缩放后的和,但当批次大小不同时,这个尺度很重要。四个损失都为 22 的示例,其和为 88、平均值为 22;八个这样的示例,其和为 1616,平均值仍为 22。和衡量集合的总损失,平均值衡量每个纳入项目的损失。

在模型训练期间,预测规则为每个示例产生一个或多个损失。归约把这些值变成用于评估当前参数的标量目标。因此,选择和、平均值,还是带掩码和加权的变体,属于模型的数学契约,而不仅仅是代码格式。

第 7 课将使用幂和根来推理模型尺度。在该课上线之前,面向 AI 的数学课程页面是按发布顺序继续学习的可靠位置。本课学到的记号会贯穿整个课程:和构建加权组合与目标,积则构建重复因子。

检查你的理解

问题 1

将从 i = 3 到 i = 6 的和展开:Σᵢ₌₃⁶ (2i − 1),然后计算其值。

显示分步解答

下界是 3,上界是 6,因此两端都出现:

i=36(2i1)=(231)+(241)+(251)+(261).\sum_{i=3}^{6}(2i-1) =(2\cdot3-1)+(2\cdot4-1)+(2\cdot5-1)+(2\cdot6-1).

先计算每个带索引的项,再相加:

5+7+9+11=32.5+7+9+11=32.

共有 63+1=46-3+1=4 项。如果只数出三项,就说明某个端点被漏掉了。

问题 2

Python 循环本来要实现 Σᵢ₌₁ⁿ aᵢ,却使用 for i in range(1, n)。缺少哪一项?循环应如何索引零基列表 a?

显示分步解答

Python 不包含 range 的停止值,所以 range(1, n) 产生 1,2,,n11,2,\ldots,n-1。缺少的项是 ana_n

让停止位置为 n + 1 以包含数学上界,然后在访问零基列表时减去 1:

total = 0
for i in range(1, n + 1):
    total += a[i - 1]

现在 i=1i=1 读取 a[0]i=ni=n 读取 a[n - 1],因此从 a1a_1ana_n 的每一项都恰好出现一次。

问题 3

展开 ∏ₖ₌₂⁴ (k + 1),计算它,并解释为什么循环累加器必须从 1 开始。

显示分步解答

包含两端的上下界给出索引 223344

k=24(k+1)=(2+1)(3+1)(4+1)=3×4×5=60.\prod_{k=2}^{4}(k+1)=(2+1)(3+1)(4+1)=3\times4\times5=60.

循环在看到第一项之前需要一个值。从 11 开始可以保留第一次乘法,因为 1×3=31\times3=3。从 00 开始则会得到 0×3×4×5=00\times3\times4\times5=0,抹去所有项。

问题 4

对于目标值 (3, 1, 2) 和预测值 (1, 2, 2),计算每个平方损失、它们的和以及 MSE。

显示分步解答

对每个示例用预测值减去目标值:

(13,  21,  22)=(2,1,0).(1-3,\;2-1,\;2-2)=(-2,1,0).

将这些误差平方,得到每个示例的损失:

(1,2,3)=((2)2,12,02)=(4,1,0).(\ell_1,\ell_2,\ell_3)=((-2)^2,1^2,0^2)=(4,1,0).

它们的和是 4+1+0=54+1+0=5。共有三个示例,因此

MSE=13i=13i=531.667.\operatorname{MSE}=\frac{1}{3}\sum_{i=1}^{3}\ell_i =\frac{5}{3}\approx1.667.

小数是近似值;5/35/3 是精确值。

问题 5

批次 A 的损失为 (2, 2),批次 B 的损失为 (2, 2, 2, 2)。比较它们的和与平均值。哪种归约保留了每个示例的尺度?

显示分步解答

对于批次 A,

sum(A)=2+2=4,mean(A)=42=2.\operatorname{sum}(A)=2+2=4, \qquad \operatorname{mean}(A)=\frac{4}{2}=2.

对于批次 B,

sum(B)=2+2+2+2=8,mean(B)=84=2.\operatorname{sum}(B)=2+2+2+2=8, \qquad \operatorname{mean}(B)=\frac{8}{4}=2.

由于批次 B 包含两倍数量的示例,和翻了一倍。平均值仍是 22,所以在这个比较中它保留了每个示例的损失尺度。

问题 6

空和与空积是什么?如果两个累加器循环都从 0 开始,会出现什么实现错误?

显示分步解答

加法的中性值是 00,所以没有接收到项的和仍为 00。乘法的中性值是 11,所以没有接收到项的积仍为 11

iai=0,iai=1.\sum_{i\in\varnothing}a_i=0, \qquad \prod_{i\in\varnothing}a_i=1.

和累加器从 0 开始是正确的。积累加器从 0 开始是错误:即使序列非空,也会因为每次更新都是 0×ai=00\times a_i=0 而变成零。积累加器必须从 1 开始。

问题 7

一个损失数组的形状为 (32, 5),组织方式是示例 × 输出。哪个 NumPy 表达式会为每个示例产生一个平均值?错误的轴会返回什么?

显示分步解答

每一行包含一个示例的五个输出损失。要在每行内组合各列,应归约轴 1:

per_example_loss = np.mean(losses, axis=1)

轴 1 的大小是 5,它消失后留下形状 (32,):32 个示例各有一个值。

如果使用 axis=0,归约的则是包含 32 个示例的轴。结果形状为 (5,),包含每个输出位置跨批次的一个平均值。这些数字可能有效,但回答的是错误的问题。

资料来源

  1. Mathematics for Machine Learning companion website
  2. Mathematics for Machine Learning book PDF
  3. NumPy documentation: numpy.sum
  4. NumPy documentation: numpy.prod
  5. NumPy documentation: numpy.mean