为 NLP 模型生成对抗样本
[TextAttack 的 ReadTheDocs 文档]
简介 •
环境配置 •
使用方法 •
设计模式
TextAttack 是一个可以实行自然语言处理的 Python 框架,用于方便快捷地进行对抗攻击,增强数据,以及训练模型。
如果你在寻找 TextAttacks 支持的预训练模型,请访问 TextAttack Model Zoo。
加入TextAttack Slack 频道,获取在线帮助与更新提示!
支持 Python 3.6 及以上。支持 CPU ,使用兼容 CUDA 的 GPU ,还可以大幅度提高代码运行速度。使用 pip 轻松安装 TextAttack:
pip install textattack
当 TextAttack 安装完成,可以通过命令行 (textattack ...
)
或者通过 python 模块 (python -m textattack ...
) 运行 TextAttack。
小提醒:TextAttack 默认将文件下载保存在
~/.cache/textattack/
路径。这些文件包括预训练模型,数据集,以及配置文件config.yaml
。若需更改缓存路径,可以通过设置环境变量TA_CACHE_DIR
。(例如:TA_CACHE_DIR=/tmp/ textattack attack ...
).
textattack --help
TextAttack 的主要功能均可通过 textattack
命令运行。常用的两个命令为 textattack attack <args>
和 textattack augment <args>
。你可以通过如下命令获取关于所有命令的介绍:
textattack --help
或者获取具体命令的用法,例如:
textattack attack --help
文件夹 examples/
里是一些示例脚本,展示了 TextAttack 的常用方法,包括训练模型,对抗攻击,以及数据增强。文档网站 中有 TextAttack 基本用法的详尽说明与示例,包括自定义攻击的变换与约束。
textattack attack --help
尝试运行对抗攻击,最快捷的方法是通过命令行接口:textattack attack
小提醒:如果你的机器有多个 GPU,可以通过
--parallel
参数将对抗攻击分布在多个 GPU 上。这对一些攻击策略的性能提升巨大。
下面是几个具体的例子:
对 MR 情感分类数据集上训练的 BERT 模型进行 TextFooler 攻击:
textattack attack --recipe textfooler --model bert-base-uncased-mr --num-examples 100
对 Quora 问句对数据集上训练的 DistilBERT 模型进行 DeepWordBug 攻击:
textattack attack --model distilbert-base-uncased-cola --recipe deepwordbug --num-examples 100
对 MR 数据集上训练的 LSTM 模型:设置束搜索宽度为 4,使用词嵌入转换进行无目标攻击:
textattack attack --model lstm-mr --num-examples 20 \
--search-method beam-search^beam_width=4 --transformation word-swap-embedding \
--constraints repeat stopword max-words-perturbed^max_num_words=2 embedding^min_cos_sim=0.8 part-of-speech \
--goal-function untargeted-classification
小提醒:除了设置具体的数据集与样本数量,你还可以通过传入
--interactive
参数,对用户输入的文本进行攻击。
textattack attack --recipe [recipe_name]
我们实现了一些文献中的攻击策略(Attack recipe)。使用 textattack list attack-recipes
命令可以列出所有内置的攻击策略。
运行攻击策略:textattack attack --recipe [recipe_name]
—————— 攻击策略 —————— | —————— 目标函数 —————— | —————— 约束条件 —————— | —————— 变换方式 —————— | ——————— 搜索方法 ——————— | 主要思想 |
---|---|---|---|---|---|
对于分类任务的攻击策略,例如情感分类和文本蕴含任务: | |||||
alzantot |
无目标 {分类,蕴含} |
被扰动词的比例,语言模型的困惑度,词嵌入的距离 | Counter-fitted 词嵌入替换 | 遗传算法 | 来自 (["Generating Natural Language Adversarial Examples" (Alzantot et al., 2018)](https://arxiv.org/abs/1804.07998)) |
bae |
无目标 分类 |
USE 通用句子编码向量的 cosine 相似度 | BERT 遮罩词预测 | 对 WIR 的贪心搜索 | 使用 BERT 语言模型作为变换的攻击方法,来自 (["BAE: BERT-based Adversarial Examples for Text Classification" (Garg & Ramakrishnan, 2019)](https://arxiv.org/abs/2004.01970)). |
bert-attack |
无目标 分类 |
USE 通用句子编码向量的 cosine 相似度, 被扰动词的最大数量 | BERT 遮罩词预测 (包括对 subword 的扩充) | 对 WIR 的贪心搜索 | (["BERT-ATTACK: Adversarial Attack Against BERT Using BERT" (Li et al., 2020)](https://arxiv.org/abs/2004.09984)) |
checklist |
{无目标,有目标} 分类 |
checklist 距离 | 简写,扩写,以及命名实体替换 | 对 WIR 的贪心搜索 | CheckList 中实现的不变性检验(["Beyond Accuracy: Behavioral Testing of NLP models with CheckList" (Ribeiro et al., 2020)](https://arxiv.org/abs/2005.04118)) |
clare (*coming soon*) |
无目标 {分类,蕴含} |
RoBERTa 掩码语言模型 | 词的替换,插入,合并 | 贪心搜索 | ["Contextualized Perturbation for Textual Adversarial Attack" (Li et al., 2020)](https://arxiv.org/abs/2009.07502)) |
deepwordbug |
{无目标,有目标} 分类 |
Levenshtein 编辑距离 | {字符的插入,删除,替换,以及临近字符交换} | 对 WIR 的贪心搜索 | 贪心搜索 replace-1 分数,多种变换的字符交换式的攻击 (["Black-box Generation of Adversarial Text Sequences to Evade Deep Learning Classifiers" (Gao et al., 2018)](https://arxiv.org/abs/1801.04354) |
fast-alzantot |
无目标 {分类,蕴含} |
被扰动词的比例,语言模型的困惑度,词嵌入的距离 | Counter-fitted 词嵌入替换 | 遗传算法 | 改进过的更快的 Alzantot et al. 遗传算法, 来自 (["Certified Robustness to Adversarial Word Substitutions" (Jia et al., 2019)](https://arxiv.org/abs/1909.00986)) |
hotflip (word swap) |
无目标 分类 |
词嵌入的 cosine 相似度,词性的匹配,被扰动词的数量 | 基于梯度的词的交换 | 束搜索 | (["HotFlip: White-Box Adversarial Examples for Text Classification" (Ebrahimi et al., 2017)](https://arxiv.org/abs/1712.06751)) |
iga |
无目标 {分类,蕴含} |
被扰动词的比例,词嵌入的距离 | Counter-fitted 词嵌入替换 | 遗传算法 | 改进的基于遗传算法的词替换,来自 (["Natural Language Adversarial Attacks and Defenses in Word Level (Wang et al., 2019)"](https://arxiv.org/abs/1909.06723) |
input-reduction |
输入归约 | 词的删除 | 对 WIR 的贪心搜索 | 基于词重要性排序的贪心攻击方法,在缩减输入词的同时保持预测结果不变 (["Pathologies of Neural Models Make Interpretation Difficult" (Feng et al., 2018)](https://arxiv.org/pdf/1804.07781.pdf)) | |
kuleshov |
无目标 分类 |
Thought vector 编码的 cosine 相似度, 语言模型给出的相似度概率 | Counter-fitted 词嵌入替换 | 贪心的词的替换 | (["Adversarial Examples for Natural Language Classification Problems" (Kuleshov et al., 2018)](https://openreview.net/pdf?id=r1QZ3zbAZ)) |
pruthi |
无目标 分类 |
词的最短长度,被扰动词的最大数量 | {临近字符替换,字符的插入与删除,基于键盘字符位置的字符替换} | 贪心搜索 | 模拟常见的打字错误 (["Combating Adversarial Misspellings with Robust Word Recognition" (Pruthi et al., 2019)](https://arxiv.org/abs/1905.11268) |
pso |
无目标 分类 |
基于 HowNet 的词替换 | 粒子群优化算法 | (["Word-level Textual Adversarial Attacking as Combinatorial Optimization" (Zang et al., 2020)](https://www.aclweb.org/anthology/2020.acl-main.540/)) | |
pwws |
无目标 分类 |
基于 WordNet 的同义词替换 | 对 WIR 的贪心搜索 | 贪心的攻击方法,基于词重要性排序,词的显著性,以及同义词替换分数(["Generating Natural Language Adversarial Examples through Probability Weighted Word Saliency" (Ren et al., 2019)](https://www.aclweb.org/anthology/P19-1103/)) | |
textbugger : (black-box) |
无目标 分类 |
USE 通用句子编码向量的 cosine 相似度 | {字符的插入、删除、替换,以及临近字符交换} | 对 WIR 的贪心搜索 | ([(["TextBugger: Generating Adversarial Text Against Real-world Applications" (Li et al., 2018)](https://arxiv.org/abs/1812.05271)). |
textfooler |
无目标 {分类,蕴含} |
词嵌入的距离,词性的匹配,USE 通用句子编码向量的 cosine 相似度 | Counter-fitted 词嵌入替换 | 对 WIR 的贪心搜索 | 对词重要性排序的贪心攻击方法(["Is Bert Really Robust?" (Jin et al., 2019)](https://arxiv.org/abs/1907.11932)) |
对 seq2seq 模型的攻击策略: | |||||
morpheus |
最小 BLEU 分数 | 词的屈折变化 | 贪心搜索 | 贪心的用词的屈折变化进行替换,来最小化 BLEU 分数(["It’s Morphin’ Time! Combating Linguistic Discrimination with Inflectional Perturbations"](https://www.aclweb.org/anthology/2020.acl-main.263.pdf) | |
seq2sick :(black-box) |
翻译结果无重叠 | Counter-fitted 词嵌入替换 | 对 WIR 的贪心搜索 | 贪心攻击方法,以改变全部的翻译结果为目标。目前实现的是黑盒攻击,计划改为与论文中一样的白盒攻击(["Seq2Sick: Evaluating the Robustness of Sequence-to-Sequence Models with Adversarial Examples" (Cheng et al., 2018)](https://arxiv.org/abs/1803.01128)) |
WIR 为 word word importance ranking 的缩写,即词重要性排序。
下面是几个样例,在命令行中验证上述实现的攻击方法:
对在 SST-2 上精调的 BERT 模型进行 TextFooler 攻击:
textattack attack --model bert-base-uncased-sst2 --recipe textfooler --num-examples 10
对用于英语-德语翻译的 T2 模型进行 seq2sick (黑盒) 攻击:
textattack attack --model t5-en-de --recipe seq2sick --num-examples 100
textattack augment
TextAttack 的组件中,有很多易用的数据增强工具。textattack.Augmenter
类使用 变换 与一系列的 约束 进行数据增强。我们提供了 5 中内置的数据增强策略:
wordnet
通过基于 WordNet 同义词替换的方式增强文本embedding
通过邻近词替换的方式增强文本,使用 counter-fitted 词嵌入空间中的邻近词进行替换,约束二者的 cosine 相似度不低于 0.8charswap
通过字符的增删改,以及临近字符交换的方式增强文本eda
通过对词的增删改来增强文本checklist
通过简写,扩写以及对实体、地点、数字的替换来增强文本clare
使用 pre-trained masked language model, 通过对词的增删改来增强文本使用 textattack 来进行数据增强,最快捷的方法是通过 textattack augment <args>
命令行接口。 textattack augment
使用 CSV 文件作为输入,在参数中设置需要增强的文本列,每个样本允许改变的比例,以及对于每个输入样本生成多少个增强样本。输出的结果保存为与输入文件格式一致的 CSV 文件,结果文件中为对指定的文本列生成的增强样本。
比如,对于下面这个 examples.csv
文件:
"text",label
"the rock is destined to be the 21st century's new conan and that he's going to make a splash even greater than arnold schwarzenegger , jean- claud van damme or steven segal.", 1
"the gorgeously elaborate continuation of 'the lord of the rings' trilogy is so huge that a column of words cannot adequately describe co-writer/director peter jackson's expanded vision of j . r . r . tolkien's middle-earth .", 1
"take care of my cat offers a refreshingly different slice of asian cinema .", 1
"a technically well-made suspenser . . . but its abrupt drop in iq points as it races to the finish line proves simply too discouraging to let slide .", 0
"it's a mystery how the movie could be released in this condition .", 0
使用命令 textattack augment --input-csv examples.csv --output-csv output.csv --input-column text --recipe embedding --pct-words-to-swap .1 --transformations-per-example 2 --exclude-original
会增强 text
列,约束对样本中 10% 的词进行修改,生成输入数据两倍的样本,同时结果文件中不保存 csv 文件的原始输入。(默认所有结果将会保存在 augment.csv
文件中)
数据增强后,下面是 augment.csv
文件的内容:
text,label
"the rock is destined to be the 21st century's newest conan and that he's gonna to make a splashing even stronger than arnold schwarzenegger , jean- claud van damme or steven segal.",1
"the rock is destined to be the 21tk century's novel conan and that he's going to make a splat even greater than arnold schwarzenegger , jean- claud van damme or stevens segal.",1
the gorgeously elaborate continuation of 'the lord of the rings' trilogy is so huge that a column of expression significant adequately describe co-writer/director pedro jackson's expanded vision of j . rs . r . tolkien's middle-earth .,1
the gorgeously elaborate continuation of 'the lordy of the piercings' trilogy is so huge that a column of mots cannot adequately describe co-novelist/director peter jackson's expanded vision of j . r . r . tolkien's middle-earth .,1
take care of my cat offerings a pleasantly several slice of asia cinema .,1
taking care of my cat offers a pleasantly different slice of asiatic kino .,1
a technically good-made suspenser . . . but its abrupt drop in iq points as it races to the finish bloodline proves straightforward too disheartening to let slide .,0
a technically well-made suspenser . . . but its abrupt drop in iq dot as it races to the finish line demonstrates simply too disheartening to leave slide .,0
it's a enigma how the film wo be releases in this condition .,0
it's a enigma how the filmmaking wo be publicized in this condition .,0
在 'embedding' 增强策略中,使用 counterfitted 词嵌入空间的最近邻来增强数据。
除了使用命令行接口,你还可以在自己的代码中导入 Augmenter
来进行动态的数据增强。所有的 Augmenter
对象都实现了 augment
和 augment_many
方法,用于对单个 string 和一个 list 的 string 进行数据增强。下面是在 python 脚本中使用 EmbeddingAugmenter
的例子:
>>> from textattack.augmentation import EmbeddingAugmenter
>>> augmenter = EmbeddingAugmenter()
>>> s = 'What I cannot create, I do not understand.'
>>> augmenter.augment(s)
['What I notable create, I do not understand.', 'What I significant create, I do not understand.', 'What I cannot engender, I do not understand.', 'What I cannot creating, I do not understand.', 'What I cannot creations, I do not understand.', 'What I cannot create, I do not comprehend.', 'What I cannot create, I do not fathom.', 'What I cannot create, I do not understanding.', 'What I cannot create, I do not understands.', 'What I cannot create, I do not understood.', 'What I cannot create, I do not realise.']
你还可以通过从 textattack.transformations
和 textattack.constraints
导入 变换 与 约束 来从头创建自己的数据增强方法。下面是一个使用 WordSwapRandomCharacterDeletion
变换 进行数据增强的例子:
>>> from textattack.transformations import WordSwapRandomCharacterDeletion
>>> from textattack.transformations import CompositeTransformation
>>> from textattack.augmentation import Augmenter
>>> transformation = CompositeTransformation([WordSwapRandomCharacterDeletion()])
>>> augmenter = Augmenter(transformation=transformation, transformations_per_example=5)
>>> s = 'What I cannot create, I do not understand.'
>>> augmenter.augment(s)
['What I cannot creae, I do not understand.', 'What I cannot creat, I do not understand.', 'What I cannot create, I do not nderstand.', 'What I cannot create, I do nt understand.', 'Wht I cannot create, I do not understand.']
textattack train
通过 textattack train
可以便捷地使用 TextAttack 框架来训练 LSTM,CNN,以及 transofrmers
模型。数据集会通过 datasets
包自动加载。
在 Yelp 分类数据集上对 TextAttack 中默认的 LSTM 模型训练 50 个 epoch:
textattack train --model-name-or-path lstm --dataset yelp_polarity --epochs 50 --learning-rate 1e-5
在 CoLA
数据集上对 bert-base
模型精调 5 个 epoch:
textattack train --model-name-or-path bert-base-uncased --dataset glue^cola --per-device-train-batch-size 8 --epochs 5
textattack peek-dataset
使用 textattack peek-dataset
可以进一步的观察数据。TextAttack 会打印出数据集粗略的统计信息,包括数据样例,输入文本的统计信息以及标签分布。比如,运行 textattack peek-dataset --dataset-from-huggingface snli
命令,会打印指定 NLP 包中 SNLI 数据集的统计信息。
textattack list
TextAttack 中有很多组件,有时很难跟进所有组件的情况。你可以使用 textattack list
列出所有的组件。比如,列出预训练模型 (textattack list models
),或是列出可用的搜索方法 (textattack list search-methods
)。
TextAttack 不依赖具体模型!你可以使用 TextAttack 来分析任何模型,只要模型的输出是 ID,张量,或者字符串。为了方便使用,TextAttack 内置了常见 NLP 任务的各种预训练模型。你可以轻松愉悦地上手 TextAttack。同时还可以更公平的比较不同文献的 attack 策略。
TextAttack 提供了各种内置模型和数据集。使用 TextAttack 命令行接口,可以自动匹配模型和数据集。
我们为 GLUE 中的九个任务内置了多种预训练模型,并且还内置了很多常见的分类任务、翻译任务和摘要任务的数据集。
textattack/models/README.md 这个列表包含可用的预训练模型以及这些模型的准确率。你还可以通过 textattack attack --help
查看完整列表,包括所有的内置模型与数据集。
下面是一个使用内置模型的例子(SST-2 数据集会自动的加载):
textattack attack --model roberta-base-sst2 --recipe textfooler --num-examples 10
transformers
模型和 datasets
数据集TextAttack 兼容 transformers
预训练模型
和 datasets
数据集! 下面是一个例子,加载数据集并攻击相应预训练模型:
textattack attack --model-from-huggingface distilbert-base-uncased-finetuned-sst-2-english --dataset-from-huggingface glue^sst2 --recipe deepwordbug --num-examples 10
你还可以通过 --model-from-huggingface
参数探索更多支持的预训练模型,或是通过
--dataset-from-huggingface
参数指定其他数据集。
你可以快捷地对本地模型或数据样本进行攻击:创建一个简单的文件就可以加载预训练模型,然后在文件中可以通过对象 model
与 tokenizer
对象加载模型。tokenizer
对象必须实现 encode()
方法,该方法将输入字符串转为一个列表或一个 ID 张量。model
对象必须通过实现 __call__
方法来加载模型。
对于你已经训练完成的模型,可以通过创建下面这样的文件,将其命名为 my_model.py
:
model = load_your_model_with_custom_code() # replace this line with your model loading code
tokenizer = load_your_tokenizer_with_custom_code() # replace this line with your tokenizer loading code
然后,在运行攻击时指定参数 --model-from-file my_model.py
,就可以自动载入你的模型与分词器。
加载本地数据集与加载本地预训练模型的方法相似。dataset
对象可以是任意可迭代的(input, output)
对。下面这个例子演示了如何在 my_dataset.py
脚本中加载一个情感分类数据集:
dataset = [('Today was....', 1), ('This movie is...', 0), ...]
然后,在运行攻击时指定参数 --dataset-from-file my_dataset.py
,就可以对这个本地数据集进行攻击。
为了对分词后的句子运行攻击方法,我们设计了 AttackedText
对象。它同时维护 token 列表与含有标点符号的原始文本。我们使用这个对象来处理原始的与分词后的文本。
我们将攻击划分并定义为四个组成部分:目标函数 定义怎样的攻击是一次成功的攻击,约束条件 定义怎样的扰动是可行的,变换规则 对输入文本生成一系列可行的扰动结果,搜索方法 在搜索空间中遍历所有可行的扰动结果。每一次攻击都尝试对输入的文本添加扰动,使其通过目标函数(即判断攻击是否成功),并且扰动要符合约束(如语法约束,语义相似性约束)。最后用搜索方法在所有可行的变换结果中,挑选出优质的对抗样本。
这种模块化的设计可以将各种对抗攻击策略整合在一个系统里。这使得我们可以方便地将文献中的方法集成在一起,同时复用攻击策略之间相同的部分。我们已经实现了 16 种简明易读的攻击策略(见上表)。史上首次!各种攻击方法终于可以在标准的设置下作为基准方法,进行比较与分析。
TextAttack 是不依赖具体模型的,这意味着可以对任何深度学习框架训练的模型进行攻击。只要被攻击的模型可以读取字符串(或一组字符串),并根据目标函数返回一个结果。比如说,机器翻译模型读取一句话,返回一句对应的翻译结果。分类或蕴含任务的模型输入字符串,返回一组分数。只要你的模型满足这两点,就可以使用 TextAttack 进行攻击。
目标函数 GoalFunction
以 AttackedText
对象作为输入,为输入对象打分,并且判别这次攻击是否满足目标函数定义的成功条件,返回一个 GoalFunctionResult
对象。
约束条件 Constraint
以 AttackedText
对象作为输入,返回一个变换后的 AttackedText
列表。对于每条变换,返回一个布尔值表示这条变换是否满足约束条件。
变换规则 Transformation
以 AttackedText
对象作为输入,返回对于 AttackedText
所有可行变换的列表。例如,一个变换规则可以是返回所有可能的同义词替换结果。
搜索方法 SearchMethod
以初始的 GoalFunctionResult
作为输入,返回最终的 GoalFunctionResult
。get_transformations
方法,以一个 AttackedText
对象作为输入,返还所有符合约束条件的变换结果。搜索方法不断地调用 get_transformations
函数,直到攻击成功 (由 get_goal_results
决定) 或搜索结束。
详细情况参见我们的分析文章:Searching for a Search Method: Benchmarking Search Algorithms for Generating NLP Adversarial Examples at EMNLP BlackBoxNLP.
正如我们在上面的文章中所强调的,我们不推荐在对攻击策略没有约束的情况下直接进行比较。
对这点进行强调,是由于最近的文献中在设置约束时使用了不同的方法或者阈值。在不固定约束空间时,攻击成功率的增加可能是源于改进的搜索方法或变换方式,又或是降低了对搜索空间的约束。
我们欢迎任何建议与改进!请提交 Issues(议题)和 Pull requests(拉取请求),我们会竭尽所能的做出即时反馈。TextAttack 当前处于 "alpha" 版本,我们仍在完善它的设计与功能。
关于提交建议与改进的详细指引,查看 CONTRIBUTING.md 。
如果 TextAttack 对你的研究工作有所帮助,欢迎在论文中引用 TextAttack: A Framework for Adversarial Attacks, Data Augmentation, and Adversarial Training in NLP。
@misc{morris2020textattack,
title={TextAttack: A Framework for Adversarial Attacks, Data Augmentation, and Adversarial Training in NLP},
author={John X. Morris and Eli Lifland and Jin Yong Yoo and Jake Grigsby and Di Jin and Yanjun Qi},
year={2020},
eprint={2005.05909},
archivePrefix={arXiv},
primaryClass={cs.CL}
}
Dear OpenI User
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.
For more agreement content, please refer to the《Openl Qizhi Community AI Collaboration Platform Usage Agreement》