第一课我们把“大模型训练”拆到了最底层:模型拿到数据,产生预测,形成 Loss,再通过 Gradient 和 Optimizer 修改参数。换句话说,训练最核心的事情始终没有变——找到一组更好的参数。

但第一课最后其实故意留下了一个更麻烦的问题:

普通监督学习可以写成:

(x,y)

输入 (x),给一个标准答案 (y)。

可语言模型的 (y),到底从哪里来?

这也正是第二课真正要解决的问题:Next Token Prediction、Conditional Probability、Context 和 Autoregressive Modeling。

这个问题一旦想通,你会第一次真正明白:

为什么互联网上那些没有人工标签的书、网页、代码和文章,居然都可以拿来训练大模型。


先想一个看起来几乎无解的问题

假设我现在给你一本小说。

里面有几十万字。

然后告诉你:

用它训练一个神经网络。

你第一反应可能会问:

训练什么?

输入是什么?

答案又是什么?

因为在传统监督学习里,我们习惯看到的是这样的数据:

输入:

“法国的首都是哪里?”

答案:

“巴黎。”

或者:

输入:

一张猫的照片。

答案:

“猫。”

这很好理解。

模型做错了,可以拿预测和标准答案比较。

有了差异,就能算 Loss。

有了 Loss,就能训练。

可是一本小说不是这样。

它没有人专门在每句话旁边写:

“这句话的标准答案是……”

互联网也不是这样。

网页、论坛、论文、新闻、GitHub 代码、技术文档,大多数都只是普通内容。

没有 Label。

没有 Answer。

没有人为它们准备 (y)。

这就产生了一个非常现实的问题。

如果训练大模型需要人类把互联网重新标注一遍,那么今天这种规模的大模型几乎不可能出现。

因为数据规模一旦来到数十亿、数千亿甚至更多 Token,人工逐条构造答案根本不可行。

所以真正关键的问题不是:

模型怎么学?

第一课已经回答了。

真正的问题变成了:

我们能不能让文本自己产生训练答案?

答案是:

可以。

而且方法简单得惊人。


一句话,自己就能产生训练数据

假设我们有一句话:

我喜欢机器学习

为了方便教学,我们暂时假设:

“我”

“喜欢”

“机器”

“学习”

分别对应一个 Token。

真实 Tokenizer 不一定这么切,那个问题我们后面单独讲。

现在先只看这句话。

我们把后面的内容暂时遮住,只给模型:

然后问它:

下一个 Token 是什么?

答案在哪里?

根本不用找人标。

原文已经告诉我们:

喜欢

于是我们得到第一条训练数据:

x=“我”

y=“喜欢”

继续。

给模型:

我喜欢

让它预测下一步。

原文已经告诉我们:

y=“机器”

再继续:

输入:

我喜欢机器

目标:

学习

你会发现,一句本来没有任何人工标签的普通文本,突然变成了很多组:

(x,y)

更准确地写:

(前面的 Token,下一个 Token)

这就是一个极其重要的转折。

传统监督学习通常需要:

人提供 Input,人再提供 Label。

语言模型却可以直接利用文本本身:

前面的文本作为 Input,原文真正出现的下一个 Token 作为 Label。

于是,原本只有“内容”的互联网,突然拥有了几乎取之不尽的训练目标。

这就是 Next Token Prediction 最容易被低估的地方。

它看起来只是:

猜下一个 Token。

实际上它解决了大规模语言模型训练首先必须解决的一个生死问题:

海量监督信号从哪里来?

答案:

从数据自己里面来。


这就是 Self-Supervised Learning 真正“Self”的地方

很多人第一次看到 Self-Supervised Learning,会误解成:

“模型自己教自己。”

不太准确。

这里的“Self”,更应该理解成:

监督信号可以从数据自身构造出来。

比如原文是:

深度学习正在改变软件开发方式

训练过程中,可以不断构造:

看到:

深度

预测:

学习

看到:

深度学习

预测:

正在

看到:

深度学习正在

预测:

改变

……

并不需要一个人坐在电脑前告诉模型:

“这里答案是‘正在’。”

因为答案早就在原始文本里。

所以,一旦拥有大量原始文本,我们就拥有了大量自动生成的训练任务。

这才是 Next Token Prediction 能够 Scale 的第一个根本原因。


但这里有一个非常重要的误区

我们经常说:

大模型就是预测下一个 Token。

这句话没有错。

但如果把它理解成:

大模型就是高级一点的文字接龙。

那就已经错得很远了。

因为模型真正学习的并不是:

“看到这几个字以后,死记硬背下一个字是什么。”

它真正要学习的是一个概率问题。

假设现在的 Context 是:

法国的首都是

接下来到底是什么?

“巴黎”非常合理。

但模型真正做的事情,不是简单输出一句:

答案 = 巴黎。

更准确地说,它需要判断整个 Vocabulary 里的大量 Token:

在当前 Context 下,

谁更可能出现?

概念上可能类似:

巴黎很高
伦敦较低
北京很低
香蕉几乎不可能
跑步几乎不可能

这里故意不写具体概率,因为这些数字取决于具体模型和上下文。

但思想非常重要:

模型真正学习的是“下一个 Token 的概率分布”。

数学上写成:

P(xt | x<t)

这条公式是理解语言模型的第一条核心公式。

先别背。

我们把它翻译成人话。


P(xt | x<t) 到底在说什么?

先看:

xt

表示现在要预测的第 (t) 个 Token。

而:

x<t

表示它之前已经出现的所有 Token。

所以:

P(xt | x<t)

真正的意思是:

在已经看到前面这些内容的条件下,下一个 Token 出现的概率是多少?

中间这个符号:

|

可以直接读成:

“在……条件下”。

例如:

P(巴黎 | 法国的首都是)

意思就是:

已经知道前面是“法国的首都是”以后,接下来出现“巴黎”的可能性有多大?

这时候你会发现:

所谓 Language Model,最底层其实真的是一个:

Probability Model。

它不断问同一个问题:

给定现在的 Context,接下来各种 Token 有多可能出现?

这件事非常重要。

因为后面的:

Logits、

Softmax、

Cross Entropy、

Sampling、

Temperature、

DPO、

Policy、

KL,

最后几乎都会重新回到“概率分布”上。

如果这一层没建立起来,后面很多东西只能靠背。


为什么一定要强调 Context?

因为语言几乎不可能脱离上下文理解。

比如只给你一个字:

它是什么意思?

不知道。

可能是:

银行。

行业。

行为。

步行。

“不行。”

“这样也行?”

单独看这个 Token,几乎没法判断。

现在我把 Context 给出来:

我准备把钱存进银

你几乎马上就知道:

下一个很可能是:

再换一个:

这个方案我觉得不

你也可能预测:

同样一个 Token。

含义完全不同。

区别在哪里?

不是 Token 自己变了。

是:

Context 变了。

所以语言模型真正学习的从来不是一个简单关系:

银→行

而是:

整个 Context

下一个 Token 的概率分布

这也是为什么现代大模型如此重视 Context。

一句话里某个“它”到底指谁?

代码里的变量在哪里定义?

一个人物几十段之前说过什么?

前面的系统指令要求了什么?

这些问题本质上都在影响:

P(xt | x<t)

于是一个我们后面会反复遇到的问题已经提前出现了:

如果 Context 越来越长,模型到底怎样知道哪些历史信息现在最重要?

这个问题最终会把我们带到 Attention。

再往后会带到 KV Cache、Long Context、Sparse Attention。

但现在不要急着往 Transformer 跳。

第二课先把概率模型这件事吃透。


Autoregressive 其实一点都不神秘

接下来讲一个听起来很学术的词:

Autoregressive Modeling

自回归建模。

第一次看到这个词,很多人会觉得又是什么复杂数学。

其实放到大语言模型里,它的核心直觉非常简单。

假设现在有:

今天下班以后我准备

模型根据当前 Context 预测下一个 Token。

假设这次产生:

那么新的 Context 就变成:

今天下班以后我准备去

接下来模型再次预测。

假设得到:

新的 Context 变成:

今天下班以后我准备去吃

再预测:

于是:

今天下班以后我准备去吃饭

生成过程一直重复:

当前 Context
预测一个 Token
把这个 Token 接回 Context
再预测下一个 Token
再接回去

所以一段几百字的回答,在建模层面并不是:

模型一次性决定整篇文章。

而是被拆成:

第一次预测。

第二次预测。

第三次预测。

……

直到结束。

这就是为什么叫:

Autoregressive。

过去已经出现的序列,会不断参与后面内容的预测。

说得更人话一点:

模型永远只决定“下一步”,但下一步一旦发生,就会改变后面的所有步骤。

这个直觉非常重要。

因为它还能解释一个日常现象:

为什么模型有时候前面生成错了一点,后面会越走越偏?

因为之前生成的内容已经进入新的 Context。

后面的预测是建立在这个 Context 上继续进行的。

错误不会自动消失。

它可能继续影响:

P(xt+1 | x≤ t)

这也是自回归生成一个天然的重要特征。


最漂亮的一步来了:整篇文章,可以拆成无数个“下一步”

现在假设一段文本是:

x1,x2,x3,…,xT

我们真正想建模的是整段文本:

P(x1,x2,…,xT)

也就是:

这一整个 Token Sequence 出现的概率。

乍看非常复杂。

几十个 Token 还好。

如果是一万 Token 呢?

十万呢?

模型难道要一次性理解一个如此巨大的联合概率?

关键就在这里。

概率论里的 Chain Rule 告诉我们:

P(x1,x2,…,xT)

可以拆成:

P(x1)
P(x2 | x1)
P(x3 | x1,x2)

P(xT | x1,…,xT-1)

压缩以后:

P(x)=∏t=1TP(xt | x<t)

这条公式非常重要。

但真正值得记住的不是公式本身。

而是它背后的思想:

一个巨大的“整段语言建模问题”,可以被拆成很多个完全相同的“下一 Token 预测问题”。

比如一句:

我今天晚上准备回家吃饭

不用直接问模型:

“这整句话的概率是多少?”

我们可以拆:

“我”出现得合不合理?

已经看到“我”,接“今天”合理吗?

已经看到“我今天”,接“晚上”合理吗?

已经看到“我今天晚上”,接“准备”合理吗?

……

一直到最后。

于是一个看起来巨大无比的问题:

怎么学习语言?

被统一成了同一个局部任务:

根据目前已经看到的东西,预测下一步。

这就是自回归语言模型设计得非常漂亮的地方。


Chain Rule 不是 Transformer 发明的

这里顺便把一个技术边界讲清楚。

P(x1,…,xT)

∏tP(xt | x<t)

本身只是概率论中的 Chain Rule。

Transformer 没有发明它。

大语言模型也没有发明它。

真正关键的设计选择是:

我们利用这种分解方式,把文本建模变成一个从左到右的 Next Token Prediction 问题。

而这件事刚好还有一个巨大的好处:

训练目标和生成过程可以自然接起来。

训练时学习:

P(xt | x<t)

真正生成时,也不断使用:

P(xt | x<t)

得到一个新 Token。

然后继续。

训练学的东西,

正好就是生成时需要使用的东西。

这也是为什么这种建模方式如此自然。


现在终于可以回答最有意思的问题

很多人第一次知道大模型是 Next Token Prediction以后,会有一种巨大的违和感。

你告诉我:

ChatGPT、Claude、Gemini 这类模型,

底层竟然只是一直在预测下一个 Token?

那为什么最后会写代码?

为什么会翻译?

为什么知道历史?

为什么能解释物理?

为什么还能表现出推理?

如果目标真的只是:

猜下一个 Token。

这些能力到底从哪里冒出来?

这里才是第二课最值得真正想明白的地方。

答案不是:

“Next Token Prediction 里面藏着一个神秘的智能公式。”

恰恰相反。

Objective 非常简单。

真正复杂的是:

想在真实世界的海量文本上持续把下一个 Token 猜对,本身就是一件极其困难的事情。


想预测好语言,你就不得不学语言

假设文本是:

虽然外面正在下暴雨,但是

如果模型完全不懂语言结构,

它很难持续预测后面的内容。

因为:

“虽然……”

和后面的:

“但是……”

之间有明显的结构关系。

这意味着为了降低预测错误,

模型需要逐渐捕捉:

语法。

词义。

上下文。

句式。

长距离依赖。

模型没有一节课叫:

《现代汉语语法》

但如果不捕捉语法规律,它的预测就很难一直做好。

所以训练会不断给它压力。


想预测好事实文本,你就不得不捕捉事实关系

再看:

法国的首都是

后面大量高质量文本里,经常会出现:

巴黎

如果模型总认为:

“东京”

“香蕉”

“CPU”

概率更高,

它就会反复产生更大的预测错误。

于是训练会推动参数变化。

久而久之,

“法国”

“首都”

“巴黎”

这些概念之间会形成某种有利于预测的内部关系。

注意这里的措辞。

不是说:

模型内部一定存在一个数据库单元:

France.capital = Paris

第一课已经讲过,神经网络里的知识通常不是这么整齐地存储的。

更准确地说:

参数逐渐形成一种分布式的内部结构,使正确关系在相关 Context 中更容易得到高概率。

这才接近真实训练过程。


想预测好代码,你就不得不学代码中的规律

假设训练数据里出现:

for i in range(10):

后面经常会是什么?

如果模型完全不知道 Python,

它很难预测。

它需要逐渐捕捉:

冒号之后的结构。

缩进。

循环变量。

函数调用。

括号配对。

变量定义。

常见程序模式。

再复杂一点:

如果前面已经写了一个函数,

几十行之后调用了其中某个变量,

想预测后面的代码,

模型甚至需要跟踪更长距离的程序关系。

所以没有人需要单独告诉它:

“现在开始学习 Python Grammar。”

训练目标永远没变:

预测下一个 Token。

但为了完成这个简单 Objective,

模型不得不逐渐形成越来越复杂的内部 Representation。


一个非常值得记住的判断

这里可以建立一个以后读论文都很有用的认知:

Objective 简单,不代表解决 Objective 所需要的能力简单。

比如国际象棋。

规则并不长。

但想真正下好,非常难。

围棋也是一样。

而 Next Token Prediction 更夸张。

它只有一句任务描述:

根据 Context,预测下一个 Token。

但我们要求它预测的不是一小批简单句子。

而是:

小说。

论文。

数学。

代码。

对话。

百科。

历史。

法律。

技术文档。

复杂推理文本。

多种语言。

如果模型想在如此庞大的数据分布上不断降低预测错误,

它就必须找到越来越多能够解释这些数据的规律。

这就是为什么一个极其简单的训练目标,

最终可能推动一个模型内部形成极其复杂的表示。

这里的“神奇”不是:

目标有多高级。

而是:

数据世界本身有多复杂。


所以“大模型只是文字接龙”到底对不对?

现在可以比较准确地回答这句话了。

说它对:

是因为自回归语言模型确实不断预测下一个 Token。

这没什么好否认。

说它误导:

是因为“文字接龙”这个说法很容易让人产生一个错误印象:

模型只是在根据相邻词频机械接词。

而现代 LLM 实际要建模的是:

P(xt | x<t)

这个 Context 可能非常长。

下一个 Token 的概率,可能取决于:

前面的语法结构。

几十个 Token 前的实体。

几百 Token 前的定义。

代码中的变量关系。

文章的主题。

用户刚刚提出的限制条件。

甚至更长范围的信息。

所以真正的问题从来不是:

它是不是在预测下一个 Token?

当然是在。

真正值得问的是:

为了把下一个 Token 预测得足够好,它必须从 Context 中提取出多复杂的结构?

这才是有价值的问题。


但是千万不要再走到另一个极端

看到这里,也很容易开始说:

原来只要不断做 Next Token Prediction,最后就一定会出现真正的智能。

这也说过头了。

Next Token Prediction 直接优化的是:

文本概率。

它并没有直接要求:

事实必须永远正确。

推理必须永远可靠。

用户指令必须永远服从。

工具必须正确调用。

复杂任务必须执行到底。

模型输出必须符合人类偏好。

举个最简单的例子。

互联网里既有:

正确知识,

也有错误信息。

有严肃论文,

也有小说。

有事实陈述,

也有讽刺。

有今天有效的资料,

也有已经过时的内容。

Pretraining 的基本任务不会因为某段话是假的,就突然改变成另一个 Objective。

它仍然在学习:

在这样的 Context 下,接下来出现什么 Token。

所以:

Language Modeling

和:

Truth

并不是同一个目标。

同样:

Next Token Prediction

也不等于:

Perfect Assistant

这就是为什么 Base Model 训练完成以后,大模型训练并没有结束。

后面还会有:

SFT。

Preference Learning。

DPO。

RL。

RLVR。

Distillation。

这些方法的出现,本质上都在继续回答:

如果“预测人类文本”还不是最终目标,那么我们应该怎样继续训练模型?

但这是后面的课。

今天不往前抢。


还有一个很容易忽略的细节:一段文本不是只有一个训练信号

假设我们有:

机器学习正在改变世界

很多初学者会下意识想象:

输入:

机器学习正在改变

目标:

世界

于是这一整句话只有一次训练。

实际上不是。

概念上,它里面有大量预测位置。

比如:

看到:

机器

预测:

学习

看到:

机器学习

预测:

正在

看到:

机器学习正在

预测:

改变

看到:

机器学习正在改变

预测:

世界

所以一段长度为 (T) 的 Token Sequence,可以贡献大量 Next Token Prediction 目标。

这件事为什么重要?

因为所谓“大规模语料”的价值,

不只是:

有很多文档。

真正更接近训练尺度的是:

里面包含多少可以用于预测的 Token。

于是你会经常看到大模型训练描述里谈:

多少 Billion Tokens。

多少 Trillion Tokens。

而不是简单说:

“我们用了多少篇文章。”

因为对于语言模型训练来说,

Token 才是更接近底层的计算单位和监督单位。


这里再纠正一个很高级、但很重要的误解

前面为了教学,我们一直这样描述:

先看到:

“我”

预测:

“喜欢”

然后再看到:

“我喜欢”

预测:

“机器”

很容易让人产生一个印象:

那训练的时候岂不是必须:

一个 Token 算完,

再算下一个 Token,

然后再算第三个?

如果真的这么训练,大规模训练会非常慢。

实际的 Decoder-only Transformer 训练并不是这么傻。

对于一段已知训练文本,

模型可以在一次计算中同时为很多位置产生 Next Token Prediction。

比如:

输入位置 1 希望预测位置 2。

输入位置 2 希望预测位置 3。

输入位置 3 希望预测位置 4。

……

这些位置可以高度并行计算。

但有一个条件:

当前位置绝对不能偷看未来。

预测第 5 个 Token 时,

不能提前看到第 6、7、8 个 Token。

否则考试时答案已经放桌上了。

后面我们讲 Causal Self-Attention 时,会专门看到模型怎样通过:

Causal Mask

实现这件事。

所以这里先记住一句特别重要的话:

Autoregressive 描述的是信息依赖关系,不代表训练时一定逐 Token 串行计算。

这个区别很多入门教程会混过去。

但后面理解 Transformer Training 和 Inference 的差异时,它非常重要。


训练时和真正聊天时,也不是完全同一回事

还有一个伏笔。

训练阶段有一个巨大优势:

正确文本已经存在。

比如训练语料是:

北京是中国的首都

在预测“是”的时候,前面真实 Context 是:

北京

在预测“中国”的时候,前面真实 Context 是:

北京是

训练数据会一直提供真实历史。

但真正生成的时候不一样。

用户输入一句话以后,

后面的 Token 是模型自己生成的。

假设模型前面生成了一个错误 Token,

那么这个错误 Token 很可能会进入下一步 Context。

下一次预测又建立在它上面。

所以:

训练时的 Context 来源,

和生成时的 Context 来源,

存在一个非常值得研究的差别。

现在不用展开。

后面讲 Teacher Forcing、Inference、以及更远处的 On-policy Learning 时,我们还会重新遇到类似思想。


到这里,我们终于可以把第一课的 ((x,y)) 改写成 LLM 版本

第一课我们一直说:

(x,y)

到了语言模型 Pretraining,

现在可以写成:

(x<t,xt)

其中:

x<t

就是已经出现的 Context。

而:

xt

就是原始数据里真实出现的下一个 Token。

模型有一组参数:

θ

于是它试图学习:

Pθ(xt | x<t)

现在第一课的训练链条终于真正变成了语言模型版本:

原始文本
Token Sequence
Context
模型
预测 Next Token
和真实 Next Token 比较
Loss
Gradient
Optimizer
Parameter Update
新模型
然后继续

你会发现:

第一课和第二课其实是在回答同一件事的两半。

第一课回答:

模型到底是怎么学的?

通过 Loss、Gradient 和 Parameter Update。

第二课回答:

语言模型这么庞大的训练信号到底从哪里来?

从文本自身的下一个 Token 来。

两件事一拼起来,

现代语言模型 Pretraining 的最基本骨架就已经出现了。


最后还有一个洞,不填这个洞,第三课就不会出现

我们今天一直在写:

Pθ(xt | x<t)

说模型会判断:

“巴黎”的概率应该比较高。

“香蕉”的概率应该很低。

听起来很自然。

但神经网络真的会直接输出:

巴黎:92%

伦敦:3%

北京:1%

吗?

不会。

神经网络首先产生的,其实只是很多普通数字。

例如:

巴黎:8.4

伦敦:4.2

北京:3.8

香蕉:-1.7

这些数字:

可能大于 1。

可以是负数。

加起来也根本不等于 1。

它们甚至还不是概率。

这些东西有一个名字:

Logits。

那么新的问题马上来了:

8.4 到底是什么意思?

为什么 8.4 不能直接理解成 84%?

怎么把一堆任意实数,

变成:

0≤ Pi≤1

并且:

∑iPi=1

的真正概率分布?

还有更有意思的问题。

假设“巴黎”概率最高。

模型是不是每一次都必须选“巴黎”?

如果永远选最高概率 Token,会发生什么?

如果不永远选第一名,那模型又凭什么决定选谁?

Temperature 到底在“加热”什么?

Top-k 和 Top-p 又到底删掉了什么?

到这里我们才发现:

今天虽然一直说:

预测下一个 Token。

但我们还没有真正打开模型输出端。

而这正是下一课要解决的问题。

模型训练原理(三)|大模型吐出来的不是文字:先看懂 Logits、Softmax 和 Sampling

下一课最重要的任务,不是教你背 Softmax 公式。

而是让你真正看见:

一句自然语言,到底是怎样从一堆神经网络内部的数字里“长出来”的。

更多推荐