【NLP-NER】如何使用BERT來做命名實體識別
- 2019 年 10 月 11 日
- 筆記
命名實體識別(Named Entity Recognition,NER)是NLP中一項非常基礎的任務。NER是資訊提取、問答系統、句法分析、機器翻譯等眾多NLP任務的重要基礎工具。
上一期我們詳細介紹NER中兩種深度學習模型,LSTM+CRF和Dilated-CNN,本期我們來介紹如何基於BERT來做命名實體識別任務。
作者&編輯 | 小Dream哥
1 引入BERT
筆者在之前的文章中介紹過BERT,想要回顧的同學可以點擊下面的鏈接,這裡就不再介紹BERT的結構了。
鑒於BERT的強大,在下游任務中,引入BERT是很自然的想法。像Google這些資源豐富的大佬,幫我們預訓練好了模型,並且開源出來,當然要好好利用。這裡就介紹下,如何基於Google開源出來的BERT base模型,進行fine tune,做NER任務。
2 獲取BERT預訓練模型
BERT源碼可以從google-research的github中獲取:
https://github.com/google-research/bert
在其GitHub中,也公布了獲取BERT Chinese的預訓練模型,正是我們需要的,鏈接如下:
https://storage.googleapis.com/bert_models/2018_11_03/chinese_L-12_H-768_A-12.zip
對下載的壓縮文件進行解壓,可以看到文件里有五個文件,其中bert_model.ckpt開頭的文件是負責模型變數載入的,而vocab.txt是訓練時中文文本採用的字典,最後bert_config.json是BERT在訓練時,可選調整的一些參數。
BERT的程式碼主要分為兩個部分:
1.預訓練部分,其入口是在run_pretraining.py。
2.Fine-tune部分。Fine-tune的入口針對不同的任務分別在run_classifier.py和run_squad.py。其中run_classifier.py適用的任務為分類任務,如CoLA、MRPC、MultiNLI等。而run_squad.py適用的是閱讀理解任務,如squad2.0和squad1.1。
那麼NER的任務該怎麼辦呢?那就需要自己動手做一些處理了。NER任務與分類任務很接近,基於run_classsifier.py做一些修改,就能夠快速實現我們NER任務的Fine-tune了,下面我們看看,大致需要做哪些修改的工作。
3 修改 processor
任何模型的訓練、預測都是需要有一個明確的輸入,而BERT程式碼中processor就是負責對模型的輸入進行處理。
在run_classsifier.py文件中我們可以看到,Google對於一些公開數據集已經寫了一些processor,如XnliProcessor,MnliProcessor,MrpcProcessor和ColaProcessor。這給我們提供了一個很好的示例,指導我們如何針對自己的數據集來寫processor。
參照上述的Processor,結合NER任務的特點,我們需要定義一個NerProcessor來處理NER標記語料,主要的工作就是將語料組織成Estimator能夠接受的格式。主要就是實現_read_data,_create_example和get_labels三個函數,具體需要組織成什麼樣的形式,可以看看源程式碼。
我們可以實現如下形式的_create_example函數,它讀取語料和標記,並且通過InputExample函數,構造成Estimator能夠接受的格式。
def _create_example(self, lines, set_type): examples = [] for (i, line) in enumerate(lines): guid = "%s-%s" % (set_type, i) text = tokenization.convert_to_unicode(line[1]) label = tokenization.convert_to_unicode(line[0])
examples.append(InputExample(guid=guid, text=text, label=label)) return examples
4 構建模型
首先,我們利用BERT的BertModel類構造BERT結構,然後獲取其最後一層的輸出:
# 使用數據載入BertModel,獲取對應的字embedding
model = modeling.BertModel( config=bert_config, is_training=is_training, input_ids=input_ids, input_mask=input_mask, token_type_ids=segment_ids, use_one_hot_embeddings=use_one_hot_embeddin )
# 獲取對應的BertModel的輸出 embedding = model.get_sequence_output()
然後增加(BiLSTM)CRF層,進行解碼:
max_seq_length = embedding.shape[1].value # 算序列真實長度
used = tf.sign(tf.abs(input_ids)) lengths = tf.reduce_sum(used, reduction_indices=1)
# 添加CRF output layer blstm_crf =
BLSTM_CRF(embedded_chars=embedding,
hidden_unit=lstm_size,
cell_type=cell,
num_layers=num_layers,
dropout_rate=dropout_rate,
initializers=initializers,
num_labels=num_labels,
seq_length=max_seq_length,
labels=labels,
lengths=lengths,
is_training=is_training) rst = blstm_crf.add_blstm_crf_layer(crf_only=True)
5 模型訓練
做了上述的準備工作之後,模型的訓練只需參照run_pretraining.py的main函數即可。主要的工作有:
1. processors初始化
2. estimator配置
3. 載入訓練數據
4. 利用model_fn_builder構造模型,載入模型參數 等。這是Tensorflow中新的架構方法,通過定義model_fn函數,定義模型。然後用Estimator API進行模型的訓練,預測,評估等。
5.調用Estimator進行訓練過程的控制及正式開始訓練等。
總結
利用BERT模型,進行NER任務Fine Tune的大致步驟如上。總的來說,相比於前面的BiLSTM+CRF模型,就是用BERT模型代替了原來的詞嵌入部分,利用BERT來進行語義編碼,BiLSTM+CRF進行解碼。因為需要用BERT,因此在輸入部分做了調整,本文介紹的使用estimator來構建和優化模型,也可以完全棄用這一套,自己構建和優化模型。