马尔可夫链是一个只根据先前事件来预测事件的随机模型。举一个简单的例子:我的猫可能的状态变化。我有一只猫,它一般都是在吃、睡或者玩。它大多时间在睡觉。不过,她偶尔会醒来吃点东西。通常情况下,吃完以后,她会变得很活泼,开始玩玩具,然后她要么回去睡觉,要么再次吃东西(我想他家的猫可能是橘色的)。
我的猫的状态可以很容易地用马尔可夫链建模,因为它决定接下来做什么,取决于它以前的状态。它不太可能醒来后马上开始玩,但在她吃完猫粮之后就很有可能开始玩。这些状态转换也可以用状态转换图说明:
每个圆圈代表一个状态,箭头指向下一个状态,每个箭头旁边的数字是从一个状态转换到另一个状态的概率。正如你所看到的,状态转变的几率完全基于以前的状态。
马尔可夫链文本生成的思想与此相同,即试图找出某个词出现在另一个词之后的概率。为了确定转换的概率,我们用一些例句来训练模型。
打个比方,我们可以用下面的句子来训练一个模型。
I like to eat apples.
You eat oranges.
只从训练数据中我们可以得出的结论是,“I”,“like”,“to”和“eat”都是这种顺序,而“you”和“eat”也总是在一起。然而,在“eat”这个词之后出现“oranges”或“apples”的概率是相等的。转换图如下:
这两个训练句子只能够产生两个新的句子。接下来,我用下面的四个句子训练了另一个模型。
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
由四个句子训练的模型,它的转换图要比两个大得多。
即使这个图与典型的马尔可夫链转换图看起来差异很大,但其背后的主要思想是一样的。路径从“START”节点开始,按概率选取下列单词直到结束节点。选取单词的概率用连接的粗细表示。
上面的模型能够产生数百个独特的句子,即使是只有四个句子的训练。
生成器的代码非常简单,除了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']}
{'START': ['i', 'we', 'you'], 'i': ['like'], 'like': ['to'], 'to': ['eat'], 'you': ['eat'], 'we': ['eat'], 'eat': ['apples', 'oranges', 'apples'], 'END': ['apples', 'oranges', 'apples']}
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))
我现在使用马尔可夫链生成的是鸡汤文。当它们作为文本生成器时,你可以提供任何输入,它会按你提供的输入生成类似的文本。
以上引用框中所有的句子都是由计算机生成的,使用的程序python代码不足20行。
马尔可夫链文本生成器也可以混合不同类型的文本。例如,在我最喜欢的电视节目之一Rick and Morty中,有一个叫Abradolf Lincler的人物,他是林肯和希特勒的混合体。如果你对此感兴趣,同样可以通过将两位领导人的演讲作为训练数据提供给马尔可夫链文本生成器来生成混合体会说的内容。