10-RNN网络模型之MNIST分类

本文介绍如何利用循环神经网络(RNN)对MNIST手写数字数据集进行分类,包括单向和双向RNN的构建、模型训练及使用TensorBoard进行可视化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言
本篇将以RNN(Recurrent Neural Network)(循环神经网络)的网络结构来对我们熟知的MNIST数据集做分类模型训练,MNIST数据集在前面的文章中有简要的介绍,这里不做赘述,仅在下面的代码中有相应展现。
二、介绍
RNN:循环神经网络是一类用于处理序列数据的神经网络,就像卷积网络是专门用于处理网格化数据的神经网络一样,属于具有不同网络结构但有重叠功能的神经网络。卷积神经网络可以很容易的拓展(应用其局部感知能力)到具有很大宽度和高度的图像,以及处理大小可变的图像,循环神经网络可以拓展到更长的序列,大多数循环神经网络也能处理可变长度的序列。循环神经网络其循环的要义就是输出的每一项是前一项的函数,并且输出的每一项对先前的输出应用相同的更新规则而产生,因而其参数共享机制是基于时间序列上的参数共享。所以RNN更加适合做对于前后有依赖关系的结构的输入来做模型训练,例如:情感分析、关键字提取、语音识别、机器翻译和股票分析等细分领域。
单向RNN:从字面意思理解,单向的意思就是下文的输出仅与之前的序列有关。
双向RNN:该结构的含义为,当前的输出不仅和之前的序列有关,并且还与之后的序列有关。
三、任务目标
1.正确的构建RNN单层和双向单隐层网络结构
2.打印模型训练过程中准确率的迭代过程
3.使用tensorboard可视化界面进一步观察网络结构
四、具体实现过程
1.导包

import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data

2.获取数据集

def get_date():
    mnist=input_data.read_data_sets('MNIST/',one_hot=True)
    return mnist,mnist.train.images,mnist.train.labels,mnist.test.images,mnist.test.labels

3.定义参数初始化方式

def get_variable(name,shape,dtype=tf.float32,initializer=tf.random_normal_initializer(mean=0,stddev=0.1)):
    return tf.get_variable(name=name,shape=shape,dtype=dtype,initializer=initializer)

4.定义网络参数

def set_params():
    training_epochs=10000
    testing_epochs=156
    #维度数目
    num_units=128
    #批次数量
    batch_size=64
    #时刻数目
    time_num=28
    #数据输入维度数目
    input_dimssion=28
    learning_rate=0.001
    class_num=10
    return training_epochs,testing_epochs,num_units,batch_size,time_num,input_dimssion,learning_rate,class_num

5.定义网络结构

def set_network(X,Y,batch_size,num_units,class_num):
    #num_units:指定Cell中各个神经网络层次中的神经元数目
    RNN_Cell=tf.nn.rnn_cell.BasicRNNCell(num_units=num_units)
    #给定初始状态
    init_state=RNN_Cell.zero_state(batch_size=batch_size,dtype=tf.float32)
    #传入输入和state获取结果值
    output,state=tf.nn.dynamic_rnn(RNN_Cell,inputs=X,initial_state=init_state)

    #拿到结果
    output=output[:,-1,:]
    network=tf.nn.bias_add(tf.matmul(output,get_variable(name='w',shape=[num_units,class_num])),get_variable('b',[class_num]))
    predict=tf.nn.softmax(network)

    return predict

5.定义双向RNN网络结构(2)

def set_network(X,Y,batch_size,num_units,class_num):
    time_num=28
    #将X按列划分为序列
    X=tf.unstack(X,time_num,1)
    #定义正反向RNN结构
    RNN_fw_Cell=tf.nn.rnn_cell.BasicRNNCell(num_units)
    RNN_bw_Cell=tf.nn.rnn_cell.BasicRNNCell(num_units)

    output,_,_=tf.nn.static_bidirectional_rnn(RNN_fw_Cell,RNN_bw_Cell,inputs=X,dtype=tf.float32)
    output=output[:][-1][:]
    network = tf.nn.bias_add(tf.matmul(output, get_variable(name='w', shape=[num_units*2, class_num])),
                             get_variable('b', [class_num]))

    predict = tf.nn.softmax(network)
    return predict

6.模型训练

def train():
    # 获取数据
    mnist, train_images, train_labels, test_images, test_labels = get_date()
    # 获取网络参数
    training_epochs, testing_epochs,num_units,batch_size,time_num, input_dimssion, learning_rate,class_num = set_params()
    #定义占位符
    X=tf.placeholder(tf.float32,shape=[None,784])
    X_=tf.reshape(X,shape=[-1,time_num,input_dimssion])
    Y=tf.placeholder(tf.float32,shape=[None,class_num])
    #batch_size=X.get_shape()[0]
    #train_images=tf.reshape(shape=[-1,time_num,input_dimssion])
    predict=set_network(X_,Y,batch_size=batch_size,num_units=num_units,class_num=class_num)
    loss=tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(logits=predict,labels=Y))
    train=tf.train.GradientDescentOptimizer(learning_rate=learning_rate).minimize(loss)

    #计算正确率
    equal=tf.equal(tf.arg_max(predict,1),tf.arg_max(Y,1))
    acc=tf.reduce_mean(tf.cast(equal,tf.float32))

    init=tf.global_variables_initializer()
    with tf.Session() as sess:
        sess.run(init)
        for epoch in range(training_epochs):
            batch_x,batch_y=mnist.train.next_batch(batch_size)
            feed_dict={X:batch_x,Y:batch_y}
            sess.run(train,feed_dict=feed_dict)
            loss_=sess.run(loss,feed_dict=feed_dict)
            acc_=sess.run(acc,feed_dict=feed_dict)
            print("epoch:{},loss:{},acc:{}".format(epoch+1,loss_,acc_))
        avg_acc=0.0
        avg_loss=0.0
        for epoch in range(testing_epochs):
            batch_x,batch_y=mnist.test.next_batch(batch_size)
            feed_dict_test={X:batch_x,Y:batch_y}
            loss_test=sess.run(loss,feed_dict=feed_dict_test)
            acc_test=sess.run(acc,feed_dict=feed_dict_test)
            avg_acc+=acc_test
            avg_loss+=loss_test
            print("*"*20,"testing","*"*20)
            print("epoch:{},loss:{},acc:{}".format(epoch+1,loss_test,acc_test))
        avg_loss=avg_loss/testing_epochs
        avg_acc=avg_acc/testing_epochs
        print("avg_loss:{},avg_acc:{}".format(avg_loss,avg_acc))

if __name__=='__main__':
    train()

7.添加tensorboard显示代码
分别在文中相应位置添加如下代码段

    #将损失以标量的形式显示
    tf.summary.scalar('loss',loss)
        #合并所有summary
        merged_summary_op=tf.summary.merge_all()
        #创建summary_writer,用于写文件
        summary_writer=tf.summary.FileWriter('log/mnist_with_summaries',sess.graph)
            #生成summary
            summary_str=sess.run(merged_summary_op,feed_dict=feed_dict)
            #将summary写入文件
            summary_writer.add_summary(summary_str,epoch)

运行结果如下图所示
7.1该图为loss标量结果的变化图
这里写图片描述
7.2该图为网络的结构图示
这里写图片描述
从图中可以看出BasicRNNCellZeroState传入到整个网络结构中去,占位符进行分时输入,GradientDescent进行权值的更新,还进行了损失函数的计算和正确率的计算等等。
7.3测试集最终结果图
这里写图片描述

五、分析与总结
1.RNN从网络结构上来讲是处理前后有依赖关系的序列,比如一句话可以分为多个词向量,每一个词向量的前后必然是有联系的,例如:隔壁家小孩说“我想吃饭”这个是正确无疑的逻辑,那么倒过来说“饭吃想我”那么就不对了,或者仅改变任意一个字的位置也会显得非常奇怪。通过这个逻辑来看,图片是有先后关系的么,仔细分析一下,显然是有的,不过这个逻辑的连结没有文字序列那么紧密,但是仅仅以mnist数据集来看的话,这个连结的稳定性还是比较强的,因为它不像那种抽象派的画,数字图片的结构是固定的,就像我们写数字的时候也不是一下子就可以写好的,也就是需要进行分时(按笔画)书写才能得以完成的。这样来看的话RNN同CNN一样也是有局部感知能力的,只是相对来说要弱于CNN的效果。
2.代码中将一副784个像素值的图片划分为28个时序分别进行输入,拿到输出结果进行全连接、softmax和argmax得到分类结果。
3.LSTM代码的书写与上面类似,仅仅修改个别代码而已,LSTM的结构这里就不赘述了,以后有机会再稍微的提一下。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值