AI生成文本的高效水印算法
大多数关于AI水印的解释描述的是一种不存在的技术。
梯形图转SCL | 博途AI辅助编程文档 | AI模型价格对比 | AI工具导航 | ONNX模型库 | Vibe Coding教程 | PLC在线仿真器 | Tripo 3D | Meshy AI | ElevenLabs | KlingAI | ArtSpace | Phot.AI | InVideo
大多数关于AI水印的解释描述的是一种不存在的技术。它们谈论隐藏在单词之间的Unicode字符,或不可见的零宽度空格,或模型被迫使用的秘密词汇,或学习了机器文章"味道"的分类器。其中一些是其他问题的真实技术。但没有一种是水印在实际系统中的工作方式,而这种困惑很重要,因为所有这些想象的机制都会被粘贴到纯文本编辑器中而被击败。
真正的方法更隐蔽也更简单,它隐藏在没人想到要找的地方:不是模型写的单词中,而是它选择不写的单词中。
每次语言模型写一个单词时,它已经考虑了所有其他可能的单词。这是人们忘记的部分。模型不是决定"下一个单词是面包"。它为词汇表中的每个令牌产生一个分数,数以万计的令牌,将这些分数转化为概率,然后从该分布中随机抽取一个。"面包"很可能。"黄油"很可能。"钨"不太可能,但它也有一个数字。
这种随机性就是水印所在的地方。如果你能在掷骰子之前轻轻推动它们,而且你以一种只有你知道如何寻找的模式来做这件事,那么输出的文本就携带了一个没有读者能看到但统计测试能找到的签名。文本仍然读起来很顺畅。签名在选择中,而不是在单词中。
1、分布是原材料
从模型在每一步实际给你的东西开始。假设到目前为止的句子是"我去商店买了一些"。模型输出一个称为对数的原始分数向量,每个令牌一个,softmax将它们转换为总和为1的概率。
# 简化:模型在一步给你的东西
tokens = ["bread", "milk", "eggs", "coffee", "tungsten", ...]
probabilities = [ 0.31, 0.22, 0.15, 0.09, 0.0000004, ...]
普通的采样器根据这些权重从列表中挑选。大约三分之一的时间得到"面包",大约五分之一的时间得到"牛奶"。运行相同的提示两次会得到不同的句子,两者都是完全好的英语。这是整个方案所依赖的关键事实:在大多数步骤中,有许多可接受的下一个单词,而不是一个。模型有余地。水印消耗了这个余地。
由此产生两个结果。首先,如果你系统性地偏好某些可接受的单词而不是其他可接受的单词,文本保持流畅。其次,"系统性"会留下指纹,因为在数百个单词中,偏好不再看起来像巧合。
2、将词汇表分成两半
最著名的方案是绿色列表,由Kirchenbauer及其同事在2023年提出。这个想法简单得令人尴尬。
在生成每个令牌之前,获取你刚刚生成的令牌。将其与密钥一起馈送到哈希函数中,并使用结果为随机数生成器播种。使用该生成器将整个词汇表随机分成两组:包含部分令牌(通常是一半)的"绿色列表"和包含其余令牌的"红色列表"。然后将一个小常数(称为delta)添加到每个绿色令牌的对数中。Softmax,采样,继续。
import hashlib
def green_mask(prev_token_id, vocab_size, secret_key, gamma=0.5):
"""使用前一个令牌确定性地分割词汇表。"""
seed = hashlib.sha256(f"{secret_key}:{prev_token_id}".encode()).digest()
rng = random.Random(seed)
ids = list(range(vocab_size))
rng.shuffle(ids)
cutoff = int(gamma * vocab_size)
return set(ids[:cutoff]) # 此步骤的绿色列表
def watermarked_logits(logits, prev_token_id, secret_key, delta=2.0):
green = green_mask(prev_token_id, len(logits), secret_key)
for i in green:
logits[i] += delta # 倾斜骰子,不要替换它们
return logits
再次阅读第二个函数,注意它没有做什么。它没有禁止红色令牌。它没有强制使用特定的单词。它改变了概率。如果模型非常确定下一个单词是"君士坦丁堡",而"君士坦丁堡"在这一步恰好是红色的,那么2.0的delta不会阻止它。当模型有信心时,模型获胜。水印只在模型无所谓时接管,这正是它可以承受的地方。
列表在每个步骤都不同,因为种子取决于前一个令牌。这就是流行解释出错的地方:没有固定的"水印单词"可以寻找,所以没有什么可以grep出来。"面包"可能在"买一些"之后是绿色的,而在"一条"之后是红色的。这就是为什么这种模式对读者不可见,而且正如我们将看到的,很难移除。

3、同一步骤,有偏和无偏
抽象概念很容易点头同意,所以这是一个带有实际数字的实际步骤。上下文是"今天早上的天气是",这一步的绿色列表恰好包含cold、lovely和grey,delta为2.0。
无偏,模型自己的分布:
token logit prob green?
---------------------------------
warm 4.0 0.34 no
cold 3.7 0.25 yes
lovely 3.2 0.15 yes
terrible 3.0 0.12 no
grey 2.6 0.08 yes
humid 2.2 0.06 no
绿色令牌占有48%的概率质量,这是你对词汇表随机一半的期望。现在将2.0添加到每个绿色对数中并重新运行softmax:
token logit prob green?
---------------------------------
cold 5.7 0.45 yes
lovely 5.2 0.27 yes
grey 4.6 0.15 yes
warm 4.0 0.08 no
terrible 3.0 0.03 no
humid 2.2 0.01 no

绿色现在占有87%的质量。看看什么改变了,什么没有改变。"Warm"仍然可用,仍然大约十二次被选中一次。没有什么被禁止。所有可能的输出,cold、lovely、grey、warm,都是人们会写的关于天气的句子。偏差没有选择一个单词;它重新加权了一组都很好的单词。
然后连续运行这个步骤三百次,每次都使用新的绿色列表,聚合结果变得不再模糊。无偏生成接近50%的绿色,因为分割与文本无关。有偏生成接近80%。单个句子都不显得异常。序列显得异常。
4、检测是一个抛硬币测试
这是优雅的部分。要检查一段文本是否被水印,你不需要模型、提示或概率。你需要密钥和文本。
逐个令牌遍历文本。在每个位置,从前一个令牌和密钥重新计算绿色列表,然后问一个是或否的问题:这个令牌是绿色的吗?计算绿色令牌的数量。
如果没有人倾斜骰子,绿色令牌应该出现大约gamma次,如果分割是均匀的,因为分割是随机的,与文本说什么无关。如果文本被水印,绿色令牌出现的频率要高得多。所以这归结为统计学中最古老的问题:这枚硬币公平吗?
在短段落上手动操作使证据的形状变得明显。取八个令牌,用它们落入的列表标记每个令牌,其中列表是根据其左侧的令牌计算的:
token: The weather this morning was cold and grey
list: · green red green green green red green
七个评分位置中有六个是绿色,而你期望的是三个或四个。这是暗示性的,仅此而已:这里的z分数约为1.9,这种情况经常发生,如果你指控任何人,那就是傻瓜。将相同的比率扩展到四百个令牌,计数在340左右,而期望值是200,这给出一个接近14的z分数。相同的模式,每个令牌相同的偏差,完全不同的判断,纯粹是因为有更多的硬币翻转。

测试统计量是z分数。检查T个令牌,其中count个是绿色的,gamma是绿色比例:
import math
def z_score(count_green, total, gamma=0.5):
expected = gamma * total
stdev = math.sqrt(total * gamma * (1 - gamma))
return (count_green - expected) / stdev
z分数为4意味着绿色计数比机会产生的高出四个标准差。在未水印文本中发生这种情况的概率大约是三万分之一。z分数为6大约是十亿分之一。这就是整个检测器:没有神经网络,没有在"AI风格"文章上训练的分类器,只是一个计数和一个平方根。
这个公式的结果值得坐下来思考。因为标准差随长度的平方根增长,而超额线性增长,置信度随长度增长。二百个单词是舒适的。二十个单词接近无望,任何聪明才智都无法修复它,因为二十次抛硬币根本无法将公平的硬币与稍微有偏的硬币区分开来。短文本无法水印,句号。
5、两个旋钮,以及它们的代价
Delta控制你推动的力度。Green控制绿色列表的大小。两者都在可检测性和质量之间进行权衡,一旦你用力推动,这种权衡就不再微妙。
将delta调高到10,模型实际上无法离开绿色列表。在一两句话之后,检测变得微不足道。它也开始奇怪地写作,不断选择第三好的单词,特定的事情会严重损坏:绿色列表偏差不尊重当你写"法国的首都是"时,只有一个令牌是正确的。高delta意味着低熵文本、事实文本、代码、引用会受损,因为没有余地可以消耗,而水印无论如何都会消耗它。
那个低熵问题是整个技术家族的根本限制。水印只能隐藏在选择自由中。要求模型输出圆周率的第一千位数字,就没有什么可以隐藏的,任何足够强的水印都足以产生错误的数字。Kirchenbauer的论文明确说明了这一点,这就是为什么实际系统使用大约2的适度delta,接受它们需要几百个令牌,并接受某些输出根本无法标记。
6、另一个家族:不偏向,选择随机性
还有第二种更聪明的方法,它根本不扭曲分布。Scott Aaronson在为OpenAI咨询时描述了它,它的工作原理如下。
正常采样绘制随机数,并使用它们从分布中选择令牌。Aaronson的版本从密钥和最近的上下文伪随机地派生这些随机数,然后选择最大化特定函数的令牌,该函数结合了模型的概率和伪随机值,使用Gumbel技巧。对所有可能的密钥取平均值,输出分布完全是模型自己的分布。没有偏差,没有质量损失,可证明。
签名在相关性中。检测器知道密钥,可以重新生成相同的伪随机序列,并测量实际令牌与其对齐的可疑程度。未水印文本没有理由相关。水印文本强烈相关。
# Gumbel风格采样:没有扭曲,相关性是信号
def sample_watermarked(probs, context, secret_key):
u = pseudorandom_uniforms(secret_key, context, n=len(probs)) # 在(0,1)中
scores = [u[i] ** (1.0 / p) if p > 0 else 0.0 # 指数竞赛
for i, p in enumerate(probs)]
return argmax(scores)
这被称为无失真水印,Kuditipudi及其同事在2023年构建了一个鲁棒版本。Google DeepMind的SynthID-Text在2024年Nature上描述,并部署在Gemini上,是这个想法的亲戚,使用伪随机比较的锦标赛;它在生产流量上进行了测试,质量回归会被注意到。
诀窍比失真更微妙。因为选择现在是密钥和上下文的确定性函数,相同的提示产生相同的输出,重复的上下文产生重复的行为。真实的系统混合额外的随机性来避免这种情况,它们混合的每一比特额外随机性都会稍微削弱信号。
7、为什么没有人能告诉你给定模型使用哪种方案
以上所有内容都是对已发布方案的描述,而不是对任何特定产品的声明。这种区别不是谦虚;这是一个硬限制,它来自使水印成为可能的相同属性。
生成的文本是从分布中抽取的样本。没有密钥,水印流和未水印流都只是可信令牌序列,偏差是相对于你无法计算的绿色列表定义的。猜测密钥在构造上是无望的,因为它是一个普通的密码学秘密。仅从输出中恢复方案意味着区分"这些令牌是诚实地采样的"和"这些令牌是用伪随机倾斜采样的",而伪随机性恰恰是对于没有种子的任何人来说看起来与随机性无法区分的属性。Christ、Gunn和Zamir形式化了这个强版本:水印可以被证明是不可检测的,意味着没有数量的输出检查能揭示它的存在。无失真方案在实践中接近这一点,因为它们的输出分布与未水印分布在数学上是相同的。
所以诚实的立场是我们从外部无法知道。供应商发布研究论文,DeepMind已经公开描述了SynthID-Text,但论文是关于团队构建了什么的声明,而不是关于今天为你的账户启用了什么的证明。任何声称仅从文本中逆向工程特定模型水印的人都是在声称打破了伪随机函数,这将是一个比水印更大的故事。
你可以推理的是成本,这就是绿色列表继续获胜的地方。它是一个哈希,一个向量加法和一个计数器,这与前向传递的成本相比不算什么。它不需要第二个模型,不需要额外的推理,不需要存储生成的文本,它的检测器在笔记本电脑上运行,毫秒内处理文档,同时返回校准的假阳性率而不是直觉。基于日志的替代方案,提供商存储每次生成并与新文本进行比较,需要保留模型编写的所有内容的可搜索副本,并且在最轻的释义上仍然失败。风格分类器需要训练数据,随着每个模型发布而漂移,并指控无辜的作者。以这种方式衡量,偏向采样分布不仅是可用的最聪明选项,而且是唯一可行的最便宜的东西,这通常是预测部署了什么的更好指标。
8、打破它
现在是有趣的一半。水印是一种安全声明,所以像对待安全声明一样对待它并攻击它。
释义。这是有效的攻击。获取水印文本并重写它,手动或使用不同的模型,绿色令牌统计崩溃,因为你替换了签名所携带的特定令牌。Sadasivan及其同事在2023年证明,递归释义在保留意义的同时,将检测准确性急剧降低。每一篇关于鲁棒性的后续论文本质上都是对这一结果的回应。语义水印(哈希含义而不是令牌)在一定程度上反击,释义会使文本稍微退化,但军备竞赛的方向不利于防御者。
翻译并返回。英语到日语到英语是带有额外步骤的释义,无需费力。效果相同。
混合来源。检测强度随水印令牌计数的增加而增加。将你自己的句子与生成的句子交错,z分数降至噪声底限,因为你稀释了证据。一半对一半大约减少一半的超额绿色计数,而标准差仍与总长度相关。
表情符号和间距技巧。要求模型在每个单词之间插入一个字符,然后删除它们。分词器看到的令牌流与水印键入的令牌流完全不同,因此哈希链无法重建。这是分词攻击,成本很低。
窃取密钥的效果。Jovanović及其同事在2024年证明,你不需要密钥。足够多次查询水印模型(数千次生成),你可以估计哪些令牌倾向于在哪些其他令牌之后是绿色的。使用该近似映射,你可以做两件比移除更糟糕的事情:高效地清除水印,或者伪造一个,你自己写文本,官方检测器自信地将其归因于模型。伪造是更令人担忧的方向,因为它将检测器变成了陷害某人的工具。

理论上限。Zhang及其同事在"沙中水印"中认为,对于具有质量预言机访问权限的足够强大的攻击者,水印移除在原则上总是可能的:你可以通过随机游走相同质量的重新措辞空间,直到签名被冲掉。将此与刚才引用的不可检测性结果相比较,这对看起来矛盾,直到你注意到它们回答不同的问题。不可检测性是关于你是否能注意到标记。鲁棒性是关于你是否能破坏它。你可以拥有第一个,你无法在坚定的、资源充足的攻击者面前拥有第二个。
9、绿色列表实际上给你什么
所以水印并不能解决人们想要解决的问题。它不会抓住释义的学生,也不会解决关于单个段落的争论,因为段落太短了。任何告诉你它使AI文本可检测的人都在卖东西。
它确实买了的东西是真实的,值得准确命名。它给平台提供了一种廉价的、仅密钥持有者使用的方法,来衡量流经它们的文本中有多少来自它们自己的模型,大规模地,在长文档上,具有可计算的假阳性率。与从风格猜测的"AI检测器"相比,这些检测器对非母语英语作者和任何文章恰好整洁的人都会触发。在两千字文档上z分数为6是带有数字的陈述。这与"这感觉是机器写的"是不同类别的声明。
运行它的成本几乎为零。整个机制是一个哈希、一个向量加法和一个计数器。这种组合,不时髦地简单且对其限制诚实,是比无法告诉你为什么触发的分类器更好的构建起点。
值得带走的部分是你如何看待生成的转变。模型的输出不是一个句子;它是从句子上的巨大分布中抽取的一个样本,分布中有空间。水印是当有人注意到未使用的空间并决定在那里存储东西时发生的事情。
原文链接:Watermarking Text Generation Efficiently
汇智网翻译整理,请转载文章时标明出处。