赞
踩
#
#作者:韦访
#博客:https://blog.csdn.net/rookie_wei
#微信:1007895847
#添加微信的备注一下是CSDN的
#欢迎大家一起学习
#
上一讲,我们学习了循环神经网络RNN,并且用RNN实现了二进制减法,实际上TensorFlow集成了RNN,我们只要调用其对应的API就可以很方便的使用RNN来解决问题了。这一讲,我们来看看怎么使用TensorFlow的RNN,作为对比,先做一个和上一讲一样功能的二进制减法,再对MNIST数据集的识别。
环境配置:
操作系统:Win10 64位
显卡:GTX 1080ti
Python:Python3.7
TensorFlow:1.15.0
先来看看TensorFlow封装的RNN怎么使用。
TensorFlow共定义了几个cell类,分别如下,
BasicRNNCell、BasicLSTMCell、LSTMCell、GRUCell、MultiRNNCell。
BasicRNNCell是最基本的RNN。
BasicLSTMCell则实现了LSTM的基本版,LSTM是RNN算法的改进,以后会有专门的博客介绍。
LSTMCell则实现了LSTM的高级版。
GRUCell则实现了GRU算法,GRU也是RNN的改进版,以后也会介绍。
MultiRNNCell则是多层RNN的实现,以后,我们用它来实现音乐文件中,将背景音乐和原唱的声音分离的功能。
得到RNN后,就可以构建RNN了,TensorFlow中可以静态构建和动态构建RNN,分别对应函数static_rnn和dynamic_rnn,至于他们俩有什么区别我就没去了解了。
现在,我们用TensorFlow来实现上一讲的二进制减法。
十进制转二进制的代码还是跟以前的一样,代码如下,
- #二进制的位数,这里只计算8位的
- binary_dim = 8
- #8位二进制的最大数,即2的8次方
- largest_number = pow(2,binary_dim)
-
- #int2binary用于整数到二进制表示的映射
- #比如十进制数2的二进制表示,可以写为int2binary[2]
- int2binary = {}
-
- #这里将十进制数0-255转成二进制表示,
- # 再将其存到int2binary中,所以十进制数2的二进制才可以用int2binary[2]表示
- binary = np.unpackbits(
- np.array([range(largest_number)],dtype=np.uint8).T,axis=1)
-
- for i in range(largest_number):
- int2binary[i] = binary[i]

在深度学习中,推荐训练数据都是以mini batch的形式,即小批量数据。所以这里我们将数据的获取方式改为批量获取,代码如下,
- # 批量获取数据
- def get_data(batch_size):
- x_data = []
- y_data = []
- for i in range(batch_size):
- # 生成一个被减数a,a的范围在[0,256)的整数
- a_int = np.random.randint(largest_number)
- # 生成减数b,减数的范围在[0, 128)的整数。
- b_int = np.random.randint(largest_number / 2)
-
- # 如果被减数比减数小,则互换,
- # 我们暂时不考虑负数,所以要确保被减数比减数大
- if a_int < b_int:
- tmp = a_int
- b_int = a_int
- a_int = tmp
-
- # 将其转为二进制的形式
- a = int2binary[a_int]
- b = int2binary[b_int]
-
- x_data.append([[a, b]])
- # 这里c保存的是a-b的答案的二进制形式
- c_int = a_int - b_int
- y_data.append([int2binary[c_int]])
- x_data = np.concatenate(x_data)
- y_data = np.concatenate(y_data)
- return x_data, y_data

接下来的做法就跟我们以前做的TensorFlow模型的步骤差不多了,先定义占位符,
- # 定义占位符,用于存放输入数据x和y
- self.x_in = tf.placeholder(tf.float32, [None, n_steps, n_input])
- self.y_in = tf.placeholder(tf.float32, [None, n_output])
接着,定义我们的网络结构,我们使用RNN+全连接网络的方式,代码如下,
- # 定义网络结构,RNN+全连接网络
- def net(self):
- # cell = tf.nn.rnn_cell.BasicRNNCell(n_hidden)
- # outputs, states = tf.nn.dynamic_rnn(cell, self.x_in, dtype=tf.float32)
- # self.pre = tf.layers.dense(inputs=states, units=n_input, activation=tf.nn.relu)
- cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden)
- outputs, states = tf.nn.dynamic_rnn(cell, self.x_in, dtype=tf.float32)
- self.pred = tf.layers.dense(inputs = states[1], units = n_input, activation =tf.nn.relu)
我们上面用的是BasicLSTMCell,因为在LSTM比基础的RNN效果好,你们可以试试使用BasicRNNCell网络,使用上面注释了的代码即可。
因为是回归问题,所以我们使用均方误差作为损失函数,而优化器则使用梯度下降法,梯度下降法也是有很多变种的,以后的博客我们再详谈,代码如下,
- # 定义损失函数和优化器
- def loss_opt(self):
- # 因为是回归问题,所以损失函数使用均方误差
- self.loss = tf.reduce_mean((self.pred - self.y_in) ** 2)
- self.opt = tf.train.AdamOptimizer(learning_rate).minimize(self.loss)
接着,我们来写测试精度的函数,用模型的预测值和真实值对比,代码如下,
- # 检测精度
- def accuracy(self):
- eq = tf.equal(tf.round(self.pred), tf.round(self.y_in))
- self.acc = tf.reduce_mean(tf.cast(eq, tf.float32))
创建会话和初始化变量的代码如下,
- # 定义会话和初始化变量
- def session(self):
- self.sess = tf.Session()
- self.sess.run(tf.global_variables_initializer())
因为我们这里不用with关键字,所以创建会话以后还要关闭会话,代码如下,
- # 关闭会话
- def close_session(self):
- self.sess.close()
训练模型,往网络里塞数据就可以了,
- # 训练模型
- def run(self, x, y):
- self.sess.run(self.opt, feed_dict={
- self.x_in: x,
- self.y_in: y,
- })
每隔一定步数的时候,打印一下当前的loss值等状态,
- # 打印
- def log(self, step, x, y):
- loss, pre, acc = self.sess.run([self.loss, self.pred, self.acc], feed_dict={
- self.x_in: x,
- self.y_in: y,
- })
- print('--------------------------------')
- print('step:', step, ' loss:', loss, ' acc:', acc)
- for yy, pp in zip(y[:1], pre[:1]):
- print('y:', yy.astype(float))
- print('p:', np.round(pp))
万事俱备,调用即可,代码如下,
- def main(argv=None):
- rnn_o = Rnn()
- for step in range(train_steps):
- # 批量获取数据
- x, y = get_data(batch_size)
- # 训练模型
- rnn_o.run(x, y)
- # 打印
- if step % 500 == 0:
- x, y = get_data(batch_size)
- rnn_o.log(step, x, y)
- #关闭会话
- rnn_o.close_session()
完整的代码在博客末尾给链接。
MNIST数据集的图片的大小是(28, 28),我们将它当成28个时间段,没个时间段的内容为28个值,将这个28个时序送入RNN网络中。
老规矩,先定义占位符,
- # 定义占位符
- self.x_in = tf.placeholder(tf.float32, [None, n_steps, n_input])
- self.y_in = tf.placeholder(tf.float32, [None, n_classes])
接着,定义网络结构,还是RNN+全连接网络,代码如下,
- # 定义网络结构,RNN+全连接网络
- def net(self):
- # cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden)
- # outputs, states = tf.nn.dynamic_rnn(cell, self.x_in, dtype=tf.float32)
- # self.pred = tf.layers.dense(inputs=states[1], units=n_classes, activation=tf.nn.relu)
- cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden)
- x1 = tf.unstack(self.x_in, n_steps, 1)
- outputs, states = tf.nn.static_rnn(cell, x1, dtype=tf.float32)
- self.pred = tf.layers.dense(inputs = states[1], units = n_classes, activation =tf.nn.relu)
上面说过,TensorFlow构建RNN有动态和静态的方法,二进制减法中我们使用了动态的方法,这里我们就用静态的方法,注释部分是用动态的方法,你们也可以使用注释部分的代码。
因为识别MNIST是分类问题,所以我们这里使用交叉熵作为损失函数,代码如下,
- # 定义损失函数和优化器
- def loss_opt(self):
- # 因为是分类问题,所以损失函数使用交叉熵
- self.loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=self.pred, labels=self.y_in))
- self.opt = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(self.loss)
跟以前一样,没什么好说的,
- # 检测精度
- def accuracy(self):
- eq = tf.equal(tf.argmax(self.pred, 1), tf.argmax(self.y_in, 1))
- self.acc = tf.reduce_mean(tf.cast(eq, tf.float32))
我们获取的MNIST的图片shape是(, 784),我们需要先将它转成(, 28, 28)的形式,再输入网络中,代码如下,
- # 训练模型
- def run(self, x, y):
- # 将输入数据shape从(, 784)变成(, 28, 28)
- x = x.reshape((x.shape[0], n_steps, n_input))
- self.sess.run(self.opt, feed_dict={self.x_in: x, self.y_in: y})
- # 打印
- def log(self, step, x, y):
- # 将输入数据shape从(, 784)变成(, 28, 28)
- x = x.reshape((x.shape[0], n_steps, n_input))
- acc, loss = self.sess.run([self.acc, self.loss], feed_dict={self.x_in: x, self.y_in: y})
- print("step: ", step, ", Minibatch Loss= " ,
- "{:.6f}".format(loss) , ", Training Accuracy= " ,
- "{:.5f}".format(acc))
- # 定义会话和初始化变量
- def session(self):
- self.sess = tf.Session()
- self.sess.run(tf.global_variables_initializer())
-
- # 关闭会话
- def close_session(self):
- self.sess.close()
都定义好以后,在main函数中使用即可,代码如下,
- #下载并导入MNIST数据集
- mnist = input_data.read_data_sets("mnist_data/", one_hot=True)
-
- #定义训练次数和batch长度
- train_steps = 40000
- batch_size = 32
-
- def main(argv=None):
- rnn_o = Rnn()
- #开始训练
- for step in range(train_steps):
- #批量获取MNIST数据
- x, y = mnist.train.next_batch(batch_size)
- rnn_o.run(x, y)
- if step % 500 == 0:
- x, y = mnist.test.next_batch(batch_size)
- rnn_o.log(step, x, y)
-
- # 关闭会话
- rnn_o.close_session()
- print (" Finished!")

完整代码链接如下,
https://mianbaoduo.com/o/bread/Y5iamZw=
下一讲,我们来学习反向传播BP的过程。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。