一、先问一个最基本的矛盾
第 1 讲把语言模型定成一个函数:P(xₜ₊₁ | x₁...xₜ)。第 2 讲讲了这个函数的第一版实现(RNN)怎么滚动维护一个"隐藏状态" hₜ。
但从头到尾我们跳过了一件事:计算机的 CPU、GPU 只会做加减乘除,不认识"字"这种东西。“苹果"这两个字,对芯片来说不是一个有意义的符号,它甚至不是一个数字。要让第 1、2 讲的公式真正跑起来,第一步必须是:把文字变成数字。
这不是"随便编个数字"就行——如果把"国王"“苹果"“你好"分别编号成 1、2、3,这三个数字之间的大小关系(1 < 2 < 3)是没有任何意义的,“国王"并不比"苹果"小。我们需要的是一种编码方式,使得**“意思相近的词,编码也相近”**。
这一讲要讲清楚的,就是这句话在数学上到底是什么意思,以及它靠什么工具实现。
二、打个比方:用坐标描述一座城市
一座城市的"位置”,你会怎么跟别人描述?最常见的办法是给出两个数字:纬度、经度。
北京: (39.9, 116.4)
天津: (39.1, 117.2)
悉尼: (-33.9, 151.2)
这两个数字放在一起,就足够把"位置"这个抽象概念,变成一个可以计算的东西:北京和天津的坐标数字很接近,悉尼和它们差得很远——这恰好对应了"北京天津离得近,悉尼离得远"这个事实。你不需要知道地理,光靠比较这两组数字,就能算出谁离谁近。
⭐ 语言模型要对词做的,是完全一样的事情:给每个词配一组数字,使得词义上相近的词,数字上也相近。“国王"和"女王"应该数字接近,“国王"和"香蕉"应该数字上差得很远。这组数字,就叫这个词的向量(vector)。
和地理坐标只需要 2 个数字不同,“意思"这个东西复杂得多——一个词的向量通常有几百到上万个数字,每一个数字负责捕捉意思里的某一个侧面。这些"侧面"具体是什么、怎么被学出来的,是第 8 讲的内容;这一讲只解决"向量"这个数学对象本身是什么、怎么运算。
三、把直觉钉成数学
向量:一列数字
向量就是按固定顺序排列的一串数字:
v = [0.2, -1.5, 0.8, 3.1]
这是一个"4 维向量”——有 4 个数字。你可以把它想象成地图坐标的推广:地图坐标是 2 维向量(东西向、南北向各一个数字),词向量可能是几百维,只是多了很多个"方向”,人脑没法直接画出来,但数学上的处理方式完全一样。
⚠️ 一个很容易被误解的点:地图坐标的两个维度分别有明确含义(“东西向"“南北向”)。词向量的几百个维度,绝大多数情况下没有一个是人类能直接读懂的含义——不存在"第 37 维专门表示’是否是水果’“这种事。这几百个数字是模型在训练里自己调出来的,只在整体上、作为一个模式捕捉了词义,单独拆开看某一维往往毫无意义。这一点在第 31 讲讲可解释性的边界时会重新变得重要。
怎么衡量"近”:点积与余弦相似度
地图上量两点距离,你会用尺子量直线距离。向量之间最常用的"近不近"的量法有两种。
点积(dot product):把两个向量对应位置的数字两两相乘,再全部加起来:
a = [1, 2, 3]
b = [4, 5, 6]
a · b = 1×4 + 2×5 + 3×6 = 4 + 10 + 18 = 32
点积有一个直觉:如果两个向量"方向差不多”,点积会是一个比较大的正数;如果方向差很多(比如接近垂直),点积接近 0;如果方向几乎相反,点积是负数。 你可以把它粗略理解成"两个向量在多大程度上指向同一个方向,同时还考虑了两者各自有多’长’"。
⚠️ 点积的数值大小会受向量本身"长度"的影响——一个数字整体偏大的向量,点积也会偏大,这不一定代表"方向"更接近。为了排除这个干扰,只关心"方向像不像”,会用余弦相似度(cosine similarity):
cos(a, b) = (a · b) / (|a| × |b|)
其中 |a| 是向量 a 的"长度”(术语叫范数,算法是每个数字平方后加总再开根号)。除以两个长度之后,结果被强制落在 -1 到 1 之间:1 表示方向完全相同,0 表示方向无关,-1 表示方向完全相反——和向量本身有多"长"完全无关,只看方向。
余弦相似度:两个向量夹角的余弦值,衡量两个向量在方向上有多接近,取值范围
[-1, 1],与向量长度无关。
⭐ 这就是"意思相近"的数学定义:如果一个训练好的模型,把"国王"和"女王"的向量算出来的余弦相似度是 0.9,把"国王"和"香蕉"算出来是 0.1,这个模型就是在用数字量化地表达"国王和女王更像"这件事。第 8 讲的词嵌入、第 9 讲的注意力机制、第 26 讲的向量检索,全部建立在这一个操作上——点积或余弦相似度,是这整个领域衡量"两个东西像不像"最基本的算子,没有例外。
矩阵:一批向量的表格
如果要同时处理很多个向量——比如一句话里的 20 个词,每个词都是一个向量——一个个写出来会很啰嗦。把它们按行摞在一起,就是一个矩阵:
[ 0.2 -1.5 0.8 ] ← "今天"的向量
M = [ 1.1 0.3 -0.4 ] ← "天气"的向量
[-0.6 2.0 0.1 ] ← "很好"的向量
这是一个"3 行 3 列"的矩阵:3 个词,每个词是 3 维向量。矩阵就是一批向量的记账方式,没有比这更深的含义。
矩阵乘法:唯一需要记住的直觉
矩阵乘法的具体计算规则(行乘列、逐项相乘再相加)网上到处都是,这里不重复推导。这门课里,你只需要死死记住一个概念性的直觉:
⭐ 矩阵乘法 = 对一整批向量,同时做同一种变换。
具体来说:如果你有一个向量 v,想把它变换成另一个向量(比如"拉伸一下、旋转一下、换个空间”),这个变换本身可以被写成一个矩阵 W,变换的过程就是 W · v。如果你不是只有一个向量,而是一整批(比如一句话里所有词的向量叠成的矩阵 M),用同一个 W 去变换这一批中的每一个向量,写出来就是 W · M——一次矩阵乘法,等价于把同一个变换,批量套用在很多个向量上。
单个向量的变换: W · v → 一个新向量
一整批向量的变换: W · M → 一整批新向量(每一行都被同一个 W 变换过)
这个"批量、同时套用同一种变换"的性质,正是第 2 讲第四节说的"可以并行计算"的数学来源——GPU 极其擅长做的事情,本质上就是这种大批量的矩阵乘法。第 9 讲计算 Q、K、V 的时候,第 10 讲的前馈层,本质上全部是这一个操作的反复堆叠。
四、这一层表示,局限在哪
局限一:一个词只能有一个向量位置(暂时)
这一讲讲的向量,是静态的——“苹果"这个词,不管它出现在"苹果公司"还是"咬一口苹果"里,此刻我们给它的都是同一个向量,因为向量只取决于"这个词是什么”,不取决于"这个词在哪句话里”。
但第 1 讲的例子已经说过,“苹果"在这两句话里的意思完全不同。一个词、一个固定向量,装不下一词多义——这是这一讲的表示方式必然留下的空隙,第 9 讲的自注意力要解决的核心问题之一,正是让向量能够根据上下文动态调整,而不是每个词永远焊死在同一个点上。
局限二:维度通常不可解释
前面已经提过:几百个维度里,你几乎无法指着某一维说"这维代表书面语气”。这意味着你没法像读代码一样直接读懂模型内部在表示什么,只能通过点积、余弦相似度这类间接的探测手段去猜测。第 31 讲会正式讨论这件事在多大程度上是个能被解决的工程问题、在多大程度上是个结构性的边界。
局限三:相似度是一种代理指标,不是"意思"本身
余弦相似度高,只能说明两个向量在训练数据里表现出的统计模式相近,不能保证这种相近一定对应人类理解意义上的"意思像"。两个词可能因为总是出现在相似的句子结构里而被算成"相似",即便它们的实际含义相去甚远。这一点在第 26 讲讲向量检索的实际效果时会有更具体的例子。
五、和后面课程的关系
这一讲定义的两个工具——向量衡量"是什么"、矩阵乘法批量做"变换"——贯穿几乎全部剩下的课程:
| 后续内容 | 用到本讲的哪个概念 |
|---|---|
| 第 4 讲:概率分布 | 一个概率分布本身就是一个向量(词表那么多维,每个分量是一个概率) |
| 第 5、6 讲:神经网络与反向传播 | 神经网络的"一层",就是一次矩阵乘法加一个非线性处理 |
| 第 8 讲:词嵌入 | 把"怎么给词配向量"这件事本身讲透——本讲只讲向量配好之后能拿来做什么 |
| 第 9 讲:自注意力 | Q/K/V 的计算是矩阵乘法,“哪个词该关注哪个词"靠的正是点积 |
| 第 26 讲:向量检索 | 找"最相关的文档”,本质就是在一堆向量里找余弦相似度最高的那个 |
第 2 讲里一带而过的 hₜ,现在可以说清楚了:它就是一个向量——一个由固定数量的数字组成、试图概括"到目前为止的上下文"的点,只是它的每个维度具体表示什么,同样没有人能直接读懂。
六、本讲小结
- 机器只认识数字,语言模型的第一步永远是"把文字变成数字"——这个数字化的结果就是向量。
- 向量 = 一列数字,可以类比成地图坐标的高维推广:坐标接近代表位置接近,词向量接近(在这一讲的定义下)代表词义接近。
- ⭐ “意思相近"在数学上被定义为"向量方向接近”,用点积或余弦相似度衡量;余弦相似度排除了向量长度的干扰,只看方向,取值
[-1, 1]。 - 矩阵是一批向量的表格,矩阵乘法的核心直觉是对一整批向量同时施加同一种变换——这是后面几乎所有神经网络计算、以及 GPU 能大规模并行计算的数学根基。
- ⚠️ 向量的维度通常不可读、不可解释,“相似"只是一种统计代理,不等于人类意义上的"意思相同”。
- 这一讲讲的是静态向量:一个词一个固定位置,装不下一词多义——这个空隙正是第 9 讲自注意力要填的坑。
思考题
- 为什么"把词编号成 1、2、3……“不是一种有效的数字化方式?这种编号方式和向量表示的本质区别是什么?
- 如果
a = [1, 0],b = [0, 1],c = [-1, 0],分别算出a和b、a和c的余弦相似度,并用"方向"来解释这两个结果的含义。 - 点积会受向量长度影响,余弦相似度不会——请设计两个向量
a和a' = 2a(方向相同、长度不同),验证它们和另一个向量b的点积不同,但余弦相似度相同。 - 本讲说"矩阵乘法 = 对一批向量同时做同一种变换”,这和第 2 讲说的 RNN"参数共享"(每个时间步用同一套
f)有什么共同的设计哲学? - “一个词只能有一个静态向量,装不下一词多义”——如果不改变向量本身的定义,你能想到什么朴素的补救办法吗(不要求正确,第 9 讲会给出真正的答案)?