日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

对抗训练浅谈:意义、方法和思考(附Keras实现)

發(fā)布時間:2024/10/8 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 对抗训练浅谈:意义、方法和思考(附Keras实现) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?PaperWeekly 原創(chuàng) ·?作者|蘇劍林

單位|追一科技

研究方向|NLP、神經(jīng)網(wǎng)絡(luò)

當(dāng)前,說到深度學(xué)習(xí)中的對抗,一般會有兩個含義:一個是生成對抗網(wǎng)絡(luò)(Generative Adversarial Networks,GAN),代表著一大類先進(jìn)的生成模型;另一個則是跟對抗攻擊、對抗樣本相關(guān)的領(lǐng)域,它跟 GAN 相關(guān),但又很不一樣,它主要關(guān)心的是模型在小擾動下的穩(wěn)健性。

本人之前所涉及的對抗話題,都是前一種含義,而今天,我們來聊聊后一種含義中的“對抗訓(xùn)練”。

本文包括如下內(nèi)容:

  • 對抗樣本、對抗訓(xùn)練等基本概念的介紹;

  • 介紹基于快速梯度上升的對抗訓(xùn)練及其在 NLP 中的應(yīng)用;

  • 給出了對抗訓(xùn)練的 Keras 實現(xiàn)(一行代碼調(diào)用);

  • 討論了對抗訓(xùn)練與梯度懲罰的等價性;

  • 基于梯度懲罰,給出了一種對抗訓(xùn)練的直觀的幾何理解。

  • 方法介紹

    近年來,隨著深度學(xué)習(xí)的日益發(fā)展和落地,對抗樣本也得到了越來越多的關(guān)注。

    在 CV 領(lǐng)域,我們需要通過對模型的對抗攻擊和防御來增強(qiáng)模型的穩(wěn)健型,比如在自動駕駛系統(tǒng)中,要防止模型因為一些隨機(jī)噪聲就將紅燈識別為綠燈。

    在 NLP 領(lǐng)域,類似的對抗訓(xùn)練也是存在的,不過 NLP 中的對抗訓(xùn)練更多是作為一種正則化手段來提高模型的泛化能力。

    這使得對抗訓(xùn)練成為了 NLP 刷榜的“神器”之一,前有微軟通過 RoBERTa+ 對抗訓(xùn)練在 GLUE [1] 上超過了原生 RoBERTa,后有我司的同事通過對抗訓(xùn)練刷新了 CoQA [2] 榜單。這也成功引起了筆者對它的興趣,遂學(xué)習(xí)了一番,分享在此。

    基本概念

    要認(rèn)識對抗訓(xùn)練,首先要了解“對抗樣本”,它首先出現(xiàn)在論文 Intriguing properties of neural networks [3] 之中。

    簡單來說,它是指對于人類來說“看起來”幾乎一樣、但對于模型來說預(yù)測結(jié)果卻完全不一樣的樣本,比如下面的經(jīng)典例子:

    理解對抗樣本之后,也就不難理解各種相關(guān)概念了,比如“對抗攻擊”,其實就是想辦法造出更多的對抗樣本,而“對抗防御”,就是想辦法讓模型能正確識別更多的對抗樣本。

    所謂對抗訓(xùn)練,則是屬于對抗防御的一種,它構(gòu)造了一些對抗樣本加入到原數(shù)據(jù)集中,希望增強(qiáng)模型對對抗樣本的魯棒性;同時,如本文開篇所提到的,在 NLP 中它通常還能提高模型的表現(xiàn)。

    Min-Max

    總的來說,對抗訓(xùn)練可以統(tǒng)一寫成如下格式:

    其中?代表訓(xùn)練集,代表輸入,代表標(biāo)簽,是模型參數(shù),是單個樣本的 loss,是對抗擾動,是擾動空間。這個統(tǒng)一的格式首先由論文 Towards Deep Learning Models Resistant to Adversarial Attacks [4]?提出。

    這個式子可以分步理解如下:

  • 往屬于里邊注入擾動?,的目標(biāo)是讓?越大越好,也就是說盡可能讓現(xiàn)有模型的預(yù)測出錯;

  • 當(dāng)然?也不是無約束的,它不能太大,否則達(dá)不到“看起來幾乎一樣”的效果,所以?要滿足一定的約束,常規(guī)的約束是?,其中?是一個常數(shù);

  • 每個樣本都構(gòu)造出對抗樣本之后,用作為數(shù)據(jù)對去最小化loss來更新參數(shù)?(梯度下降);

  • 反復(fù)交替執(zhí)行 1、2、3 步。

  • 由此觀之,整個優(yōu)化過程是?和?交替執(zhí)行,這確實跟 GAN 很相似,不同的是,GAN 所?的自變量也是模型的參數(shù),而這里?的自變量則是輸入(的擾動量),也就是說要對每一個輸入都定制一步?。

    快速梯度

    現(xiàn)在的問題是如何計算?,它的目標(biāo)是增大?,而我們知道讓 loss 減少的方法是梯度下降,那反過來,讓 loss 增大的方法自然就是梯度上升,因此可以簡單地取:

    當(dāng)然,為了防止?過大,通常要對?做些標(biāo)準(zhǔn)化,比較常見的方式是:

    有了?之后,就可以代回式 (1) 進(jìn)行優(yōu)化:

    這就構(gòu)成了一種對抗訓(xùn)練方法,被稱為?Fast Gradient Method(FGM),它由 GAN 之父 Goodfellow 在論文 Explaining and Harnessing Adversarial Examples [5] 首先提出。

    此外,對抗訓(xùn)練還有一種方法,叫做?Projected Gradient Descent(PGD),其實就是通過多迭代幾步來達(dá)到讓?更大的?。

    如果迭代過程中模長超過了?,就縮放回去,細(xì)節(jié)請參考Towards Deep Learning Models Resistant to Adversarial Attacks [6]。

    但本文不旨在對對抗學(xué)習(xí)做完整介紹,而且筆者認(rèn)為它不如 FGM 漂亮有效,所以本文還是以 FGM 為重點。關(guān)于對抗訓(xùn)練的補(bǔ)充介紹,建議有興趣的讀者閱讀富邦同學(xué)寫的功守道:NLP中的對抗訓(xùn)練 + PyTorch實現(xiàn)。

    回到NLP

    對于 CV 領(lǐng)域的任務(wù),上述對抗訓(xùn)練的流程可以順利執(zhí)行下來,因為圖像可以視為普通的連續(xù)實數(shù)向量,也是一個實數(shù)向量,因此?依然可以是有意義的圖像。

    但 NLP 不一樣,NLP 的輸入是文本,它本質(zhì)上是 one hot 向量(如果還沒認(rèn)識到這一點,歡迎閱讀詞向量與 Embedding 究竟是怎么回事?[7],而兩個不同的 one hot 向量,其歐氏距離恒為?,因此對于理論上不存在什么“小擾動”。

    一個自然的想法是像論文 Adversarial Training Methods for Semi-Supervised Text Classification [8] 一樣,將擾動加到 Embedding 層。

    這個思路在操作上沒有問題,但問題是,擾動后的 Embedding 向量不一定能匹配上原來的 Embedding 向量表,這樣一來對 Embedding 層的擾動就無法對應(yīng)上真實的文本輸入,這就不是真正意義上的對抗樣本了,因為對抗樣本依然能對應(yīng)一個合理的原始輸入。

    那么,在 Embedding 層做對抗擾動還有沒有意義呢?有!實驗結(jié)果顯示,在很多任務(wù)中,在 Embedding 層進(jìn)行對抗擾動能有效提高模型的性能。

    實驗結(jié)果

    既然有效,那我們肯定就要親自做實驗驗證一下了。怎么通過代碼實現(xiàn)對抗訓(xùn)練呢?怎么才能做到用起來盡可能簡單呢?最后用起來的效果如何呢?

    思路分析

    對于 CV 任務(wù)來說,一般輸入張量的 shape 是?,這時候我們需要固定模型的 batch size(即),然后給原始輸入加上一個 shape 同樣為?、全零初始化的Variable。

    比如就叫做?,那么我們可以直接求 loss 對?的梯度,然后根據(jù)梯度給?賦值,來實現(xiàn)對輸入的干擾,完成干擾之后再執(zhí)行常規(guī)的梯度下降。

    對于 NLP 任務(wù)來說,原則上也要對 Embedding 層的輸出進(jìn)行同樣的操作,Embedding 層的輸出 shape 為?,所以也要在 Embedding 層的輸出加上一個 shape 為?的Variable,然后進(jìn)行上述步驟。但這樣一來,我們需要拆解、重構(gòu)模型,對使用者不夠友好。

    不過,我們可以退而求其次。Embedding 層的輸出是直接取自于 Embedding 參數(shù)矩陣的,因此我們可以直接對 Embedding 參數(shù)矩陣進(jìn)行擾動。

    這樣得到的對抗樣本的多樣性會少一些(因為不同樣本的同一個 token 共用了相同的擾動),但仍然能起到正則化的作用,而且這樣實現(xiàn)起來容易得多。

    代碼參考

    基于上述思路,這里給出 Keras 下基于 FGM 方式對 Embedding 層進(jìn)行對抗訓(xùn)練的參考實現(xiàn):

    https://github.com/bojone/keras_adversarial_training

    核心代碼如下:

    def?adversarial_training(model,?embedding_name,?epsilon=1):"""給模型添加對抗訓(xùn)練其中model是需要添加對抗訓(xùn)練的keras模型,embedding_name則是model里邊Embedding層的名字。要在模型compile之后使用。"""if?model.train_function?is?None:??#?如果還沒有訓(xùn)練函數(shù)model._make_train_function()??#?手動makeold_train_function?=?model.train_function??#?備份舊的訓(xùn)練函數(shù)#?查找Embedding層for?output?in?model.outputs:embedding_layer?=?search_layer(output,?embedding_name)if?embedding_layer?is?not?None:breakif?embedding_layer?is?None:raise?Exception('Embedding?layer?not?found')#?求Embedding梯度embeddings?=?embedding_layer.embeddings??#?Embedding矩陣gradients?=?K.gradients(model.total_loss,?[embeddings])??#?Embedding梯度gradients?=?K.zeros_like(embeddings)?+?gradients[0]??#?轉(zhuǎn)為dense?tensor#?封裝為函數(shù)inputs?=?(model._feed_inputs?+model._feed_targets?+model._feed_sample_weights)??#?所有輸入層embedding_gradients?=?K.function(inputs=inputs,outputs=[gradients],name='embedding_gradients',)??#?封裝為函數(shù)def?train_function(inputs):??#?重新定義訓(xùn)練函數(shù)grads?=?embedding_gradients(inputs)[0]??#?Embedding梯度delta?=?epsilon?*?grads?/?(np.sqrt((grads**2).sum())?+?1e-8)??#?計算擾動K.set_value(embeddings,?K.eval(embeddings)?+?delta)??#?注入擾動outputs?=?old_train_function(inputs)??#?梯度下降K.set_value(embeddings,?K.eval(embeddings)?-?delta)??#?刪除擾動return?outputsmodel.train_function?=?train_function??#?覆蓋原訓(xùn)練函數(shù)

    ?

    定義好上述函數(shù)后,給 Keras 模型增加對抗訓(xùn)練就只需要一行代碼了:

    #?寫好函數(shù)后,啟用對抗訓(xùn)練只需要一行代碼 adversarial_training(model,?'Embedding-Token',?0.5)

    ?

    需要指出的是,由于每一步算對抗擾動也需要計算梯度,因此每一步訓(xùn)練一共算了兩次梯度,因此每步的訓(xùn)練時間會翻倍。

    效果比較

    為了測試實際效果,筆者選了中文 CLUE 榜?[9] 的兩個分類任務(wù):IFLYTEK和TNEWS,模型選擇了中文 BERT base。

    在 CLUE 榜單上,BERT base 模型在這兩個數(shù)據(jù)上的成績分別是 60.29% 和56.58%,經(jīng)過對抗訓(xùn)練后,成績?yōu)?62.46%、57.66%,分別提升了 2% 和 1%!

    訓(xùn)練腳本請參考:

    https://github.com/bojone/bert4keras/blob/master/examples/task_iflytek_adversarial_training.py

    當(dāng)然,同所有正則化手段一樣,對抗訓(xùn)練也不能保證每一個任務(wù)都能有提升,但從目前大多數(shù)“戰(zhàn)果”來看,它是一種非常值得嘗試的技術(shù)手段。

    此外,BERT 的 finetune 本身就是一個非常玄乎(靠人品)的過程,前些時間論文Fine-Tuning Pretrained Language Models: Weight Initializations, Data Orders, and Early Stopping [10] 換用不同的隨機(jī)種子跑了數(shù)百次 finetune 實驗,發(fā)現(xiàn)最好的結(jié)果能高出好幾個點,所以如果你跑了一次發(fā)現(xiàn)沒提升,不妨多跑幾次再下結(jié)論。

    延伸思考

    在這一節(jié)中,我們從另一個視角對上述結(jié)果進(jìn)行分析,從而推出對抗訓(xùn)練的另一種方法,并且得到一種關(guān)于對抗訓(xùn)練的更直觀的幾何理解。

    梯度懲罰

    假設(shè)已經(jīng)得到對抗擾動?,那么我們在更新?時,考慮對?的展開:

    對應(yīng)的?的梯度為:

    代入?,得到:

    這個結(jié)果表示,對輸入樣本施加?的對抗擾動,一定程度上等價于往 loss 里邊加入梯度懲罰

    如果對抗擾動是?,那么對應(yīng)的梯度懲罰項則是?(少了個,也少了個2次方)。

    事實上,這個結(jié)果不是新的,據(jù)筆者所知,它首先出現(xiàn)論文 Improving the Adversarial Robustness and Interpretability of Deep Neural Networks by Regularizing their Input Gradients?[11] 里。

    只不過這篇文章不容易搜到,因為你一旦搜索“adversarial training gradient penalty”等關(guān)鍵詞,出來的結(jié)果幾乎都是 WGAN-GP 相關(guān)的東西。

    幾何圖像

    事實上,關(guān)于梯度懲罰,我們有一個非常直觀的幾何圖像。以常規(guī)的分類問題為例,假設(shè)有?個類別,那么模型相當(dāng)于挖了?個坑,然后讓同類的樣本放到同一個坑里邊去:

    梯度懲罰則說同類樣本不僅要放在同一個坑內(nèi),還要放在坑底,這就要求每個坑的內(nèi)部要長這樣:

    為什么要在坑底呢?因為物理學(xué)告訴我們,坑底最穩(wěn)定呀,所以就越不容易受干擾呀,這不就是對抗訓(xùn)練的目的么?

    那坑底意味著什么呢?極小值點呀,導(dǎo)數(shù)(梯度)為零呀,所以不就是希望?越小越好么?

    這便是梯度懲罰 (8) 的幾何意義了。類似的“挖坑”、“坑底”與梯度懲罰的幾何圖像,還可以參考能量視角下的GAN模型:GAN=“挖坑”+“跳坑”。

    L約束

    我們還可以從 L 約束(Lipschitz 約束)的角度來看梯度懲罰。所謂對抗樣本,就是輸入的小擾動導(dǎo)致輸出的大變化,而關(guān)于輸入輸出的控制問題,我們之前在文章深度學(xué)習(xí)中的Lipschitz約束:泛化與生成模型就已經(jīng)探討過。

    一個好的模型,理論上應(yīng)該是“輸入的小擾動導(dǎo)致導(dǎo)致輸出的小變化”,而為了保證這一遍,一個很常用的方案是讓模型滿足 L 約束,即存在常數(shù)?,使得

    這樣一來只要兩個輸出的差距?足夠小,那么就能保證輸出的差距也足夠小。

    而深度學(xué)習(xí)中的Lipschitz約束:泛化與生成模型已經(jīng)討論了,實現(xiàn) L 約束的方案之一就是譜歸一化(Spectral Normalization),所以往神經(jīng)網(wǎng)絡(luò)里邊加入譜歸一化,就可以增強(qiáng)模型的對抗防御性能。

    相關(guān)的工作已經(jīng)被發(fā)表在 Generalizable Adversarial Training via Spectral Normalization [12]。

    美中不足的是,譜歸一化是對模型的每一層權(quán)重都進(jìn)行這樣的操作,結(jié)果就是神經(jīng)網(wǎng)絡(luò)的每一層都滿足 L 約束,這是不必要的(我們只希望整個模型滿足 L 約束,不必強(qiáng)求每一層都滿足),因此理論上來說 L 約束會降低模型表達(dá)能力,從而降低模型性能。

    而在 WGAN 系列模型中,為了讓判別器滿足 L 約束,除了譜歸一化外,還有一種常見的方案,那就是梯度懲罰。因此,梯度懲罰也可以理解為一個促使模型滿足 L 約束的正則項,而滿足 L 約束則能有效地抵御對抗樣本的攻擊。

    代碼實現(xiàn)

    既然梯度懲罰號稱能有類似的效果,那必然也是要接受實驗驗證的了。相比前面的 FGM 式對抗訓(xùn)練,其實梯度懲罰實現(xiàn)起來還容易一些,因為它就是在 loss 里邊多加一項罷了,而且實現(xiàn)方式是通用的,不用區(qū)分 CV 還是 NLP。

    Keras 參考實現(xiàn)如下:

    def?sparse_categorical_crossentropy(y_true,?y_pred):"""自定義稀疏交叉熵這主要是因為keras自帶的sparse_categorical_crossentropy不支持求二階梯度。"""y_true?=?K.reshape(y_true,?K.shape(y_pred)[:-1])y_true?=?K.cast(y_true,?'int32')y_true?=?K.one_hot(y_true,?K.shape(y_pred)[-1])return?K.categorical_crossentropy(y_true,?y_pred)def?loss_with_gradient_penalty(y_true,?y_pred,?epsilon=1):"""帶梯度懲罰的loss"""loss?=?K.mean(sparse_categorical_crossentropy(y_true,?y_pred))embeddings?=?search_layer(y_pred,?'Embedding-Token').embeddingsgp?=?K.sum(K.gradients(loss,?[embeddings])[0].values**2)return?loss?+?0.5?*?epsilon?*?gpmodel.compile(loss=loss_with_gradient_penalty,optimizer=Adam(2e-5),metrics=['sparse_categorical_accuracy'], )

    ?

    可以看到,定義帶梯度懲罰的 loss 非常簡單,就兩行代碼而已。需要指出的是,梯度懲罰意味著參數(shù)更新的時候需要算二階導(dǎo)數(shù),但是 Tensorflow 和 Keras 自帶的 loss 函數(shù)不一定支持算二階導(dǎo)數(shù)。

    比如K.categorical_crossentropy支持而K.sparse_categorical_crossentropy不支持,遇到這種情況時,需要自定重新定義 loss。

    效果比較

    還是前面兩個任務(wù),結(jié)果如下表??梢钥吹?#xff0c;梯度懲罰能取得跟 FGM 基本一致的結(jié)果。

    完整的代碼請參考:

    https://github.com/bojone/bert4keras/blob/master/examples/task_iflytek_gradient_penalty.py

    本文小結(jié)

    本文簡單介紹了對抗訓(xùn)練的基本概念和推導(dǎo),著重講了其中的 FGM 方法并給出了 Keras 實現(xiàn),實驗證明它能提高一些 NLP 模型的泛化性能。此外,本文還討論了對抗學(xué)習(xí)與梯度懲罰的聯(lián)系,并給出了梯度懲罰的一種直觀的幾何理解。

    相關(guān)鏈接

    [1] https://gluebenchmark.com/leaderboard

    [2] https://stanfordnlp.github.io/coqa/

    [3] http://https://arxiv.org/abs/1312.6199

    [4] https://arxiv.org/abs/1706.06083

    [5] https://arxiv.org/abs/1412.6572

    [6] https://arxiv.org/abs/1706.06083

    [7] https://kexue.fm/archives/4122

    [8] https://arxiv.org/abs/1605.07725

    [9] https://www.cluebenchmarks.com/

    [10] https://arxiv.org/abs/2002.06305

    [11] https://arxiv.org/abs/1711.09404

    [12] https://arxiv.org/abs/1811.07457

    點擊以下標(biāo)題查看更多往期內(nèi)容:?

    • 圖自編碼器的起源和應(yīng)用

    • 圖神經(jīng)網(wǎng)絡(luò)三劍客:GCN、GAT與GraphSAGE

    • 如何快速理解馬爾科夫鏈蒙特卡洛法?

    • 深度學(xué)習(xí)預(yù)訓(xùn)練模型可解釋性概覽

    • ICLR 2020 | 隱空間的圖神經(jīng)網(wǎng)絡(luò)

    ????

    現(xiàn)在,在「知乎」也能找到我們了

    進(jìn)入知乎首頁搜索「PaperWeekly」

    點擊「關(guān)注」訂閱我們的專欄吧

    關(guān)于PaperWeekly

    PaperWeekly 是一個推薦、解讀、討論、報道人工智能前沿論文成果的學(xué)術(shù)平臺。如果你研究或從事 AI 領(lǐng)域,歡迎在公眾號后臺點擊「交流群」,小助手將把你帶入 PaperWeekly 的交流群里。

    總結(jié)

    以上是生活随笔為你收集整理的对抗训练浅谈:意义、方法和思考(附Keras实现)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。