中文語料的 Bert finetune

穀粒先生發表於2019-02-23

Finetune Bert for Chinese

NLP 問題被證明同影象一樣,可以通過 finetune 在垂直領域取得效果的提升。Bert 模型本身極其依賴計算資源,從 0 訓練對大多數開發者都是難以想象的事。在節省資源避免重頭開始訓練的同時,為更好的擬合垂直領域的語料,我們有了 finetune 的動機。

Bert 的文件本身對 finetune 進行了較為詳細的描述,但對於不熟悉官方標準資料集的工程師來說,有一定的上手難度。隨著 Bert as service 程式碼的開源,使用 Bert 分類或閱讀理解的副產物--詞空間,成為一個更具實用價值的方向。

因而,此文件著重以一個例子,梳理 finetune 垂直語料,獲得微調後的模型 這一過程。Bert 原理或 Bert as service 還請移步官方文件。

依賴

python==3.6
tensorflow>=1.11.0
複製程式碼

預訓練模型

  • 下載 BERT-Base, Chinese: Chinese Simplified and Traditional, 12-layer, 768-hidden, 12-heads, 110M parameters

資料準備

  • train.tsv 訓練集
  • dev.tsv 驗證集

資料格式

第一列為 label,第二列為具體內容,tab 分隔。因模型本身在字元級別做處理,因而無需分詞。

fashion	襯衫和它一起穿,讓你減齡十歲!越活越年輕!太美了!...
houseliving	95㎡簡約美式小三居,過精美別緻、悠然自得的小日子! 屋主的客...
game	賽季末用他們兩天上一段,7.20最強LOL上分英雄推薦! 各位小夥...
複製程式碼

樣例資料位置:data

資料格式取決於業務場景,後面也可根據格式調整程式碼裡的資料匯入方式。

操作

git clone https://github.com/google-research/bert.git
cd bert
複製程式碼

bert 的 finetune 主要存在兩類應用場景:分類和閱讀理解。因分類較為容易獲得樣本,以下以分類為例,做模型微調:

修改 run_classifier.py

自定義 DataProcessor

class DemoProcessor(DataProcessor):
    """Processor for Demo data set."""

    def __init__(self):
        self.labels = 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_test_examples(self, data_dir):
      """See base class."""
      return self._create_examples(
          self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")

    def get_labels(self):
        """See base class."""
        # return list(self.labels)
        return ["fashion", "houseliving","game"] # 根據 label 自定義


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

複製程式碼

新增 DemoProcessor

  processors = {
      "cola": ColaProcessor,
      "mnli": MnliProcessor,
      "mrpc": MrpcProcessor,
      "xnli": XnliProcessor,
      "demo": DemoProcessor,
  }
複製程式碼

啟動訓練

export BERT_Chinese_DIR=/path/to/bert/chinese_L-12_H-768_A-12
export Demo_DIR=/path/to/DemoDate

python run_classifier.py \
  --task_name=demo \
  --do_train=true \
  --do_eval=true \
  --data_dir=$Demo_DIR \
  --vocab_file=$BERT_Chinese_DIR/vocab.txt \
  --bert_config_file=$BERT_Chinese_DIR/bert_config.json \
  --init_checkpoint=$BERT_Chinese_DIR/bert_model.ckpt \
  --max_seq_length=128 \
  --train_batch_size=32 \
  --learning_rate=2e-5 \
  --num_train_epochs=3.0 \
  --output_dir=/tmp/Demo_output/
複製程式碼

若一切順利,將會有以下輸出:

***** Eval results *****
  eval_accuracy = xx
  eval_loss = xx
  global_step = xx
  loss = xx
複製程式碼

最終,微調後的模型儲存在output_dir指向的資料夾中。

總結

Bert 預訓練後的 finetune,是一種很高效的方式,節省時間,同時提高模型在垂直語料的表現。finetune 過程,實際上不難。較大的難點在於資料準備和 pipeline 的設計。從商業角度講,應著重考慮 finetune 之後,模型有效性的證明,以及在業務場景中的應用。如果評估指標和業務場景都已縷清,那麼不妨一試。

參考資料

相關文章