马尔可夫链文本生成的简单应用:不足20行的Python代码生成鸡汤文

2018年01月06日 由 yuxiangyu 发表 403936 0
提到自然语言的生成时,人们通常认为要会使用高级数学来思考先进的AI系统,然而,并不一定要这样。在这篇文章中,我将使用马尔可夫链和一个小的语录数据集来产生新的语录。

马尔可夫链


马尔可夫链是一个只根据先前事件来预测事件的随机模型。举一个简单的例子:我的猫可能的状态变化。我有一只猫,它一般都是在吃、睡或者玩。它大多时间在睡觉。不过,她偶尔会醒来吃点东西。通常情况下,吃完以后,她会变得很活泼,开始玩玩具,然后她要么回去睡觉,要么再次吃东西(我想他家的猫可能是橘色的)。


我的猫的状态可以很容易地用马尔可夫链建模,因为它决定接下来做什么,取决于它以前的状态。它不太可能醒来后马上开始玩,但在她吃完猫粮之后就很有可能开始玩。这些状态转换也可以用状态转换图说明:


马尔可夫链文本生成的简单应用:不足20行的Python代码生成鸡汤文


每个圆圈代表一个状态,箭头指向下一个状态,每个箭头旁边的数字是从一个状态转换到另一个状态的概率。正如你所看到的,状态转变的几率完全基于以前的状态。



马尔可夫链的文本生成


马尔可夫链文本生成的思想与此相同,即试图找出某个词出现在另一个词之后的概率。为了确定转换的概率,我们用一些例句来训练模型。


打个比方,我们可以用下面的句子来训练一个模型。


I like to eat apples.
You eat oranges.


只从训练数据中我们可以得出的结论是,“I”,“like”,“to”和“eat”都是这种顺序,而“you”和“eat”也总是在一起。然而,在“eat”这个词之后出现“oranges”或“apples”的概率是相等的。转换图如下:


马尔可夫链文本生成的简单应用:不足20行的Python代码生成鸡汤文


这两个训练句子只能够产生两个新的句子。接下来,我用下面的四个句子训练了另一个模型。


my friend makes the best raspberry pies in town
i think apple pies are the best pies
steve thinks apple makes the best computers in the world
I own two computers and they're not apple because I am not steve or rich


由四个句子训练的模型,它的转换图要比两个大得多。


马尔可夫链文本生成的简单应用:不足20行的Python代码生成鸡汤文


即使这个图与典型的马尔可夫链转换图看起来差异很大,但其背后的主要思想是一样的。路径从“START”节点开始,按概率选取下列单词直到结束节点。选取单词的概率用连接的粗细表示。


上面的模型能够产生数百个独特的句子,即使是只有四个句子的训练。


马尔可夫链文本生成的简单应用:不足20行的Python代码生成鸡汤文



代码


生成器的代码非常简单,除了python的random模块外,不需要其他额外的模块或库。它由两部分组成,一部分用于训练,另一部分用于生成。



训练


训练代码构建了我们稍后用于生成句子的模型。我用字典(给定句子的所有单词)作为模型; 以单词作为关键帧,并将选取下个单词的概率列表作为相应的值。例如,前两行已经训练过的模型的字典:“I like to eat oranges”,“You eat apples”如下:



{'START': ['i', 'you'], 'i': ['like'], 'like': ['to'], 'to': ['eat'], 'you': ['eat'], 'eat': ['apples', 'oranges'], 'END': ['apples', 'oranges']}

我们不需要计算下一个单词出现的概率,因为如果它们出现的概率较大,那么他们会在选取下个单词的列表中出现好几次。例如,如果我们加上“we eat apples”这个额外的训练语句,“eat”这个词之后的两个句子出现“apples”这个词,因此有更高的概率。这个更高的概率通过在“eat”的列表中出现两次的方式插入模型字典。
{'START': ['i', 'we', 'you'], 'i': ['like'], 'like': ['to'], 'to': ['eat'], 'you': ['eat'], 'we': ['eat'], 'eat': ['apples', 'oranges', 'apples'], 'END': ['apples', 'oranges', 'apples']}

此外,在上面的模型字典中还有两个附加项,“START”和“END”,它们表示生成的句子的开始和结束词。
for line in dataset_file:
line = line.lower().split()
for i, word in enumerate(line):
if i == len(line)-1:
model['END'] = model.get('END', []) + [word]
else:
if i == 0:
model['START'] = model.get('START', []) + [word]
model[word] = model.get(word, []) + [line[i+1]]

生成


生成器部分由一个循环组成。它首先选择一个随机的启动词,并将其附加到一个列表。然后在字典中搜索它下一个可能的单词列表,随机选取其中一个单词,将新选择的单词附加到列表中。它继续在可能性的列表中随机选择下一个单词,重复此过程直到它到达结束词,然后停止循环,并输出生成的单词序列或者说鸡汤。



import random 

generated = []
while True:
if not generated:
words = model['START']
elif generated[-1] in model['END']:
break
else:
words = model[generated[-1]]
generated.append(random.choice(words))

我现在使用马尔可夫链生成的是鸡汤文。当它们作为文本生成器时,你可以提供任何输入,它会按你提供的输入生成类似的文本。


“Don't think of the overwhelming majority of the impossible.”
“Grew up your bliss and the world.”
“what we would end create, creates the ground and you are the one to warm it”
“look and give up in miracles”

以上引用框中所有的句子都是由计算机生成的,使用的程序python代码不足20行。


马尔可夫链文本生成器也可以混合不同类型的文本。例如,在我最喜欢的电视节目之一Rick and Morty中,有一个叫Abradolf Lincler的人物,他是林肯和希特勒的混合体。如果你对此感兴趣,同样可以通过将两位领导人的演讲作为训练数据提供给马尔可夫链文本生成器来生成混合体会说的内容。


http://rickandmorty.wikia.com/wiki/Abradolf_Lincler
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
写评论取消
回复取消