基於 CRF 的中文命名實體識別模型實現

2021-03-02 Python實驗中心

命名實體識別在越來越多的場景下被應用,如自動問答、知識圖譜等。非結構化的文本內容有很多豐富的信息,但找到相關的知識始終是一個具有挑戰性的任務,命名實體識別也不例外。

前面我們用隱馬爾可夫模型(HMM)自己嘗試訓練過一個分詞器,其實 HMM 也可以用來訓練命名實體識別器,但在本文,我們講另外一個算法——條件隨機場(CRF),來訓練一個命名實體識別器。

淺析條件隨機場(CRF)

條件隨機場(Conditional Random Fields,簡稱 CRF)是給定一組輸入序列條件下另一組輸出序列的條件概率分布模型,在自然語言處理中得到了廣泛應用。

首先,我們來看看什麼是隨機場。「隨機場」的名字取的很玄乎,其實理解起來不難。隨機場是由若干個位置組成的整體,當按照某種分布給每一個位置隨機賦予一個值之後,其全體就叫做隨機場。

還是舉詞性標註的例子。假如我們有一個十個詞形成的句子需要做詞性標註。這十個詞每個詞的詞性可以在我們已知的詞性集合(名詞,動詞……)中去選擇。當我們為每個詞選擇完詞性後,這就形成了一個隨機場。

了解了隨機場,我們再來看看馬爾科夫隨機場。馬爾科夫隨機場是隨機場的特例,它假設隨機場中某一個位置的賦值僅僅與和它相鄰的位置的賦值有關,和與其不相鄰的位置的賦值無關。

繼續舉十個詞的句子詞性標註的例子。如果我們假設所有詞的詞性只和它相鄰的詞的詞性有關時,這個隨機場就特化成一個馬爾科夫隨機場。比如第三個詞的詞性除了與自己本身的位置有關外,還只與第二個詞和第四個詞的詞性有關。

理解了馬爾科夫隨機場,再理解 CRF 就容易了。CRF 是馬爾科夫隨機場的特例,它假設馬爾科夫隨機場中只有 X 和 Y 兩種變量,X 一般是給定的,而 Y 一般是在給定 X 的條件下我們的輸出。這樣馬爾科夫隨機場就特化成了條件隨機場。

在我們十個詞的句子詞性標註的例子中,X 是詞,Y 是詞性。因此,如果我們假設它是一個馬爾科夫隨機場,那麼它也就是一個 CRF。

對於 CRF,我們給出準確的數學語言描述:設 X 與 Y 是隨機變量,P(Y|X) 是給定 X 時 Y 的條件概率分布,若隨機變量 Y 構成的是一個馬爾科夫隨機場,則稱條件概率分布 P(Y|X) 是條件隨機場。

基於 CRF 的中文命名實體識別模型實現

在常規的命名實體識別中,通用場景下最常提取的是時間、人物、地點及組織機構名,因此本模型也將提取以上四種實體。

1.開發環境。

本次開發所選用的環境為:

Sklearn_crfsuite

Python 3.6

Jupyter Notebook

2.數據預處理。

本模型使用人民日報1998年標註數據,進行預處理。語料庫詞性標記中,對應的實體詞依次為 t、nr、ns、nt。對語料需要做以下處理:

將語料全形字符統一轉為半角;

合併語料庫分開標註的姓和名,例如:溫/nr 家寶/nr;

合併語料庫中括號中的大粒度詞,例如:[國家/n 環保局/n]nt;

合併語料庫分開標註的時間,例如:(/w 一九九七年/t 十二月/t 三十一日/t )/w。

首先引入需要用到的庫:

   import re    import sklearn_crfsuite    from sklearn_crfsuite import metrics    from sklearn.externals import joblib

數據預處理,定義 CorpusProcess 類,我們還是先給出類實現框架:

class CorpusProcess(object):    def __init__(self):        """初始化"""        pass    def read_corpus_from_file(self, file_path):        """讀取語料"""        pass    def write_corpus_to_file(self, data, file_path):        """寫語料"""        pass    def q_to_b(self,q_str):        """全形轉半角"""        pass    def b_to_q(self,b_str):        """半角轉全形"""        pass    def pre_process(self):        """語料預處理 """        pass    def process_k(self, words):        """處理大粒度分詞,合併語料庫中括號中的大粒度分詞,類似:[國家/n  環保局/n]nt """        pass    def process_nr(self, words):        """ 處理姓名,合併語料庫分開標註的姓和名,類似:溫/nr  家寶/nr"""        pass    def process_t(self, words):        """處理時間,合併語料庫分開標註的時間詞,類似: (/w  一九九七年/t  十二月/t  三十一日/t  )/w   """        pass    def pos_to_tag(self, p):        """由詞性提取標籤"""        pass    def tag_perform(self, tag, index):        """標籤使用BIO模式"""        pass    def pos_perform(self, pos):        """去除詞性攜帶的標籤先驗知識"""        pass    def initialize(self):        """初始化 """        pass    def init_sequence(self, words_list):        """初始化字序列、詞性序列、標記序列 """        pass    def extract_feature(self, word_grams):        """特徵選取"""        pass    def segment_by_window(self, words_list=None, window=3):        """窗口切分"""        pass    def generator(self):        """訓練數據"""        pass

由於整個代碼實現過程較長,我這裡給出重點步驟,最後會在 Github 上連同語料代碼一同給出,下面是關鍵過程實現。

對語料中的句子、詞性,實體分類標記進行區分。標籤採用「BIO」體系,即實體的第一個字為 B_*,其餘字為 I_*,非實體字統一標記為 O。大部分情況下,標籤體系越複雜,準確度也越高,但這裡採用簡單的 BIO 體系也能達到相當不錯的效果。這裡模型採用 tri-gram 形式,所以在字符列中,要在句子前後加上佔位符。

def init_sequence(self, words_list):            """初始化字序列、詞性序列、標記序列 """            words_seq = [[word.split(u'/')[0] for word in words] for words in words_list]            pos_seq = [[word.split(u'/')[1] for word in words] for words in words_list]            tag_seq = [[self.pos_to_tag(p) for p in pos] for pos in pos_seq]            self.pos_seq = [[[pos_seq[index][i] for _ in range(len(words_seq[index][i]))]                            for i in range(len(pos_seq[index]))] for index in range(len(pos_seq))]            self.tag_seq = [[[self.tag_perform(tag_seq[index][i], w) for w in range(len(words_seq[index][i]))]                            for i in range(len(tag_seq[index]))] for index in range(len(tag_seq))]            self.pos_seq = [[u'un']+[self.pos_perform(p) for pos in pos_seq for p in pos]+[u'un'] for pos_seq in self.pos_seq]            self.tag_seq = [[t for tag in tag_seq for t in tag] for tag_seq in self.tag_seq]            self.word_seq = [[u'<BOS>']+[w for word in word_seq for w in word]+[u'<EOS>'] for word_seq in words_seq]

處理好語料之後,緊接著進行模型定義和訓練,定義 CRF_NER 類,我們還是採用先給出類實現框架,再具體講解其實現:

   class CRF_NER(object):        def __init__(self):            """初始化參數"""            pass        def initialize_model(self):            """初始化"""            pass        def train(self):            """訓練"""            pass        def predict(self, sentence):            """預測"""            pass        def load_model(self):            """加載模型 """            pass        def save_model(self):            """保存模型"""            pass

在 CRF_NER 類中,分別完成了語料預處理和模型訓練、保存、預測功能,具體實現如下。

第一步,init 函數實現了模型參數定義和 CorpusProcess 的實例化和語料預處理:

   def __init__(self):            """初始化參數"""            self.algorithm = "lbfgs"            self.c1 ="0.1"            self.c2 = "0.1"            self.max_iterations = 100            self.model_path = dir + "model.pkl"            self.corpus = CorpusProcess()              self.corpus.pre_process()              self.corpus.initialize()              self.model = None

第二步,給出模型定義,了解 sklearn_crfsuite.CRF 詳情可查該文檔。

   def initialize_model(self):            """初始化"""            algorithm = self.algorithm            c1 = float(self.c1)            c2 = float(self.c2)            max_iterations = int(self.max_iterations)            self.model = sklearn_crfsuite.CRF(algorithm=algorithm, c1=c1, c2=c2,                                              max_iterations=max_iterations, all_possible_transitions=True)

第三步,模型訓練和保存,分為訓練集和測試集:

   def train(self):            """訓練"""            self.initialize_model()            x, y = self.corpus.generator()            x_train, y_train = x[500:], y[500:]            x_test, y_test = x[:500], y[:500]            self.model.fit(x_train, y_train)            labels = list(self.model.classes_)            labels.remove('O')            y_predict = self.model.predict(x_test)            metrics.flat_f1_score(y_test, y_predict, average='weighted', labels=labels)            sorted_labels = sorted(labels, key=lambda name: (name[1:], name[0]))            print(metrics.flat_classification_report(y_test, y_predict, labels=sorted_labels, digits=3))            self.save_model()

第四至第六步中 predict、load_model、save_model 方法的實現,大家可以在文末給出的地址中查看源碼,這裡就不堆代碼了。

最後,我們來看看模型訓練和預測的過程和結果:

   ner = CRF_NER()    model = ner.train()

經過模型訓練,得到的準確率和召回率如下:

進行模型預測,其結果還不錯,如下:

基於 CRF 的中文命名實體識別模型實現先講到這兒,項目源碼和涉及到的語料,大家可以到:Github 上查看。

總結

本文淺析了條件隨機場,並使用 sklearn_crfsuite.CRF 模型,對人民日報1998年標註數據進行了模型訓練和預測,以幫助大家加強對條件隨機場的理解。

參考資料及推薦閱讀

條件隨機場(CRF)

條件隨機場CRF(一)從隨機場到線性鏈條件隨機場

命名實體:基於 CRF 的中文命名實體識別模型

條件隨機場(CRF)理論及應用

相關焦點

  • 使用CRF++實現命名實體識別(NER)
    X和Y有相同的圖結構的線性鏈條件隨機場  命名實體識別(Named Entity Recognition,簡稱NER)是信息提取、問答系統、句法分析、機器翻譯等應用領域的重要基礎工具,在自然語言處理技術走向實用化的過程中佔有重要地位。一般來說,命名實體識別的任務就是識別出待處理文本中三大類(實體類、時間類和數字類)、七小類(人名、機構名、地名、時間、日期、貨幣和百分比)命名實體。
  • NLP入門(八)使用CRF++實現命名實體識別(NER)
    X和Y有相同的圖結構的線性鏈條件隨機場  命名實體識別(Named Entity Recognition,簡稱NER)是信息提取、問答系統、句法分析、機器翻譯等應用領域的重要基礎工具,在自然語言處理技術走向實用化的過程中佔有重要地位。一般來說,命名實體識別的任務就是識別出待處理文本中三大類(實體類、時間類和數字類)、七小類(人名、機構名、地名、時間、日期、貨幣和百分比)命名實體。
  • BiLSTM-CRF實現命名實體識別(NER)
    BiLSTM-CRF實現說明3. 實驗環境說明4.代碼實現4.1 相關包及配置4.2 加載數據4.3 搭建模型4.4 模型訓練&保存模型4.5 測試4.6 預測4.7 待改進/完善完整代碼地址參考本博客中使用到的完整代碼請移步至我的github:https:/
  • 阿里AAAI2018論文解讀:輕量網絡訓練框架、GAN中文命名實體識別、英俄翻譯等
    今天由阿里巴巴的研究員們為大家介紹6篇,包括:火箭發射:一種有效的輕量網絡訓練框架、基於對抗學習的眾包標註用於中文命名實體識別、句法敏感的實體表示用於神經網絡關係抽取、一種基於詞尾預測的提高英俄翻譯質量的方法、一種利用用戶搜索日誌進行多任務學習的商品標題壓縮方法和 τ-FPL: 線性時間的約束容忍分類學習算法。1.
  • 從零開始學自然語言處理(十五)— 一個簡單的中文NLP工具包——foolnltk
  • MindSpore基於BERT實現中文新聞分類實戰
    關於BERT,本大獅有幸嘗試過基於TensorFlow的實現--【手模手學ModelArts】分分鐘部署一個Bert命名實體識別在線服務,並嘗試以該服務為原型「落地AI」--【Copy攻城獅日誌】ModelArts與AppCube雙「魔」合璧慶雙節,從0到1實現了一個簡單的命名實體識別應用。這次,我們將基於MIndSpore實現中文新聞分類實戰。
  • Keras入門(七)使用Flask+Keras-bert構建模型預測服務
    在文章NLP(三十四)使用keras-bert實現序列標註任務中,我們介紹了如何使用keras-bert模塊,利用BERT中文預訓練模型來實現序列標註任務的模型訓練、模型評估和模型預測。其中,模型預測是通過加載生成的h5文件來實現的。  本文將會介紹如何使用Flask構建模型預測的HTTP服務。
  • NLP(三十四)使用keras-bert實現序列標註任務
    loss=crf_loss,            metrics=[crf_accuracy]        )        return model模型為BERT+BiLSTM+CRF,其中對BERT進行微調,模型結構(以example數據集為例)如下:_____________________________________
  • 中文任務全面超越BERT:百度正式發布NLP預訓練模型ERNIE
    ),並發布了基於 PaddlePaddle 的開原始碼與模型,在語言推斷、語義相似度、命名實體識別、情感分析、問答匹配等自然語言處理(NLP)各類中文任務上的驗證顯示,模型效果全面超越 BERT。設想如果能夠讓模型學習到海量文本中蘊含的潛在知識,勢必會進一步提升各個 NLP 任務效果。因此百度提出了基於知識增強的 ERNIE 模型。ERNIE 模型通過建模海量數據中的實體概念等先驗語義知識,學習真實世界的語義關係。具體來說,ERNIE 模型通過對詞、實體等語義單元的掩碼,使得模型學習完整概念的語義表示。
  • 中文預訓練模型ERNIE超詳細使用指南
    2、ERNIE源碼淺嘗Okay,當我們了解了ERNIE模型的大體框架及原理之後,接下來就可以深入理解一下具體的實現啦。模型預訓練的輸入是基於百科類、資訊類、論壇對話類數據構造具有上下文關係的句子對數據,利用百度內部詞法分析工具對句對數據進行字、詞、實體等不同粒度的切分,然後基於 tokenization.py 中的 CharTokenizer 對切分後的數據進行 token 化處理,得到明文的 token 序列及切分邊界,然後將明文數據根據詞典config/vocab.txt 映射為
  • 中文NLP熱點|AMBERT模型在CLUE等數據集上獲卓越表現
    它包含八個不同的任務,包括單句分類、句子對分類和機器閱讀理解,團隊評估了CLUE現有的一些全網絡的中文預訓練模型,還包括一個小的手工製作的診斷測試集,使用不同的模型去探索特定的語言現象(其中一些是中國特有的)。項目還提供一個大型的乾淨原始的原始文本語料庫,可用於模型預訓練,在Github上發布的CLUE、基線、預訓練數據集可以為大家提供一個可以訓練中文模型的語言數據集。
  • 中文最佳,哈工大訊飛聯合發布全詞覆蓋中文BERT預訓練模型
    而在中文領域,哈工大訊飛聯合實驗室也於昨日發布了基於全詞覆蓋的中文 BERT 預訓練模型,在多個中文數據集上取得了當前中文預訓練模型的最佳水平,效果甚至超過了原版 BERT、ERINE 等中文預訓練模型。基於 Transformers 的雙向編碼表示(BERT)在多個自然語言處理任務中取得了廣泛的性能提升。
  • 模板識別:使用OpenCV實現基於特徵的圖像對齊
    我們將使用的技術通常被稱為「基於特徵圖像對齊」,因為在該技術中,在一個圖像中檢測稀疏的特徵集並且在另一圖像中進行特徵匹配。然後基於這些匹配特徵將原圖像映射到另一個圖像,實現圖像對齊。計算機視覺的許多應用中,我們分兩步解決識別問題a)定位;2)識別。例如,為了實現面部識別系統,我們首先需要一個面部檢測器,其輸出面部所在矩形的坐標。檢測器不知道或不關心該人是誰。唯一的工作就是找到一張臉。系統的第二部分是識別算法。原始圖像被裁剪為檢測到的面部矩形,並且該裁剪的圖像反饋送到最終識別該人的面部識別算法。特徵檢測器的定位器就像面部檢測器。描述子類似識別器。
  • 「數據架構」實體關係模型溯源
    基本的ER模型由實體類型(對感興趣的事物進行分類)和指定實體之間可能存在的關係(那些實體類型的實例)組成。在軟體工程中,為了執行業務流程,ER模型通常用於表示業務需要記住的內容。因此,ER模型變成了一個抽象的數據模型,它定義了一個可以在資料庫(通常是關係資料庫)中實現的數據或信息結構。
  • 數學推導+純Python實現機器學習算法23:CRF條件隨機場
    另外在早期深度學習語義分割模型中,CRF也被作為的一種後處理技術來優化神經網絡的分割結果。概率無向圖    概率圖模型是一種用圖來表示概率分布的模型。基於最大團,概率無向圖模型的聯合概率分布線性CRF的三個問題    線性CRF需要解決三個核心問題,包括基於前向-後向的概率估計算法、基於極大似然和牛頓優化的學習算法以及基於維特比算法的預測算法。
  • 論文淺嘗 | 基於知識圖譜嵌入的 Bootstrapping 實體對齊方法
    (後文全部簡稱為知識嵌入)的實體對齊工作,針對知識嵌入訓練數據有限這一情況,作者提出一種 bootstrapping 策略,迭代標註出可能的實體對齊,生成新數據加入知識嵌入模型的訓練中。但是,當模型生產了錯誤的實體對齊時,這種錯誤將會隨著迭代次數的增加而累積的越來越多。為了控制錯誤累積,作者設計了一種對齊樣本編輯方法,對每次迭代生成的對齊數據加以約束。 動機目前面向知識庫的實體對齊研究中,基於知識嵌入的方法取得了比傳統策略更好的實驗效果。但是對於知識嵌入的實體對齊,仍然存在著一些挑戰。
  • 強烈推薦| 飛槳十大中文NLP開源工具詳解
    PaddleNLP是基於飛槳(PaddlePaddle)開發的工業級中文NLP開源工具與預訓練模型集,將自然語言處理領域的多種模型用一套共享骨架代碼實現
  • 百度飛槳中文NLP開源工具集:面向工業應用,支持六大任務
    PaddleNLP 是基於飛槳(PaddlePaddle)開發的工業級中文 NLP 開源工具與預訓練模型集,將自然語言處理領域的多種模型用一套共享骨架代碼實現
  • tensorflow(8)將h5文件轉化為pb文件並利用tensorflow/serving實現模型部署
    在文章NLP(三十四)使用keras-bert實現序列標註任務中,我們使用Keras和Keras-bert進行模型訓練、模型評估和模型預測。我們對人民日報實體數據集進行模型訓練,保存後的模型文件為example.h5,h5是Keras保存模型的一種文件格式。
  • CLUECorpus2020:可能是史上最大的開源中文語料庫以及高質量中文預訓練模型集合
    可以用於語言模型和模型預訓練、文本生成、詞嵌入模型等多種任務;為了便於預訓練等任務的使用,現已處理成了預訓練的格式、多個小文件以及統一命名,並做了數據集拆分;另外我們對詞表進行了精簡,使其更加適用於中文的處理以及提高訓練和推理速度;我們在此基礎上預訓練了多個高質量模型,這些模型也開放下載使用。