0%

人工智能诗词识别

“诗者,志之所之也。在心为志,发言为诗”

————《毛诗·大序》

用统计判别的方式区分诗歌作者

问题重述

用十首杜甫和李白的五言诗歌作为训练样本,使用统计判别的方法判断“白水绕东城”该诗句出自哪位诗人?并最有可能出现在哪一句?

诗歌数据收集如下:DuFu/LiBai-github

问题分析

针对这十组诗歌,首先分析文本中哪些特征值得被我们选择。由于这些特征以文本的形式存在,下一步考虑如何将这些文本特征转化为数据。
分别针对两个问题:判断诗人;判断位置,选择不同的分类数目。由于不知道特征的概率分布,选择非参数估计方法进行类概率密度估计。最后基于最小风险准则进行类别判断。

从文本到数字

诗歌是纯文本信息,无法直接处理。首先我们要将文本转化数字。

转化过程中要考虑如下两点

  1. 文本信息的选择:要转化哪些文本中的信息
  2. 文本的转化方式:如何将这些信息转化成数字

文本信息的选择

如何选择文本信息?哪些文本信息是有价值的?哪些信息是可以忽略的?这个必须根据诗歌的特点进行判断!

正如引言所述,诗者,志之所之也。在心为志,发言为诗。诗歌表达人的情感,怀抱在心则为情感意志,用语言把它说出来就是诗。这句话里面包含诗歌文本中最重要的两个信息:其一是情感,文本上对应着意象;其二是言说,文本上对应着平仄。

除此之外,根据所掌握的诗歌知识和搜索结果,诗歌里的有效信息还有许多。总结如下:

  • 平仄
  • 韵脚
  • 意象
  • 对仗

从文本到数字

平仄提取

==诗歌不同位置的平仄顺序不同,统计平仄出现顺序可能可以推断出诗句出现的位置。==

平仄指的是汉字读音的音调,古语中对应平声、上声、入声和去声。但是随着语言流变,古语发音与现在已有不同。在普通话中,四声声调为:阴平(第一声)、阳平(第二声)、上声(第三声)、去声(第四声),其中,第一声、第二声是平声;第三声、第四声是仄声。

声调位置 字例 拼音 平仄
阴平声 mā(第一声)
阳平声 má(第二声)
上声 mǎ(第三声)
去声 mà(第四声)

分别将四种声调对应到$1234$,可以将文本转化成数字。
设$X_i$为五言诗句中某句的第$i$个字符,四种声调分别为$a_1,a_2,a_3,a_4$,则
$$
X_i=
\begin{cases}
1 & X_i\in a_1\
2 & X_i\in a_2\
3 & X_i\in a_3\
4 & X_i\in a_4\
\end{cases}
$$
中文汉字带有声调的元音字母只有六个,分别是ā ō ē ī ū ü。每个句子都对这六个元音字母进行一次判断,可以得到对应的声调数字
实例
处理前的拼音:Chuáng qián míngyuèguāng
处理后的数字:22241

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 将文本转化成四声调,每五个声调为列表中一个元素返回。
def Text2tone(filename):
with open(filename, "r", encoding='UTF-8') as f:
tone = []
for line in f.readlines():
line = line.strip('\n') #去掉列表中每一个元素的换行符
linetone = Pinyin2tone(line)
tone.append(linetone)
return tone

# 返回五个声调
def Pinyin2tone(text):
linetone = []
for str in text:
if str == 'ā' or str == 'ī' or str == 'ū' or str == 'ē' or str == 'ō':
linetone.append(1)
elif str == 'á' or str == 'í' or str == 'ó' or str == 'ú' or str == 'é':
linetone.append(2)
elif str == 'ǔ' or str == 'ǎ' or str == 'ǒ' or str == 'ě' or str == 'ǐ' or str == 'ǚ':
linetone.append(3)
elif str == 'è' or str == 'ì' or str == 'à' or str == 'ù' or str == 'ò':
linetone.append(4)
return linetone

按照这个方法可以分别的到李白与杜甫的数字声调列表。根据文字的平仄关系,通过统计判断可以推断诗句出现的位置

韵脚提取

==不同的韵脚抒发的情感不同,因此诗人对不同韵脚的使用偏好也不一样。韵脚也许可以区分诗句作者。==

韵脚是一般是句末押韵的字。就唐诗而言,一般每两句一个韵脚。比如,“床前明月光,疑是地上霜”韵脚为 ang

将同一作者所有诗文的韵脚提取出来,由于不同韵脚之间是离散关系。统计不同作者每种韵脚出现的次数,可以得到有关韵脚的最大似然概率

判断作者

诗文一共分为两类,第一类为作者是李白,第二类为作者是杜甫,故
$$
w_1=LiBai \w_2=DuFu
$$
通过韵脚提取我们可以得到不同韵脚的最大似然概率,如韵脚 ‘eng’,$N$ 为韵脚总个数 ;$k$ 为某种特定韵脚的个数,这里默认窗宽为 $1$ ,则
$$
p(eng|LiBai) = \frac{k}{N}
$$
经过简单的计算得到,
$$
p(eng|DuFu)= 0.19230769230769232\
p(eng|LiBai)=0.05263157894736842
$$
依据贝叶斯最小风险准则
$$
\frac{p(eng|DuFu)}{p(eng|LiBai)}=3.653 > 0.730 = \frac{p(LiBai)}{p(DuFu)}
$$
那么根据结果认为 “白水绕东城” 这句诗词出自杜甫

判断出现句数

背景

  1. 诗句只在 1 2 3 4 四个位置出现
  2. 训练样本中四个位置的诗句数量相等,也就是说每个类别的先验概率相等

符号

符号 说明
$w_i,i=1,2,3,4$ 类别:诗句出现的四种可能位置
$p(w_i)$ 类别$w_i$的先验概率
$p(w_i $|$ x)$ 后验概率
$p(x$|$w_i)$ 最大似然概率密度
$x^i_j$ 样本:第$i$个类别的第$j$个样本
$x$ 待估计样本

分析
训练样本中有多条已知类别的样本,即多条已经知道位置的诗句。由于不知道样本的概率分布函数,于是选择非参数估计法估计概率密度。但是训练样本的个数较少,利用窗函数的概率密度估计区间中可能样本点较少。于是采用$k_n$ 近邻法估计出总体的概率密度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def KnnDensityEstimation( X, x, knn ):
"""
X is the sample set;
x is the target;
knn is the number of sample;
prob = knn / N / V;
"""

N = np.size( X )
distances = Distance( X , x )
dis_near = np.array([])
for i in range( knn ):
dis_near = np.append( dis_near , distances.min() )
index = np.where( distances == np.min( distances ) )
distances[index] = np.max( distances )
radius = np.max( dis_near )
V = 2 * radius
prob = knn /( N * V )
return prob

def Distance( X , observation ):
distance = np.array([])
for x in X:
x_norm = np.linalg.norm( x - observation )
distance = np.append( distance , x_norm )
print('\n')
print(distance)
return distance

目标语句 $x$ 的数字声调为:2 3 4 1 2

估计得到的最大似然概率分别为:
$$
p(x|w_1)=0.0037\
p(x|w_2)=0.0037\
p(x|w_3)=0.0037\
p(x|w_4)=0.0042\
$$
因为四类训练样本的数量相同,所以
$$
p(w_1)=p(w_2)=p(w_3)=p(w_4)
$$
只比较似然概率就可以了。
对于多类问题,判决结果为似然概率最大的类别
$$
若P(w_i|x)=\underset{j}{\max}[P(w_j|x)], 则x\in w_i
$$

因此应将目标语句 $x$ 判给 $w_4$ 类

code

结果分析

很不幸,

《送友人》
唐·李白
青山横北郭,白水绕东城。
此地一为别,孤蓬万里征。
浮云游子意,落日故人情。
挥手自兹去,萧萧班马鸣。

这首诗作者是李白,而我们的结果是杜甫;白水绕东城,是第2句。训练出来的统计判别模型认为这是第4句。

  • 有没有可能换一句话能正常判断?

随意从网上选取

《遣意二首》
唐·杜甫
啭枝黄鸟近,泛渚白鸥轻。
一径野花落,孤村春水生。

使用韵脚 ‘ing’ 进行尝试
$$
\frac{p(eng|DuFu)}{p(eng|LiBai)}=0.974 > 0.730 = \frac{p(LiBai)}{p(DuFu)}
$$
认为这首诗作者是杜甫,这首诗作者也确实是杜甫

分别使用这首诗的 1 2 3 4 句进行判断,判断结果分别为

类别 似然概率
啭枝黄鸟近 泛渚白鸥轻 一径野花落 孤村春水生
1 0.01140445 0.01140445 0.01235641 0.01140445
2 0.01140445 0.01140445 0.011198947 0.014814815
3 0.013250773 0.012096246 0.010819211 0.01140445
4 0.010475656 0.012096246 0.012096246 0.011198947
更加不幸了
  • 有没有可能增加数据集能提高判断句数正确率?
    于是从网上又找了40首诗歌 MoreText

再次进行判断,“白水绕东城”的似然概率密度估计为:
$$
p(x|w_1)=0.0036350817\
p(x|w_2)=0.0032513211\
p(x|w_3)=0.0035862068\
p(x|w_4)=0.0034508291\
$$
达咩,判断为第一句

那我们用《遣意二首》再试试?

类别 似然概率
啭枝黄鸟近 泛渚白鸥轻 一径野花落 孤村春水生
1 0.006136051 0.006627693 0.006136051 0.006417236
2 0.006136051 0.006417236 0.005739751 0.006417236
3 0.007168383 0.006461493 0.006461493 0.006461493
4 0.006461493 0.006461493 0.006461493 0.006009066

虽然结果不尽人意,但是我们惊奇的发现:
如果 $w_1$ 类对应第二句; $w_2$ 对应第四句;$w_3$ 类对应第一句; $w_4$ 类对应第三句, 正确率还挺高的。

这是不是另外一种正确呢?

总结

  1. 文本转拼音有轻声,没有音调标注。只能手工解决。
  2. 统计判别来估计概率密度不太行,样本较少。
  3. 文本指标不容易量化。

学到了

  1. 复习了python

附录

训练文本资料以及程序代码:我的仓库