對抗訓(xùn)練方法
Adversarial learning
主要是用于樣本生成或者對抗攻擊領(lǐng)域雪标,主要方法是通過添加鑒別器或者根據(jù)梯度回傳生成新樣本村刨,其主要是為了提升當(dāng)前主干模型生成樣本的能力或者魯棒性
一. 對抗訓(xùn)練定義
==對抗訓(xùn)練是一種引入噪聲的訓(xùn)練方式,可以對參數(shù)進行正則化逆粹,提升模型魯棒性和泛化能力==
1.1 對抗訓(xùn)練特點
- 相對于原始輸入阿浓,所添加的擾動是微小的
- 添加的噪聲可以使得模型預(yù)測錯誤
1.2 對抗訓(xùn)練的基本概念
就是在原始輸入樣本上加上一個擾動
得到對抗樣本,再用其進行訓(xùn)練退敦,這個問題可以抽象成這樣一個模型:
其中,是
ground truth
,是模型參數(shù)。意思就是即使在擾動的情況下求使得預(yù)測出
的概率最大的參數(shù)网梢,擾動可以被定義為:
其中赂毯,為符號函數(shù)战虏,
為損失函數(shù)
最后,GoodFellow還總結(jié)了對抗訓(xùn)練的兩個作用:
- 提高模型應(yīng)對惡意對抗樣本時的魯棒性
- 作為一種regularization党涕,減少overfitting烦感,提高泛化能力
1.3 Min-Max公式
Madry在2018年的ICLR論文Towards Deep Learning Models Resistant to Adversarial Attacks中總結(jié)了之前的工作,對抗訓(xùn)練可以統(tǒng)一寫成如下格式:
其中代表輸入樣本的分布膛堤,
代表輸入手趣,
代表標簽中符,
是模型參數(shù)档插,
是單個樣本的loss,
是擾動轴咱,
是擾動空間。這個式子可以分布理解如下:
-
內(nèi)部max
是指往中添加擾動
跳昼,
的目的是讓
越大越好,也就是說盡可能讓現(xiàn)有模型預(yù)測出錯。但是,
也是有約束的恼除,要在
范圍內(nèi). 常規(guī)的約束是
,其中
是一個常數(shù)
-
外部min
是指找到最魯棒的參數(shù)是預(yù)測的分布符合原數(shù)據(jù)集的分布
這就解決了兩個問題:如何構(gòu)建足夠強的對抗樣本旷痕、和如何使得分布仍然盡可能接近原始分布
1.4 NLP領(lǐng)域的對抗訓(xùn)練
對于CV領(lǐng)域报强,圖像被認為是連續(xù)的哮缺,因此可以直接在原始圖像上添加擾動直撤;而對于NLP悄雅,它的輸入是文本的本質(zhì)是one-hot,而one-hot之間的歐式距離恒為习蓬,理論上不存在
微小的擾動
笋婿,而且遇革,在Embedding向量上加上微小擾動可能就找不到與之對應(yīng)的詞了昂勒,不是真正意義上的對抗樣本难捌,因為對抗樣本依舊能對應(yīng)一個合理的原始輸入徘公,既然不能對Embedding向量添加擾動,可以對Embedding層添加擾動竿音,使其產(chǎn)生更魯棒的Embedding向量
二. 對抗訓(xùn)練方法
2.1 FGM(Fast Gradient Method) ICLR2017
FGM是根據(jù)具體的梯度進行scale,得到更好的對抗樣本:
整個對抗訓(xùn)練的過程如下,偽代碼如下:
- 計算x的前向loss、反向傳播得到梯度
- 根據(jù)embedding矩陣的梯度計算出
猿涨,并加到當(dāng)前embedding上,相當(dāng)于
- 計算
的前向loss藐石,反向傳播得到對抗的梯度,累加到(1)的梯度上
- 將embedding恢復(fù)為(1)時的值
- 根據(jù)(3)的梯度對參數(shù)進行更新
class FGM:
def __init__(self, model: nn.Module, eps=1.):
self.model = (model.module if hasattr(model, "module") else model)
self.eps = eps
self.backup = {}
# only attack word embedding
def attack(self, emb_name='word_embeddings'):
for name, param in self.model.named_parameters():
if param.requires_grad and emb_name in name:
self.backup[name] = param.data.clone()
norm = torch.norm(param.grad)
if norm and not torch.isnan(norm):
r_at = self.eps * param.grad / norm
param.data.add_(r_at)
def restore(self, emb_name='word_embeddings'):
for name, para in self.model.named_parameters():
if para.requires_grad and emb_name in name:
assert name in self.backup
para.data = self.backup[name]
self.backup = {}
2.2 FGSM (Fast Gradient Sign Method) ICLR2015
FGSM的全稱是Fast Gradient Sign Method. FGSM和FGM的核心區(qū)別在計算擾動的方式不一樣于微,F(xiàn)GSM擾動的計算方式如下:
def FGSM(image, epsilon, data_grad):
"""
:param image: 需要攻擊的圖像
:param epsilon: 擾動值的范圍
:param data_grad: 圖像的梯度
:return: 擾動后的圖像
"""
# 收集數(shù)據(jù)梯度的元素符號
sign_data_grad = data_grad.sign()
# 通過調(diào)整輸入圖像的每個像素來創(chuàng)建擾動圖像
perturbed_image = image + epsilon*sign_data_grad
# 添加剪切以維持[0,1]范圍
perturbed_image = torch.clamp(perturbed_image, 0, 1)
# 返回被擾動的圖像
return perturbed_image
2.3 PGD(Projected Gradient Descent)
FGM
直接通過epsilon參數(shù)算出了對抗擾動逗嫡,這樣得到的可能不是最優(yōu)的。因此PGD進行了改進株依,通過迭代慢慢找到最優(yōu)的擾動
并且
PGD整個對抗訓(xùn)練的過程如下
計算
的前向loss驱证、反向傳播得到梯度并備份
-
對于每步
:
- 根據(jù)embedding矩陣的梯度計算出r,并加到當(dāng)前embedding上勺三,相當(dāng)于
(超出范圍則投影回epsilon內(nèi))
- if t不是最后一步: 將梯度歸0雷滚,根據(jù)(1)的
計算前后向并得到梯度
- if t是最后一步: 恢復(fù)(1)的梯度,計算最后的
并將梯度累加到(1)上
- 根據(jù)embedding矩陣的梯度計算出r,并加到當(dāng)前embedding上勺三,相當(dāng)于
將embedding恢復(fù)為(1)時的值
根據(jù)(5)的梯度對參數(shù)進行更新
在循環(huán)中是逐漸累加的吗坚,要注意的是最后更新參數(shù)只使用最后一個
算出來的梯度
class PGD():
def __init__(self, model):
self.model = model
self.emb_backup = {}
self.grad_backup = {}
def attack(self, epsilon=1., alpha=0.3, emb_name='emb.', is_first_attack=False):
# emb_name這個參數(shù)要換成你模型中embedding的參數(shù)名
for name, param in self.model.named_parameters():
if param.requires_grad and emb_name in name:
if is_first_attack:
self.emb_backup[name] = param.data.clone()
norm = torch.norm(param.grad)
if norm != 0 and not torch.isnan(norm):
r_at = alpha * param.grad / norm
param.data.add_(r_at)
param.data = self.project(name, param.data, epsilon)
def restore(self, emb_name='emb.'):
# emb_name這個參數(shù)要換成你模型中embedding的參數(shù)名
for name, param in self.model.named_parameters():
if param.requires_grad and emb_name in name:
assert name in self.emb_backup
param.data = self.emb_backup[name]
self.emb_backup = {}
def project(self, param_name, param_data, epsilon):
r = param_data - self.emb_backup[param_name]
if torch.norm(r) > epsilon:
r = epsilon * r / torch.norm(r)
return self.emb_backup[param_name] + r
def backup_grad(self):
for name, param in self.model.named_parameters():
if param.requires_grad:
self.grad_backup[name] = param.grad.clone()
def restore_grad(self):
for name, param in self.model.named_parameters():
if param.requires_grad:
param.grad = self.grad_backup[name]
2.4 FreeAT(Free Adversarial Training)
從FGSM到PGD祈远,主要是優(yōu)化對抗擾動的計算呆万,雖然取得了更好的效果,但計算量也一步步增加车份。對于每個樣本谋减,F(xiàn)GSM和FGM都只用計算兩次,一次是計算的前后向扫沼,一次是計算
的前后向出爹。而PGD則計算了K+1次,消耗了更多的計算資源缎除。因此FreeAT被提了出來严就,在PGD的基礎(chǔ)上進行訓(xùn)練速度的優(yōu)化
FreeAT
的思想是在對每個樣本連續(xù)重復(fù)
次訓(xùn)練,計算
時復(fù)用上一步的梯度器罐,為了保證速度梢为,整體epoch會除以
。
的更新公式為:
FreeAT的訓(xùn)練過程如下:
- 初始化
- 對于epoch=
:
- 對于每個
:
- 對于每步
:
- 利用上一步的
轰坊,計算
的前后向铸董,得到梯度
- 根據(jù)梯度更新參數(shù)
- 根據(jù)梯度更新
- 利用上一步的
- 對于每步
- 對于每個
FreeAT的問題在于每次的對于當(dāng)前的參數(shù)都是次優(yōu)的(無法最大化loss),因為當(dāng)前
是由
和
計算出來的肴沫,是對于
的最優(yōu)
2.5 YOPO(You Only Propagate Once)
YOPO的出發(fā)點是利用神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)來降低梯度計算的計算量粟害。從極大值原理PMP(Pontryagin’s maximum principle)
出發(fā),對抗擾動只和網(wǎng)絡(luò)的第0層有關(guān)颤芬,即在embedding層上添加擾動悲幅。再加之層之間是解耦合的,那就不需要每次都計算完整的前后向傳播
基于這個想法站蝠,復(fù)用后面幾層的梯度夺艰,減少非必要的完整傳播〕烈拢可以將PGD
的次攻擊拆成
次:
則對r的更新就可以變?yōu)?
其算法流程為:
對于每個樣本,初始化
减牺,對于
:
- 根據(jù)
,計算
對于
:
- 計算
- 另
2.6 FreeLB (Free Large-Batch)
YOPO的假設(shè)對于ReLU-based網(wǎng)絡(luò)來說是不成立的豌习,因為YOPO要求損失是兩次可微的,于是拔疚,F(xiàn)reeLB在FreeAT的基礎(chǔ)上將每次inner-max
中更新模型參數(shù)這一操作換掉肥隆,利用步之后累積的參數(shù)梯度進行更新,于是總體任務(wù)的目標函數(shù)就記為:
可以看成兩個球形鄰域的交上局部最大的近似稚失。同時栋艳,通過累積參數(shù)梯度的操作,可以看作是輸入了
這樣一個虛擬的
倍大小的batch句各。其中input subwords的one-hot representations記為
吸占,embedding matrix記為
晴叨,subwords embedding記為
依據(jù)下面算法中的數(shù)學(xué)符號,PGD需要進行次梯度計算矾屯,F(xiàn)reeAT需要進行
次兼蕊,F(xiàn)reeLB需要
次。雖然FreeLB在效率上并沒有特別大的優(yōu)勢件蚕,但是其效果十分不錯
另外孙技,論文中指出對抗訓(xùn)練和dropout不能同時使用,加上dropout相當(dāng)于改變了網(wǎng)絡(luò)的結(jié)果排作,影響擾動的計算牵啦。如果一定要加入dropout操作,需要在K步中都使用同一個mask
2.7 SMART(SMoothness-inducing Adversarial Regularization)
SMART放棄了Min-Max公式妄痪,選擇通過正則項Smoothness-inducing Adversarial Regularization
完成對抗學(xué)習(xí)哈雏。為了解決這個新的目標函數(shù)作者又提出了優(yōu)化算法Bregman Proximal Point Optimization
,這就是SMART的兩個主要內(nèi)容
SMART的主要想法是強制模型在neighboring data points上作出相似的預(yù)測拌夏,加入正則項后的目標函數(shù)如下所示:
是具體任務(wù)的損失函數(shù)僧著,
是generated neighbors of training points,
在分類任務(wù)中使用對稱的KL散度障簿,即
盹愚;在回歸任務(wù)中使用平方損失,
此時可以看到對抗發(fā)生在正則化項上站故,對抗的目標是最大擾動前后的輸出
Bregman Proximal Point Optimization也可以看作是一個正則項皆怕,防止更新的時候和前面的
變化過大讨惩。在第
次迭代時对竣,采用
vanilla Bregman proximal point (VBPP) method
:
其中表示
Bregman divergence
定義為:
是上面給出的對稱KL散度
使用動量來加速VBPP,此時定義為動量堕虹,記
表示指數(shù)移動平均岂津,那么
momentum Bregman proximal point (MBPP) method
就可以表示為:
下面是SMART的完整算法流程:
- 對于
輪迭代:
- 備份
虱黄,作為
Bregman divergence
計算的 - 對于每一個
:
- 使用正態(tài)分布隨機初始化擾動,結(jié)合
得到
- 循環(huán)
小步:計
- 算擾動下的梯度
- 基于
和學(xué)習(xí)率更新
- 算擾動下的梯度
- 基于
重新計算梯度吮成,更新參數(shù)
- 使用正態(tài)分布隨機初始化擾動,結(jié)合
- 更新
- 備份
三. Reference
Madry A, Makelov A, Schmidt L, et al. Towards deep learning models resistant to adversarial attacks[J]. arXiv preprint arXiv:1706.06083, 2017.
Goodfellow I J, Shlens J, Szegedy C. Explaining and harnessing adversarial examples[J]. arXiv preprint arXiv:1412.6572, 2014.
Miyato T, Dai A M, Goodfellow I. Adversarial training methods for semi-supervised text classification[J]. arXiv preprint arXiv:1605.07725, 2016.
Shafahi A, Najibi M, Ghiasi A, et al. Adversarial training for free![J]. arXiv preprint arXiv:1904.12843, 2019.
Zhang D, Zhang T, Lu Y, et al. You only propagate once: Accelerating adversarial training via maximal principle[J]. arXiv preprint arXiv:1905.00877, 2019.
Zhu C, Cheng Y, Gan Z, et al. Freelb: Enhanced adversarial training for natural language understanding[J]. arXiv preprint arXiv:1909.11764, 2019.
Jiang H, He P, Chen W, et al. Smart: Robust and efficient fine-tuning for pre-trained natural language models through principled regularized optimization[J]. arXiv preprint arXiv:1911.03437, 2019.