#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2018/5/16 8:53
# @Author : HJH
# @Site :
# @File : classification1.py
# @Software: PyCharm
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
INPUT_SIZE=784
OUT_SIZE=10
# 设置神经网络参数
LAYER1_NODE=500
# 每个Batch的大小
BATCH_SIZE=100
# 基础学习率及其衰减率
LEARNING_RATE_BASE=0.8
LEARNING_RATE_DECAY=0.99
# 正则化损失系数,训练轮数,滑动平均衰减率
REGULARIZATION_RATE=0.0001
TRAINING_STEPS=30000
MOVING_AVERAGE_DECAY=0.99
#计算神经网络前向传播结果
def inference(input_tensor,avg_class,Weight1,biase1,Weight2,biase2):
if avg_class == None:
layer1=tf.nn.relu(tf.matmul(input_tensor,Weight1)+biase1)
return tf.matmul(layer1,Weight2)+biase2
else:
layer1=tf.nn.relu(tf.matmul(input_tensor,avg_class.average(Weight1))+avg_class.average(biase1))
return tf.matmul(layer1,avg_class.average(Weight2))+avg_class.average(biase2)
def train(mnist):
X=tf.placeholder(tf.float32,[None,INPUT_SIZE],name='x_input')
y=tf.placeholder(tf.float32,[None,OUT_SIZE],name='y_input')
# 隐藏层参数
Weight1=tf.Variable(tf.truncated_normal([INPUT_SIZE,LAYER1_NODE],stddev=0.1))
biase1=tf.Variable(tf.constant(0.1,shape=[LAYER1_NODE]))
# 输出层参数
Weight2 = tf.Variable(tf.truncated_normal([LAYER1_NODE, OUT_SIZE], stddev=0.1))
biase2 = tf.Variable(tf.constant(0.1, shape=[OUT_SIZE]))
pre_y=inference(X,None,Weight1,biase1,Weight2,biase2)
# 定义存储训练轮数的变量,这个变量不需要计算滑动平均值,所以这个变量为不可训练变量
# 为什么要把它设为0,在训练过程中,每一次train_step,global_step都会增加1,所以后面这个值会越来越大
global_step=tf.Variable(0,trainable=False)
# 给定滑动平均衰减率和训练轮数的变量,初始化滑动平均类
# 给定训练轮数的变量可以加快训练早期变量的更新速度。
variable_average=tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)
# 在所有神经网络参数的变量上使用滑动平均,所有没有指定trainable=False的参数。
variable_average_op=variable_average.apply(tf.trainable_variables())
# 计算滑动平均之后的前向传播结果
# 滑动平均不会改变变量本身的取值,而是会维护一个影子变量来记录其滑动平均值
# 所以当需要使用这个滑动平均值时,需要明确调用average函数。
average_y=inference(X,variable_average,Weight1,biase1,Weight2,biase2)
# 使用交叉熵计算损失函数,注意这里用的是pre_y来计算交叉熵而不是average_y
cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=pre_y,labels=tf.argmax(y,1))
# 计算在当前batch中所有样例的交叉熵平均值
cross_entropy_mean=tf.reduce_mean(cross_entropy)
# 正则化
regularizer=tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)
# 正则化损失
regularization=regularizer(Weight1)+regularizer(Weight2)
# 总体损失
loss=cross_entropy_mean+regularization
# 设置指数衰减的学习率
learning_rate=tf.train.exponential_decay(
LEARNING_RATE_BASE, # 基础的学习率,随着迭代的进行,更新变量时使用的学习率在这个基础上递减
global_step, # 当前迭代的轮数
mnist.train.num_examples / BATCH_SIZE, # 过完所有的训练数据需要的迭代次数
LEARNING_RATE_DECAY) # 学习率的衰减速度
# 优化损失函数
train_step=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)
# 在训练神经网络模型时,每过一遍数据既需要通过反向传播来更新神经网络中的参数,
# 又要更新每个参数的滑动平均值。为了一次完成多个操作,TensorFlow提供了
# tf.control_dependencies和tf.group两种机制。下面两行程序和
# train_op = tf.group(train_step, variables_average_op)是等价的。
with tf.control_dependencies([train_step,variable_average_op]):
# tf.no_op是一个没有实际意义的函数
train_op=tf.no_op(name='train')
# 检验使用了滑动平均模型的神经网络前向传播结果是否正确。tf.argmax(average_y, 1)
# 计算每一个样例的预测结果。其中average_y是一个batch_size * 10的二维数组,每一行
# 表示一个样例的前向传播结果。tf.argmax的第二个参数“1”表示选取最大值的操作仅在第一
# 个维度中进行,也就是说,只在每一行选取最大值对应的下标。于是得到的结果是一个长度为
# batch的一维数组,这个一维数组中的值就表示了每一个样例对应的数字识别结果。tf.equal
# 判断两个张量的每一维是否相等,如果相等返回True,否则返回False。
correct_prediction=tf.equal(tf.argmax(average_y,1),tf.argmax(y,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
with tf.Session() as sess:
init=tf.global_variables_initializer()
sess.run(init)
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):
if i%1000==0:
validate_acc=sess.run(accuracy,feed_dict=validate_feed)
print("After %d training step(s), validation accuracy "
"using average model is %g " % (i, validate_acc))
xs,ys=mnist.train.next_batch(BATCH_SIZE)
sess.run(train_op,feed_dict={X:xs,y:ys})
test_acc = sess.run(accuracy, feed_dict=test_feed)
print("After %d training step(s), test accuracy using average "
"model is %g" % (TRAINING_STEPS, test_acc))
def main(argv=None):
mnist=input_data.read_data_sets('MNIST_data', one_hot=True)
train(mnist)
if __name__=='__main__':
tf.app.run()