1、概述
传统的神经网络对线性回归、逻辑回归都有比较好的效果。卷积神经网络主要应用与计算机视觉技术。使用过滤器对图片的边缘特征值进行检测。在之前的章节中使用cnn对文本分类其实是借用了计算机视觉的一些原理,过滤器的尺寸也有着特殊的设置。在人工智能领域还有一种应用场景,就是序列模型。
之前的算法总体上来讲都是概率分布学的,没有将数据的前后关系包含其中,而在实际的情况下,很多数据都是有时序关系的。比如自然语言,同样的词可以组成两个完全意思相反的句子。词的顺序就非常关键。类似的情况还出现在语音、天气、股票等数据中。甚至在某种程度上,我们也会认为图片是有先后顺序的,当然这只是学术界的一些解释。真实的行业应用还需要看最终的效果。
在本章中将使用RNN(循环神经网络)来进行mnist手写图片的分类。
2、关于RNN
RNN是一种典型的序列模型,其结构如下图所示
在上图中我们可以看到左侧的图是RNN的简单描述方式,右侧的部分是RNN的展开形式。在RNN中x作为一个有序数据依次输入到神经网络中,而每一个RNN的每一个处理单元会将对应的输入和上一次的输出来组合处理,这样RNN就有了记忆功能,可以记住之前的一些信息。RNN每一个中间状态都有输出,是否使用得看具体场景,一般来讲RNN的形式一般有以下几种:
1、多对一
理论上也存在一对多和一对一的RNN,但是一对一的RNN其实就是传统的DNN,没有序列的概念,同样如果输入只有一个也谈不上序列。多对一主要应用在分类上。
2、多对多
多对多主要应用在seq2seq(序列到序列)生成,如风格化文章编写、自动翻译等。
2、LSTM
lstm是RNN中神经元应用的最多的一种形式、这种形式源于传统RNN模型的缺点,传统RNN模型由于只具有记忆功能所以对于序列的信息提取不是很精准、而且在反向传播时很容易出现梯度消失和梯度爆炸的情况。这就是长期依赖所产生的问题,神经元不但需要记住同样需要忘记。所以LSTM的引入就变得非常的重要。
长短期记忆网络(Long Short Term Memory networks) - 通常叫做 “LSTMs” —— 是 RNN 中一个特殊的类型。由Hochreiter & Schmidhuber (1997)提出,广受欢迎,之后也得到了很多人们的改进调整。LSTMs 被广泛地用于解决各类问题,并都取得了非常棒的效果。
lstm有三个门来对信息进行拟合分别为
1、遗忘门
2、记忆门
3、输出门
3、使用RNN对mnist手写图片进行分类
我们可以将图片看成是每一行像素看成一个序列进行N行组合得到。所以可以采用RNN模型进行处理、一般来讲在RNN的外围都会有一个输入和输出层,主要是用来规整数据将其变为我们所希望的输入与输出形态的。
请参照如下结构:
该图片来源于
https://medium.com/the-artificial-impostor/notes-understanding-tensorflow-part-2-f7e5ece849f5
在输入层中我们将每一个序列的28个像素扩充为128个像素值,在输出的部分将128个隐藏层又转化为10个one-hot的输出进行分类。
4、tensorflow实现
在本次tensorflow的实现方法中,我们采用low-api的形式进行代码编写,当然也可以根据自己的喜好采用基于estimator的形式进行编写。
- 读取数据
与cnn的读取方式一致,不再赘述请参照以下代码:
# mnist数据集
import tensorflow as tf
mnist = tf.contrib.learn.datasets.load_dataset("mnist")
import numpy as np
train_data = mnist.train.images
print(train_data.shape)
train_labels = np.asarray(mnist.train.labels, dtype=np.int32)
print(train_labels.shape)
eval_data = mnist.test.images
print(eval_data.shape)
eval_labels = np.asarray(mnist.test.labels, dtype=np.int32)
print(eval_labels.shape)
- 定义超参数
需要按照上面的模型来定义参数,本次超参数的定义如下:
1、lr_rate : 学习率 采用 0.01
2、batch_size: 每个batch训练的图片数量采用100
3、input_size: 原始的训练数据的大小 即图片的列数,设置为28
4、t_steps:每个数据包含的输入序列数 即图片的行数,设置为 28
5、num_class: 分类的最终数量,设置为10
6、rnn_input: rnn真实的特征输入、这里设定为128
7、lstm_unit: lstm包含的隐藏单元个数
请参照如下代码:
# 定义超参数
lr_rate = 1e-2
batch_size = 100
input_size = 28
t_steps = 28
num_class = 10
rnn_input = 128
lstm_unit = 128
- 数据输入
对于数据来讲每张图片都是一个一行784列的数据,该数据为图片输入的原始形态,我们需要将其转化为28*28的图片数据来作为真正的rnn的输入,这里需要注意的是,新版tensorflow在读取mnist数据时不能直接读取one-hot形式必须在后期自行转换:
train_x = tf.placeholder(dtype=tf.float32,shape=[None,input_size*t_steps])
train_y = tf.placeholder(dtype=tf.int32, shape=[None])
train_labels = tf.one_hot(indices=tf.cast(train_y, tf.int32), depth=num_class)
- 定义网络结构
1、定义输入层
输入层主要是对数据进行重塑
x_for_input = tf.reshape(train_x,[-1,input_size])
o_input = tf.layers.dense(x_for_input,rnn_input,activation=tf.nn.relu)
x_for_rnn = tf.reshape(o_input,[-1,t_steps,rnn_input])
2、定义rnn,lstm,训练、loss、以及准确率
with tf.variable_scope('rnn',reuse=tf.AUTO_REUSE):
lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(lstm_unit)
outputs, (h_c, h_n)= tf.nn.dynamic_rnn(
lstm_cell,
x_for_rnn,
time_major=False,
initial_state=None,
dtype=tf.float32)
output = tf.layers.dense(outputs[:, -1, :], num_class)
loss = tf.losses.softmax_cross_entropy(onehot_labels=train_labels, logits=output)
train_op = tf.train.AdamOptimizer(lr_rate).minimize(loss)
accuracy = tf.metrics.accuracy(
labels=tf.argmax(train_labels, axis=1), predictions=tf.argmax(output, axis=1),)[1]
init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
- 训练网络
请参照一下代码:
sess = tf.Session()
# the local var is for accuracy_op
sess.run(init_op) # initialize var in graph
for step in range(1200): # training
b_x, b_y = mnist.train.next_batch(batch_size)
_, loss_ = sess.run([train_op, loss], {train_x: b_x, train_y:b_y})
if step % 50 == 0: # testing
accuracy_ = sess.run(accuracy, {train_x:eval_data, train_y: eval_labels})
print('train loss: %.4f' % loss_, '| test accuracy: %.2f' % accuracy_)
训练效果如下图所示:
train loss: 2.3085 | test accuracy: 0.10
train loss: 0.6070 | test accuracy: 0.43
train loss: 0.2589 | test accuracy: 0.58
train loss: 0.2609 | test accuracy: 0.66
train loss: 0.3123 | test accuracy: 0.72
train loss: 0.0678 | test accuracy: 0.76
train loss: 0.1774 | test accuracy: 0.79
train loss: 0.2189 | test accuracy: 0.80
train loss: 0.2386 | test accuracy: 0.82
train loss: 0.1099 | test accuracy: 0.84
train loss: 0.0312 | test accuracy: 0.85
train loss: 0.1534 | test accuracy: 0.86
train loss: 0.0405 | test accuracy: 0.87
train loss: 0.0796 | test accuracy: 0.87
train loss: 0.0919 | test accuracy: 0.88
train loss: 0.0485 | test accuracy: 0.88
train loss: 0.0639 | test accuracy: 0.89
train loss: 0.1839 | test accuracy: 0.89
train loss: 0.1297 | test accuracy: 0.90
train loss: 0.1187 | test accuracy: 0.90
train loss: 0.0318 | test accuracy: 0.91
train loss: 0.1728 | test accuracy: 0.91
train loss: 0.0183 | test accuracy: 0.91
train loss: 0.0446 | test accuracy: 0.91