【深度学习】TensorFlow:卷积神经网络(CNN)解决MNIST数字识别问题

  • 卷积神经网络与全连接神经网络唯一的区别就在于相邻两层的连接方式
  • 卷积神经网络中的前几层中的每一个节点只与上一层中的部分节点相连
  • 卷积层:特征提取
  • 池化层:下采样
  • 全连接层:完成分类任务

1、mnist_train_cnn.py

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

#配置神经网络中的参数
BATCH_SIZE = 100 #一次训练需要的样本点个数
REGULARAZTION_RATE = 0.0001 #正则化损失系数
MODEL_SAVE_PATH = "C:/Users/asus/Desktop/TensorFlow/model-cnn/"
MOVING_AVERAGE_DECAY = 0.99

def train(mnist):
    #为x y_开辟空间 只有x与全连接神经网络有所不同
    x = tf.placeholder(tf.float32,[
        BATCH_SIZE,                            #第一维表示一个batch样例的个数
        mnist_inference_cnn.IMAGE_SIZE,        #第二维和第三维表示图片的尺寸
        mnist_inference_cnn.IMAGE_SIZE,
        mnist_inference_cnn.NUM_CHANNELS],     #第四维表示图片的深度,对于RGB来说为3维
        name='x-input')
    y_ = tf.placeholder(tf.float32,[None,mnist_inference_cnn.OUTPUT_NODE],name='y-input')

    #正则化损失函数 系数为 0.0001
    regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)

    #y = (x w1) w2
    #使用定义好的前向传播函数,返回输出结果 y 并将正则化损失函数放到集合中
    y = mnist_inference_cnn.inference(x,False,regularizer)

    # 存放训练轮数
    global_step = tf.Variable(0,trainable=False)

    # 定义滑动平均函数 给所有变量使用滑动平均函数

    variables_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)
    variables_averages_op = variables_averages.apply(tf.trainable_variables())

    #交叉熵 :判断一个输出向量和期望的向量的接近程度  也就是两个概率分布之间的距离
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=tf.argmax(y_,1))
    cross_entropy_mean = tf.reduce_mean(cross_entropy)

    #损失函数 loss
    loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))

    #学习率
    l_m_B = mnist.train.num_examples/BATCH_SIZE
    learning_rate = tf.train.exponential_decay(0.8,global_step,l_m_B,0.99)

    #反向传播结果
    train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)

    #在每一次训练时 都要更新参数 和 滑动平均值 train_op
    with tf.control_dependencies([train_step,variables_averages_op]):
        train_op = tf.no_op(name='train')

    #初始化持久化类
    saver = tf.train.Saver()

    with tf.Session() as sess:
        tf.global_variables_initializer().run() #完成所有变量的初始化过程

        for i in range(30000):
            xs,ys = mnist.train.next_batch(BATCH_SIZE)
            reshaped_xs = np.reshape(xs,(BATCH_SIZE,
                                         mnist_inference_cnn.IMAGE_SIZE,
                                         mnist_inference_cnn.IMAGE_SIZE,
                                         mnist_inference_cnn.NUM_CHANNELS))
            _,loss_value,step=sess.run([train_op,loss,global_step],feed_dict={x:reshaped_xs,y_:ys})

            if i % 1000 == 0:
                # 训练中,每1000轮输出一次在当前训练batch上损失函数的大小来大致估计训练结果
                print("After %d training steps,loss on training" "batch is %g."%(step,loss_value))
                # 每1000轮保存一次训练好的模型,方便单独的测试程序进行测试
                saver.save(sess,os.path.join(MODEL_SAVE_PATH,"model.ckpt"),global_step=global_step)

def main(argv=None):
    mnist = input_data.read_data_sets("C:/Users/asus/Desktop/TensorFlow/mnist_data",one_hot=True)
    train(mnist)

if __name__ == '__main__':
    main()

2、mnist_inference_cnn.py

"""
与全连接不同的只是前向传播过程的不同
    前面所学的全连接的前向传播只有两层连接层 最终返回一个y
    CNN与全连接神经网络神经网络不同的就是相邻两层的连接方式,中间包括了卷积层和池化层
"""

import tensorflow as tf

#配置神经网络参数
INPUT_NODE = 784
OUTPUT_NODE = 10

IMAGE_SIZE = 28 #28*28
NUM_CHANNELS = 1 #通道数
NUM_LABELS = 10  #类别数

#第一层卷积层的尺寸和深度
CONV1_DEEP = 32
CONV1_SIZE = 5

#第二层卷积层尺寸和深度
CONV2_DEEP = 64
CONV2_SIZE = 5

#全连接层的节点个数
FC_SIZE = 512

#定义卷积神经网路的前向传播过程 新参数 train:训练
def inference(input_tensor,train,regularizer):

    #第一层 卷积层
    #输入为 28*28*1 的原始MNIST图片像素  卷积层使用0填充   输出为 28*28*32
    with tf.variable_scope('layer1-conv1'):
        Matrix = [CONV1_SIZE,CONV1_SIZE,NUM_CHANNELS,CONV1_DEEP]
        conv1_weights = tf.get_variable("weight",Matrix,initializer=tf.truncated_normal_initializer(stddev=0.1))
        conv1_biases = tf.get_variable("bias",[CONV1_DEEP],initializer=tf.constant_initializer(0.0))
        conv1 = tf.nn.conv2d(input_tensor,conv1_weights,strides=[1,1,1,1],padding='SAME')
        relu1 = tf.nn.relu(tf.nn.bias_add(conv1,conv1_biases))

    #第二层 池化层 选用最大池化层 池化层过滤器的边长为2  输出为 14*14*32
    with tf.name_scope('layer2-pool1'):
        pool1 = tf.nn.max_pool(relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

    #第三层 卷积层 输出为 14*14*64
    with tf.variable_scope('layer3-conv2'):
        Matrix = [CONV2_SIZE,CONV2_SIZE,CONV1_DEEP,CONV2_DEEP]
        conv2_weights = tf.get_variable("weight",Matrix,initializer=tf.truncated_normal_initializer(stddev=0.1))
        conv2_biases = tf.get_variable("bias",[CONV2_DEEP],initializer=tf.constant_initializer(0.0))
        conv2 = tf.nn.conv2d(pool1, conv2_weights, strides=[1, 1, 1, 1], padding='SAME')
        relu2 = tf.nn.relu(tf.nn.bias_add(conv2,conv2_biases))

    #第四层 池化层 输出为 7*7*64
    with tf.name_scope('layer4-pool2'):
        pool2 = tf.nn.max_pool(relu2,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')


    pool_shape = pool2.get_shape().as_list() #将7*7*64的矩阵拉成一行
    #拉成一行后 变成一个数组 应该是7*7*64  [7 7 64]
    #由于每一层神经网络的输入输出都为一个batch的矩阵,所以这里的维度就包括了batch中数据的个数
    # pool_shape[0]就是batch数据中的组数
    nodes = pool_shape[1] * pool_shape[2] * pool_shape[3] #拉成一行后的长度  一组向量的长度
    #一个batch中的一个数据就是一小副图像,有多少个数据就有多少幅图像
    #将这个四维数组pool2,转换成【】矩阵的形式
    reshape = tf.reshape(pool2,[pool_shape[0],nodes])

    #第五层 全连接层 这一层的输入就是拉直后的其中一组向量 数量为 7*7*64 = 3136
    with tf.variable_scope('layer5-fc1'):
        fc1_weights = tf.get_variable("weight",[nodes,FC_SIZE],initializer=tf.truncated_normal_initializer(stddev=0.1))
        if regularizer != None:
            tf.add_to_collection('losses',regularizer(fc1_weights))
        fc1_biases = tf.get_variable("bias",[FC_SIZE],initializer=tf.constant_initializer(0.1))
        fc1 = tf.nn.relu(tf.matmul(reshape,fc1_weights)+fc1_biases)
        #使用dropout在训练时随机将部分节点的输出改为0 dropout可以避免过拟合问题
        #dropout 只在全连接层使用,不在卷积层和池化层使用
        if train : fc1 = tf.nn.dropout(fc1,0.5)

    #第六层 全连接层
    with tf.variable_scope('layer6-fc2'):
        fc2_weights = tf.get_variable("weight", [FC_SIZE,NUM_LABELS],initializer=tf.truncated_normal_initializer(stddev=0.1))
        if regularizer != None:
            tf.add_to_collection('losses',regularizer(fc2_weights))
        fc2_biases = tf.get_variable("bias", [NUM_LABELS], initializer=tf.constant_initializer(0.1))
        logit = tf.matmul(fc1, fc2_weights) + fc2_biases
    return logit

在敲代码的过程中 在全连接层的第一层忘记给权重加上正则化了,最终的结果还没有之前的全连接层神经网络好,所以变量正则化对神经网络的影响还是很大的!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
利用tensorflow实现的卷积神经网络来进行MNIST手写数字图像的分类。 #导入numpy模块 import numpy as np #导入tensorflow模块,程序使用tensorflow来实现卷积神经网络 import tensorflow as tf #下载mnist数据集,并从mnist_data目录中读取数据 from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets('mnist_data',one_hot=True) #(1)这里的“mnist_data” 是和当前文件相同目录下的一个文件夹。自己先手工建立这个文件夹,然后从https://yann.lecun.com/exdb/mnist/ 下载所需的4个文件(即该网址中第三段“Four files are available on this site:”后面的四个文件),并放到目录MNIST_data下即可。 #(2)MNIST数据集是手写数字字符的数据集。每个样本都是一张28*28像素的灰度手写数字图片。 #(3)one_hot表示独热编码,其值被设为true。在分类问题的数据集标注时,如何不采用独热编码的方式, 类别通常就是一个符号而已,比如说是9。但如果采用独热编码的方式,则每个类表示为一个列表list,共计有10个数值,但只有一个为1,其余均为0。例如,“9”的独热编码可以为[00000 00001]. #定义输入数据x和输出y的形状。函数tf.placeholder的目的是定义输入,可以理解为采用占位符进行占位。 #None这个位置的参数在这里被用于表示样本的个数,而由于样本个数此时具体是多少还无法确定,所以这设为None。而每个输入样本的特征数目是确定的,即为28*28。 input_x = tf.placeholder(tf.float32,[None,28*28])/255 #因为每个像素的取值范围是 0~255 output_y = tf.placeholder(tf.int32,[None,10]) #10表示10个类别 #输入层的输入数据input_x被reshape成四维数据,其中第一维的数据代表了图片数量 input_x_images = tf.reshape(input_x,[-1,28,28,1]) test_x = mnist.test.images[:3000] #读取测试集图片的特征,读取3000个图片 test_y = mnist.test.labels[:3000] #读取测试集图片的标签。就是这3000个图片所对应的标签
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值