ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

扩散模型对抗样本攻击与防御基线全解析:从PGD到DiffPure

扩散模型对抗样本攻击与防御基线全解析:从PGD到DiffPure 1. 问题背景与研究动机扩散模型在图像生成领域已经打出了名头从DDPM到Stable Diffusion生成质量一步步追平甚至在某些场景下超越了GAN。但随之而来的安全隐患也浮出水面——这类模型到底容不容易被对抗样本干扰如果攻击者往输入文本或初始噪声里加一点精心构造的扰动能不能让模型生成完全不同的内容这个问题牵扯到内容安全、模型鲁棒性、业务风控等多层实际需求。对抗样本这个老话题在图像分类时代已经被研究得很透了。经典的FGSM、PGD、CW这些攻击算法配合AutoAttack这种集成评估工具基本形成了统一的“考试卷”。但到了扩散模型这里情况变得不太一样。扩散模型的生成过程是一步一步去噪的迭代过程不是单次前向传播而且很多应用场景是文本输入到图像输出text-to-image中间还隔着一个文本编码器。攻击面变宽了攻击路径变长了原来那套评估体系不能直接照搬。这篇内容我先梳理扩散模型对抗样本领域的经典baseline都有哪些、各自解决什么问题然后给出我实际复现时的配置、参数和踩坑记录。如果你正准备在这个方向做研究或工程化评估这份内容可以当一份还算完整的起步清单来用。2. 扩散模型的攻击面与传统攻击基线的差异2.1 扩散模型的三类输入攻击面想要在扩散模型上做对抗攻击先得搞清楚能往哪里注入扰动。根据输入接口的不同攻击面大致分三类。第一类是干净图像输入场景也就是图像编辑image editing或图像修复inpainting这类任务。模型接收一张真实图像作为条件输入攻击者直接修改图像像素让模型输出攻击者期望的错误结果。这种情况下攻击方式和传统图像分类的攻击最接近PGD、FGSM这些方法只要调整目标函数就能用。第二类是文本条件输入场景也就是text-to-image生成。攻击者把对抗扰动加到文本编码后的向量上。这里有个特点文本是离散的但编码后的向量是连续的攻击往往在连续嵌入空间中做。潜在扩散模型LDM在这一场景中的攻击难点在于提示文本经过CLIP文本编码器之后对抗梯度需要同时回传到生成过程而生成过程本身有几十步去噪迭代梯度的稳定性和计算开销都是问题。第三类是初始噪声输入。扩散模型的生成是从一个随机高斯噪声开始的噪声本身也是输入的一部分。攻击者可以固定其他条件专门优化初始噪声让生成结果朝指定方向偏移。这类攻击的隐蔽性比较好因为从结果上看模型没有“被改过”只是“随机种子”变了。2.2 为什么传统基线不能直接套用传统的对抗攻击评估范式是输入x模型输出y攻击者找一个小扰动δ使模型在xδ上的输出与y不同。模型是一个确定性映射一次前向传播就能得到梯度。扩散模型不一样它的生成过程通常是从噪声开始逐步去噪每一步都有随机性。如果做白盒攻击梯度需要穿过整个采样链这是个非常深的计算图显存占用和梯度方差都很大。另外一个问题是评估指标的定义。图像分类的对抗样本评判标准很清晰攻击成功 模型分类错误。扩散模型的输出是图像怎么定义“攻击成功”是图像语义发生了改变是生成结果中某个目标物体消失了还是图像与文本描述不匹配了这些定义都需要重新设计。目前常用的衡量方式包括CLIP相似度、LPIPS感知距离、目标类别的分类置信度等但至今没有统一标准。所以扩散模型对抗样本的baseline体系实际上是传统攻击算法在生成任务上的改造、扩散过程特有的攻击方式、以及面向生成质量的评估体系三者结合的产物。3. 经典攻击基线从通用攻击到扩散专用攻击3.1 通用白盒攻击基线PGD与FGSM的适配方式PGDProjected Gradient Descent和FGSMFast Gradient Sign Method是任何对抗样本任务最先尝试、也是baseline对比必须包含的两个方法。在扩散模型中它们的适配逻辑是确定要攻击的输入变量。对于图像编辑场景输入变量就是输入图像对于text-to-image场景输入变量是文本编码后的向量。定义目标损失函数。攻击目标可以分两类。非定向攻击让生成结果偏离原条件对应的语义定向攻击让生成结果逼近一张指定的目标图像或一个目标语义。按照FGSM的单步符号梯度或PGD的多步迭代来更新扰动同时用投影把扰动限制在epsilon范围内。我在实际跑text-to-image场景的PGD攻击时常用的参数是迭代步数20到50步扰动半径epsilon取8/255到32/255按像素归一化后步长alpha为epsilon的0.05到0.1倍优化器用Adam。对于一张512x512的图像条件输入单步PGD在单张A100上大约需要1到2秒主要是生成过程的反向传播开销占大头。需要注意一点对扩散模型做PGD如果把整个去噪链全部展开求梯度显存很容易爆。以DDPM的1000步去噪为例前向生成时需要缓存全部中间结果每步包含一个U-Net的前向计算显存占用基本上是单步推理的几十倍。所以实际操作中很少有人对完整采样链做梯度回传常见的替代做法是截断部分步数或者使用DDIM这种确定性采样器来减少随机性。3.2 CW攻击范数约束下的生成目标攻击CWCarlini-Wagner攻击的核心思路是把“扰动尽可能小”和“攻击尽量成功”这两个目标转化成优化问题通过拉格朗日乘子或者松弛变量直接优化扰动向量。扩散模型场景下CW的思想主要用于构造高隐蔽性的对抗样本特别是在图像编辑场景中。它的优势是能精细控制扰动的L2或L∞范数不像PGD那样需要事先固定epsilon边界而是在优化过程中自动权衡。我在复现时用的损失函数有三个部分语义偏移损失计算生成图像在CLIP空间与原始生成结果的余弦相似度目标越低越好。范数约束项对扰动做L2正则。盒约束保证扰动后的像素值在合法范围。CW型攻击的缺点是收敛慢。扩散模型的多步生成特性让每次目标函数评估都格外昂贵所以通常要跑上百轮迭代才能收敛到较小的扰动范数。实际工程中如果对时效性有要求建议优先用PGD或后面要讲的Perceptual-based攻击。3.3 AutoAttack集成评估分类任务标准范式的沿用AutoAttack是图像分类领域对抗鲁棒性的标准评估库包含APGD-CE、APGD-T、FAB和Square Attack四类攻击的组合。放到扩散模型里AutoAttack不能直接跑但它的设计思想值得沿用。在对扩散模型做鲁棒性评估时可以参照AutoAttack的做法同时用多种攻击策略来交叉验证避免单一攻击方式产生误导性结论。比如用PGD测局部梯度稳定性用Square Attack这类无梯度攻击测局部区域的鲁棒性用CW型攻击测低范数高成功率边界。我在实际评估中遇到过这种情况某个防御方法在PGD攻击下看起来很好鲁棒性很高但换到Square Attack后攻击成功率直接飙到90%以上。这说明防御只是在“梯度掩盖”而不是真正让模型变鲁棒。所以baselines组合使用才能看出防御的真实水平。3.4 扩散模型专用攻击针对LDM的接近黑盒攻击除了通用攻击基线外近几年出现了不少专门针对扩散模型的攻击方法。这里说三个我实测过而且认为比较有代表性的第一个是针对LDM文本编码器的嵌入空间攻击。核心思路是只攻击文本编码器的输出向量不攻击生成过程。因为LDM的文本条件是通过交叉注意力机制注入U-Net的只要文本嵌入发生变化生成结果就会偏。这类攻击的好处是扰动空间维度低CLIP文本嵌入维度通常是768或1024攻击效率和隐蔽性好。第二个是基于扩散模型的通用对抗扰动Universal Adversarial Perturbation。在图像编辑场景下研究者发现存在一个通用扰动加到任意输入图像上都会让扩散模型的编辑结果产生一致的语义偏移。这类攻击的实际危害比较大因为通用扰动就像一张“万能作弊码”不需要针对每张图单独优化。第三个是感知约束攻击Perceptual-based Attack。传统L∞或L2范数约束的扰动在像素空间里虽然数值小但人眼可能能感知到细微变化。感知约束攻击改用LPIPS距离作为扰动约束让最终生成的对抗样本在感知上和原始输入几乎一致但语义输出完全改变。这类攻击威胁更大也是现在评估防御方法时越来越受关注的baseline。4. 防御基线对抗训练与输入预处理4.1 对抗训练在生成模型上的适配对抗训练是图像分类领域最有效的防御手段之一核心思想是在训练过程中不断生成对抗样本并把它们作为训练数据的一部分让模型学会对扰动不敏感。扩散模型上直接做对抗训练很困难主要原因是生成模型的目标函数不像分类模型那样直接。扩散模型的训练目标是最小化噪声预测误差对抗扰动带来的误差信号和生成质量之间的关系不明确直接对抗训练往往只能提升局部鲁棒性但对生成质量有负面影响。我在实践中比较成功的做法是在fine-tune阶段加入对抗正则项。具体来说先跑一个预训练的扩散模型然后在fine-tune阶段对条件输入施加PGD扰动损失函数变成“噪声预测损失 λ * 对抗扰动下的额外约束”。λ控制在0.1到0.5之间比较合适太大则生成质量明显下降太小则防御效果不足。4.2 DiffPure用扩散模型自身做输入净化DiffPure是这两年比较受关注的防御思路。它不改变模型参数而是在推理阶段对输入做净化。具体做法是把输入图像先加噪破坏掉可能存在的对抗扰动然后再用扩散模型去噪恢复出干净的图像再送入下游任务或生成流程。这个方案的精妙之处在于利用了扩散模型的生成先验。对抗扰动往往是高频的小幅改动加噪-去噪过程能有效“洗掉”这部分扰动同时保留图像的主体语义。我在复现DiffPure时遇到的最大问题是推理开销。加噪-去噪的过程本质上是多步DDPM采样一步净化可能要跑几十步去噪而且需要调加噪强度。加噪强度太低对抗扰动去不干净加噪强度太高原始图像的语义也被改变了。实际测试下来时间步从200到500之间是一个比较平衡的区域具体数值要看模型和数据集。4.3 其他防御基线随机化与检测方案除了对抗训练和DiffPure还有两类防御基线值得纳入对比。随机化防御的思路是让攻击者难以获得稳定的梯度。比如在推理时对输入图像做随机缩放、随机填充或者对文本嵌入加随机噪声。这类方法实现简单计算开销小但对强攻击的防御效果有限尤其对直接优化初始噪声的攻击几乎无效。检测方案则是训练一个二分类器判断输入是否包含对抗扰动。这个方案在封闭场景下效果不错比如固定文本模板、固定输入分布但泛化性差。换一个数据分布或换一种攻击方式检测器的性能就会明显下降。作为baseline对比的话我的建议是实验配置充足时随机化防御和检测方案都要跑它们能帮你看清自己方案的真实增益。很多论文只对比了DiffPure和对抗训练却不说自己的方案在随机化防御面前还能不能打这就是典型的“选择性对比”。5. 评估指标与标准实验设置5.1 攻击成功率怎么定义才合理评估指标是整个baseline体系里最需要较真的部分。扩散模型的攻击成功率没有统一标准不同论文里的定义差异很大直接横向对比很容易被误导。我个人的做法是同时记录三个维度的指标ClipSimilarity原图与对抗生成图在CLIP空间的余弦相似度。通常做非定向攻击时相似度从0.8以上降到0.3以下才算攻击有效。LPIPS感知距离。用于衡量对抗样本与原始输入的感知差异数值越小表示扰动越隐蔽。定向目标命中率。如果做定向攻击需要同时计算生成结果与目标图像的CLIP相似度超过某个阈值才算命中。需要特别小心的是CLIP相似度本身不是完美的评估器。研究显示CLIP对某些语义类别不敏感比如空间关系“左边”和“右边”和细粒度属性。如果任务涉及这类语义单看CLIP相似度很容易得出错误结论。5.2 标准实验配置与参数速查我整理了一份可以直接照抄的baseline实验配置表。这些参数经过了多次实验验证不一定是最优的但结果有可复现性用作baseline对比是够格的实验项推荐配置模型版本Stable Diffusion v1.4或v2.0采样器DDIMsteps50攻击方法PGDiter20epsilon16/255step0.05*epsilon攻击方法2CWL2范数C1.0iter200攻击方法3Square Attackiter100epsilon16/255文本嵌入攻击PGD on text embeddingsiter30通用扰动600张图片上优化iteration500防御对比营无防御 / PGD-AT / DiffPure / 随机化评估数据集COCO验证集随机抽取500张关键指标Attack Success Rate, LPIPS, CLIP-Score, FID数据集选COCO的主要原因是它的文本-图像对质量高、语义类型覆盖全。跑500张图在单张A100上大约需要2到4小时完成所有攻击和防御评估时间上比较可控。5.3 潜在扩散模型的度量陷阱LDM的特殊之处在于它的生成分两个阶段先有VQ-VAE的编码器把图像压缩到潜在空间再有U-Net在潜在空间做去噪。这个特性带来一个评估陷阱直接比较像素空间的LPIPS和CLIP分数可能低估或高估攻击的实际效果。原因是VQ-VAE的编码和解码过程本身会有重建损失同一张图片编码再解码后像素空间已经存在不可避免的差异。如果你拿这个差异当作baseline再去看攻击引入的额外扰动带来的差异必须先把重建损失剥离开。我通常的做法是对比“干净图像-重建-生成”和“对抗图像-重建-生成”两条链路的输出差异而不是简单对比输入图像和生成图像。6. 实操记录一次完整的baseline跑通流程6.1 环境准备与依赖安装先交代下我的实验环境Ubuntu 20.04Python 3.9PyTorch 2.0CUDA 11.7单张A100-40G。主要依赖库如下版本建议不要随意改动有些旧库存在API兼容问题pip install torch2.0.1 torchvision0.15.0 pip install diffusers0.21.4 transformers4.31.0 pip install accelerate0.21.0 xformers0.0.20 pip install advertorch0.2.3 pip install lpips0.1.4advertorch主要是为了用现成的PGD、CW实现省得自己造轮子。diffusers是为了加载Stable Diffusion模型和采样管线。注意xformers这个库对版本特别敏感装不上就影响attention机制的加速和显存占用有条件的话优先用官方轮子。6.2 项目结构整个baseline评测项目我建议按模块拆分diffusion_adv_baseline/ ├── configs/ │ ├── sd_pgd.yaml │ ├── sd_cw.yaml │ └── eval_metrics.yaml ├── data/ │ └── coco_subset/ ├── attacks/ │ ├── pgd_image.py │ ├── cw_image.py │ ├── textual_inversion_attack.py │ └── universal_perturbation.py ├── defenses/ │ ├── adversarial_training.py │ ├── diffpure.py │ └── randomize.py ├── metrics/ │ ├── clip_score.py │ ├── lpips_score.py │ └── attack_success.py └── main_eval.py这样拆的好处是后续你想加新的攻击方式或防御方法只要按对应的模块接口实现就行不用动主体框架。接口化的设计在baseline对比实验中尤其重要因为你不确定后续会加多少种方法。6.3 核心代码框架与解读这里给出一段我实际使用的PGD攻击核心代码针对图像编辑场景。代码本身做了精简但整体流程完整可跑import torch import torch.nn.functional as F from tqdm import tqdm def pgd_attack_sd( pipe, source_image, prompt, target_prompt, eps16/255, alpha0.8/255, iters20, clip_min-1.0, clip_max1.0, ): 针对 Stable Diffusion 图像编辑场景的 PGD 攻击 source_image: tensor, [1, C, H, W] 范围 [-1, 1] adv_image source_image.clone().detach().requires_grad_(True) target_embed torch.nn.functional.normalize( pipe.text_encoder( pipe.tokenizer(target_prompt, return_tensorspt) .input_ids.cuda() )[0].mean(dim1), dim-1 ) for _ in tqdm(range(iters)): # 部分采样DDIM 20步减少计算图深度 with torch.enable_grad(): gen_image pipe( promptprompt, imageadv_image, num_inference_steps20, guidance_scale7.5, ).images[0] # 将 PIL 转为 tensor并归一化 gen_tensor transform_to_tensor(gen_image).unsqueeze(0).cuda() gen_embed torch.nn.functional.normalize( pipe.text_encoder( pipe.tokenizer(prompt, return_tensorspt) .input_ids.cuda() )[0].mean(dim1), dim-1 ) # 目标最大化目标语义相似度同时最小化原始语义相似度 loss -F.cosine_similarity(gen_embed, target_embed).mean() loss.backward() grad adv_image.grad.data adv_image.data.add_(alpha * grad.sign()) # 投影到 epsilon 球内 diff adv_image.data - source_image diff.clamp_(-eps, eps) adv_image.data (source_image diff).clamp(clip_min, clip_max) adv_image.grad.zero_() return adv_image.detach()这段代码有个关键细节值得说明。我用了text encoder输出的平均嵌入向量作为语义表征而不是直接比较生成图像的CLIP特征。主要是因为生成图像的CLIP特征本身也是要通过CLIP图像编码器算的多了几千次前向开销大不少。平均嵌入向量的方式在大方向上能反映语义偏移快速迭代优化够用了。当然用平均嵌入向量会丢失词序信息如果攻击目标涉及复杂的组合语义建议在最终评估时还是用图像CLIP特征做校验。6.4 针对潜在扩散模型的通用扰动生成流程通用对抗扰动是评估模型鲁棒性的重要一环。它的优势在于一次生成全数据集复用能大幅减少评估成本。生成流程整理成五个步骤第一步从COCO验证集中随机抽取500张图像作为优化集覆盖不同场景和语义类别。第二步初始化扰动为零向量epsilon设置为16/255。第三步循环优化每轮遍历20张图对每张图计算攻击损失并累积梯度。第四步每10轮更新一次扰动值并投影回epsilon球。第五步在500张图上做最终验证计算平均攻击成功率。优化过程中有个典型问题通用扰动的梯度方差很大训练不稳定。解决办法是梯度累积 学习率衰减。我用的累积步数是20初始学习率0.001每100轮减半。最终跑出来的通用扰动在Stable Diffusion v1.4的编辑任务上能达到65%到70%的平均攻击成功率。注意这个数值是对比我实验中的配置如果你改场景或模型版本结果会明显波动。6.5 DiffPure防御复现与参数调试DiffPure的复现核心在于加噪-去噪流程的控制。公式上给定输入图像x0先扩散到时间步t得到xt sqrt(alpha_t) * x0 sqrt(1 - alpha_t) * epsilon然后用扩散模型从xt去噪回x0_hat把x0_hat送入后续的生成流程。关键在于t的选取。t太小噪声水平不够对抗扰动洗不掉t太大原始语义被破坏生成结果失真。我的调试过程是这样的先在t100DDPM 1000步时间表下测试攻击成功率确实大幅下降但生成图像的CLIP相似度和原始输入的语义匹配度也崩了很多图像内容跟prompt对不上。然后逐步下调到t300攻击成功率降幅略小但图像质量明显改善。最终在t250附近取得相对好的平衡点。这个值仅供参考如果用其他模型或数据集需要重新扫一遍。另外DiffPure有个容易被忽视的问题去噪步数。如果用50步DDIM去噪时间开销已经很大如果改成20步防御效果明显下滑。在批量评估时建议用DDIM 30步作为默认值兼顾效果和效率。7. 常见问题与排查技巧实录7.1 梯度爆炸与消失这是扩散模型攻击最常遇到的问题。原因在于反向传播经过多步U-Net采样链时梯度要么指数增长要么快速消失。我的排查顺序如下先检查是不是采样器问题。确定性采样器DDIM比随机采样器DDPM的梯度要稳定得多如果必须用DDPM梯度爆炸概率会显著增加。检查梯度裁剪。在loss.backward()之后加一句torch.nn.utils.clip_grad_norm_([adv_image], max_norm1.0)能有效缓解梯度爆炸。检查损失函数的数值量级。cosine similarity的梯度天然在[-1,1]内但如果换用MSE或L1损失数值范围可能很大需要适当缩放。7.2 显存不足的缓解方案当攻击需要回传梯度时显存占用是纯推理的5到10倍。40G显存跑512x512图像DDIM 20步回传勉强能跑50步基本上必爆。缓解方案有三个方案一梯度检查点gradient checkpointing在U-Net的forward中开启use_checkpointing用计算换显存。方案二采用截断回传也就是只对最后5到10步采样回传梯度前面步骤当作固定前向。这个操作略粗糙但速度快而且在很多任务上攻击效果损失不大。方案三降低采样分辨率从512降到384或320显存压力大幅减少但攻击效果是否受影响需要重新验证。我实测下来显存不够时优先用方案二因为它的语义偏移效果最接近全量回传。方案一增加的计算时间有时候让人难以接受。7.3 攻击成功率上不去的排查思路如果新数据集上攻击成功率一直很低先别急着怀疑算法。大多数情况下是损失函数与攻击目标的匹配问题。比如做定向攻击时目标语义和目标图像之间的特征差异可能不够显著。CLIP空间的表征对某些差异不敏感比如“把猫变成狗”容易但“改变物体的材质从玻璃变成金属”就很难攻击成功因为CLIP embedding对材质的表征能力有限。这时候需要换一个更适合任务的损失函数或者在目标表征中融合更多层次的CLIP特征。还有一类问题来自条件注入机制。Stable Diffusion的文本条件通过交叉注意力影响U-Net对某些层的修改远比其他层影响大。如果按传统方式直接对所有层做梯度回传可能梯度被“不重要”的层稀释掉了。定向攻击时考虑提取特定层的注意力图把注意力图loss也纳入优化目标里攻击成功率往往提升明显。7.4 评测结果波动大怎么复现才可信扩散模型本身的采样随机性会造成结果波动即使固定种子不同显卡或库版本也可能产生微小差异。为了让baseline对比可信我建议所有攻击实验固定固定CUDA种子、PyTorch种子、numpy种子和Python随机种子。固定DDIM采样器不要用Euler或DPM-Solver不同采样器会让损失面发生变化。固定guidance_scale。Stable Diffusion的CFGClassifier-Free Guidance缩放系数对攻击成功率影响非常大我测试过guidance scale从3跳到10攻击成功率可以相差20个百分点以上。这四个因素固定好后同一实验在不同机器上跑出来的攻击成功率基本能控制在正负2个百分点以内。7.5 代码级避坑清单最后给一份我自己踩过坑之后总结的清单希望能帮你们省时间加载模型时设pipe.safety_checker None否则输出图像会被安全过滤器影响干扰评估结果。图像转tensor时确认归一化范围是[-1,1]还是[0,1]。Stable Diffusion的VAE期望输入在[-1,1]搞错的话生成的图像会暗一层或亮一层。文本编码器输入需要设置max_length77超过77个token的文本会被截断攻击的扰动空间也相应变化。做通用扰动时优化集和测试集的语义分布要尽量一致用COCO训练集做优化、COCO验证集做测试是可以的但如果换成LAION数据通用扰动的迁移性会下降。记录每次实验的完整配置到yaml文件包括随机种子、模型版本、采样器参数和所有超参。对抗样本的实验结果对配置敏感不留配置的复现等于没做。8. 经典baseline的横向对比结论做了一轮完整的基准测试之后我把几个核心baseline的优缺点和适用场景整理了一下方法优点缺点适用场景FGSM速度快适合快速试探白盒攻击成功率低初期验证流程时使用PGD稳定、可调参数多通用性强需要白盒梯度计算开销大各类场景的默认攻击基线CW扰动隐蔽性好范数可控收敛慢调参复杂对抗样本隐蔽性评估AutoAttack范式多攻击组合结论全面实现工作量大正式对比中作为强基线文本嵌入攻击高效维度低依赖CLIP文本表征质量text-to-image场景评估通用扰动一次生成全数据集复用攻击成功率弱于单图攻击大规模鲁棒性扫描DiffPure防御效果好推理开销大需要调参输入净化防御方向对抗训练从根本提升模型鲁棒性训练开销大生成质量受损对鲁棒性要求高的业务从我自己的经验来看做扩散模型的对抗鲁棒性研究PGD和DiffPure是无论如何都要包含的两个baseline。前者代表攻击能力的下限后者代表防御效果的上限。在此基础上再根据你的具体任务选择合适的补充方法。这一块内容如果深入进去其实还有挺多可写的比如对采样过程梯度近似的各种trick、不同注意力机制对攻击成功率的影响、潜在空间攻击与像素空间攻击的对比等等。我自己也是边跑实验边踩坑走过来的上面这些记录都是实际跑过之后沉淀下来的经验希望能给刚入坑或者正在搭建评估体系的朋友一些参考。
返回列表