Tensorflow2.0 + Transformers 实现Bert FGM对抗训练惩罚梯度损失函数
Tensorflow2.0 + Transformers 實現Bert FGM對抗訓練懲罰梯度損失函數
- 前言
- 變種實現
- Transformers中的word_embeddings
- 代碼修改
- 實驗效果
- 總結
前言
之前看了很多關于NLP中應用對抗訓練的文章,測試結果都很香,所以想在自己在用的模型上試一試看看能不能提升效果,參考了一些代碼找到了pytroch和keras實現,但發現對于tensorflows來說更改訓練過程非常繁瑣,而且容易出錯,如果要配合transformers實現則更難
——transformers的bert類會被打包成一個layers,在調用tf.layers時拿不到里面的embedding_layers,如果有大神知道怎么拿還望留言告知~
變種實現
但最近看了一篇文章對抗訓練淺談:意義、方法和思考(附Keras實現)
文中講到了FGM的效果等價轉化式:
***這里有個小技巧使用了一階泰勒展開:
并且文章也給出了keras的實現代碼:
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_with_gradient_penalty部分仍然需要調用kerasbert的方法search_layer,但transformers中的get_input_embeddings在調用時一直報錯(可能我用法不對)
Transformers中的word_embeddings
但是發現tf除了通過tf.layers追蹤到相應的參數,還能通過model.variables這個方法,
調用 model.variables (model為你搭建好的模型名稱)會返回一個list,里面是按順序排列好的tensor參數,在這里通過 model.variables[0] 即可找到模型的第一層參數:word_embeddings
可以看到前三組參數分別為word_embeddings, position_embeddings, token_type_embeddings, 這里我們只要取word_embeddings(NLP中對抗訓練的擾動對象)即可。
代碼修改
因此我們可以簡單的修改原來的代碼:
def sparse_categorical_crossentropy(y_true, y_pred):y_true = tf.reshape(y_true, tf.shape(y_pred)[:-1])y_true = tf.cast(y_true, tf.int32)y_true = tf.one_hot(y_true, K.shape(y_pred)[-1])return tf.keras.losses.categorical_crossentropy(y_true, y_pred)def loss_with_gradient_penalty(model,epsilon=1):def loss_with_gradient_penalty_2(y_true, y_pred):loss = tf.math.reduce_mean(sparse_categorical_crossentropy(y_true, y_pred))embeddings = model.variables[0]gp = tf.math.reduce_sum(tf.gradients(loss, [embeddings])[0].values**2)return loss + 0.5 * epsilon * gpreturn loss_with_gradient_penalty_2調用方法:
bert_ner_model.compile(optimizer=optimizer, loss=[loss_with_gradient_penalty(bert_ner_model,1.0)], metrics=['sparse_categorical_accuracy'])實驗效果
原sparse_cross_entropy結果:
加入懲罰項(epsilon = 1)結果:
加入懲罰項(epsilon = 0.5)結果:
總結
可以看到使用該懲罰梯度損失函數,以為要計算兩次梯度,訓練時間增加了2倍之多,但模型效果有了一個點左右的提升,而且不容易過擬合。所以看出,盡管無法復原FGM的方法,該用效果差不多的懲罰梯度損失函數,還是可以獲得一定的提升(前提是epsilon這個超參要調好)
參考鏈接:https://spaces.ac.cn/archives/7234
總結
以上是生活随笔為你收集整理的Tensorflow2.0 + Transformers 实现Bert FGM对抗训练惩罚梯度损失函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tensorlfow2.0 二分类和多分
- 下一篇: 统计学习方法第二章作业:感知机模型原始形