TensorFlow实现LeNet-5

作者: RunningSucks | 来源:发表于2019-05-11 12:06 被阅读2次

    我们依然使用之前的MNIST数据集,通过构建简单的LeNet-5卷积神经网络来进行训练。LeNet-5是Yann LeCun教授提出的(今年的图灵奖获得者),它是第一个成功应用于数字识别问题的卷积神经网络。


    LeNet-5架构

    1. 输入层
    我们依然使用之前的mnist数据集,所以每一张图片都是32 * 32 * 1的灰度值图片
    2. 卷积层C1
    这一层所使用的卷积核尺寸为5 * 5,深度为6。意思是我们使用六个不同的卷积和对图片进行处理每一个核都是5 * 5,所以一共有(5 * 5+1)* 6=156个参数。这里的1代表的是偏差bias。
    不使用全0补充,步长为1,所以每一个输入矩阵的输出大小为32-5+1=28,C1层的输出即为28 * 28 * 6。
    3. 池化层S2
    这一层我们使用2 * 2的池化进行降采样,步长为2,所以输出尺寸为14 * 14 *6。然后使用Sigmoid函数进行非线性处理
    4. 卷积层C3
    依然使用5 * 5的卷积核,但是深度为16,步长为1,不做全0补充。 所以输出大小为10 * 10 * 16。
    5. 池化层S4
    和池化层S2相同,所以输出为5 * 5 *16。
    6. 卷积层C5
    卷积大小依然是5 * 5,但是因为输入的尺寸也是5 * 5,所以相当于是一个全连接层,输出节点数为120。
    7. 全连接层F6
    输出节点为84个
    8. 全连接层
    输出节点数为10个,作为全局的输出。

    结构图

    TensorFlow实现

    加载TensorFlow和MNIST数据集
    和之前一样的输入

    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
    

    参数定义
    因为隐藏层包含很多参数,我们可以对他们分开定义,也可以定义一个通用表达以便重复使用。

    #标准差为0.1的正态分布
    def weight_variable(shape):
        initial = tf.truncated_normal(shape,stddev=0.1)
        return tf.Variable(initial)
    
    #0.1的偏差常数,为了避免死亡节点
    def bias_variable(shape):
        initial = tf.constant(0.1, shape=shape)
        return tf.Variable(initial)
    
    #二维卷积函数
    #strides代表卷积模板移动的步长,全是1代表走过所有的值
    #padding设为SAME意思是保持输入输出的大小一样,使用全0补充
    def conv2d(x,W):
        return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')
    
    #ksize [1, height, width, 1] 第一个和最后一个代表对batches和channel做池化,1代表不池化
    #strides [1, stride,stride, 1]意思是步长为2,我们使用的最大池化
    def max_pool_2x2(x):
        return tf.nn.max_pool(x,ksize=[1,2,2,1], strides=[1,2,2,1],padding='SAME')
    

    定义输入placeholder,x是特征,y_是label

    x = tf.placeholder(tf.float32, [None,784])
    y_ = tf.placeholder(tf.float32, [None,10])
    #reshape图片成28 * 28 大小,-1代表样本数量不固定,1代表channel
    x_image=tf.reshape(x,[-1,28,28,1])
    

    卷积层C1
    使用我们之前定义的函数进行赋值

    #前面两个5代表卷积核的尺寸,1代表channel,32代表深度
    W_conv1 = weight_variable([5,5,1,32])
    b_conv1 = bias_variable([32])
    h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)
    p_conv1 = max_pool_2x2(h_conv1) 
    

    卷积层C2
    这一层使用64个卷积核

    W_conv2 = weight_variable([5,5,32,64])
    b_conv2 = bias_variable([64])
    h_conv2 = tf.nn.relu(conv2d(p_conv1,W_conv2)+b_conv2)
    p_conv2 = max_pool_2x2(h_conv2) 
    

    全连接

    #输入为7 * 7 * 64, 输出为1024的一维向量
    W_fc1 = weight_variable([7*7*64,1024])
    b_fc1 = bias_variable([1024])
    h_pool2_flat = tf.reshape(p_conv2,[-1,7*7*64])
    h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)
    

    Dropout
    为了减轻过拟合问题,我们可以选择加入一个dropout层。我们之前介绍过就是通过一个保留率来随机丢弃一部分节点。

    keep_prob = tf.placeholder(tf.float32)
    h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)
    

    Softmax
    和之前一样

    W_fc2 = weight_variable([1024,10])
    b_fc2 = bias_variable([10])
    y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2) + b_fc2)
    

    损失函数

    # 交叉熵
    cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv),reduction_indices=[1]))
    #参数优化器Adam代替梯度递减,当然都可以使用,这里只是用一个和以前不一样的
    train_step=tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
    

    结果检测

    # 正确的预测结果
    correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))
    # 计算预测准确率
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    

    训练
    我们使用0.5的保留率,50的mini-batch,20000次迭代

    tf.global_variables_initilizer().run()
    for i in range(20000):
      batch = mnist.train.next_batch(50)
      #每一百次打印一次结果,keep_prob设为1意思是用原数据进行检测,所以保留所有数据
      if(i%100==0):
        train_acuracy = accuracy_eval(feed_dict={x:batch[0],y_:batch[1],keep_prob:1.0})
        print("step %d, tranning accuracy %g:"%(i,train_accuracy))
      train_step.run(feed_dict={x:batch[0],y_:batch[1],keep_prob:0.5})
    
    #训练结束后,在测试集上进行测试
    print("Model accuracy: %g:"%accuracy.eval(feed.dict={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))
    

    最终结果就是99.36%的正确率:


    测试结果

    优化
    还有一些优化的方法,我们会在下一章里进行说明。大家也可以改变这一章节里的参数和方法,尝试更多的优化。

    相关文章

      网友评论

        本文标题:TensorFlow实现LeNet-5

        本文链接:https://www.haomeiwen.com/subject/oacwoqtx.html