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

面向 AI 的标量乘法:让向量变强、变弱或转向

逐坐标缩放向量,预测方向和大小,并把同一运算联系到嵌入、学习率和 NumPy。

分享这篇文章

方向向量可以说明模型更新应该朝哪里走,却不说明移动的幅度。一个数字补上第二个决定。如果方向是 [4,−3]T[4,-3]^\mathsf{T},将它乘以 0.250.25 会得到更短的移动 [1,−0.75]T[1,-0.75]^\mathsf{T}。乘以 −1-1 会保持长度不变,但使它指向相反方向。

这个数字就是标量:应用于每个坐标的一个值。学完本课后,你将能够计算标量–向量乘积,根据标量的符号和绝对值预测其方向与大小,在 NumPy 中正确实现它,并识别学习率缩放的更新或加权嵌入贡献中相同的机制。

**学习成果:**缩放向量,并预测方向和大小的变化。

第 15 课:面向 AI 的向量加法说明,向量通过相加对应坐标来组合。标量乘法会在相加前准备其中一个向量:它控制该向量贡献的强弱。官方 Mathematics for Machine Learning 配套网站在该书第 2.2 节介绍了乘以标量。本课下面的示例、代码、交互式射线、AI 应用和评估题均为原创。

一个数字作用于每个坐标

设 v∈Rn\boldsymbol{v}\in\mathbb{R}^{n} 是一个坐标为 v1,v2,…,vnv_1,v_2,\ldots,v_n 的实向量,设 α∈R\alpha\in\mathbb{R} 是一个实标量。希腊字母 α\alpha(alpha)只是一个数字的名称;cc、ss 或 λ\lambda 等符号也可以承担同样的角色。

该运算保留向量的维度和坐标顺序。标量不会追加坐标、选择某一个坐标,也不会混合相邻坐标。它通过同一乘法规则改变全部 nn 个值。

负缩放会反转每个非零坐标

取更新向量

u=[4−32]\boldsymbol{u}= \begin{bmatrix}4\\-3\\2\end{bmatrix}

并选择 α=−1.5\alpha=-1.5。符号 u\boldsymbol{u} 表示整个三坐标更新量。请从定义出发计算,而不要只根据负号猜答案。

这个计算把两个影响分开了。绝对值——也就是标量到零的距离——为 ∣α∣=1.5|\alpha|=1.5,所以向量变为原来的 1.5 倍。负号反转其方向。这两种影响都不会改变每个坐标所代表的特征或参数。

符号选择射线;绝对值选择延伸距离

在二维中,把 v\boldsymbol{v} 画成从原点出发的箭头。每个非零标量倍都位于穿过该箭头的同一条无限直线上。正标量位于同一条射线上,负标量位于相反的射线上,而零会把箭头压缩到原点。

在本课中,大小指欧几里得箭头长度。对于 v=[v1,…,vn]T\boldsymbol{v}=[v_1,\ldots,v_n]^\mathsf{T},定义

∥v∥2=v12+⋯+vn2.\lVert\boldsymbol{v}\rVert_2 =\sqrt{v_1^2+\cdots+v_n^2}.

下标 2 用来区分这条长度规则与后续课程将讨论的其他大小规则。标量乘法使这个大小变为 ∣α∣|\alpha| 倍,而不是 α\alpha 倍:

∥αv∥2=(αv1)2+⋯+(αvn)2=α2(v12+⋯+vn2)=∣α∣v12+⋯+vn2=∣α∣∥v∥2.\begin{aligned} \lVert\alpha\boldsymbol{v}\rVert_2 &=\sqrt{(\alpha v_1)^2+\cdots+(\alpha v_n)^2}\\ &=\sqrt{\alpha^2(v_1^2+\cdots+v_n^2)}\\ &=|\alpha|\sqrt{v_1^2+\cdots+v_n^2}\\ &=|\alpha|\lVert\boldsymbol{v}\rVert_2. \end{aligned}

绝对值是必要的,因为大小不可能为负。符号属于方向;绝对值属于大小。

标量 α\alpha当 v≠0˘05cboldsymbol0\boldsymbol{v}\ne\u005cboldsymbol{0} 时 αv\alpha\boldsymbol{v} 的方向大小
α>1\alpha>1方向相同变长,倍数为 α\alpha
α=1\alpha=1方向相同不变
0<α<10<\alpha<1方向相同变短,倍数为 α\alpha
α=0\alpha=0无方向:结果为 0\boldsymbol{0}零
−1<α<0-1<\alpha<0方向相反变短,倍数为 ∣α∣\lvert\alpha\rvert
α=−1\alpha=-1方向相反不变
α<−1\alpha<-1方向相反变长,倍数为 ∣α∣\lvert\alpha\rvert

拖动下面的标量,遍历全部七种情况。固定向量为 v=[4,−3]T\boldsymbol{v}=[4,-3]^\mathsf{T},其大小为 55。缩放后的箭头、状态句子和表格都从服务器渲染的 α=1.5\alpha=1.5 状态开始,并在组件变为可见后同步更新。

交互式标量乘法:移动一个标量,将固定向量与缩放后的结果进行比较。
选择乘以 v 的标量

范围为 −2 到 2,步长为 0.25。使用方向键移动一步,或使用 Page Up 和 Page Down 进行较大变化。

当前结果:α = +1.5,v = (+4, -3),αv = (+6, -4.5)。其大小为 7.5;方向为 与 v 相同。

基向量 v——实线箭头缩放向量 αv——虚线箭头

实线和文字区分箭头,不依赖颜色。当 α = 0 时,原点处的虚线环替代缩放箭头,因为零向量没有方向。

当前标量和箭头的数值替代视图
向量缩放值第一坐标第二坐标欧几里得大小相对于 v 的方向
基向量 v——实线箭头+1+4-35参考方向
缩放向量 αv——虚线箭头+1.5+6-4.57.5与 v 相同

图形只有二维,但规则并不局限于二维。在一个包含 768 个坐标的嵌入中,一个标量仍然会乘以全部 768 个坐标,并且在欧几里得长度规则下,大小仍会变为 ∣α∣|\alpha| 倍。

加法前缩放可以控制一项贡献

标量乘法在向量加法旁边尤其有用。假设模型有一个上下文状态

c=[1−12]\boldsymbol{c}=\begin{bmatrix}1\\-1\\2\end{bmatrix}

以及一个候选嵌入贡献

e=[21−1].\boldsymbol{e}=\begin{bmatrix}2\\1\\-1\end{bmatrix}.

权重为 α=0.5\alpha=0.5 时,先缩放再相加:

αe=0.5[21−1]=[10.5−0.5],c+αe=[1−12]+[10.5−0.5]=[2−0.51.5].\begin{aligned} \alpha\boldsymbol{e} &=0.5\begin{bmatrix}2\\1\\-1\end{bmatrix} =\begin{bmatrix}1\\0.5\\-0.5\end{bmatrix},\\ \boldsymbol{c}+\alpha\boldsymbol{e} &=\begin{bmatrix}1\\-1\\2\end{bmatrix} +\begin{bmatrix}1\\0.5\\-0.5\end{bmatrix} =\begin{bmatrix}2\\-0.5\\1.5\end{bmatrix}. \end{aligned}

权重改变 e\boldsymbol{e} 对这个和的贡献强度。权重为 00 会移除这项贡献;负权重会沿相反方向贡献。这就是“嵌入强度”的精确算术含义。它不保证完整神经网络的输出会与 α\alpha 成正比变化:后续变换、归一化和非线性运算可能改变下游影响。

分配律说明,缩放一个组合信号时,可以在各部分相加之前或之后计算:

α(v+w)=αv+αw.\alpha(\boldsymbol{v}+\boldsymbol{w}) =\alpha\boldsymbol{v}+\alpha\boldsymbol{w}.

在坐标 jj 上,两边都等于 α(vj+wj)=αvj+αwj\alpha(v_j+w_j)=\alpha v_j+\alpha w_j。因为每个坐标都相同,所以两个向量相等。配套规则 (α+β)v=αv+βv(\alpha+\beta)\boldsymbol{v}=\alpha\boldsymbol{v}+\beta\boldsymbol{v} 将在下一课中帮助我们高效地组合多个加权向量。

学习率会缩放优化器提出的方向

考虑最简单的随机梯度下降(SGD)步骤,不使用动量或权重衰减。设 θ\boldsymbol{\theta} 为参数向量,g\boldsymbol{g} 为指向损失增加方向的梯度向量。正学习率 η\eta 会在相减前缩放该方向:

θnext=θ−ηg.\boldsymbol{\theta}_{\text{next}} =\boldsymbol{\theta}-\eta\boldsymbol{g}.

计算 g\boldsymbol{g} 所需的微积分会在课程后面出现;现在把它视为一个给定向量,直接检查它的缩放即可。

这就是标量乘法,随后进行向量加法 θ+(−ηg)\boldsymbol{\theta}+(-\eta\boldsymbol{g})。当前的 PyTorch SGD 文档在对更新方向应用任何已配置的权重衰减、动量或 Nesterov 修改后,也用这种形式表达最终的参数步骤。这个范围受限的说法很重要:启用这些选项时,学习率缩放的可能是修改后的方向,而不是未经修改的原始梯度。

对于一个小的数值步骤,设

θ=[21],g=[4−3],η=0.25.\boldsymbol{\theta}=\begin{bmatrix}2\\1\end{bmatrix},\qquad \boldsymbol{g}=\begin{bmatrix}4\\-3\end{bmatrix},\qquad \eta=0.25.

那么

ηg=0.25[4−3]=[1−0.75],−ηg=[−10.75],θnext=[21]+[−10.75]=[11.75].\begin{aligned} \eta\boldsymbol{g} &=0.25\begin{bmatrix}4\\-3\end{bmatrix} =\begin{bmatrix}1\\-0.75\end{bmatrix},\\ -\eta\boldsymbol{g} &=\begin{bmatrix}-1\\0.75\end{bmatrix},\\ \boldsymbol{\theta}_{\text{next}} &=\begin{bmatrix}2\\1\end{bmatrix} +\begin{bmatrix}-1\\0.75\end{bmatrix} =\begin{bmatrix}1\\1.75\end{bmatrix}. \end{aligned}

把 η=0.25\eta=0.25 换成 η=0.5\eta=0.5,会使这一次提出的更新大小加倍,同时保持方向不变。这个算术事实本身并不能说明更大的学习率会改善训练或保持稳定;这些问题取决于损失曲面和优化器行为,属于后续优化模块。

NumPy 乘数组;Python 列表会重复

NumPy 的 multiply 按元素相乘,* 是数组使用的运算符简写。NumPy 的广播规则允许一个标量作用于数组,而不必先构造一个由重复标量组成的完整数组。

import numpy as np

vector = np.array([4.0, -3.0, 2.0])
alpha = -1.5

scaled_with_operator = alpha * vector
scaled_with_function = np.multiply(alpha, vector)

print("vector shape:", vector.shape)
print("operator result:", scaled_with_operator)
print("function result:", scaled_with_function)
print("same values:", np.array_equal(
    scaled_with_operator, scaled_with_function
))

经过验证的输出是

vector shape: (3,)
operator result: [-6.   4.5 -3. ]
function result: [-6.   4.5 -3. ]
same values: True

普通 Python 列表中 * 的含义不同。Python 序列文档规定,乘以整数表示重复:

coordinates = [4.0, -3.0, 2.0]

print(2 * coordinates)
print(2 * np.array(coordinates))
[4.0, -3.0, 2.0, 4.0, -3.0, 2.0]
[ 8. -6.  4.]

第一个结果有六个条目,不是 2v2\boldsymbol{v}。使用数组运算前,请先把数值坐标转换为 NumPy 数组。像 0.5 * coordinates 这样的非整数运算不会缩放各条目,而是会引发 TypeError。

现在,标量已经承担两个任务:它的符号决定非零向量保持还是反转方向,而绝对值控制大小。当多个这样的缩放向量相加时,标量乘法和向量加法就构成线性组合——这正是下一课将使用的构造。

检查你的理解

问题 1

设 v = [−2, 5, 1]ᵀ,α = 3。逐坐标计算 αv,然后说明它的维度以及相对于 v 的方向。

显示分步解答

对三个坐标分别应用同一个标量:

(3v)1=3(−2)=−6,(3v)2=3(5)=15,(3v)3=3(1)=3.\begin{aligned} (3\boldsymbol{v})_1&=3(-2)=-6,\\ (3\boldsymbol{v})_2&=3(5)=15,\\ (3\boldsymbol{v})_3&=3(1)=3. \end{aligned}

因此

3v=[−6153]∈R3.3\boldsymbol{v}=\begin{bmatrix}-6\\15\\3\end{bmatrix}\in\mathbb{R}^{3}.

维度保持为三。因为 33 为正,结果与原来的非零向量方向相同;其大小是原大小的三倍。

问题 2

对于 v = [6, 8]ᵀ,计算 −0.5v,并将其欧几里得大小和方向与 v 比较。

显示分步解答

先缩放各坐标:

−0.5v=[(−0.5)(6)(−0.5)(8)]=[−3−4].-0.5\boldsymbol{v} =\begin{bmatrix}(-0.5)(6)\\(-0.5)(8)\end{bmatrix} =\begin{bmatrix}-3\\-4\end{bmatrix}.

原向量的大小为 ∥v∥2=62+82=100=10\lVert\boldsymbol{v}\rVert_2=\sqrt{6^2+8^2}=\sqrt{100}=10。结果的大小为

∥−0.5v∥2=∣−0.5∣ 10=5.\lVert-0.5\boldsymbol{v}\rVert_2 =|-0.5|\,10=5.

由于 ∣−0.5∣=0.5|-0.5|=0.5,其大小为原来的一半。由于标量为负,其方向相反。

问题 3

一名学生说,因为零不是负数,所以 0v 与 v 同方向。请诊断这一说法,并计算 v = [7, −2]ᵀ 时的 0v。

显示分步解答

逐坐标相乘得到

0v=[0(7)0(−2)]=[00]=0.0\boldsymbol{v} =\begin{bmatrix}0(7)\\0(-2)\end{bmatrix} =\begin{bmatrix}0\\0\end{bmatrix} =\boldsymbol{0}.

符号规则分成三种情况,而不是两种:正标量保持方向,负标量反转方向,零把每个坐标压缩成零向量;零向量的箭头没有长度,因而没有方向。学生的推理错误地把零当成了正标量。

问题 4

从欧几里得大小公式出发,说明对于 v = [v₁, v₂]ᵀ,为什么 ‖αv‖₂ 使用 |α| 而不是 α。

显示分步解答

把两个缩放后的坐标代入大小定义:

∥αv∥2=(αv1)2+(αv2)2=α2v12+α2v22=α2(v12+v22)=α2v12+v22=∣α∣∥v∥2.\begin{aligned} \lVert\alpha\boldsymbol{v}\rVert_2 &=\sqrt{(\alpha v_1)^2+(\alpha v_2)^2}\\ &=\sqrt{\alpha^2v_1^2+\alpha^2v_2^2}\\ &=\sqrt{\alpha^2(v_1^2+v_2^2)}\\ &=\sqrt{\alpha^2}\sqrt{v_1^2+v_2^2}\\ &=|\alpha|\lVert\boldsymbol{v}\rVert_2. \end{aligned}

对于实标量,α2=∣α∣\sqrt{\alpha^2}=|\alpha|。若写成 α\alpha 而不加绝对值,在 α<0\alpha<0 时就会错误地得到负大小。

问题 5

上下文为 c = [2, 0, −1]ᵀ,嵌入贡献为 e = [−2, 4, 2]ᵀ。取 α = 0.25,计算 c + αe,并准确说明 α 控制什么。

显示分步解答

先缩放贡献,再把它相加:

αe=0.25[−242]=[−0.510.5].\alpha\boldsymbol{e} =0.25\begin{bmatrix}-2\\4\\2\end{bmatrix} =\begin{bmatrix}-0.5\\1\\0.5\end{bmatrix}.

然后将对应坐标相加:

c+αe=[2−0.50+1−1+0.5]=[1.51−0.5].\boldsymbol{c}+\alpha\boldsymbol{e} =\begin{bmatrix}2-0.5\\0+1\\-1+0.5\end{bmatrix} =\begin{bmatrix}1.5\\1\\-0.5\end{bmatrix}.

标量 0.250.25 使这个嵌入向量的贡献保持原方向,但大小变为原来的四分之一。它控制这次相加中的算术权重;它本身不保证后续模型每一层的输出都会发生同比例变化。

问题 6

对于 θ = [3, −1]ᵀ、梯度 g = [2, 4]ᵀ 和学习率 η = 0.1,分三个明确步骤计算简单 SGD 更新 θnext = θ − ηg。

显示分步解答

第一步,缩放梯度:

ηg=0.1[24]=[0.20.4].\eta\boldsymbol{g} =0.1\begin{bmatrix}2\\4\end{bmatrix} =\begin{bmatrix}0.2\\0.4\end{bmatrix}.

第二步,为下降步骤反转这个缩放后的方向:

−ηg=[−0.2−0.4].-\eta\boldsymbol{g}=\begin{bmatrix}-0.2\\-0.4\end{bmatrix}.

第三步,将更新量加到参数上:

θnext=[3−1]+[−0.2−0.4]=[2.8−1.4].\boldsymbol{\theta}_{\text{next}} =\begin{bmatrix}3\\-1\end{bmatrix} +\begin{bmatrix}-0.2\\-0.4\end{bmatrix} =\begin{bmatrix}2.8\\-1.4\end{bmatrix}.

这个计算假设使用题目中给出的简单更新。动量、权重衰减或其他优化器规则都可能在学习率缩放的参数步骤之前修改方向。

问题 7

为什么 3 * [1, −2] 在 Python 中无法计算标量倍 [3, −6],而哪个 NumPy 表达式能执行预期运算?

显示分步解答

[1, -2] 是 Python 列表,也就是一个序列。整数 3 与序列相乘会把序列重复三次:

3 * [1, -2]
# [1, -2, 1, -2, 1, -2]

结果有六个条目,所以不可能等于两个坐标的向量 [3,−6]T[3,-6]^\mathsf{T}。创建数值 NumPy 数组后再相乘:

import numpy as np

3 * np.array([1, -2])
# array([ 3, -6])

NumPy 通过标量广播逐元素应用 3,这与数学定义一致。

问题 8

设 v = [2, −1]ᵀ。通过计算两边验证 (2 + (−0.5))v = 2v + (−0.5)v,然后说出使用的性质。

显示分步解答

左边先把标量相加:

(2+(−0.5))v=1.5[2−1]=[3−1.5].(2+(-0.5))\boldsymbol{v} =1.5\begin{bmatrix}2\\-1\end{bmatrix} =\begin{bmatrix}3\\-1.5\end{bmatrix}.

右边先缩放两次,再相加:

2v+(−0.5)v=[4−2]+[−10.5]=[3−1.5].\begin{aligned} 2\boldsymbol{v}+(-0.5)\boldsymbol{v} &=\begin{bmatrix}4\\-2\end{bmatrix} +\begin{bmatrix}-1\\0.5\end{bmatrix}\\ &=\begin{bmatrix}3\\-1.5\end{bmatrix}. \end{aligned}

两条路径都产生同一个向量。这是标量加法对于标量乘法的分配律: (α+β)v=αv+βv(\alpha+\beta)\boldsymbol{v}=\alpha\boldsymbol{v}+\beta\boldsymbol{v}。

资料来源

  1. Mathematics for Machine Learning companion website
  2. Mathematics for Machine Learning book PDF
  3. NumPy documentation: numpy.multiply
  4. NumPy documentation: broadcasting
  5. Python documentation: common sequence operations
  6. PyTorch documentation: stochastic gradient descent