对抗训练
目录
Min-Max公式
$$ {} {(x,y) }U[{r{adv}}L(,x+r_{adv},y)]
$$
- 内部max是为了找到worst-case的扰动,也就是攻击,其中, \(L\)为损失函数, \(\mathbb{S}\) 为扰动的范围空间。
- 外部min是为了基于该攻击方式,找到最鲁棒的模型参数,也就是防御,其中 \(\mathbb{D}\) 是输入样本的分布。 简单理解就是在输入上进行梯度上升(增大loss),在参数上进行梯度下降(减小loss)
加入扰动后的损失函数
$$ {} -P(y |x+r{adv};)
\[
那扰动要如何计算呢?Goodfellow认为,**神经网络由于其线性的特点,很容易受到线性扰动的攻击。**
# Fast Gradient Sign Method (FGSM)
\] r_{adv} = sgn(_{x}L(,x,y)) $$ # FGM ## 代码
代码来自[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()
= torch.norm(param.grad)
norm if norm != 0 and not torch.isnan(norm):
= epsilon * param.grad / norm
r_at
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
= self.backup[name]
param.data self.backup = {}
使用时:
# 初始化
= FGM(model)
fgm for batch_input, batch_label in data:
# 正常训练
= model(batch_input, batch_label)
loss # 反向传播,得到正常的grad
loss.backward() # 对抗训练
# 在embedding上添加对抗扰动
fgm.attack() = model(batch_input, batch_label)
loss_adv # 反向传播,并在正常的grad基础上,累加对抗训练的梯度
loss_adv.backward() # 恢复embedding参数
fgm.restore() # 梯度下降,更新参数
optimizer.step() model.zero_grad()