跳转至

向量积

一句话总结:向量积把两个向量合成新的量——点积测方向对齐,叉积得垂直向量与面积,三重积则度量体积与共面性。

向量积是衡量相似度和计算投影的基本操作。本节涵盖内积、点积、余弦相似度、叉积和外积——这些运算驱动着人工智能 (Artificial Intelligence, AI) 中的注意力机制、嵌入以及几何推理。

  • 我们已经见过如何相加、如何缩放向量。但两个向量能不能相乘呢?事实上乘法不止一种,每一种回答的是不同的问题。

  • 内积 (inner product) 是一个总的思路:一个函数,接收两个向量,产出一个数 (标量)。它是"向量相乘"的抽象蓝图。

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

    • 正定性 (positive definiteness):\(\langle \mathbf{v}, \mathbf{v} \rangle \geq 0\),且当且仅当向量为零向量时取零。向量与自己相乘的结果永远非负。

    • 对称性 (symmetry):\(\langle \mathbf{u}, \mathbf{v} \rangle = \langle \mathbf{v}, \mathbf{u} \rangle\)。顺序不影响结果。

    • 线性性 (linearity):\(\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) 是最常见的内积。它是几乎处处都会用到的那个具体版本。对两个向量 \(\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\)。

  • 点积还给了我们投影 (projection)——一个向量投在另一个向量上的影子。\(\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) 把点积同时除以两个向量的模长,做归一化:

\[\cos(\theta) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\| \, \|\mathbf{b}\|}\]
  • 得到的是一个介于 \(-1\) 到 \(1\) 之间的值,衡量方向对齐程度,忽略向量长度。它在机器学习 (Machine Learning, ML) 中被广泛用来比较文档、嵌入、用户偏好这类东西。

  • 到现在为止,点积接收两个向量、返回一个标量。叉积 (cross product) 反其道而行之,它接收两个向量,返回一个新的向量。

  • 叉积 \(\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)\]
  • 叉积只在 3D 里能用。点积在任意维度都成立,但叉积只属于三维空间。

  • 叉积的模长等于两个向量张成的平行四边形的面积:

\[\|\mathbf{a} \times \mathbf{b}\| = \|\mathbf{a}\| \, \|\mathbf{b}\| \sin(\theta)\]
  • 注意这个规律:点积用的是 \(\cos(\theta)\),叉积用的是 \(\sin(\theta)\)。点积衡量两个向量在方向上有多对齐,叉积衡量它们在方向上有多不同。

  • 结果向量的方向遵循右手法则 (right-hand rule):用右手四指从 \(\mathbf{a}\) 卷向 \(\mathbf{b}\),大拇指指向的就是 \(\mathbf{a} \times \mathbf{b}\) 的方向。

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

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

  • 那如果把三个向量用这两种积组合起来会怎样?这就引出了三重积 (triple products)。

  • 标量三重积 (scalar triple product) \(\mathbf{a} \cdot (\mathbf{b} \times \mathbf{c})\) 先对其中两个向量做叉积,再把结果和第三个向量做点积。输出是一个数,等于三个向量张成的平行六面体 (一个歪斜的 3D 立方体) 的体积。

  • 如果标量三重积为零,三个向量就是共面 (coplanar) 的——它们全落在同一个平面上,围不出任何体积。

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

  • 向量三重积 (vector triple product) \(\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 product: {dot}")
    print(f"Angle: {jnp.degrees(angle):.1f}°")
    

  2. 计算两个 3D 向量的叉积,并通过验证结果与两个原向量的点积都为零,来确认它同时垂直于两者。

    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"Perpendicular to a: {jnp.dot(cross, a) == 0}")
    print(f"Perpendicular to b: {jnp.dot(cross, b) == 0}")
    


📌 本节要点

  • 内积:满足正定、对称、线性三条公理的通用"向量相乘"框架,输出为标量。
  • 点积:最常用的内积,代数上等于对应分量相乘再求和,几何上等于 \(\|\mathbf{a}\|\|\mathbf{b}\|\cos\theta\).
  • 投影: \(\mathbf{a}\) 在 \(\mathbf{b}\) 方向上的"影子",由点积除以 \(\|\mathbf{b}\|^2\) 再乘 \(\mathbf{b}\) 得到。
  • 余弦相似度:把点积归一化到 \([-1, 1]\),只看方向对齐、忽略长度,是嵌入比较的标配。
  • 叉积:只在 3D 定义,输出与两输入同时垂直的新向量,模长等于平行四边形面积,反交换、不结合。