新 GitHub 开放项目 FoolNLTK:一个便捷的中文处理工具包
Trudy77W
7年前
<p>近日 GitHub 用户 wu.zheng 开源了一个使用双向 LSTM 构建的中文处理工具包,该工具不仅可以实现分词、词性标注和命名实体识别,同时还能使用用户自定义字典加强分词的效果。机器之心简要介绍了这种双向 LSTM,并给出了我们在 Windows 上测试该工具的结果。</p> <p>中文处理工具包 GitHub 地址:https://github.com/rockyzhengwu/FoolNLTK</p> <p>根据该项目所述,这个中文工具包的特点有如下几点:</p> <ul> <li>可能不是最快的开源中文分词,但很可能是最准的开源中文分词</li> <li>基于 BiLSTM 模型训练而成</li> <li>包含分词,词性标注,实体识别, 都有比较高的准确率</li> <li>用户自定义词典</li> </ul> <p>在中文信息处理中,分词(word segmentation)是一项基本技术,因为中文的词汇是彼此相连的,不像英文有一个天然的空格符可以分隔不同的单词。虽然把一串汉字划分成一个个词对于汉语使用者来说是很简单的事情,但对机器来说却很有挑战性,所以一直以来分词都是中文信息处理领域的重要的研究问题。</p> <p>如该项目所述,作者使用了双向 LSTM 来构建整个模型,这也许是作者对分词性能非常有信心的原因。在中文分词上,基于神经网络的方法,往往使用「字向量 + 双向 LSTM + CRF」模型,利用神经网络来学习特征,将传统 CRF 中的人工特征工程量将到最低。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/be11e96beda24bdd3d01aa869bb9a1ed.png"></p> <p>中文分词系统的一般神经网络架构,其中特征层就是使用的 LSTM,来源 Xinchi Chen et al.(2017)。</p> <p>除了该工具包所使用的深度方法,其实今年 ACL 的杰出论文就有一篇专门描述了分词方法。复旦大学的陈新驰、施展、邱锡鹏和黄萱菁在 Adversarial Multi-Criteria Learning for Chinese Word Segmentation 论文中提出了一个新框架,可以利用多标准的中文分词语料进行训练。</p> <p>因为该工具包主要使用的是双向 LSTM,所以我们先简要解释一下这种网络再讨论我们测试的分词效果。首先顾名思义,双向 LSTM 结合了从序列起点开始移动的 LSTM 和另一个从序列末端开始移动的 LSTM。其中正向和逆向的循环网络都由一个个 LSTM 单元组成。以下是 LSTM 单元的详细结构,其中 Z 为输入部分,Z_i、Z_o 和 Z_f 分别为控制三个门的值,即它们会通过激活函数 f 对输入信息进行筛选。一般激活函数可以选择为 Sigmoid 函数,因为它的输出值为 0 到 1,即表示这三个门被打开的程度。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/aca14cc20848c5b19dc286ba3267e509.png"></p> <p>图片来源于李弘毅机器学习讲义</p> <p>若我们输入 Z,那么该输入向量通过激活函数得到的 g(Z) 和输入门 f(Z_i ) 的乘积 g(Z) f(Z_i ) 就表示输入数据经筛选后所保留的信息。Z_f 控制的遗忘门将控制以前记忆的信息到底需要保留多少,保留的记忆可以用方程 c*f(z_f)表示。以前保留的信息加上当前输入有意义的信息将会保留至下一个 LSTM 单元,即我们可以用 c' = g(Z)f(Z_i) + cf(z_f) 表示更新的记忆,更新的记忆 c' 也表示前面与当前所保留的全部有用信息。我们再取这一更新记忆的激活值 h(c') 作为可能的输出,一般可以选择 tanh 激活函数。最后剩下的就是由 Z_o 所控制的输出门,它决定当前记忆所激活的输出到底哪些是有用的。因此最终 LSTM 的输出就可以表示为 a = h(c')f(Z_o)。</p> <p>若我们将这一系列 LSTM 单元组织为如下形式,那么它们就构成了一个 BiLSTM 网络:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/25f8833b45abfb834e88b428cdd04646.png"></p> <p>图片来源于李弘毅机器学习讲义</p> <p>如上所示,我们将两个反向读取的 LSTM 网络连接就成了 BiLSTM。如果我们同时训练正向 LSTM 与逆向 LSTM,并把这两个循环网络的隐藏层拿出来都接入一个输出层,那么我们就能得到最后的输出结果 y。使用这种 BiLSTM 的好处是模型的观察范围比较广,因为当我们只采用单向循环网络时,在时间步 t+1 只能观察到 x_t 以及之前的输入数据,而不能观察到 x_t+2 及之后的情况。而当我们使用双向循环网络,模型在每一个时间步都会观察全部的输入序列,从而决定最后的输出。</p> <p>以上是简要的 BiLSTM 概念,机器之心在 Windows 10 系统、TensorFlow 1.4、Numpy 1.13.3 成功地运行了该模型。我们简单地测试了三段文字的分词效果,即一般的文本、专业文本和定义字典后的专业文本。我们使用 Python 自带函数读取 TXT 文档并执行分词任务,分词后返回的数据结构是非常常见的 Python 列表,因此我们可以轻易地进行后续的处理。</p> <p>对于较为常见的文本,该工具的分词效果确实挺好:</p> <p>['本', '报告', '所', '讨论', '的', '「', '人工智能', '」', '主要', '是', '指', '可以', '通过', '机器', '体现', '的', '智能', ',', '也', '叫做', '机器', '智能', '。', '在', '学术', '研究', '领域', ',', '指', '能够', '感知', '周围', '环境', '并', '采取', '行动', '以', '实现', '最', '优', '可能', '结果', '的', '智能体', '。', '一般而言', ',', '人工智能', '的', '长期', '目标', '是', '实现', '通用', '人工智能', ',', '这', '被', '看作', '是', '「', '强', '人工智能', '」', '。', '在', '处理', '交叉', '领域', '问题', '时', ',', 'AGI', ' ', '的', '表现', '会', '远远', '超过', '普通', '机器', ',', '并且', '可以', '同时', '处理', '多', '个', '任务', '。', '而', '弱', '人工智能', '无法', '解决', '之前', '未', '见过', '的', '问题', ',', '而且', '其', '能力', '仅', '局限', '在', '特定', '领域', '内', '。', '但是', ',', '人工智能', '专家', '和', '科学家', '现在', '对', ' ', 'AGI', ' ', '的', '确切', '定义', '仍然', '含', '混', '不', '清', '。', '区别', '强', '人工智能', '和', '弱', '人工智能', '的', '常见', '方法', '是', '进行', '测试', ',', '比如', '图灵', '测试', '、', '机器人', '大学生', '测试', '和', '就业', '测试', '。']</p> <p>而对于较为专业性的文字,该工具倾向于将其分割为更离散的词组:</p> <p>['在', '论文', '中', ',', ' Hinton', ' ', '介绍', ' ', 'Capsule', ' ', '为', ':', '「', 'Capsule', ' ', '是', '一', '组', '神经元', ',', '其', '输入', '输出', '向', '量', '表示', '特定', '实体', '类型', '的', '实例化', '参数', '(', '即', '特定', '物体', '、', '概念', '实体', '等', '出现', '的', '概率', '与', '某些', '属性', ')', '。', '我们', '使用', '输入', '输出', '向', '量', '的', '长度', '表征', '实体', '存在', '的', '概率', ',', '向', '量', '的', '方向', '表示', '实例化', '参数', '(', '即', '实体', '的', '某些', '图形', '属性', ')', '。', '同一', '层级', '的', ' ', 'capsule', ' ', '通过', '变换', '矩阵', '对', '更', '高', '级别', '的', ' ', 'capsule', ' ', '的', '实例化', '参数', '进行', '预测', '。', '当', '多', '个', '预测', '一致', '时', '(', '本', '论文', '使用', '动态', '路', '由', '使', '预测', '一致', ')', ',', '更', '高', '级别', '的', ' ', 'capsule', ' ', '将', '变', '得', '活跃', '。', '」']</p> <p>但是我们可以将专业词汇添加到词典而加强分词的效果,如下所示为添加了字典后的分词:</p> <p>['在', '论文', '中', ','Hinton', ' ', '介绍', ' ', 'Capsule', ' ', '为', ':', '「', 'Capsule', ' ', '是', '一组', '神经元', ',', '其', '输入输出向量', '表示', '特定', '实体类型', '的', '实例化参数', '(', '即', '特定', '物体', '、', '概念', '实体', '等', '出现', '的', '概率', '与', '某些', '属性', ')', '。', '我们', '使用', '输入输出向量', '的', '长度', '表征', '实体', '存在', '的', '概率', ',', '向量', '的', '方向', '表示', '实例化参数', '(', '即', '实体', '的', '某些', '图形属性', ')', '。', '同一', '层级', '的', ' ', 'capsule', ' ', '通过', '变换', '矩阵', '对', '更', '高', '级别', '的', ' ', 'capsule', ' ', '的', '实例化参数', '进行', '预测', '。', '当', '多个', '预测', '一致', '时', '(', '本', '论文', '使用', '动态', '路由', '使', '预测', '一致', ')', ',', '更', '高', '级别', '的', ' ', 'capsule', ' ', '将', '变', '得', '活跃', '。', '」']</p> <p>以下是该开源工具的安装方法与使用说明:</p> <p><strong>安装</strong></p> <pre> <code class="language-python">pip install foolnltk</code></pre> <p><strong>使用说明</strong></p> <p>1. 分词</p> <pre> <code class="language-python">import fool text = "一个傻子在北京" print(fool.cut(text)) # ['一个', '傻子', '在', '北京']</code></pre> <p>命令行分词</p> <pre> <code class="language-python">python -m fool [filename]</code></pre> <p>2. 用户自定义词典</p> <p>词典格式格式如下,词的权重越高,词的长度越长就越越可能出现, 权重值请大于 1</p> <pre> <code class="language-python">难受香菇 10 什么鬼 10 分词工具 10 北京 10 北京天安门 10</code></pre> <p>加载词典</p> <pre> <code class="language-python">import fool fool.load_userdict(path) text = "我在北京天安门看你难受香菇"print(fool.cut(text))# ['我', '在', '北京天安门', '看', '你', '难受香菇']</code></pre> <p>删除词典</p> <pre> <code class="language-python">fool.delete_userdict();</code></pre> <p>3. 词性标注</p> <pre> <code class="language-python">import fool text = "一个傻子在北京" print(fool.pos_cut(text)) #[('一个', 'm'), ('傻子', 'n'), ('在', 'p'), ('北京', 'ns')]</code></pre> <p>4. 实体识别</p> <pre> <code class="language-python">import fool text = "一个傻子在北京" words, ners = fool.analysis(text) print(ners) #[(5, 8, 'location', '北京')]</code></pre> <p>作者暂时只在 Python3 Linux 平台测试过,不过我们发现它在 Windows 系统也能正常运行。</p> <p> </p>