使用Bert預訓練模型文字分類(內附原始碼)

THU数据派發表於2019-03-13

本文從實踐入手,帶領大家進行Bert的中文文字分類和作為句子向量進行使用的教程。

Bert介紹

Bert模型是Google在2018年10月釋出的語言表示模型,Bert在NLP領域橫掃了11項任務的最優結果,可以說是現今最近NLP中最重要的突破。Bert模型的全稱是Bidirectional Encoder Representations from Transformers,是透過訓練Masked Language Model和預測下一句任務得到的模型。關於Bert具體訓練的細節和更多的原理,有興趣的讀者可以去看在[arXiv](https://arxiv.org/abs/1810.04805)上的原文。本篇文章從實踐入手,帶領大家進行Bert的中文文字分類和作為句子向量進行使用的教程。

使用Bert預訓練模型文字分類(內附原始碼)

對於文字分類任務,一個句子中的N個字元對應了E_1,…,E_N,這N個embedding。文字分類實際上是將BERT得到的T_1這一層連線上一個全連線層進行多分類。

準備工作

1. 下載bert

在命令列中輸入

git clone

https://github.com/google-research/bert.git

2. 下載bert預訓練模型

Google提供了多種預訓練好的bert模型,有針對不同語言的和不同模型大小的。對於中文模型,我們使用[Bert-Base, Chinese](https://storage.googleapis.com/bert_models/2018_11_03/chinese_L-12_H-768_A-12.zip)。為了下載該模型,可能需要使用梯子。如果需要下載其他的模型(英文以及其他語言),可以在[Bert](https://github.com/google-research/bert)裡的Pre-trained models找到下載連結。

3.(可選項)

安裝bert-as-service,這是一個可以利用bert模型將句子對映到固定長度向量的服務。

在命令列中輸入

pip install bert-serving-server # server

pip install bert-serving-client # client, independent of 'bert-serving-server'

該服務要求tensorflow的最低版本為1.10。

準備資料

資料格式

作為中文文字分類問題,需要先將資料集整理成可用的形式。不同的格式對應了不同的DataProcessor類。可以將資料儲存成如下格式:

game APEX是個新出的吃雞遊戲。

technology Google將要推出tensorflow2.0。

一行代表一個文字,由標籤加上一個tab加上正文組成。

文字分割為三個檔案,train.tsv(訓練集),dev.tsv(驗證集),test.tsv(測試集);然後放置在同一個data_dir資料夾下。

編寫DataProcessor類

在bert資料夾下的“run_classifier.py**中的”def main(_):”函式中將processors的內容增加為

python

processors = {

"cola": ColaProcessor,

"mnli": MnliProcessor,

"mrpc": MrpcProcessor,

"xnli": XnliProcessor,

"mytask": MyTaskProcessor,

}

實現如下的“MyTaskProcessor

(DataProcessor)”類,並將這一段程式碼放置在“run_classifier.py”和其他Processor並列的位置。

“\_\_init\_\_(self)”中的self.labels含有所有的分類label,在這個例子中我們將文字可能分為3類:game, fashion, houseliving。

python

class MyTaskProcessor(DataProcessor):

"""Processor for the News data set (GLUE version)."""

def __init__(self):

self.labels = ['game', 'fashion', 'houseliving']

def get_train_examples(self, data_dir):

return self._create_examples(

self._read_tsv(os.path.join(data_dir, "train.tsv")), "train")

def get_dev_examples(self, data_dir):

return self._create_examples(

self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev")

def get_test_examples(self, data_dir):

return self._create_examples(

self._read_tsv(os.path.join(data_dir, "test.tsv")), "test")

def get_labels(self):

return self.labels

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])

examples.append(

InputExample(guid=guid, text_a=text_a, text_b=None, label=label))

return examples

如果資料格式並不是一個label,一個tab,一段文字;則需要更改“_create_examples()”的實現。

編寫執行指令碼

新建一個執行指令碼檔名為“run.sh”,將檔案內容編輯為:

bash

export DATA_DIR=/media/ganjinzero/Code/bert/data/

export BERT_BASE_DIR=/media/ganjinzero/Code/bert/chinese_L-12_H-768_A-12

python run_classifier.py \

--task_name=mytask \

--do_train=true \

--do_eval=true \

--data_dir=$DATA_DIR/ \

--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=2e-5 \

--num_train_epochs=3.0 \

--output_dir=/mytask_output

其中DATA_DIR是你的要訓練的文字的資料所在的資料夾,BERT_BASE_DIR是你的bert預訓練模型存放的地址。task_name要求和你的DataProcessor類中的名稱一致。下面的幾個引數,do_train代表是否進行fine tune,do_eval代表是否進行evaluation,還有未出現的引數do_predict代表是否進行預測。如果不需要進行fine tune,或者顯示卡配置太低的話,可以將do_trian去掉。max_seq_length代表了句子的最長長度,當視訊記憶體不足時,可以適當降低max_seq_length。

進行預測

執行指令碼

bash

./run.sh

可以得到類似如下樣式的結果

***** Eval results *****

eval_accuracy = 0.845588

eval_loss = 0.505248

global_step = 343

loss = 0.505248

如果出現了這樣的輸出,就是執行成功了。在“run.sh”裡指定的output_dir資料夾下可以看到模型的evaluation結果和fine-tune(微調)之後的模型檔案。

以句子向量的形式使用Bert

如果想要將bert模型的編碼和其他模型一起使用,將bert模型作為句子向量使用很有意義(也就是所謂的句子級別的編碼)。我們可以使用bert-as-service來完成這個目標。

安裝完bert-as-service以後,就可以利用bert模型將句子對映到固定長度的向量上。在終端中用一下命令啟動服務:

bash

bert-serving-start -model_dir /media/ganjinzero/Code/bert/chinese_L-12_H-768_A-12 -num_worker=4

model_dir後面的引數是bert預訓練模型所在的資料夾。num_worker的數量應該取決於你的CPU/GPU數量。

這時就可以在Python中呼叫如下的命令:

python

from bert_serving.client import BertClient

bc = BertClient()

bc.encode(['一二三四五六七八', '今天您吃了嗎?'])

最好以列表的形式,而非單個字串傳給”bc.encode()”引數,這樣程式執行的效率較高。

參考文件

[Github:bert]

(https://github.com/google-research/bert)

[arXiv:bert](https://arxiv.org/pdf/1810.04805.pdf)

[Github:bert-as-service](https://github.com/hanxiao/bert-as-service)

【作者簡介】

GjZero,清華大學統計中心博士二年級在讀。研究方向是醫學資訊學中的自然語言處理。興趣是撲克、麻將等和博弈論有關的運動。

github:

https://github.com/GanjinZero

個人主頁:

https://ganjinzero.github.io/

THU資料派
THU資料派

THU資料派"基於清華,放眼世界",以紮實的理工功底闖蕩“資料江湖”。釋出全球大資料資訊,定期組織線下活動,分享前沿產業動態。瞭解清華大資料,敬請關注姐妹號“資料派THU”。

相關文章