上一篇:(七)用直线去逼近曲线——讲计算机怎么处理连续的东西。 这一篇:讲计算机怎么表示"意思"——这是整个 AI 的数学地基,也是八层的最后一层。
耗时:读完约 55 分钟,动手约 2 小时。
开头:机器不懂"意思",但它能算"角度"
问一个看起来很简单的问题:
怎么让机器知道"我今天很开心"和"我心情不错"意思相近?
机器只认数字。它没有"意思"这个概念。那怎么办?
答案是把每句话变成一串数字——一个向量。
"我今天很开心" → [0.12, -0.45, 0.88, ..., 0.31] ← 768 个数
"我心情不错" → [0.15, -0.41, 0.85, ..., 0.29] ← 768 个数
"股票跌了" → [-0.62, 0.71, 0.03, ..., 0.88] ← 768 个数
然后比较它们。但不是比较"距离",是比较"夹角"。
前两个向量的夹角很小(方向接近),第三个方向完全不同。这就是"意思相近"的数学形式。
这一篇就讲这件事。它是八层里最后一层,也是最直接通向今天 AI 的一层——因为大语言模型里那个叫"注意力机制"的东西,本质就是三个矩阵相乘。
一、向量:一个数串,就是一个方向
先建立最基本的操作。
余弦相似度:用夹角衡量相似
def cos(a, b):
return (a·b) / (|a| × |b|)
取值范围 [−1, 1]。1 是同方向,0 是垂直(无关),−1 是反方向。
为什么不用距离?实测给你看
三个向量:
a = [1, 2, 0.5]
b = [2, 4, 1] ← 同方向,长度是 a 的 2 倍
d = [0.5, 1, 4] ← 不同方向
| 度量 | a vs b | a vs d |
|---|---|---|
| 余弦相似度 | 1.000000 | 0.472866 |
| 欧氏距离 | 2.2913 | 3.6742 |
看这个对比:
- 余弦:a 和 b 相似度 = 1.0,完全一样
- 欧氏距离:a 和 b 相差 2.29,比 a 和 d 的 3.67 只小一点,看起来"也挺远"
为什么?因为 b 只是 a 的"加强版"(同样方向,2 倍强度)。 在语义上它们讲的是同一件事,只是程度不同。
距离把"长度差异"当成了"不同",夹角不会。
所以在语义检索、推荐系统、RAG(知识库问答)里,全用余弦相似度,不用欧氏距离。 你问"怎么学 C++",一本标题是"如何学习 C++ 编程"的书,和一本"Python 入门"的书——距离可能差不多,但夹角差得远。
二、高维反直觉:越高的维度,距离越没用
这里有个事实,几乎所有第一次听到的人都不信。
在高维空间里,任意两个随机点的距离,几乎都一样。
实测(每个维度取 300 对随机点):
| 维度 | 平均距离 | 标准差 | 变异系数(标准差/均值) |
|---|---|---|---|
| 2 | 1.758 | 0.8912 | 0.5069 |
| 10 | 4.452 | 0.9502 | 0.2134 |
| 50 | 9.956 | 0.9692 | 0.0973 |
| 100 | 14.109 | 0.9745 | 0.0691 |
| 500 | 31.584 | 0.9654 | 0.0306 |
| 1000 | 44.664 | 1.0468 | 0.0234 |
| 5000 | 100.039 | 0.9968 | 0.0100 |
看最后一列:变异系数从 0.51 一路掉到 0.01。
5000 维时,随机两点的距离全是 100 左右,波动只有 1%。所有点都几乎等距。
这就是"维度诅咒"(curse of dimensionality)最具体的样子: 维度一高,“距离"这个度量就失去分辨力——因为大家都差不多远。
这解释了很多事:
- 为什么高维检索要用夹角(余弦),不用距离——距离已经被"稀释"了
- 为什么高维要用降维(PCA/SVD)才能可视化
- 为什么机器学习里"特征太多"反而是灾难
注意这跟前面几篇是同一条线: 第二篇讲"采样是把连续压成离散”,这一篇讲"维度一高,直觉失效"。都是"低维直觉在数学上不成立"。
三、矩阵:一个变换,不是一个表格
大多数人对矩阵的印象是"一张数字表格"。这是最误导的印象。
矩阵是一个变换。它对向量做的事,是"旋转 + 拉伸 + 压缩"。
比如这个矩阵:
A = [2 1]
[1 2]
它作用在向量上,就是一次变形。而它的特征值告诉你:这个变形有哪些"不变的方向"。
四、特征值:变形里那些"方向不变"的地方
定义,一句话
如果 A·v = λ·v,那么 v 是一个"特征向量"(方向不变),λ 是对应的"特征值"(拉长多少倍)。
方向不变,长度变。
实测
A = [2 1]
[1 2]
特征值 λ = 1, 3
特征向量 = [−0.707, 0.707] 和 [0.707, 0.707]
验证 A·v = λ·v:
λ=1: A@v = [−0.7071, 0.7071], λv = [−0.7071, 0.7071], 差 0
λ=3: A@v = [ 2.1213, 2.1213], λv = [ 2.1213, 2.1213], 差 0
完全相等。
为什么这件事重要:反复作用,方向会"收敛"
把 A 反复乘一个初始向量,每次归一化:
A^1 @ x → [0.894427, 0.447214]
A^2 @ x → [0.780869, 0.624695]
A^3 @ x → [0.732793, 0.680451]
A^5 @ x → [0.710011, 0.704191]
A^10 @ x → [0.707119, 0.707095]
A^20 @ x → [0.707107, 0.707107] ← 收敛了
最大特征向量 = [0.707107, 0.707107]
不管从哪开始,反复乘同一个矩阵,方向都会收敛到"最大特征值"的那个特征向量。
为什么?因为每次乘法,那个方向的成分被乘 3 倍,其他方向的成分被乘 1 倍。反复乘下去,3ⁿ 会彻底压过 1ⁿ。
这个性质叫"幂迭代",是 Google 的 PageRank 的核心算法。 整个互联网的链接矩阵,最大的那个特征向量,就是网页的重要性排序。 “谁最重要"这个问题,数学上就是"求最大特征向量”。
五、SVD:所有矩阵都能拆成"旋转·拉伸·旋转"
特征值只对方阵有意义。SVD(奇异值分解)把它推广到任何矩阵:
任何矩阵 A = U · Σ · Vᵀ U、V 是正交矩阵(旋转),Σ 是对角矩阵(拉伸)。
一句话理解:任何线性变换,都是"先转一下、再拉伸、再转一下"。
实测:一个 4×3 矩阵
A = [[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]]
奇异值 S = [25.462, 1.291, 2.5e-15]
秩 = 2
第三个奇异值是 2.5e-15——约等于 0。 这个矩阵虽然写着 4×3,实际只有 2 维的信息(因为每一行都是等差数列,第三行是前两行的线性组合)。
用前 k 个分量重建:
| k | 最大误差 | 保留能量 |
|---|---|---|
| 1 | 0.8098 | 95.18% |
| 2 | 0.000000 | 100.00% |
| 3 | 0.000000 | 100.00% |
2 个分量就精确重建。第 3 个分量是噪声(数值误差)。
SVD 告诉你一件事:矩阵的"真实维度"可能远小于它的"表面尺寸"。
图像压缩:真实数字
我拿一张 200×200 的图(40000 个数)做 SVD:
| k(保留分量) | 要存几个数 | 压缩比 | 保留能量 | 最大误差 |
|---|---|---|---|---|
| 1 | 401 | 99.8× | 27.28% | 0.9285 |
| 2 | 802 | 49.9× | 54.54% | 0.2296 |
| 10 | 4,010 | 10.0× | 58.62% | 0.2198 |
| 50 | 20,050 | 2.0× | 75.13% | 0.1415 |
| 100 | 40,100 | 1.0× | 89.17% | 0.0706 |
| 200 | 80,200 | 0.5× | 100.00% | 0.0000 |
看 k=10 那一行:只用 4010 个数(1/10 的数据),保留 58.62% 的能量,最大误差 0.22。
这就是图像压缩、推荐系统降维、数据去噪的数学基础。
一句话:SVD 找出"哪些方向最重要",然后扔掉不重要的。 不是"删数据",是"删方向"。
六、注意力机制:本质就是三次矩阵乘法
现在到这一篇最重要的部分。GPT、BERT 这些大模型的核心,就叫"注意力机制"(Attention)。
大多数人以为它很神秘。它其实就是三步矩阵乘法。
三个矩阵:Q、K、V
每个 token(词)都变成三个向量:
- Q(Query,查询):我在找什么
- K(Key,键):我有什么
- V(Value,值):我的内容
用矩阵表示:Q、K、V。
三步
第一步:算两两相关度
scores = Q · Kᵀ / √d
这就是一个矩阵乘法。 结果是一个 n×n 的表:第 i 行第 j 列 = 第 i 个词有多关注第 j 个词。
第二步:归一化成权重
W = softmax(scores)
每行加起来等于 1——变成"注意力分配比例"。
第三步:加权求和
output = W · V
又是一个矩阵乘法。 每个词的新表示 = 所有词的内容按注意力加权平均。
实测(4 个词,8 维)
scores = Q@Kᵀ/√8 形状 (4,4)
原始打分:
[[-0.654 -0.489 0.468 -1.722]
[-0.316 -1.142 -0.286 -1.216]
[-1.244 1.083 -0.044 0.001]
[-0.667 0.990 -0.283 -0.371]]
softmax 后(每行和为 1):
[[0.179 0.211 0.549 0.061]
[0.348 0.152 0.358 0.142]
[0.055 0.568 0.184 0.193]
[0.110 0.579 0.162 0.148]]
行和: [1. 1. 1. 1.]
最后 W@V → 输出形状 (4, 8)
就这三步。没有第四步。
大模型的"理解",数学上就是: 每个词先算出它该看哪些词(Q·Kᵀ),再按权重把所有词的信息混在一起(W·V)。
为什么这一步这么关键
因为它让每个词都能"看到全局"。
没有注意力之前,模型只能一个个词顺着读(RNN),信息传得越远越模糊。有了注意力,第 1 个词和第 5000 个词可以直接对话——因为它们在同一个矩阵乘法里。
代价:O(n²)
但是注意 Q·Kᵀ 的大小是 n×n。
n = 4 → 16 个分数
n = 4096 → 16,777,216 个分数
n = 100000 → 10,000,000,000 个分数
上下文长度翻倍,注意力的计算量翻四倍。 这就是为什么大模型的"上下文窗口"是稀缺资源、为什么长文本这么贵。
这也把第五篇的复杂度接了回来: 注意力是 O(n²d),而矩阵乘法朴素实现是 O(n³)。 整个 AI 的算力账单,就是矩阵乘法的账单。
实测矩阵乘法的立方增长(朴素实现):
| n | 耗时 |
|---|---|
| 50 | 15.6 ms |
| 100 | 86.5 ms |
| 150 | 242.8 ms |
| 200 | 594.1 ms |
n 翻倍,耗时约 8 倍(2³)。 这就是为什么全世界的公司都在抢 GPU——GPU 存在的唯一理由,就是把矩阵乘法做得更快。
七、词向量的经典魔术:king − man + woman ≈ queen
最后讲一个让人拍案的结果,它说明了"高维表示"到底能做到什么。
把词变成向量之后,向量的加减对应语义的加减:
king − man + woman ≈ ?
实测(50 维,带噪声):
| 比较对象 | 余弦相似度 |
|---|---|
| king | 0.8381 |
| queen | 0.9535 ← 最高 |
| man | 0.1515 |
| woman | 0.0797 |
| apple | 0.2470 |
最相似的是 queen,相似度 0.95。
“国王"减去"男人"加上"女人”,得到"女王"。
这不是巧合,也不是程序员写死的规则。这是"把语义映射到向量空间"这件事自然产生的结构——因为"性别"在向量空间里变成了一个方向,你可以沿着这个方向加减。
这就是"表示学习"(representation learning)的全部意义: 不是人去定义规则,而是找到一个空间,让规则变成几何。
这也解释了为什么大模型不需要人教它语法——语法结构在向量空间里变成了几何结构,模型只要学几何,就自动学会了语法。
八、八层走完:整个专题的骨架
八篇,八层,一条线。
| 层 | 问什么 | 数学 | 篇 |
|---|---|---|---|
| 一 | 一个数怎么装进机器 | 数值分析 | (一) |
| 二 | 一堆东西怎么装进机器 | 离散数学 | (二) |
| 三 | 怎么确认它是对的 | 数理逻辑 | (三) |
| 四 | 什么根本算不了 | 计算理论 | (四) |
| 五 | 能算的有多快 | 算法分析 | (五) |
| 六 | 不确定怎么处理 | 概率论 | (六) |
| 七 | 连续怎么逼近 | 微积分 | (七) |
| 八 | 意思怎么表示 | 线性代数 | 本篇 |
它们在 AI 里怎么合起来
这是我最想让你看到的一张图。一个大语言模型,八层全用上了:
| 层 | 在 GPT 里对应什么 |
|---|---|
| 一 数值 | 权重是 float16/bfloat16,精度直接影响模型能不能训起来 |
| 二 离散 | token 是离散的,词表是有限的,softmax 把连续变回离散 |
| 三 证明 | 训练不收敛时,靠不变量思维(梯度该多大、loss 该多低)定位问题 |
| 四 可计算 | 有些问题模型永远学不会(停机问题那类) |
| 五 复杂度 | O(n²d) 的注意力,就是算力账单的来源 |
| 六 概率 | 输出是概率分布,采样温度、top-p 全是概率 |
| 七 微积分 | 反向传播 = 链式法则,梯度下降 = 学习本身 |
| 八 线代 | 整个模型就是矩阵乘法堆起来的 |
所以"AI 时代的计算机数学"这句话,不是修辞。 一个 GPT,就是这八层数学的一次性总动员。
最后一句收口
整个专题第一句话是:
数学是连续的、无限的、精确的;计算机是离散的、有限的、近似的。这两者之间的翻译工作,就是计算机数学。
八篇走完,这句话可以升级成:
计算机数学,是在"离散、有限、近似"的机器上,把"连续、无限、精确"的数学算到够用—— 而 AI,是把这八层全部押上去,去逼近一件它自己也说不清的事。
九、动手:六个实验
实验 1:为什么用夹角不用距离
import math
def cos(a,b):
return sum(x*y for x,y in zip(a,b)) / (
math.sqrt(sum(x*x for x in a)) * math.sqrt(sum(x*x for x in b)))
def dist(a,b):
return math.sqrt(sum((x-y)**2 for x,y in zip(a,b)))
a=[1,2,0.5]; b=[2,4,1]; d=[0.5,1,4]
print(f"cos(a,b)={cos(a,b):.4f} cos(a,d)={cos(a,d):.4f}")
print(f"dist(a,b)={dist(a,b):.4f} dist(a,d)={dist(a,d):.4f}")
a 和 b 是"同方向不同强度",余弦说 1.0,距离说 2.29。
实验 2:维度诅咒
import numpy as np
for dim in [2, 10, 50, 100, 1000, 5000]:
ds = [np.linalg.norm(np.random.randn(dim) - np.random.randn(dim))
for _ in range(300)]
ds = np.array(ds)
print(f"{dim:>5} 维: 均值 {ds.mean():7.2f} 变异系数 {ds.std()/ds.mean():.4f}")
看变异系数从 0.5 掉到 0.01——高维里所有点几乎等距。
实验 3:特征值和幂迭代
import numpy as np
A = np.array([[2.,1.],[1.,2.]])
w, v = np.linalg.eigh(A)
print("特征值:", w)
x = np.array([1.,0.])
for k in [1,2,3,5,10,20]:
y = np.linalg.matrix_power(A,k) @ x
y = y/np.linalg.norm(y)
print(f"A^{k:<2}: [{y[0]:.6f}, {y[1]:.6f}]")
不管从哪开始,都会收敛到最大特征向量 [0.707, 0.707]。
实验 4:SVD 压缩一张图
import numpy as np
h = w = 200
x = np.linspace(0, 4*np.pi, w)
img = (np.sin(x)[None,:] + np.sin(x)[:,None])/2 + np.random.randn(h,w)*0.05
U, S, Vt = np.linalg.svd(img, full_matrices=False)
for k in [1, 5, 10, 50]:
Ak = U[:,:k] @ np.diag(S[:k]) @ Vt[:k,:]
print(f"k={k:2d}: 存 {k*(h+w+1):,} 个数, 误差 {np.abs(img-Ak).max():.4f}")
实验 5:注意力就是矩阵乘法
import numpy as np
np.random.seed(7)
n, d = 4, 8
Q, K, V = [np.random.randn(n, d) for _ in range(3)]
scores = Q @ K.T / np.sqrt(d) # 第 1 次矩阵乘法
W = np.exp(scores) / np.exp(scores).sum(axis=1, keepdims=True) # softmax
out = W @ V # 第 2 次矩阵乘法
print("打分:\n", scores.round(3))
print("权重行和:", W.sum(axis=1).round(6))
print("输出形状:", out.shape)
实验 6:king − man + woman
import numpy as np
np.random.seed(3)
d = 50
base = {k: np.pad(np.array(v), (0, d-len(v)))
for k, v in {'king':[1,.9,.2], 'queen':[1,.1,.2],
'man':[0,.9,0], 'woman':[0,.1,0],
'apple':[.1,0,1]}.items()}
W = {k: v + np.random.randn(d)*0.02 for k,v in base.items()}
cos = lambda a,b: a@b/(np.linalg.norm(a)*np.linalg.norm(b))
target = W['king'] - W['man'] + W['woman']
for k in W: print(f"cos(结果, {k:6s}) = {cos(target, W[k]):.4f}")
十、带走的东西
一句话:
机器不懂"意思",但它能把意思变成向量——然后"意思相近"就变成了"夹角小",“语义加减"就变成了"向量加减”。
三句话:
- 高维要用夹角,不用距离。 实测 5000 维时随机两点的距离变异系数只有 0.01——所有点几乎等距,距离失去分辨力。
- SVD 找出"哪些方向重要"。 200×200 的图,只存 1/10 的数(k=10),保留 58.62% 能量,最大误差 0.22。不是删数据,是删方向。
- 注意力机制 = Q·Kᵀ → softmax → W·V,就三步矩阵乘法。 大模型的"理解",数学上是"每个词算出该看谁,再按权重把信息混起来"。
一个最该记住的判断
AI 不是"理解了语言",是"找到了一个几何空间,让语义变成了方向"。 king − man + woman ≈ queen,不是规则,是几何的副产品。 所以模型不需要人教语法——语法结构在向量空间里变成了几何结构,学几何就学会了语法。
十一、这个专题到这里结束了
八篇,从"0.1 + 0.2 为什么不等于 0.3",一路走到"GPT 的注意力机制"。
这不是八门互不相关的数学。是一条线:
数装不下 → 所以要离散化 → 所以要证明对 → 所以要知道什么算不了
→ 所以要算得快 → 所以要处理不确定 → 所以要逼近连续 → 所以要表示高维
每一层都在解决上一层留下的问题,每一层都留下新的问题给下一层。
如果这个专题你只带走一句话,带这句:
数学不是编程的前置课。数学是"凭什么判断它对"的来源。 而"彻底掌握"的体感,不是会推导,是同一个结构你认出来三次。
后续还想深入的话
八层,八门课,都在这张表里:
| 层 | 正统学科 | 入门书(按难度) |
|---|---|---|
| 一 | 数值分析 | Burden & Faires |
| 二 | 离散数学 | Rosen / MIT 6.042 |
| 三 | 数理逻辑 | Rosen 第 1 章 / Hoare 1969 |
| 四 | 计算理论 | Sipser |
| 五 | 算法与复杂度 | Sipser 后半 / CLRS |
| 六 | 概率统计 | Ross《A First Course in Probability》 |
| 七 | 微积分与优化 | Stewart / Boyd《Convex Optimization》 |
| 八 | 线性代数 | Strang / Goodfellow《Deep Learning》第 2 章 |
这些我不做页码引用——不同版本页码不同,写了就是骗你。按书名和章节找。
附:本篇所有数字的来源
全部本机跑出来:Ubuntu / Python 3.8 / numpy 1.17 / x86-64。
余弦 vs 距离:a=[1,2,0.5], b=[2,4,1](同方向 2 倍长), d=[0.5,1,4];cos(a,b)=1.000000、cos(a,d)=0.472866;欧氏 dist(a,b)=2.2913、dist(a,d)=3.6742。
维度诅咒(每维 300 对随机点):2/10/50/100/500/1000/5000 维 → 平均距离 1.758/4.452/9.956/14.109/31.584/44.664/100.039,变异系数 0.5069/0.2134/0.0973/0.0691/0.0306/0.0234/0.0100。
特征值:A=[[2,1],[1,2]] → λ=1, 3;幂迭代 A^1/2/3/5/10/20 @ [1,0] 归一化后收敛到 [0.707107, 0.707107]。
SVD(4×3 矩阵):奇异值 25.462/1.291/2.5e-15,秩 2;k=1 误差 0.8098(保留 95.18% 能量),k=2 误差 0(100%)。
SVD 图像压缩(200×200 = 40,000 数):k=1/2/10/50/100/200 → 存 401/802/4010/20050/40100/80200 个数,压缩比 99.8/49.9/10.0/2.0/1.0/0.5 倍,保留能量 27.28/54.54/58.62/75.13/89.17/100%,最大误差 0.9285/0.2296/0.2198/0.1415/0.0706/0。
注意力:4 token × 8 维,scores 形状 (4,4),softmax 后行和全为 1.0,输出 (4,8)。
矩阵乘法:n=50/100/150/200 → 15.6/86.5/242.8/594.1 ms(近似 n³)。
词向量:king−man+woman 与 queen 余弦 0.9535(最高),king 0.8381,apple 0.2470,man 0.1515,woman 0.0797。
你自己机器上跑出来的数字会略有不同(BLAS 库、CPU)。差一点不影响结论——结论是结构性的。