原创帖子,转载请说明出处
一、RNN神经网络结构
RNN隐藏层神经元的连接方式和普通神经网路的连接方式有一个非常明显的区别,就是同一层的神经元的输出也成为了这一层神经元的输入。当然同一时刻的输出是不可能作为这个时刻的输入的。所以是前一个时刻(t-1)的输出作为这个时刻(t)的输入。
序列结构展开示意图,s为隐藏层,o为输出层,x为输入层,U为输入层到隐层的权重矩阵,V则是隐层到输出层的权重矩阵,这个网络在t时刻接收到输入 之后,隐藏层的值是 ,输出值是 。关键一点是, 的值不仅仅取决于 ,还取决于 。
二、RNN应用范围
RNNs主要用于处理NLP类的问题,如词向量表达、语句合法性检查、词性标注等。在RNNs中,目前使用最广泛最成功的模型便是LSTMs(Long Short-Term Memory,长短时记忆模型)模型,该模型通常比vanilla RNNs能够更好地对长短时依赖进行表达,该模型相对于一般的RNNs,只是在隐藏层做了手脚。下篇文章会对LSTM进行介绍。
三、使用RNN进行影评情感分析
0x00 实验环境
tensorflow2.0,此版本的keras已经被包含到tf中,导入keras时注意加入tensorflow前缀,如果想关闭vision2.0版本的特性的话,可以使用:
import tensorflow.compat.v1 as tf tf.disable_v2_behavior()
0x01 数据预处理
导入数据集和相应的库,这里使用imdb数据集
#导入imdb影评库 from tensorflow.keras.datasets import imdb from tensorflow.keras.preprocessing import sequence
之后我们对数据集与训练集进行划分,下面的vocab_num代表着我要从imdb数据库中导入10000条数据,第二行的左括号与右括号代表训练集与测试集的划分
#划分训练集与测试集 #label中的0代表消极,1代表积极 vocab_num=10000 (X_train,y_train),(X_test,y_test)=imdb.load_data(num_words=vocab_num) print("----review----") print(X_train[5]) print("----label-----") print(y_train[5])
打印结果
----review---- [1, 6740, 365, 1234, 5, 1156, 354, 11, 14, 5327, 6638, 7, 1016, 2, 5940, 356, 44, 4, 1349, 500, 746, 5, 200, 4, 4132, 11, 2, 9363, 1117, 1831, 7485, 5, 4831, 26, 6, 2, 4183, 17, 369, 37, 215, 1345, 143, 2, 5, 1838, 8, 1974, 15, 36, 119, 257, 85, 52, 486, 9, 6, 2, 8564, 63, 271, 6, 196, 96, 949, 4121, 4, 2, 7, 4, 2212, 2436, 819, 63, 47, 77, 7175, 180, 6, 227, 11, 94, 2494, 2, 13, 423, 4, 168, 7, 4, 22, 5, 89, 665, 71, 270, 56, 5, 13, 197, 12, 161, 5390, 99, 76, 23, 2, 7, 419, 665, 40, 91, 85, 108, 7, 4, 2084, 5, 4773, 81, 55, 52, 1901] ----label----- 1
上面打印结果显示的数字代表着字典中对应单词的索引,我们使用下面的代码来找出每个索引对应的词
word2id = imdb.get_word_index() id2word = {i: word for word,i in word2id.items()} print('---review with word---') print([id2word.get(i, '') for i in X_train[6]])
为了让数据能够输入 RNN 模型,所有的输入文档必须有相同的长度。我们需要设置max_words变量来限制评论的最大长度,超过该长度的评论将被截断,不足该长度的评论将被填充空值(0)。在 Keras 中,我们可以使用pad_sequences()函数来达到此目标。现在设置max_words变量的值为 500。
from tensorflow.keras.preprocessing.sequence import pad_sequences max_words=500 X_train = pad_sequences(X_train, maxlen=max_words) X_test = pad_sequences(X_test, maxlen=max_words)
0x02 模型建立
from tensorflow.keras import Sequential from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout embedding_size = 32 model=Sequential() model.add(Embedding(vocab_num,embedding_size, input_length= max_words)) model.add(LSTM(100)) model.add(Dense(1, activation='sigmoid')) print(model.summary())
这里逐个解释一下每个参数的情况。这几步为建立神经网络的基本流程。
(1)首先,embedding_size,是第六行嵌入层的一个参数,嵌入层,要了解它,首先要知道词嵌入,这里以https://juejin.im/entry/5acc23f26fb9a028d1416bb3 这篇文章来简单介绍一下词嵌入以及embedding层的作用。词嵌入是对传统的词袋模型编码方案的改进,词袋模型可以看这篇https://www.cnblogs.com/chenyusheng0803/p/10978883.html ,
在嵌入中,单词由密集向量表示,其中向量表示将单词投影到连续向量空间中。向量空间中的单词的位置是从文本中学习的,并且基于在使用单词时围绕单词的单词。学习到的向量空间中的单词的位置被称为它的嵌入:Embedding。通俗的说,就是以一种比较准确的方式表达词的位置。
Keras提供了一个嵌入层,适用于文本数据的神经网络。它要求输入数据是整数编码的,所以每个字都用一个唯一的整数表示。例如我们这篇文章说到的imdb的词库中每个数字代表的词。嵌入层用随机权重进行初始化,并将学习训练数据集中所有单词的嵌入。
嵌入层被定义为网络的第一个隐藏层。它必须指定3个参数:
- input_dim:这是文本数据中词汇的取值可能数。例如,如果您的数据是整数编码为0-9之间的值,那么词汇的大小就是10个单词;
- output_dim:这是嵌入单词的向量空间的大小。它为每个单词定义了这个层的输出向量的大小。例如,它可能是32或100甚至更大,可以视为具体问题的超参数;
- input_length:这是输入序列的长度,就像您为Keras模型的任何输入层所定义的一样,也就是一次输入带有的词汇个数。例如,如果您的所有输入文档都由1000个字组成,那么input_length就是1000。
因此,这里的embedding_size就是嵌入单词的向量空间大小,同时,嵌入层的输出是一个二维向量,每个单词在输入文本(输入文档)序列中嵌入一个。
(2)sequential()
Keras有两种类型的模型,序贯模型(Sequential)和函数式模型(Model),函数式模型应用更为广泛,序贯模型是函数式模型的一种特殊情况。sequential model就是那种最简单的结构的模型。按顺序一层一层训练,一层一层往前的那种。没有什么环的结构。比如像前馈网络那样。Keras 的核心数据结构是“模型”,模型是一种组织网络层的方式。Keras 中主要的模型是 Sequential 模型,Sequential 是一系列网络层按顺序构成的栈。
(3) 之后加入LSTM
Keras中的LSTM函数参数可以参考这篇文章:https://blog.csdn.net/jiangpeng59/article/details/77646186 ,这里的100是指输出维度为100
(4)Dense层
这里的DENSE层添加了激活函数为sigmoid,Dense层的详细知识可以见:https://blog.csdn.net/m0_37592397/article/details/79982601
(5)model.summary是指展示model的层数现状,这里的显示结果为:
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding (Embedding) (None, 500, 32) 320000 _________________________________________________________________ lstm (LSTM) (None, 100) 53200 _________________________________________________________________ dense (Dense) (None, 1) 101 ================================================================= Total params: 373,301 Trainable params: 373,301 Non-trainable params: 0 _________________________________________________________________ None
0x03 模型训练
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) from tensorflow.keras.callbacks import EarlyStopping #from tensorboardcolab import TensorBoardColab #tbc = TensorBoardColab() es = EarlyStopping(monitor = "val_loss", patience = 10) batch_size = 64 num_epochs = 10 X_valid, y_valid = X_train[:batch_size], y_train[:batch_size] X_train2, y_train2 = X_train[batch_size:], y_train[batch_size:] model.fit(X_train2, y_train2, validation_data=(X_valid, y_valid), batch_size=batch_size, epochs=num_epochs, callbacks = [es])
(1)model.compile
这个函数主要为设置损失函数和优化器及评估标准。参数设置如下:
- 优化器 optimizer。它可以是现有优化器的字符串标识符,如
rmsprop
或adagrad
,也可以是 Optimizer 类的实例。详见:optimizers。 - 损失函数 loss,模型试图最小化的目标函数。它可以是现有损失函数的字符串标识符,如
categorical_crossentropy
或mse
,也可以是一个目标函数。详见:losses。 - 评估标准 metrics。对于任何分类问题,你都希望将其设置为
metrics = ['accuracy']
。评估标准可以是现有的标准的字符串标识符,也可以是自定义的评估标准函数
(2)earlystipping
这个为keras封装的回调函数,具体信息可以查看https://keras.io/zh/callbacks/,具体的作用为当被监测的数量不再提升,则停止训练
(3)batch_size,num_epochs
简单说,epochs 指的就是训练过程中数据将被“轮询”多少次。
深度学习的优化算法,说白了就是梯度下降。每次的参数更新有两种方式。
第一种,遍历全部数据集算一次损失函数,然后算函数对各个参数的梯度,更新梯度。这种方法每更新一次参数都要把数据集里的所有样本都看一遍,计算量开销大,计算速度慢,不支持在线学习,这称为批梯度下降(Batch gradient descent)。
另一种,每看一个数据就算一下损失函数,然后求梯度更新参数,这个称为随机梯度下降(stochastic gradient descent)。这个方法速度比较快,但是收敛性能不太好,可能在最优点附近晃来晃去,达不到最优点。两次参数的更新也有可能互相抵消掉,造成目标函数震荡的比较剧烈。
为了克服两种方法的缺点,现在一般采用的是一种折中手段,小批的梯度下降(mini-batch gradient decent),这种方法把数据分为若干个批,按批来更新参数,这样,一个批中的一组数据共同决定了本次梯度的方向,下降起来就不容易跑偏,减少了随机性。另一方面因为批的样本数与整个数据集相比小了很多,所以计算量也不是很大。基本上现在的梯度下降都是基于 mini-batch 的,所以 Keras 的模块中经常会出现 batch_size
,就是指这个。
(4)model.fit函数启动训练
0x04 模型评估
scores = model.evaluate(X_test, y_test, verbose=0) print('Test accuracy:', scores[1])
(1)verbose
verbose:日志显示,verbose = 0 为不在标准输出流输出日志信息,verbose = 1 为输出进度条记录,verbose = 2 为每个epoch输出一行记录
0x05 全部代码
因为懒所以麻烦各位自己复制整合了
四、总结
RNN的基本实践流程如上,这是网咯上大部分文章共同流传的一个python代码的例子,我这里将每一行代码进行讲解,适用于具备一丁点ML或者DL基础的旁友观看。
scores = model.evaluate(X_test, y_test, verbose=0)
print('Test accuracy:', scores[1])