乾貨| BERT fine-tune 終極實踐教程

2020-12-11 雷鋒網

從11月初開始,google-research就陸續開源了BERT的各個版本。google此次開源的BERT是通過tensorflow高級API—— tf.estimator進行封裝(wrapper)的。因此對於不同數據集的適配,只需要修改代碼中的processor部分,就能進行代碼的訓練、交叉驗證和測試。

以下是奇點機智技術團隊對BERT在中文數據集上的fine tune終極實踐教程。

在自己的數據集上運行 BERT

BERT的代碼同論文裡描述的一致,主要分為兩個部分。一個是訓練語言模型(language model)的預訓練(pretrain)部分。另一個是訓練具體任務(task)的fine-tune部分。在開源的代碼中,預訓練的入口是在run_pretraining.py而fine-tune的入口針對不同的任務分別在run_classifier.py和run_squad.py。其中run_classifier.py適用的任務為分類任務。如CoLA、MRPC、MultiNLI這些數據集。而run_squad.py適用的是閱讀理解(MRC)任務,如squad2.0和squad1.1。

預訓練是BERT很重要的一個部分,與此同時,預訓練需要巨大的運算資源。按照論文裡描述的參數,其Base的設定在消費級的顯卡Titan x 或Titan 1080ti(12GB RAM)上,甚至需要近幾個月的時間進行預訓練,同時還會面臨顯存不足的問題。不過所幸的是谷歌滿足了Issues#2裡各國開發者的請求,針對大部分語言都公布了BERT的預訓練模型。因此在我們可以比較方便地在自己的數據集上進行fine-tune。

下載預訓練模型

對於中文而言,google公布了一個參數較小的BERT預訓練模型。具體參數數值如下所示:

Chinese Simplified and Traditional, 12-layer, 768-hidden, 12-heads, 110M parameters

模型的下載連結可以在github上google的開原始碼裡找到。對下載的壓縮文件進行解壓,可以看到文件裡有五個文件,其中bert_model.ckpt開頭的文件是負責模型變量載入的,而vocab.txt是訓練時中文文本採用的字典,最後bert_config.json是BERT在訓練時,可選調整的一些參數。

修改 processor

任何模型的訓練、預測都是需要有一個明確的輸入,而BERT代碼中processor就是負責對模型的輸入進行處理。我們以分類任務的為例,介紹如何修改processor來運行自己數據集上的fine-tune。在run_classsifier.py文件中我們可以看到,google對於一些公開數據集已經寫了一些processor,如XnliProcessor,MnliProcessor,MrpcProcessor和ColaProcessor。這給我們提供了一個很好的示例,指導我們如何針對自己的數據集來寫processor。

對於一個需要執行訓練、交叉驗證和測試完整過程的模型而言,自定義的processor裡需要繼承DataProcessor,並重載獲取label的get_labels和獲取單個輸入的get_train_examples,get_dev_examples和get_test_examples函數。其分別會在main函數的FLAGS.do_train、FLAGS.do_eval和FLAGS.do_predict階段被調用。
這三個函數的內容是相差無幾的,區別只在於需要指定各自讀入文件的地址。

以get_train_examples為例,函數需要返回一個由InputExample類組成的list。InputExample類是一個很簡單的類,只有初始化函數,需要傳入的參數中guid是用來區分每個example的,可以按照train-%d'%(i)的方式進行定義。text_a是一串字符串,text_b則是另一串字符串。在進行後續輸入處理後(BERT代碼中已包含,不需要自己完成) text_a和text_b將組合成[CLS] text_a [SEP] text_b [SEP]的形式傳入模型。最後一個參數label也是字符串的形式,label的內容需要保證出現在get_labels函數返回的list裡。

舉一個例子,假設我們想要處理一個能夠判斷句子相似度的模型,現在在data_dir的路徑下有一個名為train.csv的輸入文件,如果我們現在輸入文件的格式如下csv形式:

1,你好,您好
0,你好,你家住哪

那麼我們可以寫一個如下的get_train_examples的函數。當然對於csv的處理,可以使用諸如csv.reader的形式進行讀入。

def get_train_examples(self, data_dir):
   file_path = os.path.join(data_dir, 'train.csv')    with open(file_path, 'r') as f:
       reader = f.readlines()
   examples = []    for index, line in enumerate(reader):
       guid = 'train-%d'%index
       split_line = line.strip().split(',')
       text_a = tokenization.convert_to_unicode(split_line[1])
       text_b = tokenization.convert_to_unicode(split_line[2])
       label = split_line[0]
       examples.append(InputExample(guid=guid, text_a=text_a,
                                    text_b=text_b, label=label))    return examples

同時對應判斷句子相似度這個二分類任務,get_labels函數可以寫成如下的形式:

def get_labels(self):
   return ['0','1']

在對get_dev_examples和get_test_examples函數做類似get_train_examples的操作後,便完成了對processor的修改。其中get_test_examples可以傳入一個隨意的label數值,因為在模型的預測(prediction)中label將不會參與計算。

修改 processor 字典

修改完成processor後,需要在在原本main函數的processor字典裡,加入修改後的processor類,即可在運行參數裡指定調用該processor。

processors = {

      "cola": ColaProcessor,

      "mnli": MnliProcessor,

      "mrpc": MrpcProcessor,

      "xnli": XnliProcessor,
      "selfsim": SelfProcessor #添加自己的processor
 }

運行 fine-tune

之後就可以直接運行run_classsifier.py進行模型的訓練。在運行時需要制定一些參數,一個較為完整的運行參數如下所示:

export BERT_BASE_DIR=/path/to/bert/chinese_L-12_H-768_A-12 #全局變量 下載的預訓練bert地址export MY_DATASET=/path/to/xnli #全局變量 數據集所在地址python run_classifier.py \
 --task_name=selfsim \ #自己添加processor在processors字典裡的key名
 --do_train=true \
 --do_eval=true \
 --dopredict=true \
 --data_dir=$MY_DATASET \
 --vocab_file=$BERT_BASE_DIR/vocab.txt \
 --bert_config_file=$BERT_BASE_DIR/bert_config.json \
 --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
 --max_seq_length=128 \ #模型參數
 --train_batch_size=32 \
 --learning_rate=5e-5 \
 --num_train_epochs=2.0 \
 --output_dir=/tmp/selfsim_output/ #模型輸出路徑

BERT 原始碼裡還有什麼

在開始訓練我們自己fine-tune的BERT後,我們可以再來看看BERT代碼裡除了processor之外的一些部分。
我們可以發現,process在得到字符串形式的輸入後,在file_based_convert_examples_to_features裡先是對字符串長度,加入[CLS]和[SEP]等一些處理後,將其寫入成TFrecord的形式。這是為了能在estimator裡有一個更為高效和簡易的讀入。

我們還可以發現,在create_model的函數裡,除了從modeling.py獲取模型主幹輸出之外,還有進行fine-tune時候的loss計算。因此,如果對於fine-tune的結構有自定義的要求,可以在這部分對代碼進行修改。如進行NER任務的時候,可以按照BERT論文裡的方式,不只讀第一位的logits,而是將每一位logits進行讀取。

BERT這次開源的代碼,由於是考慮在google自己的TPU上高效地運行,因此採用的estimator是tf.contrib.tpu.TPUEstimator,雖然TPU的estimator同樣可以在gpu和cpu上運行,但若想在gpu上更高效地做一些提升,可以考慮將其換成tf.estimator.Estimator,於此同時model_fn裡一些tf.contrib.tpu.TPUEstimatorSpec也需要修改成tf.estimator.EstimatorSpec的形式,以及相關調用參數也需要做一些調整。在轉換成較普通的estimator後便可以使用常用的方式對estimator進行處理,如生成用於部署的.pb文件等。

GitHub Issues 裡一些有趣的內容

從google對BERT進行開源開始,Issues裡的討論便異常活躍,BERT論文第一作者Jacob Devlin也積極地在Issues裡進行回應,在交流討論中,產生了一些很有趣的內容。

在GitHub Issues#95中大家討論了BERT模型在今年AI-Challenger比賽上的應用。我們也同樣嘗試了BERT在AI-Challenger的機器閱讀理解(mrc)賽道的表現。如果簡單得地將mrc的文本連接成一個長字符串的形式,可以在dev集上得到79.1%的準確率。

如果參考openAI的GPT論文裡multi-choice的形式對BERT的輸入輸出代碼進行修改則可以將準確率提高到79.3%。採用的參數都是BERT默認的參數,而單一模型成績在賽道的test a排名中已經能超過榜單上的第一名。因此,在相關中文的任務中,bert能有很大的想像空間。

在GitHub Issues#123中,@hanxiao給出了一個採用ZeroMQ便捷部署BERT的service,可以直接調用訓練好的模型作為應用的接口。同時他將BERT改為一個大的encode模型,將文本通過BERT進行encode,來實現句子級的encode。此外,他對比了多GPU上的性能,發現bert在多GPU並行上的出色表現。

總結

總的來說,google此次開源的BERT和其預訓練模型是非常有價值的,可探索和改進的內容也很多。相關數據集上已經出現了對BERT進行修改後的複合模型,如squad2.0上哈工大(HIT)的AoA + DA + BERT以及西湖大學(DAMO)的SLQA + BERT。 在感謝google這份付出的同時,我們也可以藉此站在巨人的肩膀上,嘗試將其運用在自然語言處理領域的方方面面,讓人工智慧的夢想更近一步。

雷鋒網版權文章,未經授權禁止轉載。詳情見轉載須知。

相關焦點

  • PyTorch 學習筆記(五):Finetune和各層定製學習率
    同時提供每月大咖直播分享、真實項目需求對接、乾貨資訊匯總,行業技術交流。點擊文末「閱讀原文」立刻申請入群~作者 | 餘霆嵩來源專欄 | PyTorch學習筆記本文截取自一個github上千星的火爆教程——《PyTorch 模型訓練實用教程》,教程內容主要為在 PyTorch 中訓練一個模型所可能涉及到的方法及函數的詳解等,本文為作者整理的學習筆記(五),
  • 「fine-tune」別理解成「好的調子」!
    大家好,今天我們分享一個非常有用且地道的表達——fine-tune, 這個短語的含義不是指「好的調子」,其正確的含義是:fine-tune 對…進行微調,調整She spent hours fine-tuning
  • bert之我見-positional encoding
    近期我會一連幾篇談談bert中的關鍵細節,這個position encoding是我看到的bert(實質上是transformer中提出的)中最為驚喜的但是卻被很多人忽略(可以理解為媒體鼓吹最少的)一個細節,這裡給大家談談。什麼是position encoding顧名思義,就是基於位置的一套詞嵌入方法,說得簡單點,就是對於一個句子,都有對應的一個向量。
  • 3分鐘看懂史上最強NLP模型BERT
    然後,使用少量經過標記的訓練數據對模型進行fine-tune,以監督學習的方式,執行多種監督任務。預訓練機器學習模型已經在包括視覺、自然語言處理在內的各個領域取得了成功。它基於谷歌2017年發布的Transformer架構,通常的Transformer使用一組編碼器和解碼器網絡,而BERT只需要一個額外的輸出層,對預訓練進行fine-tune,就可以滿足各種任務,根本沒有必要針對特定任務對模型進行修改。BERT將多個Transformer編碼器堆疊在一起。
  • 【BERT】如何訓練並使用Bert【持續更新】
    什麼叫做finetuning,什麼叫做feature-based。For each task, we simply plug in the task- specific inputs and outputs into BERT and fine- tune all the parameters end-to-end
  • BERT在情感分析ATSC子任務的應用
    準備fine-tuning BERT語言模型的數據這個步驟是準備fine-tuning(其實是在BERT基礎模型的基礎上繼續pretraining)語言模型的數據,作者也提供了他fine-tuning之後的模型,如果讀者不想自己fine-tuning語言模型可以跳過這一步。
  • 如何用 GPT2 和 BERT 建立一個可信的 reddit 自動回復機器人?
    如果願意,可以直接跳轉到項目代碼:https://github.com/lots-of-things/gpt2-bert-reddit-bot 。現在,你可以使用此腳本將數據轉換為 GPT-2 微調所需的格式,並將其保存為 gpt2_finetune.csv。微調 GPT-2 並為 reddit 生成文本使用 GPT-2 的主要優勢在於,它已經在網際網路上數百萬頁文本的海量數據集上進行了預訓練。然而,如果你直接使用 GPT-2,你最終生成的文本會看起來像你在網際網路上找到的任何東西。
  • 三分鐘帶你讀懂 BERT
    每個fine-tuning實驗採用單個TPU均在1小時內完成,GPU上需要幾小時。  結果BERT在11項NLP任務中超越了最優的算法。模型可進行fine-tuned,然後用於多項NLP任務,諸如文本分類、文本相似度、問答系統、文本標記如詞性POS命名和實體識別NER等。當然預訓練BERT計算上相當昂貴,除非你採用TPU或類似Nvidia V100這樣的GPU。BERT技術人員同時也放出了多語言模型,模型採用Wikipedia裡的100多種語言。不過多語言BERT模型比單語言模型的性能要略低幾個百分點。
  • 大神教程乾貨:使用BERT的多類別情感分析!(附代碼)
    , df_bert_dev = train_test_split(df_bert, test_size=0.01)建築測試數據集我們在測試數據集中只需要兩列列0:GUID:該行的ID。(『yelp_review_full_csv\\train.tsv』, sep=』\t』, index=False, header=False)df_bert_dev.to_csv(『yelp_review_full_csv\\dev.tsv』, sep=』\t』, index=False, header=False)df_bert_test.to_csv
  • 「瘦身成功」的ALBERT,能取代BERT嗎?
    wget https://github.com/LydiaXiaohongLi/Albert_Finetune_with_Pretrain_on_Custom_Corpus/raw/master/model_checkpoint/finetune_checkpoint 9!
  • [PyTorch 學習筆記] 7.2 模型 Finetune
    本章代碼:https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson7/finetune_resnet18.py這篇文章主要介紹了模型的 Finetune。
  • 從 one-hot 到 BERT,帶你一步步理解 BERT
    我們會從one-hot、word embedding、rnn、seq2seq、transformer一步步逼近bert,這些是我們理解bert的基礎。Word Embedding首先我們需要對文本進行編碼,使之成為計算機可以讀懂的語言,在編碼時,我們期望句子之間保持詞語間的相似行,詞的向量表示是進行機器學習和深度學習的基礎。
  • 詞向量詳解:從word2vec、glove、ELMo到BERT
    目前,詞向量(又叫詞嵌入)已經成為NLP領域各種任務的必備一步,而且隨著bert elmo,gpt等預訓練模型的發展,詞向量演變為知識表示方法,但其本質思想不變。學習各種詞向量訓練原理可以很好地掌握NLP各種方法。生成詞向量的方法有很多種,本文重點介紹word2vec,glove和bert。
  • Wavs tune音高節奏修正工具參數功能詳解「圖文教程」
    關於音高修正的工具比較多,之前我們講過Melodyne,Flex Pitch,這次我們把Waves tune,waves realtime tune也一併講了。關於音高修正方面就齊全了。Wavs tune修音,它的手工修正操作方便簡單,而且音質聽起來非常自然,也是我們修音的重要工具,另外界面看起來也比較友好,操作也相對方便,他的工具都放在下部工具架上,直接選取就可以。
  • [預訓練語言模型專題] BERT,開啟NLP新時代的王者
    文章在一開始概括了當時的兩種不同的預訓練語言模型的策略,feature-based 策略及 fine-tuning 策略。feature-based策略的代表模型為ELMo,它把預訓練得到的「向量表示」作為訓練下遊任務的額外特徵。訓練下遊任務時使用新的任務相關模型,並基於得到的特徵來進行進一步的訓練。f
  • 長文解讀綜述NLP中的預訓練模型(純乾貨)
    finetune:微調階段以文本分類為例。一個sentence在送入Transfomer處理之前,先要在前後加入連個標識符<s>和<e>.分別表示開始和結束。然後經過一個全連接層之後映射到類別數目,與真值進行二進位交叉熵損失函數的計算,最後反向傳播對模型參數進行finetune。當然作者也提到了在finetune階段加上預測下一個詞的任務能提高整體的模型性能。損失函數包含兩項:
  • 如何用 Python 和 BERT 做多標籤(multi-label)文本分類?
    一文裡,給你講過遷移學習的範例 ULMfit (Universal language model fine-tuning for text classification)。你只需要依次執行代碼,就可以復現本教程的運行結果了。如果你對 Google Colab 不熟悉,沒關係。我這裡有一篇教程,專門講解 Google Colab 的特點與使用方式。為了你能夠更為深入地學習與了解代碼,我建議你在 Google Colab 中開啟一個全新的 Notebook ,並且根據下文,依次輸入代碼並運行。在此過程中,充分理解代碼的含義。
  • BERT4Rec:使用Bert進行序列推薦
    Encoder Representations from Transformer,https://blog.csdn.net/luoxiaolin_love/article/details/93192601【5】BERT4REC:使用Bert進行推薦 - 魏晉的文章 - 知乎 https://zhuanlan.zhihu.com/p/97123417【6】BERT在美團搜索核心排序的探索和實踐