前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用TensorFlow构建一个中文分词模型需要几个步骤

用TensorFlow构建一个中文分词模型需要几个步骤

作者头像
段清华DEAN
发布2020-11-03 15:00:25
1.2K0
发布2020-11-03 15:00:25
举报
文章被收录于专栏:AI工程AI工程

用TensorFlow构建一个中文分词模型需要几个步骤

分析

中文分词方法现在主要有两种类型,一种是jieba这样软件包中用隐马尔科夫(HMM)模型构建的。

另一种就是使用如TensorFlow、PyTorch这类训练深度学习序列标注(Tagging)模型。

这里面我们主要以后者为参考。

中文分词往往有两个直接目标,一个是把词汇分开,另一个给每个词以词性,例如动词、名词,或者更细分的地点名词、机构名词等等。

如果只是分词,是中文分词任务(SEG,Chinese Segmentation),如果需要词性,也可以被称为词性标注任务(POS,Part os Speech)任务。

这两个任务都可以通过深度学习的序列标注(Tagging)模型实现,当然也可以通过其他模型实现,在文章末尾会提及其他方法。

序列标注是一个将输入序列,标注为另一个符号序列的任务,例如我们定义每个词的开头符号是B,非开头符号是I。

那么分词一句话如:“中文的分词任务”,就可以被标注为“B I B B I B I”,不过具体的颗粒度往往由训练语料决定,例如上一句中,“分词任务”到底是一个词,还是两个词组成的词组,这是由标注决定的。

如果是词性标注(POS),那么上面的序列就需要增加更多符号,例如“你开心吗”,可以被标注为:“Br Ba Ia Bu”

其中“Br”可以认为是一个代词的开头。

“Ba Ia”可以认为是一个形容词的开头和中间部分。

“Bu”是助词的开头。

以此讲一个句子的每个字符(字)都标注为一个新的符号序列,我们就可以得到句子的分词或词性标注了。

数据

从理想上来说,我们当然希望能有一个模型直接同时完成分词和词性标注两个任务。

但是现实中可能有一定困难,因为并不是我们能找到的所有数据集都包括了这两者的标注的,也就是有一些数据集可能只标注了分词,有些数据集标注了分词和词性。

这里我们从hankcs整理的一些历史上的分词和词性标注数据集为开始,地址为 https://github.com/hankcs/multi-criteria-cws

在这里REPO里,有些数据集是标注了词性的,例如CNC(data/other/cnc/test.txt),但是其他很多数据集是没标注词性的。

这里我们使用一个半监督学习方法(Semi-supervised learning),先用有POS数据的数据集,训练一个模型。

然后用这个模型标注其他只有分词的数据集,扩充这些数据集,最终得到一个融合多个数据集的词性标注模型。

在标注其他数据集的时候,应该注意不影响其他数据集的分词结果,只是给这些分词结果一个词性而已。

注意,所谓半监督学习(Semi-supervised learning),其实是一大类算法、方法的统称,这里使用的方法只是某种非常简单的半监督学习方法的应用。

模型

在模型上,我们选择使用Albert-small版本的模型,这个版本的模型大小不到30MB,适合比较轻量级的任务,我们可以先尝试实现一个最简单的序列标注模型。

这样的模型最简单是什么样子呢?大概这样:

代码语言:javascript
复制
import tensorflow as tf
import tensorflow_hub as hub

model = tf.keras.Sequential([
    hub.KerasLayer(
        'https://code.aliyun.com/qhduan/bert_v3/raw/98354b8924d9b22fd7b9c4466e36ae9d42cc5a42/albert_base.tar.gz',
        output_key='sequence_output'
    ),
    tf.keras.layers.Dense(2),
    tf.keras.layers.Activation('softmax')
])

以上的模型本质上就实现了序列标注,这里使用的TensorFlow Hub来载入一个bert模型,这个模型的介绍可以参考: https://github.com/qhduan/bert-model

Dense层提供到符号的转换,例如这里我们只考虑B和I两种符号,这里就可以是2。

我们可以简单测试一下这个模型:

代码语言:javascript
复制
x = tf.constant([
    ['你', '好', '吗'],
    ['你', '好', '']
])
y = tf.constant([
    [0, 1, 0],
    [0, 1, 0]
])

model(x)

最后的model(x)会输出:

代码语言:javascript
复制
<tf.Tensor: shape=(2, 3, 2), dtype=float32, numpy=
array([[[0.7527009 , 0.24729903],
        [0.7459688 , 0.2540312 ],
        [0.73734486, 0.26265517]],

       [[0.6320372 , 0.36796272],
        [0.71670467, 0.28329533],
        [0.5       , 0.5       ]]], dtype=float32)>

这代表了模型的结果,已经输出了softmax后的两个符号的概率值。

我们还可以进一步测试模型训练,例如:

代码语言:javascript
复制
model.compile(
    loss=tf.keras.losses.SparseCategoricalCrossentropy(),
    optimizer=tf.keras.optimizers.Adam())

model.train_on_batch(x, y)

最后这一句就可以输出loss。

以上只要我们喂给模型类似上面x、y这样定义的数据,就可以训练相应的分词模型了。

技巧

以上我们实现了一个非常简单的序列标注模型。

这里我们使用非常简单的线性层作为输出,在现在的序列标注模型,输出层可能有以下几种:

  • 线性层
  • RNN + 线性层
  • CRF
  • RNN + CRF
  • MRC

线性层就比较简单,如我们上面所写。

CRF层的话可以参考TensorFlow Addons的CRF实现: https://www.tensorflow.org/addons/api_docs/python/tfa/text/crf

MRC是指机器学习理解,这个方法也是可以用来进行分词、命名实体识别(NER)等工作的,不过在分词上不常用。

打包

TensorFlow 2.x的一个优势是,在比较多平台比较方便扩展,至少在Python、C++、NodeJS这个角度。

所以就可以很方便的把当前的TensorFlow模型打包为应用,具体例子可以参考本文这个分词的例子:

https://github.com/deepdialog/tfseg

安装:pip install tfseg

分词:

代码语言:javascript
复制
>>> import tfseg
>>> tfseg.lcut('我爱北京天安门')
['我', '爱', '北京', '天安门']

词性:

代码语言:javascript
复制
>>> from tfseg import posseg
>>> posseg.lcut('我爱北京天安门')
[pair('我', 'r'), pair('爱', 'v'), pair('北京', 'ns'), pair('天安门', 'ns')]
>>> posseg.lcut('我爱北京天安门')[0].word
'我'
>>> posseg.lcut('我爱北京天安门')[0].flag
'r'
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 用TensorFlow构建一个中文分词模型需要几个步骤
  • 分析
  • 数据
  • 模型
  • 技巧
  • 打包
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档