太強了!10行模型代碼帶你完成Bi-LSTM+CRF的NLP任務!

2021-03-02 數據科學雜談

俗話說的好,NER該怎麼做?雙向LSTM+CRF啊。這LSTM聽說比一般的RNN牛逼,那這雙向的LSTM豈不是更牛逼了?(BERT心想:渣渣)

不管是實際業務需要,還是參加一些NLP比賽,亦或是參加面試,都有可能用到NER,那雙向LSTM+CRF簡直就是NER界的標配。今天我們就手把手教大家如何用Keras優雅的搭建Bi-LSTM+CRF模型。

我們假設大家已經有了可供訓練的數據(文末提供數據)。其數據格式應該為這樣:

這裡我們以字為單元進行標註。「O」是other的縮寫,表示非實體詞。「B」表示「開頭」,即實體詞的開頭字符,「I」表示「中間」,實體詞的中間字符。我們的數據樣例裡面是使用的是「BIO」標籤,沒有「E」,「E」表示的是實體詞的結尾。但是在絕大多數情況下,沒有「E」問題也不大,畢竟很難找出混淆實體的例子。

關於命名實體識別(NER)任務和Bi-LSTM還有CRF,我們在之前的文章中寫過:

從零開始學自然語言處理(六)—— 命名實體識別

從零開始學自然語言處理(22)—— 效果震撼的Bi-LSTM

從零開始學自然語言處理(23)—— 巧妙的條件隨機場(CRF)(上)

從零開始學自然語言處理(24)—— 巧妙的條件隨機場(CRF)(下)

我們引入我們需要的python包:

from keras.models import Modelfrom keras.layers import Embedding, Bidirectional, LSTM, Dense, Dropout, Inputfrom keras_contrib.layers import CRFfrom keras.preprocessing.sequence import pad_sequencesfrom keras.utils import np_utils

keras_contrib.layers.CRF是某個大神封裝在keras的CRF包,keras可以直接調用。

構建模型。

class bi_lstm_crf():    def __init__(self,                 vocab_size,                 n_class,                 embedding_dim=128,                 rnn_units=128,                 drop_rate=0.3,                 ):        self.vocab_size = vocab_size   #詞彙量        self.n_class = n_class         #NER label種類數        self.embedding_dim = embedding_dim #embedding層維度        self.rnn_units = rnn_units      #lstm單元維度        self.drop_rate = drop_rate
def creat_model(self): inputs = Input(shape=(None,)) embedding = Embedding(input_dim=self.vocab_size, output_dim=self.embedding_dim)(inputs) x = Bidirectional(LSTM(units=self.rnn_units, return_sequences=True))(embedding) #雙向lstm對輸入進行編碼 x = Dropout(self.drop_rate)(x) x = Dense(self.n_class)(x) crf = CRF(self.n_class, sparse_target=False) x = crf(x) model = Model(inputs=inputs, outputs=x) model.compile('adam', loss=crf.loss_function, metrics=[crf.accuracy]) return model

是不是很簡單,模型的代碼量其實只有不到10行。首先將文本進行id化,然後輸入到embedding層取出對應的詞向量,然後經過雙向LSTM編碼,再經過一層Dense(其實可有可無)的線性變換,最後經過CRF層,即可。

數據處理的代碼稍微複雜一點。我們第一步要做的就是構建詞典,即給語料中的每一個詞一個唯一的id。同時,我們也需要對label(即那些B、I、O)進行id化處理。具體代碼如下:

from collections import Counterdef get_dict(min_num = 5):    paths = [        'data/example.train',        'data/example.dev',        'data/example.test'    ]
label_dict = [] word_dict = [] for path in paths: with open(path) as f: for line in f: p = line.split() if len(p) == 1: word_dict.append(p[0]) elif len(p) == 2: word_dict.append(p[0]) label_dict.append(p[1])
label_dict = Counter(label_dict) word_dict = dict(Counter(word_dict)) label2id = {key: index for index, key in enumerate(label_dict)} id2label = {v: k for k, v in label2id.items()} word_dict = {v:k for k,v in dict(word_dict).items() if word_dict.get(k)>min_num } word2id = {key: index+2 for index, key in enumerate(word_dict)} word2id['PAD'] = 0 word2id['UNK'] = 1 id2word = {v: k for k, v in word2id.items()} return word2id, id2word, label2id, id2label
word2id, id2word, label2id, id2label = get_dict()

再寫一個生成訓練數據的函數:

def get_data(path, train=True):    X, Y = [], []    x, y = [], []    with open(path) as f:        for line in f:            if line == '\n':                X.append(x)                Y.append(y)                x = []                y = []                continue            p = line.split()            x.append(word2id.get(p[0], 1))            y.append(label2id.get(p[1]))        if len(x)>0:            X.append(x)            Y.append(y)
return X, Y

訓練數據X,Y以及驗證數據val_x,val_y,對其進行補零和截斷操作。同時,將label進行to_categorical操作,轉化為one-hot編碼。

X, Y = get_data('data/example.train')val_x, val_y = get_data('data/example.dev')X, Y  = pad_sequences(X, maxlen=200), pad_sequences(Y, maxlen=200)val_x, val_y = pad_sequences(val_x, maxlen=200), pad_sequences(val_y, maxlen=200)Y =np_utils.to_categorical(Y)val_y =np_utils.to_categorical(val_y)

訓練模型:

lstm_crf = bi_lstm_crf(vocab_size=len(word2id), n_class=len(label2id))model = lstm_crf.creat_model()model.fit(X, Y, batch_size=64, epochs=2,              validation_data=[val_x, val_y])

簡單訓練幾輪就可以達到不錯的效果。

歡迎關注公眾號「數據科學雜談」,回復「CRF」獲取本文全部代碼和數據,本公眾號原創技術文章第一時間推送。

精選好文推薦:

今日頭條面試,這幾個坑爹問題讓我與50w年薪擦肩而過...(Transformer)

面試阿里P7,這個問題沒回答出來,幫忙看看!(Encoder-Decoder)

面試官青睞的高頻面試問題,被我徹底搞懂!(Attention機制)

深入理解Python中import機制

不會虛擬環境搭建?那還怎麼寫項目代碼!

相關焦點

  • PyTorch Bi-LSTM+CRF NER標註代碼精讀
    前言首先,本文是對pytorch官方的Bi-LSTM+CRF實現的代碼解讀,原文地址:https://pytorch.org/tutorials/beginner/nlp/advanced_tutorial.html#bi-lstm-conditional-random-field-discussion然後,要搞清楚為什麼要用它而不是其它序列模型,如LSTM、Bi-LSTM。
  • python代碼實戰 | 用 TensorFlow 實現序列標註:基於bi-LSTM+CRF和字符嵌入實現NER和POS
    有一天,我在這裡,問自己:「如果你試圖在Tensorflow中編寫其中一個序列標記模型怎麼辦?需要多長時間?「答案是:不超過幾個小時。這篇文章的目標是提供一個如何使用 Tensorflow 構建一個最先進的模型(類似於本文)進行序列標記,並分享一些令人興奮的NLP知識的例子!與這篇文章一起,我發布了代碼,並希望有些人會發現它很有用。
  • 歷史最全深度學習與NLP核心概念、模型、策略及最新論文整理分享
    資源整理自網絡,源地址:https://github.com/neulab/nn4nlp-concepts/blob/master/concepts.md    帶論文連結資源下載地址:    連結: https://pan.baidu.com/s/1lC8DiPJnyzbxtvns-HXr_w
  • PyTorch:Bi-LSTM的文本生成
    目前,自然語言處理(NLP)領域通過不同的方法和技術處理不同的任務,即對語言進行推理、理解和建模。自然語言處理(NLP)領域在過去的十年裡發展非常迅速。許多模型都從不同的角度提出了解決不同NLP任務的方法。同樣,最受歡迎的模型中的共同點是實施基於深度學習的模型。
  • 賊好理解,這個項目教你如何用百行代碼搞定各類NLP模型
    整體而言,基本所有代碼都是作者自己完成的,當然都會借鑑已有的實現。很多模型都同時有 TensorFlow 和 PyTorch 兩種版本,但像 Transformer 和 BERT 等擁有谷歌官方實現的模型,作者只提供了 PyTorch 實現。據作者介紹,隨後他計劃將添加 Keras 版本的實現。
  • 【NER】NLP-入門實體命名識別(NER)+Bilstm-CRF模型原理Pytorch代碼詳解——最全攻略
    )代碼運行環境一、NER資料參考:NLP之CRF應用篇(序列標註任務)(CRF++的詳細解析、Bi-LSTM+CRF中CRF層的詳細解析、Bi-LSTM後加CRF的原因、CRF和Bi-LSTM+CRF優化目標的區別)CRF++完成的是學習和解碼的過程:訓練即為學習的過程,預測即為解碼的過程。
  • NLP-入門實體命名識別(NER)+Bilstm-CRF模型原理Pytorch代碼詳解——最全攻略
    希望能夠以這篇文章為載體,幫助其他跟我一樣的學習者梳理、串起NER的各個小知識點,最後上手NER的主流模型(Bilstm+CRF)(文中講的是pytorch,但是懂了pytorch去看keras十分容易相信我哈)二、主流模型Bilstm-CRF實現詳解(Pytorch篇)一、NER資料參考:NLP之CRF應用篇(序列標註任務)(CRF++的詳細解析、Bi-LSTM+CRF
  • 【深度學習】PyTorch:Bi-LSTM的文本生成
    目前,自然語言處理(NLP)領域通過不同的方法和技術處理不同的任務,即對語言進行推理、理解和建模。自然語言處理(NLP)領域在過去的十年裡發展非常迅速。許多模型都從不同的角度提出了解決不同NLP任務的方法。同樣,最受歡迎的模型中的共同點是實施基於深度學習的模型。
  • 97.5%準確率的深度學習中文分詞(字嵌入+Bi-LSTM+CRF)
    模型基本是參考論文:http://www.aclweb.org/anthology/N16-1030相關方法中文分詞是個比較經典的問題,各大網際網路公司都會有自己的分詞實現。 考慮到性能,可維護性,詞庫更新,多粒度,以及其他的業務需求,一般工業界中文分詞方案都是基於規則。1) 基於規則的常見的就是最大正/反向匹配,以及雙向匹配。
  • 支持53種語言預訓練模型,斯坦福發布全新NLP工具包StanfordNLP
    或者,你還可以從該 git repo 中安裝 StanfordNLP,這樣你可以更加靈活地基於 StanfordNLP 開發,以及訓練自己的模型。初始設置如下:下載 Stanford CoreNLP 和你想使用語言的模型。
  • tensorflow中crf源碼解析
    剛學習lstm+crf時,就閱讀過crf層的源碼,發現時間一久,就忘了。這次準備重新閱讀一下,順便做個筆記。主要的目的是深入理解代碼細節,提高自己編寫模型的能力。本文假定大家對lstm+crf的基本原理基本清楚。
  • 2019已經過去一大半了,努力一把成為NLP專家!
    lesson它會教你在fastai,語言模型是如何實現的。LSTM:即使transfomer更為流行,你還是有必要學習一些LSTM相關的知識, 因為在某些時候你仍然可以使用它,並且它是第一個在序列數據上取得較好較好效果的模型。
  • NLP實戰-中文命名實體識別
    那麼NER的任務就是從這句話中提取出目前在NER上表現較好的模型都是基於深度學習或者是統計學習的方法的,這些方法共同的特點都是需要大量的數據來進行學習,所以接下來我先介紹一下本項目使用的數據集的格式,好讓讀者在閱讀模型的代碼之前對數據的形式有個直觀的認識。
  • 【NLP/AI算法面試必備-2】NLP/AI面試全記錄
    5、crf的損失函數是什麼?lstm+crf怎麼理解?6、GBDT vs Xgboost7、評估指標f1和auc的區別是哪些?8、sigmoid用作激活函數時,分類為什麼要用交叉熵損失,而不用均方損失?9、神經網絡中的激活函數的對比?二、NLP高頻問題1、word2vec和tf-idf 相似度計算時的區別?
  • 【NLP】流水的NLP鐵打的NER:命名實體識別實踐與探索
    如果有新人苦於不知道怎麼實現一個 NER 模型,不知道 LSTM-CRF、BERT-CRF 怎麼寫,看到代碼之後便可以原地起飛,從此打開新世界的大門;或者有老 NLPer 從我的某段探索過程裡感覺還挺有意思的,那我就太開心了。
  • 用 Keras+LSTM+CRF 的實踐命名實體識別NER
    當今的各個應用裡面幾乎不會說哪個任務會沒有深度學習的影子,很多子任務的發展歷程都是驚人的相似,最初大部分的研究和應用都是集中在機器學習領域裡面,之後隨著深度學習模型的發展,也被廣泛應用起來了,命名實體識別這樣的序列標註任務自然也是不例外的,早就有了基於LSTM+CRF的深度學習實體識別的相關研究了,只不過與我之前的方向不一致,所以一直沒有化太多的時間去關注過它,最近正好在學習NER,在之前的相關文章中已經基於機器學習的方法實踐了簡單的命名實體識別了
  • 復旦邱錫鵬教授:2020最新NLP預訓練模型綜述
    背景「nlp、cv領域的傳統方法極度依賴於手動特徵工程」。例如nlp中的log-linear、CRF模型等,cv中各種抽取特徵的模型,如sift特徵等。深度學習中本質上是一種表示學習,能夠一定程度上避免手動的特徵工程。
  • 基於飛槳PaddlePaddle的語義角色標註任務全解析
    ;LSTM 模型學習輸入序列的特徵表示,得到新的特性表示序列;CRF 以第 3 步中 LSTM 學習到的特徵為輸入,以標記序列為監督信號,完成序列標註;圖:SRL 任務上的深層雙向 LSTM 模型接下來,我們就一步一步的實踐這個任務
  • 【CMU 2017秋季】深度學習NLP課程,PPT+視頻+課程表
    本課程將從神經網絡的簡要概述開始,然後話費大部分課時來講解如何將神經網絡應用於自然語言處理問題。本課程每個部分將介紹自然語言的一個特定問題或語言現象,描述為什麼這些問題或現象很難建模,並展示幾個解決這些問題的模型。課程將涵蓋在創建神經網絡模型中涉及到的不同技術,包括處理易變大小和結構化句子,高效處理大數據,半監督和無監督學習,結構化預測和多語言建模。