ITPub博客

首页 > > > 6.3 基于NER的自动填单系统小试

6.3 基于NER的自动填单系统小试

作者:RayChou 时间:2019-12-30 10:04:59 0 删除 编辑

前言

  同学们好,本节我们来尝试使用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结构即可。


构建NER模型

  当构造完数据后,就开始设计我们的模型了。这里我们使用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/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: 8 语言模型简介
请登录后发表评论 登录
全部评论
现任金山办公软件人工智能组高级AI研发工程师。多年从事机器学习,特别是NLP自然语言处理算法的研究及开发工作。拥有丰富的软件开发经验,以及丰富的人工智能算法训练平台开发经验。

注册时间:2019-11-14

  • 博文量
    71
  • 访问量
    60567