小孔同学推荐了两个基于循环神经网络以及CRF处理nlp问题的算法,分别是中分分词以及命名实体识别,都是github上开源的项目,之前也用过一些开源的分词工具以及产品级分词工具,比如波森nlp,发现github上这两个【BiLSTM+CRF】 【NeuroNER】,效果都非常不错,感谢koth 以及 Franck Dernoncourt。在这不分析模型,只说下把两个模型frozen一下,然后一块封装到nlp相关的接口中,通过flask可以非常方便的发布供项目其他模块使用~
分词模型
按照README中介绍的过程训练模型,训练完成后,想把分词作为工程的其他模块通过接口的形式发布出来,在这直接使用了作者固化出来的模型在Python中加载,最终脚本如下所示,指示单句子分词,如果是长文本,参照着作者github中 kcws/cc/seg_backend_api.cc 调用的分割函数,分割成短文本即可。
"""
分词主类,加载预先训练好并固化好的模型文件,加载训练生成的词-id映射表并进行分词
"""
import numpy as np
import tensorflow as tf
import math
class Node:
"""
trie树中的节点, weight=0 表示该节点不是叶子节点
"""
def __init__(self):
self.weight = 0.0
self.next = {}
class Trie:
"""
trie 树实现,用来添加用户自定义词典
每个节点包括一个权重以及指向下一个节点的连接
权重初始化为0,当该节点是词的最终节点时,权重赋值为用户自定义词典的权重
"""
def __init__(self):
self.root = Node()
def push_node(self, word, weight):
"""
将词与权重压入构建trie数的节点以及路径
:param word: 词
:param weight: 权重
:return: None
"""
word_len = len(word)
if word_len == 0: return
temp = self.root
for index, char in enumerate(word):
if char in temp.next:
temp = temp.next[char]
if index + 1 == word_len: temp.weight = weight
continue
else:
temp.next[char] = Node()
temp = temp.next[char]
if index + 1 == word_len: temp.weight = weight
def search(self, sentence):
"""
对输入的文本通过trie树做检索,查找文本中出现的用户自定义词,并返回该词所在位置以及该词权重
:param sentence: 文本
:return: eg: [([0, 1], 4.0), ([9, 10, 11], 4.0)]
tuple 列表,其中[0, 1]表示该词出现在句子的第0,1索引出, 4.0表示用户对该词定义的权重
"""
fake_list = []
word_len = len(sentence)
if word_len == 0: return fake_list
point = self.root
index = 0
pre_match = -1
word_range = None
while index < word_len:
word = sentence[index]
if word in point.next:
if pre_match < 0: pre_match = index
point = point.next[word]
index += 1
if point.weight > 0: word_range = ([i for i in range(pre_match, index)], point.weight)
if index == word_len: fake_list.append(word_range)