第一讲 · 补充
DeltaMed
内部培训 · 第一讲补充 · 插在 1.1 与 1.2 之间

词是怎么变成数字的

1.1 说模型眼里的世界是一串 token 编号。但编号只是个 ID,没法拿来算。这一段补上中间缺的一环:编号怎么变成一串数字,那串数字为什么带着「意思」,以及大家常听到的「权重」「参数」到底是什么东西。答案全在线性代数里——而且只用到加减、点积、矩阵乘法三样。

位置
第一讲板块 1 · 1.1 之后
时长
约 22 分钟
前置要求
听过 1.1「猜下一个 token」
演示
5 个可交互动画

页内演示的三种标签(与第一讲讲义相同)

真实运行这段数学真的在你的浏览器里算:矩阵乘法、点积、softmax 归一化。你动滑块,结果就跟着重算。
模拟沙盘行为照真实过程复刻,输出是事先写好的。本页没有这一类。
示意数值词的坐标是我为了讲清道理手工摆的,不是从真实模型里取出来的。真实的向量有几千维,没法画;这里画的是二维的示意。看这类演示时,请把它当示意图,不要当测量结果。

所有演示都能用键盘操作。整页可直接打印,打印时按钮会自动隐藏。

引子

1.1 留下的一个洞

2 min

1.1 那张循环图里,「全部文本」进去、「一张概率表」出来,中间只写了四个字:一次前向计算。这一段就是把那四个字拆开。拆开之后应该能回答三个问题:「1750 亿参数」数的是什么为什么它能做类比、能跨语言为什么它「知道」的东西没法指着某一条说「存在这里」

前提先对齐

编号不能算,所以第一步一定是换成数字

1.1 的 Demo 1 里,「头痛」被切成一个 token,编号比如 15071。这个编号和 USUBJID 一样,只是个 key,它的大小没有任何含义——15071 不比 15070 更「头痛」。而模型内部只会做一件事:算数。所以进模型的第一步,永远是把每个编号换成一串数字

那串数字叫向量,串的长度叫维度。整段补充只讨论三个问题:这串数字从哪来(第 1 节)、它为什么带着意思(第 2、3 节)、模型拿它做什么(第 4、5 节)。

SAS 锚点

一个向量就是一条 observation,有 d 个数值变量:dim1dim12288。「12288 维」不比「一个数据集有 12288 列」更神秘。线性代数是对这种整表做运算的语言——整列相加、整行做加权求和——你在 PROC IML 或者 PROC REG 里已经见过它。

第 1 节

查表:编号换成向量

4 min

这一节只做一件事:让「嵌入」(embedding)这个词落地。它不是什么算法,它是一张表——词表里每个 token 占一行,每行是一串数字。把编号换成向量,就是拿编号去这张表里取出那一行

1.14 min

嵌入表:词表有多少行,它就有多少行

这是模型里第一批「参数」——而且是最容易看懂的一批

模型开机时,手里有一张固定的表:行数 = 词表大小(几万到二十几万),列数 = 维度(几千到一万多)。表里每一个数字都是训练时调出来的,出厂之后就不变了。一句话进来,切成 token,每个 token 拿编号去表里查出自己那一行,句子就从「5 个编号」变成了「5 行 × d 列的数字表」。这张数字表才是模型真正读到的输入。

Demo V1查表:一句话怎么变成一张数字表示意数值

点上面任意一个 token,看它去表里取哪一行;点「整句」看五个一起取出来。这里只画 8 列,真实模型是几千到一万多列;表里的数字是为演示编的。

向量长度(列数) 8 (示意)
嵌入表 · 词表里每个 token 一行(只画了 9 行,真实有几万行)
取出来的向量 · 模型真正读到的输入
还没取任何一行
词表大小 V50,257
维度 d12,288
这张表的参数量 V×d6.2 亿
占全模型 1750 亿的0.35 %

四个数字来自 GPT-3 的论文(2020 年,结构全部公开,所以数字凑得整)。当前的商用模型(Claude、GPT-4 之后的 GPT 系列)不公开这些数字;开源模型(Llama、Qwen 等)公开,量级类似:词表十几万,维度几千到一万多。

从这个演示能直接读出的三件事 一、「嵌入」就是查表,没有别的。不是算法、不是模型「理解」了这个词,是拿编号去取一行数字。PROC FORMAT 也是查表——区别只是这里取回的不是一个值,是一整行。
二、这一行数字是「参数」。你听到「参数」「权重」的时候,第一批就是它:几万行 × 几千列的一张表,每个格子一个数,训练时被反复微调。第 4 节会数清楚剩下的 99.65% 在哪。
三、表里没有任何一列叫「词性」「褪色」「疼痛程度」。列没有名字,也没人给它们定义——它们的含义是训练中长出来的,单看一列几乎没法解释。这就是「知识没法指着说存在哪一条」的第一层原因:一个词的意思,散在几千个数字里。
第 2 节

位置:意思相近,坐标就相近

4 min

一行 12288 个数字,等价于12288 维空间里的一个点。人画不出 12288 维,但二维、三维里的直觉都能搬过去。这一节的结论只有一句:训练做的事,就是把每个词的点挪到「意思相近的词挨在一起」的位置。

2.14 min

训练前是一团随机的点,训练后自动分了堆

没有人告诉它「这几个是症状、那几个是药」——堆是自己长出来的

模型出厂前,嵌入表里填的是随机数:每个词是平面上一个随机位置的点,谁和谁都不挨着。然后开始训练——反复做「猜下一个 token」,猜错了就把相关的点各挪一点点。几万亿 token 做下来,在相似上下文里出现的词,会被一次次推到一起。「头痛」和「恶心」总出现在「患者服药后出现 ___」后面,所以它们最后靠得很近。

Demo V2看着它分堆:随机初始化 → 训练示意数值

先点任意一个词,看它「最像」的邻居是谁——训练前的邻居是随机的。然后点「训练」,等点停下来再点同一个词。二维只是投影:真实模型里这些点在几千维空间里分堆,画不出来,但「挨得近 = 像」这条直觉不变。

17 个词在二维平面上的位置(示意)
与所选词的余弦相似度 · 1 = 同向,0 = 无关,−1 = 反向
还没选词。点左边任意一个点。
训练轮次0
猜错程度(离目标的平均距离)

「猜错程度」是这个演示里真算的:每个点到它训练完成位置的平均距离。真实训练里这个数叫损失(loss),衡量的是「下一个 token 猜错的程度」,含义一致,算法不同。

读懂这个演示 一、「像」是可以算的。两个向量的夹角越小越像,用夹角的余弦当分数:同向是 1,垂直是 0,反向是 −1。这个分数叫余弦相似度,第二讲 RAG 检索文档时用的就是它——把你的问题和文档段落都变成向量,找余弦最大的几段。
二、类别是长出来的,不是标出来的。勾上右上角的复选框:颜色是我标的,模型的训练数据里没有「这是症状」这种标签。它只是把常在相似上下文里出现的词推到一起,堆就形成了。这就是「没有理解,但有结构」。
三、这也是它跨语言的原因。多语言模型里,「头痛」和 headache 的点几乎重合——因为它们出现在同样的上下文里。你用中文问、它引英文资料答,靠的就是这个。
SAS 锚点

余弦相似度和 PROC CORR 算的 Pearson 相关系数是近亲:把两列先各自减去均值,再算夹角余弦,就是 Pearson 相关。你已经会读 0.9 和 0.1 的区别了,这里一样。

第 3 节

方向:关系是一根箭头,可以平移

4 min

位置代表意思,那两个位置之差代表什么?代表「从这个词到那个词的关系」。关键性质是:同一种关系,在空间里是同一根箭头——「男人→国王」和「女人→王后」几乎平行等长。所以向量可以加减,加减出来的是「意思的加减」。这一节就演示这件事,以及它失灵的时候长什么样。

3.14 min

国王 − 男人 + 女人 ≈ 王后

最著名的一个例子,2013 年 word2vec 论文里就有;换成 SDTM 和 ADaM 也一样成立

把「国王」的坐标减去「男人」的坐标,得到一根箭头,含义大致是「王权」。把这根箭头原封不动平移到「女人」上,箭头尖落在哪?落在「王后」旁边。这不是模型「懂」什么是王权——是训练把「男人/国王」和「女人/王后」摆成了平行四边形,而平行四边形是加减法能描述的东西。

Demo V3向量加减 = 意思加减示意数值

选一组类比,一步一步点,看右边的坐标算式怎么和左边的箭头对应。最后试「自己搭」一组毫无道理的组合——注意它照样会给你一个「最近的词」

类比
① 标出 A② 画 A − B 的箭头③ 平移到 C 上④ 找最近的词
二维示意平面
同一件事,用坐标写出来
读懂这个演示 一、右边的算式是全部真相。「国王 − 男人 + 女人」在模型里就是两列数字逐个相减再相加,没有别的步骤。「意思能加减」听着玄,落到数字上是小学算术。
二、结果是「≈」不是「=」。算出来的点落在王后旁边,不是正好压在上面;最后一步是「在词表里找离这个点最近的词」。这一步永远会给出一个答案,哪怕那个点周围什么都不该有。
三、所以「自己搭」那组才是这一节的重点。「巴黎 − 男人 + AE」没有任何意义,但它照样返回一个最近的词,语气和正确答案一模一样。这就是 1.4 讲的幻觉,在几何上的样子:概率表里没有「这里什么都没有」这个选项,只有「谁最近」。
往第二讲埋的线

ADAE − AE + LB ≈ ADLB 这组不是我编来讨好大家的:在真实的代码语料上训练过的模型,确实会把 SDTM 域和对应的 ADaM 数据集摆成平行关系,因为它们在几十万份 spec 和程序里成对出现。第三讲讲 Coding Agent 时,它能「顺手」把你写给 AE 的逻辑改成 LB 版本,几何上靠的就是这根箭头。

第 4 节

矩阵:「权重」就是一张把点搬家的表

5 min

前三节讲的是输入长什么样。这一节讲模型拿它做什么:一层网络 = 一个矩阵乘一次 + 一次很简单的弯折。「1750 亿参数」数的就是这些矩阵里的格子数。讲完这一节,「参数」「权重」「层」三个词应该都变成能指着说的东西。

4.15 min

矩阵乘向量 = 给整个平面换一套坐标

四个数字就能旋转、拉伸、压扁一个平面;几千 × 几千个数字,就是模型的一层

拿一个二维点 (x, y),乘一个 2×2 的矩阵,得到一个新点:x′ = a·x + b·yy′ = c·x + d·y。就这两行算式。它的妙处在于对平面上所有点用的是同一套 a b c d——所以它不是挪一个点,是把整张平面一起旋转、拉伸、剪切。模型里的每一层,本质上就是拿一个几千 × 几千的矩阵,给所有 token 的向量集体换一套坐标。

Demo V4亲手调一层「权重」:四个数字搬动整个平面真实运行

拖动 a b c d 四个滑块,或点预设。网格、两根基向量和四个词一起变——它们用的是同一个矩阵。矩阵乘法是真算的;词的坐标沿用第 3 节的示意位置。最后勾上「弯折」,看为什么只有矩阵不够。

预设
平面 · 灰色是原网格,彩色是矩阵搬过之后
这一层的全部参数:4 个数字
面积倍数 ad − bc1.00
信息可逆 · 没丢
读懂这个演示 一、参数 = 矩阵里的格子。这一层有 4 个参数。真实模型一层的矩阵是 12288 × 12288,即 1.5 亿个格子;一层里有好几个这样的矩阵,96 层叠起来——下面那张表会把 1750 亿一个不差地数出来。
二、训练 = 调这些数字。你刚才手动拖滑块让四个词落到想要的位置;训练就是让机器自动做这件事,判据是「下一个 token 猜得准不准」,一次挪一点点,挪几十万次。
三、「压成一条线」那个预设是关键。面积倍数变成 0,所有点被压到一条线上,两个不同的词落到了同一个位置——信息丢了,而且回不来。模型里每一层都在做取舍:保留对猜下一个 token 有用的差别,压掉没用的。
四、为什么要弯折。两个矩阵连乘还是一个矩阵——不管叠多少层,纯矩阵只能做「旋转拉伸剪切」这一类事。在层与层之间加一次「负数归零」这种极简单的弯折,叠起来就能拟合任意复杂的形状。「神经网络」= 矩阵、弯折、矩阵、弯折……重复几十到上百次。

把 1750 亿数出来

拿 GPT-3(2020 年论文,结构公开)算一遍。它的每一层有两部分:注意力(让每个 token 的向量去看其他 token 的向量,用四个 d×d 的矩阵)和前馈(两个矩阵,先把维度放大四倍再缩回来)。数格子:

部件形状格子数×小计
嵌入表(第 1 节)50,257 × 12,2886.18 亿16.2 亿
注意力 · 每层四个矩阵4 × (12,288 × 12,288)6.04 亿96 层580 亿
前馈 · 每层两个矩阵2 × (12,288 × 49,152)12.08 亿96 层1,160 亿
最后一步:向量 → 词表分数(第 5 节)12,288 × 50,2576.18 亿1(常与嵌入表共用)0 – 6.2 亿
合计≈ 1,750 亿

加上位置编码、偏置、归一化系数这些零头,正好是论文报的 175B。「参数」这个词从此可以直译为「矩阵里的格子总数」。当前一代商用模型的数字不公开,但结构是同一套:一张嵌入表 + 几十到上百层「矩阵 + 弯折」+ 一张回词表的表。

SAS 锚点

训练大模型和 PROC LOGISTIC 迭代拟合是同一件事。LOGISTIC 从一组初始 β 出发,每次沿着让似然更大的方向挪一步,日志里那几行 Iteration History 就是它。大模型没有闭式解,也是这么迭代——区别只是 β 从十几个变成几千亿个,「拟合的目标」是猜对下一个 token,迭代几十万步,跑几个月,烧掉几万块显卡。「权重」= β,「训练」= 拟合,「损失」= 拟合得多差。

注意力,只说一句

表里的「注意力」是这一代模型区别于旧模型的核心部件,但机制并不神秘:每个 token 的向量和句子里其他 token 的向量做点积(第 2 节的「像不像」),得分高的就多搬一点它的信息过来。所以「上下文」对模型的作用是字面意义的:前面每个词的向量都被按相关度加权、混进当前词的向量里。1.1 说「每生成一个 token,前面所有 token 都要重算一遍」,重算的就是这批点积。板块 3 的「中间丢失」也是从这里来的——不展开,知道它是点积就够。

第 5 节

回到概率表:最后一步也是点积

3 min

几十层矩阵之后,句子最后一个位置手里有一个向量。1.1 那张「概率表」就是从这个向量来的:拿它和词表里每一行做点积,谁的分数高谁概率大。这一节把循环闭上。

5.13 min

一个向量 × 整张词表 = 一列分数 → softmax → 概率

这一步用的表,和第 1 节的嵌入表形状一样、常常就是同一张

最后那个向量叫「隐状态」,它的方向大致指向「接下来该出现什么样的词」。把它和词表里每个词的向量做点积——方向越一致分数越高——得到 5 万个分数,再用 softmax 把分数压成加起来等于 1 的概率。1.1 Demo 2 里你拉温度时重算的那张表,就是这样来的。

Demo V5拖动隐状态,看概率表跟着变示意数值

拖左图的箭头尖(或用滑块)改变隐状态的方向和长度,右边的概率表实时重算。词的坐标是第 2 节的示意位置;点积和 softmax 是真算的。三个预设对应三种上下文。

患者服药后出现
上下文
方向
80°
长度
1.60
词表里的 10 个词 + 隐状态(青色箭头,可拖)
分数 = 点积 · 概率 = softmax(分数)

读懂这个演示 一、概率表不是查出来的,是比出来的。没有任何一步是「去知识库里查下一个词」——是一个向量和 5 万个向量各做一次点积。1.1 说「它的知识全压在参数里,没有一条能指着说存在哪」,现在可以说得更具体:知识是「隐状态会指向哪个方向」,散在前面几十层矩阵的所有格子里。
二、长度决定「自信」,方向决定「内容」,两者独立。把长度拉到 3,概率会集中到最像的一两个词上;拉到 0.3,十个词几乎均分。而这和「方向对不对」毫无关系——第四个预设「模型没把握」就是一个指向空档的方向,短了就是摊薄,长了照样自信。这是 1.4「自信和正确是两件事」的几何版。
三、温度就是除长度。1.1 Demo 2 的温度参数,数学上就是把这里的分数统一除以 T,等价于缩放箭头长度。现在你知道它为什么只改变「敢不敢选第二名」、不改变知识了。
收束

整条流水线,和三句话

2 min
全景回到 1.1

1.1 那张图里「一次前向计算」四个字,现在长这样

token 编号 15071, 2231, … 查嵌入表 V 行 × d 列 第 1 节 · 6 亿参数 n 个向量 n 行 × d 列 矩阵 · 弯折 · 矩阵 · 弯折 × 96 层 注意力:向量间点积 前馈:矩阵 + 弯折 第 4 节 · 1,740 亿参数 最后位置的向量 隐状态 · 1 × d 与词表逐行点积 第 5 节 · 与嵌入表共用 V 个分数 logits softmax 压成加起来 = 1 一张概率表 → 1.1 的采样 带方框底色的三处就是「参数」所在: 两张查表(黄)+ 几十层矩阵(青)。中间所有白框都是流过去的数据,不存任何东西。这就是「知识没法指着某一条说存在哪」的完整解释。
把这张图和 1.1 的循环图拼起来,就是全部。概率表出来之后采样一个 token,追加到输入末尾,回到最左边的「token 编号」,再走一遍。
词 → 向量:意思就是位置

嵌入是查表;训练把常在相似上下文里出现的词推到一起。相似度可以算,用的是夹角余弦——第二讲的 RAG 检索靠它。

第 1、2 节
关系 → 方向:向量能加减

同一种关系是同一根箭头,所以类比能成立、跨语言能成立。但「找最近的词」永远有答案——这是幻觉的几何版。

第 3 节
权重 → 矩阵:参数就是格子数

一层 = 矩阵 + 弯折;1750 亿是格子总数。训练 = 迭代拟合。最后一层和词表逐行点积,长度管自信,方向管内容,两者无关。

第 4、5 节
回到 1.1 那句「记原理,别记参数」

这一段讲的全部是原理层:向量、点积、矩阵、softmax。它们从 2013 年的 word2vec 到今天没有变过,各家模型的差别在矩阵的大小、层数和训练数据,不在这套算术本身。所以这一段的内容不用标日期——除了那几个 GPT-3 的具体数字。

附录

术语表与预设问答

只列这一段新出现的词。第一讲讲义的术语表里已有的(token、上下文窗口、温度)不重复。

术语表

向量 vector
一串有序的数字。一条有 d 个数值变量的 observation;也是 d 维空间里的一个点。
维度 dimension
那串数字的长度,也就是列数。当前模型几千到一万多。单独一列通常没有可解释的含义。
嵌入 embedding
把 token 编号换成向量的那张表(V 行 × d 列),或者查表这个动作本身。也泛指「把一段文字变成一个向量」。
点积 dot product
两个等长向量对应位置相乘再求和,得一个数。方向越一致越大。注意力和最后一步「向量 → 分数」用的都是它。
余弦相似度 cosine similarity
点积除以两个向量的长度,即夹角的余弦。−1 到 1。去掉了长度的影响,只看方向。RAG 检索的默认度量。
矩阵 matrix
一张 m 行 × n 列的数字表。乘一个向量 = 给它换一套坐标(旋转、拉伸、剪切、投影的组合)。
参数 / 权重 parameter / weight
所有矩阵和嵌入表里的格子,训练时被调、推理时不变。「1750 亿参数」= 格子总数。等价于回归里的 β。
层 layer
一次「矩阵 + 弯折」。当前模型几十到上百层,每层里又有注意力和前馈两部分。
弯折 / 激活函数 activation
层与层之间的非线性一步,最简单的是「负数归零」(ReLU)。没有它,叠多少层都等于一个矩阵。
logits / softmax
logits 是词表里每个词的原始分数(点积结果);softmax 把一列分数压成加起来等于 1 的概率。温度 = 分数统一除以 T 再 softmax。
隐状态 hidden state
某个 token 位置经过若干层之后的向量。最后一个位置的隐状态决定下一个 token 的概率表。
损失 loss
训练时衡量「猜得多差」的一个数。训练 = 迭代地调参数让它变小。等价于拟合里的负对数似然。

预设问答

真实的向量几千维,你画的是二维,这算不算骗人?

是投影,不是编造。几千维空间里的「挨得近」「平行」「夹角小」这些关系,投到二维仍然是这些关系——就像三维物体的影子仍能看出形状。但要说清两点:投影会丢信息(几千维里分得开的两团,二维里可能重叠);本页所有坐标是我手摆的,不是从真实模型里降维出来的。真要看真实数据,可以用开源模型的嵌入表配合 t-SNE / UMAP 画,结论一致。

这些坐标是谁定的?维度有名字吗?

没人定,也没名字。出厂前是随机数,训练中被「猜下一个 token 猜错了就挪一点」推到现在的位置。单独看一列几乎不可解释——「第 3071 列」不对应「疼痛程度」这样的东西;意思散在几千列的组合里。这也是「知识没法指着某一条说存在哪」的根源。

两个不同模型的向量能拿来比吗?

不能直接比。每个模型有自己的坐标系,同一个词在 A 模型和 B 模型里的数字毫无关系。所以第二讲做 RAG 时有一条铁律:存文档时用哪个嵌入模型,检索时必须用同一个,中途换模型要全部重算。

既然是查表加矩阵乘法,为什么它能「推理」?

诚实的回答是:这个问题目前没有完整的理论答案。能说清的是机制——几十层「矩阵 + 弯折」叠起来可以拟合极复杂的函数,而「猜下一个 token」这个任务逼着它把语法、常识、逻辑的规律都压进参数里,因为不压进去就猜不准。它表现出的「推理」是这种拟合的结果,不是另外装了一个推理模块。1.4 讲的所有边界(算数不准、会编造)也都从这里来。

这和第二讲的 RAG 到底什么关系?

RAG 的检索环节就是第 2 节:把你的文档切块(第一讲 3.2 的切块),每块过一次嵌入模型变成一个向量存起来;提问时问题也变成向量,算余弦相似度,取最像的几块塞进上下文。「向量数据库」就是一张存了很多向量、能快速找最近邻的表。听完这一段,第二讲的 RAG 应该没有新概念。

「弯折」为什么这么重要?多叠几层矩阵不行吗?

不行,这是线性代数的一条定理:矩阵乘矩阵还是矩阵。叠一百层纯矩阵,等价于一层。它们只能做旋转、拉伸、剪切、投影这一类「直的」变换,画不出任何弯的边界。层间加一次极简单的非线性(负数归零),叠起来就能逼近任意函数。Demo V4 勾上那个复选框,看网格怎么被折起来,就是这件事的最小版本。