利用tensorflow實現LeNet5卷積神經網絡

首先介紹一下什麼是卷積神經網絡。
卷積神經網絡(Convolutional Neural Networks, CNN)是一類包含卷積計算且具有深度結構的前饋神經網絡(Feedforward Neural Networks),是深度學習(deep learning)的代表算法之一,它主要包含卷積層和池化層。下圖是卷積神經網絡的基本結構。
卷積神經網絡架構
一個卷積神經網絡通常由以下5部分組成。

  1. 輸入層。 輸入層是整個神經網絡的輸入,在卷積神經網絡中,是一個像素矩陣,而且引入了深度的概念,如果是黑白灰度圖像的話,那麼深度爲1,如果是彩色圖像,深度爲3(RGB3個色彩通道)。
  2. 卷積層。卷積層是一組平行的特徵圖(feature map),它通過在輸入圖像上滑動不同的卷積核並執行一定的運算而組成。此外,每一個滑動的位置上,卷積核與輸入圖像之間會執行一個元素對應乘積並求和的運算以將感受野內的信息投影到特徵圖中的一個元素。卷積核的尺寸要比輸入圖像小得多,且重疊或平行地作用於輸入圖像中,一張特徵圖中的所有元素都是通過一個卷積覈計算得出的,也即一張特徵圖共享了相同的權重和偏置項。一般來說,通過卷積層處理之後深度會增加。
  3. 池化層。池化(Pooling)是卷積神經網絡中另一個重要的概念,它實際上是一種形式的降採樣。有多種不同形式的非線性池化函數,而其中“最大池化(Max pooling)”是最爲常見的。可以認爲是將一張分辨率高的圖片轉化爲分辨率低的圖片,通過池化層會不斷地減小數據的空間大小,因此參數的數量和計算量也會下降,這在一定程度上也控制了過擬合。通常來說,CNN的卷積層之間都會週期性地插入池化層。
  4. 全連接層。在經過多次卷積和池化處理之後,在卷積神經網絡的最後一般由1到2個全連接層來給出最後分類結果,一般來說,我們可以將卷積和池化處理過程當作圖像自動特徵提取的過程,所以特徵提取之後,還使用全連接層來完成分類任務。
  5. Softmax層。這一層主要用於分類問題,通過Softmax層,可以得到不同分類的概率分佈。

在本文中,我們將介紹經典的LeNet-5模型。
下圖爲LeNet-5模型圖。
在這裏插入圖片描述
以mnist數據集爲例介紹LeNet-5的每一層的結構及其參數設置。
第一層:輸入層
這一層爲原始的圖像元素,圖片大小爲28*28*1,其中1表示黑白圖像,所以channel爲1
第二層:卷積層
這一層的輸入爲輸入層的輸出,即原始圖像,卷積層的過濾器尺寸爲5*5,深度爲32,使用全0填充,所以本層的輸出矩陣大小爲28*28*32。
第三層:池化層
這一層的輸入爲卷積層的輸出,是一個28*28*32的節點矩陣。本層採用過濾器大小爲2*2,長和寬的步長均爲2,所以本層輸出矩陣大小爲 14*14*32。
第四層:卷積層
這一層的輸入爲上一池化層的輸出,卷積層的過濾器尺寸爲5*5,深度爲64,使用全0填充,所以本層的輸出矩陣大小爲14*14*32。
第五層:池化層
這一層的輸入爲卷積層的輸出,是一個14*14*64的節點矩陣。本層採用過濾器大小爲2*2,長和寬的步長均爲2,所以本層輸出矩陣大小爲 7*7*64。
第六層:全連接層
這一層的輸入爲上一池化層的輸出,輸入節點個數爲7*7*64=3136個,輸出節點個數爲512(人爲設置)個。
第七層:全連接層
本層輸入節點個數爲512,輸出節點個數爲10(分類個數)。

上面介紹了LeNet-5模型每一層的結構和參數設置,下面給出利用tensorflow實現LeNet-5模型的卷積神經網絡來解決mnist數字識別問題。本文采用滑動平均模型與正則化方法等優化方法對網絡結構進行優化,並且用drop out方法防止過擬合,具體代碼如下。

inference.py (前向傳播結果)

import tensorflow as tf
IN_NODE = 784
OUT_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

def inference(input,train, regularizer):
    with tf.variable_scope('layer1-conv1'):
        conv1_w = tf.get_variable('w', [CONV1_SIZE, CONV1_SIZE, NUM_CHANNELS, CONV1_DEEP], initializer=tf.truncated_normal_initializer(stddev=0.1))
        conv1_b = tf.get_variable('b', [CONV1_DEEP], initializer=tf.constant_initializer(0.0))
        conv1 = tf.nn.conv2d(input, conv1_w, strides=[1,1,1,1], padding='SAME')
        relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_b))
        print(relu1.shape)
    with tf.name_scope('layer2-pool1'):
        pool1 = tf.nn.max_pool(relu1, ksize=[1, 2, 2, 1],strides=[1,2,2,1],padding='SAME')
        print(pool1.shape)
    with tf.variable_scope('layer3-conv2'):
        conv2_w = tf.get_variable('w', [CONV2_SIZE, CONV2_SIZE, CONV1_DEEP, CONV2_DEEP], initializer=tf.truncated_normal_initializer(stddev=0.1))
        conv2_b = tf.get_variable('b', [CONV2_DEEP], initializer=tf.constant_initializer(0.0))
        conv2 = tf.nn.conv2d(pool1, conv2_w, strides=[1,1,1,1], padding='SAME')
        relu2 = tf.nn.relu(tf.nn.bias_add(conv2, conv2_b))
        print(relu2.shape)
    #池化層 7*7*64
    with tf.name_scope('layer4-pool2'):
        pool2 = tf.nn.max_pool(relu2, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
        print(pool2.shape)
    pool_shape = pool2.get_shape().as_list()
    nodes = pool_shape[1] * pool_shape[2] * pool_shape[3]
    reshaped = tf.reshape(pool2, [pool_shape[0], nodes])

    with tf.variable_scope('layer5-fc1'):
        fc1_w = tf.get_variable('w', [nodes, FC_SIZE], initializer=tf.truncated_normal_initializer(stddev=0.1))
        fc1_b = tf.get_variable('b', [FC_SIZE], initializer=tf.constant_initializer(0.1))
        if regularizer != None:
            tf.add_to_collection('losses', regularizer(fc1_w))
        fc1 = tf.nn.relu(tf.matmul(reshaped, fc1_w)+fc1_b)
        print(fc1.shape)
        if train == True:
            fc1 = tf.nn.dropout(fc1, 0.5)
    with tf.variable_scope('layer6-fc2'):
        fc2_w = tf.get_variable('w', [FC_SIZE, NUM_LABELS], initializer=tf.truncated_normal_initializer(stddev=0.1))
        fc2_b = tf.get_variable('b', [NUM_LABELS], initializer=tf.constant_initializer(0.1))
        if regularizer != None:
            tf.add_to_collection('losses', regularizer(fc2_w))
        logis = tf.matmul(fc1, fc2_w)+fc2_b
        print(logis.shape)
    return logis

train.py(訓練過程)

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

import mnist_inference

BATCH_SIZE = 100
LEARNINIG_RATE_BASE = 0.01
LEARNING_RATE_DECAY = 0.99
REGULARAZTION_RATE = 0.0001
TRAINING_STEPS = 3000
MOVING_AVERAGE_DEACY = 0.99
#模型保存文件的路徑
MODEL_SAVE_PATH = '/path/to/model/mnist_CNN/'
MODEL_NAME = 'mnist.ckpt'
def train(mnist):
    x = tf.placeholder(tf.float32, [BATCH_SIZE, mnist_inference.IMAGE_SIZE,mnist_inference.IMAGE_SIZE,mnist_inference.NUM_CHANNELS], name='x-input')
    y = tf.placeholder(tf.float32, [None, mnist_inference.OUT_NODE], name='y-input')
    regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)
    y_ = mnist_inference.inference(x, True, regularizer)
    global_step = tf.Variable(0, trainable=False)
    variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DEACY, global_step)
    variable_averages_op = variable_averages.apply(tf.trainable_variables())
    cross_entropy = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y_, labels=tf.argmax(y,1)))
    loss = cross_entropy + tf.add_n(tf.get_collection('losses'))
    learning_rate = tf.train.exponential_decay(LEARNINIG_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')
    saver = tf.train.Saver()
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for i in range(TRAINING_STEPS):
            xs, ys = mnist.train.next_batch(BATCH_SIZE)
            reshaped_xs = np.reshape(xs, (BATCH_SIZE, mnist_inference.IMAGE_SIZE,mnist_inference.IMAGE_SIZE,mnist_inference.NUM_CHANNELS))
            _, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x:reshaped_xs, y:ys})
            if i % 100 == 0:
                print("%d輪之後的損失率爲%g" % (i, loss_value))
                saver.save(sess, os.path.join(MODEL_SAVE_PATH, MODEL_NAME), global_step=global_step)
def main(argv = None):
    print(os.path.join(MODEL_SAVE_PATH, MODEL_NAME))
    mnist = input_data.read_data_sets("/data/MNIST_data", one_hot=True)
    train(mnist)
if __name__ == '__main__':
    tf.app.run()

test.py(測試驗證)

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

import mnist_inference
import mnist_train
import numpy as np

def evaluate(mnist):
    with tf.Graph().as_default() as g:
        x = tf.placeholder(tf.float32, [5000, mnist_inference.IMAGE_SIZE, mnist_inference.IMAGE_SIZE,
                                        mnist_inference.NUM_CHANNELS], name='x-input')
        y = tf.placeholder(tf.float32, [None, mnist_inference.OUT_NODE], name='y-input')
        xx = mnist.validation.images
        reshape_x = np.reshape(xx, (5000, mnist_inference.IMAGE_SIZE,mnist_inference.IMAGE_SIZE,mnist_inference.NUM_CHANNELS))
        validate_feed = {x:reshape_x, y:mnist.validation.labels}
        y_ = mnist_inference.inference(x, None, None)
        correct = tf.equal(tf.argmax(y, 1), tf.argmax(y_,1))
        acc = tf.reduce_mean(tf.cast(correct, tf.float32))
        variable_averages = tf.train.ExponentialMovingAverage(mnist_train.MOVING_AVERAGE_DEACY)
        variables_to_restore = variable_averages.variables_to_restore()
        saver = tf.train.Saver(variables_to_restore)
        while True:
            with tf.Session() as sess:
                ckpt = tf.train.get_checkpoint_state(mnist_train.MODEL_SAVE_PATH)
                if ckpt and ckpt.model_checkpoint_path:
                    saver.restore(sess, ckpt.model_checkpoint_path)
                    global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
                    acc_restore = sess.run(acc, feed_dict=validate_feed)
                    print("%s輪之後的正確率爲%g" % (global_step, acc_restore))
                else:
                    return
def main(argv=None):
    mnist = input_data.read_data_sets("/data/MNIST_data", one_hot=True)
    evaluate(mnist)
if __name__ == '__main__':
    tf.app.run()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章