BiLSTM+CRF(三)命名實體識別 實踐與總結
本博文是對上一篇部落格(https://blog.csdn.net/jmh1996/article/details/84779680 BiLSTM+CRF(二)命名實體識別 )的完善。
資料處理功能模組
語料庫資料格式:
訓練集:
source_data.txt :文字
每一行為一個句子,每個句子用“\n”隔開,句子內部詞之間用空格分開。
精 品 、 專 題 、 系 列 、 稀 見 程 度 才 是 質 量 的 核 心 。 藏 書 的 數 量 多 少 不 能 反 映 收 藏 的 質 量 , 更 不 是 工 薪 層 的 承 受 範 圍 。 書 籍 浩 如 煙 海 , 靠 個 人 的 精 力 與 財 力 不 可 能 廣 而 博 之 。
source_label.txt :命名實體 標註文字
第i行為對應source_data第i行的標註結果
結果與結果之間用空格分開
O O O O O O O O O O O O O O O O O O O O O O O O O O O B-LOC I-LOC I-LOC I-LOC I-LOC O O O O O O O O O O O O O O O O O O O O O O O O O O O O B-ORG I-ORG I-ORG O O O O O O O O O O O O O O O O O O B-PER I-PER I-PER O O O B-PER I-PER O O O O B-ORG I-ORG I-ORG I-ORG O O
測試集:
test_data.txt :文字
test_label.txt :標註答案
格式同訓練集。
(github上有資料集):https://github.com/jmhIcoding/bilstm-crf/tree/rewrite
__author__ = 'jmh081701'
import json
import copy
import numpy as np
import random
class DATAPROCESS:
def __init__(self,train_data_path,train_label_path,test_data_path,test_label_path, word_embedings_path,vocb_path,seperate_rate=0.1,batch_size=100,
state={'O':0,'B-LOC':1,'I-LOC':2,'B-PER':3,'I-PER':4,'B-ORG':5,'I-ORG':6}):
self.train_data_path =train_data_path
self.train_label_path =train_label_path
self.test_data_path = test_data_path
self.test_label_path = test_label_path
self.word_embedding_path = word_embedings_path
self.vocb_path = vocb_path
self.state = state
self.seperate_rate =seperate_rate
self.batch_size = batch_size
self.sentence_length = 100
#data structure to build
self.train_data_raw=[]
self.train_label_raw =[]
self.valid_data_raw=[]
self.valid_label_raw = []
self.test_data_raw =[]
self.test_label_raw =[]
self.word_embeddings=None
self.id2word=None
self.word2id=None
self.embedding_length =0
self.__load_wordebedding()
self.__load_train_data()
self.__load_test_data()
self.last_batch=0
def __load_wordebedding(self):
self.word_embeddings=np.load(self.word_embedding_path)
self.embedding_length = np.shape(self.word_embeddings)[-1]
with open(self.vocb_path,encoding="utf8") as fp:
self.id2word = json.load(fp)
self.word2id={}
for each in self.id2word:
self.word2id.setdefault(self.id2word[each],each)
def __load_train_data(self):
with open(self.train_data_path,encoding='utf8') as fp:
train_data_rawlines=fp.readlines()
with open(self.train_label_path,encoding='utf8') as fp:
train_label_rawlines=fp.readlines()
total_lines = len(train_data_rawlines)
assert len(train_data_rawlines)==len(train_label_rawlines)
for index in range(total_lines):
data_line = train_data_rawlines[index].split(" ")[:-1]
label_line = train_label_rawlines[index].split(" ")[:-1]
#assert len(data_line)==len(label_line)
#align
if len(data_line) < len(label_line):
label_line=label_line[:len(data_line)]
elif len(data_line)>len(label_line):
data_line=data_line[:len(label_line)]
assert len(data_line)==len(label_line)
#add and seperate valid ,train set.
data=[int(self.word2id.get(each,0)) for each in data_line]
label=[int(self.state.get(each,self.state['O'])) for each in label_line]
if random.uniform(0,1) <self.seperate_rate:
self.valid_data_raw.append(data)
self.valid_label_raw.append(label)
else:
self.train_data_raw.append(data)
self.train_label_raw.append(label)
self.train_batches= [i for i in range(int(len(self.train_data_raw)/self.batch_size) -1)]
self.train_batch_index =0
self.valid_batches=[i for i in range(int(len(self.valid_data_raw)/self.batch_size) -1) ]
self.valid_batch_index = 0
def __load_test_data(self):
with open(self.test_data_path,encoding='utf8') as fp:
test_data_rawlines=fp.readlines()
with open(self.test_label_path,encoding='utf8') as fp:
test_label_rawlines=fp.readlines()
total_lines = len(test_data_rawlines)
assert len(test_data_rawlines)==len(test_label_rawlines)
for index in range(total_lines):
data_line = test_data_rawlines[index].split(" ")[:-1]
label_line = test_label_rawlines[index].split(" ")[:-1]
#assert len(data_line)==len(label_line)
#align
if len(data_line) < len(label_line):
label_line=label_line[:len(data_line)]
elif len(data_line)>len(label_line):
data_line=data_line[:len(label_line)]
assert len(data_line)==len(label_line)
data=[int(self.word2id.get(each,0)) for each in data_line]
label=[int(self.state.get(each,self.state['O'])) for each in label_line]
self.test_data_raw.append(data)
self.test_label_raw.append(label)
def pad_sequence(self,sequence,object_length,pad_value=None):
'''
:param sequence: 待填充的序列
:param object_length: 填充的目標長度
:return:
'''
sequence =copy.deepcopy(sequence)
if pad_value is None:
sequence = sequence*(1+int((0.5+object_length)/(len(sequence))))
sequence = sequence[:object_length]
else:
sequence = sequence+[pad_value]*(object_length- len(sequence))
return sequence
def next_train_batch(self):
#padding
output_x=[]
output_label=[]
efficient_sequence_length=[]
index =self.train_batches[self.train_batch_index]
self.train_batch_index =(self.train_batch_index +1 ) % len(self.train_batches)
datas = self.train_data_raw[index*self.batch_size:(index+1)*self.batch_size]
labels = self.train_label_raw[index*self.batch_size:(index+1)*self.batch_size]
for index in range(self.batch_size):
#複製填充
data= self.pad_sequence(datas[index],self.sentence_length)
label = self.pad_sequence(labels[index],self.sentence_length)
output_x.append(data)
output_label.append(label)
efficient_sequence_length.append(min(100,len(labels[index])))
return output_x,output_label,efficient_sequence_length
#返回的都是下標,注意efficient_sequence_length是有效的長度
def test_data(self):
output_x=[]
output_label=[]
efficient_sequence_length=[]
datas = self.test_data_raw[0:]
labels = self.test_label_raw[0:]
for index in range(len(datas)):
#複製填充
data= self.pad_sequence(datas[index],self.sentence_length)
label = self.pad_sequence(labels[index],self.sentence_length)
output_x.append(data)
output_label.append(label)
efficient_sequence_length.append(min(100,len(labels[index])))
return output_x,output_label,efficient_sequence_length
def next_valid_batch(self):
output_x=[]
output_label=[]
efficient_sequence_length=[]
index =self.valid_batches[self.valid_batch_index]
self.valid_batch_index =(self.valid_batch_index +1 ) % len(self.valid_batches)
datas = self.valid_data_raw[index*self.batch_size:(index+1)*self.batch_size]
labels = self.valid_label_raw[index*self.batch_size:(index+1)*self.batch_size]
for index in range(self.batch_size):
#複製填充
data= self.pad_sequence(datas[index],self.sentence_length)
label = self.pad_sequence(labels[index],self.sentence_length)
output_x.append(data)
output_label.append(label)
efficient_sequence_length.append(min(100,len(labels[index])))
return output_x,output_label,efficient_sequence_length
state={'O':0,'B-LOC':1,'I-LOC':2,'B-PER':3,'I-PER':4,'B-ORG':5,'I-ORG':6}
def extract_named_entity(labels,lens):
#輸入是一個句子的標籤
B_PER=-1
L_PER=-1
B_LOC=-1
L_LOC=-1
B_ORG=-1
L_ORG=-1
rst = set()
for index in range(lens):
if labels[index]==state['O']:
if B_PER >=0:
rst.add(('PER',B_PER,L_PER))
B_PER=-1
L_PER=0
if B_ORG >=0:
rst.add(('ORG',B_ORG,L_ORG))
B_ORG=-1
L_ORG=0
if B_LOC>=0:
rst.add(('LOC',B_LOC,L_LOC))
B_LOC=-1
L_LOC=0
if labels[index]==state['B-LOC']:
if B_PER >=0:
rst.add(('PER',B_PER,L_PER))
B_PER=-1
L_PER=0
if B_ORG >=0:
rst.add(('ORG',B_ORG,L_ORG))
B_ORG=-1
L_ORG=0
if B_LOC>=0:
rst.add(('LOC',B_LOC,L_LOC))
B_LOC=-1
L_LOC=0
B_LOC=index
L_LOC=1
if labels[index]==state['B-PER']:
if B_PER >=0:
rst.add(('PER',B_PER,L_PER))
B_PER=-1
L_PER=0
if B_ORG >=0:
rst.add(('ORG',B_ORG,L_ORG))
B_ORG=-1
L_ORG=0
if B_LOC>=0:
rst.add(('LOC',B_LOC,L_LOC))
B_LOC=-1
L_LOC=0
B_PER=index
L_PER=1
if labels[index]==state['B-ORG']:
if B_PER >=0:
rst.add(('PER',B_PER,L_PER))
B_PER=-1
L_PER=0
if B_ORG >=0:
rst.add(('ORG',B_ORG,L_ORG))
B_ORG=-1
L_ORG=0
if B_LOC>=0:
rst.add(('LOC',B_LOC,L_LOC))
B_LOC=-1
L_LOC=0
B_ORG=index
L_ORG=1
if labels[index]==state['I-LOC']:
if B_LOC>=0:
L_LOC+=1
if labels[index]==state['I-ORG']:
if B_ORG>=0:
L_ORG+=1
if labels[index]==state['I-PER']:
if B_PER>=0:
L_PER+=1
return rst
def evaluate(predict_labels,real_labels,efficient_length):
#輸入的單位是batch;
# predict_labels:[batch_size,sequence_length],real_labels:[batch_size,sequence_length]
sentence_nums =len(predict_labels) #句子的個數
predict_cnt=0
predict_right_cnt=0
real_cnt=0
for sentence_index in range(sentence_nums):
try:
predict_set=extract_named_entity(predict_labels[sentence_index],efficient_length[sentence_index])
real_set=extract_named_entity(real_labels[sentence_index],efficient_length[sentence_index])
right_=predict_set.intersection(real_set)
predict_right_cnt+=len(right_)
predict_cnt += len(predict_set)
real_cnt +=len(real_set)
except Exception as exp:
print(predict_labels[sentence_index])
print(real_labels[sentence_index])
precision = predict_right_cnt/(predict_cnt+0.000000000001)
recall = predict_right_cnt/(real_cnt+0.000000000001)
F1 = 2 * precision*recall/(precision+recall+0.00000000001)
return {'precision':precision,'recall':recall,'F1':F1}
if __name__ == '__main__':
dataGen = DATAPROCESS(train_data_path="data/source_data.txt",
train_label_path="data/source_label.txt",
test_data_path="data/test_data.txt",
test_label_path="data/test_label.txt",
word_embedings_path="data/source_data.txt.ebd.npy",
vocb_path="data/source_data.txt.vab",
batch_size=90,
seperate_rate=0.3
)
datas,labels,efficient_sequence_length = dataGen.test_data()
print(evaluate(labels,labels,efficient_sequence_length))
bilstm+crf 網路部分
相關推薦
BiLSTM+CRF(三)命名實體識別 實踐與總結
本博文是對上一篇部落格(https://blog.csdn.net/jmh1996/article/details/84779680 BiLSTM+CRF(二)命名實體識別 )的完善。
資料處理功能模組
語料庫資料格式: 訓練集: source_data.txt :文字 每一行為
BiLSTM+CRF(二)命名實體識別
前言
前一篇部落格裡面,我們已經提到了如何構建一個雙向的LSTM網路,並在原來單層的RNN的基礎上,修改少數幾行程式碼即可實現。 Bi-LSTM其實就是兩個LSTM,只不過反向的LSTM是把輸入的資料先reverse 首尾轉置一下,然後跑一個正常的LSTM,然後再把輸出結果rever
NLP入門(四)命名實體識別(NER)
本文將會簡單介紹自然語言處理(NLP)中的命名實體識別(NER)。 命名實體識別(Named Entity Recognition,簡稱NER)是資訊提取、問答系統、句法分析、機器翻譯等應用領域的重要基礎工具,在自然語言處理技術走向實用化的過程中佔有重要地位。一般來說,命名實體識
基於CRF的中文命名實體識別模型
條件隨機場(Conditional Random Fields,簡稱 CRF)是給定一組輸入序列條件下另一組輸出序列的條件概率分佈模型,在自然語言處理中得到了廣泛應用。
新建corpus_process類
import re
import sklearn_crfsuite
from
BiLSTM介紹及中文命名實體識別應用
What-什麼是LSTM和BiLSTM?
LSTM:全稱Long Short-Term Memory,是RNN(Recurrent Neural Network)的一種。LSTM由於其設計的特點,非常適合用於對時序資料的建模,如文字資料。
BiLSTM:Bi-directional
零基礎入門--中文命名實體識別(BiLSTM+CRF模型,含程式碼)
自己也是一個初學者,主要是總結一下最近的學習,大佬見笑。
中文分詞
說到命名實體抽取,先要了解一下基於字標註的中文分詞。
比如一句話
"我愛北京天安門”。
分詞的結果可以是
“我/愛/北京/天安門”。
那什麼是基於字標註呢?
“我/O 愛/O 北/B
命名實體識別(biLSTM+crf)
為什麼要用biLSTM?為了使特徵提取自動化。當使用CRF++工具來進行命名實體識別時,需要自定義模板(或者使用預設的模板)。
任務和資料
任務是進行命名實體識別(named entity recognition),例如:
在CoNLL2003任務中,實體是LO
BILSTM+CRF實現命名實體識別NER
#第一步:資料處理
#pikle是一個將任意複雜的物件轉成物件的文字或二進位制表示的過程。
#同樣,必須能夠將物件經過序列化後的形式恢復到原有的物件。
#在 Python 中,這種序列化過程稱為 pickle,
#可以將物件 pickle 成字串、磁碟上的檔案或者任何類似於檔案的物件,
#也可以
BiLSTM-CRF模型做基於字的中文命名實體識別
在MSRA的簡體中文NER語料(我是從這裡下載的,非官方出品,可能不是SIGHAN 2006 Bakeoff-3評測所使用的原版語料)上訓練NER模型,識別人名、地名和組織機構名。嘗試了兩種模型:一種是手工定義特徵模板後再用CRF++開源包訓練CRF模型;另一種是
BiLSTM-CRF 模型實現中文命名實體識別
三個月之前 NLP 課程結課,我們做的是命名實體識別的實驗。在MSRA的簡體中文NER語料(我是從這裡下載的,非官方出品,可能不是SIGHAN 2006 Bakeoff-3評測所使用的原版語料)上訓練NER模型,識別人名、地名和組織機構名。嘗試了兩種模型:一種是手工定義特徵模板後再用CRF++開源包訓練CR
NLP入門(八)使用CRF++實現命名實體識別(NER)
CRF與NER簡介
CRF,英文全稱為conditional random field, 中文名為條件隨機場,是給定一組輸入隨機變數條件下另一組輸出隨機變數的條件概率分佈模型,其特點是假設輸出隨機變數構成馬爾可夫(Markov)隨機場。
較為簡單的條件隨機場是定義線上性鏈上的條件隨機場,稱為線性鏈條件
神經網絡結構在命名實體識別(NER)中的應用
field edi most 好的 向量 後來 目標 領域 png 神經網絡結構在命名實體識別(NER)中的應用
近年來,基於神經網絡的深度學習方法在自然語言處理領域已經取得了不少進展。作為NLP領域的基礎任務—命名實體識別(Named Entity Recogni
用CRF做命名實體識別
裏的 以及 命名 語料庫 images AD 之前 .dll alt 摘要
本文主要講述了關於人民日報標註語料的預處理,利用CRF++工具包對模型進行訓練以及測試
目錄
明確我們的標註任務
語料和工具
數據預處理
1.數據說明
2.數據預處理
模型訓練及測試
1.流程
2
簡單NLP分析套路(2)----分詞,詞頻,命名實體識別與關鍵詞抽取
文章大綱
中文分詞技術
評測參考
雲服務
哈工大語言云 ltp
基於深度學習方法的中文分詞
資訊檢索與關鍵詞提取
tf-idf
TEXTRANK
word2vector
神經網路結構在命名實體識別(NER)中的應用
近年來,基於神經網路的深度學習方法在自然語言處理領域已經取得了不少進展。作為NLP領域的基礎任務—命名實體識別(Named Entity Recognition,NER)也不例外,神經網路結構在NER中也取得了不錯的效果。最近,我也閱讀學習了一系列使用神經網路結構進行
自然語言處理 crf++命名實體識別
自然語言處理的方法有很多種,crf++是也是使用比較多的一種方法,關於crf++ 的詳細解釋可以參考網上的資料,這裡不再做介紹,這裡直接說的就是用crf++進行命名實體識別。
crf++ 進行自然語言處理的時候需要下載一個crf工具包,然後使用工具包進行處理,我使用的是CR
NLP入門(五)用深度學習實現命名實體識別(NER)
前言
在文章:NLP入門(四)命名實體識別(NER)中,筆者介紹了兩個實現命名實體識別的工具——NLTK和Stanford NLP。在本文中,我們將會學習到如何使用深度學習工具來自己一步步地實現NER,只要你堅持看完,就一定會很有收穫的。
OK,話不多說,讓我們進入正題。
幾乎所有的NLP都依賴一
命名實體識別(NER)的發展歷程
命名實體識別(Named Entity Recognition,NER)簡單說就是從一段自然語言文字中找出相關實體,並標註出其位置以及型別。一般我們歸為序列標註問題(sequence labeling problem)中的一種。與分類問題相比,序列標註問題中當前的預測標籤不僅與當
命名實體識別訓練集彙總(一直更新)
在學習過程中,整理了一些已標準好的訓練集,彙總如下:
連結: https://pan.baidu.com/s/1BU0XS-I5qZIA7Y9trGxc8w 提取碼: gnqt 來源:https://github.com/zjy-ucas/ChineseNER
連結: https:/
基於crf的CoNLL2002資料集命名實體識別模型實現-pycrfsuite
下面是用python的pycrfsuite庫實現的命名實體識別,是我最初為了感知命名實體識別到底是什麼,調研命名實體識別時跑的案例,記錄在下面,為了以後查閱。
案例說明:
內容:在通用語料庫CoNLL2002上,用crf方法做命名實體識別(地點、組織和人名)。
工具:Anacond