iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 19
0

https://ithelp.ithome.com.tw/upload/images/20191004/20119971kajyMmwuo2.png
Multi-label Text Classification using BERT – The Mighty Transformer

今天要來芝麻街上英文課囉!
最近芝麻街的腳色紛紛重出江湖,又引起大家的熱烈討論,在做語意相關研究的一定都聽過這個創造語意新世代的模型 - BERT

以前在做語意分類任務時,常常就是先斷詞斷句,接著透過自己用一個大的corpus 做 word embedding,或是使用一些別人訓練好的模型,像是 google-news pre-trained 模型,最後接一個分類模型常常就可以有不錯的表現,但後來大家也發現一些問題,像是同字異義的詞,往往也用同一組詞向量表示,但其實他們的意思可能天差地遠。

以現在很多大廠爭相在做的智慧音箱為例,他的功能可能有購物、聽音樂、查詢天氣......等等,所以如果這時你對音箱說
Q: 小寶小寶 我想買東西

應該是可以順利分到購物的任務裡面,但如果這時你對音箱說

Q: 小寶小寶 你是什麼東西?

這時很有可能其他的字沒看過,他只學過 東西 這個詞,應此也進到購物的任務裡,這時後顧客可能會想要退貨,並想說你這個音箱太爛了吧,還號稱人工智慧...

而今天要介紹的主角 - BERT ,能力遠不止這樣,其架構精神為Transfomer Encoder。BERT主要的應用會是以Transfer learning後接著Fine tune model。接著會帶大家一步一步實際去 fine tune 一個語意分類任務。 如果是想更進階的知道BERT內部的架構,可以參考李宏毅老師的ELMO&BERT 以及 Transformer不是變形金剛唷,裡面有非常完整的介紹。

這邊會使用常出現在情感分析教學的資料集 - IMDB

comment: Oh yeah! Jenna Jameson did it again! Yeah Baby! This movie rocks. It was one of the 1st movies i saw of her. 
label: 1 

資料包含使用者對於電影的評論,還有該評論是屬於正面還是負面的標注,
接著照著bert tf2.0專案裡面的教學安裝好環境

PS: 因為BERT 這個專案一開始是搭配 tensor flow 1.11,所以當你在使用 tensorflow 2.0 時可能會誤觸很多雷,所以請小心服用。
包括像是 pre-trained model 下載,2.0的專案目前也還沒提供多國語言版本,另外如果在訓練過程中有遇到 out-of-memory 問題,請參考

裡面也提到 when using a GPU with 12GB - 16GB of RAM, you are likely to encounter out-of-memory issues if you use the same hyperparameters described in the paper.
總之,訓練一定有風險,訓練前請詳閱 github 的 readme

接著我們選用一個比較小的 pre-trained model
BERT-Base, Uncased : 12-layer, 768-hidden, 12-heads, 110M parameters

把剛剛的專案下載下來
把剛剛的專案下載下來
git clone https://github.com/tensorflow/models/tree/master/official/nlp/bert

然後把剛剛下載好的模型移進去,接下來我們需要改動到的部分就只要下面的這些檔案

├── classifier_data_lib.py(需要新增一個自己的 dataprocessor)
├── create_finetuning_data.py(小修改設定)
├── create_finetuning_data.sh(config)
├── dataset(轉換成 tf_record格式的資料)
│   ├── IMDB_eval.tf_record
│   ├── IMDB_meta_data
│   └── IMDB_train.tf_record
├── uncased_L-12_H-768_A-12(下載的 pre-trained model)
│   ├── bert_config.json
│   ├── bert_model.ckpt.data
│   └── bert_model.ckpt.index
│   └── vocab.txt
├── imdb_data(imdb 整理好的 .tsv檔 )
│   ├── train.tsv
│   ├── test.tsv
│   └── dev.tsv

一開始我們先在 classifier_data_lib.py 新增自己的 data processor,這邊可以參考其他幾個預設的 processor,主要就是定義一下每個資料的路徑,然後就是你的 sentence 和 label 各在哪個欄位,guid就只是一個 unique的 id。

class ImdbProcessor(DataProcessor):
  """Processor for the IMDB data set."""

  def get_train_examples(self, data_dir):
    """See base class."""
    return self._create_examples(
        self._read_tsv(os.path.join(data_dir, "train.tsv")), "train")

  def get_dev_examples(self, data_dir):
    """See base class."""
    return self._create_examples(
        self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")


  def get_labels(self):
    """See base class."""
    return ["0", "1"]

  @staticmethod
  def get_processor_name():
    """See base class."""
    return "IMDB"

  def _create_examples(self, lines, set_type):
    """Creates examples for the training and dev sets."""
    examples = []
    for (i, line) in enumerate(lines):
      if i == 0:
        continue
      else:
        guid = "%s-%s" % (set_type, i)
        text_a = tokenization.convert_to_unicode(line[2])
        label = tokenization.convert_to_unicode(line[1])
      examples.append(
          InputExample(guid=guid, text_a=text_a, text_b=None, label=label))
    return examples

create_fintuning_data.py 加上剛剛新增的 ImdbProcessor

Line 44 ["COLA", "MNKI", "MRPC", "XNLI"]
Lines 101-106
processor = {
  "cola": classifier_data.lib.ColaProcessor,
  "mnli": classifier_data.lib.MnliProcessor,
  "mrpc": classifier_data.lib.MrpcProcessor,
  "xnli": classifier_data.lib.XnliProcessor,
  "imdb": classifier_data.lib.ImdbProcessor,
} 

然後就可以透過跑 create_fintuning_data.py 把一開始的 tsv 資料,轉換成 tf_record格式,會是以二進位存取,加快整個訓練,在設定檔中只要填上剛剛 data存放的路徑、模型路徑、剛剛創建的任務及輸出檔案路徑。

export IMDB_DIR=./imdb_data
export BERT_BASE_DIR=./uncased_L-12_H-768_A-12
export TASK_NAME=IMDB
export OUTPUT_DIR=./dataset

python3 create_finetuning_data.py \
 --input_data_dir=${IMDB_DIR}/ \
 --vocab_file=${BERT_BASE_DIR}/vocab.txt \
 --train_data_output_path=${OUTPUT_DIR}/${TASK_NAME}_train.tf_record \
 --eval_data_output_path=${OUTPUT_DIR}/${TASK_NAME}_eval.tf_record \
 --meta_data_file_path=${OUTPUT_DIR}/${TASK_NAME}_meta_data \
 --fine_tuning_task_type=classification --max_seq_length=128 \
 --classification_task_name=${TASK_NAME}

最後我們就進入重頭戲,開始 fine tune 我們的 BERT,這邊只是稍微示範訓練了3個 epoch,而 batch_size 只有設定 4,但在訓練時 GPU 的 memory 就會需要超過 31GB (跟友人借了 NVIDIA Tesla V100的環境)

export BERT_BASE_DIR=./uncased_L-12_H-768_A-12
export MODEL_DIR=./model_output
export IMDB_DIR=./dataset
export TASK=IMDB

CUDA_VISIBLE_DEVICES=6 \ # 如果要指定特定 GPU
python run_classifier.py \
  --mode='train_and_eval' \
  --input_meta_data_path=${IMDB_DIR}/${TASK}_meta_data \
  --train_data_path=${IMDB_DIR}/${TASK}_train.tf_record \
  --eval_data_path=${IMDB_DIR}/${TASK}_eval.tf_record \
  --bert_config_file=${BERT_BASE_DIR}/bert_config.json \
  --init_checkpoint=${BERT_BASE_DIR}/bert_model.ckpt \
  --train_batch_size=4 \
  --eval_batch_size=16 \
  --steps_per_loop=1 \
  --learning_rate=2e-5 \
  --num_train_epochs=3 \
  --model_dir=${MODEL_DIR} \
  --strategy_type=mirror # 如果要使用TPU的話這邊要做更改

我們總共拿了 20000筆資料訓練,5000筆驗證,這邊可以看到雖然我們只訓練了3個 epoch,但是在驗證資料集的準確率也有 88%,當然這邊只是最粗淺的拿 raw data 直接丟到 BERT裡面,完全沒有做任何的前處理,之後有興趣的朋友,可以自己先做一些資料前處理,像評論中其實包含了很多 HTML tag、特殊符號,這些都是要先做處理的,還有也可以考慮自己先做斷詞斷句。

{'train_loss': 0.0003554773866198957, 'total_training_steps': 14997, 'last_train_metrics': 1.0, 'eval_metrics': 0.8838232159614563}

小結:

今天只是讓大家快速的了解,怎麼在最短時間執行你的 BERT 訓練,之後有時間也會再細講裡面的每個處理,讓大家對 BERT 的印象不再是只可遠觀。這次的Colab並非我自己寫的,是google所提供!這次跑的都在local端,但還是附上google大神所提供的Colab!有興趣可以拿來玩玩看~

一天一梗圖:

https://ithelp.ithome.com.tw/upload/images/20191004/20119971XP9C555vj0.png
source

Reference

LeeMeng - 進擊的 BERT:NLP 界的巨人之力與遷移學習

Bert_predict_Movie_Revies_Colab


上一篇
[Day-18] LSTM - 股價預測 (Data: 台灣50 )
下一篇
[Day-20] 推薦系統介紹 (Recommendation System)
系列文
Towards Tensorflow 2.030

尚未有邦友留言

立即登入留言