標(biāo)簽: BILSTM-CRF
作者: 煉己者
歡迎大家訪問(wèn)我的簡(jiǎn)書以及我的博客
本博客所有內(nèi)容以學(xué)習(xí)、研究和分享為主,如需轉(zhuǎn)載,請(qǐng)聯(lián)系本人,標(biāo)明作者和出處,并且是非商業(yè)用途,謝謝!
基于CRF做命名實(shí)體識(shí)別系列
用CRF做命名實(shí)體識(shí)別(一)
用CRF做命名實(shí)體識(shí)別(二)
用CRF做命名實(shí)體識(shí)別(三)
一. 摘要
- 之前用CRF做了命名實(shí)體識(shí)別,效果還可以,最高達(dá)到0.9293,當(dāng)然這是自己用sklearn寫的計(jì)算F1值,后來(lái)用conlleval.pl對(duì)CRF測(cè)試結(jié)果進(jìn)行評(píng)價(jià),得到的F1值是0.9362。
- 接下來(lái)基于BILSTM-CRF做命名實(shí)體識(shí)別,代碼不是自己寫的,用的github上的一個(gè)大佬寫的,換了自己的數(shù)據(jù)集,得到最終的結(jié)果是0.92。
- 本文主要簡(jiǎn)單的介紹下BILSTM-CRF的原理,以及如何把大佬的數(shù)據(jù)集換成我們自己的數(shù)據(jù)集,進(jìn)行訓(xùn)練。
二. 正文
如果你想細(xì)致地了解BILSTM,那你首先得去看RNN(循環(huán)神經(jīng)網(wǎng)絡(luò)),然后再看RNN的升級(jí)版本LSTM,最好才能過(guò)渡到BILSTM。了解完這些再去看CRF(條件隨機(jī)場(chǎng)),CRF這邊可又是一番天地了,等你了解完你的老板該炒你魷魚了。所以對(duì)于初學(xué)者我一向主張不擇手段先把模型跑下來(lái),跑出結(jié)果,然后才有信心去好好學(xué)習(xí)原理。在這里還是要好好感謝那位大佬。
1. BILSTM-CRF的原理簡(jiǎn)介
如果你不懂什么叫做BILSTM,CRF,沒(méi)關(guān)系,你只要知道他們是命名實(shí)體識(shí)別里兩個(gè)層就行,就像神經(jīng)網(wǎng)絡(luò)里的概念一樣,層次結(jié)構(gòu)。

如上圖,這里面做了一件什么事情呢?
- 輸入是詞向量,這個(gè)直接用word2vec訓(xùn)練就能得到
- 輸出是每個(gè)句子預(yù)測(cè)的標(biāo)簽
流程
詞向量輸入到 BILSTM層 ,然后輸出值是這句話每個(gè)標(biāo)簽的預(yù)測(cè)分?jǐn)?shù),這些分?jǐn)?shù)便是 CEF層 的輸入,其實(shí)沒(méi)有CRF層我們也可以訓(xùn)練 BILSTM,但是我們就不能保證每次預(yù)測(cè)的都是對(duì)的,因?yàn)樗锌赡芎鷣?lái),比如第一個(gè)預(yù)測(cè)的是B-PER,下一個(gè)預(yù)測(cè)的是B-ORG,這就不符合自然語(yǔ)言的規(guī)則了,所以我們加入了CRF這一層,用來(lái)約束這些標(biāo)簽,它可以自動(dòng)地去學(xué)習(xí)這些約束。
那么CRF是怎么學(xué)習(xí)這些約束的呢?
簡(jiǎn)單地說(shuō)就是計(jì)算每個(gè)標(biāo)簽下一個(gè)標(biāo)簽地概率,概率大就有可能出現(xiàn)這樣的標(biāo)簽,概率小就不會(huì)出現(xiàn)了。
2. 他山之石,可以攻玉
1). 保證代碼運(yùn)行正確
Chinese NER
大家點(diǎn)擊去Clone下來(lái)就行
然后就是重點(diǎn)來(lái)了!??!
下載下來(lái)運(yùn)行并不會(huì)那么順利,會(huì)報(bào)錯(cuò)的
首先打開(kāi)main.py文件,如果訓(xùn)練的話就是圖中的兩個(gè)True,如果測(cè)試的話就把圖中的兩個(gè)True改成False
flags = tf.app.flags
flags.DEFINE_boolean("clean", True, "clean train folder")
flags.DEFINE_boolean("train", True, "Wither train the model")
- 錯(cuò)誤1
TypeError: slice indices must be integers or None or have an index method
解決方案:遇到這個(gè)錯(cuò)誤你就去data_utils.py文件里找到下面的代碼,改一下即可
def sort_and_pad(self, data, batch_size):
num_batch = int(math.ceil(len(data) /batch_size))
sorted_data = sorted(data, key=lambda x: len(x[0]))
batch_data = list()
for i in range(num_batch):
batch_data.append(self.pad_data(sorted_data[i*int(batch_size) : (i+1)*int(batch_size)]))
return batch_data
- 錯(cuò)誤2
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa3 in position 0: invalid start byte
解決方案:這個(gè)是編碼問(wèn)題,遇到這個(gè)問(wèn)題你就進(jìn)到utils.py里,找到下面的代碼,加上一句encoding = 'utf-8'就OK了。我印象中是這幾處,如果還報(bào)這個(gè)錯(cuò)誤就繼續(xù)排查類似的即可
def test_ner(results, path):
"""
Run perl script to evaluate model
"""
output_file = os.path.join(path, "ner_predict.utf8")
with open(output_file, "w", encoding='utf-8') as f:
to_write = []
for block in results:
for line in block:
to_write.append(line + "\n")
to_write.append("\n")
f.writelines(to_write)
eval_lines = return_report(output_file)
return eval_lines
def save_config(config, config_file):
"""
Save configuration of the model
parameters are stored in json format
"""
with open(config_file, "w", encoding="utf8") as f:
json.dump(config, f, ensure_ascii=False, indent=4)
def load_config(config_file):
"""
Load configuration of the model
parameters are stored in json format
"""
with open(config_file, encoding="utf8") as f:
return json.load(f)
- 錯(cuò)誤3
NameError: name 'os' is not defined
這個(gè)錯(cuò)誤很奇怪,我是看到作者代碼里有導(dǎo)入os的
解決方案:import os
2). 更換數(shù)據(jù)集
打開(kāi)下載下來(lái)的文件,data文件夾里面有三個(gè)文件,分別為驗(yàn)證,測(cè)試,訓(xùn)練數(shù)據(jù)集,你只需把你的數(shù)據(jù)集切分成這三份即可(比例自己定,我的是7:2:1)。
- 標(biāo)簽必須得是BIO格式,總之你的標(biāo)簽要和它的一模一樣。
- 還有標(biāo)識(shí)符,windows生成的數(shù)據(jù)集文件我們發(fā)現(xiàn)換行符都是\r\n,也就是在notpad++上打開(kāi)的話,顯示所有標(biāo)識(shí)符后會(huì)發(fā)現(xiàn)CRLF,我們要把它改成LF。
可以用替換的方法,直接把\r\n替換成\n,這樣就滿足條件了
3). 訓(xùn)練
這些操作之后你就可以運(yùn)行main.py了
三. 總結(jié)與展望
最近一直在努力地理解這些個(gè)原理,爭(zhēng)取早日攻克它們。大家工作的話一般項(xiàng)目會(huì)比較緊急,沒(méi)有時(shí)間給你慢慢理解原理,然后再去寫代碼做項(xiàng)目。所以要學(xué)會(huì)用別人的代碼,改造它們,讓它為自己所用。最后很感謝github的那位大佬,真的很厲害。希望這篇博客能幫到大家,謝謝各位
以下是我所有文章的目錄,大家如果感興趣,也可以前往查看
??戳右邊:打開(kāi)它,也許會(huì)看到很多對(duì)你有幫助的文章