为什么 AI 论文全是天书?因为每一个数学符号,其实都是一句人话

2026-07-31 · Steve Chan

AI 论文里的 ∑、∂、∇、𝔼、argmax 为什么越看越像天书?其实它们不是新的知识,而是一整句话被压缩后的缩写。从数学符号的诞生历史,到 GPT、Transformer、PyTorch 代码,一篇文章教你读懂任何公式。

"一个好的记号,能把大脑从不必要的劳动中解放出来,让它去思考更高级的问题。" —— 怀特海

"在 1591 年之前,人类甚至写不出'一般的方程'这句话。"

上一篇(Chapter 0 / 0.5)讲的是为什么是这个公式 —— 为什么反复出现平方、\(1/r^2\)\(\log\)。 这一篇讲更前置、也更卡人的一步:你拿到一个陌生公式,怎么把它读下去。

很多人说"我数学不好",其实说的是:"我看到 \(\sum\)\(\partial\)\(\nabla\)\(\mathbb{E}\)\(\arg\max\)\(\otimes\) 就自动关机了。" 这不是智力问题,是没人告诉你这些符号是缩写,而缩写的全称从来没被展开过


🕰️ 0.6.1 先看一件震撼的事实:数学在 1600 年前,是用大白话写的

数学史学家 Nesselmann(1842)把代数分成三个阶段:

阶段 时代 长什么样
文辞代数(rhetorical) 巴比伦 ~ 花拉子米(820) 全是句子,一个符号都没有
简写代数(syncopated) 丢番图(~250) 开始用缩写字母,但仍是"速记"
符号代数(symbolic) 韦达(1591)→ 笛卡尔(1637) 可以写出"任意的方程"

花拉子米(al-Khwārizmī, 820,al-Jabr —— "algebra" 一词的来源)解一元二次方程时,原文大意是:

"一个平方,与十个它的根,等于三十九迪拉姆。取根数目之半,得五;自乘之,得二十五;加于三十九,得六十四;取其方根,得八;减去根数目之半,得三 —— 此即所求之根。"

翻译成今天的符号,全文就是一行:

\[x^2 + 10x = 39 \;\Rightarrow\; x = \sqrt{(10/2)^2 + 39} - 10/2 = 3\]

一整段话 → 一行符号。 你现在感受到的"公式好难",本质是信息密度难:一行公式压缩了一整段人话,而没人教你解压。

而且这些符号是被一个一个发明出来的,每一个背后都有一个具体的人、一个具体的偷懒动机:

符号 发明者 / 年份 发明动机(真实的)
\(+\;-\) 维德曼 1489 仓库账本上的盈余/亏空记号,先是商业符号,后被数学借用
\(\sqrt{\;}\) 鲁道夫 1525 拉丁文 radix(根)的手写体 r 拉长
\(=\) 雷科德 1557 "我写腻了 is equal to",取两条等长平行线 —— "再没有两样东西比它们更相等"
\(\times\) 奥特雷德 1631 莱布尼茨嫌它像字母 x,坚持用 \(\cdot\)(今天两派仍并存)
\(<\;>\) 哈里奥特 1631(遗著) 开口朝大数
未知数 \(x,y,z\) 笛卡尔 1637 韦达 1591 用元音表未知、辅音表已知;笛卡尔改成字母表末尾=未知,开头=已知
指数 \(x^3\) 笛卡尔 1637 此前要写 cubus,或画三个 x
\(\infty\) 沃利斯 1655 罗马数字里表"很多"的符号变体
\(\int\) 莱布尼茨 1675.10.29 拉长的 s = summa(和)—— 积分号从诞生第一天起就在喊:"我是求和"
\(dx\) 莱布尼茨 1675.11.11 differentia(差)的首字母 —— 差分的 d
\(\dot{x}\) 牛顿 1665 "流数",强调对时间的变化率
\(f(x)\) 欧拉 1734 第一次把"函数"当成可命名的对象
\(\sum\) 欧拉 1755 希腊大写 Sigma = Sum
\(\pi\) 琼斯 1706 / 欧拉 1748 推广 περιφέρεια(周长)首字母
\(e\) 欧拉 1727 很可能只是 exponential,或 a,b,c,d 之后的下一个可用字母
\(i\) 欧拉 1777 / 高斯 1801 推广 imaginarius
\(n!\) 克拉普 1808 为了排版方便(此前写成 \(\lfloor\!\underline{n}\) 这类怪东西)
\(\prod\) 高斯 1812 大写 Pi = Product
\(\partial\) 勒让德 1786 / 雅可比 1841 推广 "圆 d",用来区分"只对其中一个变量偷偷动一下"
\(\lim\) 吕利耶 1786;箭头 \(\to\) 由哈代 ~1908 此前只能写"无限趋近于"
\(\varepsilon,\delta\) 柯西 1821(\(\varepsilon\) = erreur 误差)→ 魏尔斯特拉斯 1860s 严格化 把"无穷小"这个哲学争议翻译成可验证的不等式
矩阵 西尔维斯特 1850 命名,凯莱 1858 成为代数对象 先有"一堆数排成方阵"的用法,两千年后才有名字
\(\in\;\cup\;\cap\;\subset\) 皮亚诺 1888–1889 \(\in\) 取自希腊语 ἐστί("是")的 ε
\(\exists\) 皮亚诺 1897 反写的 Exists
\(\forall\) 根岑 1935 倒写的 All
\(\nabla\) 哈密顿 1837,泰特命名 "nabla" 形似一种希伯来竖琴;吉布斯/亥维赛把它推成向量分析标配
\(\aleph\) 康托尔 1893 希伯来字母第一个,标记无穷的"大小"
求和约定 爱因斯坦 1916 "重复指标就求和" —— 他自嘲这是他"数学史上最大的贡献"
$\langle\psi \phi\rangle$ 狄拉克 1939

看这张表要看出的东西:没有一个符号是"从天上掉下来的规定"。每一个都是某个人嫌麻烦,于是把一段话压成一个记号。 所以读符号的正确姿势永远是:把它解压回那句人话。


🧭 0.6.2 读公式六步法:像读代码一样读公式

数学公式和一段代码是同构的。程序员读陌生代码有一套本能流程 —— 读公式用同一套。

Step 1 · 先做 shape check:每个符号是什么"类型"?

在读含义之前,先读类型:标量?向量?矩阵?函数?算子?集合?分布?

\[\hat{y} = \sigma(W x + b)\]
import torch
# 读公式的第一件事不是"理解",是"标注类型"
x = torch.randn(4)        # 输入:向量,  shape (4,)      —— 小写粗体 → 向量
W = torch.randn(3, 4)     # 权重:矩阵,  shape (3, 4)    —— 大写 → 矩阵
b = torch.randn(3)        # 偏置:向量,  shape (3,)
sigma = torch.sigmoid     # σ:函数 R→R,逐元素作用     —— 希腊字母这里是"函数"不是"标准差"

y = sigma(W @ x + b)      # (3,4)@(4,) -> (3,) ; +(3,) -> (3,) ; σ 不改 shape
print(y.shape)            # torch.Size([3])

类型对不上,公式一定读错了。 这一步能过滤掉 80% 的误读 —— 就像编译器帮你抓住的那 80% 的 bug。

Step 2 · 找"主动词":从外向内读,不要从左向右读

汉语句子先找谓语,公式先找最外层的运算。这才是这个公式"在干什么"。

\[\mathcal{L}(\theta) = -\frac{1}{N}\sum_{i=1}^{N}\sum_{c=1}^{C} y_{ic}\log \hat{p}_{ic}(\theta)\]

从外往里剥:

最外层:  负号 + 平均            → "我要最小化某个平均量"
第二层:  ∑_i  遍历 N 个样本      → "这个量是逐样本算完再平均的"
第三层:  ∑_c  遍历 C 个类别      → "每个样本内部再对类别求和"
最内层:  y·log p̂                → "只有真实类别 (y=1) 那一项活下来"

到这里公式已经读完了:交叉熵 = 对每个样本,取真实类别的 \(-\log\) 预测概率,再平均。 一行代码:

loss = -(y_onehot * p_hat.log()).sum(dim=1).mean()   # 逐符号对应,一一映射

由外向内是关键。从左向右读 \(-\frac{1}{N}\sum\sum y\log\hat p\),你会淹死在下标里; 先看清"这是一个平均",剩下的都是细节。

Step 3 · 分清哑变量与自由变量 —— 这是最大的困惑源

\[S = \sum_{i=1}^{n} a_i \qquad\text{和}\qquad S = \sum_{k=1}^{n} a_k \qquad\text{是同一个东西}\]

\(i\) / \(k\)哑变量(bound variable):它只在 \(\sum\) 内部存在,出了求和号就没有意义。 \(n\)\(a\)自由变量:它们从外面传进来。

这就是 lambda 的参数,改名不改语义 —— λ 演算里叫 α-变换(呼应 Chapter 0.9):

# 哑变量 = 函数的局部参数,改名毫无影响
f = lambda a, n: sum(a[i] for i in range(n))   # i 是哑的
g = lambda a, n: sum(a[k] for k in range(n))   # k 是哑的,f 和 g 完全相同

凡是带"绑定器"的符号,其紧跟的变量都是哑的

绑定器 哑变量 编程对应
\(\sum_{i}\)\(\prod_{i}\) \(i\) for i in ... 的循环变量
\(\int f(x)\,dx\) \(x\) 积分变量 = 被积函数的形参
\(\forall x\)\(\exists x\) \(x\) all(... for x in ...)
\(\max_{\theta}\)\(\arg\min_{\theta}\) \(\theta\) 优化循环里的可变参数
\(\{x : P(x)\}\) \(x\) 列表推导 [x for x in S if P(x)]
\(\lambda x.\,M\) \(x\) lambda x: M

一旦你会分辨"哪个字母是临时工、哪个是从外面传进来的",公式的作用域就清晰了 —— 和读代码找变量作用域是同一个动作。

Step 4 · 量纲/维度检查:加号两边必须是同类东西

  • 加号两边必须同量纲、同 shape。 \(E = mc^2 + v\) 一眼就是错的(能量 + 速度)。
  • \(\exp\)\(\log\)\(\sin\) 的宗量必须无量纲。 所以 \(e^{-t/\tau}\) 里必然有个时间常数 \(\tau\) 来把 \(t\) 除成纯数 —— 看到 \(e^{-x/\lambda}\),你立刻知道 \(\lambda\)\(x\) 同量纲。
  • 比值和平方要跟着量纲走。 \(\mathrm{Var}[X]\) 的量纲是 \(X\) 的平方,所以才需要开根号变成标准差,才能跟 \(X\) 画在同一张图上。
# 用量纲反推陌生公式里某个符号的身份:高斯密度里的 σ 一定和 x 同量纲
# 因为 exp 的宗量 (x-μ)²/(2σ²) 必须无量纲
# 又因为整个密度要积分成 1(无量纲),前面的 1/(σ√(2π)) 必须是 1/量纲(x)

这一步不需要理解公式就能做,却能倒推出符号的身份。 物理学家用它猜公式(呼应 Chapter 0.7),你可以用它读公式。

Step 5 · 代极端值:\(n=0,1\)\(\sigma\to0,\infty\)\(T\to 0\)

公式是抽象的,抽象的东西要审问(呼应 Chapter 0.95 的代入法):

import torch

def softmax_T(z, T):
    return torch.softmax(z / T, dim=-1)

z = torch.tensor([2.0, 1.0, 0.1])
print(softmax_T(z, 1.0))    # tensor([0.6590, 0.2424, 0.0986])            正常
print(softmax_T(z, 0.01))   # tensor([1.0000e+00, 3.78e-44, 0.0000e+00])  T→0 退化成 argmax(一位独大)
print(softmax_T(z, 100.0))  # tensor([0.3366, 0.3332, 0.3302])            T→∞ 退化成均匀分布

三个极端一试,\(T\) 这个符号的身份立刻水落石出:它是"决策锐度"的旋钮。 这比读十行文字描述都快。任何含参数的公式,都先把参数推到两个极端看它退化成什么。

Step 6 · 写成代码跑一遍 —— 唯一的验收标准

能把公式写成一个不用任何数学库的 for 循环,才算真读懂了。

\[\text{Var}[X] = \mathbb{E}[(X-\mu)^2]\]
xs = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]

mu = sum(xs) / len(xs)                         # 𝔼[X]      → 平均
var = sum((x - mu) ** 2 for x in xs) / len(xs) # 𝔼[(X-μ)²] → 平方后再平均
print(mu, var)                                 # 5.0 4.0

# 对拍:库函数必须给出一样的答案,否则是你读错了公式
import torch
t = torch.tensor(xs)
print(t.mean().item(), t.var(unbiased=False).item())   # 5.0 4.0  ✓

"手写 for 循环 vs 库函数对拍" 是检验"我是不是真看懂这个符号"的黄金标准 —— 它无法自欺欺人。


📖 0.6.3 符号 → 代码 总字典

把这张表贴在显示器旁边。读公式时逐符号查,读三个月,就不用查了。

求和 / 求积 / 积分 —— "循环"家族

符号 读作 代码 注意
\(\sum_{i=1}^{n} a_i\) 对 i 从 1 到 n 求和 sum(a[i] for i in range(n)) / a.sum() 数学下标从 1,代码从 0
\(\sum_{i \ne j}\) 跳过对角 mask = ~torch.eye(n,dtype=bool) 极易漏掉的条件
\(\prod_i a_i\) 求积 a.prod() 数值上常改成 a.log().sum().exp() 防下溢
\(\int_a^b f(x)dx\) 求和的连续版 torch.trapz(f(x), x) \(\int\) 就是拉长的 s = summa
\(\oint\) 沿闭合回路积分 首尾相接的 trapz 环路 → 守恒量、绕数
\(\iint,\ \iiint\) 多重积分 嵌套循环 / meshgrid 对应多重 for
\(\mathbb{E}[X]\) X 的期望 x.mean()(蒙特卡洛) 期望 = 概率加权求和,采样后就是平均
\(\mathbb{E}_{x\sim p}[f(x)]\) 在分布 p 下的期望 f(p.sample((N,))).mean() 下标写的是从哪个分布采样

微分 —— "变化率"家族

符号 读作 代码 含义差别
\(\dot{x}\) 牛顿点记法 grad(x, t) 专指对时间求导
\(\frac{dy}{dx}\) 莱布尼茨记法 torch.autograd.grad(y, x) 强调"两个微分的比值",可以约分(换元法的心理支柱)
\(\frac{\partial f}{\partial x}\) 偏导,"圆 d" 多元函数中对单个参数求导 其它变量按住不动
\(f'(x)\) 拉格朗日撇号 同上 撇号也可能表示"另一个变量",看上下文!
\(\nabla f\) 梯度(nabla / del) torch.autograd.grad(f, x) → 向量 标量→向量,指向上升最快方向
\(\nabla \cdot \mathbf{F}\) 散度 sum(∂F_i/∂x_i) → 标量 "这里是源还是汇"
\(\nabla \times \mathbf{F}\) 旋度 反对称组合 → 向量 "这里在打转吗"
\(\nabla^2,\ \Delta\) 拉普拉斯算子 二阶导之和 热传导、扩散、图拉普拉斯的核心
\(J\) 雅可比矩阵 torch.func.jacrev(f)(x) shape = (输出维, 输入维)
\(H\) 海森矩阵 torch.func.hessian(f)(x) 二阶导,曲率 = 牛顿法的地基
\(\delta\)(变分) 泛函的"微分" 最优控制 / 拉格朗日力学 和 Kronecker \(\delta\)、Dirac \(\delta\) 完全不是一个东西
import torch
x = torch.tensor([1.0, 2.0], requires_grad=True)
f = (x ** 2).sum()                      # f = x₁² + x₂²
g, = torch.autograd.grad(f, x)          # ∇f = (2x₁, 2x₂)
print(g)                                # tensor([2., 4.])
# ∇ 这个符号在代码里的全部内容,就是这一行:把标量变成和输入同 shape 的向量

线性代数 —— "shape 流"家族

符号 读作 代码 shape 变化
\(A^{\mathsf T}\) 转置 A.T (m,n) → (n,m)
\(A^{-1}\) torch.linalg.inv(A) 实战中几乎总该换成 solve
\(A^{+}\) 伪逆 torch.linalg.pinv(A) 最小二乘的闭式解
\(\langle u, v\rangle\)\(u\cdot v\)\(u^{\mathsf T}v\) 内积 u @ v (n,),(n,) → 标量
\(u \otimes v\)\(uv^{\mathsf T}\) 外积 / 张量积 torch.outer(u,v) (m,),(n,) → (m,n)
\(A \odot B\) 逐元素积(Hadamard) A * B shape 不变
\(\|x\|_2\) L2 范数 x.norm() 向量 → 标量(长度)
\(\|x\|_1\) L1 范数 x.abs().sum() 稀疏正则
\(\det A\) 行列式 torch.linalg.det(A) 矩阵 → 标量(有向体积)
\(\operatorname{tr} A\) A.trace() 特征值之和
\(\lambda_i,\ v_i\) 特征值 / 特征向量 torch.linalg.eig(A) "被这个矩阵作用后只缩放不转向"的方向
\(A_{ij}B_{jk}\)(爱因斯坦约定) 重复指标即求和 torch.einsum('ij,jk->ik', A, B) einsum 就是爱因斯坦 1916 的记号本身

\(\otimes\)\(\odot\) 这类符号最容易糊 —— 别背名字,背 shape: 外积让维度变多,Hadamard 让维度不变,内积让维度消失。

逻辑 / 集合 —— "断言"家族

符号 读作 代码
\(\forall x \in S,\ P(x)\) 对所有 all(P(x) for x in S)
\(\exists x \in S,\ P(x)\) 存在 any(P(x) for x in S)
\(x \in S\) 属于 x in S
\(A \subset B\) 子集 A <= B(Python set
\(A \cup B,\ A\cap B\) 并、交 A | BA & B
\(\Rightarrow,\ \iff\) 蕴含、当且仅当 not p or qp == q
\(:=\)\(\triangleq\) 定义为(不是等式) = 赋值 —— 左边是新名字,不用去"解"它
\(\propto\) 正比于 差一个常数因子;贝叶斯里表示"归一化常数省略了"
\(\sim\) 服从分布 / 渐近于 x = dist.sample();或 \(n! \sim \sqrt{2\pi n}(n/e)^n\)
\(\sup,\ \inf\) 上确界、下确界 max/min但可能取不到(开区间)
\(\arg\max_x f(x)\) 使 f 最大的那个 x x[f(x).argmax()] —— 返回位置,不是返回值

\(\max\)\(\arg\max\) 的区别,是初学者最常见的翻车点: \(\max_x f(x)\) 返回最高的分数\(\arg\max_x f(x)\) 返回取得最高分的那个选手。 一个是 f(x).max(),一个是 f(x).argmax()


⚠️ 0.6.4 一词多义地图:同一个符号,五种意思

这是"符号看不懂"最真实的原因 —— 不是符号太多,是符号太少,被反复重用。 希腊字母只有 24 个,而数学分支有上百个。

符号 可能的含义(靠上下文消歧)
\(\sigma\) 标准差 / 激活函数(sigmoid)/ 奇异值 / 置换 / 表面电荷密度 / 应力
\(\Sigma\) 求和号 / 协方差矩阵 / 字母表(形式语言)
\(\lambda\) 特征值 / 正则化系数 / 波长 / 泊松参数 / λ 演算的抽象 / 学习率衰减
\(\delta\) Kronecker \(\delta_{ij}\)(相等取 1)/ Dirac \(\delta(x)\)(广义函数)/ 变分 \(\delta J\) / ε-δ 里的小量 / 反向传播的误差项
\(\varepsilon\) 任意小量 / 噪声项 / 强化学习探索率 / 数值稳定项 1e-8 / 介电常数
\(\mu\) 均值 / 测度 / 磁导率 / 动量系数 / 微(\(10^{-6}\)
\(\pi\) 圆周率 / 策略函数(RL)/ 置换 / 平稳分布
\(\theta\) 角度 / 模型参数(ML 中最常见)
\(\rho\) 密度 / 相关系数 / 谱半径 / 密度矩阵
\(\|\cdot\|\) 绝对值 / 复数模 / 集合势 / 行列式($
\(*\) 乘法 / 卷积 \(f*g\) / 共轭 \(z^*\) / 对偶空间 \(V^*\) / 最优解 \(x^*\)
\('\) 导数 / "另一个"变量(\(x'\))/ 转置(部分统计文献)
\(\top\) 转置 / 逻辑真 / 格的顶元素
\(\nabla\) 梯度 / 散度(配 \(\cdot\))/ 旋度(配 \(\times\))/ 联络(微分几何)
\(\cdot\) 乘法 / 内积 / 占位符(\(f(\cdot)\) 表示"这里放一个参数")

唯一的消歧规则:符号本身没有意义,"符号 + 领域 + 位置"才有意义。

具体三招: 1. 看它出现在什么运算里\(\Sigma\) 后面跟下标 \(i=1\) 就是求和,出现在 \(\mathcal{N}(\mu,\Sigma)\) 里就是协方差矩阵。 2. 看它的 shape\(\delta\) 带两个下标(\(\delta_{ij}\))是 Kronecker,带括号(\(\delta(x)\))是 Dirac。 3. 看这一页的第一次出现:论文的规范是首次出现处必须定义。看不懂就往回找定义 —— 找不到的话,那是作者的错,不是你的。


🔬 0.6.5 实战解剖:三个公式,逐符号拆开

按本项目的规矩:现象 → 模拟 → 拆解 → 公式(Chapter 0.7),不是反过来。

案例一:高斯分布 —— 从"高尔顿板"到符号

先看现象:一堆小球从上往下掉,每层随机左右偏一次,落到底部形成一堆。

import torch, matplotlib.pyplot as plt

n_balls, n_rows = 20000, 32
steps = (torch.randint(0, 2, (n_balls, n_rows)) * 2 - 1)   # 每层 ±1,公平的硬币
pos = steps.sum(dim=1).float()                             # 累积左右偏移

plt.hist(pos.numpy(), bins=40, density=True, alpha=.6, label="高尔顿板(模拟)")
mu, sigma = pos.mean(), pos.std()
xs = torch.linspace(pos.min(), pos.max(), 300)
pdf = 1/(sigma*torch.sqrt(torch.tensor(2*torch.pi))) * torch.exp(-(xs-mu)**2/(2*sigma**2))
plt.plot(xs, pdf, lw=2, label="高斯公式")
plt.legend(); plt.show()

先跑出那个钟形,再回头解剖公式

\[p(x) = \underbrace{\frac{1}{\sigma\sqrt{2\pi}}}_{\text{③ 归一化}} \exp\Big(-\underbrace{\frac{(x-\mu)^2}{2\sigma^2}}_{\text{① 标准化距离的平方}}\Big)\]
片段 它在干什么 对应代码
\(x - \mu\) 距离中心多远 xs - mu
\((\cdot)^2\) 左右对称 + 可微(呼应 0.5.1) ** 2
\(/\sigma^2\) 用"自然尺度"去量,使宗量无量纲 / sigma**2
\(\exp(-\cdot)\) 让远处衰减得极快,且永不为零 torch.exp
\(\frac{1}{\sigma\sqrt{2\pi}}\) 让总面积 = 1,\(\sqrt{2\pi}\) 是被逼出来的常数 归一化因子

\(\sqrt{2\pi}\) 不是审美,是积分 \(\int e^{-x^2/2}dx=\sqrt{2\pi}\) 逼出来的账单(那个极坐标换元技巧,正是 Chapter 0.3 的 gaussian_integral_polar.py)。

案例二:注意力公式 —— 现代 AI 里最"吓人"的一行

\[\mathrm{Attention}(Q,K,V) = \mathrm{softmax}\!\left(\frac{QK^{\mathsf T}}{\sqrt{d_k}}\right)V\]

用六步法,只跟 shape 走,两分钟读完:

import torch
n, d_k, d_v = 5, 8, 8                     # 5 个 token
Q = torch.randn(n, d_k)                   # Query:我在找什么
K = torch.randn(n, d_k)                   # Key  :我是什么
V = torch.randn(n, d_v)                   # Value:我能提供什么

scores = Q @ K.T                          # (n,d_k)@(d_k,n) -> (n,n)   ← 每对 token 的内积=相似度
scores = scores / d_k ** 0.5              # 除 √d_k:内积随维度增长 ~√d_k,不缩放 softmax 会饱和
w = torch.softmax(scores, dim=-1)         # (n,n),每行求和为 1        ← 变成"注意力权重分配"
out = w @ V                               # (n,n)@(n,d_v) -> (n,d_v)   ← 按权重把别人的信息加权平均

print(scores.shape, w.shape, out.shape)   # (5,5) (5,5) (5,8)
print(w.sum(dim=-1))                      # tensor([1., 1., 1., 1., 1.]) ✓ 归一化确认

逐符号翻译成人话:

符号 人话 历史血统
\(QK^{\mathsf T}\) 每个查询和每个键的内积 = 相似度 内积 = 投影 = 欧几里得的"夹角"(0.5.4)
\(\sqrt{d_k}\) 尺度校正,避免 softmax 饱和 随机向量内积的标准差 \(\propto\sqrt{d}\) —— 中心极限定理
\(\mathrm{softmax}\) 把任意分数变成概率分布 玻尔兹曼分布(1877)改名换姓
\(\cdot\, V\) 按权重加权平均 期望 \(\mathbb{E}\) 的离散形式

结论:这一行公式的全部内容是 —— "算相似度 → 归一化成权重 → 加权平均"。 三个动作,每个都有两百年历史。吓人的只是符号密度,不是思想密度。

案例三:链式法则 —— 一个 \(\partial\) 引发的百年国耻

\[\frac{\partial L}{\partial w} = \frac{\partial L}{\partial \hat{y}}\cdot\frac{\partial \hat{y}}{\partial z}\cdot\frac{\partial z}{\partial w}\]

莱布尼茨记法的天才之处:它长得就像可以约分\(\frac{\partial L}{\partial \hat y}\cdot\frac{\partial \hat y}{\partial z}\) 中间的 \(\partial\hat y\) "消掉")。 这个视觉暗示不是严格证明,但它让人敢往下推 —— 这就是好符号的全部价值。

import torch
w = torch.tensor(2.0, requires_grad=True)
x = torch.tensor(3.0)

z     = w * x                     # ∂z/∂w = x = 3
y_hat = torch.sigmoid(z)          # ∂ŷ/∂z = ŷ(1-ŷ)
L     = (y_hat - 1.0) ** 2        # ∂L/∂ŷ = 2(ŷ-1)

L.backward()                      # ← 这一行就是那个连乘

manual = 2*(y_hat-1) * y_hat*(1-y_hat) * x     # 逐符号手抄公式
print(w.grad.item(), manual.item())            # 两者相等 ✓ —— 公式读对了

而牛顿的 \(\dot{x}\) 写不出这种链式约分。 英国数学界出于民族情绪坚持点记法一百年,直到 1812 年剑桥的巴贝奇、赫歇尔、皮考克成立"分析学会",打出那句著名口号:

"推行纯粹的 d 主义,反对这所大学的 点时代。" (the principles of pure D-ism in opposition to the Dot-age of the University —— 一句双关:D-ism / deism(自然神论),Dot-age / dotage(老糊涂))

一个符号的选择,让一个国家的数学落后了一个世纪。 这是"符号即思维外骨骼"最贵的一次学费。


🧠 0.6.6 三条习惯:把"看不懂"变成"查得到"

  1. 看到陌生符号,先问"它是什么类型",而不是"它是什么意思"。 标量/向量/矩阵/函数/算子/集合 —— 类型定了,能做什么运算就定了一半。这是 shape check,不是理解力问题。
  2. 看到复杂公式,先找最外层运算,由外向内剥。 一个公式只有一个"主动词"。找到它,你就知道这个公式产出什么;剩下的括号都是它的参数。
  3. 看到任何公式,最后一定要写成能跑的代码,并跟库函数对拍。 手写 for 循环 = 唯一无法自欺欺人的验收。跑通那一刻,符号就从"要背"变成了"我造过"。

再补一条对付一词多义的:符号无意义,符号 + 领域才有意义。 别问"\(\sigma\) 是什么",要问"在这一页里,\(\sigma\) 是什么"。


🎨 0.6.7 可视化与代码:ch00_97_reading_formulas/

脚本 做什么
symbol_timeline.py 数学符号发明编年史时间轴(1489 → 1939),标注发明者与动机
rhetorical_to_symbolic.py 花拉子米原文 ↔ 现代符号 ↔ Python 代码,三栏同步高亮动画
shape_flow_attention.py 注意力公式的 shape 流动图:\((n,d)\to(n,n)\to(n,d_v)\) 逐步可视化
bound_variable_alpha.py 哑变量改名(α-变换)动画:\(\sum_i\)\(\sum_k\) 是同一段代码
gaussian_dissection.py 高尔顿板模拟 → 逐片段点亮高斯密度公式的每个因子
dot_vs_leibniz.py 点记法 vs \(d/dx\) 记法推链式法则,并排展示"能不能约分"
sigma_disambiguation.py 一词多义交互面板:同一个 \(\sigma\) 在 6 个语境中的不同身份
einsum_as_einstein.py 爱因斯坦求和约定 ↔ torch.einsum 的逐指标对照动画
formula_to_forloop.py 输入一个公式,输出手写 for 循环 + 库函数对拍结果

本文小结:数学符号不是门槛,是压缩包。每一个都由某个具体的人,为了少写几个字,在某一年发明出来 —— 莱布尼茨 1675 年 10 月 29 日写下的那个拉长的 s,至今仍在每一篇论文里喊着"我是求和"。

看不懂公式,从来不是因为你笨,而是因为没人给你解压密码。密码就三条:先读类型,由外向内,写成代码。

下期预告:Chapter 0.7 —— 学物理就是学数学,为什么大脑只记得住"有现实意义的事"。