小數據福音!BERT在極小數據下帶來顯著提升的開源實現
機器之心專欄
作者:金立達
笨鳥社交 AI Lab
標註數據,可以說是 AI 模型訓練里最艱巨的一項工作了。自然語言處理的數據標註更是需要投入大量人力。相對計算機視覺的圖像標註,文本的標註通常沒有準確的標準答案,對句子理解也是因人而異,讓這項工作更是難上加難。
但是,谷歌最近發布的 BERT [1] 大大地解決了這個問題!根據我們的實驗,BERT 在文本多分類的任務中,能在極小的數據下帶來顯著的分類準確率提升。並且,實驗主要對比的是僅僅 5 個月前發布的 State-of-the-Art 語言模型遷移學習模型 – ULMFiT [2],結果有著明顯的提升。我們先看結果:
圖1. 實驗結果對比,BERT在極少的數據集上表現非常出色
從上圖我們可以看出,在不同的數據集中,BERT 都有非常出色的表現。我們用的實驗數據分為 1000、 6700 和 12000 條,並且各自包含了測試數據,訓練測試分割為 80%-20%。數據集從多個網頁來源獲得,並經過了一系列的分類映射。但 Noisy 數據集帶有較為顯著的噪音,抽樣統計顯示噪音比例在 20% 左右。
實驗對比了幾個模型,從最基礎的卷積網路作為 Baseline,到卷積網路加上傳統的詞向量 Glove embedding, 然後是 ULMFiT 和 BERT。為了防止過擬合,CNN 與 CNN+Glove 模型訓練時加入了 Early stopping。
值得注意的是,這裡用的 BERT 模型均為基礎版本,「BERT-Base, Uncased」,12 層,110M 參數,對比的是 ULMFiT 調整過的最優化參數。可見 BERT 在此任務中的強大。
然而,在 12000 條樣本的數據集上,BERT 的結果相對 6700 條並沒有顯著的提升。數據分類不平衡可能是導致此結果的一大因素。
BERT 開源的多個版本的模型:
圖2. 開源的多個版本的BERT模型
接下來,我們直奔主題 – 如何在自己的機器上實現 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。
圖3. 輸入文本格式樣板
並將這三個文件放入 DATA_DIR 中。
實現細節
首先我們 Clone 官方的 BERT Github repo:
https://github.com/google-research/bert
由於我們要做的是文本多分類任務,可以在 run_classifier.py 基礎上面做調整。
這裡簡單介紹一下這個腳本本來的任務,也就是 BERT 示範的其中一個任務。這個例子是在 Microsoft Research Paraphrase Corpus (MRPC) corpus 數據集上面做微調,數據集僅包含 3600 個樣本,在 GPU 上面幾分鐘就可完成微調。
此數據集可以用以下腳本下載:
https://gist.github.com/W4ngatang/60c2bdb54d156a41194446737ce03e2e
注意運行的時候要用 --tasks all 參數來下載。
圖4. 運行腳本下載MRPC數據集
可以打開看一下輸入數據的結構,都是以 tsv 的形式保存:
圖5. MRPC數據集輸入數據樣本
圖6. MRPC數據集結構樣本
這裡 MRPC 的任務是 Paraphrase Identification,輸入為兩個句子,然後判斷二者是否表示相同的意思,輸出為二分類:是和不是。我們的分類任務只需要一個輸入,而不是一對句子,這個在讀取的過程中可以自動識別,並調整相應的 Sentence Embedding 如下圖所示:
圖7. BERT Sentence Embedding自動調整過程
run_classifier.py 的腳本中,由於輸入格式和之前有少許不同,我們需要更改 _create_examples 函數裡面的讀取順序,原本的讀取位置為:
圖8. MRPC數據集輸入文本讀取方式
我們需要讓 text_a 讀取被分類的文本,而 label 讀取我們的標註:
圖9. 在文本多分類的任務中,讀取輸入的方式
同時由於沒有 text_b,我們需要在後面製作 example 的時候將他賦值為 None:
圖10. 由於沒有Sentence Pair輸入,在這裡需要將text_b定義為None
接下來,相對於原本的二分類,我們需要針對多分類做出一些調整。代碼中原本將標籤列表手動設置為 0 和 1:
圖11. 原本直接將標註列表定義為0和1
這裡我們加入一個新的輸入,然後將輸出調整如下:
圖12. 調整get_labels的輸入和輸出
這裡 labels 輸入為新添加的所有訓練樣本的 Label,然後通過 set() 返回所有 25 個標籤的列表。調整之後,代碼可以自動根據分類數量定義標籤列表,可以適配多種多分類任務。
同時,在 _create_examples 中,我們增加兩個返回值,labels 和 labels_test:
圖13. _create_examples函數增加兩個返回值,labels和label_test
labels 返回的是所有訓練樣本的 label,用來輸入到之前提到的 get_labels()。Labels 的定義如下圖所示:
圖14. 新添加的變數labels
接下來我們需要調整 main() function 裡面的一些順序,因為現在的 get_labels() 需要額外的輸入(讀取的完整 label list),我們需要把讀取訓練集的步驟放到前面。原來的順序:
1. 獲取 label_list;
圖15. 第一步
2. 如果在訓練模式,再讀取訓練集。
圖16. 第二步
現在需要調整為:
1. 無論什麼模式都讀取訓練集,因為需要用到訓練標籤,注意新添加的輸出變數 train_labels;
圖17. 第一步
2. 然後再獲取 label_list,用前面的 train_labels。
圖18. 第二步
最後,我們在開頭設置好參數,可以直接輸入默認值來運行。下面拿 DATA_DIR 來舉例:
圖19. 原始參數
調整後的輸入參數:
圖20. 調整後的參數
1000 條樣本數據 10 分類,BERT 運行結果如下:
圖21. 1000條樣本數據10分類BERT結果
總結
本文介紹了如何實現 BERT 的文本多分類任務,並對比了 Baseline 以及不久前的 State-of-the-Art 模型 ULMFiT。實驗結果可以看出 BERT 在此任務中,可以輕鬆打敗先前的 SOTA。
這裡附上本教程的開源代碼:
https://github.com/Socialbird-AILab/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.
本文為機器之心專欄,轉載請聯繫原公眾號獲得授權。
------------------------------------------------
※別再使用pip安裝TensorFlow了!用conda吧~
※Recurrent AI:呼叫系統的「變廢為寶」
TAG:機器之心 |