这篇关于LSTM,GRU的原理和实现部分还需要再完善一下…后期会更新的。
RNN简介
普通的网络上一次输入对下一次的输入的结果不会有影响,但是难免遇到需要记忆的场景。RNN与原先网络不同在于其保存上一次的输入,并赋予一个权重U加到本次的输出结果中。
普通网络:
y
i
=
a
c
t
i
v
a
t
i
o
n
(
w
∗
x
i
+
b
)
y_{i} = activation(w*x_{i}+b)
yi=activation(w∗xi+b)
SimpleRNN:
y
i
=
a
c
t
i
v
a
t
i
o
n
(
w
∗
x
i
+
u
∗
y
i
−
1
+
b
)
y_{i} = activation(w*x_{i}+u*y_{i-1}+b)
yi=activation(w∗xi+u∗yi−1+b)
LSTM层:
y
i
=
a
c
t
i
v
a
t
i
o
n
(
w
∗
x
i
+
u
∗
y
i
−
1
+
v
∗
c
i
+
b
)
y_{i} = activation(w*x_{i}+u*y_{i-1}+v*c_{i}+b)
yi=activation(w∗xi+u∗yi−1+v∗ci+b)
SimpleRNN
代码实现
import numpy as np
timesteps = 20 #输入序列的时间步数
input_features = 4 #输入数据维度
output_features = 8 #输出数据维度
inputs = np.random.random((timesteps, input_features)) #随机初始化输入数据
state_t = np.zeros((output_features,)) #初始状态,全0向量
w = np.random.random((output_features, input_features)) #初始化w
u = np.random.random((output_features, output_features)) #初始化u
b = np.random.random((output_features,)) #初始化b
successive_out_puts = [] #输出列表
for input_t in inputs:
output_t = np.tanh(np.dot(w, input_t) + np.dot(u, state_t) + b) #计算输出并使用tanh函数激活
successive_out_puts.append(output_t) #将本次输出加入结果列表
state_t = output_t #更新state_t
final_output_sequence = np.stack(successive_out_puts, axis = 0) #将输出列表改为numpy形式
print(final_output_sequence)
LSTM层
simpleRNN由于梯度消失问题,不可能学到长期依赖。LSTM允许过去的信息稍后重新进入,从而解决梯度消失问题。LSTM增加了一种携带信息跨越多个时间步的方法。携带信息用
c
i
c_{i}
ci表示,它将与输入连接和循环连接进行运算(与权重矩阵
v
v
v做点积,加上偏置,再应用激活函数)
GRU层
门控循环单元GRU的工作原理与LSTM相似,只是基于LSTM做了一些简化。
SimpleRNN实现IMDB分类
代码详解
from keras.models import Sequential
from keras.layers import Embedding, SimpleRNN
from keras.datasets import imdb
from keras.layers import Dense
from keras.preprocessing import sequence
import matplotlib.pyplot as plt
max_features = 10000 #作为特征的单词个数
maxlen = 500
batch_size = 32
print('Loading data...')
(input_train, y_train), (input_test, y_test) = imdb.load_data(num_words = max_features) #加载数据
print(len(input_train), 'train sequences')
print(len(input_test), 'test sequences')
print('Pad sequences (samples x time')
input_train = sequence.pad_sequences(input_train, maxlen=maxlen)
input_test = sequence.pad_sequences(input_test, maxlen = maxlen)
print('input_train shape:', input_train.shape)
print('input_test shape:', input_test.shape)
model = Sequential()
model.add(Embedding(max_features, 32))
#simpleRNN有两种输出模式,一种返回每个时间步连续输出的完整序列,一种只返回每个输入序列的最终输出
#默认为第二种
model.add(SimpleRNN(32))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss = 'binary_crossentropy', metrics=['acc'])
history = model.fit(input_train, y_train, epochs=10, batch_size=128, validation_split=0.2)
print(model.summary())
#绘制loss曲线和acc曲线
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1,len(acc) + 1)
plt.plot(epochs, acc, 'bo', label = 'Training acc')
plt.plot(epochs, val_acc, 'b', label = 'Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label = 'training loss')
plt.plot(epochs, val_loss, 'b', label = 'Validation loss')
plt.title('Training and Validation loss')
plt.legend()
plt.show()
运行结果
LSTM实现IMDB分类
代码详解:
只需要简单修改上文中的网络结构
model = Sequential()
model.add(Embedding(max_features, 32))
model.add(LSTM(32))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss = 'binary_crossentropy', metrics=['acc'])
history = model.fit(input_train, y_train, epochs=10, batch_size=128, validation_split=0.2)
print(model.summary())
运行结果:
GRU实现IMDB分类
代码:
#将model.add(LSTM(32))即可
model.add(GRU(32))
运行结果:
使用SimpleRNN、LSTM、GRU分别对Imdb进行二分类问题,差不多在3轮左右都收敛了,RNN和GRU准确率在0.85,LSTM准确率最高在0.875左右