第 5 课 · 动手学大模型(上海交大)
Model Watermarking
模型水印:给生成文本盖一个看不见的章
这一章处理一个越来越现实的问题:一段文本是不是机器写的?做法是在生成时就把水印嵌进去——人读不出来,算法检测得到。
学习目标
- 水印嵌入:在语言模型生成内容时嵌入水印。
- 水印检测:检测给定文本的水印强度。
- 水印评估:评估水印方法的检测性能。
- 评估水印的鲁棒性(可选)。
核心概念
教程用 X-SIR 代码仓库,里面实现了三种文本水印算法(X-SIR、SIR、KGW)和两种水印去除攻击(改写 paraphrase 与翻译 translation)。实操从最经典的 KGW 入手。
KGW 的思路是在每一步解码时,用上文的哈希把词表切成绿名单和红名单,然后偏向绿名单采样。检测端不需要模型的原始输出,只要用同一套哈希规则数一数绿词比例,算出 z-score:有水印的文本 z-score 会显著偏高,无水印的文本则接近随机基线。
评估的关键在于同时看两端。只测有水印文本的 z-score 说明不了问题——必须拿无水印文本做对照,才知道在给定阈值下的误报率有多高。鲁棒性评估则是把生成结果先改写或翻译一遍再检测,看水印还剩多少。
实践步骤
- 装好 X-SIR 的依赖,
requirements.txt里的版本是建议值,不是硬性要求。 - 把待输入的提示组织成 jsonl 文件,每行一个 json 对象,至少包含
prompt键。教程用data/dataset/mc4/mc4.en.jsonl,共 500 条,嫌慢可以自行缩减。 - 选模型和算法:
baichuan-inc/Baichuan-7B加--watermark_method kgw。 - 跑
gen.py生成带水印的内容,输出仍是 jsonl,response字段是模型输出。 - 跑
detect.py分别计算有水印文本和无水印文本的 z-score,输出到各自的 z_score.jsonl。 - 用两组 z-score 画分布、定阈值,算检测性能。
- 可选:对生成结果做 paraphrase 或 translation 攻击后重新检测,量化鲁棒性。
常见误区
- 只跑嵌入不跑对照。 没有无水印基线,z-score 是个没有刻度的数。
- 把阈值当常数。 阈值取决于文本长度和采样温度,短文本的 z-score 天然不稳。
- 忽略生成质量。 水印强度和文本质量是一对权衡,只报检测率不报困惑度或人工评分,结论是片面的。
动手练习
用同一批提示生成两份结果:一份开水印,一份关水印。各算 z-score,画两条分布曲线,选一个阈值使误报率低于 1%,记录此时的检出率。然后把带水印的那份整体做一次改写攻击,重新检测,看检出率掉了多少。最后把生成长度从默认值砍半再来一遍,观察短文本对水印的影响。
要点回顾
水印是可验证的机制,不是承诺。嵌入端要看质量损失,检测端要看两类错误,鲁棒性端要看它扛不扛得住最常见的改写与翻译。三样都测过,才谈得上「这个水印能用」。
参考来源
- 上海交通大学《动手学大模型》系列编程实践教程,第五章「模型水印」:documents/chapter5,核验日期:2026-09-06。