CNN通俗解析

摘要: CNN基礎知識介紹及TensorFlow具體實現,對於初學者或者求職者而言是一份不可多得的資料。

clipboard.png

定義:

簡而言之,卷積神經網絡(Convolutional Neural Networks)是一種深度學習模型或相似於人工神經網絡的多層感知器,經常使用來分析視覺圖像。卷積神經網絡的創始人是着名的計算機科學家Yann LeCun,目前在Facebook工做,他是第一個經過卷積神經網絡在MNIST數據集上解決手寫數字問題的人。git

clipboard.png

Yann LeCunngithub

卷積神經網絡的出現是受到了生物處理過程的啓發,由於神經元之間的鏈接模式相似於動物的視覺皮層組織。算法

clipboard.png

人腦的視覺結構數組

個體皮層神經元僅在被稱爲感覺野的視野受限區域中對刺激做出反應,不一樣神經元的感覺野部分重疊,使得它們可以覆蓋整個視野。網絡

clipboard.png

計算機視覺與人類視覺session

正如上圖所示,咱們在談論任何類型的神經網絡時,都不可能不說起一點神經科學以及人體(特別是大腦)及其功能相關的知識,這些知識成爲建立各類深度學習模型的主要靈感的來源。架構

卷積神經網絡的架構:

clipboard.png
卷積神經網絡架構dom

如上圖所示,卷積神經網絡架構與常規人工神經網絡架構很是類似,特別是在網絡的最後一層,即全鏈接。此外,還注意到卷積神經網絡可以接受多個特徵圖做爲輸入,而不是向量。機器學習

下面讓咱們探索構成卷積神經網絡的基本構件及相關的數學運算過程,並根據在訓練過程當中學到的特徵和屬性對圖像進行可視化和分類。ide

輸入層|Input Layer:

輸入層主要是n×m×3 RGB圖像,這不一樣於人工神經網絡,人工神經網絡的輸入是n×1維的矢量。

clipboard.png

RGB圖像

卷積層|Convolution Layer:

在卷積層中,計算輸入圖像的區域和濾波器的權重矩陣之間的點積,並將其結果做爲該層的輸出。濾波器將滑過整個圖像,重複相同的點積運算。這裏注意兩件事:

• 濾波器必須具備與輸入圖像相同數量的通道;

• 網絡越深,使用的濾波器就越多;擁有的濾波器越多,得到的邊緣和特徵檢測就越多;

clipboard.png

前向卷積運算

卷積層輸出的尺寸:

輸出寬度:

clipboard.png

輸出高度:

clipboard.png

其中:

• W :輸入圖像的寬度

• H :輸入圖像的高度

• Fw :濾波器或內核的寬度

• Fh :濾波器的高度

• P :填充

• S :移動步幅

卷積層輸出的通道數等於卷積操做期間使用的濾波器的個數。

爲何選擇卷積?

有時候可能會問本身,爲何要首先使用卷積操做?爲何不從一開始就展開輸入圖像矩陣?在這裏給出答案,若是這樣作,咱們最終會獲得大量須要訓練的參數,並且大多數人都沒有可以以最快的方式解決計算成本高昂任務的能力。此外,因爲卷積神經網絡具備的參數會更少,所以就能夠避免出現過擬合現象。

池化層|Pooling Layer:

目前,有兩種普遍使用的池化操做——平均池化(average pooling)和最大池化(max pooling),其中最大池化是二者中使用最多的一個操做,其效果通常要優於平均池化。池化層用於在卷積神經網絡上減少特徵空間維度,但不會減少深度。當使用最大池化層時,採用輸入區域的最大數量,而當使用平均池化時,採用輸入區域的平均值。

clipboard.png

最大池化

爲何要池化?

池化層的核心目標之一是提供空間方差,這意味着你或機器將可以將對象識別出來,即便它的外觀以某種方式發生改變,更多關於池化層的內容能夠查看Yann LeCunn的文章。

非線性層|Non-linearity Layer:

在非線性層中,通常使用ReLU激活函數,而不是使用傳統的Sigmoid或Tan-H激活函數。對於輸入圖像中的每一個負值,ReLU激活函數都返回0值,而對於輸入圖像中的每一個正值,它返回相同的值(有關激活函數的更深刻說明,請查看這篇文章)。

clipboard.png

ReLU激活函數

全鏈接層}Fully Connected Layer:

在全鏈接層中,咱們將最後一個卷積層的輸出展平,並將當前層的每一個節點與下一層的另外一個節點鏈接起來。全鏈接層只是人工神經網絡的另外一種說法,以下圖所示。全鏈接層中的操做與通常的人工神經網絡中的操做徹底相同:

clipboard.png

clipboard.png

卷積層展開.

clipboard.png
全鏈接層

上面討論的層和操做都是每一個卷積神經網絡的核心組件,如今已經討論了卷積神經網絡在前向傳播中經歷的操做,下面讓咱們跳轉到卷積神經網絡在反向傳播中經歷的操做。

反向傳播|Backpropagation:

全鏈接層:

在全鏈接層中,反向傳播與任何常規人工神經網絡徹底相同,在反向傳播中(使用梯度降低做爲優化算法),使用損失函數的偏導數即損失函數關於權重的導數來更新參數,其中咱們將損失函數的導數與激活輸出相乘,激活輸出的導數與非激活輸出相乘,導數爲未激活的輸出與權重相對應。

數學表達式以下:

clipboard.png

反向傳播說明圖

在計算梯度以後,咱們從初始權重中減去它以獲得新的優化:

clipboard.png

其中:

• θi+ 1 :優化的權重## 標題文字 ##

• θi:初始權重

• α :學習率

• ∇J(θi):損失函數的梯度

clipboard.png

梯度降低

在下面的動態圖中,是將梯度降低應用於線性迴歸的結果。從圖中能夠清楚地看到代價函數越小,線性模型越適合數據。

clipboard.png
梯度降低應用於線性迴歸

此外,請注意一點,應該謹慎地選擇學習率的取值,學習率過高可能會致使梯度超過目標最小值, 學習率過低可能致使網絡模型收斂速度變慢。

clipboard.png
小學習率與大學習率

在全部優化任務中,不管是在物理學、經濟學仍是計算機科學中,偏導數都被大量使用。偏導數主要用於計算因變量f(x, y, z)相對於其獨立變量之一的變化率。例如,假設你擁有一個公司的股份,後者的股票會根據多種因素(證券、政治、銷售收入等)上漲或下跌,在這種狀況下經過偏導數,你會計算多少股票受到影響而其餘因素保持不變,股票發生變化,則公司的價格也會發生變化。

池化層|Pooling Layer:

在最大池化特徵圖層中,梯度僅經過最大值反向傳播,所以稍微更改它們並不會影響輸出。在此過程當中,咱們將最大池化操做以前的最大值替換爲1,並將全部非最大值設置爲零,而後使用鏈式法則將漸變量乘以先前量以獲得新的參數值。

clipboard.png

池化層反向傳播

與最大池化層不一樣,在平均池化層中,梯度是經過全部的輸入(在平均合併以前)進行傳播。

卷積層|Convolution Layer:

你可能如今問本身,若是卷積層的前向傳播是卷積,那麼它的反向傳播是什麼?幸運的是,它的向後傳播也是一個卷積,因此你沒必要擔憂學習新的難以掌握的數學運算。

clipboard.png
卷積層反向傳播

其中:

• ∂hij:損失函數的導數

clipboard.png

簡而言之,上圖代表了反向傳播是如何在卷積層中起做用的。如今假設你已經對卷積神經網絡有了深入的理論理解,下面讓咱們用TensorFlow構建的第一個卷積神經網絡吧。

TensorFlow實現卷積神經網絡:

什麼是Tensorflow?

clipboard.png

TensorFlow是一個使用數據流圖進行數值計算的開源軟件庫。它最初由谷歌機器智能研究機構谷歌大腦團隊開發,用於機器學習和深度神經網絡的研究。

什麼是張量?

張量是一個有組織的多維數組,張量的順序是表示它所需數組的維數。

clipboard.png
張量的類型

什麼是計算圖?

計算圖是計算代數中的一個基礎處理方法,在機器學習中的神經網絡和其餘模型推導算法和軟件包方面很是富有成效。計算圖中的基本思想是表達一些模型——例如前饋神經網絡,計算圖做爲表示計算步驟序列的一個有向圖。序列中的每一個步驟對應於計算圖中的頂點, 每一個步驟對應一個簡單的操做,每一個操做接受一些輸入並根據其輸入產生一些輸出。

在下面的圖示中,咱們有兩個輸入w1 = x和w2 = y,這個輸入將流經圖形,其中圖形中的每一個節點都是數學運算,爲咱們提供如下輸出:

• w3 = cos(x),餘弦三角函數操做

• w4 = sin(x),正弦三角函數操做

• w5 = w3∙w4,乘法操做

• w6 = w1 / w2,除法操做

• w7 = w5 + w6,加法操做

clipboard.png

如今咱們瞭解了什麼是計算圖,下面讓咱們TensorFlow中構建本身的計算圖吧。

代碼:

# Import the deep learning library
import tensorflow as tf

# Define our compuational graph 
W1 = tf.constant(5.0, name = "x")
W2 = tf.constant(3.0, name = "y")
W3 = tf.cos(W1, name = "cos")
W4 = tf.sin(W2, name = "sin")
W5 = tf.multiply(W3, W4, name = "mult")
W6 = tf.divide(W1, W2, name = "div")
W7 = tf.add(W5, W6, name = "add")

# Open the session
with tf.Session() as sess:

    cos = sess.run(W3)
    sin = sess.run(W4)
    mult = sess.run(W5)
    div = sess.run(W6)
    add = sess.run(W7)
    
    # Before running TensorBoard, make sure you have generated summary data in a log directory by creating a summary writer
    writer = tf.summary.FileWriter("./Desktop/ComputationGraph", sess.graph)
    
    # Once you have event files, run TensorBoard and provide the log directory
    # Command: tensorboard --logdir="path/to/logs"

使用Tensorboard進行可視化:

什麼是Tensorboard?

TensorBoard是一套用於檢查和理解TensorFlow運行和圖形的Web應用程序,這也是Google的TensorFlow比Facebook的Pytorch最大的優點之一。

clipboard.png

上面的代碼在Tensorboard中進行可視化

在卷積神經網絡、TensorFlow和TensorBoard有了深入的理解,下面讓咱們一塊兒構建咱們的第一個使用MNIST數據集識別手寫數字的卷積神經網絡。

clipboard.png

MNIST數據集

咱們的卷積神經網絡模型將似於LeNet-5架構,由卷積層、最大池化和非線性操做層。

clipboard.png

卷積神經網絡三維仿真

代碼:

# Import the deep learning library
import tensorflow as tf
import time

# Import the MNIST dataset
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)

# Network inputs and outputs
# The network's input is a 28×28 dimensional input
n = 28
m = 28
num_input = n * m # MNIST data input 
num_classes = 10 # MNIST total classes (0-9 digits)

# tf Graph input
X = tf.placeholder(tf.float32, [None, num_input])
Y = tf.placeholder(tf.float32, [None, num_classes])

# Storing the parameters of our LeNET-5 inspired Convolutional Neural Network
weights = {
   "W_ij": tf.Variable(tf.random_normal([5, 5, 1, 32])),
   "W_jk": tf.Variable(tf.random_normal([5, 5, 32, 64])),
   "W_kl": tf.Variable(tf.random_normal([7 * 7 * 64, 1024])),
   "W_lm": tf.Variable(tf.random_normal([1024, num_classes]))
    }

biases = {
   "b_ij": tf.Variable(tf.random_normal([32])),
   "b_jk": tf.Variable(tf.random_normal([64])),
   "b_kl": tf.Variable(tf.random_normal([1024])),
   "b_lm": tf.Variable(tf.random_normal([num_classes]))
    }

# The hyper-parameters of our Convolutional Neural Network
learning_rate = 1e-3
num_steps = 500
batch_size = 128
display_step = 10

def ConvolutionLayer(x, W, b, strides=1):
    # Convolution Layer
    x = tf.nn.conv2d(x, W, strides=[1, strides, strides, 1], padding='SAME')
    x = tf.nn.bias_add(x, b)
    return x

def ReLU(x):
    # ReLU activation function
    return tf.nn.relu(x)

def PoolingLayer(x, k=2, strides=2):
    # Max Pooling layer
    return tf.nn.max_pool(x, ksize=[1, k, k, 1], strides=[1, strides, strides, 1],
                          padding='SAME')

def Softmax(x):
    # Softmax activation function for the CNN's final output
    return tf.nn.softmax(x)

# Create model
def ConvolutionalNeuralNetwork(x, weights, biases):
    # MNIST data input is a 1-D row vector of 784 features (28×28 pixels)
    # Reshape to match picture format [Height x Width x Channel]
    # Tensor input become 4-D: [Batch Size, Height, Width, Channel]
    x = tf.reshape(x, shape=[-1, 28, 28, 1])

    # Convolution Layer
    Conv1 = ConvolutionLayer(x, weights["W_ij"], biases["b_ij"])
    # Non-Linearity
    ReLU1 = ReLU(Conv1)
    # Max Pooling (down-sampling)
    Pool1 = PoolingLayer(ReLU1, k=2)

    # Convolution Layer
    Conv2 = ConvolutionLayer(Pool1, weights["W_jk"], biases["b_jk"])
    # Non-Linearity
    ReLU2 = ReLU(Conv2)
    # Max Pooling (down-sampling)
    Pool2 = PoolingLayer(ReLU2, k=2)
    
    # Fully connected layer
    # Reshape conv2 output to fit fully connected layer input
    FC = tf.reshape(Pool2, [-1, weights["W_kl"].get_shape().as_list()[0]])
    FC = tf.add(tf.matmul(FC, weights["W_kl"]), biases["b_kl"])
    FC = ReLU(FC)

    # Output, class prediction
    output = tf.add(tf.matmul(FC, weights["W_lm"]), biases["b_lm"])
    
    return output

# Construct model
logits = ConvolutionalNeuralNetwork(X, weights, biases)
prediction = Softmax(logits)

# Softamx cross entropy loss function
loss_function = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
    logits=logits, labels=Y))

# Optimization using the Adam Gradient Descent optimizer
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
training_process = optimizer.minimize(loss_function)

# Evaluate model
correct_pred = tf.equal(tf.argmax(prediction, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

# recording how the loss functio varies over time during training
cost = tf.summary.scalar("cost", loss_function)
training_accuracy = tf.summary.scalar("accuracy", accuracy)
train_summary_op = tf.summary.merge([cost,training_accuracy])

train_writer = tf.summary.FileWriter("./Desktop/logs",
                                        graph=tf.get_default_graph())

# Initialize the variables (i.e. assign their default value)
init = tf.global_variables_initializer()

# Start training
with tf.Session() as sess:

    # Run the initializer
    sess.run(init)
    
    start_time = time.time()
    
    for step in range(1, num_steps+1):
        
        batch_x, batch_y = mnist.train.next_batch(batch_size)
        # Run optimization op (backprop)
        sess.run(training_process, feed_dict={X: batch_x, Y: batch_y})
        
        if step % display_step == 0 or step == 1:
            # Calculate batch loss and accuracy
            loss, acc, summary = sess.run([loss_function, accuracy, train_summary_op], feed_dict={X: batch_x,
                                                                 Y: batch_y})
            train_writer.add_summary(summary, step)
            
            print("Step " + str(step) + ", Minibatch Loss= " + \
                  "{:.4f}".format(loss) + ", Training Accuracy= " + \
                  "{:.3f}".format(acc))
            
    end_time = time.time() 
    
    print("Time duration: " + str(int(end_time-start_time)) + " seconds")
    print("Optimization Finished!")
            
    # Calculate accuracy for 256 MNIST test images
    print("Testing Accuracy:", \
        sess.run(accuracy, feed_dict={X: mnist.test.images[:256],
                                      Y: mnist.test.labels[:256]}))

上面的代碼顯得有些冗長,但若是一段一段的對其進行分解,讀起來不是很難理解。

運行完該程序,對應結果應以下所示:

Step 1, Minibatch Loss= 74470.4844, Training Accuracy= 0.117
Step 10, Minibatch Loss= 20529.4141, Training Accuracy= 0.250
Step 20, Minibatch Loss= 14074.7539, Training Accuracy= 0.531
Step 30, Minibatch Loss= 7168.9839, Training Accuracy= 0.586
Step 40, Minibatch Loss= 4781.1060, Training Accuracy= 0.703
Step 50, Minibatch Loss= 3281.0979, Training Accuracy= 0.766
Step 60, Minibatch Loss= 2701.2451, Training Accuracy= 0.781
Step 70, Minibatch Loss= 2478.7153, Training Accuracy= 0.773
Step 80, Minibatch Loss= 2312.8320, Training Accuracy= 0.820
Step 90, Minibatch Loss= 2143.0774, Training Accuracy= 0.852
Step 100, Minibatch Loss= 1373.9169, Training Accuracy= 0.852
Step 110, Minibatch Loss= 1852.9535, Training Accuracy= 0.852
Step 120, Minibatch Loss= 1845.3500, Training Accuracy= 0.891
Step 130, Minibatch Loss= 1677.2566, Training Accuracy= 0.844
Step 140, Minibatch Loss= 1683.3661, Training Accuracy= 0.875
Step 150, Minibatch Loss= 1859.3821, Training Accuracy= 0.836
Step 160, Minibatch Loss= 1495.4796, Training Accuracy= 0.859
Step 170, Minibatch Loss= 609.3800, Training Accuracy= 0.914
Step 180, Minibatch Loss= 1376.5054, Training Accuracy= 0.891
Step 190, Minibatch Loss= 1085.0363, Training Accuracy= 0.891
Step 200, Minibatch Loss= 1129.7145, Training Accuracy= 0.914
Step 210, Minibatch Loss= 1488.5452, Training Accuracy= 0.906
Step 220, Minibatch Loss= 584.5027, Training Accuracy= 0.930
Step 230, Minibatch Loss= 619.9744, Training Accuracy= 0.914
Step 240, Minibatch Loss= 1575.8933, Training Accuracy= 0.891
Step 250, Minibatch Loss= 1558.5853, Training Accuracy= 0.891
Step 260, Minibatch Loss= 375.0371, Training Accuracy= 0.922
Step 270, Minibatch Loss= 1568.0758, Training Accuracy= 0.859
Step 280, Minibatch Loss= 1172.9205, Training Accuracy= 0.914
Step 290, Minibatch Loss= 1023.5415, Training Accuracy= 0.914
Step 300, Minibatch Loss= 475.9756, Training Accuracy= 0.945
Step 310, Minibatch Loss= 488.8930, Training Accuracy= 0.961
Step 320, Minibatch Loss= 1105.7720, Training Accuracy= 0.914
Step 330, Minibatch Loss= 1111.8589, Training Accuracy= 0.906
Step 340, Minibatch Loss= 842.7805, Training Accuracy= 0.930
Step 350, Minibatch Loss= 1514.0153, Training Accuracy= 0.914
Step 360, Minibatch Loss= 1722.1812, Training Accuracy= 0.875
Step 370, Minibatch Loss= 681.6041, Training Accuracy= 0.891
Step 380, Minibatch Loss= 902.8599, Training Accuracy= 0.930
Step 390, Minibatch Loss= 714.1541, Training Accuracy= 0.930
Step 400, Minibatch Loss= 1654.8883, Training Accuracy= 0.914
Step 410, Minibatch Loss= 696.6915, Training Accuracy= 0.906
Step 420, Minibatch Loss= 536.7183, Training Accuracy= 0.914
Step 430, Minibatch Loss= 1405.9148, Training Accuracy= 0.891
Step 440, Minibatch Loss= 199.4781, Training Accuracy= 0.953
Step 450, Minibatch Loss= 438.3784, Training Accuracy= 0.938
Step 460, Minibatch Loss= 409.6419, Training Accuracy= 0.969
Step 470, Minibatch Loss= 503.1216, Training Accuracy= 0.930
Step 480, Minibatch Loss= 482.6476, Training Accuracy= 0.922
Step 490, Minibatch Loss= 767.3893, Training Accuracy= 0.922
Step 500, Minibatch Loss= 626.8249, Training Accuracy= 0.930
Time duration: 657 seconds
Optimization Finished!
Testing Accuracy: 0.9453125

綜上,們剛剛完成了第一個卷積神經網絡的構建,正如在上面的結果中所看到的那樣,從第一步到最後一步,模型的準確性已經獲得很大的提高,但咱們的卷積神經網絡還有較大的改進空間。

如今讓咱們在Tensorboard中可視化構建的卷積神經網絡模型:

clipboard.png
可視化卷積神經網絡

clipboard.png
準確性和損失評估

結論:

卷積神經網絡是一個強大的深度學習模型,應用普遍,性能優異。卷積神經網絡的使用只會隨着數據變大和問題變得更加複雜變得更加具備挑戰性。

注意:

能夠在如下位置找到本文的Jupyter筆記本:

https://github.com/AegeusZeri...

參考文獻:

https://en.wikipedia.org/wiki...

https://en.wikipedia.org/wiki...

http://yann.lecun.com/exdb/mn...

https://opensource.com/articl...

https://en.wikipedia.org/wiki...

http://www.cs.columbia.edu/~m...

https://github.com/tensorflow...

http://yann.lecun.com/exdb/le...

本文做者:【方向】

閱讀原文

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索