Part I · 第 1 章 线性代数 · 1.7

点积

点积把两个向量变成一个数,回答一个简单的问题:这两支箭头有多同向?正数表示大致同向,零表示垂直,负数表示相反。障碍物在前还是在后,目标在不在视野里,速度有多少真正朝着目标,一个力做了多少功,甚至一句话和一张图像配不配,用的都是这一个运算。

约 25 分钟 前置:1.1 向量 · 1.3 矩阵即变换 6 个交互

    1为什么机器人需要它

    机器人每时每刻都在回答一类很小的问题:

    • 前方检测到一个障碍物,它在我的前面还是后面?
    • 那个人在不在我的相机视野里?
    • 我现在的速度,有多少是真正朝着目标的?
    • 机械臂推着一个箱子,我的力里有多少在做功,有多少只是白白顶着墙?
    • 这句指令和这张图像不像?(CLIP 这类模型正是这样把语言和图像配对的,见 Part V。)

    这些问题看上去毫不相干,答案却都来自同一个运算:点积 (dot product)。它还有一个隐藏身份:1.3 节里矩阵乘向量的"行视角",每一个分量就是一次点积。这一节把它的两种写法、两种读法,以及机器人最常用的几个场景,一次讲清楚。

    2直觉:两支箭头有多"一致"

    取两支箭头 \(\mathbf a\) 和 \(\mathbf b\),夹角为 \(\theta\)。把 \(\mathbf b\) 垂直地"投"到 \(\mathbf a\) 所在的直线上,得到一段影子,它的带符号长度是 \(|\mathbf b|\cos\theta\)。再乘上 \(\mathbf a\) 自己的长度,就是点积:

    $$ \cv{\mathbf a}\cdot\cw{\mathbf b} \;=\; |\mathbf a|\,\big(|\mathbf b|\cos\theta\big) \;=\; |\mathbf a|\times(\text{shadow of }\mathbf b\text{ on }\mathbf a). $$

    影子和 \(\mathbf a\) 同向,结果为正;影子反向,结果为负;\(\mathbf b\) 垂直于 \(\mathbf a\) 时,影子缩成一个点,结果为 0。

    最具体的例子是推车。小车只能沿导轨走,你推它的力 \(\mathbf F\) 却常常是斜的。真正推动小车的只有沿导轨的那一份,垂直于导轨的那一份只是顶着导轨。物理里"力做的功"正是 \(W = \mathbf F\cdot\mathbf s\),\(\mathbf s\) 是小车的位移。拖动力的箭头,看看什么时候做正功、零功、负功。

    FIG 1沿导轨推车:功就是点积
    拖动琥珀色力 F 的箭头尖。粗线是力沿导轨的影子(绿:推着走,红:在刹车),虚线是被导轨"吃掉"的垂直部分。图中格子既当 1 N 又当 1 m,只是为了把方向画在一起;小车位移固定为 2 m。
    • 用一个不小的力(\(|\mathbf F| \ge 2\) N)推车,但让它做的功几乎为 0。力应该朝哪?
    • 让这个力做负功(\(W < -2\) J),也就是在给小车刹车。
    核心洞见

    点积 = 一个向量中沿另一个向量方向的那一部分,乘上另一个向量的长度。符号告诉你方向关系:正(夹角小于 90°)、零(垂直)、负(夹角大于 90°)。它不关心垂直于那个方向的部分。

    3动手玩:点积实验室

    拖动琥珀色 a 和紫色 b 的箭头尖。紫色虚线从 b 的尖端垂直落到 a 所在的直线上,落点与原点之间的粗线就是 b 的影子:为正时绿色,为负时红色。淡绿、淡红的底色标出 b 落在哪一侧时点积为正、为负。右边用两个公式各算一遍同一个数,看看它们是否永远一致。

    FIG 2点积实验室
    底色:绿 = b·a > 0,红 = b·a < 0
    把 b 放到
    琥珀色箭头 a 和紫色箭头 b 都可以拖动(位置吸附到 0.1)。"等值线"按钮会画出一条穿过 b 尖端的虚线:这条线上所有点与 a 的点积都相同。
    试一试
    • 让 \(\mathbf a\cdot\mathbf b = 0\),而且两个向量都不是零向量。此时影子是什么样?
    • 两个向量的长度不变,让点积尽可能小(最负)。这时夹角是多少?
    • 让 \(\mathbf a\cdot\mathbf b = |\mathbf a|^2\),但 \(\mathbf b \ne \mathbf a\)。提示:影子要和 \(\mathbf a\) 一样长。
    • 打开"等值线",保持 a 不动,把 b 沿那条线拖出至少 1.5 的距离:点积一动不动。为什么?
    想一想:为什么沿等值线拖动,点积不变?

    点积只看 b 在 a 方向上的分量(影子)。沿着垂直于 a 的方向移动 b,影子的长度完全不变,所以点积也不变。于是 \(\{\mathbf x : \mathbf a\cdot\mathbf x = c\}\) 是一条垂直于 \(\mathbf a\) 的直线(三维里是垂直于 \(\mathbf a\) 的平面)。"平面方程 \(\mathbf n\cdot\mathbf x = d\)"就是这个事实:\(\mathbf n\) 是法向量。另外两个极端也值得记住:垂直时点积为 0;反向(\(\theta = 180°\))时点积取到最小值 \(-|\mathbf a||\mathbf b|\)。

    4第二个视角:两个公式为什么是同一个数

    实验室右边有两个公式。代数公式 \(a_1b_1 + a_2b_2\) 要用到坐标,换一套坐标轴,每个分量都变了。几何公式 \(|\mathbf a||\mathbf b|\cos\theta\) 只用到长度和夹角,而把整幅图转个角度,长度和夹角都不会变。两者要想永远相等,分量的乘积就必须"此消彼长",使总和保持不变。

    下面把 \(\mathbf a\) 和 \(\mathbf b\) 当作一个刚性的整体一起转动,用三根柱子看这件事。

    FIG 3一起转动:分量在变,点积不变
    左图:虚线是各向量在坐标轴上的分量(红:x,绿:y)。拖动 a 的箭头尖,或用滑块转动整对向量。右图:红柱是 \(a_1b_1\),绿柱是 \(a_2b_2\),青柱是它们的和。红柱和绿柱此起彼伏,青柱纹丝不动。
    • 找一个角度,让红柱 \(a_1b_1\) 变成负数,而青柱依然是同一个正数。
    • 转到 a 正好躺在 x 轴上(\(a_2 \approx 0\))。这时绿柱消失,点积就只剩 \(a_1b_1\)。
    核心洞见

    点积是一个不依赖坐标轴朝向的量:它只由两个长度和一个夹角决定。这正是它在机器人里如此好用的原因:不管你用世界坐标系、机器人坐标系还是相机坐标系,只要两个向量在同一个坐标系里写出来,点积都是同一个数(1.10 节会把这一点升级成"正交矩阵保持点积")。

    5第三个视角:矩阵乘向量的行视角

    1.3 节按列读矩阵乘向量:\(A\mathbf v\) 是 \(A\) 各列的线性组合。同一个乘积还有第二种读法,也是代码里真正在算的那一种:\(A\mathbf v\) 的第 \(i\) 个分量,是 \(A\) 的第 \(i\) 行与 \(\mathbf v\) 的点积。

    可以把每一行想成一个"探测器",它有自己的朝向 \(\mathbf r_i\),读出的是 \(\mathbf v\) 在自己方向上有多少。下面左图画出两行 \(\mathbf r_1, \mathbf r_2\) 和 \(\mathbf v\),右图用列视角拼出同一个 \(A\mathbf v\)。两边的结果必须一样。

    FIG 4行视角 与 列视角
    行视角:每个分量是一次点积
    列视角:列的线性组合(缩小显示)
    左图:拖动 r₁、r₂ 的箭头尖(即改矩阵的两行)和琥珀色 v。每一行画出 v 落在它所在直线上的影子,影子长度乘以该行的长度就是点积。右图的虚线从 Av 的尖端垂到坐标轴:落点的坐标恰好就是 \(\mathbf r_1\cdot\mathbf v\) 和 \(\mathbf r_2\cdot\mathbf v\)。
    • 让第一行与 \(\mathbf v\) 垂直。右图里 \(A\mathbf v\) 的 x 分量会变成 0,箭头落到 y 轴上。
    • 让 \(A\mathbf v = \mathbf 0\),而 \(\mathbf v \ne \mathbf 0\),两行也都不是零向量。两行之间必须是什么关系?
    另一种读法

    第二个任务的答案:\(\mathbf v\) 同时垂直于两行,所以两行只能互相平行(在平面里垂直于 \(\mathbf v\) 的方向只有一条线)。这样的 \(\mathbf v\) 被矩阵压成 \(\mathbf 0\),所有这样的 \(\mathbf v\) 组成零空间 (null space),1.6 节会专门讲。行视角还有一个后果:矩阵 \(A^\top A\) 的第 \((i,j)\) 项,是 \(A\) 的第 \(i\) 列与第 \(j\) 列的点积,1.12 和 1.13 节里会反复出现。

    6再看数学

    提示:把鼠标悬停在公式中带底色的符号上,FIG 2 中对应的元素会被高亮。

    定义

    两个同维度的向量 \(\mathbf a, \mathbf b\in\R^n\),点积是对应分量乘积之和,也可以写成行向量乘列向量:

    $$ \mathbf a\cdot\mathbf b \;=\; \mathbf a^{\T}\mathbf b \;=\; \sum_{i=1}^{n} a_i b_i \;=\; a_1b_1 + a_2b_2 + \dots + a_nb_n. $$

    例如 \((1,2,3)\cdot(4,-5,6) = 4 - 10 + 18 = 12\)。结果是一个标量,不是向量。

    性质

    • 对称:\(\mathbf a\cdot\mathbf b = \mathbf b\cdot\mathbf a\)。
    • 线性(对每个位置分别线性):\(\mathbf a\cdot(\mathbf b + \mathbf c) = \mathbf a\cdot\mathbf b + \mathbf a\cdot\mathbf c\),\((s\mathbf a)\cdot\mathbf b = s\,(\mathbf a\cdot\mathbf b)\)。
    • 与长度的关系:\(\mathbf a\cdot\mathbf a = |\mathbf a|^2\),所以 \(|\mathbf a| = \sqrt{\mathbf a\cdot\mathbf a}\)。

    几何形式从哪里来

    把差向量 \(\mathbf a-\mathbf b\) 当作三角形的第三条边。几何上,余弦定理说:

    $$ |\mathbf a-\mathbf b|^2 \;=\; |\mathbf a|^2 + |\mathbf b|^2 - 2\,|\mathbf a||\mathbf b|\cos\theta. $$

    代数上,用上面的对称性与线性把同一个量展开:

    $$ |\mathbf a-\mathbf b|^2 = (\mathbf a-\mathbf b)\cdot(\mathbf a-\mathbf b) = |\mathbf a|^2 - 2\,\mathbf a\cdot\mathbf b + |\mathbf b|^2. $$

    两式相比,\(|\mathbf a|^2 + |\mathbf b|^2\) 消掉,剩下:

    $$ \hl{a}{\cv{\mathbf a}}\cdot\hl{b}{\cw{\mathbf b}} \;=\; \hl{la}{|\mathbf a|}\,\hl{lb}{|\mathbf b|}\,\cos\hl{theta}{\theta} \;=\; \hl{la}{|\mathbf a|}\;\hl{shadow}{\big(|\mathbf b|\cos\theta\big)}. $$

    这就是 FIG 3 里"代数 = 几何"的证明。用到了余弦定理,所以它在任意维度都成立:任意两个向量总落在同一个平面里,夹角 \(\theta\) 就是那个平面里的夹角。

    夹角、正交与影子长度

    $$ \theta = \arccos\!\left(\operatorname{clamp}\!\Big(\frac{\mathbf a\cdot\mathbf b}{|\mathbf a||\mathbf b|},\,-1,\,1\Big)\right), \qquad \mathbf a\perp\mathbf b \iff \mathbf a\cdot\mathbf b = 0, \qquad \text{shadow of }\mathbf b\text{ on unit }\mathbf u:\;\; \mathbf u\cdot\mathbf b. $$

    "clamp"把括号里的数夹在 \([-1, 1]\) 之内(原因见"常见误区")。例:\(\mathbf a = (3,1)\),\(\mathbf b = (1,2)\),则 \(\mathbf a\cdot\mathbf b = 5\),\(|\mathbf a||\mathbf b| = \sqrt{10}\sqrt{5} = \sqrt{50}\),\(\cos\theta = 5/\sqrt{50} = \tfrac{\sqrt2}{2}\),\(\theta = 45°\)。

    当 \(\mathbf u\) 是单位向量时,\(\mathbf u\cdot\mathbf b\) 就是 \(\mathbf b\) 在 \(\mathbf u\) 方向上的带符号长度。把这个长度再乘回 \(\mathbf u\),得到完整的"投影向量" \((\mathbf u\cdot\mathbf b)\,\mathbf u\),那是 1.9 节的主题。

    Cauchy–Schwarz 与余弦相似度

    因为 \(|\cos\theta|\le 1\),立刻得到

    $$ |\mathbf a\cdot\mathbf b| \le |\mathbf a||\mathbf b|, \qquad \text{equality} \iff \mathbf a,\mathbf b \text{ are parallel}; \qquad \mathrm{sim}_{\cos}(\mathbf a,\mathbf b) = \frac{\mathbf a\cdot\mathbf b}{|\mathbf a||\mathbf b|} = \hat{\mathbf a}\cdot\hat{\mathbf b}\in[-1,1]. $$

    第一个不等式叫 Cauchy–Schwarz 不等式。它回答了"固定长度时点积最大能到多少":当两者同向时取到 \(|\mathbf a||\mathbf b|\)。第二个量是余弦相似度,先把两个向量都除以自己的长度,再做点积:它只比较方向,不受长度影响,是机器学习里比较 embedding 的标准做法。

    矩阵写法与旋转不变性

    \(\mathbf a^\top\mathbf b\) 是 \(1\times n\) 乘 \(n\times 1\),得到 \(1\times 1\),也就是一个数;反过来 \(\mathbf a\mathbf b^\top\) 是 \(n\times n\) 的矩阵(外积,1.12 节的"一层")。行视角则写成 \((A\mathbf v)_i = \mathbf r_i^\top\mathbf v\)。若 \(R\) 是旋转矩阵,满足 \(R^\top R = I\)(1.10 节),那么 FIG 3 的观察就是一个等式:

    $$ (R\mathbf a)\cdot(R\mathbf b) = \mathbf a^\top R^\top R\,\mathbf b = \mathbf a^\top\mathbf b = \mathbf a\cdot\mathbf b. $$

    7机器人中的它:视野判断与朝向目标的速度

    视野判断:目标在不在视野里?

    机器人的朝向是单位向量 \(\hat{\mathbf h}\),相机的视野半角是 \(\alpha\)。物体相对机器人的位移是 \(\mathbf d = \mathbf p_{\text{obj}} - \mathbf p_{\text{robot}}\)。物体可见,当且仅当 \(\mathbf d\) 与 \(\hat{\mathbf h}\) 的夹角 \(\varphi\le\alpha\)。因为 \(\cos\) 在 \([0,\pi]\) 上递减,这等价于

    $$ \varphi \le \alpha \iff \cos\varphi \ge \cos\alpha \iff \hat{\mathbf h}\cdot\mathbf d \;\ge\; |\mathbf d|\cos\alpha. $$

    右边的 \(\cos\alpha\) 只算一次,每个物体只需要一次点积和一次开方,不需要 \(\operatorname{atan2}\) 或 \(\arccos\)。拖动机器人的朝向(红色箭头尖),再调节视野半角,看看右侧表格里每个物体的"点积 ≥ 阈值"是怎么变的。

    FIG 5视野判断小游戏
    绿色:通过测试(在视野内),红色:没通过。每个物体旁边的数是 \(\hat{\mathbf h}\cdot\mathbf d\)。垂直于朝向的虚线是 \(\hat{\mathbf h}\cdot\mathbf d = 0\):把 \(\alpha\) 调到 90°,视野恰好变成"这条线的前方",测试退化成只看点积的符号。
    • 把视野半角调到 30° 或更小(窄镜头),转动机器人,让至少 3 个物体同时在视野里。
    • 让某个物体恰好卡在视野边缘(夹角与 \(\alpha\) 相差不到 1.5°,它的圆环会变成琥珀色)。这时不等式两边几乎相等。

    朝向目标的速度:贪心控制器的核心

    机器人在原点,目标在 \(\mathbf G\),指向目标的单位向量是 \(\hat{\mathbf g} = \mathbf G/|\mathbf G|\)。速度 \(\mathbf v\) 中朝向目标的那一份,就是逼近速度 \(s = \mathbf v\cdot\hat{\mathbf g}\):每秒大约离目标近多少米。假设速度大小不能超过 \(v_{\max}\),什么方向最好?Cauchy–Schwarz 给出答案:\(s\le|\mathbf v||\hat{\mathbf g}|\le v_{\max}\),当且仅当 \(\mathbf v = v_{\max}\hat{\mathbf g}\) 时取等号。

    很多局部规划器的做法与此一脉相承:生成一批候选速度(图中速度圆上的小点),给每个候选打分,选分数最高的。点积 \(\mathbf v\cdot\hat{\mathbf g}\) 就是最基本的"朝向目标"得分。

    FIG 6逼近速度 \(s = \mathbf v\cdot\hat{\mathbf g}\)
    自动设置速度
    拖动琥珀色速度 v(被限制在速度圆内)或紫色目标 G。速度圆上的小点是候选速度:绿色得分为正,红色为负,点越大得分越极端,圆环标出最优的方向 \(\hat{\mathbf g}\)(它不一定恰好落在某个候选点上)。
    • 让逼近速度达到上限的 97% 以上(\(s \ge 1.94\) m/s)。v 应该指向哪里?
    • 保持几乎全速(\(|\mathbf v| \ge 1.7\)),但让逼近速度几乎为 0(\(|s| < 0.08\))。机器人这时在做什么?

    第二个任务的答案:\(\mathbf v\perp\hat{\mathbf g}\),机器人绕着目标转圈,既不靠近也不远离,一直在白费力气。

    真实系统里

    功率。力与速度的点积 \(P = \mathbf F\cdot\mathbf v\) 是瞬时功率;对关节,\(P = \boldsymbol\tau\cdot\dot{\mathbf q}\),即关节力矩向量与关节速度向量的点积。\(P>0\) 说明电机在向机械臂输出能量,\(P<0\) 说明外力在拖着电机转,能量流回驱动器(再生制动)。能耗估计、电机发热和功率限制都从这个点积出发。

    余弦相似度。CLIP 这样的模型把图像和文字都映射成同一空间中的向量(embedding),归一化后,匹配分数就是点积,也就是余弦相似度。机器人用它判断"拿起红色的杯子"这句话和相机画面里哪个区域最匹配。对比学习的细节见 Part V。

    8常见误区

    误区 1:不归一化,直接拿点积当作"角度有多近"

    点积同时包含长度和夹角。取 \(\mathbf a = (1,0)\),\(\mathbf b = (3,3)\),\(\mathbf c = (1, 0.1)\):\(\mathbf a\cdot\mathbf b = 3\),\(\mathbf a\cdot\mathbf c = 1\),\(\mathbf b\) "得分更高"。但 \(\mathbf b\) 与 \(\mathbf a\) 相差 45°,\(\mathbf c\) 只差约 5.7°。要比较方向,必须先除以长度,用余弦相似度(\(\cos 45° \approx 0.71\),而 \(\cos 5.7° \approx 0.995\))。

    误区 2:对略大于 1 的数做 acos,得到 NaN

    数学上 \(\cos\theta\in[-1,1]\),但浮点误差可能让归一化后的点积变成 \(1.0000000000000002\)。例如 NumPy 里 a = np.array([0.4, 0.06, 0.3]),计算 a @ a / (np.linalg.norm(a) * np.linalg.norm(a)),结果就是这个数,np.arccos 对它返回 nan。机器人代码里一个 NaN 会顺着控制链一路传下去。永远写成 np.arccos(np.clip(c, -1.0, 1.0))。

    误区 3:对任何坐标都按"分量乘积之和"算点积

    \(\sum a_ib_i\) 只有在标准正交基(轴互相垂直、长度为 1)里写出的坐标上,才等于几何点积。反例:取斜的基 \(\mathbf f_1 = (1,0)\),\(\mathbf f_2 = (1,1)\)。坐标 \((1,1)\) 与 \((1,-1)\) 的"分量乘积和"是 \(1 - 1 = 0\),好像垂直;但真实向量是 \(\mathbf a = \mathbf f_1 + \mathbf f_2 = (2,1)\),\(\mathbf b = \mathbf f_1 - \mathbf f_2 = (0,-1)\),真正的点积是 \(-1 \ne 0\)。同理,不同单位的量不能放在一起点乘:位姿 \((x, y, \theta)\) 里米和弧度混在一起,它的"点积"没有几何意义。

    误区 4:点积 > 0 就等于"在我的视野里"

    \(\hat{\mathbf h}\cdot\mathbf d>0\) 只说明夹角小于 90°,也就是"在我前方的半个平面里"。真实相机的视野半角通常只有 30° 到 60°,必须和阈值比较:\(\hat{\mathbf h}\cdot\mathbf d\ge|\mathbf d|\cos\alpha\)。把 \(\alpha\) 当成 90° 写代码,会把相机侧面的物体也当成"看得见"。反过来,若 \(\mathbf h\) 没有归一化,阈值那一侧也要乘上 \(|\mathbf h|\)。

    9小练习

    1. 向量 \(\mathbf a = (3,1)\) 和 \(\mathbf b = (1,2)\) 之间的夹角是多少?
    \(\mathbf a\cdot\mathbf b = 3\cdot1 + 1\cdot2 = 5\),\(|\mathbf a||\mathbf b| = \sqrt{10}\sqrt{5} = \sqrt{50}\approx 7.07\),\(\cos\theta = 5/7.07 \approx 0.707\),所以 \(\theta = 45°\)。
    2. 小车沿 x 轴方向位移 \(\mathbf s = (2, 0)\) m,你施加的力是 \(\mathbf F = (-3, 4)\) N。力做的功是多少,它对小车的效果是什么?
    \(W = \mathbf F\cdot\mathbf s = (-3)(2) + (4)(0) = -6\) J。力的 y 分量 4 N 垂直于位移,完全不做功;x 分量 \(-3\) N 与运动方向相反,所以在刹车。
    3. 机器人朝向 \(\hat{\mathbf h} = (1,0)\),视野半角 \(\alpha = 30°\)。物体相对机器人的位移是 \(\mathbf d = (2, 1.5)\)。它在视野里吗?
    \(|\mathbf d| = \sqrt{4 + 2.25} = 2.5\),阈值是 \(2.5\cos 30° \approx 2.165\),而 \(\hat{\mathbf h}\cdot\mathbf d = 2\),不够。直接验证:物体方向与朝向的夹角是 \(\arctan(1.5/2) \approx 36.9° > 30°\)。点积为正只说明在 90° 以内;选项 C 忘了乘 \(|\mathbf d|\)。
    4. 设 \(A = \begin{bmatrix}1&2\\3&-1\end{bmatrix}\),\(\mathbf v = (2,1)\)。用行视角算 \(A\mathbf v\),结果是?
    第 1 行 \((1,2)\cdot(2,1) = 2 + 2 = 4\);第 2 行 \((3,-1)\cdot(2,1) = 6 - 1 = 5\)。所以 \(A\mathbf v = (4,5)\)。用列视角验算:\(2\,(1,3) + 1\,(2,-1) = (4,5)\)。\((5,3)\) 是 \(A^\top\mathbf v\),即把行和列弄反了。
    5. 图像 embedding 为 \(\mathbf u = (1,0)\)。候选文字 embedding 有 \(\mathbf t_1 = (3,3)\) 和 \(\mathbf t_2 = (1,0.1)\)。按余弦相似度,哪个更匹配?
    \(\cos(\mathbf u,\mathbf t_1) = 3/(1\cdot 4.243) = 0.707\),\(\cos(\mathbf u,\mathbf t_2) = 1/(1\cdot 1.005) \approx 0.995\)。原始点积被 \(\mathbf t_1\) 的长度抬高了。余弦相似度先归一化,只比较方向,所以 \(\mathbf t_2\) 更匹配。

    10延伸阅读

    • 3Blue1Brown, Essence of Linear Algebra — 第 9 章(点积与对偶性)
    • G. Strang, Introduction to Linear Algebra, Ch. 1.2 — 长度与点积
    • J. Ström et al., Immersive Linear Algebra, Ch. 3 — 点积(带交互插图)
    • A. Radford et al., Learning Transferable Visual Models From Natural Language Supervision (CLIP), ICML 2021 — 余弦相似度在图文匹配中的应用