tensorflow实践-mnist数字识别(1)

tensorflow实践-mnist数字识别(1)

简单版本

利用tensorflow含有的mnist数据集训练一个简单的数字识别神经网络。
在一个脚本中实现一个完整的训练过程并每隔固定的轮数,在测试集中验证准确率。

脚本中几个注意的点

  1. 使用了随迭代变化的学习率。可以控制模型在训练初期的时候以较大的学习率进行调整,而到了后期以较小的学习率进行微调参数,不至于来回摆动。
  2. 使用滑动平率模型,用来维护一个影子变量,可以在一定程度上提高在测试集上的表现,使得模型更加稳健。
  3. 在损失函数中,增加正则损失,防止模型过拟合。
衰减的学习率
  • 计算公式: d = l r ∗ d e c y ∗ e x p ( g l o b a l S t e b / b a s e S t e p ) d=lr * decy *exp(globalSteb/baseStep) d=lrdecyexp(globalSteb/baseStep)
    • d :学习率
    • lr:初始学习率
    • decy:学习率衰减率
    • globalSteb:当前训练的轮数
    • baseStep:训练完一遍数据所需要的轮数,一般为训练数据除以batch数
  • 实现方式:tf.train.exponential_decay(lr, globalStep, baseStep, decy, staircase=True)
  • 参数:staircase; 当这个参数设置为True的时候,这个时候的指数优化会变成阶梯函数,这个时候学习率是阶梯下降的,可以设置base_step为训练完一遍数据需要的迭代轮数。这个值默认为false。
滑动平均模型
  • 计算公式:
    • s h a d o w V a r i a b l e = s h a d o w V a r i a b l e ∗ d e c a y + ( 1 − d e c a y ) ∗ v a r i a b l e shadowVariable = shadowVariable * decay + (1-decay) * variable shadowVariable=shadowVariabledecay+(1decay)variable
    • d e c a y = m i n ( u s e r D e c a y , ( 1 + n u m U p d a t e s ) / ( 10 + n u m U p d a t e s ) ) decay = min(userDecay, (1+numUpdates)/(10+numUpdates)) decay=min(userDecay,(1+numUpdates)/(10+numUpdates))
      • shadowVariable:影子变量
      • variable:真实的变量
      • userDecay:用户定义的滑动平均衰减率
      • numUpdates:此时的训练轮数
  • 实现方式:
    • 通过 ema=tf.train.ExponentialMovingAverage(user_decay, num_updates) 初始化
    • maintrain_ema = ema.apply([v1]) 在变量上运用滑动平均
正则损失
  • 计算方式:通过对每一个参数进行惩罚,当参数量很多时,损失就会大很多。正则方式(L1,L2)
  • 通过 tf.contrib.layers.l2_regularizer(lambda)(w) 进行调用L2正则损失
完整脚本
# -*- coding: utf-8 -*-
"""
Created on Fri Sep  6 13:52:31 2019

@author: JustMo
"""

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# mnist = input_data.read_data_sets("/wind/ainfs/jupyterspace/yxmo/Tensorflow/", one_hot=True)

## 定义初始化参数,对于一些
INPUT_NODE = 784 #因为是32*32的图片格式
OUTPUT_NODE = 10 #输出的是数字的分类
###网络参数
LAYYER1_NODE = 500 #定义第一层网络的节点数
BATCH_SIZE = 100 #定义一个batch训练的数据量,batch越小越接近随机梯度下降,batch越大越接近梯度下降
TRAINING_STEPS = 30000 #训练的轮数
###各种率参数
LEARNING_RATE_BASE = 0.8 #初始的学习率,越大参数的优化越快
LEARNING_RATE_DECAY = 0.99 #学习率的衰减率
REGULARIZATION_RATE = 0.0001 #模型复杂度的正则参数
MOVING_AVERAGE_DECAY = 0.99 #滑动平均衰减率,初始比较大,可以在训练前期更新得更快

## 定义模型的网络框架
## 接下来定义一个函数,用来计算每一轮的前向传播训练结果,这里定义了一个三层的全连接网络
## 最后一层由于有加入softmax的损失函数,所以可以不用加激活函数
## 还加入了滑动平均模型
def inference(input_tensor, avg_class, weights1, biases1, weights2, biases2):
    #当没有提供滑动平均类的时候,直接使用参数当前的取值
    if avg_class == None:
        ##进行前向计算
        layer1 = tf.nn.relu(tf.matmul(input_tensor, weights1) + biases1)
        
        ##因为准备用封装了softmax的cross_enrtopy,所以最后一层没有加激活函数直接输出
        return tf.matmul(layer1, weights2) + biases2
    else:
        ##使用avg_class.average来计算变量滑动平均值,然后再利用变量进行前向的计算
        layer1 = tf.nn.relu(tf.matmul(input_tensor, avg_class.average(weights1)) + avg_class.average(biases1))
        
        return tf.matmul(layer1, avg_class.average(weights2)) + avg_class.average(biases2)
    
def train(mnist):
    ##定义输入
    x = tf.placeholder(dtype=tf.float32, shape=(None, INPUT_NODE), name="x-input")
    y_ = tf.placeholder(dtype=tf.float32, shape=(None, OUTPUT_NODE), name="y-input")
    
    ##定义权重
    weights1 = tf.Variable(tf.random_normal([INPUT_NODE, LAYYER1_NODE], stddev=0.1, seed=1, dtype=tf.float32), name="w-1")
    biases1 = tf.Variable(tf.constant(0.1, shape=[LAYYER1_NODE]), dtype=tf.float32, name="b-1")
    weights2 = tf.Variable(tf.random_normal([LAYYER1_NODE, OUTPUT_NODE], stddev=0.1, seed=1, dtype=tf.float32), name="w-2")
    biases2 = tf.Variable(tf.constant(0.1, shape=[OUTPUT_NODE]), dtype=tf.float32, name="b-2")
    
    ##定义输出
    ##这里的avg_class设置为None,所以没有进行滑动平均
    y = inference(x, None, weights1, biases1, weights2, biases2)
    
    ##接下来进行定义当前运行的轮数,用来进行更新学习率以及调整滑动平均衰减率,这个变量是不可训练的
    global_step = tf.Variable(0, trainable=False)#初始状态训练轮数为0
    
    ##定义滑动平均的声明
    variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
    
    ##在定义好了滑动平均声明之后,对整个网络中的可训练的参数使用滑动平均
    variable_averages_op = variable_averages.apply(tf.trainable_variables())
    
    ##利用滑动平均计算前向传播的结果
    average_y = inference(x, variable_averages, weights1, biases1, weights2, biases2)
    
    ##定义好各个变量之后,需要定义损失函数,确定优化方向,这里因为是多分类所以使用的是softmax
    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)
    
    ##为了防止过拟合,这里除了使用交叉验证之外,加入正则项约束,因为一般不对偏置进行正则,所以这里不用trainable_variables
    regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)
    regularization = regularizer(weights1) + regularizer(weights2)
    
    ##计算总的损失
    loss = cross_entropy_mean + regularization
    
    ##在定义反向传播优化参数之前,需要对学习率进行设置,因为这里将要使用随训练轮数增加进行改变,注意global_step是没有传值的
    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)
    
    ##因为在整个训练网络中,每过一遍数据,即需要通过反向传播来更新神经网络中的参数,也需要更新每一个参数的滑动平均值
    ##下面的方法将可以将这两个优化,在一次运算中完成
    with tf.control_dependencies([train_step, variable_averages_op]):
        train_op = tf.no_op(name="train")
    ##上面的两行代码可以用  train_op = tf.group([train_step, variable_averages_op])  等价
    
    ##上面就是训练过程定义,接下来需要验证使用了滑动平均模型的神经网络的传播结果正确性,故需要计算准确率
    ###先判断滑动平均预测出来的结果与真实结果的对比情况
    correct_prediction = tf.equal(tf.argmax(average_y, 1), tf.argmax(y_, 1))
    ##为了直观看结果,这种判断结果进行量化,cast将转换为实数型
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, dtype=tf.float32))
    
    
    ###上面定义好了整个的训练过程,优化过程以及损失、准确率计算时候,计算图中的节点的变量以及运算都确定,接下来需要建立一个会话来执行运算
    with tf.Session() as sess:
        ##进行全部参数的初始化
        tf.global_variables_initializer().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):
            ##为了判断模型效果,每1000轮训练看一次测试结果
            if i % 1000 == 0:
                ##看训练的参数在验证集上的准确率
                validate_acc = sess.run(accuracy, feed_dict=validate_feed)
                print("在训练轮数为 %d 时,数据在验证集上的准确率为 %g"%(i,validate_acc))
                print("global_step %d"%(sess.run(global_step)))
            
            #产生新的一轮迭代训练数据进行模型的训练
            xs, ys = mnist.train.next_batch(BATCH_SIZE)
            ##并调用train_op进行反向迭代以及滑动平均变量的计算
            sess.run(train_op, feed_dict={x:xs, y_:ys})
            
        
        ##当训练完所有轮之后,看整个模型在测试集上的一个预测效果
        test_acc = sess.run(accuracy, feed_dict=test_feed)
        print("经过了 %d 轮的训练之后,模型在测试集上的准确率为 %g"%(TRAINING_STEPS, test_acc))
    
def main(argv=None):
    #声明处理mnist的类,在程序运行的时候自动下载数据
    mnist = input_data.read_data_sets("/path/to/MNIST_data/", one_hot=True)
    
    train(mnist)

if __name__ == "__main__":
    ##tensorflow提供了一个主程序的入口,tf.app.run()会调用上面的main函数
    tf.app.run()

参考资料

tensorflow:实战Google深度学习框架。1


  1. tensorflow:实战Google深度学习框架,郑泽宇、梁博文、顾思宇。 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值