TensorFlow入门教程(12)TensorFlow RNN

#
#作者:韦访
#博客:https://blog.csdn.net/rookie_wei
#微信:1007895847
#添加微信的备注一下是CSDN的
#欢迎大家一起学习
#

1、概述

上一讲,我们学习了循环神经网络RNN,并且用RNN实现了二进制减法,实际上TensorFlow集成了RNN,我们只要调用其对应的API就可以很方便的使用RNN来解决问题了。这一讲,我们来看看怎么使用TensorFlow的RNN,作为对比,先做一个和上一讲一样功能的二进制减法,再对MNIST数据集的识别。

环境配置:

操作系统:Win10 64位

显卡:GTX 1080ti

Python:Python3.7

TensorFlow:1.15.0

 

 

2、TensorFlow 封装的RNN

先来看看TensorFlow封装的RNN怎么使用。

cell类

TensorFlow共定义了几个cell类,分别如下,

BasicRNNCell、BasicLSTMCell、LSTMCell、GRUCell、MultiRNNCell。

BasicRNNCell是最基本的RNN。

BasicLSTMCell则实现了LSTM的基本版,LSTM是RNN算法的改进,以后会有专门的博客介绍。

LSTMCell则实现了LSTM的高级版。

GRUCell则实现了GRU算法,GRU也是RNN的改进版,以后也会介绍。

MultiRNNCell则是多层RNN的实现,以后,我们用它来实现音乐文件中,将背景音乐和原唱的声音分离的功能。

构建RNN

得到RNN后,就可以构建RNN了,TensorFlow中可以静态构建和动态构建RNN,分别对应函数static_rnn和dynamic_rnn,至于他们俩有什么区别我就没去了解了。

 

3、二进制减法

现在,我们用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,
    })

Log打印

每隔一定步数的时候,打印一下当前的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))

Main函数

万事俱备,调用即可,代码如下,

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()

完整的代码在博客末尾给链接。

运行结果

4、识别MNIST

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})

Log打印

# 打印
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函数

都定义好以后,在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!")

运行结果

5、完整代码

完整代码链接如下,

https://mianbaoduo.com/o/bread/Y5iamZw=

 

下一讲,我们来学习反向传播BP的过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值