TensorFlow官方文档样例——三层卷积神经网络训练MNIST数据

        上篇博客根据TensorFlow官方文档样例实现了一个简单的单层神经网络模型,在训练10000次左右可以达到92.7%左右的准确率。但如果将神经网络的深度拓展,那么很容易就能够达到更高的准确率。官方中文文档中就提供了这样的样例,它的网络结构如下:

  • 输入层(28 * 28 * 1)
  • 卷积层1(28 * 28 * 32)
  • 池化层1(14 * 14 * 32)
  • 卷积层2(14 * 14 * 64)
  • 池化层2(7 * 7 * 64)
  • 全连接层(1 * 1024)
  • softmax层(10)

        使用卷积层给神经网络带来的好处是能够提取到图像的边缘特征,但是由于图片本身尺寸一般较大,通过卷积层获得到的特征数量也会很大,而通过池化层(一般为最大池化层)进行池化,能够将特征中最为明显的部分提取出来,在尽量不损失特征的情况下,达到缩小特征数量的目的。

        关于这些层的意义与原理,在吴恩达的deeplearning.ai课程中有非常详尽的描述,这里给上网易云课堂的链接。大家可以自行去学习。

        本次的代码使用了上篇博客提到的TensorFlow的内置函数  tf.nn.softmax_cross_entropy_with_logits() 。

        本次的代码使用了dropout函数,是一个应对神经网络中过拟合非常有效的方式。

        本次代码使用时,因为本人没有在优化器函数  train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)  中自定义使用学习速率参数,导致优化器不能自适应训练数据所需的学习速率,将会使损失函数无法收敛。添加学习速率参数如 1e-4 后,损失函数可以正常收敛,模型正常进行训练。

       代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import tensorflow as tf
import time

# 模型结构
# 输入层(28 * 28 * 1)
# 卷积层1(28 * 28 * 32)
# pooling层1(14 * 14 * 32)
# 卷积层2(14 * 14 * 64)
# pooling层2(7 * 7 * 64)
# 全连接层(1 * 1024)
# softmax层(10)

sess = tf.InteractiveSession()

# 从TensorFlow的样例中获取下载mnist的文件,并解压输入
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
NUM_STEPS = 10000
MINIBATCH_SIZE = 64

x = tf.placeholder(tf.float32, [None, 784])     # 初始化输入图像矩阵x
W = tf.Variable(tf.zeros([784, 10]))            # 初始化权重矩阵w
b = tf.Variable(tf.zeros([10]))                 # 初始化偏置矩阵b
y_labels = tf.placeholder("float", [None, 10])  # 初始化标签矩阵y_labels


def weight_variable(shape):
    """权重初始化函数,接收矩阵行列值,返回权重矩阵"""
    initial = tf.truncated_normal(shape, stddev=0.1)    # 产生正太分布数据
    return tf.Variable(initial)


def bias_variable(shape):
    """权重初始化函数,接收矩阵行列值,返回权重矩阵"""
    initial = tf.constant(0.1, shape=shape)     # 产生常量
    return tf.Variable(initial)


def conv2d(x, W):
    """二维图像卷积函数"""
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')    # 步长为1,尺寸不变,边距为'SAME',尺寸不变


def max_pool_2x2(x):
    """2x2的最大池化层"""
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')    # 2x2池化,步长为2,宽高缩小一倍


# 计算开始时间
start = time.clock()

"""第一层卷积,在每个5x5的patch中算出32个特征,得到[28,28,32],第一层池化,将4个像素池化为1个,使宽高缩减一半成为[14,14,32]"""

"""将x转化为四维向量,分别为图片数量,宽,高,通道# (取-1,使每次从x中取出[28,28,1]后,就会取下一个同样的矩阵,因此可以取出一个个[28,28,1])"""
x_image = tf.reshape(x, [-1, 28, 28, 1])
W_conv1 = weight_variable([5, 5, 1, 32])    # 权重矩阵,前两个维度为patch的大小,以及输入通道数目,输出通道数目
b_conv1 = bias_variable([32])               # 偏置矩阵,每个输出通道对应一个输出矩阵

h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)    # 第一层卷积,激活函数为relu
h_pool1 = max_pool_2x2(h_conv1)                             # 第一层卷积后的池化层

"""第二层卷积,在每个5x5的patch中由32个特征计算出64个特征,得到[14,14,64],第一层池化,将4个像素池化为1个,使宽高缩减一半成为[7,7,64]"""
W_conv2 = weight_variable([5, 5, 32, 64])   # 权重矩阵,前两个维度为patch的大小,以及输入通道数目,输出通道数目
b_conv2 = bias_variable([64])               # 偏置矩阵,每个输出通道对应一个输出矩阵

h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)    # 第二层卷积,激活函数为relu
h_pool2 = max_pool_2x2(h_conv2)                             # 第一层卷积后的池化层

"""密集连接层(全连接层),在每个5x5的patch中算出32个特征"""
W_fc1 = weight_variable([7 * 7 * 64, 1024])    # 权重矩阵,维度为输入特征数目,输出通道数目
b_fc1 = bias_variable([1024])                  # 偏置矩阵,每个输出通道对应一个输出特征

h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])            # 全连接层,把输入reshape回向量
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)  # 全连接层,激活函数为relu

"""dropout层,随机丢弃部分权重值,以达到预防过拟合的效果"""
keep_prob = tf.placeholder("float")             # dropout层,保留参数率,可使训练时启动dropout层,测试时关闭dropout层
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)    # dropout层

"""softmax层,根据1024个特征计算输出标签"""
W_fc2 = weight_variable([1024, 10])            # 权重矩阵,维度为输入特征数目,标签数
b_fc2 = bias_variable([10])                    # 偏置矩阵,每个输出通道对应一个标签

y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)    # softmax层,计算输出标签

# cross_entropy = -tf.reduce_sum(y_labels*tf.log(y_conv))    # 使用TensorFlow内置的交叉熵函数避免出现权重消失问题
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_labels, logits=y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)    # 调用Adma算法,最小化损失函数
correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_labels, 1))    # 计算预测准确的数量
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))    # 计算准确率
sess.run(tf.global_variables_initializer())
for i in range(NUM_STEPS):
    # 随机获取批数据进行训练
    batch = mnist.train.next_batch(MINIBATCH_SIZE)
    train_step.run(feed_dict={x: batch[0], y_labels: batch[1], keep_prob: 0.5})    # 以0.5的dropout保留率进行训练

    if i % 100 == 0:    # 每当训练次数达到100的整数倍时,输出当前批次训练集数据的准确率
        train_accuracy = accuracy.eval(feed_dict={
            x: batch[0], y_labels: batch[1], keep_prob: 1.0})
        print("训练次数为{}次时,当前批次训练集准确率为:{:.4}%".format(i, 100 * train_accuracy))

    if i % int(NUM_STEPS/10) == 0 and i != 0:    # 每当训练次数达到1000的整数倍时,输出当前模型在验证集以及测试集上的准确率
        validation_accuracy = []
        for _ in range(int(mnist.validation.num_examples / MINIBATCH_SIZE)):    # 由于内存问题,将验证集分批获取并计算准确率
            batch = mnist.validation.next_batch(MINIBATCH_SIZE)
            validation_accuracy.append(accuracy.eval(feed_dict={x: batch[0], y_labels: batch[1], keep_prob: 1.0}))    # 以1.0的dropout保留率进行训练

        test_accuracy = []
        for _ in range(int(mnist.test.num_examples / MINIBATCH_SIZE)):    # 由于内存问题,将测试集分批获取并计算准确率
            batch = mnist.test.next_batch(MINIBATCH_SIZE)
            test_accuracy.append(accuracy.eval(feed_dict={x: batch[0], y_labels: batch[1], keep_prob: 1.0}))    # 以1.0的dropout保留率进行训练

        print("训练已完成{:.4}%, 当前训练次数为{}次,验证集准确率为:{:.4}%, 测试集准确率为: {:.4}%".format(i / int(NUM_STEPS/100), i,
            100 * sum(validation_accuracy) / (mnist.validation.num_examples / MINIBATCH_SIZE), 100 * sum(test_accuracy) / (mnist.test.num_examples / MINIBATCH_SIZE)))


test_accuracy = []
for _ in range(int(mnist.test.num_examples / MINIBATCH_SIZE)):    # 由于内存问题,将测试集分批获取并计算准确率
    batch = mnist.test.next_batch(MINIBATCH_SIZE)
    test_accuracy.append(accuracy.eval(feed_dict={x: batch[0], y_labels: batch[1], keep_prob: 1.0}))    # 以1.0的dropout保留率进行训练
print("训练完成,测试集准确率为: {:.4}%".format(100 * sum(test_accuracy) / (mnist.test.num_examples / MINIBATCH_SIZE)))

# 计算程序结束时间
end = time.clock()
print("训练完成,本次共训练{}轮,用时{}秒".format(NUM_STEPS, end-start))

        以上为TensorFlow的官方文档入门样例,对MNIST手写数字数据集使用三层卷积神经网络的我的一个总结。

猜你喜欢

转载自blog.csdn.net/hwl19951007/article/details/81126699
今日推荐