☰
扩散模型对抗样本Baselines全解析:原理、实践与评估
2026/10/4 17:48:19 网站建设 项目流程

1. 从生成到攻防:为什么扩散模型需要对抗样本基线

扩散模型这几年火到什么程度,相信不用我多说了。从图像生成到视频合成,从语音克隆到分子设计,几乎每一个跟"生成"沾边的领域,都能看到它的身影。但很多刚接触这个方向的同学容易忽略一个问题:模型能生成逼真内容,不代表它是安全的。当一个扩散模型被恶意输入欺骗,生成结果完全偏离预期时,这个模型还能被放心用在生产环境里吗?

这就要聊到对抗样本了。传统分类任务里,对抗样本是在输入上加一点人眼看不出的噪声,让模型给出错误分类。而在扩散模型这个体系下,对抗攻击的逻辑更复杂,也更值得深挖。因为扩散模型的输入输出空间都相当宽泛——你可以攻击它的文本编码器,让它把"一只猫"理解成"一只狗";可以攻击它的潜空间表征,让生成结果彻底乱掉;甚至可以针对采样过程中的某一时间步做扰动,造成全局崩溃。

正因为攻击面广、攻击方式多样,这个领域才催生了一批经典的baselines。这些baselines不只是给学术论文做对比实验用的,它们更是理解扩散模型鲁棒性的入口。如果你正在研究扩散模型的安全问题、想在生成任务里加入对抗训练,或者单纯想搞明白现有防御方法到底在防什么,那这篇文章就是给你准备的。

我会从扩散模型的相关基础说起,逐个拆解那些绕不开的经典攻击方法,包括针对潜在扩散模型的攻击思路、评估这些方法时容易踩的坑,再把手上的实测经验一并分享出来。内容会偏实践,公式点到为止,重点是让你看完之后能明确知道:某个baseline在什么场景下有效、在什么场景下失效、以及为什么。

2. 先对齐基本盘:扩散模型和对抗样本的底层逻辑

在铺开讲baselines之前,得先把两块底层逻辑对齐。不然很多方法设计出来之后,你会觉得"为什么要这么干"很费解。

2.1 扩散模型的两阶段结构与攻击面

扩散模型,尤其以潜在扩散模型(LDM)为代表的那一类,基本可以拆成两个阶段。前向过程是把干净图像逐步加噪,最后变成一个纯高斯噪声;反向过程则是从高斯噪声出发,通过去噪网络一步步还原出图像。看起来是单纯的加噪和去噪,但实际工程里LDM还额外多了一个环节——先把图像通过编码器压缩到潜在空间,在潜空间里完成扩散和去噪,再通过解码器还原回像素空间。

这个设计极大地降低了计算成本,也让模型的应用范围扩大到了Stable Diffusion这样的超大模型场景。但同时也带来了一个新问题:攻击面变多了。

  • 攻击可以发生在文本条件编码阶段,比如对抗性提示词,直接扰乱CLIP文本编码器对语义的理解。
  • 攻击可以发生在潜空间初始化阶段,比如构造一个恶意的初始噪声张量,让后续去噪全部走偏。
  • 攻击可以发生在采样过程,比如在某个时间步的预测结果上叠加精心计算的扰动。
  • 攻击还可以发生在解码阶段,让还原出的图像在像素层面出现异常。

理解这些攻击面,是理解baselines的前提。因为每个经典baseline,往往只针对其中一个或两个攻击面做文章。

2.2 分类任务对抗攻击与生成任务对抗攻击的本质差异

传统图像分类的对抗攻击,本质上是在输入空间里找一个邻域内的点,让模型的Cross-Entropy损失变大。优化目标很直接,评估方式也很直接——攻击成功就是分类标签变了。

生成任务的对抗攻击完全不是这套逻辑。你没有一个明确的标签来判断"攻击是否成功",而是要回答一个更模糊的问题:生成出的东西还是不是用户想要的?这就带来两个麻烦。

第一,优化目标不好定。分类任务可以用交叉熵,生成任务该用什么?有人用CLIP分数作为代理指标,有人用感知距离,有人用结构相似度,还有直接用下游任务精度来评估的。选不同的代理指标,最后选出来的"对抗样本"就是完全不同的东西。

第二,约束条件不好定。分类任务里对扰动的约束通常是Lp范数球,生成任务里由于攻击往往发生在潜空间或文本空间,Lp范数的含义变得很微妙。一个在潜空间里看起来很小的扰动,解码回像素空间可能就是一个巨大的语义漂移。

这也是为什么扩散模型的对抗样本baselines不能直接照搬分类任务里的PGD、CW那些方法,必须在扰动空间、优化目标、评估方式上重新设计。后面要讲的几种方法,本质上都是在这个"重新设计"的过程中逐步沉淀下来的。

3. 扩散模型攻击赛道的经典baselines逐个拆解

这个方向从兴起到现在,其实迭代出了好几代工作。我按时间线和攻击思路两条线来拆,这样大家既能看出方法演进的轨迹,也能明白不同方法之间的底层联系。

3.1 直接优化采样轨迹的攻击:DiffAttack

首先要聊的是DiffAttack,这套方法在扩散模型安全研究里属于旗帜性存在。它背后的核心洞察是:扩散模型的采样过程是一个多步迭代过程,任何中间时间步的微小偏差都可能被后续步骤放大,最终导致生成结果的彻底漂移。DiffAttack的出发点,就是主动利用这个特性来做攻击。

它设计的对抗损失有一个很明显的特征——搜索多样性。攻击时不仅要让最终生成结果偏离预期,还要让中间步骤的预测出现明显偏离。具体做法是对采样轨迹上的多个时间步同时施加攻击信号,而不是只盯着最后一步的输出做优化。这样做有一个额外的好处:即便防御方使用了某种去噪预处理,把最后几步的扰动抹掉了一部分,中间步骤已经被污染的轨迹仍然会让最终结果偏掉。

我测试下来发现,DiffAttack对使用DDIM采样的模型特别有效,因为DDIM的采样轨迹相对确定,反向过程可以被精确预测;反过来看,如果目标模型用了随机性较强的采样策略,比如加了额外噪声的SDE求解器,那DiffAttack的效果会有明显折扣。这个特性在对比实验里很容易被忽略,很多人拿DiffAttack做完baseline就直接下结论说"攻击有效"或"攻击无效",却不看一眼目标模型的采样器类型,这是要特别注意的。

3.2 黑盒场景的通用攻击框架:AdvDM

DiffAttack是白盒攻击,需要拿到梯度和模型参数。但实际场景里,很多扩散模型服务只对外提供API,你拿不到任何梯度信息。这就轮到AdvDM登场了。

AdvDM解决的核心问题是怎么在完全黑盒的情况下生成对抗样本。它的思路很巧妙:把攻击目标定义在一个更大的范围上,让整个对抗样本的生成以"预期图像分布"与"生成结果分布"之间的距离最小化为目标,而不是针对某一个具体的目标图像或单一采样轨迹。这样设计带来的一个巨大好处是,对抗样本具有更强的迁移性——在黑盒模型上学到的扰动,往往可以直接迁移到另一个未知模型上。

我个人理解AdvDM的底层逻辑,其实可以类比成"分布层面的毒性攻击"。它不追求让某一类图像生成失败,而是致力于在更泛的层面让模型整体性能下滑。实际测试里,如果攻击用的代理模型和目标模型结构比较接近,AdvDM的迁移效果会相当可观;但如果结构差异太大,比如从UNet结构迁移到DiT结构,攻击效果会明显下降。这也是当前黑盒攻击研究的普遍痛点。

3.3 文本驱动的对抗攻击:针对CLIP编码器的对抗提示词

在潜在扩散模型里,文本编码器是极其关键的入口。CLIP编码器把用户输入的文本映射成语义向量,再通过CrossAttention去影响图像生成过程。那么很自然的一个攻击思路就是:如果我能构造一段文本,它在人类看来没什么异常,但经过CLIP编码之后语义完全偏离,生成结果不就崩了吗?

这组思路的代表方法是针对提示词优化的攻击手段。它们把离散的文本token当成一个连续向量来优化,迭代更新token的embedding,最终得到一段在embedding空间里被扰动过的对抗性提示词。这段提示词看起来可能还是"一只红色的鸟",但在模型的语义空间里已经被推向了"一片模糊的噪点"或某个不相关的概念。

我实际复现过这类方法,有一个比较深的体会:对抗提示词攻击的难点不在优化本身,而在于如何保持"语义表面的一致"。如果你完全不受约束地优化,最后得到的可能是一串无意义字符,人类一眼就能看出它是攻击输入。但真正有价值的对抗提示词,需要在embedding空间和token空间的约束下做交替优化,让它既符合人类语义、又能欺骗模型。这个平衡点是这类baseline的精华所在。

3.4 通用攻击范式:PGD类方法在扩散模型中的适配

PGD(Projected Gradient Descent,投影梯度下降)是分类任务里最经典的攻击方法,很多研究者在刚开始涉足扩散模型对抗攻击时,做的第一件事就是把PGD直接搬过来用。输入图像经过一个可微的扩散过程,计算损失,然后沿着梯度方向迭代更新输入,再把输入投影回允许的扰动范围内。

这个方法能用,但效果会受到很大限制。原因也很直接:扩散模型的迭代去噪过程非常深,几十步的反向传播会导致梯度消失和梯度爆炸。尤其是当你使用DDIM的确定性采样时,完整的反向传播要穿越几十个去噪网络,计算图的深度惊人,训练显存和时间的消耗都是巨大的。

所以后续很多工作沿着PGD框架做适配时,基本都在解决同一个问题——怎么在保证攻击效果的同时降低反向传播的复杂度。常见的做法包括:只反传部分采样步长、使用代理梯度近似、或者把攻击信号投影到潜空间而不是像素空间。这些改进方案慢慢也演化成了后续很多baselines的底层构件。

我自己的建议是:如果你只想快速验证一个防御模型的有效性,直接用简单适配后的PGD就足够了;但如果你想严谨评估防御模型的上限,还是应该搭配DiffAttack这类专门设计的攻击方法。因为PGD在扩散模型上受梯度估计误差的影响太大,容易出现"表面有效、实际脆弱"的结论偏差。

4. 典型攻击方法核心机制对比

这么多方法摆在面前,容易让人懵圈——到底该用哪个方法做baseline?我建议你用下面这套表格来快速做决策。

方法分类代表方法攻击背景核心优化空间主要适用场景主要局限
轨迹攻击DiffAttack白盒多时间步采样轨迹对已知模型做高强度的针对性攻击评估对随机采样器效果下降明显
分布级攻击AdvDM黑盒潜空间或像素空间的扰动分布迁移攻击、未知模型鲁棒性评估代理模型与目标模型结构差异大时效果大幅下降
提示词攻击基于Embedding优化的方法黑盒/白盒文本token的embedding针对文生图模型的语义攻击需要保持语义表面一致性,优化复杂度高
PGD适配多种白盒像素空间或潜空间快速验证防御有效性反向传播深度大,计算开销高

这张表的用途不是让你记住每个方法的细节,而是在设计实验时帮你对齐场景。比如说你的目标模型是开源的Stable Diffusion,你又想做一个新的防御方法,那DiffAttack应该进对比;如果目标是评估黑盒API的安全性,那AdvDM和提示词攻击必须安排上;如果想要一个大而全的评估结果,建议至少覆盖这四类方法里的三种。

有一点必须反复强调:baseline的选择直接影响你实验结论的可靠程度。如果只用PGD类的简单攻击做评测,得出的"模型很鲁棒"结论很可能经不起推敲。真实世界中的攻击者不会只用最简单的招式。

5. 潜在扩散模型的专属攻击视角与评估陷阱

潜在扩散模型是当前扩散模型应用中最常见的一个子类,但它和直接在像素空间做扩散的模型有很大区别。如果不理解这些区别,你在做攻击评估时可能会出现"实验做完,结论却完全不对"的情况。

5.1 潜空间攻击的本质:压缩域里的扰动放大

LDM之所以效率高,是因为它把图像从像素空间压缩到潜空间。这个压缩过程是有损的,但也正是这个"损"给了攻击者可乘之机。在潜空间里一个相对小的扰动,经过解码器放大之后,在像素空间可能是一个结构性的大扰动。这个特性意味着,潜空间攻击的扰动幅度衡量标准不能沿用像素空间的L2/Linf约束,你要重新校准攻击预算。

我在实测中经常遇到一个现象:同样的攻击方法,在像素空间做攻击,扰动幅度看起来很大,但攻击成功率不算高;搬到潜空间做攻击后,扰动幅度数值上很小,攻击成功率却飙升。原因就在于潜空间的各个通道具有不同的语义重要性,解码器对这些通道的敏感度也完全不同。

所以如果你评估的模型是LDM,我强烈建议攻击和防御的实验都同时汇报像素空间和潜空间的扰动指标。只报一边,往往会让结论失真。

5.2 代理指标陷阱:CLIP分数不是万能的

在扩散模型攻击评估里,最常用的代理指标就是CLIP Score。攻击效果好不好?看CLIP Score降了多少。但这个指标有一个系统性缺陷:CLIP Score的变化很多时候反映的是"风格偏移"而不是"内容错误"。

我做一个简单的例子你就能理解。把一张"戴着帽子的狗"的图片攻击过后,CLIP分数可能从0.30掉到0.25,但你仔细看生成的图,狗狗依然清晰,只是帽子从红色变成了蓝色。这算攻击成功吗?从CLIP分数上看,语义确实偏离了;从人类感知上看,猫咪还是猫咪,狗还是狗,只是局部属性变了。所以CLIP分数的落差无法精确反映对抗样本的实际威胁程度。

这就是为什么评估扩散模型对抗攻击时,应该搭配多个指标:结构距离(如LPIPS)、语义保留度(如FaceID相似度或物体检测置信度)、以及人工评估。单独依赖CLIP分数,极容易在高鲁棒性模型上得出"攻击成功"但人类完全没感知的结论。

5.3 时间步采样策略对攻击成功率的影响

扩散模型的反向过程通常要经过20到50步迭代,攻击者没必要对每一个时间步都施加扰动。不同的baseline对时间步的选择策略差异巨大:

  • 有的方法只在前期时间步施加攻击,因为前期的去噪决定了图像的结构布局。
  • 有的方法只在后期时间步攻击,因为后期决定的是纹理细节。
  • 有的方法均匀选取若干时间步,攻击效果更均衡。
  • 有的方法则用注意力机制来动态选取"最关键"的时间步。

这个差异带来的结果是:同一个攻击方法,在20步采样下表现很好,换到50步采样下可能直接失效。很多研究者忽略了这个变量,导致复现别人实验时,攻击效果大打折扣。

如果你设计自己的新攻击方法,建议在论文里清晰说明时间步选择策略,并至少对比两种时间步采样方案;如果你只是拿这些baselines做评测,那么至少要在相同的时间步设置下统一测试所有方法,跨设置对比本身就是不可靠的。

6. 基于Pytorch的实操参考:跑通一套攻击baseline

光讲理论不实践,等于白看。下面我手把手带大家跑一个简化但完整的攻击流程。这里直接操作LDM框架,采用的是类似DistDiffAttack的一种简化思路,目的是让大家看明白攻击管线到底怎么搭起来的,代码可以直接参考。

6.1 环境准备和关键依赖

这里假设你已经有基本的深度学习环境,PyTorch 2.0以上,一台带CUDA的GPU。需要额外安装的库很少,关键就两个:diffusers用来加载现成的扩散模型,torchvision用来处理图像变换。

pip install diffusers transformers accelerate torchvision

如果是在国内网络环境,huggingface_hub下载模型可能会出现各种奇怪问题,建议提前配置镜像源。这一步卡住的人非常多,特此提醒。

6.2 加载预训练模型

以Stable Diffusion v1.4为例,这是LDM架构的经典形态。加载过程非常简单:

import torch from diffusers import StableDiffusionPipeline model_id = "CompVis/stable-diffusion-v1-4" pipe = StableDiffusionPipeline.from_pretrained( model_id, torch_dtype=torch.float16, safety_checker=None, ) pipe = pipe.to("cuda")

这里设置safety_checker=None的目的是去掉NSFW过滤器,因为在攻击实验里,我们需要观察模型在对抗扰动下的完整输出分布,安全过滤器会截断部分输出,干扰最终评估。

生成一张正常的基准图像:

prompt = "a photo of a cute cat sitting on a sofa" with torch.no_grad(): image = pipe(prompt, num_inference_steps=50, guidance_scale=7.5).images[0] image.save("clean.png")

6.3 构造攻击损失,定义对抗样本优化循环

现在进入核心环节。这个简化版攻击的核心思路是:固定文本条件不变,优化一个对抗性的初始潜变量,让采样出的图像与"目标语义"彻底偏离。

我们用一个预训练的图像分类器或CLIP模型来提取预期图像的特征,再让攻击后的生成图像在特征空间中离得越远越好。简化版本直接用MSE损失让初始潜变量偏离原始分布。

def attack_ldm(pipe, prompt, eps=0.05, num_iter=20, lr=0.01): # 使用固定的随机种子保证初始潜变量一致 generator = torch.manual_seed(42) latents = torch.randn( (1, 4, 64, 64), generator=generator, device="cuda", dtype=torch.float16, ) latents.requires_grad_(True) # 文本编码 text_input = pipe.tokenizer( prompt, padding="max_length", max_length=pipe.tokenizer.model_max_length, truncation=True, return_tensors="pt", ) text_embeddings = pipe.text_encoder(text_input.input_ids.to("cuda"))[0] optimizer = torch.optim.Adam([latents], lr=lr) for i in range(num_iter): optimizer.zero_grad() # 从当前latents出发,跑完整采样过程 # 为了简化,这里只跑40步DDIM with torch.enable_grad(): # 重建采样需要绕过部分diffusers内部实现,这里用pipe的scheduler pipe.scheduler.set_timesteps(40, device="cuda") latents_current = latents.clone() for t in pipe.scheduler.timesteps: latent_model_input = torch.cat([latents_current] * 2) with torch.no_grad(): noise_pred = pipe.unet( latent_model_input, t, encoder_hidden_states=torch.cat([text_embeddings] * 2), ).sample # CFG noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + 7.5 * (noise_pred_text - noise_pred_uncond) latents_current = pipe.scheduler.step( noise_pred, t, latents_current ).prev_sample # 解码 with torch.no_grad(): image = pipe.vae.decode(latents_current / 0.18215).sample # 攻击损失:让图像均值偏离正常范围 loss = -image.mean() # 简化攻击目标 loss.backward() optimizer.step() # 投影约束 with torch.no_grad(): latents.data = torch.clamp(latents.data, -eps, eps) return latents.detach()

这段代码做了以下几件事:

  1. 初始化一个需要梯度的随机潜变量。
  2. 手动遍历调度器的时间步,执行完整的DDIM采样循环。
  3. 使用CFG(Classifier-Free Guidance)合并条件与非条件预测结果。
  4. 用image.mean()作为简化攻击损失的代表。
  5. 每轮优化后对latents做投影约束,确保不跑飞。

实际使用时,这个简化损失会比较粗糙,因为它没有结合文本语义。更合理的做法是换成CLIP loss或感知损失。

6.4 完整攻击流程汇总

把上面几个模块串起来,完整流程是:

clean_latents = torch.randn( (1, 4, 64, 64), generator=torch.manual_seed(42), device="cuda", dtype=torch.float16, ) adv_latents = attack_ldm( pipe, prompt="a photo of a cute cat sitting on a sofa", eps=0.08, num_iter=30, lr=0.005, ) # 使用对抗latents生成攻击后的图像 with torch.no_grad(): pipe.scheduler.set_timesteps(50, device="cuda") latents_current = adv_latents.clone() text_input = pipe.tokenizer( prompt, padding="max_length", max_length=pipe.tokenizer.model_max_length, truncation=True, return_tensors="pt", ) text_embeddings = pipe.text_encoder(text_input.input_ids.to("cuda"))[0] for t in pipe.scheduler.timesteps: latent_model_input = torch.cat([latents_current] * 2) with torch.no_grad(): noise_pred = pipe.unet( latent_model_input, t, encoder_hidden_states=torch.cat([text_embeddings] * 2), ).sample noise_pred_uncond, noise_pred_text = noise_pred.chunk(2) noise_pred = noise_pred_uncond + 7.5 * (noise_pred_text - noise_pred_uncond) latents_current = pipe.scheduler.step(noise_pred, t, latents_current).prev_sample adversarial_image = pipe.vae.decode(latents_current / 0.18215).sample # 保存结果,对比两张图 from torchvision.utils import save_image clean_latents_for_decode = clean_latents / 0.18215 with torch.no_grad(): clean_image = pipe.vae.decode(clean_latents_for_decode).sample save_image((clean_image + 1) / 2, "clean_output.png") save_image((adversarial_image + 1) / 2, "attack_output.png")

跑完之后,你会得到两张图,一张是正常采样得到的图,一张是经过对抗扰动后生成的图。正常情况下,他们应该有肉眼可见的语义差异,比如猫的形态完全变形,或者直接生成了完全无关的内容。

6.5 代码运行中的常见报错与对应解法

这段代码在实际跑的过程中,有几个高频坑位,我提前给你列出来。

坑位一:显存溢出(OOM)。因为整个反传过程要通过40步的UNet,显存峰值会非常高。解决办法有两个:降低采样的时间步数,比如从40降到10;或者开启梯度检查点。

pipe.unet.enable_gradient_checkpointing()

坑位二:梯度全零。如果你发现loss一直不下降,先检查有没有在不该加torch.no_grad()的地方误加。尤其是VAE解码器到损失函数这一段,必须有梯度流通。

坑位三:图像全黑或全白。这种情况十有八九是解码时的缩放系数不对。Stable Diffusion系列模型的VAE输出要在/0.18215之后才能正确地送入scheduler,这个缩放系数是固定值,不同模型略有差异,换模型时别忘了重新确认。

坑位四:调度器的timesteps与采样步数不一致。如果你在pipe.scheduler.set_timesteps(50)之后又手动改了步数,可能会出现索引错位。解决方式是每次采样前重新设置timesteps。

7. 实测避坑指南:那些论文里不写但你一定会遇到的破事

代码跑通了只是一个开始。真正让一个baseline发挥价值的,取决于你有没有绕开下面这些坑。这些都是我一次次踩出来的,价值不比任何论文代码低。

7.1 随机种子的影响比你想的大得多

采样过程中,每一步都有随机噪声的参与,即便你是用DDIM这样的确定性采样器,初始潜变量也是随机的。这意味着攻击实验的可复现性天生就比较差。

所以做实验时一定要固定三个地方的种子:

  1. 初始潜变量的生成种子。
  2. PyTorch的全局随机种子。
  3. NumPy的随机种子(很多预处理库会依赖它)。

不固定种子的话,两次实验之间的攻击成功率差异可能高达10个百分点以上。如果你发现实验结果波动巨大,先怀疑种子,再去怀疑方法本身。

7.2 CFG系数对攻击难度的影响

Classifier-Free Guidance的系数(也就是guidance_scale)直接影响生成结果的多样性。我测试下来,guidance_scale越高,模型越遵循文本条件,攻击也越难成功;guidance_scale越低,生成结果更随机,攻击效果更好。

这意味着同一套攻击方法,在guidance_scale=7.5时可能只有20%的攻击成功率,在guidance_scale=2.0时可能冲到80%。这是一条被绝大多数baselines论文忽略的重要变量。

做防御评测时,我强烈建议测试多组CFG系数,并逐一汇报结果。否则你无法判断"模型鲁棒性提升"是因为防御生效了,还是因为CFG系数太高导致攻击变难了。

7.3 解码器返回的图像范围如何对齐

扩散模型的VAE解码器输出值域通常在[-1, 1]之间,但经过clip之后可能会被截断。这个看似微小的细节会在多步采样时产生累积偏差。尤其在几十步的循环里,数值如果始终处于极端值附近,最终图像会出现色偏或条纹伪影。

实测中最稳妥的做法是:在保存图像或用CLIP评分之前,手动对图像张量做一次(image + 1) / 2的归一化。如果发现图像出现异常色偏,先检查这一步有没有漏掉。

7.4 对比实验一定要统一采样器

前面提到过DiffAttack对DDIM有效但对SDE求解器效果会下降。这背后的原理是随机采样器引入了额外噪声,攻击信号在噪声扰动下被稀释了。所以对比多个baselines时,所有方法必须在同一个采样器、同一个采样步数、同一个CFG系数下跑,否则比较出来的结论没有任何意义。

8. 评估指标的正确打开方式:别让CLIP分数骗了你

评估一套攻击方法的时候,量化指标是必不可少的。但扩散模型的评估指标并不像分类任务那样一目了然,用错指标比不用指标更糟。下面把几个常用指标的适用边界说清楚。

8.1 结构距离指标:LPIPS

LPIPS(Learned Perceptual Image Patch Similarity)衡量的是两张图片在感知层面的距离,数值越大表示感知差异越大。在对抗攻击评测里,LPIPS常被用来衡量攻击对生成结果的破坏程度。

LPIPS的优势在于,它比L2距离更贴近人类感知。但它对纹理细节的变化敏感,对严重的语义错误反而不够敏感。比如一张图里的猫变成了狗,但整体构图、色彩、纹理风格保持接近,LPIPS可能只给出一个中等偏上的分数,掩盖了语义层面的严重错误。所以LPIPS适合配合其他指标一起用,单独使用会误导。

8.2 语义一致性指标:CLIP Score与它的局限

CLIP Score是把生成图像和文本提示分别编码,然后计算余弦相似度。它的优点是非常方便、无需人工标注;缺点前面也说了,对风格变化敏感、对具体的语义实体变化不敏感。

一个更稳妥的使用方式是:同时计算CLIP Score下降值和下降方向。如果CLIP Score降到很低,至少说明攻击产生了某种跨模态的语义扰动;但如果只是从0.3降到0.28,那就需要额外看生成图像来确认这次攻击是否有实际威胁。

8.3 面向特定任务的下游指标

如果攻击的是真实业务场景里使用的扩散模型,那还需要用下游任务指标来评估攻击的实际破坏力。

  • 人脸生成模型:用FaceID相似度衡量身份保留程度。
  • 物体生成模型:用目标检测器的置信度衡量关键物体是否被保留。
  • 图像编辑模型:用编辑指令的遵循度做人工评估。

这些指标通常比通用CLIP分数更能反映真实攻击威胁。做研究阶段的baseline对比时可能用不上,但当你把方案落地到实际业务时,就完全绕不开它们了。

9. 防御视角下的baseline意义:用攻击找短板

聊了这么多攻击方法,不代表这个话题的意义只是为了"破解"模型。事实上,对抗样本baselines在模型防御研究中承担的角色,远比"攻击工具"要重要得多。

一个不具备对抗鲁棒性的扩散模型,在实际部署中面临的风险是真实的。比如文生图模型被用于内容审核辅助场景时,攻击者可以构造对抗提示词让生成结果绕过审核;比如图像编辑服务如果被恶意构造的输入攻击,生成结果可能严重偏离用户意图,带来不可控的影响。

防御方法大体上有这么几类思路:基于对抗训练的方法、基于输入预处理的防御、基于采样过程修正的防御、以及基于检测器的防御。不管哪一类,它们的评估环节都必须依赖对抗样本baselines。只有在强攻击下依然保持性能的防御,才是真正可信的防御。

所以我的建议是:如果在做扩散模型相关的研究或者应用,别只盯着生成效果好的指标,一定要把鲁棒性评估纳入到测试流程里来。对抗样本baselines不是论文里的装饰品,而是你判断模型是否"可用"的一把硬尺子。

10. 关于baseline选型和实验结果解读的几点个人建议

最后再分享一些我自己在实际项目里的体会,算是给准备入坑的同学一些参考。

第一,不要迷信任何单一baseline。扩散模型的攻击和防御,本质上是一个攻防对抗的博弈过程,单一方法的评估结果只能代表非常有限的能力边界。做实验时尽量覆盖白盒、黑盒、文本驱动这三种大方向的攻击,才能对模型的鲁棒性有一个全面的认知。

第二,复现baseline前先读透代码里的采样细节。很多baseline的论文写得非常模糊,关键时刻只能靠读源码理解。通常最影响实验效果的都是那些"看起来不打紧"的实现细节,比如时间步选择策略、梯度裁剪方式、投影约束使用的范数等。读代码花费的时间,会以"少踩坑"的方式加倍还给你。

第三,合理的baseline选取逻辑是:先明确你的威胁模型,再选择对应的baseline。如果你关心的是API黑盒攻击,就别用DiffAttack来证明模型安全;如果你关心的是白盒安全性,那AdvDM只能作为辅助参考。威胁模型定错了,后续所有实验都会变得没有意义。

说实话,扩散模型的对抗样本方向到现在仍然有大量问题没有解决。多时间步攻击的计算效率瓶颈、黑盒攻击的迁移性问题、语义级攻击的统一量化标准,这些都还属于开放问题。但正因如此,这个方向在学术和工业场景里都有不错的研究价值。希望这篇文章能帮你把这几个经典baseline的来龙去脉理清楚,在真正动手做实验的时候少走一些我已经走过的弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询