模型窃取(Model Extraction):通过 API 查询,复制一个闭源模型——能做到吗

我最早以为,偷一个训练好的模型,至少得黑进服务器把权重文件拷出来。直到我读了一篇 2016 年的论文,才发现更简单的办法:对着模型的 API 发几千个查询,就能复制出一个功能几乎一样的模型。被偷的公司可能完全察觉不到。

AI technology illustration

模型本质上是一个函数:输入一个样本,输出一个预测。如果我能拿到足够多的输入输出对,我就能训练一个新模型来拟合这个映射。这个过程就叫模型窃取(Model Extraction)。用大白话说:你调用别人的 API,把查询结果当自己的训练数据,训练一个“山寨版”模型。我当时的反应是:这也行?后来发现,不仅行,而且有一堆学术论文专门研究怎么做。

先搞清楚:你要偷的是“功能”还是“参数”

模型窃取听起来很厉害,但目标不同,难度天差地别。学术界通常把它分成两类:

  • 功能窃取:训练一个替代模型,让它在尽可能多的输入上产生和目标模型相同的输出。攻击者不关心内部参数,只关心“行为”相似。
  • 参数窃取:通过精心构造的查询,直接恢复模型的内部参数(比如神经网络的权重)。这比功能窃取困难得多,但对某些特定模型是可行的。

这两者的区别,我做一个对比:

维度 功能窃取 参数窃取
目标 复刻输出行为 恢复内部参数
查询量 几万到几十万次 可能非常多,且依赖模型结构
适用模型 任何黑盒模型 结构简单或可线性化的模型
经典论文 Tramer 2016, Knockoff Nets Jagielski 2020

Tramer 等人的论文证明了在逻辑回归、决策树等模型上,参数窃取几乎是“白给”的。而深度神经网络由于参数太多,参数窃取在很长一段时间里被认为是不可行的,直到 Jagielski 等人 2020 年在两层网络上取得了突破,但也仅限于小网络。

参数窃取到底怎么“猜”出权重?

这里有一个很反直觉的点:虽然神经网络是黑盒,但如果它的激活函数是分段线性的(比如 ReLU),那么整个模型在输入空间上就是一个分段线性函数。这意味着,模型的决策边界是由很多超平面拼出来的。

攻击者可以刻意查询一些位于决策边界附近的点,通过观察输出的变化方向,推断出每个超平面的方程。这就像是拿一根探针在黑盒里戳,戳到边界时,反射回来的信号会告诉你边界的方向。Jagielski 的论文正是利用了这个特性,成功恢复了包含 ReLU 激活函数的两层网络的精确权重。

不过,一旦网络深度超过两层,这种“逐层拆解”的方法就会指数级复杂化。所以参数窃取目前还只能在玩具模型上表演。

黑盒查询为什么能拟合模型?

你可能会问:模型内部那么复杂,光靠输入输出怎么就能近似出来?其实这本质上是一个函数逼近问题。神经网络学到的决策边界是光滑的(至少在分类问题里),如果我在输入空间里密集采样,然后用这些样本去训练另一个模型,这个新模型就能学到类似的决策边界。

关键在于输出的信息量。很多商业 API 不仅返回 top-1 标签,还返回每个类别的概率(softmax 分数)。这些概率包含了模型对每个类别的置信度,信息量远大于一个干巴巴的标签。攻击者拿这些“软标签”当训练数据,效果接近知识蒸馏。

Tramer 在论文里甚至直接说了:

“In this paper, we show that adversarial queries can be used to steal machine learning models.”

甚至有些 API 返回 logits(未归一化的分数),那就等于把模型的“底牌”亮了一半。相比之下,如果 API 只返回 top-1 标签,攻击者只能根据决策边界的正反来猜测,信息量大大减少,窃取难度会成倍上升。

查询也有兵法

随机发查询当然也能收集数据,但效率太低。真正的研究者会采用主动学习元学习策略,让每一次查询都“打在关键点上”。

常见方法可以拆成几步:

  1. 先用随机样本初始化一个替代模型,让它学会基本的输入输出映射。
  2. 用一个“查询策略”从候选池中选出替代模型最不确定的样本。
  3. 把这些样本发给目标 API,得到标签或概率。
  4. 将新样本加入训练集,重新训练替代模型。
  5. 重复第 2-4 步,直到查询预算用完。

比如 Knockoff Nets 这篇论文提出用强化学习训练一个“查询策略网络”,让代理自己去生成最有助于窃取的样本。在 ImageNet 这样的任务上,只用 10 万次查询,替代模型就能达到原模型约 80% 的准确率。

一个朴素的主动学习实现长这样(伪代码):

import numpy as np
import requests

def query_target(x):
    r = requests.post('https://api.example.com/predict', json={'input': x.tolist()})
    return np.array(r.json()['probabilities'])

def select_uncertain_samples(pool, surrogate, budget):
    proba = surrogate.predict_proba(pool)
    entropy = -np.sum(proba * np.log(proba + 1e-8), axis=1)
    return pool[np.argsort(entropy)[-budget:]]

这里用熵作为不确定性度量:模型对样本越“没把握”,这个样本的信息量越大。

实验数据:哪些模型真的能被偷走

我最初有个误解:觉得模型窃取只对简单模型有效,对深度学习这种大规模网络应该没戏。但实验结果让我意外。

Tramer 2016 的实验里,他们从 Amazon 的机器学习 API 上成功窃取了逻辑回归和决策树模型,准确率几乎无损。Knockoff Nets 证明,即便目标是一个在 ImageNet 上训练的 ResNet-34,攻击者也能用几十万次查询达到原模型近 80% 的 top-1 准确率。

但要注意,这些攻击都有前提:目标 API 必须提供连续的置信度分数,或者允许大量无限制的查询。如果 API 只返回离散标签,攻击难度会陡增。Jagielski 2020 的论文也指出,虽然他们能从两层神经网络中恢复权重,但扩展到更深网络时,优化过程很容易陷入局部最优。

所以“复制闭源模型”这件事,不是万能的,但绝对不像很多人想的那样不可能。

防窃取:API 供应商有哪些招?

既然查询可以窃取模型,那服务商当然也会想办法防御。我总结一下常见的招数:

  • 限制查询频率和总量:这是最直接的办法,超过阈值就封禁或收费。
  • 检测异常查询模式:如果用户一直在查那些“边界样本”或低置信度样本,就触发风控。
  • 输出扰动:在返回概率之前加一点随机噪声,降低攻击者获得精确梯度的可能性。
  • 模型水印:在训练时嵌入特定样本,如果后来发现一个模型对这些样本有特殊响应,就能证明它可能偷了自己的数据。
  • 差分隐私训练:让模型本身对任何单条样本都不敏感,但这也牺牲了精度。

这些方法各有代价。限制太严影响正常用户体验,输出扰动会降低 API 的可用性。说白了,防御和攻击是一场军备竞赛。

FAQ

模型窃取和知识蒸馏有什么区别?

知识蒸馏是一种合法的模型压缩技术,教师模型(大)指导学生模型(小)学习,目标是让小的模型尽量接近大的。模型窃取本质上就是“没有授权的蒸馏”。如果攻击者拿到了软标签,那么他训练替代模型的过程和蒸馏完全一样。

如果 API 只返回 top-1 标签,还能偷吗?

可以,但难度更大。因为离散标签丢失了置信度信息,攻击者需要更多的查询,而且替代模型的精度会下降。有研究专门研究这种 hard-label 攻击,比如用决策边界附近的样本(例如对抗样本)来提取模型。

偷一个 GPT-4 这种大模型现实吗?

短期内不现实。因为大模型的参数量有几千亿,查询一次成本很高,而且 OpenAI 等公司有严格的风控和速率限制。但你可以“偷”它的特定能力,比如用它来标注数据,训练一个小模型专门做某个任务——这其实是很多公司已经在做的“伪窃取”。从功能上说,这也算一种模型复制。

模型被偷了,你就完了吗

回到最初的问题:通过 API 查询,复制一个闭源模型,能做到吗?

我的答案是:能,但取决于你偷什么、怎么偷。对于中小型模型、或者有软标签输出的 API,功能窃取的成本已经低到几乎每个开发者都负担得起。对于巨型模型,完全复制不现实,但窃取其某个垂直领域的能力是可行的。

但这件事真正有意思的地方在于:模型窃取之所以可能,根源在于模型本身是一个“可查询的函数”。只要你要对外提供服务,你就在某种程度上暴露了你的知识。这有点像厨师做菜——客人吃完,就能猜到大概的配方。你可以通过控制调料用量(限制输出)、监控食客行为(检测异常)来增加模仿难度,但没法完全杜绝。

所以,与其拼命防守,不如想想你的护城河到底是什么。如果模型只是你业务的一小部分,而你的核心竞争力来自数据飞轮、实时更新或生态闭环,那么模型被偷并不会伤筋动骨。反之,如果你的全部家当就是那个权重文件,那哪怕没有模型窃取,你也会被其他方式卷死。

这是一个残酷但现实的技术真相。

原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/204.html

(0)
上一篇 2026年8月20日
下一篇 2026年8月20日

相关推荐