首页>>科技 >>内容

nlp理解六层次,简单总结几种NLP常用的对抗训练方法

发布时间:2023-08-13 13:32:10编辑:温柔的背包来源:

很多朋友对nlp理解六层次,简单总结几种NLP常用的对抗训练方法不是很了解,每日小编刚好整理了这方面的知识,今天就来带大家一探究竟。

nlp理解六层次,简单总结几种NLP常用的对抗训练方法

对抗性训练的本质是提高模型的鲁棒性。总的来说,在传统训练的基础上,加入对抗性训练可以进一步提高效果。这是比赛中打排名、调整参数时非常重要的技巧。对抗性训练在CV领域非常常用,那么如何在NLP领域使用它呢?本文简单总结了几种常用的对抗训练方法。

公式理解:

最大化扰动:选择一个能够使模型产生更大损失(更大梯度)的扰动量作为攻击;

最小化损失:根据最大扰动量,将其添加到输入样本中后,朝最小化扰动损失的方向更新参数(梯度下降);

这个构建的“对抗性例子”不能具体对应于某个单词。因此,在推理阶段,没有办法通过修改原始输入来获得这样的对抗性例子。

对抗性训练有两个作用,一是提高模型对恶意攻击的鲁棒性,二是提高模型的泛化能力。

在CV任务中,根据经验结论,对抗性训练往往会使模型在非对抗性样本上的表现变差。然而神奇的是,在NLP任务中,模型的泛化能力变得更强。

常用的几种对抗训练方法有FGSM、FGM、PGD、FreeAT、YOPO、FreeLB、SMART。本文暂时只介绍博主常用的三种方法,分别是FGM、PGD和FreeLB。在具体实现中,不同的对抗方法会有所不同,但从训练速度和代码编辑难度角度考虑,建议使用迭代次数较少的FGM和PGD。

:一、FGM算法

FGM的代码很少,只需要自己实现简单的类:

importtorchclassFGM():def__init__(self,model):self.model=modelself.backup={}#用于保存模型扰动defattack前的参数(self,epsilon=1.emb_name='word_embeddings'#emb_name表示embedding的参数in the model Name) :'''生成扰动和对抗样本'''forname,paraminself.model.named_parameters() :#遍历模型所有参数ifparam.requires_gradandemb_nameinname:#只取wordembedding层的参数self.backup[ name]=param.data .clone()#保存参数值norm=torch.norm(param.grad)#对两个范式下的参数梯度进行归一化ifnorm!=0andnottorch.isnan(norm):#计算扰动并添加对输入参数值的扰动r_at=epsilon*param.grad/normparam.data.add_(r_at)defrestore(self,emb_name='word_embeddings'#emb_name表示模型中embedding的参数名称) :'''恢复参数for name,paraminself .model.named_parameters():#遍历模型的所有参数ifparam.requires_gradandemb_nameinname:#只取wordembedding层的参数assertnameinself.backupparam.data=self.backup[name]#重新加载保存的参数值self.backup={}

训练时只需要额外添加5行代码:

fgm=FGM(model)#(#1)初始化forbatch_input,batch_labelindata:loss=model(batch_input,batch_label)#正常训练loss.backward()#反向传播,得到正常grad#对抗训练fgm.attack()#(#2)添加抗扰loss_adv=model(batch_input,batch_label)#(#3),计算包含扰动的对抗样本对embedding的lossloss_adv.backward()#(#4),并在正常grad的基础上,累加对抗训练的梯度fgm.restore()#(#5)恢复embedding参数#梯度下降,更新参数optimizer.step()model.zero_grad()

:二、PGD算法

梯度下降计划(PGD)是一种迭代攻击算法。与普通FGM只进行一次迭代相比,PGD进行多次迭代,每次迭代一小步,每次迭代都会将扰动投影到指定范围内。正式描述为:

代码实现如下:

ImportTorchClassPGD () :DEF__INIT __ (Self, Model) :Self.model=Modeltemlf.emb_backup={} Self.grad_backup={} DEFATTACK (Self, EPSILON=1. alpha=0.3, emb_name='word_embeddings', is_first_attack=false) :FORNAME , paraminself.model.named_parameters():ifparam.requires_gradandemb_nameinname:ifis_first_attack:self.emb_backup[name]=param.data.clone()norm=torch.norm(param.grad)ifnorm!=0andnottorch.isnan(norm):r_at=alpha*param.grad /normparam.data.add_(r_at)param.data=self.project(name,param.data,epsilon)defrestore(self,emb_name='word_embeddings'):forname,paraminself.model.named_parameters():ifparam.requires_gradandemb_nameinname:assertnameinself。 emb_backupparam.data=self.emb_backup[name]self.emb_backup={}defproject(self,param_name,param_data,epsilon):r=param_data-self.emb_backup[param_name]iftorch.norm(r)epsilon:r=epsilon*r/torch. norm(r )return self.emb_backup[param_name]+rdefbackup_grad(self):forname,paraminself.model.named_parameters():ifparam.requires_grad:self.grad_backup[name]=param.grad.clone() defrestore_grad(self):forname,param inself. model.named_parameters() :ifparam.requires_grad:param.grad=self.grad_backup[name]pgd=PGD(model)K=3forbatch_input,batch_labelindata:#正常训练loss=model(batch_input,batch_label)loss.backward()#反向传播,得到正态gradpgd.backup_grad ()#累积多次对抗训练—— 每生成对抗样本后,进行一次对抗训练,不断累积梯度fortinrange(K) :pgd.attack(is_first_attack=(t==0))#在embedding上添加对抗干扰,备份param.dataift!=K-1:model.zero_grad()else:pgd.restore_grad()loss_adv=model(batch_input,batch_label)loss_adv.backward()#反向传播,并在正常grad的基础上,累积对抗训练梯度pgd。 Restore()#恢复嵌入参数#梯度下降,更新参数optimizer.step()model.zero_grad()

:三、FreeLB算法

明显发现FreeLB和PGD的区别在于累加的方式:

FreeLB:通过平均K K K 次梯度作为扰动进行更新

PGD:只取最后一个梯度进行更新

实现流程如下图所示:

审计刘庆

以上知识分享希望能够帮助到大家!