模型是怎么跑起来、又怎么变聪明的:从一次推理到一次训练的后端视角拆解
你在一台 8 核 16G 的机器上,curl 了一下 https://api.deepseek.com/chat/completions,等了三秒钟,收到一段流畅得像人写的回答。
你心里可能闪过一个问题:云端那台机器,在这三秒钟里到底干了什么? 它打开了一个文件吗?跑了一段代码吗?查了数据库吗?还有那个更玄的问题:它是怎么”学会”这些的?
前两篇文章(《大模型无状态》《从大模型到 Agent》)讲的是”壳”——客户端怎么反复重发历史、Agent 怎么拼循环和工具。今天把镜头往里推一层,讲那个一直被一笔带过的”核”:模型自己是怎么算的,又是怎么被训练出来的。
这篇不用一个公式,全程拿后端微服务那套东西当翻译器。读完你会得到一个可以随时复用的心智模型:
一次推理 = 一次只读的前向计算;一次训练 = 一次改参数的批量迭代。
把它想象成一个部署在 GPU 上的、参数写死的”只读服务”,训练就是它的”持续发布”——这个类比会贯穿全文。
第一部分 · 模型本身怎么跑起来(推理 Inference)
1. 模型 = 一堆数字(权重)
先打破一个幻觉:模型不是”代码”,至少主要不是。
一个”大模型文件”,剥开看,绝大部分是几十亿甚至几千亿个浮点数。这些数字有一个统一的名字叫权重(weight / parameter)。DeepSeek-V3 这类模型常被标注为 “671B”,那个 B 是十亿(billion),意思是这个模型有 6710 亿个参数。7B 就是 70 亿个。
类比到后端:一个微服务的”行为”由两部分决定——代码(固定写死的处理逻辑)和配置(可以改的参数)。模型也一样:
| 后端 | 模型 | 说明 |
|---|---|---|
| 代码(Controller/Service 的套路) | 架构(Transformer 层的结构) | 固定不变,所有同类模型共用 |
| 配置(连接串、阈值、开关) | 权重(几十亿个数字) | 决定”具体怎么答”,是训练学出来的 |
代码告诉你”怎么算”,权重告诉你”算出什么”。 同样是 Transformer 这套架构,权重换一套,它就从”聊天机器人”变成”写代码的”、再变成”写诗的”——就像同一套 Spring Boot 代码,换一份配置,就能连不同的库、走不同的路由。
这几个数字占多大地方?一个参数用 16 位浮点(FP16)存就是 2 字节,用 8 位整数(INT8)存就是 1 字节。粗算一下:
| 模型规模 | 参数量 | FP16 大约占用 | INT8 大约占用 |
|---|---|---|---|
| 7B | 70 亿 | ~14 GB | ~7 GB |
| 70B | 700 亿 | ~140 GB | ~70 GB |
| 671B | 6710 亿 | ~1.3 TB | ~670 GB |
这就是为什么大模型”贵”:它不是一个程序,是一张大到必须用多张显卡才能装下的参数表。 一张消费级显卡显存也就 24G~80G,671B 的模型得用好几张卡并行才装得下。
而推理这件事,关键恰恰是:整个过程不”改”任何一个数字,只”读”它们。 这直接呼应上一篇说的”无状态”——模型推理是一个纯只读的过程,参数表就是那份只读的”代码+配置”。
2. 一次推理 = 一次前向计算(Forward Pass)
你发的那句 “帮我写一个冒泡排序”,到模型里,会经历一个非常固定的流水线:
一段文字 → 切成 token → 查表转成向量
→ 过几十层 Transformer(层层矩阵乘法 + 非线性)
→ 得到"下一个 token 该是谁"的概率表
→ 采样挑出一个 token
→ 拼回输入,再从头算下一个 token …… 直到吐出终止符
这个过程叫前向计算(forward pass)。类比后端,它就像一条”固定拓扑、权重写死”的处理链路:
请求(token) → 网关(Embedding) → 服务A(Transformer层1) → 服务B(层2) → … → 服务N(层N) → 出口(输出头) → 响应(下一个token)
区别只有一点:你熟悉的微服务是”每层逻辑各不相同、几十个服务”,模型是”同一层结构重复几十次、上百层”。 它把一件事——”看全句、算每个词该不该出现在这里”——反复做了一百遍,每遍的权重都不一样。
但注意一个反直觉的点:模型不是一次性把整句回答算出来的,而是一个字一个字”挤”出来的。
输入: "帮我写一个冒泡排序"
↓ 前向计算
输出: "下" (拼回去)
↓
输入: "帮我写一个冒泡排序下"
↓ 前向计算
输出: "面" (拼回去)
↓
输入: "帮我写一个冒泡排序下面"
↓ … 反复循环 …
直到输出一个特殊的"终止符",才停
这个”输出一个、拼回去、再算下一个”的机制叫自回归(autoregressive)。类比后端,就像一段循环:每次 RPC 返回一个字符,你把它追加进请求体,再发下一次 RPC,直到服务端返回一个”end”标志。这就是为什么大模型回答长问题会”一个字一个字蹦出来”,也是为什么它天生就慢——一个 500 字的回答,等于 500 次完整的前向计算。
3. 三件套:Embedding → Transformer 层 → 输出头
把上面那条流水线拆成三块积木,模型内部就没什么神秘的了。
3.1 Embedding:把字变成向量
模型不认识”字”,它只认数字。第一步是把每个 token 查表,变成一个向量——一串固定长度的数字(比如 4096 个 float)。
类比后端:这就是一次特征编码。就像你把”用户等级”这个枚举编码成一个 one-hot 向量、把”IP 地址”转成一个整数,Embedding 做的事是:把”猫”这个 token 映射成 [0.12, -0.45, 0.88, …] 这样一串数字。有意思的是,意思相近的词,编码出来的向量方向也相近——”猫”和”狗”的向量,比”猫”和”公司债”的向量更”像”。这是训练阶段自然涌现出来的,先记着,后面会再碰到。
3.2 Transformer 层:整篇的重头戏
Embedding 之后,向量会穿过几十上百层一模一样的 Transformer 层。每一层里有两个关键子模块,工程师只需要记住两句话。
(1)自注意力(Self-Attention):让每个词”看一眼”其他所有词
这是 Transformer 最核心、也是名字最唬人的部分。它回答的问题是:句子里的每个词,应该从其他哪些词那里”借”多少信息?
拆到底层,它靠三张参数表,分别叫 Q(Query,查询)、K(Key,键)、V(Value,值)。名字看着吓人,翻译成后端就亲切了:
它本质上就是一次”关联查询 + 加权聚合”。
想象一个句子 “小明 打了 篮球”,里面的每个 token 都是表里的一行。对当前这个词(比如”打”),模型做三件事:
- 拿这个词的 Q,去和整句里每个词的 K 算”相似度”(类比:拿查询条件去匹配每个 key);
- 把相似度换算成权重(谁跟我越相关,谁的权重越大);
- 用这套权重,把每个词的 V 加权求和,得到这个词”更新后”的表示。
"打" 这个词,Q = 我在找什么?
├─ 和 "小明" 的 K 算相似度 → 权重 0.6
├─ 和 "打了" 的 K 算相似度 → 权重 0.1
└─ 和 "篮球" 的 K 算相似度 → 权重 0.3
↓ 加权求和
"打" 的新表示 = 0.6 × V(小明) + 0.1 × V(打了) + 0.3 × V(篮球)
这样,”打”这个词的向量里,就”混进”了主语”小明”和宾语”篮球”的信息。这就是为什么模型能理解”它“指的是谁、能看出”这句里哪个词在修饰哪个词”——因为它让每个词都和整句里的其他词做了一次带权重的信息交换。
类比:这就像 SQL 里,你想知道”订单”的完整信息,得 JOIN 一下”用户表”和”商品表”,把分散的信息聚到一行。自注意力就是给每一个 token 做一次全表 JOIN,只不过”关联权重”不是写死的 ON 条件,而是训练学出来的、可以有小数的”软连接”。
顺带说一句:这套机制有个名场面级的代价——每个词都要和所有词比一遍,句子有 n 个词,就要做 n×n 次比较。 这就是上一篇讲”上下文窗口为什么不能无限大”时提过的 O(n²) 成本,也是模型”长文又贵又慢”的根源。
(2)前馈网络(FFN):把借来的信息”消化”一遍
注意力做完了”信息交换”,接着过一个前馈网络——简单说就是两层全连接,中间夹一个非线性激活。它的作用可以理解成”把刚聚合来的信息重新加工一遍”:升维、变换、再降维。
类比:注意力是”把多方数据 JOIN 成一行”,FFN 是”对这一行再做一次业务计算”。注意力负责”看到谁”,FFN 负责”想明白看到的是啥”。
(3)两个让网络不崩的小零件:LayerNorm 与残差连接
这俩不是主角,但工程师会心一笑:
- 残差连接(Residual):每层算完,把”输入”原样加回”输出”。类比:一条旁路直连,保证就算这层算岔了,原始信息也不会丢。
- LayerNorm:把数值压到一个稳定的范围。类比:限流/归一化,防止数值一层层传下去越滚越大、最后溢出。
你只需要知道:它们是”稳定器”,让几十上百层能顺利堆起来而不爆炸。
3.3 输出头:把向量变成”下一个字该是谁”
过了几十层,最后一个向量被送进输出头。它的任务是回答一个具体问题:在所有可能的 token(比如 10 万个)里,下一个字最可能是谁?
它会把那个向量换算成一张”概率表”——每个候选 token 一个概率分。这个”把分数换算成概率”的动作叫 softmax(记名字就行,不写公式):分数高的,概率被放大;分数低的,被压得更低;最后所有 token 的概率加起来正好是 1。
然后就是采样——从这张概率表里”抽”一个 token 出来。这里有两个工程师天天见的旋钮:
| 旋钮 | 作用 | 类比 |
|---|---|---|
| temperature(温度) | 调概率分布的”陡峭度”:越低越只挑最高分的(保守),越高越敢碰低分项(发散) | 像”随机打散 vs 严格排序”,温度高 = 更容易抽到冷门答案 |
| top-p | 只从概率最高的前若干个 token 里抽 | 像”只考虑 Top N 候选,砍掉长尾” |
为什么要有随机性?因为同一个输入 + 同样的权重,如果每次都挑最高分,答案就永远一样。 加了采样,模型才能”同一句话答出十个版本”。你在界面上看到”重新生成”每次结果不同,就是这个旋钮在起作用。
4. 为什么非要 GPU:全是矩阵乘法
把上面所有环节串起来,你会发现一个朴素的事实:推理的本质,是海量的矩阵乘法(GEMM)。 一句话进来,就是几万次”大矩阵 × 大矩阵”。
为什么 CPU 不行?不是 CPU 算得慢,是”单核再快,也架不住要同时做一万次同样的乘法”:
| CPU | GPU | |
|---|---|---|
| 核心数量 | 少(几核到几十核),单核极强 | 多(几千上万个),单核弱但海量 |
| 适合 | 串行、逻辑分支多、顺序依赖强 | 海量相同运算、可并行 |
| 类比 | 一个专家,一件事做得又快又准 | 一万个小工,同时抄一万道一模一样的算术题 |
矩阵乘法恰好是”一万道一模一样的算术题”——没有任何分支判断,就是乘和加,可以完美拆开并行。所以 GPU 上几千个核心同时开跑,一次前向计算就能在毫秒级完成。
真正的瓶颈往往不是算力,是显存(VRAM):权重、中间结果、缓存都得住在显存里,装不下就得靠多卡、量化、或者直接跑不动。这也是为什么 671B 的模型普通人机器上根本起不来——不是 CPU 不够快,是显存根本塞不下那张 1TB 的参数表。
5. KV Cache:推理的”缓存”(工程师最亲切的一节)
回到第 2 节那个”一个字一个字挤”的自回归。这里藏着一个巨大的浪费:
算第 2 个字的时候,第 1 个字的所有计算被原封不动地重算了一遍;算第 100 个字的时候,前 99 个字的计算被重算了 99 遍。
就像每次请求都从头算一遍全量报表,哪怕其中 99% 的数据上一秒刚算过。工程师的第一反应一定是:缓存它!
于是有了 KV Cache。在自注意力里,每个 token 的 K 和 V 是”只要算出来就不变”的(因为权重是只读的,前面的 token 不会因为后面来了新 token 而改变自己的 K/V)。所以工程上就把已生成 token 的 K、V 存进显存,下次算新 token 时只算新增那一个,历史部分直接读缓存。
没有 KV Cache:算第 100 个字 → 重算前 99 个字的所有 K/V + 第 100 个
有 KV Cache: 算第 100 个字 → 只算第 100 个字的 K/V,前 99 个直接读缓存
这就像一个”按请求增量补算、历史结果常驻内存”的服务:KV Cache 就是模型推理的 Redis。 它用显存换时间——历史越长,省的时间越多,但占的显存也线性上涨。这也正是上一篇《上下文窗口》里说的”KV Cache 随长度线性增长、超长窗口 = 显存爆炸”的那个东西,两篇在这里合上了。
6. 工程侧:量化、批处理、服务化
到这里,”模型怎么跑起来”的算法部分讲完了。真到生产,还有三个纯工程的招,全是后端熟悉的味道。
(1)量化(Quantization):降精度换吞吐
权重默认是 FP32(4 字节)或 FP16(2 字节)。量化就是把它压成 INT8(1 字节)甚至 INT4(0.5 字节)。效果立竿见影:显存省一半以上,速度更快;代价是精度略降,回答质量可能掉一点点。
类比:这就是”压缩 JSON 传输”。把 {"userName": "zhangsan", "level": 5} 压成更省的格式,能装更多、传更快,代价是丢一点细节。所以现在手机上跑的、或者你本地跑的”小模型”,几乎都是量化过的。
(2)批处理(Batching):把多个请求并成一个算
单次推理受限于显存带宽,算力用不满。批处理把多个用户请求拼成一个大 batch 一起前向计算,摊薄单位成本、提吞吐。类比:数据库的批量插入、连接池的复用——单条处理低效,攒一批一起处理高效。
(3)服务化:vLLM / TensorRT 等推理框架
把”模型 + KV Cache + 批处理 + 量化”打包成一个高吞吐的无状态推理服务,暴露成标准 API。vLLM、TensorRT-LLM 这类框架干的就是这件事。到这里你应该看出来了:这就是上一篇说的”无状态服务”——服务端每次只对这一份完整输入做一次前向计算,算完即弃,不记会话。 底层原理和算法,跟前面几节完全对得上。
第二部分 · 怎么变聪明(训练 Training)
讲完”怎么跑”,讲”怎么学会”。这是比推理更反直觉的部分,因为你平时接触的都是”已经训练好”的模型,训练现场几乎没人见过。
7. 核心任务:预测下一个 token(Next Token Prediction)
训练这件事,聪明得有点赖皮。它不需要人来标注”这句话是什么意思”,只需要海量文本,然后玩一个游戏:
随便抓一段文字,挡住最后一个词,让模型”猜”被挡住的词是什么。猜对加分,猜错扣分。
输入: "今天天气很" → 模型猜:___?
正确答案:"好" → 猜对,加分
把全世界互联网上的文本都这么切一遍,就是无穷无尽的”自动出题 + 自动批改”。这个”猜下一个词”的任务,专业叫下一个 token 预测(Next Token Prediction),是几乎所有大模型预训练的唯一核心任务。
为什么练”猜下一个词”,能练出”会写代码、会翻译、会推理”的能力?因为“猜下一个词”逼着模型去理解前面所有内容的规律。要猜中”资产负债表里的下一项”,它就得学会财务;要猜中一段 Java 里下一个该出现什么,它就得学会语法和逻辑。世界的一切知识,都被压缩进了”下一个词”这个任务里。 这其实是全篇最重要的一句话:模型的”聪明”,是被”猜词”这个看似弱智的任务倒逼出来的。
而那个”加分/扣分”的分数,就是下一节的主角——损失函数。
8. 损失函数 + 梯度下降:怎么一步步”改进”
模型一开始是随机的,瞎猜。怎么让它变好?三步走,全部有后端对应物。
(1)损失函数(Loss):衡量”错得多离谱”
损失函数的作用是给每次预测打一个分:错得越离谱,分数越高(越”痛”)。 目标是让这个分越低越好。
类比:这就是你的监控指标。CPU 使用率、P99 延迟、错误率——损失函数就是模型的”错误率”,训练的目标就是把这个”错误率”打到最低。只不过它衡量的是”预测下一个词”这件事的准确度,而不是服务的健康度。
(2)反向传播(Backpropagation):从输出往回,找出”谁的责任”
损失算出来了,但模型有几十亿个参数,到底是哪个参数该背锅、该往哪调? 反向传播干的就是这件事:从最终的损失出发,往回一层层推,算出每个参数”该往上调还是往下调、调多少”。这个”该调多少”就是梯度(gradient)。
类比:这就是分布式调用链反过来定位瓶颈。线上一个请求慢了,你从入口一路往下看每个 span 的耗时,找到最慢的那个节点。反向传播是同一件事:从”错误”这个最终指标出发,一路回溯,把责任精确分摊到每一个参数上——哪个参数对错误贡献大,它的梯度就大,就得多调。
(3)梯度下降(Gradient Descent):沿梯度方向,小步调参
有了梯度,就按它指示的方向,把每个参数调一点点:该往上就往上挪一步,该往下就往下挪一步。挪多少?由学习率(learning rate)这个步长决定。
类比:这就是滚动发布 + 调参。每次发布只改一点点配置(小步快跑),而不是一把梭全改;学习率就是每次改的”幅度”——太大容易改过头(模型训崩),太小又收敛太慢。
把三步串起来,就是训练的完整闭环:
① 喂一批文本 → ② 前向计算(和推理一模一样)→ ③ 算损失(错得多离谱)
→ ④ 反向传播(谁的责任、该往哪调)→ ⑤ 梯度下降(小步调参)
→ 回到 ① 喂下一批 ……
注意第 ② 步:训练里也有前向计算,和推理用的是同一个流程。 区别只在后面多了 ③④⑤——训练要”算完再回头改参数”,推理到 ② 就停了(只读,不改)。
这就是开头那句话的完整含义:一次推理 = 一次只读的前向计算;一次训练 = 一次”前向计算 + 回头改参数”的批量迭代。 训练就是把”算 → 错 → 改”这个循环,在几十亿参数上重复几万亿次。
9. 规模定律(Scaling Laws):为什么”更大就更聪明”
有个现象值得单独说:过去几年,模型变聪明的主要方式,不是发明了多巧妙的算法,而是”把三样东西一起加大”。
这三样是:参数量(模型多大)、数据量(喂了多少文本)、算力(练了多久)。 大量实验发现,这三者按一定比例一起涨时,模型的损失会可预测地、平滑地下降——能力几乎稳定地变强。这就是规模定律(Scaling Laws)。
类比:这非常像后端扩容——不是给系统加”新功能”,而是同一个系统,喂更多数据、上更多机器。 代码一行没改,光靠”更大”,能力就上来了。
规模涨到某个点,还会出现涌现能力(Emergent Abilities):某些能力(比如多步推理、用工具)在小模型上完全测不到,参数跨过某个门槛后突然出现,像开关被打开了一样。这也是为什么各家在”越大越好”这条路上狂奔——因为真的有效。
(顺带一句:这两年大家也发现,光”大”不够,还得”数据质量好、训练得精细”,于是有了 DeepSeek-V3 这种”用更少算力训出同等能力”的做法。但方向没变:规模和数据的堆积,依然是”变聪明”的地基。)
10. 预训练之后:让它”听话”(对齐 / 微调)
第 7~9 节讲的叫预训练(pretraining)。它练出来的模型有个特点:会”接话”,但不会”听指令”。
你问它”帮我写个排序”,它可能接着你的话往下”续写”,而不是”回答”你——因为它只学会了”猜下一个词”,没学会”你是在命令我”。就像一个看了全世界的书、但从没跟人说过话的书呆子:满脑子知识,但不知道”别人问它问题,是要它回答”。
所以预训练之后,还要做第二步:对齐(alignment)/ 微调(fine-tuning),让它学会”照做”。这一步分两个层次,都有人类参与:
(1)SFT(监督微调,Supervised Fine-Tuning)
给模型看成对的示范:”这样的问题 → 应该这样答”。它照着标准答案去学,把”续写”的倾向改成”回答”的倾向。
类比:照着 SOP 上岗培训。 新人(预训练模型)已经满肚子理论,现在给他一本”标准话术/标准流程”的 SOP,照着练几遍,就知道客户问 A 该怎么答了。
(2)RLHF / DPO(基于人类反馈的强化学习 / 直接偏好优化)
光有 SOP 不够,因为”答得对不对”很多时候是主观的:两条都通顺的回答,哪条更礼貌、更有用、更少胡说?这一步的做法是:让人来给模型的多个回答打分/排序,模型学着”更讨人喜欢”的方向调整。
类比:KPI + 评审驱动优化。 SFT 是”照着标准流程做”,RLHF 是”按老板的偏好打分,谁分高学谁”。它对”礼貌、有用、无害、少编造”这类没有唯一标准答案的东西特别有效。
到这里,”变聪明”的完整路径就清楚了,它是两层:
第一层(预训练) :海量文本 + 猜下一个词 → 学会"世界知识 + 语言规律"
第二层(对齐/微调):标准示范 + 人类打分 → 学会"听指令 + 说人话 + 对齐人类偏好"
第一层让它”懂”,第二层让它”乖”。没有第一层,第二层是无米之炊;没有第二层,第一层只是个人形续写器。
11. 训练 vs 推理:一张对照表
把两部分并排看,训练的”神秘感”就彻底消失了——它俩本质是同一条流水线的两种用法:
| 维度 | 训练(Training) | 推理(Inference) |
|---|---|---|
| 一句话 | 改参数的批量迭代 | 只读的前向计算 |
| 对权重 | 写(反复更新) | 读(只读不动) |
| 流程 | 前向 → 算损失 → 反向传播 → 更新参数 | 前向 → 采样 → 出 token |
| 频率 | 离线,几个月/几周一次 | 在线,每个请求一次 |
| 算力 | 海量(几千上万张卡,几周起步) | 相对小(几张卡即可,毫秒~秒级) |
| 类比 | CI / 离线训练流水线 | 线上只读服务 |
| 产物 | 一份新的”权重文件” | 一句回答 |
一句话收束这个类比:训练 = 打一份新配置,推理 = 线上服务读这份配置跑。
总结
一条贯穿全局的心智模型
训练(离线,改配置)
海量文本 → 猜下一个词 → 算损失 → 反向传播 → 小步调参
│ 重复几万亿次
▼
一份权重文件(几十亿个只读数字)
▼
推理(在线,读配置)
token → Embedding → 几十层 Transformer(注意力+FFN)→ 输出头
→ 采样出一个字 → 拼回输入 → 再来一遍 ……(自回归 + KV Cache 加速)
两句话记住全文:
跑起来 = 读着一份参数表,做一次只读的矩阵乘法流水线,一个字一个字往外挤。 变聪明 = 用海量文本玩”猜下一个词”,猜错了就往回算责任、小步调参数,重复几万亿次。
术语翻译表(作弊小抄)
| 大模型术语 | 后端心智映射 |
|---|---|
| 权重 / 参数 | 决定行为的”配置”,几十亿个只读数字 |
| 前向计算 | 一次只读的请求处理流水线 |
| 自回归 | 循环 RPC:输出一个字符,拼回请求再发下一次 |
| Embedding | 把 token 编码成特征向量 |
| 自注意力 / QKV | 给每个词做一次带权重的”全表 JOIN + 加权聚合” |
| FFN | 对聚合结果再算一遍的业务逻辑 |
| 残差 / LayerNorm | 旁路直连 / 限流归一化,稳定器 |
| 输出头 + softmax | 把向量换算成”下一个字该是谁”的概率表 |
| 采样 / 温度 / top-p | 从概率表里抽 token;温度 = 随机程度旋钮 |
| KV Cache | 模型推理的 Redis:缓存历史 K/V,用显存换时间 |
| 量化 | 压缩 JSON 传输:降精度换吞吐/省显存 |
| 批处理 | 攒一批一起算,摊薄成本提吞吐 |
| 损失函数 | 监控指标(模型的”错误率”) |
| 反向传播 | 分布式调用链反过来定位瓶颈,算清每个参数的责任 |
| 梯度下降 / 学习率 | 滚动发布小步调参;学习率 = 每次改的幅度 |
| 规模定律 | 不加班功能,喂更多数据、上更多机器 |
| 预训练 | 海量文本 + 猜下一个词,练出”懂” |
| SFT / RLHF | 照着 SOP 培训 / 按评审打分优化,练出”乖” |
附录:往前接、往后读
- 上一篇《大模型无状态》讲的是”壳”怎么反复重发历史、上下文窗口和 KV Cache 的显存账,正好和本文第 2、5 节接上。
- 《从大模型到 Agent》里那张”训练侧/推理侧”的词表,本文算是把那两行字真正展开了。
- 想再往下钻一层(注意力矩阵具体怎么算、softmax 的公式长啥样、梯度到底怎么链式传播),可以去看《Attention Is All You Need》原论文和 Andrej Karpathy 的 “Neural Networks: Zero to Hero” 系列——本文刻意停在”零公式”这一层,把直觉搭好,再碰公式会轻松得多。
最后回到开头那个问题:你在自己机器上 curl 那三秒钟,云端 GPU 上发生的事,现在你应该能全程复述出来了——它读着一份几千亿个数字的参数表,把你那句话和一个字一个字挤出来的历史一起,反复做了几百次”全表 JOIN + 矩阵乘法”,再从概率表里一次次采样,直到挤出一个终止符。 而那些数字之所以”聪明”,不过是同一套流水线,在几万亿次”猜下一个词—算错—回头改参”的循环里,被一点一点磨出来的。