首页 > > > 6.3 基于NER的自动填单系统小试
同学们好,本节我们来尝试使用NER做一个自动填单的小case。不知道同学们在日常生活中,有没有见过这样的应用。在你网购、叫外卖的时候,往往需要输入一些收货信息,如:收货地址、手机号码、姓名等等。有时候这些信息很多而且大多都是重复的,让人十分厌倦。为了解决这个痛点,一些大型的网站通常会提供地址自动识别功能。

如上图,你只需输入一整串字符,里面可以包含地址、姓名、电话,系统就可以自动识别出这些的信息并将其填入对应的位置。那么这个功能的底层逻辑是什么呢?无论是使用什么方法,要做的无非就是识别出这一串字符里面,哪个是地址,哪个是人名,哪个是电话。想想,这不就是我们之前所讲的NER的功能吗?我们只要利用一些标注好的数据训练一个NER模型,即可实现这个功能。下面我们将讲解如何使用bilstm+crf实现的ner模型去自动识别收货信息。
构造数据
在训练之前,先得有训练数据。在这个case中,我们需要识别的实体有三个,分别是人名、地址以及电话号码。我们就定义这三个字段分别为PER、LOC、TEL好了。现在将这些字段保存起来,存在一个叫tag_index.json的文件里面,结构如下:
{"O": 0,"I-PER": 1, "B-PER": 2, "I-LOC": 3, "B-LOC": 4, "B-TEL": 5, "I-TEL": 6}
现在来捏造一些训练数据,我们下面就举两个栗子,大家可以发挥自己的脑洞自行脑补出更多的数据。栗子如下:
小红,广东省广州市珠江新城,25835104695
小明,广东省珠海市唐家湾镇金山软件园,25875003665
原始数据有了,训练数据也就很容易构造了。
小 B-PER
红 I-PER
, O
广 B-LOC
东 I-LOC
省 I-LOC
广 I-LOC
州 I-LOC
市 I-LOC
珠 I-LOC
江 I-LOC
新 I-LOC
城 I-LOC
, O
2 B-TEL
5 I-TEL
8 I-TEL
3 I-TEL
5 I-TEL
1 I-TEL
0 I-TEL
4 I-TEL
6 I-TEL
9 I-TEL
5 I-TEL
通常我们会把训练数据构造成上面的模样,然后每个句子用一个空格符隔开。最后放到一个train_data.txt文件里面去。
除了上述的这些数据外,我们还需要一个word_index.json的文件,这个是字的索引。内容如下:
{"韩": 717, "御": 1970, "钦": 1484, ... ,"暮": 2962, "椎": 2987}
这个词表的构造很简单,里面大概包含了3000多个常用的汉字,大家只要把汉字按照1、2、3、....这样的顺序排列,做成一个json结构即可。
当构造完数据后,就开始设计我们的模型了。这里我们使用BI-LSTM模型。
bilstm_crf.py
#!/usr/bin/env python3
# -*- coding=utf-8 -*-
from keras.models import Model
from keras.layers import Input, Embedding, Bidirectional, LSTM
from keras_contrib.layers import CRF
class BiLSTM_CRF_NER(object):
""" Implementation of Bi-LSTM-CRF NER model by Keras. """
def __init__(self, vocab_size=50000,
emb_dims=100,
birnn_unit=200,
max_sent_len=200,
tag_num=7):
self.vocab_size = vocab_size
self.emb_dims = emb_dims
self.birnn_unit = birnn_unit
self.max_sent_len = max_sent_len
self.tag_num = tag_num
def build_model(self):
input_layer = Input(shape=(self.max_sent_len,), name='input_layer')
embed_layer = Embedding(self.vocab_size,
self.emb_dims,
mask_zero=True,
name='embedding_layer'(input_layer)
birnn_layer = Bidirectional(LSTM(self.birnn_unit // 2,
return_sequences=True,
name = 'bilstm_layer'))(embed_layer)
crf = CRF(self.tag_num, sparse_target=False, name='crf_layer')
crf_layer = crf(birnn_layer)
model = Model(inputs=input_layer, outputs=crf_layer)
model.compile(optimizer='adam',
loss=crf.loss_function,
metrics=[crf.accuracy])
return model我这里使用keras进行建模,在你运行程序之前请确保你已经安装了这个python包,如未安装,可使用一下命令进行安装:
pip install git+https://www.github.com/keras-team/keras-contrib.git在这里,我们使用kreas定义了一个BI-LSTM的神经网络结构,其中build_model函数就是等下来训练需要调用的函数。
模型构造完之后就进入训练环节了。先来看看训练的代码,
bilstm_crf.py
#!/usr/bin/env python3#
-*- coding: utf-8 -*-"
import json
import keras.backend as K
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from bilstm_crf import BiLSTM_CRF_NER
# 读取词表
with open('data/word_index.json', encoding='utf8') as f:
word_index = json.load(f)
# 读取tag标签
with open('data/tag_index.json', encoding='utf8') as f:
tag_index = json.load(f)
# 加载词表
token = Tokenizer()
token.word_index = word_index
def load_data(fname, tag2id):
#读取训练数据
with open(fname, encoding='utf8') as f:
split_tag = '\n\n'
content = f.read().strip().split(split_tag)
data = [[line.split() for line in s.split('\n')] for s in content]
text_seq = [[x[0] for x in line] for line in data]
tag_seq = [[x[1] for x in line] for line in data]
# tokenize data
text_token = token.texts_to_sequences(text_seq)
tag_token = [[tag2id[t] for t in line] for line in tag_seq]
# padding data
text_pad = pad_sequences(text_token, maxlen=200)
tag_pad = pad_sequences(tag_token, maxlen=200)
tag_pad = K.eval(K.one_hot(tag_pad, len(tag2id)))
return text_pad, tag_pad
# 加载数据
x_train, y_train = load_data('data/train_data.data', tag_index)
x_test, y_test = load_data('data/test_data.data', tag_index)
# 训练模型
bilstm_crf = BiLSTM_CRF_NER()
model = bilstm_crf.build_model()
model.fit(x_train, y_train,
batch_size=128,
epochs=10,
validation_data=(x_test, y_test))首先,我们先将词表和tag标签加载进来,分别为word_index和tag_index。
接着,调用load_data函数加载训练数据和测试数据。
最后,调用BiLSTM_CRF_NER进行模型训练。这里我们只是做演示,所以只设置了10轮的迭代,如果想要获得更好的效果,可以提高迭代次数。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69954080/viewspace-3131141/ ,如需转载,请注明出处,否则将追究法律责任。