小資料福音!BERT在極小資料下帶來顯著提升的開源實現
作者丨金立達
單位丨笨鳥社交 AI Lab
學校丨英國帝國理工學院
研究方向丨自然語言處理、知識圖譜
標註資料,可以說是 AI 模型訓練裡最艱鉅的一項工作了。自然語言處理的資料標註更是需要投入大量人力。相對計算機視覺的影象標註,文字的標註通常沒有準確的標準答案,對句子理解也是因人而異,讓這項工作更是難上加難。
但是,谷歌最近釋出的 BERT [1] 大大地解決了這個問題!根據我們的實驗,BERT 在文字多分類的任務中,能在極小的資料下帶來顯著的分類準確率提升。並且,實驗主要對比的是僅僅 5 個月前釋出的 State-of-the-Art 語言模型遷移學習模型 – ULMFiT [2],結果有著明顯的提升。我們先看結果:

從上圖我們可以看出,在不同的資料集中,BERT 都有非常出色的表現。我們用的實驗資料分為 1000、 6700 和 12000 條,並且各自包含了測試資料,訓練測試分割為 80%-20%。資料集從多個網頁來源獲得,並經過了一系列的分類對映。但 Noisy 資料集帶有較為顯著的噪音,抽樣統計顯示噪音比例在 20% 左右。
實驗對比了幾個模型,從最基礎的卷積網路作為 Baseline,到卷積網路加上傳統的詞向量 Glove embedding, 然後是 ULMFiT 和 BERT 。為了防止過擬合,CNN 與 CNN+Glove 模型訓練時加入了 Early stopping。
值得注意的是, 這裡用的 BERT 模型均為基礎版本 ,“BERT-Base, Uncased”,12 層,110 萬引數, 對比的是 ULMFiT 調整過的最優化引數 。可見 BERT 在此任務中的強大。
然而,在 12000 條樣本的資料集上,BERT 的結果相對 6700 條並沒有顯著的提升。資料分類不平衡可能是導致此結果的一大因素。
BERT 開源的多個版本的模型:

接下來,我們直奔主題 – ofollow,noindex">如何在自己的機器上實現 BERT 的文字 25 分類任務 。教程分為以下幾部分:
- 執行環境
- 硬體配置
- 下載模型
- 輸入資料準備
- 實現細節
執行環境
TensorFlow 版本為 Windows 1.10.0 GPU,具體安裝教程可以參考此連結:
https://www. tensorflow.org/install/ pip?lang=python3
Anaconda 版本為 1.9.2。
硬體配置
實驗用的機器顯示卡為 NVIDIA GeoForce GTX 1080 Ti,BERT base 模型佔用視訊記憶體約為 9.5G。
下載模型
所有的執行環境設定好後,在這裡可以下載到我們實驗用的 BERT base:
https:// storage.googleapis.com/ bert_models/2018_10_18/uncased_L-12_H-768_A-12.zip
下載完後,放在 BERT_BASE_DIR 中。
輸入資料準備
我們需要將文字資料分為三部分:
- Train: train.tsv
- Evaluate: dev.tsv
- Test: test.tsv
下面可以看到每個檔案的格式,非常簡單,一列為需要做分類的文字資料,另一列則是對應的 Label。

並將這三個檔案放入 DATA_DIR 中。
實現細節
首先我們 Clone 官方的 BERT Github repo:
https:// github.com/google-resea rch/bert
由於我們要做的是文字多分類任務,可以在 run_classifier.py 基礎上面做調整。
這裡簡單介紹一下這個指令碼本來的任務,也就是 BERT 示範的其中一個任務。這個例子是在 Microsoft Research Paraphrase Corpus (MRPC) corpus 資料集上面做微調,資料集僅包含 3600 個樣本,在 GPU 上面幾分鐘就可完成微調。
此資料集可以用以下指令碼下載:
https:// gist.github.com/W4ngata ng/60c2bdb54d156a41194446737ce03e2e
注意執行的時候要用 -- tasks all 引數來下載。

可以開啟看一下輸入資料的結構,都是以 tsv 的形式儲存:


這裡 MRPC 的任務是 Paraphrase Identification,輸入為兩個句子,然後判斷二者是否表示相同的意思,輸出為二分類:是和不是。我們的分類任務只需要一個輸入,而不是一對句子,這個在讀取的過程中可以自動識別,並調整相應的 Sentence Embedding 如下圖所示:

run_classifier.py 的指令碼中,由於輸入格式和之前有少許不同,我們需要更改 _create_examples 函式裡面的讀取順序,原本的讀取位置為:

我們需要讓 text_a 讀取被分類的文字,而 label 讀取我們的標註:

同時由於沒有 text_b ,我們需要在後面製作 example 的時候將他賦值為 None :

接下來,相對於原本的二分類,我們需要針對多分類做出一些調整。程式碼中原本將標籤列表手動設定為 0 和 1:

這裡我們加入一個新的輸入,然後將輸出調整如下:

這裡 labels 輸入為新新增的所有訓練樣本的 Label,然後通過 set() 返回所有 25 個標籤的列表。調整之後,程式碼可以自動根據分類數量定義標籤列表,可以適配多種多分類任務。
同時,在 _create_examples 中,我們增加兩個返回值, labels 和 labels_test :

labels 返回的是所有訓練樣本的 label,用來輸入到之前提到的 get_labels() 。 Labels 的定義如下圖所示:

接下來我們需要調整 main() function 裡面的一些順序,因為現在的 get_labels() 需要額外的輸入(讀取的完整 label list),我們需要把讀取訓練集的步驟放到前面。 原來的順序:
1. 獲取 label_list;

2. 如果在訓練模式,再讀取訓練集。

現在需要調整為:
1. 無論什麼模式都讀取訓練集 ,因為需要用到訓練標籤,注意新新增的輸出變數 train_labels ;

2. 然後再獲取 label_list,用前面的 train_labels。

最後,我們在開頭設定好引數,可以直接輸入預設值來執行。下面拿 DATA_DIR 來舉例:

調整後的輸入引數:

1000 條樣本資料 10 分類,BERT 執行結果如下:

總結
本文介紹瞭如何實現 BERT 的文字多分類任務,並對比了 Baseline 以及不久前的 State-of-the-Art 模型 ULMFiT 。實驗結果可以看出 BERT 在此任務中,可以輕鬆打敗先前的 SOTA。
這裡附上本教程的開原始碼:
https:// github.com/Socialbird-A ILab/BERT-Classification-Tutorial
我們依然會在 BERT 的基礎上不斷嘗試,繼續努力研究,也歡迎大家積極交流。
參考文獻
[1] Devlin, Jacob and Chang, Ming-Wei and Lee, Kenton and Toutanova, Kristina. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. arXiv preprint arXiv:1810.04805.
[2] Jeremy Howard and Sebastian Ruder. 2018. Universal language model fine-tuning for text classification. In ACL. Association for Computational Linguistics.
#投 稿 通 道#
如何才能讓更多的優質內容以更短路徑到達讀者群體,縮短讀者尋找優質內容的成本呢? 答案就是:你不認識的人。
總有一些你不認識的人,知道你想知道的東西。PaperWeekly 或許可以成為一座橋樑,促使不同背景、不同方向的學者和學術靈感相互碰撞,迸發出更多的可能性。
PaperWeekly 鼓勵高校實驗室或個人,在我們的平臺上分享各類優質內容,可以是 最新論文解讀 ,也可以是 學習心得 或 技術乾貨 。我們的目的只有一個,讓知識真正流動起來。
:memo: 來稿標準:
• 稿件確係個人 原創作品 ,來稿需註明作者個人資訊(姓名+學校/工作單位+學歷/職位+研究方向)
• 如果文章並非首發,請在投稿時提醒並附上所有已釋出連結
• PaperWeekly 預設每篇文章都是首發,均會新增“原創”標誌
:mailbox_with_mail: 投稿方式:
• 方法一:在PaperWeekly知乎專欄頁面點選“投稿”,即可遞交文章
• 方法二:傳送郵件至: [email protected] ,所有文章配圖,請單獨在附件中傳送
• 請留下即時聯絡方式(微信或手機),以便我們在編輯釋出時和作者溝通
關於PaperWeekly
PaperWeekly 是一個推薦、解讀、討論、報道人工智慧前沿論文成果的學術平臺。如果你研究或從事 AI 領域,歡迎在公眾號後臺點選 「交流群」 ,小助手將把你帶入 PaperWeekly 的交流群裡。
加入社群: http:// paperweek.ly
微信公眾號:PaperWeekly