Keras 的RNN实现有三种,分别为:
- SimpleRNN
- GRU
- LSTM
一个最简单的RNN数学公式表达就是:
Y
n
+
1
=
W
.
∗
X
+
U
.
∗
Y
n
+
b
Y_{n+1} = W.*X + U.*Y_{n}+b
Yn+1=W.∗X+U.∗Yn+b
我们就是要训练Trainning data的到最佳的W、U、b
如果我们给定
input_data.shape=(100, 32)
output_data.shape=(64,)
那么明显:
W.shape=(64, 32)
U.shape=(64, 64)
b.shape=(64,)
python实现代码如下:
timesteps = 100
input_features = 32
output_features = 64
inputs = np.random.random((timesteps, input_features))
state_t = np.zeros((output_features,))
W = np.random.random((output_features, input_features))
U = np.random.random((output_features, output_features))
b = np.random.random((output_features,))
successive_outputs = []
shape (input_features,).
for input_t in inputs:
output_t = np.tanh(np.dot(W, input_t) + np.dot(U, state_t) + b)
successive_outputs.append(output_t)
state_t = output_t
final_output_sequence = np.concatenate(successive_outputs, axis=0)
这样我们可以得到序列长度为100的完整输出序列或者只得到一个最终值。如果实在keras中我们可以通过设置
return_sequences=True / False
来控制。
如果我们使用我们的keras API , 建立一个SimpleRNN
的model
model = Sequential()
model.add(Embedding((input_dim=10000, output_dim=32, input_length=100))
# model.add(SimpleRNN(32, return_sequences=True))
model.add(SimpleRNN(32))
model.summary()
input_dim
: 特征数大小max_feature
, 如果用于文本处理的话就是词典的词量
output_dim
: 输出维度,用于文本序列的话就是词向量维度。
input_length
: 序列的长度
SimpleRNN((32))
:返回维度为32的向量,如果设置returen_sequences=True
,那么返回维度为32的向量序列。
为什么要将循环层堆叠?
就像上面这张图,如果仅一层RNN的话,最终输出仅关联前面入一次,如果多层的话,输入前面数据多次,这样可以保证数据更不容易丢失。
对于长序列普通RNN会出现梯度消失问题,LSTM和GRU就是为了解决这个问题而设计的。
LSTM 原理图:
可以发现和简单RNN相比,LSTM新增了三个门:
- Input Gate: 控制那些输入可以进入记忆中心
- Forget Gate: 是否清除记忆中心的数据
- Output Gate: 控制是否讲其输出
李宏毅机器学习视频里讲了一个例子,非常好可以去看一下就明白了。
可见门的开关都是由训练数据生成的。
那么我们如何使用这样的一个model去生成为本呢。
假设我们已经训练好了一个LSTM model
# dict_len=10000, input_length=20
model = Sequential()
model.add(Embedding(input_dim=dict_len, output_dim=32, input_length=max_len))
model.add(Conv1D(filters=32, kernel_size=3, padding='same', activation='relu'))
model.add(MaxPooling1D(pool_size=2))
model.add(LSTM(units=256))
model.add(Dropout(.2))
model.add(Dense(units=dict_len, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
model.summary()
并且有输入样本,算上标点符号长度刚好等于input_length
start_doc = ‘Alice is a little girl, who has a dream to go to visit the land in the time.’
- 将输入文本转换为词向量序列
values
- load_model(), load_weight()
- 迭代生成文本
for i in range(words):
x = make_dataset(values)
prediction = model.predict(x, verbose=0)
prediction = np.argmax(prediction)
values.append(prediction)
new_document.append(prediction)
values = values[1:]
易发现本质上还是通过一个sequence-->word
,并且都是一个word一个word的生成,后面会介绍如何大批量文本的生成。