<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【關(guān)于 數(shù)據(jù)增強 之 對抗訓(xùn)練】 那些你不知道的事

          共 5741字,需瀏覽 12分鐘

           ·

          2021-08-31 17:14

          作者:楊夕

          面筋地址:https://github.com/km1994/NLP-Interview-Notes

          個人筆記:https://github.com/km1994/nlp_paper_study

          個人介紹:大佬們好,我叫楊夕,該項目主要是本人在研讀頂會論文和復(fù)現(xiàn)經(jīng)典論文過程中,所見、所思、所想、所聞,可能存在一些理解錯誤,希望大佬們多多指正。

          【注:手機閱讀可能圖片打不開?。?!】

          一、介紹篇

          1.1 什么是 對抗訓(xùn)練 ?

          對抗訓(xùn)練 從 CV 引入到 NLP 領(lǐng)域,作為一種防御機制,能夠在修改部分信息的情況下,提高模型的泛化能力。

          1.2 為什么 對抗訓(xùn)練 能夠 提高模型效果?

          對抗樣本可以用來攻擊和防御,而對抗訓(xùn)練其實是“對抗”家族中防御的一種方式,其基本的原理呢,就是通過添加擾動構(gòu)造一些對抗樣本,放給模型去訓(xùn)練,以攻為守,提高模型在遇到對抗樣本時的魯棒性,同時一定程度也能提高模型的表現(xiàn)和泛化能力。

          1.3 對抗訓(xùn)練 有什么特點?

          • 對抗樣本一般需要具有兩個特點:

            • 相對于原始輸入,所添加的擾動是微小的;

            • 能使模型犯錯

          1.4 對抗訓(xùn)練 的作用?

          1. 提高模型應(yīng)對惡意對抗樣本時的魯棒性;

          2. 作為一種regularization,減少overfitting,提高泛化能力。

          二、概念篇

          2.1 對抗訓(xùn)練的基本概念?

          在原始輸入樣本 x 上加一個擾動 $r_adv$ ,得到對抗樣本后,用其進行訓(xùn)練。也就是說,問題可以被抽象成這么一個模型:

          2.2 如何計算擾動?

          • 動機:神經(jīng)網(wǎng)絡(luò)由于其線性的特點,很容易受到線性擾動的攻擊

          • 方法:FGSM

          注:sgn 為符號函數(shù), L 為損失函數(shù)。Goodfellow發(fā)現(xiàn),令 ε=0.25 ,用這個擾動能給一個單層分類器造成99.9%的錯誤率。

          2.3 如何優(yōu)化?

          • 動機:將問題重新定義成了一個找鞍點的問題

          • 方法:Min-Max公式


          注:公式由兩部分構(gòu)成:一個是內(nèi)部損失函數(shù)的最大化,一個是外部經(jīng)驗風(fēng)險的最小化 內(nèi)部max是為了找到worst-case的擾動,也就是攻擊,其中, L 為損失函數(shù), S 為擾動的范圍空間。外部min是為了基于該攻擊方式,找到最魯棒的模型參數(shù),也就是防御,其中 D 是輸入樣本的分布。

          三、實戰(zhàn)篇

          3.1 NLP 中經(jīng)典對抗訓(xùn)練 之 Fast Gradient Method(FGM)

          • 方法:假設(shè)輸入的文本序列的embedding vectors [v1,v2,...,vT] 為 x ,embedding的擾動為:

          注:實際上就是取消了符號函數(shù),用二范式做了一個scale,需要注意的是:這里的norm計算的是,每個樣本的輸入序列中出現(xiàn)過的詞組成的矩陣的梯度norm。原作者提供了一個TensorFlow的實現(xiàn) [10],在他的實現(xiàn)中,公式里的 x 是embedding后的中間結(jié)果(batch_size, timesteps, hidden_dim),對其梯度 g 的后面兩維計算norm,得到的是一個(batch_size, 1, 1)的向量 $||g||_2$ 。為了實現(xiàn)插件式的調(diào)用,筆者將一個batch抽象成一個樣本,一個batch統(tǒng)一用一個norm,由于本來norm也只是一個scale的作用,影響不大。

          • 代碼實現(xiàn):

          1. FGM 類實現(xiàn)

              import torch
          class FGM():
          def __init__(self, model):
          self.model = model
          self.backup = {}

          def attack(self, epsilon=1., 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:
          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.'):
          # 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.backup
          param.data = self.backup[name]
          self.backup = {}
          1. FGM 類調(diào)用

              # 初始化
          fgm = FGM(model)
          for batch_input, batch_label in data:
          # 正常訓(xùn)練
          loss = model(batch_input, batch_label)
          loss.backward() # 反向傳播,得到正常的grad
          # 對抗訓(xùn)練
          fgm.attack() # 在embedding上添加對抗擾動
          loss_adv = model(batch_input, batch_label)
          loss_adv.backward() # 反向傳播,并在正常的grad基礎(chǔ)上,累加對抗訓(xùn)練的梯度
          fgm.restore() # 恢復(fù)embedding參數(shù)
          # 梯度下降,更新參數(shù)
          optimizer.step()
          model.zero_grad()

          注:PyTorch為了節(jié)約內(nèi)存,在backward的時候并不保存中間變量的梯度。因此,如果需要完全照搬原作的實現(xiàn),需要用register_hook接口[11]將embedding后的中間變量的梯度保存成全局變量,norm后面兩維,計算出擾動后,在對抗訓(xùn)練forward時傳入擾動,累加到embedding后的中間變量上,得到新的loss,再進行梯度下降。

          3.2 NLP 中經(jīng)典對抗訓(xùn)練 之 Projected Gradient Descent(PGD)

          • 動機:內(nèi)部max的過程,本質(zhì)上是一個非凹的約束優(yōu)化問題,F(xiàn)GM解決的思路其實就是梯度上升,那么FGM簡單粗暴的“一步到位”,是不是有可能并不能走到約束內(nèi)的最優(yōu)點呢?

          • 方法:用Projected Gradient Descent(PGD)的方法,簡單的說,就是“小步走,多走幾步”,如果走出了擾動半徑為 ε 的空間,就映射回“球面”上,以保證擾動不要過大:


          • 代碼實現(xiàn):

          1. PGD 類實現(xiàn)

              import torch
          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]
          1. FGM 類調(diào)用

              pgd = PGD(model)
          K = 3
          for batch_input, batch_label in data:
          # 正常訓(xùn)練
          loss = model(batch_input, batch_label)
          loss.backward() # 反向傳播,得到正常的grad
          pgd.backup_grad()
          # 對抗訓(xùn)練
          for t in range(K):
          pgd.attack(is_first_attack=(t==0)) # 在embedding上添加對抗擾動, first attack時備份param.data
          if t != K-1:
          model.zero_grad()
          else:
          pgd.restore_grad()
          loss_adv = model(batch_input, batch_label)
          loss_adv.backward() # 反向傳播,并在正常的grad基礎(chǔ)上,累加對抗訓(xùn)練的梯度
          pgd.restore() # 恢復(fù)embedding參數(shù)
          # 梯度下降,更新參數(shù)
          optimizer.step()
          model.zero_grad()

          參考

          1. 【煉丹技巧】功守道:NLP中的對抗訓(xùn)練 + PyTorch實現(xiàn)


          瀏覽 235
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本免费黄色视频 | 亚洲高清中文字幕 | 日韩av在线免费 日韩福利视频一区 | 黄色日本国产 | 无码精品人妻喷潮一区二区三区白浆 |