研究笔记 | 唐诗无监督分词实验
唐诗无监督分词实验
1
引言
如果要对文本中的内容进行挖掘,就需要提取其中的语义实体,而分词就是提取语义实体的第一步。但提到诗歌分词,大家很多时候第一反应都是诗歌分词没有必要。因为似乎针对诗歌没有多少信息处理的任务,而诗歌所传达的信息本来也不是唯一确定的。对诗歌的解读也会因读者的知识背景、文化背景区别而有很大不同。因此,如果希望藉由远读的方式来理解诗歌的内涵,是有着相当的困难的。但是一些分析处理的目的并不是为了利用数理统计彻底理解诗歌,而只是为了对诗歌中的信息进行结构化整理,从而进行下一步的分析整理。这时,诗歌的分词就有了必要性。分词最终的目的就是为了抽取出诗歌中的一些词汇,作为命名实体用于下一步的分析,并希望可以由此在统计分析的层面观察所选择的诗歌语料。
现代汉语的分词已经有很多成熟的工具比如:HanLP、jieba分词等等。但是涉及到古代汉语的分词任务,使用上述基于现代汉语的语料库构建的工具所得到的处理结果往往会比较差,因此无法直接使用。同时,古代汉语没有大规模公开的分词数据,也无法采用监督学习,比如基于条件随机场模型(CRF)的训练方式,训练得到模型来分词,因此目前需要尝试以无监督的方式来进行分词的任务。
2
分词原理
2.1 无监督分词
对无监督分词的认知主要来源于苏剑林在2016年撰写的一篇博客:基于语言模型的无监督分词 [1]。这里简单解释一下无监督分词的原理。
很多自然语言问题可以通过对文字进行标注,把任务转化为序列顺序优化问题从而进行处理。有了语料标注的数据后,可以利用各式模型比如隐式马尔可夫模型(HMM)、条件随机场模型(CRF)等等进行分词。其中隐马尔可夫模型是一个比较简易的分词模型,通过使用各个状态的转移概率与各个字对应状态的概率分布即字的标签概率,来进行预测,具体的原理可以细看一篇介绍分词的博客:字标注法与HMM模型 [2]。
因此在进行分词任务前,需要有标注好的语料供语言模型训练,如果没有标注好的语料,就需要以另外的方式来计算、推测出所需的转移概率。这里可以利用以字为单位的N-gram语言模型推测出某个单字对应的标签概率 [1](关于N-gram的介绍可以阅读这篇博客:自然语言处理中N-gram模型介绍 [3])。而状态的转移概率则只能通过经验来设定了,不过在分词过程中可以视分词效果来调整。
在这里,无监督分词与监督分词的区别在于不同字符的标签概率的获得方式。监督分词会使用已分词的语料,字的标签概率是根据语料统计得来;无监督分词则通过计算出N-gram语言模型,即以统计得到字词组合的频率,再反推出字的标签概率。无监督分词实际上是总结出了语料中用语的习惯,然后基于用词习惯进行分词,常常出现在一起的字符就会被认为是同一个词,但是中文的使用有时候并不完全符合统计规律,会有很多不符合规律的地方存在,如以下的分词结果:“花下 | 忘归 | 因 | 美景 , 尊前 | 劝酒 | 是 | 春风”,其中“花下”、“尊前”等从语感上来说可能不是一个词组的两个字也被组合在了一起。所以无监督分词的效果一定意义上会差于有着充分分词训练语料的监督分词。但在无法取得大规模标注语料的情况下,无监督分词也不失为一种可用的方法。
2.2 诗词结构干预分词
诗歌有它自身的语言结构,诗歌在撰写的时候已经有对仗和韵律等考虑,但是单纯的基于统计的分词过程并没有将这些约束考虑进去。因此,在分词的时候,可以利用诗歌的规则,来规避掉一些明显的错误。目前采用的方式有两种:
1)基于诗歌断词习惯的干预。首先,在以五言和七言为主的唐诗分词中,很多时候诗歌分词都有一些规律可循[5]。五言大多采用 2+2+1 或者 2+1+2 的分法,而七言则主要采用是 2+2+1+2 和 2+2+2+1 的断词方式。在分词结果不符合这些结果的时候,对不合常理之处进行判定并调整。而不合理之处经常会存在,比如:”寂寂 | 孤 | 莺啼 | 杏园 , 寥寥 | 壹 | 犬吠 | 桃源 。落花 | 芳草 | 无寻处 , 万壑 | 千峰 | 独 | 闭门“,其中 “莺啼”、“犬吠” 从诗句断词上来说不该被组合在一起。2)基于对仗的干预。虽然绝句有很多不对仗的情况,律诗的首联与尾联也常常不对仗[6],但是针对剩余的诗句就可以进行基于对仗的干预,因为该对仗诗句之间的断词结果也应该相同。当诗句上下联的分词结果不一致时,可以通过比较不同之处的语言模型概率来进行判断,必要时纠正其中的一个,使分词结果在断词层面对仗。以下是几个例子:“南山 | 缭上苑 , 祇树 | 连 | 岩翠” :可以根据下句把“缭上苑”分为“缭 | 上苑”。“瑞 | 影 | 玉楼 | 开 | 组绣 , 欢声 | 丹禁 | 奏云 | 韶 ”:可以基于前一句的切分方式与词汇标签概率的比较,把“奏云 | 韶”改为“奏 | 云韶”。通过这两种方式干预无监督分词得到的输出,可以使得最终的结果更加符合语感。3
分词流程
3.1 环境配置
环境配置:Ubuntu 20.04 LTS + kenlm + python3。这里选择基于Linux系统,使用kenlm工具[7]训练N-gram语言模型。kenlm本身基于Linux系统开发,而且kenlm的作者并没能频繁、及时地维护windows版本,所以这里的试验暂时使用Linux系统。kenlm的安装只要依照作者给出的安装指南(https://kheafield.com/code/kenlm/),一步步操作下来即可。但有时不可避免地会遇到一些依赖的问题,kenlm作者也给出了依赖安装指南 (https://kheafield.com/code/kenlm/dependencies/)。训练过程结束后的分词过程对环境没有特别多的需求,只是因为我们要使用kenlm训练得到的模型,所以需要一个安装了kenlm拓展包的python环境。
3.2 语言模型训练
在安装完kenlm后就可以开始训练语言模型。首先通过编写程序(图1中的wrangle.py)将需要训练的唐诗语料输出为以空格间隔开的单字数据,通过管道输入kenlm程序训练。这一步的输出是一个arpa格式的通用语言模型。这里选择训练4-gram 模型。试验过训练3-gram、5-gram模型,但效果还是4-gram稍好一些。
图1 训练过程
在第一步得到的arpa语言模型的内容如图2所示,其中,存储的是各个字词对数形式的概率。因此未来在调用时,概率的乘除运算可以简化为加减。利用kenlm提供的工具可以进一步把模型压缩到二进制格式,得到占用更小的klm格式文件以供后面使用,如图3。这样就得到了一个4-gram语言模型,接下来使用它进行分词的操作。
图2 arpa模型文件内部结构
图3 转换模型格式
3.3 分词
这里利用GitHub上Jiajie Yan实现的Jiayan项目[8]作为基础,基于唐诗特定结构修改代码,以进行最后的分词。Jiayan是一个古汉语处理的NLP工具包,它的分词功能就是基于上述的无监督分词方法实现的;其具有丰富的功能,我们主要利用的是它tokenizer模块中的hmm_tokenizer.py程序,修改它所使用的训练模型、转移概率,以及添加我们自己的干预方法。这里我们提供一个增加了诗词结构干预的分词器 tang_tokenizer.py [9],里面的intervene_tokenize方法可以将输入的字符串输出为由分词完毕的字词组成的列表。以下是几个需要注意的点:
1)如果面向古文分词领域,既可以使用自己训练得到的语言模型,也可以使用Jiayan作者已经提供的模型 [8]。该模型的训练语料以文言典籍为主,也包括了诗经、全唐诗全宋词等。在测试中,我们使用单纯“全唐诗全宋诗”语料训练得到了一个模型。原本以为会更加好用,但是在实测之下发现还是Jiayan作者提供的全覆盖模型效果更好,因为它对生僻词的识别能力更强。比如,我们的模型中无法识别 ”彼苍“ 这个词,但是具有更大覆盖范围的模型(如覆盖了诗经文本的Jiayan语言模型)就可以识别出来。2)转移概率是直接设定的,可以根据需要调整以适应特定项目控制多字成词比例的需求。Jiayan作者提供的转移概率已经较为合理,可以保留。3)干预方法的主要内容就是本文上一章分词原理中所说明的两种。在实际分词程序编写中,使用会有先后。这里选择先进行基于断词习惯的干预,再进行基于对仗的干预。因为前一阶段的断词依据更加充分,而且可以减少后一阶段的计算量。需要分词的时候可以直接在python中安装Jiayan包,使用封装好的分词方法分词。在本次尝试中由于对程序作了修改,因此是通过编写相应的测试文件,调用tokenizer中的函数进行分词。下图4、5所示为部分测试代码与结果。
图4 测试代码示例
图5 测试结果示例
4
实验结果
这里拿现代汉语的分词工具jieba分词、Jiayan分词器及我们的修改版的分词结果对比,以卢频《失题》为例:
jieba分词:春泪 | 烂 | 罗绮 , 泣声 | 抽恨 | 多 。莫滴 | 芙蓉 | 池 , 愁伤 | 连蒂荷 。壹朵 | 花叶 | 飞 , 壹枝花 | 光彩 。美人惜 | 花心 , 但愿 | 春长 | 在 。
jiayan:春 | 泪 | 烂 | 罗绮 , 泣声抽恨 | 多 。莫 | 滴 | 芙蓉 | 池 , 愁 | 伤 | 连蒂 | 荷 。壹 | 朵花 | 叶 | 飞 , 壹 | 枝花 | 光彩 。美人 | 惜花 | 心 , 但愿 | 春 | 长 | 在 。
基于jiayan并进行干预:春 | 泪 | 烂 | 罗绮 , 泣声 | 抽恨 | 多 。莫 | 滴 | 芙蓉 | 池 , 愁 | 伤 | 连蒂 | 荷 。壹 | 朵 | 花 | 叶 | 飞 , 壹 | 枝 | 花 | 光彩 。美人 | 惜花 | 心 , 但愿 | 春 | 长 | 在 。
从这个例子中可以看出,利用无监督的隐马尔可夫模型分词得到的结果对古汉语词汇的切分较好。经过进一步的干预之后,又可以纠正一些低级的错误,使得整体分词结果更加符合语感,有一定的改进效果。
5
总结
近年来,出现了许多AI写诗这样的项目,由于诗歌的语义并不需要特别明确,因此自动写诗是易于实现的。但是机器写出的诗歌仍然有许多缺点,比如缺少情感与情绪的表达。我们反过来看,或许可以明白依靠统计分析去理解诗歌的真正涵义也是不可能的。因此,本文所介绍的分词方法得到的结果,也只适合在宏观层面上观察所选的诗歌语料而使用。
当然大部分时候使用现有的、基于大规模分词语料训练的分词工具是最好的选择,但在面对古诗文处理任务时,现有的分词工具无法很好地匹配研究的需要。这种情况下,也没有很多现成的分词语料可用于训练,因此只能采用无监督分词的方式。最终通过这种方式分词,所得到的是一个以古汉语用语习惯的诗句切分结果,分词的效果肯定不是最好的。就目前的需求来看,如果要直接使用无监督分词的结果,就得接受它的局限性,即分词精度不够高。在研究中要意识到这种局限性并把它考虑进结果分析中。如果有更好的语言模型,或许可以提高一些结果的准确性[1],这也是未来工作可以尝试的方向。与人工分词相比,机器分词有一些明显的优点。除了速度够快以外,其分词的标准至少也是统一的。不过如果真的需要使用,一定程度的人工校对是必要的。
注:本文为非专业人士撰写,不保证内容完全有效、正确,欢迎读者批评指正。
6
参考资料
[1] 苏剑林. (Sep. 12, 2016). 【中文分词系列】 5. 基于语言模型的无监督分词 [Blog post]. Retrieved from https://spaces.ac.cn/archives/3956
[2] 苏剑林. (Aug. 19, 2016). 【中文分词系列】 3. 字标注法与HMM模型 [Blog post]. Retrieved from https://kexue.fm/archives/3922
[3] 忆臻. (May. 23, 2019). 自然语言处理中N-Gram模型介绍 [Blog post]. Retrieved from https://zhuanlan.zhihu.com/p/32829048
[4] Matrix67. (Jun. 8, 2012). 互联网时代的社会语言学:基于SNS的文本数据挖掘 [Blog post]. Retrieved from http://www.matrix67.com/blog/archives/5044
[5] 劉昭麟,張淳甯,邱偉雲等. 《全唐詩》的分析、探勘與應用-風格、對仗、社會網路與對聯 [C]. 計算語言學研討會會刊, 2015: 43-57.
[6] 老街味道. (Dec. 11, 2018). 诗词创作必备知识 [Blog post]. Retrieved from https://zhuanlan.zhihu.com/p/52068512
[7] Kenneth Heafield. KenLM Language Model Toolkit [Blog post]. Retrieved from https://kheafield.com/code/kenlm/
[8] Jiajie Yan. (Aug. 2019). 甲言Jiayan [source code]. https://github.com/jiaeyan/Jiayan
[9] SHAPC lab. 基于唐诗特定结构修改实现的分词器 [source code].https://github.com/1153470104/Jiayan/blob/master/jiayan/tokenizer/tang_tokenizer.py
编辑 / 沈孙乐
校对 / 张舒