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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

语义匹配(一)【NLP论文复现】Sentence-BERT 句子语义匹配模型的tensorflow实现以及训练Trick

發(fā)布時間:2025/3/8 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 语义匹配(一)【NLP论文复现】Sentence-BERT 句子语义匹配模型的tensorflow实现以及训练Trick 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Sentence-BERT 句子語義匹配模型的tensorflow實現(xiàn)以及訓(xùn)練trick

  • 論文模型回顧
  • 建模與訓(xùn)練
    • 模型代碼部分
    • 數(shù)據(jù)處理
    • 訓(xùn)練
  • 模型訓(xùn)練Trick
    • trick1 warm up
      • 代碼實現(xiàn):
    • trick2 focal loss
      • 代碼實現(xiàn):
  • 總結(jié)與思考


論文模型回顧

論文鏈接:https://arxiv.org/abs/1908.10084
文章在已有的語義匹配模型的基礎(chǔ)上提出了基于Bert的句義匹配孿生網(wǎng)絡(luò)

模型介紹:將兩個句子通過Bert(注意:在對句子相似度建模時,兩個句子經(jīng)過的Bert層應(yīng)該是共享權(quán)重的,及同一個Bert)進(jìn)行特征提取后,取最后一層的hidde_layers進(jìn)行pooling,文章試驗了直接取CLS向量、max_pooling、mean_pooling,結(jié)果顯示mean_pooling效果最好。將pooling后得到的兩個句子向量進(jìn)行特征交叉,文章嘗試了多種交叉方式,|u-v|的效果最好,當(dāng)然使用者可以根據(jù)具體任務(wù)和場景自行嘗試多種交叉方法;最后通過softmax層。
訓(xùn)練好模型之后,我們可以將語料庫中的句子通過單塔轉(zhuǎn)化為對應(yīng)的句子向量,當(dāng)待匹配句子進(jìn)入時,通過向量相似度檢索來直接搜索相似句子,節(jié)省了大量的模型推理時間。



建模與訓(xùn)練

tensorflow 2.0.0
transformers 3.1.0

模型代碼部分

class BertNerModel(tf.keras.Model):dense_layer = 512class_num = 2drop_out_rate = 0.5def __init__(self,pretrained_path,config,*inputs,**kwargs):super(BertNerModel,self).__init__()config.output_hidden_states = Trueself.bert = TFBertModel.from_pretrained(pretrained_path,config=config,from_pt=True)self.liner_layer = tf.keras.layers.Dense(self.dense_layer,activation='relu')self.softmax = tf.keras.layers.Dense(self.class_num,activation='softmax')self.drop_out = tf.keras.layers.Dropout(self.drop_out_rate) def call(self,input_1):hidden_states_1,_,_ = self.bert((input_1['input_ids'],input_1['token_type_ids'],input_1['attention_mask']))hidden_states_2,_,_ = self.bert((input_1['input_ids_2'],input_1['token_type_ids_2'],input_1['attention_mask_2']))hidden_states_1 = tf.math.reduce_mean(hidden_states_1,1)hidden_states_2 = tf.math.reduce_mean(hidden_states_2,1)concat_layer = tf.concat((hidden_states_1,hidden_states_2,tf.abs(tf.math.subtract(hidden_states_1, hidden_states_2))),1,)drop_out_l = self.drop_out(concat_layer)Dense_l = self.liner_layer(drop_out_l)outputs = self.softmax(Dense_l)print(outputs.shape)return outputs

這里比較難受的是,在自定義模型的時候本來想直接繼承transformers的TFBertPreTrainedModel類,但是發(fā)現(xiàn)這傳入訓(xùn)練數(shù)據(jù)的時候需要以元組的形式傳入,但是在tf model.fit的時候會報錯無法識別元組+datasets的數(shù)據(jù),因此這里改為繼承tf.keras.Model,在類中直接加入TFBertModel.from_pretrained加載之后的TFBertModel,再在后面接自定義的層。

數(shù)據(jù)處理

def data_proceed(path,batch_size,tokenizer):data = pd.read_csv(path)data = data.sample(frac=1)inputs_1 = tokenizer(list(data['sentence1']), padding=True, truncation=True, return_tensors="tf",max_length=30)inputs_2 = tokenizer(list(data['sentence2']), padding=True, truncation=True, return_tensors="tf",max_length=30)inputs_1 = dict(inputs_1)inputs_1['input_ids_2'] = inputs_2['input_ids']inputs_1['token_type_ids_2'] = inputs_2['token_type_ids']inputs_1['attention_mask_2'] = inputs_2['attention_mask']label = list(data['label'])steps = len(label)//batch_sizex = tf.data.Dataset.from_tensor_slices((dict(inputs_1),label))return x,steps

訓(xùn)練

optimizer = tf.keras.optimizers.Adam(learning_rate=5e-5)bert_ner_model.compile(optimizer=optimizer,loss='sparse_categorical_crossentropy',metrics=['acc'])bert_ner_model.fit(train_data,epochs=5,verbose=1,steps_per_epoch=steps_per_epoch,validation_data=test_data,validation_steps=validation_steps)

模型訓(xùn)練Trick

trick1 warm up

原文中提到了在訓(xùn)練時warm up learning rate的訓(xùn)練技巧

由于剛開始訓(xùn)練時,模型的權(quán)重(weights)是隨機(jī)初始化的,此時若選擇一個較大的學(xué)習(xí)率,可能帶來模型的不穩(wěn)定(振蕩),選擇Warmup預(yù)熱學(xué)習(xí)率的方式,可以使得開始訓(xùn)練的幾個epoches或者一些steps內(nèi)學(xué)習(xí)率較小,在預(yù)熱的小學(xué)習(xí)率下,模型可以慢慢趨于穩(wěn)定,等模型相對穩(wěn)定后再選擇預(yù)先設(shè)置的學(xué)習(xí)率進(jìn)行訓(xùn)練,使得模型收斂速度變得更快,模型效果更佳。
該段摘自深度學(xué)習(xí)訓(xùn)練策略-學(xué)習(xí)率預(yù)熱Warmup

代碼實現(xiàn):

class WarmupExponentialDecay(Callback):def __init__(self,lr_base=0.0002,decay=0,warmup_epochs=0,steps_per_epoch=0):self.num_passed_batchs = 0 #一個計數(shù)器self.warmup_epochs=warmup_epochs self.lr=lr_base #learning_rate_baseself.decay=decay #指數(shù)衰減率self.steps_per_epoch=steps_per_epoch #也是一個計數(shù)器def on_batch_begin(self, batch, logs=None):# params是模型自動傳遞給Callback的一些參數(shù)if self.steps_per_epoch==0:#防止跑驗證集的時候唄更改了if self.params['steps'] == None:self.steps_per_epoch = np.ceil(1. * self.params['samples'] / self.params['batch_size'])else:self.steps_per_epoch = self.params['steps']if self.num_passed_batchs < self.steps_per_epoch * self.warmup_epochs:K.set_value(self.model.optimizer.lr,self.lr*(self.num_passed_batchs + 1) / self.steps_per_epoch / self.warmup_epochs)else:K.set_value(self.model.optimizer.lr,self.lr*((1-self.decay)**(self.num_passed_batchs-self.steps_per_epoch*self.warmup_epochs)))self.num_passed_batchs += 1def on_epoch_begin(self,epoch,logs=None):#用來輸出學(xué)習(xí)率的,可以刪除print("learning_rate:",K.get_value(self.model.optimizer.lr))

trick2 focal loss

在實際應(yīng)用中,負(fù)樣本往往來自于負(fù)采樣,大量的負(fù)采樣會時訓(xùn)練時負(fù)樣本數(shù)量遠(yuǎn)多余正樣本數(shù)量導(dǎo)致訓(xùn)練樣本不平衡,且軟負(fù)采樣的負(fù)樣本往往非常弱,在模型推理時置信度一般較高,加入focal loss可以讓模型專注于那些置信度低的比較難區(qū)分的樣本,提高模型的訓(xùn)練效果。
詳細(xì)可以查看我的之前的博客Tensorlfow2.0 二分類和多分類focal loss實現(xiàn)和在文本分類任務(wù)效果評估

代碼實現(xiàn):

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#使用方法: model.compile(optimizer=optimizer, loss=softmax_focal_loss,metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])

效果:
在公開數(shù)據(jù)集上:該focal_loss可以很好的抑制模型過擬合且模型效果也有1個多點(diǎn)的提升。


總結(jié)與思考

本次訓(xùn)練使用的數(shù)據(jù)集:LCQMC 是哈爾濱工業(yè)大學(xué)在自然語言處理國際頂會 COLING2018 構(gòu)建的問題語義匹配數(shù)據(jù)集,其目標(biāo)是判斷兩個問題的語義是否相同。準(zhǔn)確率能達(dá)到90%+

但在實際測試時發(fā)現(xiàn),模型推理相似的問句條件比較嚴(yán)格,無法做到真的根據(jù)語義進(jìn)行匹配,(對于同義詞、別名等無法識別區(qū)分)需要應(yīng)用到實際生產(chǎn)工作則對訓(xùn)練樣本的要求比較嚴(yán)格。

拓展思考:由于該孿生模型的兩個句子共享一個bert參數(shù),因此要求兩個句子的分布或者說兩個句子必須來自統(tǒng)一場景,需要在格式、長度、風(fēng)格、句式上比較相近。因此在問句匹配、句子相似度判斷等工作上能有不錯的表現(xiàn)。但可能不適用于類似評論于商品相關(guān)度等任務(wù)的分析(因為評論文本于商品介紹文本不統(tǒng)一,經(jīng)過同一個Bert會產(chǎn)生偏差)因此思考對于此類問題,借鑒雙塔模型,使用兩個不同的Bert來提取兩種分布的句子特征,或許仍能有不錯的標(biāo)簽,之后有機(jī)會會試驗一下~

總結(jié)

以上是生活随笔為你收集整理的语义匹配(一)【NLP论文复现】Sentence-BERT 句子语义匹配模型的tensorflow实现以及训练Trick的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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