线性代数直觉:AI 的几何骨架 本节摘要:每一个 AI 模型,本质上都是穿着华丽外衣的矩阵运算。本节不追求做数学家,而要让你看见这些运算在几何上意味着什么:向量是空间里的点与方向,矩阵是把点搬到新位置的运动,点积度量两个方向的相似度,投影是把高维信息压到低维的手术刀。我们把向量、矩阵、点积、线性无关、秩、基、投影、Gram-Schmidt 这八个核心概念逐个用 Python 从零实现一遍,再用 NumPy/PyTorch 对比验证,最后回到 AI 工程的真实现场——词嵌入、注意力分数、LoRA、最小二乘——告诉你「为什么这就是矩阵数学干的活」。读完本节,你打开任何 ML 论文第一页那些符号,都能在脑子里画出它们对应的几何图像。
本节摘要:每一个 AI 模型,本质上都是穿着华丽外衣的矩阵运算。本节不追求做数学家,而要让你看见这些运算在几何上意味着什么:向量是空间里的点与方向,矩阵是把点搬到新位置的运动,点积度量两个方向的相似度,投影是把高维信息压到低维的手术刀。我们把向量、矩阵、点积、线性无关、秩、基、投影、Gram-Schmidt 这八个核心概念逐个用 Python 从零实现一遍,再用 NumPy/PyTorch 对比验证,最后回到 AI 工程的真实现场——词嵌入、注意力分数、LoRA、最小二乘——告诉你「为什么这就是矩阵数学干的活」。读完本节,你打开任何 ML 论文第一页那些符号,都能在脑子里画出它们对应的几何图像。
对应原课程:Phase 01 · Lesson 01 ·
linear-algebra-intuition(原英文phases/01-math-foundations/01-linear-algebra-intuition/docs/en.md)。本章为「数学基础」的开篇,前置依赖为第 1 章(开发环境与工具链)。
阅读完本节,你应当能够:
翻开任何一篇 ML 论文,第一页之内你一定会撞见向量、矩阵、点积、变换。如果没有线性代数直觉,它们只是符号;有了直觉,你就能看见神经网络真正在做什么——把空间里的点搬来搬去。
你不必成为数学家。你只需要看见这些运算在几何上的含义,然后亲手把它们写一遍。
一个向量就是一串数。但这串数有意义——它是空间里的坐标。
2D 向量 [3, 2]:从原点 (0,0) 出发,指向平面上的 (3, 2)。它的大小(magnitude)是 sqrt(3² + 2²) = sqrt(13),方向朝右上方。
在 AI 里,向量代表一切:
矩阵把一个向量变成另一个向量——可以旋转、缩放、拉伸或投影。
在 AI 里,矩阵就是模型本身:
两个向量的点积告诉你它们有多「像」。
a · b = a₁×b₁ + a₂×b₂ + ... + aₙ×bₙ 同向: a · b > 0 (相似) 正交: a · b = 0 (无关) 反向: a · b < 0 (相反)
搜索引擎、推荐系统、RAG 检索的底层,本质上都是在找点积最大的向量。
一组向量线性无关,当且仅当其中任何一个都不能写成其余向量的(加权)组合。若 v1、v2、v3 线性无关,它们张成三维空间;若有一个能被其他表示,它们只张成一个平面。
为什么这对 AI 重要:你的特征矩阵应当列线性无关。如果两个特征完全相关(线性相关),模型无法区分它们各自的影响——这就是回归中的多重共线性,权重矩阵变得不稳定,输入微小抖动就引发输出剧烈震荡。
具体例子:
v1 = [1, 0, 0] v2 = [0, 1, 0] v3 = [2, 1, 0] # v3 = 2*v1 + v2
v1、v2 互相独立;但 v3 = 2·v1 + v2,所以 {v1, v2, v3} 是相关组。三个向量都躺在 xy 平面里,无论怎么组合都到不了 [0, 0, 1]——你有三个向量,却只有两个自由维度。在数据集里,若 feature_3 = 2·feature_1 + feature_2,加入 feature_3 不带来任何新信息,更糟的是它让正规方程奇异——权重无唯一解。
基(Basis) 是一组最小且足以张成整个空间的线性无关向量,基向量的个数就是该空间的维度。3D 空间的标准基是 {[1,0,0], [0,1,0], [0,0,1]},但任意三个独立的 3D 向量都构成合法的基——选基就是选坐标系。
矩阵的秩(Rank) = 线性无关列数 = 线性无关行数。若秩 < min(行数, 列数),矩阵秩亏:
| 情形 | 秩 | 对 ML 的含义 |
|---|---|---|
| 满秩(rank = min(m,n)) | 最大可能 | 存在唯一最小二乘解,模型良态 |
| 秩亏(rank < min(m,n)) | 低于最大 | 特征冗余,权重解有无穷多,需正则化 |
| 秩 = 1 | 1 | 每一列都是某向量的缩放,全部数据落在一条直线上 |
| 接近秩亏(奇异值很小) | 数值上低 | 矩阵病态,微小噪声导致大输出波动,用 SVD 截断或岭回归 |
把向量 a 投影到向量 b,得到 a 在 b 方向上的分量:
proj_b(a) = (a·b / b·b) · b
残差 (a − proj_b(a)) 垂直于 b。这种正交分解正是最小二乘拟合的地基。投影在 ML 中无处不在:
例子:a = [3, 4],b = [1, 0]
proj_b(a) = (3·1 + 4·0)/(1·1 + 0·0) · [1, 0] = 3 · [1, 0] = [3, 0]
投影丢掉了 y 分量——这就是最朴素的降维:扔掉你不关心的方向。
把任意一组独立向量改造成标准正交基(Orthonormal Basis):每个向量长度为 1,两两正交。算法:
输入: v1, v2, v3, ...(线性无关) u1 = v1 / |v1| w2 = v2 − (v2·u1)·u1 u2 = w2 / |w2| w3 = v3 − (v3·u1)·u1 − (v3·u2)·u2 u3 = w3 / |w3| 输出: u1, u2, u3, ...(标准正交基)
这正是 QR 分解的内核:Q 是标准正交基,R 记录投影系数。QR 用于:解线性方程组(比高斯消元更稳定)、计算特征值(QR 算法)、最小二乘回归(标准数值方法)。
完整源码见 phases/01-math-foundations/01-linear-algebra-intuition/code/(Python 主版本,另有 Julia 版)。下面给出关键骨架与设计要点。
class Vector: def __init__(self, components): self.components = list(components) self.dim = len(self.components) def __add__(self, other): # 逐元素加 return Vector([a + b for a, b in zip(self.components, other.components)]) def dot(self, other): # 点积 ∑ aᵢbᵢ return sum(a * b for a, b in zip(self.components, other.components)) def magnitude(self): # 模长 ‖v‖ = √(∑ vᵢ²) return sum(x**2 for x in self.components) ** 0.5 def normalize(self): # 单位向量 v / ‖v‖ mag = self.magnitude() return Vector([x / mag for x in self.components]) def cosine_similarity(self, other): # cos θ = (a·b)/(‖a‖‖b‖) return self.dot(other) / (self.magnitude() * other.magnitude())
设计要点:把向量当对象而非裸 list,既能让算式读起来贴近数学符号(如
a + b、a.dot(b)),也为后续自动微分(PyTorch 的张量思路)做了铺垫。
矩阵的核心运算是 __matmul__(支持 @ 语法),分两种情况:乘向量、乘矩阵。
class Matrix: def __matmul__(self, other): if isinstance(other, Vector): # 矩阵 × 向量:每个输出分量是行与向量的点积 return Vector([ sum(self.rows[i][j] * other.components[j] for j in range(self.shape[1])) for i in range(self.shape[0]) ]) # 矩阵 × 矩阵:cᵢⱼ = Σₖ aᵢₖ·bₖⱼ ... def transpose(self): # 行列互换 ...
一个验证几何直觉的例子——90° 旋转矩阵:
rotation_90 = Matrix([[0, -1], [1, 0]]) # 标准 90° 旋转 point = Vector([3, 1]) rotated = rotation_90 @ point # → Vector([-1, 3])
矩阵乘法就是神经网络的层:output = W @ input,W 把输入向量从输入维度搬到输出维度。
用高斯-约旦消元把矩阵化成行最简形,非零行数即秩;秩等于向量个数则线性无关:
def is_linearly_independent(vectors): # 把向量组成矩阵 → 逐列找主元 → 主元行归一 → 消去其他行同列 → 统计主元数 ... return rank == n
def project(a, b): scalar = a.dot(b) / b.dot(b) # 投影系数 return Vector([scalar * x for x in b.components]) def gram_schmidt(vectors): orthonormal = [] for v in vectors: w = v for u in orthonormal: # 减去在已有基向量上的投影 w = w - project(w, u) if w.magnitude() < 1e-10: # 模长过小 → 该向量原可被表示 → 跳过 continue orthonormal.append(w.normalize()) return orthonormal
验证 {v1=[1,0,0], v2=[1,1,0], v3=[1,1,1]} 经 Gram-Schmidt 后,任意两两 uᵢ·uⱼ = 0,每个 ‖uᵢ‖ = 1。
import numpy as np a = np.array([1, 2, 3], dtype=float) print(np.dot(a, b)) # 点积 print(np.linalg.norm(a)) # 模长 W = np.random.randn(2, 3) * 0.1 print(W @ x) # 一行完成神经网络层 print(np.linalg.matrix_rank(A)) # 秩 Q, R = np.linalg.qr(np.random.randn(3,3)) # QR 分解
NumPy 把本节所有手工实现压缩成一两个函数调用——但你现在知道每个调用底下在做什么。
import torch x = torch.randn(3, requires_grad=True) y = torch.tensor([1.0, 0.0, 0.0]) similarity = torch.dot(x, y) similarity.backward() print(x.grad) # 点积对 x 的梯度就是 y 本身
点积对 x 的梯度恰好是 y,PyTorch 自动算出来了。神经网络里每一个操作(矩阵乘、点积、投影)都由这类原语组成,autodiff 贯穿全程跟踪梯度。
💡 你刚刚从零实现了 NumPy 一行就能搞定的事——现在你真正理解了底层。
本节产出(位于原课程 outputs/):
prompt-linear-algebra-tutor.md:一个用于 AI 助手的提示,指导助手通过几何直觉讲授线性代数(把抽象公式翻译成空间里的动作)。源码(code/ 目录)是独立教学实现,Python 主版本可读、可改、可单步调试;另有 Julia 版演示同概念在科学计算语言里的写法(支持 ⋅ 等 Unicode 运算符)。
Vector.angle_between(other),返回两向量夹角(度)。rank() 验证,并解释其列张成的几何对象。下一节,我们正式系统化向量与矩阵的运算体系——加法、数乘、矩阵乘、转置、逆——并对接 NumPy 的
ndarray视图。