前文
这篇文章首先介绍基础版的RNN,虽然在自然语言处理上已经有了Transformer和Bert模型,但是RNN在小规模数据集上还有很有用的
正文
怎样对持续数据来建模?
我们知道人类的大脑在阅读处理信息的时候,是从左到右,逐渐积累信息,当你阅读完一段话之后,脑子就已经积累的整段文字的大意。
RNN模型,输入输出的长度都不需要固定,适合文本,语音持续序列等数据
如下图,RNN每次看一个词,就会用状态h来积累阅读过的信息
整个RNN只有一个参数A,不论这条链有多长,参数A只有一个,最开始A随机初始化,然后利用训练数据来学习A
双曲正切函数
为什么需要这个激活函数呢
假设输入向量都是0,
状态会爆炸或者都等于0,用激活函数做nomalization,回到正1和负1之间,把激活函数的输出作为新的状态向量
整个参数的数量:h的维度*(h的维度+x的维度)
如下图所示,新的状态
h
t
是由旧状态
h
t
−
1
和新的输入
x
t
的函数生成的
h_t是由旧状态h_{t-1}和新的输入x_t的函数生成的
ht是由旧状态ht−1和新的输入xt的函数生成的
搭建神经网络
上一篇文章,我们使用线形规划二分类判断电影评论是正面还是负面的,这里改用RNN来解决这个问题,搭建神经网络
最底层是Word Embedding,它可以把词映射到向量X,利用交叉验证函数来选择最优的维度
再往上搭建一层Simple RNN Layer,输入的是词向量X,输出的状态是h,h的维度也是超参数,根据自己需要设置,应该用交叉验证来选出最好维度
将状态矩阵变成一个向量,经过Flatten
simple RNN 的缺点
is bad at long-term dependence
如下图,输出应该是Chinese,但是Simple RNN看不远,也不需要更多的上下文,最可能输出一种语言,但不一定是Chinese
总结
代码实现
'数据集读取与预处理'
# 此处使用Keras库自带函数进行简洁实现(从零开始实现请看上一节)
# 使用keras的embedding层处理文字数据(同样使用imdb数据集)
from keras.datasets import imdb
from keras import preprocessing
max_feature = 10000 # 词汇量(作为特征的单词个数)
maxlen = 500 # 在500个单词以后截断文本
(input_train, y_train), (input_test, y_test) = imdb.load_data(num_words=max_feature)
# y_train、y_test分别表示训练集和测试集的标签
# max_words=10000:只考虑数据集中前10000个最常见的单词
print(len(input_train), 'train sequences')
print(len(input_test), 'test sequences')
print('sequence 格式:(samples*time)')
input_train = preprocessing.sequence.pad_sequences(input_train, maxlen=maxlen)
input_test = preprocessing.sequence.pad_sequences(input_test, maxlen=maxlen)
# 此处相当于对齐序列(补0或者阶段评论)
print('input_train shape:', input_train.shape)
print('input_test shape:', input_test.shape)
'定于模型:Simple RNN'
from keras.models import Sequential # 调入Sequential模型,按顺序搭建神经网络层
from keras.layers import SimpleRNN, Dense, Embedding # 各种层
'词嵌入操作:降低输入向量维度'
embedding_dim = 32
model = Sequential()
model.add(Embedding(max_feature, embedding_dim, input_length=maxlen))
# 第一层是Embedding层,设定字典里10000个单词,Embedding层的输出是个500×32的矩阵,
# 只考虑每条电影评论中最后的500个单词,每个单词用32维的向量来表示
# 参数矩阵在此的维度是320000,矩阵的参数根据设定的每个单词表示的向量(32)*字典词个数10000得到
'Simple RNN Layer'
state_dim = 32
model.add(SimpleRNN(state_dim, return_state=False))
# return_state=False,不需要存储ht之前的状态
model.add(Dense(1, activation='sigmoid'))
# units :代表该层的输出维度或神经元个数,此处设定输出的维度为1
# activation=None:激活函数.但是默认 liner
'设定优化算法以及模型评价标准'
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
# optimizer: 优化器,loss:损失函数,metrics: 评价函数.
# 评价函数的结果不会用于训练过程中,可以传递已有的评价函数名称
'设置训练模型'
history = model.fit(
input_train, y_train,
epochs=10,
batch_size=128,
validation_split=0.2
)
# input_train:输入数据,y_train:标签,
# batch_size:整数,指定进行梯度下降时每个batch包含的样本数
# epochs:整数,训练终止时的epoch值
# validation_split:0~1之间的浮点数,用来指定训练集的一定比例数据作为验证集
model.summary()
'查看模型最终性能'
loss_and_acc = model.evaluate(input_test, y_test)
print('loss=' + str(loss_and_acc[0]))
print('acc=' + str(loss_and_acc[1]))
# loss=0.6762722058105469
# acc=0.80744