TensorFlow學習筆記(四)圖像識別與卷積神經網絡

 

1、卷積神經網絡簡介node

卷積神經網絡(Convolutional Neural Network,CNN)是一種前饋神經網絡,它的人工神經元能夠響應一部分覆蓋範圍內的周圍單元,對於大型圖像處理有出色表現。 它包括卷積層(convolutional layer)和池化層(pooling layer)。git

通常地,CNN的基本結構包括兩層,其一爲特徵提取層,每一個神經元的輸入與前一層的局部接受域相連,並提取該局部的特徵。一旦該局部特徵被提取後,它與其它特徵間的位置關係也隨之肯定下來;其二是特徵映射層,網絡的每一個計算層由多個特徵映射組成,每一個特徵映射是一個平面,平面上全部神經元的權值相等。特徵映射結構採用影響函數核小的sigmoid函數做爲卷積網絡的激活函數,使得特徵映射具備位移不變性。此外,因爲一個映射面上的神經元共享權值,於是減小了網絡自由參數的個數。卷積神經網絡中的每個卷積層都緊跟着一個用來求局部平均與二次提取的計算層,這種特有的兩次特徵提取結構減少了特徵分辨率。算法

這是一個最典型的卷積網絡,由卷積層、池化層、全鏈接層組成。其中卷積層與池化層配合,組成多個卷積組,逐層提取特徵,最終經過若干個全鏈接層完成分類。網絡

卷積層完成的操做,能夠認爲是受局部感覺野概念的啓發,而池化層,主要是爲了下降數據維度。架構

綜合起來講,CNN經過卷積來模擬特徵區分,而且經過卷積的權值共享及池化,來下降網絡參數的數量級,最後經過傳統神經網絡完成分類等任務。app

 

2、卷積神經網絡經常使用結構dom

一、卷積層ide

CNN最重要的部分就是卷積核。又稱爲過濾器或內核。函數

---恢復內容結束---學習

1、卷積神經網絡簡介

卷積神經網絡(Convolutional Neural Network,CNN)是一種前饋神經網絡,它的人工神經元能夠響應一部分覆蓋範圍內的周圍單元,對於大型圖像處理有出色表現。 它包括卷積層(convolutional layer)和池化層(pooling layer)。

通常地,CNN的基本結構包括兩層,其一爲特徵提取層,每一個神經元的輸入與前一層的局部接受域相連,並提取該局部的特徵。一旦該局部特徵被提取後,它與其它特徵間的位置關係也隨之肯定下來;其二是特徵映射層,網絡的每一個計算層由多個特徵映射組成,每一個特徵映射是一個平面,平面上全部神經元的權值相等。特徵映射結構採用影響函數核小的sigmoid函數做爲卷積網絡的激活函數,使得特徵映射具備位移不變性。此外,因爲一個映射面上的神經元共享權值,於是減小了網絡自由參數的個數。卷積神經網絡中的每個卷積層都緊跟着一個用來求局部平均與二次提取的計算層,這種特有的兩次特徵提取結構減少了特徵分辨率。

這是一個最典型的卷積網絡,由卷積層、池化層、全鏈接層組成。其中卷積層與池化層配合,組成多個卷積組,逐層提取特徵,最終經過若干個全鏈接層完成分類。

卷積層完成的操做,能夠認爲是受局部感覺野概念的啓發,而池化層,主要是爲了下降數據維度。

綜合起來講,CNN經過卷積來模擬特徵區分,而且經過卷積的權值共享及池化,來下降網絡參數的數量級,最後經過傳統神經網絡完成分類等任務。

 

2、卷積神經網絡經常使用結構

一、卷積層

CNN最重要的部分就是卷積核。又稱爲過濾器或內核。

CNN最重要的部分就是卷積核。又稱爲過濾器或內核。

共享每個卷積層中過濾器的參數能夠巨幅減小神經網絡中的參數。

f(X.W+b)

爲了不尺寸變化,能夠在當前層矩陣的邊界中加入全0填充。

TensorFlow對卷積神經網絡提供了很是好的支持,下面的程序實現了一個卷積層的前向傳播過程。

 

# -*- coding:utf-8 -*-
import tensorflow as tf
import numpy as np
#經過tf.get_variable的方式建立過濾器的權重和偏置。
x = np.random.randn(4,5)
filter_weight = tf.get_variable("weight",[5,5,3,16],initializer=tf.truncated_normal_initializer(stddev=0.1))
#和卷積層的權重相似,當前層不一樣位置的偏置項也是共享的。
biases = tf.get_variable("biases",shape=[16],initializer=tf.constant_initializer(0.1))
#tf.nn.conv2d 提供了一個很是方便的函數來實現卷積層前向傳播算法。
conv=tf.nn.conv2d(x,filter_weight,strides=[1,1,1,1],padding="SAME")
# tf.nn.bias_add函數給每一個節點增長偏執項
bias = tf.nn.bias_add(conv,biases)
#經過relu激活函數去線性化
active_conv = tf.nn.relu(bias)

 

2池化層

池化層能夠很是有效的縮小矩陣的尺寸, 從而減小後面全鏈接層的參數。使用池化層能夠有效的加快計算速度,也能夠防止過擬合。

池化層的過濾器不是加權求和,而是採用最大值或平均值運算。

池化層過濾器的移動和填充方式與卷積層的相似,惟一的區別是卷積層的過濾器是橫跨整個深度的,而池化層使用的過濾器隻影響一個深度上的節點。

 

3 經典的卷積神經網絡

3.1 LeNet-5模型

模型總共七層,模型的結構以下

用TF來實現

#mnsit_inference
# -*- coding:utf-8 -*-

import tensorflow as tf

#定義神經網絡的參數
INPUT_NODE = 784
OUTPUT_NODE = 10
IMAGE_SIZE = 28
NUM_CHANNELS = 1
NUM_LABELS = 10
#第一層conv參數
CONV1_DEEP = 32
CONV1_SIZE = 5

#第二層卷積層參數
CONV2_DEEP = 64
CONV2_SIZE = 5
#全鏈接層節點個數
FC_SIZE = 512



#定義神經網絡的前向傳播過程.這裏添加了一個新的參數train ,用於區分訓練過程和測試過程。在這個過程當中將用到dropout方法。dropout方法只在訓練中使用。

def inference(input_tensor,train,regularizer):
    #第一層卷積層
    with tf.variable_scope("layer1_conv1"):
        conv1_weights = tf.get_variable("wight",[CONV1_SIZE,CONV1_SIZE,NUM_CHANNELS,CONV1_DEEP],initializer=tf.truncated_normal_initializer(stddev=0.1))
        conv1_biases = tf.get_variable("bias",shape=[CONV1_DEEP],initializer=tf.constant_initializer(0.0))
        #使用邊長爲5,深度爲32 的過濾器,過濾器的移動步長爲1,填充爲全0
        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))
    #第二層pooling
    with tf.variable_scope("layer2_pool1"):
        pool1 = tf.nn.max_pool(relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")
    #第三層,卷積層
    with tf.variable_scope("layer3_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('bias',[CONV2_DEEP],initializer=tf.constant_initializer(0.0))
        #使用邊長爲5,深度爲64 的過濾器,過濾器的移動步長爲1,填充爲全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))
    #第四層,池化層
    with tf.variable_scope("layer4_pool2"):
        pool2=tf.nn.max_pool(relu2,[1,2,2,1],[1,2,2,1],padding="SAME")
    #第四層的輸出爲7*7*64,然而第五層全鏈接層須要的輸入格式爲向量,因此這裏須要將7*7*64拉伸爲一個向量。pool2.get_shape。由於每層網絡的輸入輸出都是一batch
    #矩陣因此這裏的維度也包含batch中數據的個數。
    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_weights = tf.get_variable('weight',[nodes,FC_SIZE],initializer=tf.truncated_normal_initializer(stddev=0.1))
        fc1_biases = tf.get_variable("bias",[FC_SIZE],initializer=tf.constant_initializer(0.1))
        #只有全鏈接層的權重須要加入正則化
        if regularizer != None:
            tf.add_to_collection("losses",regularizer(fc1_weights))
        fc1 = tf.nn.relu(tf.matmul(reshaped,fc1_weights)+fc1_biases)
        if train:
            #利用dropout減小過擬合
            fc1 = tf.nn.dropout(fc1,0.5)
    #聲明第六層-全鏈接層。輸入爲512的向量,輸出爲10的向量
    with tf.variable_scope("layer6_fc2"):
        fc2_weights = tf.get_variable('weight',[FC_SIZE,OUTPUT_NODE],initializer=tf.truncated_normal_initializer(stddev=0.1))
        fc2_biases = tf.get_variable('biases',[OUTPUT_NODE],initializer=tf.constant_initializer(0.1))
        if regularizer != None:
            tf.add_to_collection('losses',regularizer(fc2_weights))
        logit = tf.matmul(fc1,fc2_weights)+ fc2_biases
    return logit

 

#mnsit_train
# -*- coding:utf-8 -*-
import os
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
#加載mnsit_inference.py中定義的變量和函數
from integerad_mnist import mnsit_inference
import numpy as np

#配置神經網絡的參數
BATCH_SIZE = 100
LR_BASE = 0.8
LR_DECAY = 0.99
REGULARAZTION_RATE = 0.0001
TRANING_STEPS = 30000
MOVING_AVERAGE_DECAY = 0.99
#模型保存的文件名和路徑
MODEL_SAVE_PATH = "path/to/model/"
MODEL_SAVE_NAME = "model.ckpt"
INPUT_SHAPE = [BATCH_SIZE,mnsit_inference.IMAGE_SIZE,mnsit_inference.IMAGE_SIZE,mnsit_inference.NUM_CHANNELS]
def train(mnsit):
    #定義輸入和輸出的placeholder
    x = tf.placeholder(tf.float32,shape=INPUT_SHAPE,name="x_input")
    y_ = tf.placeholder(tf.float32,shape=[None,mnsit_inference.OUTPUT_NODE],name="y_input")
    regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)
    #直接使用mnsit_inference中定義的前向傳播過程
    y = mnsit_inference.inference(x,True,regularizer)
    global_step = tf.Variable(0,trainable=False)
    variable_average = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)
    variable_average_op = variable_average.apply(tf.trainable_variables())
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.argmax(y_,1),logits=y)
    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(LR_BASE,global_step,mnsit.train.num_examples/BATCH_SIZE,LR_DECAY)
    train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)
    with tf.control_dependencies([train_step,variable_average_op]):
        train_op = tf.no_op("train")
    #初始化TF的持久化類
    saver = tf.train.Saver()
    with tf.Session() as sess:
        tf.initialize_all_variables().run()
        for i in range(TRANING_STEPS):
            xs,ys = mnsit.train.next_batch(BATCH_SIZE)
            reshaped_xs = np.reshape(xs,INPUT_SHAPE)
            _,loss_value,step = sess.run([train_op,cross_entropy_mean,global_step],feed_dict={x:reshaped_xs,y_:ys})
            #每1000輪保存一次模型
            if i % 1000 == 0:
                print("After {0} training steps,loss on training batch is {1}".format(step,loss_value))
                saver.save(sess,os.path.join(MODEL_SAVE_PATH,MODEL_SAVE_NAME),global_step=global_step)

def main(argv = None):
    mnsit = input_data.read_data_sets("mnist_set",one_hot=True)
    train(mnsit)
if __name__ == '__main__':
    tf.app.run()

 

3.2 Inception-V3 模型

LeNet-5模型中,卷積層是經過串聯的方式鏈接在一塊兒的,而Inception-v3中的inception結構與之徹底不一樣,它是經過並聯的方式結合在一塊兒的。以下圖所示;

 

 總體的inception-v3模型架構圖

Inception-v3模型總共有46層,由11個inception模塊組成。Inception-v3模型中有96個卷積層。若是還按照以前的代碼,一個卷積5行代碼,96個須要480行代碼,代碼可讀性差,能夠用TonserFlow=Slim來實現。一行便可實現一個conv層。

比較一下原始的tf和slim

import tensorflow as tf
import numpy as np
import tensorflow.contrib.slim as slim
#經過tf.get_variable的方式建立過濾器的權重和偏置。
x = np.random.randn(4,5)
filter_weight = tf.get_variable("weight",[5,5,3,16],initializer=tf.truncated_normal_initializer(stddev=0.1))

biases = tf.get_variable("biases",shape=[16],initializer=tf.constant_initializer(0.1))
conv=tf.nn.conv2d(x,filter_weight,strides=[1,1,1,1],padding="SAME")
bias = tf.nn.bias_add(conv,biases)
active_conv = tf.nn.relu(bias)
#使用TensorFlow-Slim實現卷積層。slim.conv2d函數有三個必填的參數,第一個爲輸入節點的矩陣,第二個爲當前卷積層過濾器的深度,第三個爲過濾器的尺寸
#可選參數有步長,填充0,激活函數和變量的命名空間
net = slim.conv2d(x,16,[5,5])

代碼實現一個inception模塊。

import tensorflow as tf
import numpy as np
import tensorflow.contrib.slim as slim

#slim.arg_scope函數用來設置默認的參數取值,第一個參數是函數名列表。

with slim.arg_scope([slim.conv2d,slim.max_pool2d,slim.avg_pool2d],stride = 1,padding = "SAME"):
    #.......此處省略了前面的網絡結構,
    net = "上一層網絡的輸出"
    #爲一個inception模塊聲明一個統一的變量命名空間
    with tf.variable_scope("Mixed_7c"):
        #給inception的每一條分支聲明一個變量命名空間
        with tf.get_variable('branch_0'):
            branch_0 = slim.conv2d(net,320,[1,1],scope="Conv2d_0a-1X1")
        #第二條路徑自己也是一個inception
        with tf.get_variable("branch_1"):
            branch_1 = slim.conv2d(net,384,[1,1],scope="Conv2d_0a-1X1")
            #tf.concat能夠將多個矩陣進行拼接,第二個參數指定拼接的維度,這裏的「3」表明深度。
            branch_1 = tf.concat([slim.conv2d(branch_1,[1,3],scope="Conv2d_0b-1X3"),slim.conv2d(branch_1,[3,1],scope="Conv2d_0c-3X1")],3)
        with tf.get_variable("branch_2"):
            branch_2 = slim.conv2d(net,448,[1,1],scope="Conv2d_0a-1X1")
            branch_2 = slim.conv2d(branch_2,384,[3,3],scope="Conv2d_0b-3X3")
            branch_2 = tf.concat([slim.conv2d(branch_2,[1,3],scope="Conv2d_0c-1X3"),slim.conv2d(branch_2,[3,1],scope="Conv2d_0c-3X1")],3)

        #第四條inception路徑
        with tf.get_variable("branch_3"):
            branch_3 = slim.avg_pool2d(net,[3,3],scope="avg_pool-0a-3X3")
            #tf.concat能夠將多個矩陣進行拼接,第二個參數指定拼接的維度,這裏的「3」表明深度。
            branch_3 = slim.conv2d(branch_3,192,[1,1],scope="Conv2d_0a-1X1")
        #當前inception模塊的最後輸出由上面的四個結果拼接獲得
        net_output = tf.concat([branch_0,branch_1,branch_2,branch_3],3)

 五、卷積神經網絡的遷移學習

   5.1什麼是遷移學習?

  所謂的遷移學習,就是將一個問題上訓練好的模型經過簡單的調整使其適用於一個新的問題。

 瓶頸層:

  在最後一層全鏈接層之間的網絡層稱之爲瓶頸層。

  通常來講,在數據量足夠的狀況下,遷移學習的效果不如徹底從新學習。

 5.2 TensorFlow 實現遷移學習

相關文章
相關標籤/搜索