对抗训练
目录
Min-Max公式
$$ {} {(x,y) }U[{r{adv}}L(,x+r_{adv},y)]
$$
- 内部max是为了找到worst-case的扰动,也就是攻击,其中,
为损失函数, 为扰动的范围空间。 - 外部min是为了基于该攻击方式,找到最鲁棒的模型参数,也就是防御,其中
是输入样本的分布。 简单理解就是在输入上进行梯度上升(增大loss),在参数上进行梯度下降(减小loss)
加入扰动后的损失函数
$$ {} -P(y |x+r{adv};)
## 代码
代码来自[1],注意的是一般扰动加在了embedding矩阵上,相当于x+r。
import torch
class FGM():
def __init__(self, model):
self.model = model
self.backup = {}
def attack(self, epsilon=1., emb_name='emb.'):
# emb_name为embedding矩阵参数对应名
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 != 0 and not torch.isnan(norm):
r_at = epsilon * param.grad / norm
param.data.add_(r_at)
def restore(self, emb_name='emb.'):
for name, param in self.model.named_parameters():
if param.requires_grad and emb_name in name:
assert name in self.backup
param.data = self.backup[name]
self.backup = {}
使用时:
# 初始化
fgm = FGM(model)
for batch_input, batch_label in data:
# 正常训练
loss = model(batch_input, batch_label)
loss.backward() # 反向传播,得到正常的grad
# 对抗训练
fgm.attack() # 在embedding上添加对抗扰动
loss_adv = model(batch_input, batch_label)
loss_adv.backward() # 反向传播,并在正常的grad基础上,累加对抗训练的梯度
fgm.restore() # 恢复embedding参数
# 梯度下降,更新参数
optimizer.step()
model.zero_grad()
v1.5.2