Skip to content

Vector Products(向量积)

Vector products 是衡量相似性和计算投影的基础运算。本节涵盖 inner product、dot product、cosine similarity、cross product 和 outer product——这些运算驱动着 AI 中的 attention 机制、embedding 和几何推理。

  • 我们已经学会了如何对 vector 进行加法和缩放。但能不能把两个 vector 相乘呢?事实证明,有不止一种乘法,每一种回答的是不同的问题。

  • Inner product 是一个通用概念:它是一个函数,接受两个 vector 并产生一个数(scalar)。它是"乘法 vector"的抽象蓝图。

  • 任何 inner product 都必须满足三条规则:

    • 正定性\(\langle \mathbf{v}, \mathbf{v} \rangle \geq 0\),且只有零 vector 时等于零。一个 vector 与自身的乘积始终非负。

    • 对称性\(\langle \mathbf{u}, \mathbf{v} \rangle = \langle \mathbf{v}, \mathbf{u} \rangle\)。顺序无关紧要。

    • 线性性\(\langle a\mathbf{u} + b\mathbf{v}, \mathbf{w} \rangle = a\langle \mathbf{u}, \mathbf{w} \rangle + b\langle \mathbf{v}, \mathbf{w} \rangle\)。它对加法和缩放均满足分配律。

  • Dot product 是最常见的 inner product,是你几乎在所有地方都会用到的具体形式。对于两个 vector \(\mathbf{a} = (a_1, a_2, \ldots, a_n)\)\(\mathbf{b} = (b_1, b_2, \ldots, b_n)\)

\[\mathbf{a} \cdot \mathbf{b} = a_1 b_1 + a_2 b_2 + \cdots + a_n b_n\]
  • 将对应分量相乘,然后全部加起来。就这么简单。

  • 但这个数字的意义是什么?Dot product 有一个优美的几何解释:

\[\mathbf{a} \cdot \mathbf{b} = \|\mathbf{a}\| \, \|\mathbf{b}\| \cos(\theta)\]

Dot product:vector a 在 b 上的投影,显示角度 θ 和投影长度

  • 这将 dot product 直接与两个 vector 之间的角度 \(\theta\) 联系起来。结果告诉你两个 vector 在方向上的"一致程度"。

  • 若它们同向(\(\theta = 0°\)),\(\cos(\theta) = 1\),dot product 取最大值。

  • 若它们正交(\(\theta = 90°\)),\(\cos(\theta) = 0\),dot product 恰好为零。这给了我们一个精确的正交性判断方法。

  • 若它们反向(\(\theta = 180°\)),\(\cos(\theta) = -1\),dot product 为负。

  • 一个 vector 与自身的 dot product 等于其 magnitude 的平方:\(\mathbf{a} \cdot \mathbf{a} = \|\mathbf{a}\|^2\)

  • Dot product 还给我们带来了投影——一个 vector 在另一个 vector 上投下的"影子"。\(\mathbf{a}\)\(\mathbf{b}\) 上的投影为:

\[\text{proj}_{\mathbf{b}}(\mathbf{a}) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{b}\|^2} \, \mathbf{b}\]
  • 想象垂直向下照射在 \(\mathbf{b}\) 上的光。\(\mathbf{a}\) 在那条线上的影子就是投影。它告诉你 \(\mathbf{a}\) 中有多少部分沿 \(\mathbf{b}\) 方向。

  • Cosine similarity 通过除以两个 vector 的 magnitude 来对 dot product 进行归一化:

\[\cos(\theta) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\| \, \|\mathbf{b}\|}\]
  • 这给出一个介于 \(-1\)\(1\) 之间的值,衡量方向的一致程度,而忽略 vector 的长度。它在 ML 中被广泛用于比较文档、embedding 和用户偏好等。

  • Dot product 接受两个 vector 并返回一个 scalar。Cross product 则相反——它接受两个 vector 并返回一个新 vector

  • Cross product \(\mathbf{a} \times \mathbf{b}\) 产生一个同时垂直于 \(\mathbf{a}\)\(\mathbf{b}\) 的 vector:

\[\mathbf{a} \times \mathbf{b} = (a_2 b_3 - a_3 b_2, \; a_3 b_1 - a_1 b_3, \; a_1 b_2 - a_2 b_1)\]
  • Cross product 只适用于三维空间。Dot product 适用于任意维数,而 cross product 仅限于三维。

  • 其 magnitude 等于两个 vector 围成的平行四边形的面积:

\[\|\mathbf{a} \times \mathbf{b}\| = \|\mathbf{a}\| \, \|\mathbf{b}\| \sin(\theta)\]
  • 注意规律:dot product 使用 \(\cos(\theta)\),cross product 使用 \(\sin(\theta)\)。Dot product 衡量两个 vector 的对齐程度,cross product 衡量它们在方向上的差异程度

  • 结果的方向遵循右手定则:将右手手指从 \(\mathbf{a}\) 卷向 \(\mathbf{b}\),拇指所指的方向就是 \(\mathbf{a} \times \mathbf{b}\) 的方向。

  • 与 dot product 不同,cross product 不满足交换律\(\mathbf{a} \times \mathbf{b} = -(\mathbf{b} \times \mathbf{a})\)。交换顺序会翻转方向。

  • 如果两个 vector 平行,它们的 cross product 为零 vector(因为 \(\sin(0°) = 0\))。没有面积,也没有垂直方向。

  • 将三个 vector 同时使用两种乘法组合时,就得到了三重积

  • 标量三重积 \(\mathbf{a} \cdot (\mathbf{b} \times \mathbf{c})\) 先对两个 vector 求 cross product,然后将结果与第三个 vector 做 dot product。输出是一个数,等于三个 vector 所围成的平行六面体(一种倾斜的三维盒子)的体积。

  • 如果标量三重积为零,则三个 vector 共面——它们都位于同一个平面上,不围成任何体积。

  • 循环交换顺序不改变结果:\(\mathbf{a} \cdot (\mathbf{b} \times \mathbf{c}) = \mathbf{b} \cdot (\mathbf{c} \times \mathbf{a}) = \mathbf{c} \cdot (\mathbf{a} \times \mathbf{b})\)

  • 向量三重积 \(\mathbf{a} \times (\mathbf{b} \times \mathbf{c})\) 对 cross product 连续应用两次并返回一个 vector。它通过以下恒等式整洁地展开:

\[\mathbf{a} \times (\mathbf{b} \times \mathbf{c}) = (\mathbf{a} \cdot \mathbf{c})\mathbf{b} - (\mathbf{a} \cdot \mathbf{b})\mathbf{c}\]
  • 结果始终位于 \(\mathbf{b}\)\(\mathbf{c}\) 所张成的平面中。注意 cross product 不满足结合律\(\mathbf{a} \times (\mathbf{b} \times \mathbf{c}) \neq (\mathbf{a} \times \mathbf{b}) \times \mathbf{c}\)

编程练习(使用 CoLab 或 notebook)

  1. 计算两个 vector 的 dot product,用它求它们之间的角度。尝试让它们正交、平行或反向,观察角度如何变化。

    import jax.numpy as jnp
    
    a = jnp.array([1.0, 2.0, 3.0])
    b = jnp.array([4.0, -1.0, 2.0])
    
    dot = jnp.dot(a, b)
    angle = jnp.arccos(dot / (jnp.linalg.norm(a) * jnp.linalg.norm(b)))
    
    print(f"Dot product: {dot}")
    print(f"角度: {jnp.degrees(angle):.1f}°")
    

  2. 计算两个三维 vector 的 cross product,通过验证结果与每个原始 vector 的 dot product 为零来确认其垂直性。

    import jax.numpy as jnp
    
    a = jnp.array([1.0, 0.0, 0.0])
    b = jnp.array([0.0, 1.0, 0.0])
    
    cross = jnp.cross(a, b)
    
    print(f"a x b = {cross}")
    print(f"与 a 垂直: {jnp.dot(cross, a) == 0}")
    print(f"与 b 垂直: {jnp.dot(cross, b) == 0}")