← 文章 / AI技术
Sebastian Raschka 2小时前 · 2026-09-22 12:05:01 · 7 阅读

Claude 如何为 AI 生成文本添加水印

前几天我发了一条 Substack 笔记,聊了聊 Claude 新推出的文本水印方案及其实现。这个话题很热门,讨论也很热烈,所以我想进一步展开,详细讲讲它的原理。

这次没有写成常规文章,而是录制了一期小讲座(换个花样)。下面是视频和对应的文字稿。

原本计划做 10 页幻灯片,录一个 10 分钟的短视频。结果整理过程中不断补充关键细节,最后变成了 50 多页幻灯片、48 分钟的录制。

希望这次能把原理讲清楚。祝观看愉快!

Subscribe

视频文字稿

说明:以下文字稿经过少量编辑和润色以方便阅读,但保留了视频讲座的整体顺序和脉络。


0:00

Claude 文本水印的工作原理

第 2 页(共 52 页),时间点 0:00

大家好。几天前,Anthropic 宣布将为 Claude 模型输出的文本添加水印。我当时在社交媒体上发帖简单解释了它的原理,反响挺热烈的——火倒不是水印本身,而是背后的解释和机制。考虑到那条帖子只有一张图,还引出了不少问题和讨论,所以值得展开来讲,把细节说清楚。

于是我想,那索性再多画几张图吧。我原本的计划是只做大约 10 页幻灯片,带大家过一遍流程。结果居然做成了 50 页,但我相信这些内容能清晰解释水印机制的原理、水印如何失效或被移除等问题。我认为这个话题挺有意思,因为如今很多人都在使用 LLM,同时也消费着大量可能由 LLM 生成的互联网文本。

现在会出现这种水印技术,大家可能会担心它降低文本质量,或者疑惑水印的实际好处是什么,它到底意味着什么。我觉得如果能更好地理解水印的本质,就能消除大部分疑虑,也便于我们自行判断这是好是坏,权衡其利弊。

所以,我的目标真的是解释清楚其底层机制,以及如何实现这种文本水印。


Benefits of working "from scratch"
第 2 张幻灯片,共 52 张,时间戳 1:41

这也是一个很好的例子,可以说明从头理解事物为何如此有用。这种水印技术也恰好能解释传统模型或 LLM 在底层是如何工作的。没错,你们可能知道我喜欢“从零开始”做事。比如我的书:《从零构建大语言模型》、《从零构建推理模型》,还有一些标注为“从零开始”的文章。

对我来说,“从零开始”通常包括编码。这次的内容与代码无关,但从零编写代码确实是一项非常有用的技术,因为它能帮你真正理解某件事是如何实现的。由此出发,我们才能推导出理解、图表和概念。因为如果我们不真正动手实现,没有代码,很多时候事情就会模棱两可。当然,我也意识到,现在已经不是每个人都从零开始写代码了。

想当年,代码全靠人手写,从零开始造轮子是唯一的办法。如今 LLM 已经能写代码了,但这并不意味着读代码就没用了——代码里包含大量信息。就拿本文讲的水印技术来说,花时间从零实现过一个 LLM,你才能真正明白内部的采样是怎么做的。我们后面也会给出相关的代码片段。

这反过来能帮助我们理解:哦,原来水印是在这个位置加上的,它会带来这样那样的影响。所以我觉得,尽管现在人们不再总是从零写代码了,但从头构建一些东西仍然有价值——既能在教育层面深入理解原理,也能在研究层面以透明的方式对其进行修改,而不是把一切藏在层层抽象之下。

不过抛开这些不谈,这里算是个巧合的美好呼应:这份幻灯片里其实用了不少我「从零实现」系列教程里的图。


Anthropic 关于 Claude 文本水印的公告
第 3 页,共 52 页,时间戳 3:58

几天前(8 月 14 日),出了一篇文章《How Claude’s Text Watermark Works》,就是这篇。它基本上是个屏幕录制形式的内容,把幻灯片里的东西都放了出来,细节相当丰富。而且后来还更新了好几版——我最初读的时候比现在短得多。不过它还是比较偏概念性,有个总体概述,而且一整篇文章里连一张图都没有。

所以,他们到底想做什么,其实还是不太好琢磨。他们花了很多篇幅解释为什么要这么做,却对“怎么做”避而不谈。文中某处链接了一篇论文,但那篇论文技术含量极高。因此,我觉得很有必要退一步,从头讲起,这样才能更好地理解他们想通过这种水印技术实现什么。

顺带一提,引入水印的核心动机,是让他们能够识别出某段文本是否由他们的模型生成。比如,当有人发布了一段文字,他们可以据此断定:“哦,这段文字是我们 Claude Opus 4.8 模型生成的。” 也就是说,只要文本中嵌入了这种水印,他们就能判断出这是 AI 生成的内容。而且,这种水印对用户是隐形的,只有他们自己能解码,从而验证文本是否带有水印。

为什么只有他们能做到?这一点我们会在后面(希望视频不会太长的情况下)详细解释,我们一步步来。


5:38

LLM 文本生成的工作原理

导言:LLM 中的文本生成
第 4 页(共 52 页),时间戳 5:35

我想先简单做个铺垫,解释一下 LLM 中的文本生成是怎么运作的。有了这个基础,大家就能更轻松地理解水印是如何工作的——实际上,它并非一个额外昂贵的复杂模块,充其量只是在常规文本生成流程中做了一点轻微的调整。


ChatGPT interface used as a text-generation example
第 5/52 页,时间戳 6:01

举个例子,当我们在 ChatGPT 里输入“德国首都是什么”,这类 LLM 就会像示例中那样回答“柏林”。实际上它生成了两个 token,分别是“柏林”和句号。为了简化说明,我们假设这里只生成了一个 token,即下一个 token 是“柏林”。那这个 token 内部是如何生成的呢?

当我们输入“德国首都是什么”并收到“柏林”这个 token 时,幕后到底发生了什么?底层的实际运行机制是怎样的?


Question about what happens when the next token is generated
第 6/52 页,时间戳 6:41

接下来几页,我会简单讲讲生成下一个 token 时底层发生了什么。


第 1 步:将输入文本转换为 token ID
第 52 页幻灯片中的第 7 页,时间戳 6:50

假设我们的提示词依然是“德国首都是”。这里的第一步是将文本转换为 token ID。分词(tokenizing)并将其映射为 token ID 是初始阶段的核心环节之一。这一步发生在 LLM 外部,而非内部。我们只是将文本转换为一种 embedding 层能够处理的格式。


第 2 步:对输入文本进行分词
第 52 页幻灯片中的第 8 页,时间戳 7:22

随后,数据进入 LLM。LLM 会输出下一个 token 的分数分布。


第 3 步:获取下一 token 的分数分布
第 52 页幻灯片中的第 9 页,时间戳 7:31

以上简要概述了 LLM 的内部运作机制。我并不打算在此深入讲解 LLM 的具体实现细节,相关内容我在之前关于从零构建 LLM 的视频和书籍中已多次阐述。关键点在于,当我们生成下一个 token(例如“柏林”)时,此时已获得一组分数分布,这就是 LLM 的输出结果。

在这里,我们看的是 logit 值。这本质上就是一组分数,取值范围从负无穷到正无穷。图中给出的例子,范围大约在 -8 到 20 之间。虽然我们能把这些数值转换为概率分布,但根据采样方式的不同,这在技术上并非绝对必要。因此,你可以把 logit 值理解为一组原始分数。

这些原始分数覆盖整个词汇表。


The score distribution spans the model vocabulary
第 52 页幻灯片中的第 10 页,时间点 8:39

也就是说,LLM 可能生成的每一个单词都包含在内。在当前的词汇索引中,某个特定值(索引位置 19,846)获得了最高分。为了更清晰地展示,我将分布做了平滑处理。如果你把这段 prompt 实际跑一遍,会发现结果更为极端:几乎所有项的分数都极其接近零,而“Berlin”的分数会远高于其他。

为了展示几个峰值,让画面看起来更有趣,我把分布图放大并展开了一些。在这个图中,“Berlin”的得分最高。你可以把它理解为:在我给出一个非常具体的 prompt 时,它是最有可能或最合理的下一个 token。其他选项可能是 LLM 会误判的词汇,比如“Hamburg”或“Munich”。

但现在,LLM 应该能相当确定地判断“Berlin”才是正确答案。你在这里看到的也是词汇索引,它覆盖了整个词汇表。如今 LLM 的输出候选项大约有 25 万个 token。由于幻灯片空间有限,我这里截取的是 19,800 到 19,900 这一小段。如果展示出 25 万个单词的完整分布,曲线会极度狭窄,我们将几乎看不到任何细节。

这里为了教学做了截断。关键在于:常规文本生成会得到这样一个分数分布,接下来我们要做的就是找出其中最高的分数。


第 4 步:从分数分布中采样一个 token
第 11 页(共 52 页),时间点 10:33

具体怎么选,后面会详细讲。实际上不一定严格取最高的那个,但为简单起见,就当这里是取最高分。在这个例子里,最高分是 19,846。


第 5 步:对采样出的 token 进行 detokenize
第 12 页(共 52 页),时间点 10:52

接着对这个分数做 detokenize,就还原出了“Berlin”。这就是本页幻灯片展示的完整流程:从输入 prompt 开始,转成 token ID 并完成 tokenization,交给 LLM,得到分数分布,取出下一个 token,再转换回文本。


Append the sampled token and repeat the generation loop
第 13 张幻灯片(共 52 张),时间戳 11:12

随后,这段文本会被追加到输入中。因此,如果某个问题需要输出多个 token,我们会在这个循环中持续进行,直到答案生成完毕。这通常意味着 LLM 生成了一个文本结束符(end-of-text token),比如图中所示。为了简化演示,我只展示了一次迭代过程,即生成一个 token。正如我之前所说,实际上它会这样持续下去,把修改后的输入反馈给 LLM,以便进行下一轮生成。

那么,我们究竟该如何采样下一个 token 呢?


11:39

Next-Token 采样机制解析

Question about how the next token is sampled
第 14 张幻灯片(共 52 张),时间戳 11:44

我刚才简要提到,从技术上讲,我们可以直接选择得分最高的那个。这被称为贪婪解码(greedy decoding),是一种可行的方式。但大多数 LLM 在使用时并不采用贪婪解码,即并非总是选取最高分选项。因为在某些提示词下,始终追求最高分可能并非我们想要的结果,那样会导致模型仅仅是在复述训练数据。

这样模型总会给出相似的响应,缺乏多样性。因此,我们通常希望输出具备一定的变化性,但又不能随机到胡言乱语的程度。其工作原理是:当我们从该分布中采样时,首先通常会将其转换为概率分数。


将 token 分数转换为概率
第 15 页(共 52 页),时间戳 12:28

如这张图所示,我只把分数展示了出来。为了简洁,这里用的是 NumPy;无论你用什么工具(比如 PyTorch),原理都一样。假设我们手里是 NumPy 里的分数,我会先算 softmax。严格来说,我会调用 Torch 或 PyTorch 里实现好的 softmax 函数,这种实现在数值上是稳定的,能处理极大、极小,以及正负幅值都很高的数值。

这里我直接写出来,只是标准 softmax 的简化写法,方便阅读。具体细节不重要。


从概率分布中采样
第 16 页(共 52 页),时间戳 13:20

关键在于,经过这个转换后,这些分数的总和为 1,相当于做一次重归一化。概率转换的核心就是这一步:softmax。有了概率之后,就可以用随机数或随机采样算法来生成结果了。

举个例子,在 NumPy 里我们可以用 choice 函数。这里传入了 vocabulary 的索引,指定了一个固定的随机种子。关键在于,我们还把概率作为权重传了进去——本质上就是在回答"某个 token 被选中的可能性有多大"。比如经过 softmax 归一化之后,"Berlin" 的概率是 99%,其他 token 加起来只有 1%,那么采样 100 次,大概会有 99 次选中 "Berlin"。

在训练充分的现实 LLM 中,"Berlin" 的概率可能高达 99.999999% 之类,所以你几乎每次都会采样到 "Berlin",因为模型非常确信这个场景下答案就是 "Berlin"。这就是从这个分布中采样的方式。此外还有一些变体,比如 top-k 采样或 top-p 采样。简单起见,以 top-k 采样为例:我们只取得分最高的 100 个 token,然后只在这 top 100 里做随机选择,这样就能避免采到无意义的 token。

对这个例子来说这其实不重要,我只是顺带一提,简单带过。你可以假设这里已经是用 top-k 之类方法筛过的 top 100 token 了。


Repeated sampling selects "Berlin" most of the time
第 17 张幻灯片(共 52 张),时间点 15:37

再举个例子:如果采样 10000 次,"Berlin" 的概率很高,达到 99.9%,那么结果大概是采样到 "Berlin" 9997 次,"Hal" 两次,"Moh" 一次。后面这两个基本就是无意义的 token。这种情况其实很少发生——模型会生成无意义内容,是因为我之前为了演示效果刻意把概率分布拉得平了一些。

一个真实的 LLM 在一万次采样中大概会有九千多次都选中"Berlin",因为这个词的概率极高。这里只是为了示意。


16:19

从采样到水印

Anthropic's explanation of Claude's text watermark
第 18 张幻灯片(共 52 张),时间戳 16:21

刚才我们简单讲了 LLM 的底层机制,这本身也是个挺有趣的概念。不过我讲过很多次了,不想太啰嗦,只是想为接下来介绍水印原理铺个背景。


Without watermarking, random sampling can choose overcast or grey
第 19 张幻灯片(共 52 张),时间戳 16:41

我们说过采样时会取得分最高的 token,或者说用概率采样,大多数时候都会选中得分最高或次高的那个。这里再举个没有水印的例子。我把提示词稍微改了一下,现在提示词是:今天的天气是"cold",可能的答案可以是"gray"或"overcast"。和"Berlin"那个例子相比,我认为"gray"和"overcast"基本可以互换。

考虑到补全文本或生成下一个词的目标,这两个词作为下一个 token 都相当合理。选择哪一个几乎如同抛硬币,二者客观上并无明显优劣。因此,当我们进行随机采样时,由于这两个 token 得分都较高且数值接近,结果可能是其中任意一个。

也就是说,如果多次重复采样,大约一半的结果会是 “overcast”,另一半则是 “gray”。LLM 对同一提示词往往给出不同答案,原因就在这里:当你多次输入相同提示词时,结果通常会略有差异。因为在某些位置,两个候选 token 的概率几乎相同,模型就会随机选取其中一个。

一旦选定了某个 token,它还会影响后续所有 token 的生成,如此层层递进。


18:23

随机种子与确定性采样

随机种子可带来可复现性
第 20 页 / 共 52 页,时间戳 18:25

这里快速讲一下随机数生成。例如,使用随机数生成器会产生一串随机数字,再次运行时,这串数字就会不同。你可以看到,每次生成五个数字,结果都不一样。但如果我设置一个随机种子(比如 1、2、3),然后多次运行,虽然生成的仍是随机数,但每次的结果完全一致,对吗?

即便使用了随机种子,生成的仍然是彼此不同的随机数,但这些序列是可复现的。无论是否使用随机种子,我们得到的都是随机数;区别在于,设置了随机种子后,能得到可复现的数字序列。请记下这一点,这只是个铺垫,稍后会用到这个概念。


Random seed 42 consistently selects overcast
52 页幻灯片中的第 21 页,时间戳 19:26

举个例子,我之前提到过随机采样时可能选中 "gray" 或 "overcast"。但如果我们指定一个随机种子,比如 42,那每次都会选中 "overcast"。也就是说,这仍然是随机选择,但通过随机种子让它变成了确定性的。在这个例子里,给定同样的提示词,模型每次都会选中 "overcast"。


Random seed 99 consistently selects grey
52 页幻灯片中的第 22 页,时间戳 19:49

如果换一个随机种子,模型可能就会选中 "gray"。而且每次采样时,下一个 token 都会固定选 "gray"。所以本质上还是随机采样,只是借助随机种子让它变得可复现、可确定。


20:03

水印密钥的工作原理

Watermarking derives a random seed from a secret key and token context
第 23 张幻灯片(共 52 张),时间戳 20:04

水印技术中,Claude 的方法本质上是设置一个随机种子。但这里的种子并非由某人写死的一个固定数值,而是通过类似 API Key 的密钥,结合前四个词的信息推导出来的。换句话说,他们利用密钥和上下文共同生成这个随机种子。

回顾上一张幻灯片,原理类似:固定的随机种子始终会选择同一个后续 Token。例如,通常可能使用固定种子 99,但在 Claude 的方法中,是通过密钥加上前序 Token 的信息来动态推导种子。具体细节稍后再展开。


Without watermarking, sampling can produce many plausible texts
第 24 张幻灯片(共 52 张),时间戳 21:06

水印技术让文本生成在特定位置变得更确定。例如,左侧展示了多种合理的文本可能。假设有一句话:

> 今天天气寒冷,且

后面既可以接“阴沉”也可以接“灰暗”。下一句可能是:

> 随后,“轻风”或“微风”

这两个词也是可以互换的。

> 然后,微风在树间“拂过”或“吹动”,街道显得“宁静”或“静止”。

换句话说,我可以说“安静”,也可以说“宁静”。这意味着文本中有某些位置,不同的 token 选择概率几乎相同,就像我们之前看到的。也就是说,在没有加水印的情况下,当我们让 LLM 处理提示词时,有时会得到这个答案,有时又会是那个答案,如此种种。

根据位置的数量,这里可能有 128 种潜在答案。当然,文本越长,可替换词的位置就越多,可能的组合也就越多,生成的文本输出自然也更多。举个例子,其中一种可能的输出是:

> 今天天气又冷又阴,微风轻拂过树梢,街道显得格外宁静。我想留在家,泡杯茶看本书。

这是其中一种可能的文本。另一种则是:

> 今天天气又冷又灰,柔和的微风穿过树林,街道显得静悄悄的。我想留在室内,捧杯茶读本小说。顺便说一句,外面其实还在下雨。我不知道这个麦克风效果如何,但这情景倒是挺应景的。

总之,你可以看到,这里生成了两段都很合理的文本,而且还有更多可能的组合。它们都很合理,没有哪一段一定比另一段更好,只是细微的变体。如果我们不加水印,可能会得到其中一种,这纯粹是随机的。由于随机采样的存在,我们可能得到这个,也可能得到那个。


固定随机种子会复现出其中某一段合理的文本
第 25 页,共 52 页,时间戳 23:31

现在,如果我们固定随机种子——之前提过,比如种子设为 99——那么每次可能都会得到同一段文本。也就是说,借助随机种子,我们可以“锁定”输出结果:采样过程仍然是随机的,但同时又是可复现的、确定性的,每次都一样。好,这依然是没加水印、只用随机种子的情况。


加水印后,由密钥决定生成哪段合理的文本
第 26 页,共 52 页,时间戳 23:59

水印本质上做的事情是一样的,只是不再用简单的随机种子,而是用一个所谓的随机密钥(key),由这个密钥参与决定生成哪段文本。由此我们不难看出 Claude 博客里说的那句话为什么成立——水印不会让文本质量变差。

顺带说一句,我不是在为水印辩护,只是在解释原理,别迁怒于我。我想说的是:对最终用户来说,加水印无非就是固定了一个随机种子,让采样变得某种意义上的确定性,就这么回事。


24:45

水印施加在哪里

Summary of generation with and without watermarking
第 27 页(共 52 页),时间戳 24:47

那么,目前的总结是:在没有水印的情况下,我们通常不使用随机种子进行采样,因为我知道大多数人甚至都不用随机种子。老实说,我不确定你通过 Claude 和 OpenAI API 能否做到这一点。我知道你可以在 Ollama 里实现,但我之前也有些问题,因为我在书中用作奖励材料时,用 Ollama 生成过一些文本。

我固定了随机种子,但它仍然并不总是具有确定性,诸如此类。所以这很棘手。根据软件版本等因素,你的体验也可能会有所不同。总之,在没有水印的情况下,我们进行随机采样。右边带有水印的情况,我们仍然进行随机采样。但除了纯随机采样之外,我们还有一个水印密钥。

这个水印密钥被传递给随机种子生成器,以设置特定的随机种子,使其具有确定性。但本质上非常相似,正如我所说,从头理解这些事情有很多好处。现在我们知道这个水印本质上是应用在哪里了。它应用在采样阶段,而不是在 LLM 内部,这其实是个很酷的知识。

因此,他们不需要为此训练一个新的 LLM。他们可以使用现有的 LLM,只在这个采样阶段应用即可。他们不需要重新训练任何东西。所以,是的,这确实很有趣,对吧?


26:13

水印检测是如何工作的

水印检测需要密钥访问权限
幻灯片第 28/52 页,时间戳 26:21

不过我们还没讲完。接下来聊聊如何判断或查看文本是否带有水印。检测水印的前提是拥有密钥。假设我们有若干文本,其中某段(比如第四段)是你从网上随机找到的,你想确认它是否含水印——这就难办了。

因为你不知道,就得靠水印密钥。你需要一个评分函数,用它对文本打分。如果分数超过某个阈值,就认定含水印;否则就是没有。但作为终端用户,我们做不到这些,因为手里没有密钥。密钥对我们是不可见的。

只有 Anthropic 掌握密钥。不过那篇博文中提到,他们可能会开放相应资源,或者开发一个 API 供外部使用。具体细节我不清楚,毕竟我没有官方内部消息,只是读了那篇博客。所以,这个 API 最终可能仅限某些公司使用,比如 X 或 Substack Notes,用来标记 AI 生成的帖子。

他们也可能向普通用户开放。孰是孰非,只能拭目以待。总结起来就是:除非拥有水印密钥,或者使用他们即将推出的 API,否则无法检测水印。


28:00

如何去除水印

通过编辑被水印标记的位置可以移除水印
第 29 页(共 52 页),时间戳 28:03

接下来聊聊移除水印,这就有意思了。搞清楚了水印的工作原理,自然也就知道了它的短板。水印高度依赖特定位置上的特定 token。比如在这段文本里,如果这些彩色单词(也就是 token)是水印位置,那么只要编辑这些地方就能去掉水印,对吧?只要把这些位置上的词全部换掉,就一定能破解这个水印。

但问题在于,我们根本不知道这些位置在哪,对吧?


实际操作中,移除水印需要编辑多个位置
第 30 页(共 52 页),时间戳 28:41

我们不知道这些词在哪,因为水印不是我们生成的,自然不知道该盯哪些位置。所以实际可行的办法就是随机编辑文本:随便改几个词,赌改动足够多的位置能碰到水印点,这算是一种移除水印的方式。另外,我们也无法知道哪些位置得分最高——那需要拿到背后的 LLM,把 prompt 重新跑一遍才能确定——所以只能靠猜了。

举个例子,我们可能会说,把“overcast”换成“cloudy”,因为我们并不知道“gray”的得分更高。在这个例子里,选择“gray”可能很直观,但情况并不总是如此。我想说明的是,这是一种通用的文本编辑方式:我们在调整词的位置,但依然是在猜测哪些位置属于水印。

既然我们事先不知道,就只在各处替换了几个词。如果替换得足够多,同样会破坏水印的有效性。


30:17

水印评分函数的工作原理

幻灯片 31/52,时间点 29:59

上面就是水印技术的简述。我提到过一个评分函数,用来判断文本是否带有水印。视频已经挺长了,但作为额外内容,我还是想简单解释一下这个评分函数是如何工作的,因为这很有趣。它稍微有点复杂,理解其细节并非必要条件。

他们采用特定方式的主要原因是为了降低检测成本。否则,如果我们回看前一两张幻灯片,要检查某段文本是否带水印——即便他们自己也想检查——就必须重新运行提示词(prompt)来获取这些得分,然后应用水印随机种子生成文本,再进行比对。这就非常昂贵了,因为这意味着你想对比的每一段文本,都得重新跑一遍 LLM。

你得知道用的是哪个 LLM,这往往行不通,因为你通常连原始提示词都不清楚。因此,他们采用了一个技巧——可以这么说——修改采样过程,使得后续评分阶段不再需要依赖 LLM。在博客文章中,他们提到这种方法源自一篇论文。

那是一篇发表在 Nature 上的论文,该方法被称为 SynthID-Text。这篇论文大约是一两年前发布的,由 Google 主导,他们使用了类似的技术,称为 Claude watermarking。我不确定,抱歉,我不确定他们是否完全采用了那种技术,但文中提到的是这个。


31:18

SynthID Text 与锦标赛采样

低成本评分中使用的修改采样阶段
第 32 张幻灯片(共 52 张),时间戳 31:39

具体是怎么实现的呢?在看幻灯片之前,我们先回顾一下常规的概览:输入文本,通过 LLM,得到 logit 分布,然后从该分布中采样,输出 token。在此过程中,我们使用了水印密钥和随机种子生成器。这个流程描述依然准确,但这只是概况,token 采样的具体细节还包含更多微妙的地方。

他们并非简单使用 NumPy 的 random choice,而是采用了更精细的方法。


可能的下一个 token 及其概率
第 33 张幻灯片(共 52 张),时间戳 32:16

再次假设上下文为“今天的天气很冷”,我们需要生成下一个 token,例如 “gray”、“overcast”、“gloomy” 或 “cloudy”。其中 “gray” 的概率为 50%, “overcast” 为 30%, “gloomy” 为 15%, “cloudy” 设为 0.05,其余设为 0。这里的图示与实际略有不同,比如将概率最高的 “gray” 和 “overcast” 作为示例。我直接复用了这张图。想象一下,除了 “gloomy” 和 “cloudy” 概率稍高外,其他 token 的概率都非常小。

为了简化说明,我们把词表缩小到只有四个词,而不是之前的 50 个。之前提到过,我们可以用 NumPy 的 random choice 按这些概率采样下一个 token。


加权随机采样可以选择下一个 token
52 页幻灯片中的第 34 页,时间点 33:13

再配合水印密钥作为随机种子,就能让采样过程变成确定性的,得到我们想要的水印。但正如之前所说,这样做代价很高。问题不在采样本身——采样其实很便宜——而在于后续的检测:如果要在互联网上检查海量随机文本,成本会非常高。


锦标赛采样取代普通的加权随机采样
52 页幻灯片中的第 35 页,时间点 33:35

所以他们改用了锦标赛采样(tournament sampling)。这种方法在生成阶段采样时就用上,之后检测阶段可以直接复用。它不再用 random choice 这类方式,而是采用锦标赛采样的思路。原理是怎样的?看起来有点复杂,但说实话,它只是显得复杂,实际没那么难。

所以,你可能得在某个时间点暂停视频,仔细看看那张图。不过我觉得它其实比看上去简单。一旦弄懂了,思路就很清晰。让我来解释一下。我们这里有上下文,然后有一组可能的下一个 token,每个 token 对应不同的概率。

他们称之为随机水印函数。


34:33

随机水印函数

随机水印函数为灰色词分配位签名
第 36 张幻灯片,共 52 张,时间戳 34:35

这里有三个水印函数:G1、G2 和 G3。实际中可能有 30 个、50 个甚至更多。这张幻灯片上我只用了三个,因为这样更简洁,版面也更紧凑。现在,如果看“gray”这个词,它会生成一个 101 的签名。也就是说,我们用这个水印密钥生成随机种子,配合 G1、G2、G3 这三个函数。

如果输入“gray”这个词,我省略了一步细节:通常要把“gray”和上下文中的前两到三个词一起输入,比如“cold gray”。把“cold gray”连同水印密钥一起喂给 G1,得到结果 1。为什么?这就是该函数的特性。它是个随机函数,返回值只有 0 或 1。在这种情况下,配合这个随机密钥和这个 token,它返回了 1。

用同样的密钥,换成不同的函数,结果可能是 0;再换一个函数,结果又变成 1。所以如果有更多函数(比如 30 个),这串 1 和 0 会非常长。


随机水印函数为每个候选项分配位签名
第 37/52 张幻灯片,时间戳 36:00

本质上,它就像一串由 0 和 1 组成的比特串。好的,这里以“gray”为例,通过这些水印函数,我们得到签名 101。对其它词也可以做同样的操作,比如对“overcast”、“gloomy”和“cloudy”都分别处理。每个词都有不同的签名,例如“overcast”是 010。

“Gloomy”是 001,“cloudy”是 100。好了,现在我们有了这些比特值。下一步是所谓的锦标赛抽样,也就是把这些值两两配对。


36:36

锦标赛抽样分步解析

锦标赛抽样中的候选词配对
第 38/52 张幻灯片,时间戳 36:39

这就好比足球比赛的淘汰赛阶段,或者美式橄榄球的季后赛,总是两支队伍进行对决。这里的原理类似,我们将两个 token 配对,让它们本质上相互竞争。这里的得分来自上述函数。因此,我们从第一轮的第一个函数开始。第一组对手是“cloudy”和“gray”。

原始来源: Sebastian Raschka

评论 (0)