3. 测试环境与工具链搭建
对抗样本测试与模型安全评估,本质上是一类“可复现的受控实验”。如果直接在开发机上跑攻击脚本,很容易出现三类问题:依赖版本冲突导致攻击算法行为不一致;测试流量与生产流量混在一起,误伤线上服务;缺少资源隔离,一次大规模迭代就把 GPU 显存打满。因此本节的核心任务是搭出一套隔离、可复现、可观测的测试环境,并把模型以服务形式暴露出来,最后接入主流安全测试工具链。
一、隔离测试环境:从“能跑”到“可复现”
隔离的第一层是进程与依赖隔离。推荐用 Conda 为每个攻击框架建独立环境,因为 CleverHans、Foolbox、ART、TextAttack 对 TensorFlow / PyTorch / NumPy 的版本要求差异较大。例如 ART 对 TensorFlow 2.x 与 PyTorch 双后端支持较好,而 Foolbox 3.x 主要面向 PyTorch、TensorFlow 2 和 JAX。一个可用的环境划分如下:
# 攻击框架环境(示例,版本需按实际锁定)
conda create -n adv-attack python=3.10 -y
conda activate adv-attack
pip install torch==2.1.0 torchvision==0.16.0
pip install cleverhans==4.0.0 foolbox==3.3.4
pip install adversarial-robustness-toolbox==1.17.0
pip install textattack==0.3.10
# 被测模型服务环境(与攻击环境分离)
conda create -n model-serve python=3.10 -y
conda activate model-serve
pip install fastapi uvicorn onnxruntime-gpu==1.17.0
隔离的第二层是网络与资源隔离。测试环境应使用独立网段或 Docker 网络,模型服务只监听内网地址,例如 127.0.0.1:8000 或 172.20.0.10:8000,不直接暴露公网。GPU 资源通过 CUDA_VISIBLE_DEVICES 指定,避免攻击脚本与被测服务争抢同一张卡:
# 被测服务使用 0 号卡,攻击脚本使用 1 号卡
CUDA_VISIBLE_DEVICES=0 uvicorn serve:app --host 127.0.0.1 --port 8000
CUDA_VISIBLE_DEVICES=1 python run_attack.py
隔离的第三层是数据隔离。测试集、对抗样本、日志应放在独立目录,例如 /data/security_test/{clean,adv,logs},并记录每次实验的随机种子、框架版本、模型哈希,保证结果可追溯。
二、模型服务化部署:把模型变成可攻击的接口
安全测试工具通常需要“输入张量 → 输出 logits 或概率”的接口。最直接的方式是用 FastAPI 封装一个推理服务,暴露 /predict 接口。下面是一个最小可用示例,加载 ONNX 模型并返回 logits:
# serve.py
import numpy as np, onnxruntime as ort
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
sess = ort.InferenceSession("model.onnx",
providers=["CUDAExecutionProvider"])
class Req(BaseModel):
data: list # shape [N, C, H, W] 展平后的嵌套列表
@app.post("/predict")
def predict(req: Req):
x = np.array(req.data, dtype=np.float32)
logits = sess.run(None, {"input": x})[0]
return {"logits": logits.tolist()}
启动后可用 curl 验证:
curl -X POST http://127.0.0.1:8000/predict \
-H "Content-Type: application/json" \
-d '{"data": [[[[0.1,0.2],[0.3,0.4]]]]}'
关键判断依据:返回的 logits 维度应与类别数一致,且对同一输入多次请求结果稳定(可关闭 dropout、固定随机种子)。若返回概率而非 logits,需在攻击脚本中做 log 变换,否则 FGSM、PGD 等基于梯度的攻击会失真。
三、常用安全测试工具的安装与配置
四类工具定位不同,配置要点也不同:
- CleverHans:偏教学与经典攻击实现,提供 FGSM、PGD、CW 等。配置重点是
model需为可求导的 TensorFlow/PyTorch 模型,且clip_min/clip_max要与输入归一化范围一致。 - Foolbox:API 简洁,支持
LinfFastGradientAttack、L2PGD等。配置重点是epsilon需按像素尺度设定,例如 [0,1] 输入下常用 8/255≈0.031。 - ART:覆盖攻击、防御、检测、评估全流程,支持
PyTorchClassifier、TensorFlowV2Classifier包装器。配置重点是loss、optimizer、input_shape、nb_classes必须与模型严格一致。 - TextAttack:面向 NLP,通过
AttackRecipe组合替换、插入、删除等扰动。配置重点是model_wrapper与tokenizer要匹配,且需设置query_budget控制查询次数。
下面给出一个 Foolbox 攻击 PyTorch 模型的配置片段,用于验证环境是否打通:
import torch, foolbox as fb
model = torch.load("model.pt").eval().cuda()
fmodel = fb.PyTorchModel(model, bounds=(0,1))
attack = fb.attacks.LinfFastGradientAttack()
eps = 8/255
adv = attack(fmodel, images, labels, epsilons=eps)
# 判断:攻击成功率应显著高于随机扰动
若攻击成功率为 0,优先检查三件事:模型是否处于 eval 模式、输入是否已归一化到 bounds 范围、标签是否为 tensor 且与输出维度对齐。
四、工具链协同关系
把上述环节串起来,就形成一条从“隔离环境”到“攻击评估”的链路。下图展示了测试环境、模型服务与四类工具之间的数据流与依赖关系:
图中左侧是隔离环境,中间是模型服务,右侧是工具链;下方数据流说明一次完整评估的路径:干净样本经攻击算法生成对抗样本,再送入模型服务获取预测,最后统计攻击成功率。虚线回路表示根据成功率调整 epsilon、迭代步数或查询预算,形成迭代优化。