本文可用于学习基于TensorFlow编写神经网络模型进行手写数字体识别!!!
import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data #载入MNIST数据集,自动划分训练、验证数据集 mnist = input_data.read_data_sets('MNIST_data/',one_hot=True) #获得数据集信息 print("训练集样本:",mnist.train.num_examples) print("验证集样本:",mnist.validation.num_examples) print("测试集样本:",mnist.test.num_examples) # print("训练样本:",mnist.train.images[0]) # print("训练样本标签:",mnist.train.labels[0]) print("训练样本维度:",mnist.train.images[0].shape) print("测试样本维度:",mnist.test.images[0].shape) #配置神经网络的参数 INPUT_NODE = 784#输入层节点数 OUTPUT_NODE = 10#输出层节点数 LAYER1_NODE = 500#隐层节点数 BATCH_SIZE = 100#每次训练的样本数 LEARNING_RATE_BASE = 0.8#初始学习速率 LEARNING_RATE_DECAY = 0.99#学习率的衰减率 LAMBDA = 0.0001#正则化系数 TRAINING_STEPS = 10000#训练轮数 MOVING_AVERAGE_DECAY = 0.99#滑动平均衰减率 #前向传播过程 def forward(x, avg_class, w1, b1, w2, b2): #如果没有提供滑动平均类时,直接使用参数当前的取值 if avg_class == None: #隐层输出 layer1 = tf.nn.relu( tf.matmul(x, w1) + b1 ) #返回输出层输出,不需要进行非线性.因为预测使用的是输出节点相对大小的列表索引,所以可以不需要softmax层 return tf.matmul( layer1, w2 ) + b2 else: #首先计算各变量的滑动平均值,再计算隐层输出 layer1 = tf.nn.relu( tf.matmul( x, avg_class.average(w1) ) + avg_class.average(b1) ) return tf.matmul( layer1, avg_class.average(w2) ) + avg_class.average(b2) #1.定义batch训练集的占位变量 x = tf.placeholder( tf.float32, [None, INPUT_NODE], name = 'x_input' ) y_ = tf.placeholder( tf.float32, [None, OUTPUT_NODE], name = 'y_input' ) #2.定义权重参数和偏置参数,正态分布初始化 w1 = tf.Variable( tf.truncated_normal( [INPUT_NODE, LAYER1_NODE], stddev = 0.1) ) w2 = tf.Variable( tf.truncated_normal( [LAYER1_NODE, OUTPUT_NODE], stddev = 0.1) ) b1 = tf.Variable( tf.constant(0.1, shape = [LAYER1_NODE]) ) b2 = tf.Variable( tf.constant(0.1, shape = [OUTPUT_NODE]) ) #3.获得没有滑动平均类的前向传播结果 y = forward( x, None, w1, b1, w2, b2 ) #4.定义当前训练轮数的变量,指定此参数为不可训练 global_step = tf.Variable( 0, trainable = False ) #初始化滑动平均类,给定滑动平均衰减率和当前训练的轮数 variable_averages = tf.train.ExponentialMovingAverage( MOVING_AVERAGE_DECAY, global_step ) #更新滑动平均值得操作,在所有代表神经网络参数的变量上使用滑动平均,global_step不需要,通过trainable=False指定 variable_averages_op = variable_averages.apply( tf.trainable_variables() ) #5.获得使用滑动平均类的前向传播结果 average_y = forward( x, variable_averages, w1, b1, w2, b2 ) #6.交叉熵损失函数 tf.argmax(y_, 1)获得二维列表y_每行列表的最大值索引,最终变成一维列表 cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits( logits=y, labels=tf.argmax(y_, 1) ) #batch的交叉熵损失均值 cross_entropy_mean = tf.reduce_mean( cross_entropy ) #7.L2正则化,一般只计算各层模型的正则化损失,不计算各层偏置损失 regularizer = tf.contrib.layers.l2_regularizer( LAMBDA ) regularition = regularizer(w1) + regularizer(w2) #8.计算总损失 loss = cross_entropy_mean + regularition #9.设置指数衰减的学习速率 (起始学习速率,当前迭代的轮数,训练完所有数据的轮数,学习率衰减速度) learning_rate = tf.train.exponential_decay( LEARNING_RATE_BASE, global_step, mnist.train.num_examples/BATCH_SIZE, LEARNING_RATE_DECAY ) #10.梯度下降算法优化损失函数 train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize( loss, global_step=global_step) #11.同时进行多个操作。训练神经网络时,每过一遍数据既需要完成反向传播更新神经网络参数,又需要更新每一个参数的滑动平均值 with tf.control_dependencies( [train_step, variable_averages_op] ): train_op = tf.no_op( name='train' ) #12.计算滑动平均模型的前向传播结果是否正确,tf.argmax(averabe_y, 1),返回维度为batch的一维数组,每个元素为预测数组的最大值索引 correct_prediction = tf.equal( tf.argmax(average_y, 1), tf.argmax(y_, 1) ) #计算准确率,将布尔型强制类型转换为实数型 accuracy = tf.reduce_mean( tf.cast( correct_prediction, tf.float32 ) ) #13.创建有上下文管理器的会话 with tf.Session() as sess: #初始化变量 tf.initialize_all_variables().run() #验证数据集 validate_feed = { x:mnist.validation.images, y_:mnist.validation.labels } #测试数据集 test_feed = { x:mnist.test.images, y_:mnist.test.labels } #迭代训练神经网络 for i in range(TRAINING_STEPS): #14.每1000轮输出一次在验证集、测试集上的测试结果 if i%1000==0: #验证集上的准确率 validate_acc = sess.run( accuracy, feed_dict = validate_feed ) print("当前模型在验证集上的准确率:", validate_acc) #测试集上的准确率 test_acc = sess.run( accuracy, feed_dict=test_feed ) print("当前训练模型在测试集上的准确率:", test_acc) #15.每一轮使用一个batch训练集 xs,ys = mnist.train.next_batch(BATCH_SIZE) sess.run( train_op, feed_dict={ x:xs, y_:ys } ) #16.最终测试集上的准确率 test_acc = sess.run( accuracy, feed_dict=test_feed ) print("最终训练模型在测试集上的准确率:", test_acc)
所用知识:
1.回归问题和分类问题的损失函数?
分类问题的损失函数常用交叉熵损失函数,输出层节点数量为类别数量;回归问题的损失函数常用均方误差(MSE,mean squared error)损失函数,输出层节点数量一般为一个节点,节点的输出值即为预测值。
2.交叉熵损失函数?
刻画的是实际输出p(概率)与期望输出q(概率)的距离,也就是交叉熵的值越小,两个概率分布就越接近。在神经网络中,交叉熵常常与Sorfmax函数组合使用。在TensorFlow中,其交叉熵损失函数获得nxm矩阵,n为batch数量,m为类别数量,其最终结果为整个矩阵的均值(先对行求均值,再对列求均值),即为整个batch的平均交叉熵;
2.梯度下降算法?
批量梯度下降:不能保证被优化的函数(凸函数可以)达到全局最优解;计算时间长,因为损失函数J是在所有训练数据上的损失和。
随机梯度下降:为了加速训练过程,可以使用随机梯度下降算法,在每一轮迭代中,随机优化某一条训练数据上的损失函数。但是可能无法达到局部最优;
batch梯度下降:综合批量梯度下降算法和随机梯度下降算法,提出了batch梯度下降,每次计算一个batch训练数据上的损失函数,优化神经网络上的参数。
4.验证数据的作用?
神经网络模型的最终目标是对未知数据的预测。所以一般从训练数据集中获取一部分验证数据集用于调试模型参数,(当数据量较小时,可使用交叉验证的方法)然后用此模型对测试数据进行预测。
参考资料:
1.《TensorFlow实战Google深度学习框架》