@knight
2016-01-14T22:03:17.000000Z
字数 3830
阅读 2231
神经网络
这是RNN教程的第二部分。第一部分在这里。
本文Github code
在这个部分我们会使用python和theano(GPU运算的库)完全从零开始实现一个RNN。全部代码可以在github获取到。我会跳过一些样板代码这对你理解RNN不是必需的,但是同样可以在gihub获取。
我们的目的是使用RNN构建一个语言模型。下面是定义。让我们看到有m个词的句子。一个语言模型让我们能预测观察句子的概率。
为什么这是有用的?为什么我们希望给观察句子分配概率?
首先这样的模型可以用作得分机制。例如,机器翻译系统从输入生成候选句子。你可以使用语言模型来选出最可能的句子。直观上讲,最可能的句子是语法最正确的。相似的得分也应用到语音识别系统。
处理语言模型的问题同样是一个很酷的方面。因为我们能通过给定先前词预测一个词的概率来生成一个新文本。这就是生成模型。给定一个存在的词序列,我们可以从概率预测中抽样生成下一个词,重复抽取直到得到整个句子。Andrej Karparthy在他的博客中描述了语言模型的能力。不同于词,他的模型在单词字符训练,能够生成所有的东西包括Shakespear
到linux code
。
值得注意的是上面所有的获取每个词的公式都是基于所有先前词的。由于计算能力和内存的限制,许多模型都很难表示这样的长距离依赖。这显然将先前词限制在了几个之内。在理论上RNN可以捕获长距离依赖,但是实际中它有一些复杂了。我们回来后面解释这个。
为了训练语言模型我们需要文本去学习。幸运的是,我们训练语言模型不需要类标的。我从Google's BigQuery下载了15,000 longish reddit
评论。我们的文本生成模型听起来有点像reddit评论。但是大多数机器学习项目第一件需要做的事都是预处理获得的数据得到正确的格式。
我们有原始的文本,但是我们希望基于每个词预测。这意味着我们必须从评论中切分句子,然后句子中切分单词。我们以空格划分评论,但是不能合适处理标点符号。"He left !"
应该有3个划分:"He","left","!"
.我们使用NLTK's的word_tokenize
和sent_tokenize
方法
文本中大部分词都只出现1或者2词。一个好的方法是移除这些地坪词。巨大的词表使得我们的模型训练很慢(我们会在后面谈论这个原因),因为我们没有许多上下文信息,我们不知道怎样正确的学习和使用它们。这个相当类似于人类的学习。为了学习怎样恰如其分的使用一个词,你需要观察它们在不同上下文的表现。
在我们的代码中,使用vocabulary_size
来限制词表数量(我设置的是8000,但那是感觉可以随意修改)。我们将词表中没有出现的所有词都替换为UNKNOWN_TOKEN
.例如,如果你的词表没有包含"nonlinearities"句子"nonlieraties are important in neural networks"将替换为"UNKNOWN_TOKEN are import in neural networks"。UNKNOWN_TOKEN
将成为词表的一部分,我们会预测其他词一样预测它。当生成新文本时再次替换 UNKNOWN_TOKEN
.例如,随机抽样出一个不在我们词表的单词,或者生成文本直到不包含unknown_token
我们希望能知道句子的开始和结尾。为此我们预先给一个特殊的SENTENCE_START
和SENTENCE_END
token.不禁要问,给定第一个切分是SENTENCE_START
,可能的下一个词是什么(句子中实际的第一个词)?
RNN的输入是向量而不是字符串。所以我们要在词和索引之间映射index_to_word
和word_to_index
.例如词"friendly"可能在索引2001.训练样例x可能是[0,179,341,416] 0对应SENTENCE_START。对应的标签y[179,341,416,1].记住我们的目的是预测下一个词。所有y只是向量x的偏移量,1 对应SENTENCE_END。换句话说,179的词是预测341的,也是实际的下一个词。
vocabulary_size = 8000
unknown_token = "UNKNOWN_TOKEN"
sentence_start_token = "SENTENCE_START"
sentence_end_token = "SENTENCE_END"
# Read the data and append SENTENCE_START and SENTENCE_END tokens
print "Reading CSV file..."
with open('data/reddit-comments-2015-08.csv', 'rb') as f:
reader = csv.reader(f, skipinitialspace=True)
reader.next()
# Split full comments into sentences
sentences = itertools.chain(*[nltk.sent_tokenize(x[0].decode('utf-8').lower()) for x in reader])
# Append SENTENCE_START and SENTENCE_END
sentences = ["%s %s %s" % (sentence_start_token, x, sentence_end_token) for x in sentences]
print "Parsed %d sentences." % (len(sentences))
# Tokenize the sentences into words
tokenized_sentences = [nltk.word_tokenize(sent) for sent in sentences]
# Count the word frequencies
word_freq = nltk.FreqDist(itertools.chain(*tokenized_sentences))
print "Found %d unique words tokens." % len(word_freq.items())
# Get the most common words and build index_to_word and word_to_index vectors
vocab = word_freq.most_common(vocabulary_size-1)
index_to_word = [x[0] for x in vocab]
index_to_word.append(unknown_token)
word_to_index = dict([(w,i) for i,w in enumerate(index_to_word)])
print "Using vocabulary size %d." % vocabulary_size
print "The least frequent word in our vocabulary is '%s' and appeared %d times." % (vocab[-1][0], vocab[-1][1])
# Replace all words not in our vocabulary with the unknown token
for i, sent in enumerate(tokenized_sentences):
tokenized_sentences[i] = [w if w in word_to_index else unknown_token for w in sent]
print "\nExample sentence: '%s'" % sentences[0]
print "\nExample sentence after Pre-processing: '%s'" % tokenized_sentences[0]
# Create the training data
X_train = np.asarray([[word_to_index[w] for w in sent[:-1]] for sent in tokenized_sentences])
y_train = np.asarray([[word_to_index[w] for w in sent[1:]] for sent in tokenized_sentences])
下面是实际的训练样例:
x:
SENTENCE_START what are n't you understanding about this ? !
[0, 51, 27, 16, 10, 856, 53, 25, 34, 69]
y:
what are n't you understanding about this ? ! SENTENCE_END
[51, 27, 16, 10, 856, 53, 25, 34, 69, 1]