pinyin

拼音输入法报告

实验环境

python3.10.13
需要安装tqdm

使用的语料库及数据预处理方法

使用了下发的sina_news_gbk,SMP2020语料库,
以及自己寻找的THUCNews语料库,下载链接http://thuctc.thunlp.org/#%E4%B8%AD%E6%96%87%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%E6%95%B0%E6%8D%AE%E9%9B%86THUCNews

数据预处理:对于每一条新闻,根据非中文字符进行分割,生成句子集合,即

1
2
3
for line in file:
sentences=re.split(r'[^\u4e00-\u9fa5]+',line)# 分割
sentences=[s for s in sentences if s]# 去除空字符串
之后以每个句子集合里的句子为单位统计字频,词频。
二字词、三字词频直接考虑句子中所有词即可。

基于字的二元模型

基本思路

将拼音翻译成句子,即求出使得最大的句子,但是推理复杂度太高,对上述公式简化为二元版本,每个字的生成只考虑其前一个字的影响。

对上式取对数,,将看做从的路径长度,就可以采用viterbi算法: 对于当前的拼音pyi,以所有这个读音的字为节点,需要获取从起点到这一层每个节点的最短路径。
因为已知起点到上一层节点的最短路径,所以对这一层每一个节点,遍历上一层节点即可得知到当前层的最短路径长度。

实验上

条件概率从语料库中习得,,所以需要统计所有字频以及二字词频。
由于可能为0,所以采用平滑,用代替。

效果

使用了sina_news_gbk和SMP所有数据进行训练,字准确率达到0.8405,句准确率达到0.3992,统计词频时间267s,生成所有句子总时间5.16s,平均生成一个句子时间为0.01032s

字准确率 句准确率
0.70 0.827316141356256 0.34930139720558884
0.75 0.8317096466093601 0.36327345309381237
0.80 0.8340019102196753 0.36327345309381237
0.85 0.8340019102196753 0.3652694610778443
0.90 0.8382043935052531 0.3772455089820359
0.95 0.8378223495702005 0.37924151696606784
0.99 0.8385864374403056 0.3912175648702595
0.999 0.8370582617000956 0.38922155688622756

随着参数的上升,准确率呈现上升的趋势,可见考虑两个字的概率还是优于单取决于字的概率。同时,参数非常接近1时,准确率反而下降,可能是因为语料中会有一些生僻的词,模型错误的学到了这些生僻词,忽略了字本身的概率,从而生成了不太常用的字与字的组合。

使用文件数 字准确率 句准确率
1 0.8290353390639924 0.34930139720558884
2 0.833810888252149 0.37524950099800397
4 0.8385864374403056 0.3912175648702595
8 0.8401146131805157 0.3932135728542914

典型例子分析

效果好的

  • 中国共产党员的初心和使命是为中国人民谋幸福为中华民族谋复兴
  • 消灭剥削消除两极分化最终达到共同富裕
  • 要把我们的祖国建设成为一个富强民主的国家

分析:这些句子很长,但是准确无误产生了,原因应该是语料库中相关的表述很多,句子中的二字词也比较多

效果差的

  • 北京首个举办过夏奥会与冬奥会的城市

分析:在生成句子的时候对上下文考虑的不够,北京市可能多次出现,导致京市是一个高频词汇,所以生成了北京市,但是这里应该为,这是由句子整体的结构决定的,不能简单考虑前后几个字。

  • 青藏大甩卖
  • 疫情以来一次在外就餐
  • 口罩防止交叉感染

分析 :这三个是由于多音字产生的误差,多音字中一个读音常用可能导致另一个读音出现的概率变高,因为只存储了字的出现概率,推理时并没有考虑同一个字不同读音的出现概率不同。比如第二句,“的”的读音为di,本来读音为di的“的”的概率并不高,但是读音为de的“的”的概率很高,这里生成时并没有对此区分产生了错误。要避免这种错误,需要对训练的数据加注音来区分。

复杂度分析

设一个拼音平均对应n个汉字,句子长为T,则推理需要T步,每一步遍历两层的全连接,需要O()时间,所以推理一个句子的时间复杂度为O()

预估时间,经测得,
测试进行1781326次log计算以及500次输入输出,时间为0.25s,所以每一条句子的推理时间约为20.64

空间上,首先需要存所有单字双字的出现次数,设汉字表中的汉字个数为N,这一步的空间复杂度为O()
对于每一次推理的每一个节点,只需记录起点到当前节点的最短路径以及这条路上自己的前一个节点,推理空间复杂度为O(),实际上前面已经使用过的节点可以释放掉,所以O(n)的空间就可以解决问题。 总空间复杂度为O()

基于字的三元模型

二元模型中推理字只考虑上一个字的影响,三元模型则考虑上两个字的影响。

实现上,对于当前层i,考虑与上一层全连接的所有二字词,需要记录以此二字词结尾的句子中概率最大的句子。按照路径的视角看,考虑两层全连接约个道路,需要知道以单条道路结尾的所有道路中概率最大的,在已知上一层这一数据的基础上,需要遍历与这条道路连接的上一层所有道路求得最大值。

效果

使用了sina_news_gbk和SMP所有数据进行训练,字准确率达到0.9144,句准确率达到0.6407,统计词频时间548s,生成所有句子总时间184s,平均生成一个句子时间为0.368s

字准确率 句准确率
0.70 0.9090735434574976 0.6187624750499002
0.75 0.9104106972301814 0.6287425149700598
0.80 0.9109837631327603 0.6367265469061876
0.85 0.9119388729703916 0.6407185628742516
0.90 0.9130850047755492 0.6467065868263473
0.95 0.914422158548233 0.6407185628742516
0.99 0.9130850047755492 0.6387225548902196
0.999 0.9130850047755492 0.6367265469061876

三元模型中,准确率的极大值出现在参数更小的情况中,可能因为三元模型更加倚重于字与字的联系,而语料中生僻的、没有完整意思的三元词更多,模型误学的概率更大,所以需要适当降低参数的值,使得模型考虑生成那些常用的字。

使用文件数 字准确率 句准确率
1 0.8773638968481375 0.5029940119760479
2 0.8976122254059217 0.5748502994011976
4 0.9062082139446036 0.5988023952095808
8 0.9130850047755492 0.6467065868263473

典型例子分析

效果好的

  • 清仓大甩卖

分析:三元模型在这个测例上得到了正确输出,但在训练上并没有额外考虑多音字,可能因为多结合了后面的da的读音才选择了清仓

效果差的

  • 北京市首个举办过夏奥会与冬奥会的城市
  • 中国市人民民主专政的社会主义国家

分析:这两个例子看出三元模型的视野仍旧不足,不能分析出整个句子的结构从而得到shi处应该填一个动词

复杂度分析

对于当前层,与上一层全连接会产生条道路,每条道路遍历与其连接的n条上一层的道路,共O(),所以总的时间复杂度为O()

预估时间,经测得,
测试进行32868613次log计算以及500次输入输出,时间为4.62s,所以每一条句子的推理时间约为39.83

空间上,需要储存汉字表中单字双字三字词的概率,为O(),推理时,每一层有条道路,每条道路储存一个最短路径值以及父节点,T层的空间就是O()。 总空间复杂度为O()

模型对比

相同参数选择下,两个模型字准确率对比

相同参数选择下,两个模型句准确率对比

相同训练文件数下,两个模型字准确率对比

相同训练文件数下,两个模型句准确率对比

结论:

  • 无论是在相同的参数选择下还是相同的训练语料下,三元模型比二元模型取得的效果都更好,但同时,推理时间由5s上升至184s,实际应用时需要权衡效果与效率。
  • 同时,注意到随着训练语料数的上升,两个模型的准确率都有所上升并逐渐放缓。在8个文件时,二元模型的增长几乎停滞,而三元模型还有增长空间,实践中在训练三元模型时加入了THUCNews数据库,字准确率达到0.93,句准确率达到0.6866,还是有不小的提升(不过训练文件的大小也扩大了一倍多,训练时间也来到了30min)。

其他评判标准

可以采用困惑度来评价模型

感受和建议

这次实验使用了viterbi算法来实现一个拼音输入法,写代码的过程中自己能看到程序的输出,以及定量的准确率,所以调参的时候也没有那么无聊,自己也对训练所需的语料的数量进行了一些测试,总体来说是挺有意思的。
也是第一次遇到一下子跑30min的代码,也是第一次遇到跑30min后因为内存不够被kill的情况(因为自己对所需要的语料没有概念所以加了很多数据硬训)。
暂无有建设性的建议。