卷 III · 猜CH 12深度 12/24

语言模型就是压缩器(真的,不是比喻)

这一章只做一件事:拿同一台模型走两条完全不同的路,然后把两个数字并排放。它们会相差 1.6 个比特——整条消息一共 1.6 个。

★★ 全书中心真模型压缩器预测 = 压缩

▷ 先猜一下

一台 3 阶字符模型,训练在 2053 个字符上。用它压一段没见过的 222 字符文本。gzip 在同一段文字上压到 136 字节。这台模型压到多少?

A 压不过 gzip,约 160 字节B 和 gzip 差不多,约 130 字节C 约 90 字节D 约 45 字节

把两件事接起来

到这里,两块拼图都在桌上了:

  • 第 8 章:算术编码每一步只需要「当前这一步的概率表」,而这张表可以每一步都不一样——只要解码方能算出同一张。
  • 第 10、11 章:一台模型的好坏,就是它给正确答案分配的概率有多高,量化成交叉熵。

把它们拼起来:

◆ 一台模型 + 一台算术编码器 = 一台压缩器
编码:
  for 每个字符 x_i:
      p = 模型.预测(已编码的历史)      # 一张概率表
      算术编码器.编(x_i, p)             # 按这张表切区间

解码:
  for i in 1..n:
      p = 模型.预测(已解码的历史)      # 【同一张表】
      x_i = 算术解码器.解(p)
      把 x_i 追加到历史里

# 两边的历史永远一样,所以两边算出的 p 永远一样。
# 【模型本身完全不需要传输】——只要收发双方装的是同一台模型。

而这台压缩器的输出长度是多少?第 8 章证明过:−log₂ P(整条消息)。而那正好是交叉熵乘以长度。

所以「模型的交叉熵」和「压缩后的比特数」是同一个数。

这不是推理,是可以当场验证的。下面这台真的跑了这两条路:

那两个数字

在 3 阶那一档,两条路给出的是:

走哪条路做的事结果
预测路把模型每步给正确答案的概率取 −log₂,加起来352.4 比特
压缩路拿同一台模型驱动算术编码器,数输出了几位354 比特
收尾开销 + 概率量化的零头1.6 比特

左边那个数字,计算过程里完全没有出现「编码」两个字——它只是一串对数相加。

右边那个数字,计算过程里完全没有出现「交叉熵」四个字——它只是数了数输出缓冲区里有多少位。

而它们相差 1.6 个比特,还是整条消息一共 1.6 个。

◆ 这本书的中心句

「模型有多准」和「文件能压多小」不是两件相关的事,是同一个数字的两种读法。

更准确地说:

压缩后的比特数  =  −log₂ P_模型(数据)
                =  交叉熵 × 数据长度
                =  「模型对这份数据有多惊讶」

# 一台模型看到数据不惊讶  →  它压得小
# 一台模型看到数据很惊讶  →  它压得大
# 「不惊讶」= 「预测得准」= 「压得小」,三句话是一句话。

和 gzip 比一比

压 222 字节的那段文字字节压缩比它知道什么
原文2221.0
gzip -91361.6只有这 222 字节本身
3 阶模型 + 算术编码454.9另外 2053 个字符的先验

三倍。而且这不是因为算法更聪明,是因为它见过东西

这一点必须说清楚,否则这个对比是不公平的:

◆ 那 45 字节的前提

模型压出 45 字节,前提是解压的一方也装着同一台模型——也就是说,那 2053 个字符的训练语料的「知识」,必须已经在解码方手上。

如果你要把模型也一起传过去,账就完全不同了。

所以这个对比的正确读法是:

  • 如果你只需要传一次 222 字节 → gzip 赢(它自带一切)。
  • 如果你要传几千万段这样的文字,而模型只传一次 → 模型完胜,而且差距会越拉越大。

这正是现实中语言模型的经济学:几百 GB 的权重是一次性的固定成本,之后每一次推理都在享受那个成本带来的先验。

而「模型本身要多少比特」这个问题不是可以回避的记账技巧——它是第 13 章的主题,而且它有一个精确的名字。

这个等号在现实里长什么样

▸ 在现实里:三件因为这个等号而存在的事

一、Hutter Prize。2006 年设立的一个奖,规则很简单:把 1 GB 的维基百科文本压到最小,奖金按你比上一个记录省了多少发。

它的设立理由写在官网上,大意是:「压缩这个语料,等价于理解它。」而事实站在这一边——榜上前列的方法全是「神经网络预测下一个字节 + 算术编码」。一个纯压缩比赛,事实上变成了一个语言模型比赛。

二、用压缩率当模型评测指标。2023 年 DeepMind 有一篇论文(Language Modeling Is Compression)直接把大语言模型当通用压缩器用,去压文本、图片、音频。结论是:在这些模态上,一台没见过图片和音频的语言模型,压得比 PNG 和 FLAC 还好。

这件事听上去很怪,但按上面那个等号是必然的:只要模型能给字节序列分配好概率,它就能压——不管那些字节原来是什么。

三、用压缩当分类器。有一个很土的方法:判断文本 A 属于哪一类,就看「把 A 和类别 C 的样本放在一起压」比「单独压 A」省了多少。省得越多,说明 A 和 C 越像。

2023 年有篇论文(“Low-Resource” Text Classification: A Parameter-Free Classification Method with Compressors)用 gzip + kNN 做文本分类,在一些低资源数据集上打平甚至超过了 BERT。这篇论文引发了不少争议(有人指出它的 kNN 评估方式偏乐观),但核心洞察是站得住的:压缩率是一种相似度度量,而且是一种不需要训练的相似度度量。

那么「理解」呢

这个等号成立之后,有一个很诱人的推论摆在那里:「压缩 = 预测 = 理解」。

前两个等号我们已经证明了。第三个呢?

诚实的说法是:它有很强的一半,也有明显的另一半。

◆ 强的那一半

要把一段文本压得很小,你必须捕捉它的规律。

想把一本物理教材压到极小,你的模型得「知道」F = ma——因为知道这个,它才能在看到 F = m 的时候把 a 的概率推到很高。想把一本小说压得小,你的模型得跟得上人物关系和情节。

压缩率是一个无法作弊的指标:你不能靠说漂亮话把文件变小。这一点比几乎所有 AI 评测基准都硬。

✗ 但这个直觉也是错的
「压缩率最好的模型,就是理解得最深的模型。」 压缩率下界了理解——压得好必须懂一些东西。但它不等于理解。

三个具体的缺口:

  1. 它奖励表层统计。把「的、了、是」的分布学得极准,能省下大量比特,而这和理解无关。大部分比特花在最没意思的地方。
  2. 它不区分「知道」和「能用」。一个能完美预测数学教材下一个字符的模型,不一定能解一道新题。预测文本和执行推理是两个不同的任务,只是前者的训练信号恰好也能推动后者一部分。
  3. 它对「重要」和「不重要」一视同仁。这正是第 1 章那个分工的延续——信息论不碰意义。一段文本里那句真正改变结论的话,和一句客套话,在比特账上没有区别。

所以更稳妥的说法是:压缩是理解的必要条件的一个可测量的代理,而不是理解本身。而「用力优化一个不完美的代理会发生什么」——那是第 23 章。

∑ 为什么解码方不需要额外信息

这一点值得单独说清,因为它是整个方案能成立的关键,也是初学者最容易怀疑的地方。

「编码时模型看的是原文的历史,解码时哪来的原文?」

答案:解码时看的是「已经解出来的部分」,而它和原文的对应部分逐字相同。

编码第 i 个字符时,模型看到的上下文 = 原文[0 .. i−1]
解码第 i 个字符时,模型看到的上下文 = 已解出[0 .. i−1]

# 而只要前面 i 个字符都解对了,这两个字符串就完全相同。
# 于是两边算出的概率表逐位相同,算术编码器就能对上。
# 数学归纳法:第 0 个对了,第 i 个也就对了。

代价是解码必须严格串行——第 i 个字符解出来之前,第 i+1 个的概率表算不出来。这也是为什么这类压缩器又慢又不能并行,而 LZ77 可以。压得好和解得快,在这里是一对真实的矛盾。

这本书的引擎里那个 arithDecodeStreaming 函数就是干这件事的——它每解出一个符号就回调一次,让调用方把符号喂回模型。如果你把它写成「先解完再算概率」,程序会在第二个符号就解错。

◇ 结账
D:45 字节,是 gzip 的三分之一

如果你选了 A 或 B,那是把「一台只读过两千个字符的玩具模型」和「工业级压缩算法」放在同一个尺度上比了。但它们比的根本不是同一件事:gzip 比的是算法,模型比的是它见过多少东西。

而这正是这一章的重点:压缩这门手艺,在某个点上停止了关于算法的竞争,变成了关于知识的竞争。那个点大约就在算术编码被发明出来、模型可以随意插拔的时候。

这一章的一句话

352.4 和 354。一个来自纯预测,一个来自纯压缩,中间隔着 1.6 个比特。「模型有多准」和「文件能压多小」不是两件事——它们是同一个数字。

下一章补上这一章故意欠下的那笔账:模型本身要多少比特?

这个问题会把我们带到一个比熵更根本的量——柯尔莫哥洛夫复杂度,「能生成这个数据的最短程序有多长」。它是奥卡姆剃刀的数学形式,它给了「随机」一个终极定义,而且它不可计算。三件事我们都会讲清楚,还会给你一台真的在算这笔账的机器。