matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例...

8cd4ae9e52bd109b7301ccfb40628ebd.png

点击上方 蓝字 关注我呀!

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第1张图片

b50f7d9be0b19ce6662607cc155b7492.png

53cd4527c37365e1e892d8b984db9714.png

[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例

057debc42464b4d55f63e0e879f74436.png

从本专栏开始,正式开始研究Python深度学习、神经网络及人工智能相关知识。前一篇讲解了TensorFlow如何保存变量和神经网络参数,通过Saver保存神经网络,再通过Restore调用训练好的神经网络。本文将详细讲解循环神经网络RNN和长短期记忆网络LSTM的原理知识,并采用TensorFlow实现手写数字识别的RNN分类案例。基础性文章,希望对您有所帮助,如果文章中存在错误或不足之处,还请海涵~

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第2张图片

前文:[Python人工智能] 一.TensorFlow2.0环境搭建及神经网络入门[Python人工智能] 二.TensorFlow基础及一元直线预测案例[Python人工智能] 三.TensorFlow基础之Session、变量、传入值和激励函数[Python人工智能] 四.TensorFlow创建回归神经网络及Optimizer优化器[Python人工智能] 五.Tensorboard可视化基本用法及绘制整个神经网络[Python人工智能] 六.TensorFlow实现分类学习及MNIST手写体识别案例[Python人工智能] 七.什么是过拟合及dropout解决神经网络中的过拟合问题[Python人工智能] 八.卷积神经网络CNN原理详解及TensorFlow编写CNN[Python人工智能] 九.Tensorflow+Opencv实现CNN自定义图像分类案例及与机器学习KNN图像分类算法对比[Python人工智能] 十.Tensorflow如何保存神经网络参数

文章目录:

  • 一.循环神经网络
    • 1.RNN原理
    • 2.RNN应用
  • 二.LSTM RNN原理详解
    • 1.为什么引入LSTM
    • 2.LSTM
  • 三.Tensorflow编写RNN代码

b50f7d9be0b19ce6662607cc155b7492.png

一.循环神经网络

在编写代码之前,我们需要介绍什么是RNN,RNN是怎样运行的以及RNN的结构。

1.RNN原理

循环神经网络英文是Recurrent Neural Networks,简称RNN。假设有一组数据data0、data1、data2、data3,使用同一个神经网络预测它们,得到对应的结果。如果数据之间是有关系的,比如做菜下料的前后步骤,英文单词的顺序,如何让数据之间的关联也被神经网络学习呢?这就要用到——RNN。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第3张图片

假设存在ABCD数字,需要预测下一个数字E,会根据前面ABCD顺序进行预测,这就称为记忆。预测之前,需要回顾以前的记忆有哪些,再加上这一步新的记忆点,最终输出output,循环神经网络(RNN)就利用了这样的原理。

首先,让我们想想人类是怎么分析事物之间的关联或顺序的。人类通常记住之前发生的事情,从而帮助我们后续的行为判断,那么是否能让计算机也记住之前发生的事情呢?

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第4张图片

在分析data0时,我们把分析结果存入记忆Memory中,然后当分析data1时,神经网络(NN)会产生新的记忆,但此时新的记忆和老的记忆没有关联,如上图所示。在RNN中,我们会简单的把老记忆调用过来分析新记忆,如果继续分析更多的数据时,NN就会把之前的记忆全部累积起来。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第5张图片

RNN结构如下图所示,按照时间点t-1、t、t+1,每个时刻有不同的x,每次计算会考虑上一步的state和这一步的x(t),再输出y值。在该数学形式中,每次RNN运行完之后都会产生s(t),当RNN要分析x(t+1)时,此刻的y(t+1)是由s(t)和s(t+1)共同创造的,s(t)可看作上一步的记忆。多个神经网络NN的累积就转换成了循环神经网络,其简化图如下图的左边所示。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第6张图片

总之,只要你的数据是有顺序的,就可以使用RNN,比如人类说话的顺序,电话号码的顺序,图像像素排列的顺序,ABC字母的顺序等。在前面讲解CNN原理时,它可以看做是一个滤波器滑动扫描整幅图像,通过卷积加深神经网络对图像的理解。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第7张图片

而RNN也有同样的扫描效果,只不过是增加了时间顺序和记忆功能。RNN通过隐藏层周期性的连接,从而捕获序列化数据中的动态信息,提升预测结果。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第8张图片

2.RNN应用

RNN常用于自然语言处理、机器翻译、语音识别、图像识别等领域,下面简单分享RNN相关应用所对应的结构。

RNN情感分析: 当分析一个人说话情感是积极的还是消极的,就用如下图所示的RNN结构,它有N个输入,1个输出,最后时间点的Y值代表最终的输出结果。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第9张图片

RNN图像识别: 此时有一张图片输入X,N张对应的输出。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第10张图片

RNN机器翻译: 输入和输出分别两个,对应的是中文和英文,如下图所示。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第11张图片

b50f7d9be0b19ce6662607cc155b7492.png

二.LSTM RNN原理详解

接下来我们看一个更强大的结构,称为LSTM。

1.为什么引入LSTM

RNN是在有序的数据上进行学习的,RNN会像人一样对先前的数据发生记忆,但有时候也会像老爷爷一样忘记先前所说。为了解决RNN的这个弊端,提出了LTSM技术,它的英文全称是Long short-term memory,长短期记忆,也是当下最流行的RNN之一。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第12张图片

假设现在有一句话,如下图所示,RNN判断这句话是红烧排骨,这时需要学习,而“红烧排骨“在句子开头。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第13张图片

"红烧排骨"这个词需要经过长途跋涉才能抵达,要经过一系列得到误差,然后经过反向传递,它在每一步都会乘以一个权重w参数。如果乘以的权重是小于1的数,比如0.9,0.9会不断地乘以误差,最终这个值传递到初始值时,误差就消失了,这称为梯度消失或梯度离散。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第14张图片 反之,如果误差是一个很大的数,比如1.1,则这个RNN得到的值会很大,这称为梯度爆炸。 matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第15张图片

梯度消失或梯度爆炸:
在RNN中,如果你的State是一个很长的序列,假设反向传递的误差值是一个小于1的数,每次反向传递都会乘以这个数,0.9的n次方趋向于0,1.1的n次方趋向于无穷大,这就会造成梯度消失或梯度爆炸。

这也是RNN没有恢复记忆的原因,为了解决RNN梯度下降时遇到的梯度消失或梯度爆炸问题,引入了LSTM。

2.LSTM

LSTM是在普通的RNN上面做了一些改进,LSTM RNN多了三个控制器,即输入、输出、忘记控制器。左边多了个条主线,例如电影的主线剧情,而原本的RNN体系变成了分线剧情,并且三个控制器都在分线上。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第16张图片
  • 输入控制器(write gate): 在输入input时设置一个gate,gate的作用是判断要不要写入这个input到我们的内存Memory中,它相当于一个参数,也是可以被训练的,这个参数就是用来控制要不要记住当下这个点。

  • 输出控制器(read gate): 在输出位置的gate,判断要不要读取现在的Memory。

  • 忘记控制器(forget gate): 处理位置的忘记控制器,判断要不要忘记之前的Memory。

LSTM工作原理为:如果分线剧情对于最终结果十分重要,输入控制器会将这个分线剧情按重要程度写入主线剧情,再进行分析;如果分线剧情改变了我们之前的想法,那么忘记控制器会将某些主线剧情忘记,然后按比例替换新剧情,所以主线剧情的更新就取决于输入和忘记控制;最后的输出会基于主线剧情和分线剧情。

通过这三个gate能够很好地控制我们的RNN,基于这些控制机制,LSTM是延缓记忆的良药,从而带来更好的结果。

b50f7d9be0b19ce6662607cc155b7492.png

三.Tensorflow编写RNN代码

接下来我们通过手写数字图片集数据编写RNN代码。RNN是基于顺序的数据,想象下图片的顺序,它是一行一行像素组成的,最终判定图片的数字属于哪类。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第17张图片 matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第18张图片

第一步,打开Anaconda,然后选择已经搭建好的“tensorflow”环境,运行Spyder。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第19张图片

第二步,导入扩展包。

import tensorflow as tffrom tensorflow.examples.tutorials.mnist import input_data

第三步,下载数据集。
由于MNIST数据集是TensorFlow的示例数据,所以我们只需要下面一行代码,即可实现数据集的读取工作。如果数据集不存在它会在线下载,如果数据集已经被下载,它会被直接调用。

# 下载手写数字图像数据集mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第20张图片

第四步,定义参数。

# 设置参数learning_rate = 0.001     # 学习效率train_iters = 100000      # 训练次数batch_size = 128          # 自定义n_inputs = 28             # MNIST 输入图像形状 28*28 黑白图片高度为1n_steps = 28              # time steps 输入图像的28行数据n_hidden_units = 128      # 神经网络隐藏层数量n_classes = 10            # 分类结果 数字0-0

第五步,定义placeholder,用于传入值xs和ys至神经网络。

# 设置传入的值xs和ysx = tf.placeholder(tf.float32, [None, n_steps, n_inputs])  #每张图片28*28=784个点y = tf.placeholder(tf.float32, [None, n_classes])          #每个样本有10个输出

第六步,定义权重和误差变量。
权重和偏置包括输入和输出值,需要注意其设置的形状。

# 定义权重 进入RNN前的隐藏层 输入&输出weights = {    # (28, 128)    'in': tf.Variable(tf.random_normal([n_inputs, n_hidden_units])),    # (128, 10)    'out': tf.Variable(tf.random_normal([n_hidden_units, n_classes])),}# 定义偏置 进入RNN前的隐藏层 输入&输出biases = {    # (128, )    'in': tf.Variable(tf.constant(0.1, shape=[n_hidden_units, ])),    # (10, )    'out': tf.Variable(tf.constant(0.1, shape=[n_classes, ])),}

第七步,定义RNN神经网络。
RNN定义分别对应三层,X输入、Cell为中心计算、H为最终输出,需要注意数据形状的变化。在RNN运算过程中,每一步的输出都存储在outputs序列中,LSTM包括c_state(主线)和m_state(分线)。最终输出结果为Cell的输出和权重输出的乘积,再加上输出偏置。(详见注释)

#---------------------------------定义RNN-------------------------------def RNN(X, weights, biases):    # hidden layer for input to cell    #######################################################    # X (128 batch, 28 steps, 28 inputs) 28行*28列     # X ==> (128*28, 28 inputs)    X = tf.reshape(X, [-1, n_inputs])    # 隐藏层 输入    # X_in ==> (128batch*28steps, 128 hidden)    X_in = tf.matmul(X, weights['in']) + biases['in']    # 二维数据转换成三维数据     # 注意:神经网络学习时要注意其形状如何变化    # X_in ==> (128 batch, 28 steps, 128 hidden)    X_in = tf.reshape(X_in, [-1, n_steps, n_hidden_units]) # 128个隐藏层    # cell    #######################################################    # Cell结构 隐藏层数 forget初始偏置为1.0(初始时不希望forget)    lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden_units, forget_bias=1.0, state_is_tuple=True)    # RNN会保留每一步计算的结果state    # lstm cell is divided into two parts (c_state, m_state) 主线c_state 分线m_state    _init_state = lstm_cell.zero_state(batch_size, dtype=tf.float32)    # RNN运算过程 每一步的输出都存储在outputs序列中    # 常规RNN只有m_state LSTM包括c_state和m_state    outputs, states = tf.nn.dynamic_rnn(lstm_cell, X_in, initial_state=_init_state, time_major=False)    # hidden layer for output as final results    #######################################################    # 第三层加工最终的输出    # 最终输出=Cell的输出*权重输出+偏置数据    # states包含了主线剧情和分线剧情 states[1]表示分线剧情的结果 即为outputs[-1]最后一个输出结果    results = tf.matmul(states[1], weights['out']) + biases['out']    # 第二种方法    # 解包 unpack to list [(batch, outputs)..] * steps    #outputs = tf.unstack(tf.transpose(outputs, [1,0,2])) # states is the last outputs    #results = tf.matmul(outputs[-1], weights['out']) + biases['out']    return results

第八步,定义误差和准确度。

#---------------------------------定义误差和训练-------------------------------pre = RNN(x, weights, biases)# 预测值与真实值误差cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pre, labels=y))# 训练学习 学习效率设置为0.001train_step = tf.train.AdamOptimizer(learning_rate).minimize(cost) #梯度下降减小误差# 预测正确个数correct_pred = tf.equal(tf.argmax(pre, 1), tf.argmax(y, 1))# 准确度accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

第九步,初始化及训练。

#---------------------------------初始化及训练-------------------------------init = tf.initialize_all_variables()with tf.Session() as sess:    sess.run(init)    step = 0    # 循环每次提取128个样本    while step * batch_size < train_iters:        # 从下载好的数据集提取128个样本        batch_xs, batch_ys = mnist.train.next_batch(batch_size)        # 形状修改 [128, 28, 28]        batch_xs = batch_xs.reshape([batch_size, n_steps, n_inputs])        # 训练        sess.run([train_step], feed_dict={            x: batch_xs,            y: batch_ys,        })        # 每隔20步输出结果        if step % 20 == 0: # 20*128            print(sess.run(accuracy, feed_dict={                x: batch_xs,                y: batch_ys,            }))        step += 1

最终输出结果如下所示,可以看到,最早预测的准确度结果非常低为2.187%,最后提升到了96.87%,其结果高于之前的一般神经网络的结果87.79%(第六篇博客),由此可见TensorFlow RNN的分类学习效果还不错,并且在不断学习中。

Extracting MNIST_data\train-images-idx3-ubyte.gzExtracting MNIST_data\train-labels-idx1-ubyte.gzExtracting MNIST_data\t10k-images-idx3-ubyte.gzExtracting MNIST_data\t10k-labels-idx1-ubyte.gz0.21875000.67968750.82812500.82031250.83593750.89843750.88281250.83593750.9062500....0.98437500.96093750.94531250.96093750.97656250.93750000.99218750.96093750.99218750.9687500

完整代码如下:

# -*- coding: utf-8 -*-import tensorflow as tffrom tensorflow.examples.tutorials.mnist import input_data# 下载手写数字图像数据集mnist = input_data.read_data_sets('MNIST_data', one_hot=True)# 设置参数learning_rate = 0.001     # 学习效率train_iters = 100000      # 训练次数batch_size = 128          # 自定义n_inputs = 28             # MNIST 输入图像形状 28*28 黑白图片高度为1n_steps = 28              # time steps 输入图像的28行数据n_hidden_units = 128      # 神经网络隐藏层数量n_classes = 10            # 分类结果 数字0-0#-----------------------------定义placeholder输入-------------------------# 设置传入的值xs和ysx = tf.placeholder(tf.float32, [None, n_steps, n_inputs])  #每张图片28*28=784个点y = tf.placeholder(tf.float32, [None, n_classes])          #每个样本有10个输出# 定义权重 进入RNN前的隐藏层 输入&输出weights = {    # (28, 128)    'in': tf.Variable(tf.random_normal([n_inputs, n_hidden_units])),    # (128, 10)    'out': tf.Variable(tf.random_normal([n_hidden_units, n_classes])),}# 定义偏置 进入RNN前的隐藏层 输入&输出biases = {    # (128, )    'in': tf.Variable(tf.constant(0.1, shape=[n_hidden_units, ])),    # (10, )    'out': tf.Variable(tf.constant(0.1, shape=[n_classes, ])),}#---------------------------------定义RNN-------------------------------def RNN(X, weights, biases):    # hidden layer for input to cell    #######################################################    # X (128 batch, 28 steps, 28 inputs) 28行*28列     # X ==> (128*28, 28 inputs)    X = tf.reshape(X, [-1, n_inputs])    # 隐藏层 输入    # X_in ==> (128batch*28steps, 128 hidden)    X_in = tf.matmul(X, weights['in']) + biases['in']    # 二维数据转换成三维数据     # 注意:神经网络学习时要注意其形状如何变化    # X_in ==> (128 batch, 28 steps, 128 hidden)    X_in = tf.reshape(X_in, [-1, n_steps, n_hidden_units]) # 128个隐藏层    # cell    #######################################################    # Cell结构 隐藏层数 forget初始偏置为1.0(初始时不希望forget)    lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden_units, forget_bias=1.0, state_is_tuple=True)    # RNN会保留每一步计算的结果state    # lstm cell is divided into two parts (c_state, m_state) 主线c_state 分线m_state    _init_state = lstm_cell.zero_state(batch_size, dtype=tf.float32)    # RNN运算过程 每一步的输出都存储在outputs序列中    # 常规RNN只有m_state LSTM包括c_state和m_state    outputs, states = tf.nn.dynamic_rnn(lstm_cell, X_in, initial_state=_init_state, time_major=False)    # hidden layer for output as final results    #######################################################    # 第三层加工最终的输出    # 最终输出=Cell的输出*权重输出+偏置数据    # states包含了主线剧情和分线剧情 states[1]表示分线剧情的结果 即为outputs[-1]最后一个输出结果    results = tf.matmul(states[1], weights['out']) + biases['out']    # 第二种方法    # 解包 unpack to list [(batch, outputs)..] * steps    #outputs = tf.unstack(tf.transpose(outputs, [1,0,2])) # states is the last outputs    #results = tf.matmul(outputs[-1], weights['out']) + biases['out']    return results#---------------------------------定义误差和训练-------------------------------pre = RNN(x, weights, biases)# 预测值与真实值误差cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pre, labels=y))# 训练学习 学习效率设置为0.001train_step = tf.train.AdamOptimizer(learning_rate).minimize(cost) #梯度下降减小误差# 预测正确个数correct_pred = tf.equal(tf.argmax(pre, 1), tf.argmax(y, 1))# 准确度accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))#---------------------------------初始化及训练-------------------------------init = tf.initialize_all_variables()with tf.Session() as sess:    sess.run(init)    step = 0    # 循环每次提取128个样本    while step * batch_size < train_iters:        # 从下载好的数据集提取128个样本        batch_xs, batch_ys = mnist.train.next_batch(batch_size)        # 形状修改 [128, 28, 28]        batch_xs = batch_xs.reshape([batch_size, n_steps, n_inputs])        # 训练        sess.run([train_step], feed_dict={            x: batch_xs,            y: batch_ys,        })        # 每隔20步输出结果        if step % 20 == 0: # 20*128            print(sess.run(accuracy, feed_dict={                x: batch_xs,                y: batch_ys,            }))        step += 1

注意,在运行代码过程中可能会报错“ValueError: Variable rnn/basic_lstm_cell/kernel already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope?”

在Spyder中有kernel选项,点击选择 “ Restart & RunAll ” 重新运行代码即可解决问题。

matlab编写识别手写数字_[Python人工智能] 十一.循环神经网络RNN和LSTM原理详解及TensorFlow编写RNN分类案例..._第21张图片

b50f7d9be0b19ce6662607cc155b7492.png

希望文章对大家有所帮助,如果有错误或不足之处,还请海涵。 真心想把自己所学所感所做分享出来,还请各位多多指教,真诚邀请您的关注!谢谢。

5cd045a4f0494d6ec85e9deb9a7ca440.png

点个赞,证明你还爱我

cc652860dd92e78d473244b145d221b6.gif 83a3a77fae96685083643ab21c7e4be3.png

b50f7d9be0b19ce6662607cc155b7492.png

你可能感兴趣的:(matlab编写识别手写数字,tensorflow,saver,分类预测,python)