糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > Tensorflow2.0 + Transformers 实现Bert FGM对抗训练惩罚梯度损失函数

Tensorflow2.0 + Transformers 实现Bert FGM对抗训练惩罚梯度损失函数

时间:2022-05-29 18:08:32

相关推荐

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 * pile(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

调用方法:

pile(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这个超参要调好)


参考链接:/archives/7234

如果觉得《Tensorflow2.0 + Transformers 实现Bert FGM对抗训练惩罚梯度损失函数》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。