NLP对抗样本的评测框架:从字符级扰动到语义保持的攻防实验设计

📅 2026/7/14 14:01:30
NLP对抗样本的评测框架:从字符级扰动到语义保持的攻防实验设计
NLP对抗样本的评测框架从字符级扰动到语义保持的攻防实验设计一、对抗样本评测的三个维度——有效性、不可察觉性与语义保持NLP对抗样本与视觉对抗样本之间存在一个根本差异图像的像素空间扰动几乎是无限的对任意像素的微小改变不会影响人类感知而文本的离散token空间使微小扰动的定义本身就成为一个问题。将一个词替换为另一个词——即使它们语义相近——也可能改变句子的流畅度、语法正确性甚至整体含义。因此NLP对抗攻击的评测必须在三个相互制约的维度上进行攻击有效性attack success rate — 模型预测是否被改变、扰动不可察觉性perturbation imperceptibility — 扰动是否被人类察觉和语义保持度semantic preservation — 扰动后的文本是否保留了原意。这三个维度构成一个不可能三角——优化其中一个通常会牺牲其他。graph TD A[NLP对抗样本质量] -- B[攻击有效性] A -- C[语义保持度] A -- D[不可察觉性] B -- B1[模型预测改变率] C -- C1[语义相似度 ≥0.9?] D -- D1[扰动率 15%?] B1 -.-|此消彼长| C1 C1 -.-|此消彼长| D1二、扰动空间的层级分类NLP对抗攻击可以根据扰动发生的语言学层级进行分类每个层级有不同的语义保持和不可察觉性特征字符级扰动Character-level包括插入、删除、交换、替换字符。如good→goood或g00d。这类扰动的优势是高攻击成功率模型对字符变化敏感但语义保持度通常较高人类可以轻易纠错。典型攻击HotFlip、TextBugger。词级扰动Word-level包括同义词替换、词序调换、词插入/删除。如the movie is great→the film is excellent。这类扰动在语义保持上表现最好但攻击成功率较低因为模型对同义词有一定鲁棒性。典型攻击TextFooler、BAE。句级扰动Sentence-level包括释义、从句添加、否定插入。如添加One might argue that前缀。这类扰动最难以被自动检测但语义保持的边界最模糊。# NLP对抗样本的统一评测框架 # 设计思路为不同层级的攻击提供统一的评测接口 import numpy as np from typing import List, Dict, Callable, Tuple from dataclasses import dataclass from sentence_transformers import SentenceTransformer from sklearn.metrics.pairwise import cosine_similarity dataclass class AdversarialExample: 对抗样本的数据结构 original_text: str perturbed_text: str original_label: int perturbation_type: str # char | word | sentence perturbations: List[dict] # 每个扰动的详情 class NLPAdversarialEvaluator: NLP对抗样本三维评测器 评测流程 1. 攻击有效性 → 模型预测是否改变 2. 语义保持度 → 基于sentence embedding的相似度 3. 不可察觉性 → 扰动率 语法正确性 def __init__( self, model_fn: Callable[[List[str]], np.ndarray], semantic_model: SentenceTransformer None, ): 参数: model_fn: 待评测模型的预测接口输入文本列表输出预测标签 semantic_model: 语义相似度模型默认all-MiniLM-L6-v2 self.predict model_fn self.semantic_model semantic_model or SentenceTransformer( all-MiniLM-L6-v2 ) def evaluate_attack_success( self, examples: List[AdversarialExample] ) - Dict: 评测攻击有效性 n_total len(examples) # 获取原始文本和扰动文本的预测 original_texts [e.original_text for e in examples] perturbed_texts [e.perturbed_text for e in examples] original_preds self.predict(original_texts) perturbed_preds self.predict(perturbed_texts) # 攻击成功率 预测发生改变的样本比例 changed (original_preds ! perturbed_preds).sum() success_rate changed / n_total # 按原始label分析攻击成功率揭示类别偏见 per_class_rates {} for label in np.unique(original_preds): mask original_preds label per_class_rates[int(label)] ( perturbed_preds[mask] ! original_preds[mask] ).mean() return { success_rate: success_rate, n_total: n_total, n_changed: int(changed), per_class_rates: per_class_rates, } def evaluate_semantic_preservation( self, examples: List[AdversarialExample], threshold: float 0.85, ) - Dict: 评测语义保持度 使用sentence embedding的余弦相似度作为语义保持的代理指标。 注这不是完美的语义衡量embedding模型本身有偏见 但作为大规模的自动化评测是当前的最佳可行方案。 original_texts [e.original_text for e in examples] perturbed_texts [e.perturbed_text for e in examples] # 编码所有文本 orig_embeddings self.semantic_model.encode( original_texts, show_progress_barFalse ) pert_embeddings self.semantic_model.encode( perturbed_texts, show_progress_barFalse ) # 计算余弦相似度 similarities np.array([ cosine_similarity( orig_embeddings[i:i1], pert_embeddings[i:i1] )[0][0] for i in range(len(original_texts)) ]) # 语义保持率 相似度超过阈值的样本比例 preserved (similarities threshold).mean() return { mean_similarity: float(similarities.mean()), std_similarity: float(similarities.std()), preservation_rate: float(preserved), min_similarity: float(similarities.min()), # 分布分位数用于识别异常低语义保持的样本 percentiles: { 25th: float(np.percentile(similarities, 25)), 50th: float(np.percentile(similarities, 50)), 75th: float(np.percentile(similarities, 75)), } } def evaluate_imperceptibility( self, examples: List[AdversarialExample], ) - Dict: 评测不可察觉性 使用两个代理指标 1. 扰动率修改的词数/总词数 2. 扰动类型分布 perturbation_rates [] type_distribution {} for ex in examples: # 简单词级扰动率基于空格分词 orig_words ex.original_text.split() pert_words ex.perturbed_text.split() # 使用编辑距离的归一化版本 n_changes len(ex.perturbations) pert_rate n_changes / max(len(orig_words), 1) perturbation_rates.append(pert_rate) # 统计扰动类型 for p in ex.perturbations: p_type p.get(type, unknown) type_distribution[p_type] type_distribution.get(p_type, 0) 1 return { mean_perturbation_rate: float(np.mean(perturbation_rates)), perturbation_rate_std: float(np.std(perturbation_rates)), type_distribution: type_distribution, low_perturbation_rate: float( (np.array(perturbation_rates) 0.15).mean() ), # 扰动率15%的样本比例 } def full_evaluation( self, examples: List[AdversarialExample], ) - Dict: 三维全景评测 返回值包含三个维度的所有指标以及一个综合攻击质量评分。 综合评分 success_rate × preservation_rate × (1 - perturbation_rate的惩罚) 这个公式隐含的假设三个维度同等重要。 调整权重可以通过修改公式中的系数实现。 attack_results self.evaluate_attack_success(examples) semantic_results self.evaluate_semantic_preservation(examples) imperceptibility_results self.evaluate_imperceptibility(examples) # 综合攻击质量仅在三个维度都达标的样本上计算 # 设计原则一个对抗样本只有在既改变了预测、又保持了语义、 # 且扰动不可察觉时才是高质量的对抗样本 quality_score ( attack_results[success_rate] * semantic_results[preservation_rate] * imperceptibility_results[low_perturbation_rate] ) return { attack_effectiveness: attack_results, semantic_preservation: semantic_results, imperceptibility: imperceptibility_results, composite_quality_score: quality_score, }三、评测中的常见陷阱语义相似度模型的偏见使用sentence embedding的余弦相似度来判断语义保持度这一方法本身就假设embedding模型对语义变化的敏感度是线性和无偏的。但实际上sentence transformer对某些类型的扰动如否定词插入的敏感度远低于人类感知。补救措施是对低相似度样本进行人工抽检校准阈值。白盒攻击与黑盒评测的混淆攻击者通常需要模型梯度白盒来生成对抗样本但评测时应在黑盒条件下报告攻击成功率——因为真实场景中的攻击者也不会拥有目标模型的完整信息。四、三维权衡的决策应用graph TD A[对抗样本评测] -- B{评测目的} B --|评估模型鲁棒性| C[优先攻击有效性br/容忍部分语义损失] B --|比较攻击方法| D[三个维度等权重br/使用综合质量评分] B --|构建防御| E[优先发现高语义保持br/的攻击,因为最难防御]五、总结NLP对抗样本的评测必须从攻击成功率的单维度扩展为攻击有效性×语义保持度×不可察觉性的三维框架。三个维度之间的内在权衡意味着不存在全面最优的对抗攻击——根据评测目的选择优先级是必要的。sentence embedding相似度作为语义保持的自动化代理在大规模评测中不可或缺但需要配合人工抽检来校准。