看了Andrej Karpathy写的文章“The Unreasonable Effectiveness of Recurrent Neural Networks”。用RNN来学习某些作者的文章,然后用学习好的哦RNN网络来Generate句子,最后出来的结果看起来还挺有道理。再想想Theano tutorial中提供的elman RNN实现(在句子层次将Word Embedding和Classification一起做),觉得Recurrent Neural Networks模型真的很强大。(该文还说道用RNN来识别街景的文字,这不是抢CNN的饭碗吗)
Andrej Karpathy提供了源代码char-rnn,不过是用Torch+Lua写的。机器学习山头林立,框架众多,让我们这些追随者都有点不知所措了。最开始是VB,然后是C++,然后Matlab,等自己觉得 I can speak matlab之后,Python+Theano又来了。Theano学得差不多了,这帮人又搞了一个Torch+Lua,实在学不动了。(目前感兴趣的分布式平台scala都没有时间看) 从文章来看,应该是一个双层的RNN网络,决定用Theano来实现一下。
1 参考一下代码
char-rnn的基本框架应该是这样,即两层叠加的RNN:
y1 = rnn1.step(x)
y = rnn2.step(y1)
虽然不懂Lua,但是看起来和Python还是比较像。(还有if … end这种结构,看起来比Python好。) 分析一下主执行文件,主执行文件应该是这个:https://github.com/karpathy/char-rnn/blob/master/train.lua
require 'torch' # = import torch
require 'nn' # = import nn
local LSTM = require 'model.LSTM' # 使用LSTM,最常见的RNN
cmd = torch.CmdLine() # 获得command line
cmd:text() # = print ''
cmd:text('Train a character-level language model')
cmd:option('-rnn_size', 128, 'size of LSTM internal state') # 默认的RNN internal 大小为128
cmd:option('-num_layers', 2, 'number of layers in the LSTM') #两层的LSTM
local vocab_size = loader.vocab_size # 字符个数
protos.rnn = LSTM.lstm(vocab_size, opt.rnn_size, opt.num_layers, opt.dropout) # 构造两层 LSTM
protos.criterion = nn.ClassNLLCriterion() # 大概是目标函数
再看看https://github.com/karpathy/char-rnn/blob/master/model/LSTM.lua,我理解这是LSTM的类。
function LSTM.lstm(input_size, rnn_size, n, dropout) # n是层数,没有输出大小。这个例子应该输入大小和输出大小一致。
-- there will be 2*n+1 inputs
local inputs = {}
table.insert(inputs, nn.Identity()()) -- x #第一层的输入也需要前一层?
for L = 1,n do
table.insert(inputs, nn.Identity()()) -- prev_c[L]
table.insert(inputs, nn.Identity()()) -- prev_h[L]
end # 内部状态和输入,初始化为单位矩阵?
if L == 1 then # 如果是第一层,input_size就是X的大小
x = OneHot(input_size)(inputs[1])
input_size_L = input_size
else # 如果是第其他层,input_size就是内部状态的大小
x = outputs[(L-1)*2]
input_size_L = rnn_size
end
第一个层RNN的输出是否需要argmax一下再到下一层RNN?从代码来看似乎不需要。
2 用Theano来实现
使用Theano_lstm库来实现一个两层的LSTM RNN网络。使用的数据集是input.txt
,里面是若干Shakespear写的剧本。lstm_shake.py
文件构造一个基于字符的序列的模型,该通过学习Shakespear的剧本,希望能像Shakespear一样写剧本。
3 测试运行
运行little shakespear的例子。每50个Epoch,输入’T’作为首字母,然后采样输出的结果。
python lstm_shake.py
epoch 0, error=4504142.19
TPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
epoch 10, error=4346742.41
epoch 20, error=3667818.53
epoch 30, error=3452454.01
epoch 40, error=3378974.10
epoch 50, error=3290961.33
T I I It t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t
t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t
t t t t t t t t t t t t t t t t t t t t
epoch 60, error=3220026.99
epoch 70, error=3174889.48
epoch 80, error=3145530.92
epoch 90, error=3121806.02
epoch 100, error=3100589.85
T Ih tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt
tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt tt
tt tt tt tt tt tt tt tt tt tt tt tt tt t
epoch 110, error=3083279.73
epoch 120, error=3068120.72
只有CPU,非常慢。而且没有进行优化处理,句子长短不一,非常浪费。没有使用minibatch,内存占用非常高。另外,CPU的使用率也不高。
学习的效果似乎也不好,完全没法和Shakespear比。