小白对抗训练入门(1)--FGM

文章目录

先想再做,对比总结!

原理

FGM核心思想是:在训练时对样本施加一定的变形,从而提升模型的健壮性。

如何施加一定的变形呢,而且还不会把模型搞为白痴呢,而且施加的形变太小,容易没啥用,施加的太大又容易搞错边界。作者提出对每个样本施加一个梯度变化方向上的 ϵ \epsilon ϵ,即可以解决此问题。具体步骤如下:

  1. 对于训练样本 x x x y y y, 得出来预测值 f ( x ) f(x) f(x),并求梯度 Δ f ( x ) \Delta f(x) Δf(x)
  2. 对于每个特征 x i x_i xi加一个 ϵ ∗ s i g n ( Δ f ( x ) ) \epsilon * sign(\Delta f(x)) ϵsign(Δf(x)),公式如下: x ′ = x + ϵ ∗ s i g n ( Δ f ( x ) ) x' = x + \epsilon * sign(\Delta f(x)) x=x+ϵsign(Δf(x))
  3. 对于 x ′ x' x进行预测得到 f ( x ′ ) f(x') f(x),然后求的梯度,进行反向传播,更新模型参数。

实现

在NLP领域,每个样本最后会变成embedding,输入到模型进行预测。所以只需要对embedding层进行施加变化就好。
具体代码如下:

class PGM:
	def __init__(self, model, epsilon, embedding_name):
		self.model = model
		self.epsilon = epsilon
		self.embedding_name = embedding_name
	
	def attack(self):
		# 找到那一层,然后施加扰动
		for name, para in self.model.named_parameters():
			if name == self.embedding_name and para.requires_grad:
				# 对这个进行embedding
				self.backup[name] = para.data.clone()
				norm = torch.norm(para.grad)
				if norm!=0 and not torch.isnan(norm):
					rat = self.epsilon * (para.grad/norm)
					para.data.add_(rat)
	
	def restore(self):
		for name, para in self.model.named_parameters():
			if name == self.embedding_name:
				para.data = self.backup[name]

# 训练调用
pgm_model = PGM(model, epsilon=1, embedding_name='embedding')

for batch_input in train_dataset:
    # 第一次正向传播 求 f(x)
	pred = model(batch_input['input'])
	# 反向传播,求梯度
	loss = myloss(pred, batch_input['y'])
	loss.backward()
	
	# 开始攻击,得到x'
	pgm_model.attack()
	# 再次方向传播,得到f(x')
	pred_2 = model(batch_input['input'])
	loss2 = myloss(pred_2, batch_input['y'])
	loss2.backward()
	# 回退原始参数
	pgm_model.restore()
	
	# 总体开始更新参数
	optimizer.step()
	model.zero_grad()
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值