全连神经网络的经典实战--MNIST手写体数字识别

mnist数据集

MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片:它也包含每一张图片对应的标签,告诉我们这个是数字几。比如,上面这四张图片的标签分别是5,0,4,1。 在本章中,我们将训练一个机器学习模型用于预测图片里面的数字。

  • from tensorflow.examples.tutorials.mnist import input_data
  • read_data_sets(train_dir,fake_data=False,one_hot=False,dtype=dtypes.float32,reshape=True,validation_size=5000)

  • train_dir 需要传入放置mnist数据的路径,如果在train_dir路径下没有找到MNIST数据集文件,read_data_sets()函数就会调用mnist.py文 件中的其他函数在Yann LeCun教授的网站下载MNIST数据集文件

  • one_hot=True 指定是否将样本图片对应到标注信息(label,即答案)

  • import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    mnist = input_data.read_data_sets("/Users/目录/", one_hot=True)
    print('Training data and label size:')
    print(mnist.train.images.shape,mnist.train.labels.shape)
    print('testing data and label size:')
    print(mnist.test.images.shape,mnist.test.labels.shape)
    print('validating data and label size:')
    print(mnist.validation.images.shape,mnist.validation.labels.shape)
    print('example training data:',mnist.train.images[0])
    print('............................')
    print('example training label:',mnist.train.labels[0])
    print(mnist.train.images[0].shape)
    print('example training data:',mnist.train.images[67])
    print('............................')
    print('example training label:',mnist.train.labels[67])
    print('example training data:',mnist.train.images[54999])
    print('............................')
    print('example training data:',mnist.train.labels[54999])
    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    mnist = input_data.read_data_sets("/Users/zhouhongxiao/Downloads/MNIST_data/", one_hot=True)
    
    batch_size = 100                #设置每一轮训练的batch大小
    learning_rate = 0.8             #学习率
    learning_rate_decay = 0.999     #学习率的衰减
    max_steps = 30000               #最大训练步数
    
    #定义存储训练轮数的变量,在使用Tensorflow训练神经网络时,
    #一般会将代表训练轮数的变量通过trainable参数设置为不可训练的
    training_step = tf.Variable(0,trainable=False)
    
    #定义得到隐藏层和输出层的前向传播计算方式,激活函数使用relu()
    def hidden_layer(input_tensor,weights1,biases1,weights2,biases2,layer_name):
        layer1=tf.nn.relu(tf.matmul(input_tensor,weights1)+biases1)
        return tf.matmul(layer1,weights2)+biases2
    
    x = tf.placeholder(tf.float32,[None,784],name="x-input")   #INPUT_NODE=784
    y_ = tf.placeholder(tf.float32,[None,10],name="y-output")   #OUT_PUT=10
    #生成隐藏层参数,其中weights包含784x500=392000个参数
    weights1=tf.Variable(tf.truncated_normal([784,500],stddev=0.1))
    biases1 = tf.Variable(tf.constant(0.1,shape=[500]))
    #生成输出层参数,其中weights2包含500x10=5000个参数
    weights2 = tf.Variable(tf.truncated_normal([500, 10], stddev=0.1))
    biases2 = tf.Variable(tf.constant(0.1, shape=[10]))
    
    #计算经过神经网络前向传播后得到的y的值,这里没有使用滑动平均
    y = hidden_layer(x,weights1,biases1,weights2,biases2,'y')
    
    
    #初始化一个滑动平均类,衰减率为0.99
    #为了使模型在训练前期可以更新地更快,这里提供了num_updates参数
    #并设置为当前网络的训练轮数
    averages_class = tf.train.ExponentialMovingAverage(0.99,training_step)
    #定义一个更新变量滑动平均值的操作需要向滑动平均类的apply()函数提供一个参数列表
    #train_variables()函数返回集合图上Graph.TRAINABLE_VARIABLES中的元素,
    #这个集合的元素就是所有没有指定trainable_variables=False的参数
    averages_op = averages_class.apply(tf.trainable_variables())
    #再次计算经过神经网络前向传播后得到的y的值,这里使用了滑动平均,但要牢记滑动平均值只是一个影子变量
    average_y = hidden_layer(x,averages_class.average(weights1),averages_class.average(biases1),
                    averages_class.average(weights2),averages_class.average(biases2),'average_y')
    
    #计算交叉熵损失的函数原型为sparse_softmax_cross_entropy_with_logits(_sential, labels, logdits, name)
    #它与softmax_cross_entropy_with_logits()函数的计算方式相同,适用于每个类别相互独立且排斥的情况,
    #即一幅图只能属于一类。在1.0.0版本的TensorFlow中,这个函数只能通过命名参数的方式来使用,在这里
    #logits参数是神经网络不包括softmax层的前向传播结果,lables参数给出了训练数据的正确答案
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=tf.argmax(y_, 1))
    #argmax()函数原型为argmax(input, axis, name, dimension),用于计算每一个样例的预测答案,
    #其中input参数y是一个batch_size * 10(batch_size行,10列)的二维数组,每一行表示一个样例前向传播的结果,
    #axis参数“1”表示选取最大值的操作仅在第一个维度中进行,即只在每一行选取最大值对应的下标。
    #于是得到的结果是一个长度为batch_size的一维数组,这个一维数组中的值就表示了每一个样例对应的
    #数字识别结果。
    
    
    regularizer = tf.contrib.layers.l2_regularizer(0.0001)       #计算L2正则化损失函数
    regularization = regularizer(weights1)+regularizer(weights2) #计算模型的正则化损失
    loss = tf.reduce_mean(cross_entropy)+regularization          #总损失
    
    
    #用指数衰减法设置学习率,这里staircase参数采用默认的False,即学习率连续衰减
    laerning_rate = tf.train.exponential_decay(learning_rate,training_step,mnist.train.num_examples/batch_size,
                                                                                           learning_rate_decay)
    #使用GradientDescentOptimizer优化算法来优化交叉熵损失和正则化损失
    train_step= tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=training_step)
    
    
    #在训练这个模型时,每过一遍数据既需要通过反向传播来更新神经网络中的参数又需要
    #更新每一个参数的滑动平均值,control_dependencies()用于完成这样的一次性多次操作,
    # 同样的操作也可以使用下面这行代码完成:
    # train_op = tf.group(train_step,averages_op)
    with tf.control_dependencies([train_step,averages_op]):
         train_op = tf.no_op(name="train")
    
    
    #检查使用了滑动平均值模型的神经网络前向传播结果是否正确。
    #equal()函数原型为equal(x, y, name),用于判断两个张量的每一维是否相等,如果相等返回True,否则返回False。
    crorent_predicition = tf.equal(tf.argmax(average_y,1),tf.argmax(y_,1))
    
    #cast()函数原型为cast(x, DstT, name)。在这里用于将一个bool型的数据转为float32类型
    #之后会将得到的float32 的数据求一个平均值,这个平均值就是模型在这一组数据上的正确率
    accuracy = tf.reduce_mean(tf.cast(crorent_predicition,tf.float32))
    
    
    with tf.Session() as sess:
        #在稍早的版本中一般使用 initialize_all_variables()函数初始化全部变量
        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(max_steps):
            if i%1000==0:
                #计算滑动平均模型在验证数据上的结果。
                # 为了能得到百分数输出,需要将得到的validate_accuracy扩大100倍
                validate_accuracy = sess.run(accuracy, feed_dict=validate_feed)
                print("After %d trainging step(s) ,validation accuracy"
                      "using average model is %g%%"%(i,validate_accuracy*100))
    
            #产生这一轮使用的一个batch的训练数据,并进行训练
            #input_data.read_data_sets()函数生成的类提供了train.next_bacth()函数,
            #通过设置函数的batch_size参数就可以从所有的训练数据中提读取一小部分作为一个训练batch
            xs,ys = mnist.train.next_batch(batch_size=100)
            sess.run(train_op,feed_dict={x:xs,y_:ys})
    
        #使用测试数据集检验神经网络训练之后的最终正确率
        # 为了能得到百分数输出,需要将得到的test_accuracy扩大100倍
        test_accuracy = sess.run(accuracy,feed_dict=test_feed)
        print("After %d trainging step(s) ,test accuracy using average"
                      " model is %g%%"%(max_steps,test_accuracy*100))

    超参数

    大多数机器学习算法都有超参数,可以设置来控制算法行为。超参数的值不是通过学习算法本身学习出来的(尽管我们可以设计一个嵌套的学习过程,一个学习算法为另一个学习算法学出最优超参数)。

    有时一个选项被设为学习算法不用学习的超参数,是因为它太难优化了。更多的情况是,该选项必须是超参数,因为它不适合在训练集上学习。这适用于控制模型容量的所有超参数。如果在训练集上学习超参数,这些超参数总是趋向于最大可能的模型容量,导致过拟合

    和训练数据相同分布的样本组成的测试集,它可以用来估计学习过程完成之后的学习器的泛化误差。其重点在于测试样本不能以任何形式参与到模型的选择中,包括设定超参数。基于这个原因,测试集中的样本不能用于验证集。因此,我们总是从训练集中构建验证集。特别地,我们将训练数据分成两个不相交的子集。其中一个用于学习参数。另一个作为验证集,用于估计训练中或训练后的泛化误差,更新超参数。用于学习参数的数据子集通常仍被称为训练集,尽管这会和整个训练过程用到的更大的数据集相混。用于挑选超参数的数据子集被称为验证集(validation set)。通常,80%的训练数据用于训练,20%用于验证。由于验证集是用来”训练”超参数的,尽管验证集的误差通常会比训练集误差小,验证集会低估泛化误差。所有超参数优化完成之后,泛化误差可能会通过测试集来估计。

    交叉验证:将数据集分成固定的训练集和固定的测试集后,若测试集的误差很小,这将是有问题的。一个小规模的测试集意味着平均测试误差估计的统计不确定性,使得很难判断算法A是否比算法B在给定的任务上做的更好。当数据集有十万计或者更多的样本时,这不会是一个严重的问题。当数据集太小时,也有替代方法允许我们使用所有的样本估计平均测试误差,代价是增加了计算量。这些过程是基于在原始数据上随机采样或分离出的不同数据集上重复训练和测试的想法。最常见的是k-折交叉验证过程。将数据集分成k个不重合的子集。测试误差可以估计为k次计算后的平均测试误差。在第i次测试时,数据的第i个子集用于测试集,其它的数据用于训练集。带来的一个问题是不存在平均误差方差的无偏估计,但是我们通常会使用近似来解决。

    目前超参数往往只能人工基于经验来设置,以及采用暴力枚举的方式来尝试以寻求最优的超参数。

    所谓超参数,就是机器学习模型里面的框架参数,比如聚类方法里面类的个数,或者话题模型里面话题的个数等等,都称为超参数。它们跟训练过程中学习的参数(权重)是不一样的,通常是手工设定,不断试错调整,或者对一系列穷举出来的参数组合一通枚举(叫做网格搜索)。

    常用的超参数:

    (1)、learning rate:学习率决定了权值更新的速度,设置得太大会使结果超过最优值,太小会使下降速度过慢。学习率是指在优化算法中更新网络权重的幅度大小。学习率可以是恒定的、逐渐降低的、基于动量的或者是自适应的,采用哪种学习率取决于所选择优化算法的类型,如SGD、Adam、Adgrad、AdaDelta、RMSProp等算法。

    (2)、weight decay(权值衰减):在实际应用中,为了避免网络的过拟合,必须对价值函数(cost function)加入一些正则项。在机器学习或者模式识别中,会出现overfitting,而当网络逐渐overfitting时网络权值逐渐变大,因此,为了避免出现overfitting,会给误差函数添加一个惩罚项,常用的惩罚项是所有权重的平方乘以一个衰减常量之后。其用来惩罚大的权值。weight decay的使用既不是为了提高收敛精确度也不是为了提高收敛速度,其最终目的是防止过拟合。在损失函数中,weight decay是放在正则项(regularization)前面的一个系数,正则项一般指示模型的复杂度,所以weight decay的作用是调节模型复杂度对损失函数的影响,若weight decay很大,则复杂的模型损失函数的值也越大。

    (3)、momentum(动量):动量来源于牛顿定律,基本思想是为了找到最优加入”惯性”的影响。mementum是梯度下降法中一种常用的加速技术。总能得到更好的收敛速度。

    (4)、learing rate decay:每次迭代的时候减少学习率的大小。

    (5)、迭代次数:迭代次数是指整个训练集输入到神经网络进行训练的次数。当测试错误率和训练错误率相差较小时,可认为当前的迭代次数是合适的,否则需继续增大迭代次数,或调整网络结构。

    (6)、权重初始化:在网络中,通常会使用小随机数来初始化各网络层的权重,以防止产生不活跃的神经元,但是设置过小的随机数可能生成零梯度网络。一般来说,均匀分布方法效果较好。

    (7)、Dropout方法:作为一种常用的正则化方式,加入Dropout层可以减弱深层神经网络的过拟合效应。该方法会按照所设定的概率参数,在每次训练中随机地不激活一定比例的神经单元。该参数的默认值为0.5.

    自动超参数优化算法:

    (1)、网格搜索:如果有三个或更少的超参数时,常见的超参数搜索方法是网格搜索。对于每个超参数,使用者选择一个较小的有限值集去探索。然后,这些超参数笛卡尔乘积得到一组组超参数,网格搜索使用每组超参数训练模型。挑选验证集误差最小的超参数作为最好的超参数。

    (2)、随机搜索:如果超参数较多,首先,我们为每个超参数定义一个边缘分布,在这些边缘分布上进行搜索。

  • x = tf.placeholder(tf.float32, [None, 784])
    y_ = tf.placeholder(tf.float32, [None, 10])
    weight = tf.Variable(tf.zeros([784, 10]))
    bias = tf.Variable(tf.zeros([10]))
    y = tf.matmul(x, weight) + bias
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
    train_op = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, 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(30000):
            if i % 1000 == 0:
                # 计算滑动平均模型在验证数据上的结果。
                # 为了能得到百分数输出,需要将得到的validate_accuracy扩大100倍
                validate_accuracy = sess.run(accuracy, feed_dict=validate_feed)
                print("After %d trainging step(s) ,validation accuracy"
                      "using average model is %g%%" % (i, validate_accuracy * 100))
    
            xs, ys = mnist.train.next_batch(100)
            sess.run(train_op, feed_dict={x: xs, y_: ys})
    
        test_accuracy = sess.run(accuracy, feed_dict=test_feed)
        print("After 30000 trainging step(s) ,test accuracy using average"
              " model is %g%%" % (test_accuracy * 100))
    
    

    结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值