import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
input_node = 784
output_node = 10
layer1_node = 500
batch_size = 100
#基础学习率
learing_rate_base = 0.8
#学习率的衰减率
learing_rate_decay = 0.99
#复杂度的正则化在损失函数中的系数
regularization_rate = 0.0001
# 迭代次数
traing_steps = 30000
#滑动平均衰减率
moving_average_decay = 0.99
def inference(input, avg_class, w1, b1, w2, b2):
#avg_class 当没有提供滑动平均类时, 直接使用参数当前的取值
if avg_class == None:
layer1 = tf.nn.relu(tf.matmul(input, w1) + b1)
return tf.nn.softmax(tf.matmul(layer1, w2) + b2)
else:
layer1 = tf.nn.relu(tf.matmul( input, avg_class.average(w1) + avg_class.average(b1)) )
return tf.nn.softmax(tf.matmul(layer1, avg_class.average(w2)) + avg_class.average(b2))
def train(mnist):
x = tf.placeholder(tf.float32, [None, input_node], name='x-input')
y = tf.placeholder(tf.float32, [None, output_node], name='y-input')
#第一层
w1 = tf.Variable(tf.truncated_normal(shape=(input_node, layer1_node), stddev=0.1))
b1 = tf.Variable(tf.constant(shape=[layer1_node], value=0.1))
#输出层
w2 = tf.Variable(tf.truncated_normal(shape=(layer1_node, output_node), stddev=0.1))
b2 = tf.Variable(tf.constant(shape=[output_node], value=0.1))
y_ = inference(x, None, w1, b1, w2, b2)
#定义存储训练轮数的变量,这个变量不需要计算滑动平均值,
#所以这里指定这个变量为不可训练的变量(trainable=False)
#在使用tf训练网络时,一般会将代表训练轮数的吧变量指定为不可训练的参数.
global_step = tf.Variable(0, trainable=False)
'''
使用平均滑动模型
1.初始化滑动平均的函数类,加入训练轮数的变量可以加快需年早期变量的更新速度
2.对神经网络里所有可训练参数(列表)应用滑动平均模型,每次进行这个操作,列表里的元素都会得到更新
3.计算使用了滑动平均的网络前向传播结果,滑动是维护影子变量来记录其滑动平均值,需要使用时要明确调用average函数
'''
variable_averages = tf.train.ExponentialMovingAverage(moving_average_decay,
global_step)
# for ele1 in tf.trainable_variables():
# print( ele1.name )
# with tf.Session() as sess:
# sess.run(tf.global_variables_initializer())
# print( sess.run(tf.trainable_variables()) )
variable_averages_op = variable_averages.apply(tf.trainable_variables())
average_y = inference(x, variable_averages, w1, b1, w2, b2)
'''
定义loss
当只有一个标准答案的时候,使用sprase_softmax_cross_entropy_with_logits计算损失,可以加速计算
参数:不包含softma层的前向传播结果,训练数据的正确答案
因为标准答案是一个长度为10的一维数组,而该函数需要提供一个正确答案的数字
因此需要使用tf.argmax函数得到正确答案的对应类别编号
'''
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.argmax(y,1), logits=y_)
# 计算在当前batch里所有样例的交叉熵平均值,并加入损失集合
cross_entropy_mean = tf.reduce_mean(cross_entropy)
#计算l2正则化损失函数
regularizer = tf.contrib.layers.l2_regularizer(regularization_rate)
#计算模型正则化损失, 一般只计算神经网络边上权重的正则化损失,不计算偏置项
#regularization = regularizer(w1) + regularizer(w2) 与下面的等价
#计算权重的l2正则化
tf.add_to_collection('losses', regularizer(w1))
tf.add_to_collection('losses', regularizer(w2))
tf.add_to_collection('losses', cross_entropy_mean)
# get_collection返回一个列表,列表是所有这个集合的所有元素(在本例中,元素代表了其他部分的损失,加起来就得到了所有的损失)
loss = tf.add_n(tf.get_collection('losses')) # regularizer(w1) + regularizer(w2) + cross_entropy_mean
'''
设置指数衰减的学习率
使用GradientDescentOptimizer()优化算法的损失函数
'''
learning_rate = tf.train.exponential_decay(learning_rate=learing_rate_base, # 基础的学习率,在此基础上进行递减
global_step=global_step, # 迭代的轮数
decay_steps=mnist.train.num_examples / batch_size, # 所有的数据得到训练所需要的轮数
decay_rate=learing_rate_decay # 学习率衰减速度
)
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
'''
在训练神经网络模型的时候,每过一次数据既需要BP更新参数又要更新参数的滑动平均值。
为了一次完成多种操作,tensroflow提供了两种机制:tf.control_dependencies和tf.group
'''
#train_op = tf.group(train_step, variable_averages_op) #用于创造一个操作,可以将传入参数的所有操作进行分组
with tf.control_dependencies([train_step, variable_averages_op]):
train_op = tf.no_op(name='train')
'''
进行验证集上的准确率计算,这时需要使用滑动平均模型
判断两个张量的每一维是否相等,如果相等就返回True,否则返回False
这个运算先将布尔型的数值转为实数型,然后计算平均值,平均值就是准确率
'''
correct_prediction = tf.equal(tf.argmax(average_y, 1), tf.argmax(y, 1))
acc = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
# 准备验证数据,一般在神经网络的训练过程中会通过验证数据来判断大致停止的条件和评判训练的效果
validate_feed = {x: mnist.validation.images, y: mnist.validation.labels}
# 准备测试数据,在实际中,这部分数据在训练时是不可见的,这个数据只是作为模型优劣的最后评价标准
test_feed = {x: mnist.test.images, y: mnist.test.labels}
# 迭代的训练神经网络
for i in range(1000000):
xs, ys = mnist.train.next_batch(batch_size)
xs = xs/255
_, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: xs, y: ys})
if i % 1000 == 0:
print("After %d training step(s), loss on training batch is %g." % (step, loss_value))
validate_acc = sess.run(acc, feed_dict=validate_feed)
print("After %d training step(s),validation accuracy using average model is %g " % (step, validate_acc))
test_acc = sess.run(acc, feed_dict=test_feed)
print("After %d training step(s) testing accuracy using average model is %g" % (step, test_acc))
#TensorFlow主程序入口
def main(argv=None):
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
train(mnist)
#TensorFlow提供了一个主程序入口,tf.app.run会调用上面定义的main函数
if __name__ == '__main__':
tf.app.run()