分析
中文分词方法现在主要有两种类型,一种是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,适合比较轻量级的任务,我们可以先尝试实现一个最简单的序列标注模型。
这样的模型最简单是什么样子呢?大概这样:
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。
我们可以简单测试一下这个模型:
x = tf.constant([
['你', '好', '吗'],
['你', '好', '']
])
y = tf.constant([
[0, 1, 0],
[0, 1, 0]
])
model(x)
最后的model(x)会输出:
tf.Tensor: shape=(2, 3, 2), dtype=float32, numpy=
array([[[0.7527009 , 0.24729903],
[ ],
[ ]],
[ ],
[ ],
[ ]]], dtype=float32)>
这代表了模型的结果,已经输出了softmax后的两个符号的概率值。
我们还可以进一步测试模型训练,例如:
model.compile(
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
optimizer=tf.keras.optimizers.Adam())
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
分词:
> import tfseg
'我爱北京天安门') > tfseg.lcut(
['我', '爱', '北京', '天安门']
词性:
> from tfseg import posseg
'我爱北京天安门') > posseg.lcut(
[pair('我', 'r'), pair('爱', 'v'), pair('北京', 'ns'), pair('天安门', 'ns')]
'我爱北京天安门')[0].word > posseg.lcut(
'我'
'我爱北京天安门')[0].flag > posseg.lcut(
'r'
由于微信平台算法改版,公号内容将不再以时间排序展示,如果大家想第一时间看到我们的推送,强烈建议星标我们和给我们多点点【在看】。星标具体步骤为:
(1)点击页面最上方"AINLP",进入公众号主页。
(2)点击右上角的小点点,在弹出页面点击“设为星标”,就可以啦。
感谢支持,比心。
推荐阅读
征稿启示| 200元稿费+5000DBC(价值20个小时GPU算力)
完结撒花!李宏毅老师深度学习与人类语言处理课程视频及课件(附下载)
模型压缩实践系列之——bert-of-theseus,一个非常亲民的bert压缩方法
文本自动摘要任务的“不完全”心得总结番外篇——submodular函数优化
斯坦福大学NLP组Python深度学习自然语言处理工具Stanza试用
关于AINLP
AINLP 是一个有趣有AI的自然语言处理社区,专注于 AI、NLP、机器学习、深度学习、推荐算法等相关技术的分享,主题包括文本摘要、智能问答、聊天机器人、机器翻译、自动生成、知识图谱、预训练模型、推荐系统、计算广告、招聘信息、求职经验分享等,欢迎关注!加技术交流群请添加AINLPer(id:ainlper),备注工作/研究方向+加群目的。
阅读至此了,分享、点赞、在看三选一吧🙏