Skip to content

向量乘积

向量乘积是衡量相似度和计算投影的基本运算。本章涵盖内积、点积、余弦相似度、叉积和外积,这些运算为人工智能中的注意力机制、嵌入表示和几何推理提供动力。

  • 我们已经知道如何对向量进行加法和缩放。但能否将两个向量相乘?事实上,存在不止一种乘法方式,每种方式回答不同的问题。

  • 内积是它的抽象概念:一个接受两个向量并返回一个标量(单个数字)的函数。这是“向量相乘”的抽象蓝图。

  • 任何内积必须满足三条规则:

    • 正定性\(\langle \mathbf{v}, \mathbf{v} \rangle \geq 0\),且仅当 \(\mathbf{v} = \mathbf{0}\) 时等于零。一个向量与其自身相乘总是得到非负结果。

    • 对称性\(\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\)。它对加法和缩放满足分配律。

  • 点积是最常见的内积。它是你几乎到处都会用到的具体版本。对于两个向量 \(\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\]
  • 将对应分量相乘,然后全部相加。仅此而已。

  • 但这个数字意味着什么?点积有一个优美的几何解释:

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

点积:向量 a 投影到 b 上,显示夹角 θ 和投影

  • 这直接将点积与两个向量之间的夹角 \(\theta\) 联系起来。结果告诉你两个向量在方向上“一致”的程度。

  • 如果它们指向相同方向(\(\theta = 0°\)),则 \(\cos(\theta) = 1\),点积达到最大。

  • 如果它们正交(\(\theta = 90°\)),则 \(\cos(\theta) = 0\),点积恰好为零。这为我们提供了正交性的精确测试。

  • 如果它们指向相反方向(\(\theta = 180°\)),则 \(\cos(\theta) = -1\),点积为负。

  • 向量与自身的点积给出其大小的平方:\(\mathbf{a} \cdot \mathbf{a} = \|\mathbf{a}\|^2\)

  • 点积还给出了投影,即一个向量在另一个向量上投射的影子。\(\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}\) 方向上有多少分量。

  • 余弦相似度通过将两个向量的长度都除掉来归一化点积:

\[\cos(\theta) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\| \, \|\mathbf{b}\|}\]
  • 这给出了介于 \(-1\)\(1\) 之间的值,衡量方向的对齐程度,而忽略向量的长度。它在机器学习中被广泛用于比较文档、嵌入表示和用户偏好等。

  • 现在,点积接受两个向量返回一个标量。叉积则相反,它接受两个向量并返回一个新向量

  • 叉积 \(\mathbf{a} \times \mathbf{b}\) 产生一个垂直于 \(\mathbf{a}\)\(\mathbf{b}\) 的向量:

\[\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)\]
  • 叉积只在三维空间中有效。点积可以在任意维度下工作,但叉积仅限于三维空间。

  • 它的大小等于两个向量张成的平行四边形的面积:

\[\|\mathbf{a} \times \mathbf{b}\| = \|\mathbf{a}\| \, \|\mathbf{b}\| \sin(\theta)\]
  • 注意这个模式:点积使用 \(\cos(\theta)\),叉积使用 \(\sin(\theta)\)。点积衡量两个向量对齐的程度,叉积衡量它们方向差异的大小。

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

  • 与点积不同,叉积不可交换\(\mathbf{a} \times \mathbf{b} = -(\mathbf{b} \times \mathbf{a})\)。交换顺序会翻转方向。

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

  • 当你将三种向量用两种乘积组合起来会发生什么?这就得到了三重积

  • 标量三重积 \(\mathbf{a} \cdot (\mathbf{b} \times \mathbf{c})\) 先计算两个向量的叉积,然后将结果与第三个向量点积。输出是一个标量,等于三个向量张成的平行六面体(一个倾斜的三维盒子)的体积。

  • 如果标量三重积为零,则三个向量共面,它们都位于同一个平面内,不形成体积。

  • 循环改变顺序不改变结果:\(\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})\) 应用两次叉积,返回一个向量。它可以用恒等式简洁展开:

\[\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}\) 张成的平面内。注意叉积不满足结合律\(\mathbf{a} \times (\mathbf{b} \times \mathbf{c}) \neq (\mathbf{a} \times \mathbf{b}) \times \mathbf{c}\)

编程任务(使用 CoLab 或 notebook)

  1. 计算两个向量的点积,并用它求它们之间的夹角。尝试让它们正交、平行或相反,观察夹角如何变化。

    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}")
    print(f"夹角: {jnp.degrees(angle):.1f}°")
    

  2. 计算两个三维向量的叉积,并通过检查叉积与每个原始向量的点积是否为零来验证结果垂直于二者。

    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}")