1. 程式人生 > >Tensorflow學習——6 LeNet-5的研究

Tensorflow學習——6 LeNet-5的研究

1、LeNet-5的成就

LeNet-5是Yann LeCun在1998年設計的用於手寫數字識別的卷積神經網路,當年美國大多數銀行就是用它來識別支票上面的手寫數字的,它是早期卷積神經網路中最有代表性的實驗系統之一,LeNet-5在MNIST資料集上可以達到99.2%的準確率。

2、LeNet-5的優點

LeNet-5一共有七層

  1. 每一個卷積層包含三個部分:卷積操作、池化操作和非線性啟用函式
  2. 使用卷積來提取空間特徵
  3. 下采樣層的平均池化層
  4. 層與層之間的稀疏連線減少計算複雜度

3、LeNet-5的網路圖

在這裡插入圖片描述
LeNet有七層,卷積–>池化–>卷積–>池化–>全連線–>全連線–>全連線
第一層,卷積層


輸入是原始的影象畫素,LeNet-5接受的輸入是32×32×1的,第一個卷積層的過濾器大小是5×5,深度為6,不使用全0補充,步長為1。
所以這一層的輸出為(32-5+1=28)【注out_length = (in_length-filter_length+1)/stride_length】,所以第一次的引數有5×5×1×6+6=158個,其中5×5是卷積核的length和width,1是輸入層的通道數,第一個6是卷積核深度,第2個6是偏置項的引數。
連線數是122304個,因為下一層的節點是28×28×6=4704個節點,每一個節點和5×5個當前節點相連,所以本層有(5×5+1)×28×28×6=122304個連線。
第二層,池化層

輸入的矩陣是28×28×6的矩陣,過濾器的大小是2×2,長和寬都是2,使用全0填充,所以輸出矩陣是14×14×6
(input_width+2*pad-pool_size)/stride+1
(28+2×0-2)/2 + 1
第三層,卷積層
輸入是14×14×6的矩陣節點,第二個卷積層的過濾器大小是5×5,深度為16,不使用全0補充,步長為1。
所以這一層的輸出為10×10×16 (14-5+1=10)【注out_length = (in_length-filter_length+1)/stride_length】,所以第一次的引數有5×5×6×16+16=2416個,其中5×5是卷積核的length和width,6是輸入層的通道數,第一個16是卷積核深度,第2個16是偏置項的引數。
連線數是41600個,因為下一層的節點是10×10×16個節點,每一個節點和5×5個當前節點相連,所以本層有(5×5+1)×10×10×16=41600個連線。
第四層,池化層

輸入的矩陣是10×10×16的矩陣,過濾器的大小是2×2,長和寬都是2,使用全0填充,所以輸出矩陣是5×5×16
第五層,全連線層
輸入的矩陣是5×5×16的矩陣,輸出的節點個數是120,所以引數為5×5×16×120+120=48120
第六層,全連線層
輸入的節點是120個,輸出是84個,引數120×84 +84 = 10164
第五層,全連線層
輸入的節點是84個,輸出是10個,引數84×10+10= 850

4、LeNet-5的程式碼

# _*_ encoding=utf8 _*_

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
import os
import numpy as np


# 配置神經網路的引數
INPUT_NODE = 784
OUTPUT_NODE = 10

IMAGE_SIZE = 28 #畫素
NUM_CHANNELS = 1 #通道數
NUM_LABELS = 10

#第一層卷積層的深度大小
CONV1_DEEP = 32
CONV1_SIZE = 5
#第二層卷積層的深度大小
CONV2_DEEP = 64
CONV2_SIZE = 5
# 全連線層的節點個數

FC_SIZE = 512


# 定義神經網路的前向傳播v
def inference(input_tensor,train,regularizer):
    # 第一層,輸入是28*28*1 input_tensor, 卷積核 5 *5 *1*6 最後兩個是影象通道數和卷積核個數,
    # strides 為1 用0補齊
    # 輸出是28*28*32
    with tf.variable_scope("layer-conv1"):
        conv1_weights = tf.get_variable("weight",[CONV1_SIZE,CONV1_SIZE,NUM_CHANNELS,CONV1_DEEP],
                                        initializer=tf.truncated_normal_initializer(stddev=0.1))
        conv1_biases = tf.get_variable("biases",[CONV1_DEEP],initializer=tf.constant_initializer(0.0))

        #使用邊長為5,深度32的過濾器,移動的步長為1,
        conv1 = tf.nn.conv2d(input_tensor,conv1_weights,strides=[1,1,1,1],padding="SAME")
        relu1 = tf.nn.relu(tf.nn.bias_add(conv1,conv1_biases))

    # 第二層,池化層,最大池化,輸入是28*28*32的矩陣,輸入是14*14*32
    with tf.name_scope('layer2-pool1'):
        pool1 = tf.nn.max_pool(
            relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME"
        )

    # 第三層,卷積層 輸入14*14*32  輸出是14*14*64
    with tf.name_scope("layer-conv2"):
        conv2_weights = tf.get_variable(
            "weight",[CONV2_SIZE,CONV2_SIZE,CONV1_DEEP,CONV2_DEEP],initializer=tf.truncated_normal_initializer(stddev=0.1)
        )

        conv2_biases = tf.get_variable("biased",[CONV2_DEEP],initializer=tf.constant_initializer(0.0))

        conv2 = tf.nn.conv2d(pool1,conv2_weights,strides=[1,1,1,1],padding="SAME")
        relu2 = tf.nn.relu(tf.nn.bias_add(conv2,conv2_biases))

    #第四層,池化層
    # 輸入是14*14*64  輸出7*7*64
    with tf.name_scope('layer-pool2'):
        pool2 = tf.nn.max_pool(
            relu2,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME"
        )


    # 將池化層的輸出轉化為全連線層的資料格式,也是就是reshape一下,第四層輸出是矩陣,第五層輸入是一個向量,batch不變
    pool_shape = pool2.get_shape().as_list()
    # 將矩陣拉直成向量的長度,長度也就是矩陣長寬高的乘積,pool_shape[0]是一個batch中資料的個數
    nodes = pool_shape[1]*pool_shape[2]*pool_shape[3]
    # 通過tf.reshape將第四層的輸出變成一個batch的向量
    reshaped = tf.reshape(pool2,[pool_shape[0],nodes])

    # 第五層,全連線層
    # 拉直後向量的長度為3136,輸出是512的向量,加入dropout,避免過擬合,這個一般只是在全連線層使用,
    with tf.variable_scope("layer-fc1"):
        fc1_weights = tf.get_variable(
            "weight",[nodes,FC_SIZE],
            initializer=tf.truncated_normal_initializer(stddev=0.1)
        )

        if regularizer != None:
            tf.add_to_collection("losses",regularizer(fc1_weights))

        fc1_biases = tf.get_variable(
            "biased",[FC_SIZE],initializer=tf.constant_initializer(0.1)
        )

        fc1 = tf.nn.relu(tf.matmul(reshaped,fc1_weights) + fc1_biases)
        if train:
            fc1 = tf.nn.dropout(fc1,0.5)

    #第六層,全連線層,輸入512,輸出10,通過softmax可以得到最後的分類
    with tf.variable_scope("layer-fc2"):
        fc2_weights = tf.get_variable(
            "weight",[FC_SIZE,NUM_LABELS],
            initializer=tf.truncated_normal_initializer(stddev=0.1)
        )
        if regularizer != None:
            tf.add_to_collection("losses",regularizer(fc2_weights))

        fc2_biases = tf.get_variable(
            "biases",[NUM_CHANNELS],
            initializer=tf.constant_initializer(0.1)
        )

        logit = tf.matmul(fc1,fc2_weights) + fc2_biases


    return logit


BATCH_SIZE = 100
LEARNING_RATE_BASE = 0.01
LEARNING_RATE_DECAY = 0.99
REGULARIZATION_RATE = 0.0001
TRAINING_STEPS = 6000
MOVING_AVERAGE_DECAY = 0.99

# 訓練模型的過程
def train(mnist):
    # 定義輸出為4維矩陣的placeholder
    x = tf.placeholder(tf.float32, [
        BATCH_SIZE,
        IMAGE_SIZE,
        IMAGE_SIZE,
        NUM_CHANNELS],
        name='x-input')
    
    y_ = tf.placeholder(tf.float32, [None, OUTPUT_NODE], name='y-input')

    regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)
    y = inference(x, False, regularizer)
    global_step = tf.Variable(0, trainable=False)

    # 定義損失函式、學習率、滑動平均操作以及訓練過程。
    variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
    variables_averages_op = variable_averages.apply(tf.trainable_variables())
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
    cross_entropy_mean = tf.reduce_mean(cross_entropy)
    loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
    learning_rate = tf.train.exponential_decay(
        LEARNING_RATE_BASE,
        global_step,
        mnist.train.num_examples / BATCH_SIZE, LEARNING_RATE_DECAY,
        staircase=True)

    train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
    with tf.control_dependencies([train_step, variables_averages_op]):
        train_op = tf.no_op(name='train')

    # 初始化TensorFlow持久化類。
    saver = tf.train.Saver()
    with tf.Session() as sess:
        tf.global_variables_initializer().run()
        for i in range(TRAINING_STEPS):
            xs, ys = mnist.train.next_batch(BATCH_SIZE)

            reshaped_xs = np.reshape(xs, (
                BATCH_SIZE,
                IMAGE_SIZE,
                IMAGE_SIZE,
                NUM_CHANNELS))
            _, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: reshaped_xs, y_: ys})

            if i % 1000 == 0:
                print("After %d training step(s), loss on training batch is %g." % (step, loss_value))




if __name__ == '__main__':
    mnist = input_data.read_data_sets("../bin/data", one_hot=True)
    train(mnist)