用Python和Theano实现RNN

2017-07-03

这是RNN教程的第二部分,第一部分RNN介绍
本文代码托管在Github上。
我们将会用Python从头实现一个递归神经网络(RNN)并用Theano进行优化。我们将跳过对理解RNN非必要的代码,完整版的代码可以查看Github

语言建模

我们的目标是用RNN建立一个语言模型。假设我们有一句含有$m$个单词的句子,语言模型允许我们预测句子在给定数据集中的概率:
$P(w_1,...,w_m)=\prod_{i=1}^mP(w_i|w_1,...,w_{i-1})$
换句话说,一个句子的概率等于每个单词在已经给定(出现)的单词作为条件的情况下,条件概率的乘积。所以,句子“He went to buy some chocolate.”的概率等于单词“chocolate”在“He went to buy some”下的概率,乘上“some”在“He went to buy”下的概率,乘上“buy”在“He went to”下的概率,乘上“to”在“He went”下的概率,乘上“went”在“He”下的概率,乘上“He”的概率。
那么这样做有什么用?为什么我们要计算一个句子的概率呢?
首先,这样的模型可以用作评分机制。举个例子,机器翻译系统通常会为输入的句子生成多个候选句子,我们可以用语言模型去决策,选择最有可能的句子。类似的评分机制也可以用在语音识别领域。
解决语言建模问题的时候,我们还有个意外收获:因为我们可以根据给定前面内容,预测下一个单词出现的概率,我们可以用它来生成文本。这就是生成模型。给定句子的一部分内容,我们从预测概率中抽取下一个单词,重复这一过程,直到生成一个完整的句子。Andrej Karparthy的一篇博文中展示了这一成果。他用单个字符而不是完整的单词进行训练,建立起来的模型可以生成从莎士比亚风格的文字到Linux代码等各种各样的文本。
需要注意的是,在上面的公式中,每个单词的条件概率是基于前面出现的所有单词的。但是在实践中,由于计算或者内存的限制,模型很难捕获这种长程依赖(long-term dependencies)关系。通常情况下,RNN仅能捕获前几个单词的关系,再早一点出现的单词就无能为力了。所以,尽管理论上RNN可以捕获这种长程依赖(long-term dependencies),但是在实际运用的时候它更复杂一些。我们将在文章的后面探讨这一问题。

训练集和预处理