怎么证明"你这个模型是偷我的"——把蒸馏变成取证工具

怎么证明"你这个模型是偷我的"------把蒸馏变成取证工具

背景

模型蒸馏这两年从学术话题变成了生意话题:厂商指控对手用输出训练自己的模型,被指控方说是独立训练的,两边谁都拿不出证据。

取证难在蒸馏不改参数------小模型是用大模型的输出训练的,权重跟老师毫无参数层面的联系,传统的参数比对、指纹探针在这一类攻击面前完全失效。

这两篇新工作的价值,就是给出了两条不依赖权重的取证路线。

技术要点一:Redwood 的"蒸馏审讯"(DFI)

Redwood 的思路建立在一个叫 Distillation Double Bind(蒸馏两难) 的观察上。

假设有个"不可信"模型 U------强到我们不能排除它在策略性隐藏不对齐。把它蒸馏到更弱的"可信"学生 T,只有三种可能:

  • U 的坏毛病传过去,但 T 太弱藏不住 → 审 T 就能拿到 U 的罪证。这叫 DFI(Distillation for Incrimination,蒸馏归罪) 。
  • 坏毛病没传过去,能力传过去了 → 得到更强但可信的模型。这叫 DFC(Distillation for Capabilities,蒸馏取能) 。
  • 最坏情况:既传了坏毛病,又传了足够强的隐藏能力。这时 U 逃出两难。

只要不落在第三种,蒸馏要么给你罪证,要么给你更强的可信模型。

实验结果:在 AuditBench 的 secret-keeping model organisms 上(每个被微调成"有一个隐藏怪癖,并被训练成否认它"),把 organism 蒸馏回自己底层的 instruction-tuned 模型,学生承认怪癖的频率远高于 organism 自己。

一句话概括:坏毛病传得比"藏住它的能力"快。

这结论反直觉,我第一次读时停了一下。按常识,"会撒谎"该是高阶能力,弱模型学不会才对。但实验显示,quirky behavior 通过 subliminal learning(通过语义无关的训练数据传递特质)传得很快,而"评估意识""能不能识别蜜罐"这类审计规避能力传得慢。

一条关键工程结论 :DFI 在学生和老师不共享预训练底座时效果很差,所以应该针对老师自己的 pre-RL checkpoint------比老师弱但共享底座。这意味着 DFI 目前主要是内部工具,外部审计方拿不到 checkpoint 就没法用。

技术要点二:蒸馏推断(ArcXiv 2610.12137)

Redwood 那条路解决的是"它坏不坏",这条路解决的是"它偷没偷"。

问题:判断一个可疑模型是从某个老师蒸馏来的,还是独立训练的。

方法 :假设检验 + 影子模型。训练两组 shadow models------distilled 的学老师推理轨迹 (reasoning traces),independent 的只学参考答案;审计员测量每个模型对老师推理输出的"贴合度",再用 shadow 把它转成校准后的 p-value。

结果:Qwen2.5-7B 当老师、Llama-3.2-3B 当嫌疑人,α=0.02 下真阳性率 1.0。

注意标题里的 "Preliminary Study"------只有一对 teacher/suspect 组合,规模很小。但它证明了这条路是通的。

实操:把"贴合度"转成 p 值

下面这个脚本用纯标准库实现了第 3 步------从贴合度分数到校准 p-value 的那一层。真实场景里贴合度要靠跑模型算,这里用固定随机种子模拟。

python 复制代码
# -*- coding: utf-8 -*-
"""蒸馏推断:把「可疑模型对老师输出的贴合度」转成校准后的 p-value
纯标准库。模拟 ArcXiv 2610.12137 里 shadow model + 假设检验的那一层。
用法: python distill_audit.py
"""
import random

ALPHA = 0.02  # 显著性水平,论文里取的就是 0.02


def gen_scores(rng, n, mu, sd):
    """生成一组「贴合度分数」,分数越高越像偷了老师"""
    out = []
    for _ in range(n):
        s = 0.0
        for _ in range(6):  # 6 个均匀噪声相加,凑个近似的钟形
            s += rng.random()
        s = (s - 3.0) / 0.7071  # 标准化
        out.append(mu + s * sd)
    return out


def p_value(null_scores, observed):
    """零假设下的置换 p-value:(1 + #{空分布 >= 观测}) / (n + 1)
    加 1 是把观测值自己也算进参考集,保证 p 不会等于 0,也不会被 n 卡死分辨率"""
    n = len(null_scores)
    ge = sum(1 for x in null_scores if x >= observed)
    return (1 + ge) / (n + 1)


def audit(name, observed, null_scores, distilled_scores):
    p = p_value(null_scores, observed)
    # 备选分布下的分位:如果它落在蒸馏影子分布里也很正常,说明证据不够"指向蒸馏"
    d_ge = sum(1 for x in distilled_scores if x >= observed) / len(distilled_scores)
    verdict = "拒绝独立训练假设 → 疑似蒸馏" if p < ALPHA else "不拒绝 → 证据不足"
    print("%-22s 贴合度 %6.3f | p=%7.4f | 蒸馏分布分位 %5.1f%% | %s"
          % (name, observed, p, d_ge * 100, verdict))
    return p


def main():
    rng = random.Random(20261010)

    # 独立影子模型:只学参考答案,对老师推理轨迹的贴合度天然低
    null_scores = gen_scores(rng, 200, mu=0.30, sd=0.05)
    # 蒸馏影子模型:学过老师推理轨迹,贴合度高
    distilled_scores = gen_scores(rng, 200, mu=0.62, sd=0.06)

    print("零假设 H0:可疑模型是独立训练的(没偷)")
    print("独立影子分布   均值 %.3f  标准差 %.3f"
          % (sum(null_scores) / len(null_scores),
             (sum((x - sum(null_scores) / len(null_scores)) ** 2 for x in null_scores)
              / len(null_scores)) ** 0.5))
    print("蒸馏影子分布   均值 %.3f  标准差 %.3f"
          % (sum(distilled_scores) / len(distilled_scores),
             (sum((x - sum(distilled_scores) / len(distilled_scores)) ** 2 for x in distilled_scores)
              / len(distilled_scores)) ** 0.5))
    print("显著性水平 alpha = %.2f" % ALPHA)
    print("-" * 78)

    audit("嫌疑 A(自己训的)", 0.31, null_scores, distilled_scores)
    audit("嫌疑 B(灰度地带)", 0.44, null_scores, distilled_scores)
    audit("嫌疑 C(明显偷师)", 0.61, null_scores, distilled_scores)
    audit("嫌疑 D(重度蒸馏)", 0.74, null_scores, distilled_scores)

    print("-" * 78)
    print("提醒:p 值是「如果它真没偷,看到这么高贴合度的概率」,")
    print("      不是「它偷了的概率」。影子模型的训练配方一旦猜错,")
    print("      零假设分布就歪了,p 值再漂亮也没意义。")


if __name__ == "__main__":
    main()

实跑输出:

ini 复制代码
零假设 H0:可疑模型是独立训练的(没偷)
独立影子分布   均值 0.302  标准差 0.050
蒸馏影子分布   均值 0.616  标准差 0.054
显著性水平 alpha = 0.02
------------------------------------------------------------------------------
嫌疑 A(自己训的)             贴合度  0.310 | p= 0.4378 | 蒸馏分布分位 100.0% | 不拒绝 → 证据不足
嫌疑 B(灰度地带)             贴合度  0.440 | p= 0.0100 | 蒸馏分布分位 100.0% | 拒绝独立训练假设 → 疑似蒸馏
嫌疑 C(明显偷师)             贴合度  0.610 | p= 0.0050 | 蒸馏分布分位  53.5% | 拒绝独立训练假设 → 疑似蒸馏
嫌疑 D(重度蒸馏)             贴合度  0.740 | p= 0.0050 | 蒸馏分布分位   0.5% | 拒绝独立训练假设 → 疑似蒸馏
------------------------------------------------------------------------------
提醒:p 值是「如果它真没偷,看到这么高贴合度的概率」,
      不是「它偷了的概率」。影子模型的训练配方一旦猜错,
      零假设分布就歪了,p 值再漂亮也没意义。

看嫌疑 B 那一行,最有教学价值:贴合度 0.440,离独立分布均值 0.302 也就 2.8 个标准差,p 值已是 0.0100,低于 0.02,判"疑似蒸馏"。

但它在蒸馏分布里的分位是 100%------如果它真蒸馏来的,0.440 这个分数低得离谱。

两个信号打架。说明 0.44 这个区间是盲区,光看 p 值会误判。所以我让脚本同时输出蒸馏分布的分位,这两个数得一起看:p 值小 + 蒸馏分位不极端,才是干净的证据。

还有个细节:p 值最小分辨率是 1/(n+1)。这里 n=200,下限约 0.005。C 和 D 都是 0.0050,不是因为一样可疑,是分辨率到顶了。想区分两者得把影子模型数量提上去。

踩坑提示

  1. p 值不是"有罪概率"。 这话统计学课上听过一百遍,真用时还是会忘。p 值是"如果它真没偷,看到这么高贴合度的概率"。
  1. 影子模型必须复现嫌疑人的训练配方。 你猜嫌疑人用了什么数据规模、学习率、训了多少步,就得照着训影子。配方猜错,零假设分布就歪了。这是这套方法最大的软肋。
  1. 论文是 preliminary study。 只有 Qwen2.5-7B → Llama-3.2-3B 一对组合,n 也不大。别直接往生产上搬。
  1. DFI 需要老师自己的 pre-RL checkpoint。 拿不到就没法用,所以它目前是对内工具而非第三方审计工具。
  1. 别把它当合规证据。 这是研究原型。真打官司,法官不看 p 值。
  1. 分辨率被影子模型数量卡死。 p 值下限是 1/(n+1)。n=200 时约 0.005,再可疑也只能显示 0.005。

顺带一句:DFI 说"蒸馏能让坏人露出马脚",蒸馏推断说"蒸馏会留下痕迹"------都把它从单向攻击变成了双向证据链。

相关推荐
小O的算法实验室44 分钟前
IEEE TMC,面向异构物联网的多目标量子行为拓扑优化算法
算法
liliangcsdn1 小时前
派息率指标的应用探索和分析
大数据·算法
袁哥大话安全2 小时前
巡隐WEBSHELL扫描软件
人工智能·安全·web
垆边人似月.2 小时前
华为机试题 :两数之和
c++·算法·华为
默默开发2 小时前
物流行业可用算法方向
算法
垆边人似月.2 小时前
华为机试题 :有效的括号
c++·算法·华为
小宋10212 小时前
A2UI从零实战:Agent安全生成交互界面与事件回传
javascript·人工智能·安全·交互
草根大哥2 小时前
04-推拉流安全:签名、Token 与防盗链
安全·成本·延迟·自建cdn·ppcdn
A加ITIL教练长河achotsao3 小时前
ITIL Master 战略领导者课后系列分享:AI编程正在重新划分研发与运维的边界
算法