CNN通俗解析
定義:
簡而言之, ofollow,noindex" target="_blank">卷積神經網路(Convolutional Neural Networks) 是一種深度學習模型或類似於人工神經網路的多層感知器,常用來分析視覺影象。卷積神經網路的創始人是著名的電腦科學家Yann LeCun,目前在Facebook工作,他是第一個通過卷積神經網路在 MNIST資料集 上解決手寫數字問題的人。
Yann LeCunn
卷積神經網路的出現是受到了生物處理過程的啟發,因為神經元之間的連線模式類似於動物的視覺皮層組織。
人腦的視覺結構
個體皮層神經元僅在被稱為感受野的視野受限區域中對刺激作出反應,不同神經元的感受野部分重疊,使得它們能夠覆蓋整個視野。
計算機視覺與人類視覺
正如上圖所示,我們在談論任何型別的神經網路時,都不可能不提及一點神經科學以及人體(特別是大腦)及其功能相關的知識,這些知識成為建立各種深度學習模型的主要靈感的來源。
卷積神經網路的架構:
卷積神經網路架構
如上圖所示,卷積神經網路架構與常規人工神經網路架構非常相似,特別是在網路的最後一層,即全連線。此外,還注意到卷積神經網路能夠接受多個特徵圖作為輸入,而不是向量。
下面讓我們探索構成卷積神經網路的基本構件及相關的數學運算過程,並根據在訓練過程中學到的特徵和屬性對影象進行視覺化和分類。
輸入層|Input Layer:
輸入層主要是n×m×3 RGB影象,這不同於人工神經網路,人工神經網路的輸入是n×1維的向量。
RGB影象
卷積層|Convolution Layer:
在卷積層中,計算輸入影象的區域和濾波器的權重矩陣之間的點積,並將其結果作為該層的輸出。濾波器將滑過整個影象,重複相同的點積運算。這裡注意兩件事:
- 濾波器必須具有與輸入影象相同數量的通道;
- 網路越深,使用的濾波器就越多;擁有的濾波器越多,獲得的邊緣和特徵檢測就越多;
前向卷積運算
卷積層輸出的尺寸:
輸出寬度:
輸出高度:
其中:
- W :輸入影象的寬度
- H :輸入影象的高度
- Fw :濾波器或核心的寬度
- Fh :濾波器的高度
- P :填充
- S :移動步幅
卷積層輸出的通道數等於卷積操作期間使用的濾波器的個數。
為什麼選擇卷積?
有時候可能會問自己,為什麼要首先使用卷積操作?為什麼不從一開始就展開輸入影象矩陣?在這裡給出答案,如果這樣做,我們最終會得到大量需要訓練的引數,而且大多數人都沒有能夠以最快的方式解決計算成本高昂任務的能力。此外,由於卷積神經網路具有的引數會更少,因此就可以避免出現過擬合現象。
池化層|Pooling Layer:
目前,有兩種廣泛使用的池化操作——平均池化(average pooling)和最大池化(max pooling),其中最大池化是兩者中使用最多的一個操作,其效果一般要優於平均池化。池化層用於在卷積神經網路上減小特徵空間維度,但不會減小深度。當使用最大池化層時,採用輸入區域的最大數量,而當使用平均池化時,採用輸入區域的平均值。
最大池化
為什麼要池化?
池化層的核心目標之一是提供空間方差,這意味著你或機器將能夠將物件識別出來,即使它的外觀以某種方式發生改變,更多關於池化層的內容可以檢視 Yann LeCunn的文章 。
非線性層|Non-linearity Layer:
在非線性層中,一般使用ReLU啟用函式,而不是使用傳統的Sigmoid或Tan-H啟用函式。對於輸入影象中的每個負值,ReLU啟用函式都返回0值,而對於輸入影象中的每個正值,它返回相同的值(有關啟用函式的更深入說明,請 檢視這篇文章 )。
ReLU啟用函式
全連線層}Fully Connected Layer:
在全連線層中,我們將最後一個卷積層的輸出展平,並將當前層的每個節點與下一層的另一個節點連線起來。全連線層只是人工神經網路的另一種說法,如下圖所示。全連線層中的操作與一般的人工神經網路中的操作完全相同:
卷積層展開
全連線層
上面討論的層和操作都是每個卷積神經網路的核心元件,現在已經討論了卷積神經網路在前向傳播中經歷的操作,下面讓我們跳轉到卷積神經網路在反向傳播中經歷的操作。
反向傳播|Backpropagation:
全連線層:
在全連線層中,反向傳播與任何常規人工神經網路完全相同,在反向傳播中(使用梯度下降作為優化演算法),使用損失函式的偏導數即損失函式關於權重的導數來更新引數,其中我們將損失函式的導數與啟用輸出相乘,啟用輸出的導數與非啟用輸出相乘,導數為未啟用的輸出與權重相對應。
數學表示式如下:
反向傳播說明圖
在計算梯度之後,我們從初始權重中減去它以得到新的優化:
其中:
- θi+ 1 :優化的權重
- θi:初始權重
- α :學習率
- ∇J(θi):損失函式的梯度
梯度下降
在下面的動態圖中,是將梯度下降應用於線性迴歸的結果。從圖中可以清楚地看到代價函式越小,線性模型越適合資料。
梯度下降應用於線性迴歸
此外,請注意一點,應該謹慎地選擇學習率的取值,學習率太高可能會導致梯度超過目標最小值, 學習率太低可能導致網路模型收斂速度變慢。
小學習率與大學習率
在所有優化任務中,無論是在物理學、經濟學還是電腦科學中,偏導數都被大量使用。偏導數主要用於計算因變數f(x, y, z)相對於其獨立變數之一的變化率。例如,假設你擁有一個公司的股份,後者的股票會根據多種因素(證券、政治、銷售收入等)上漲或下跌,在這種情況下通過偏導數,你會計算多少股票受到影響而其他因素保持不變,股票發生變化,則公司的價格也會發生變化。
池化層|Pooling Layer:
在最大池化特徵圖層中,梯度僅通過最大值反向傳播,因此稍微更改它們並不會影響輸出。在此過程中,我們將最大池化操作之前的最大值替換為1,並將所有非最大值設定為零,然後使用鏈式法則將漸變數乘以先前量以得到新的引數值。
池化層反向傳播
與最大池化層不同,在平均池化層中,梯度是通過所有的輸入(在平均合併之前)進行傳播。
卷積層|Convolution Layer:
你可能現在問自己,如果卷積層的前向傳播是卷積,那麼它的反向傳播是什麼?幸運的是,它的向後傳播也是一個卷積,所以你不必擔心學習新的難以掌握的數學運算。
卷積層反向傳播
其中:
- ∂hij:損失函式的導數
簡而言之,上圖表明瞭反向傳播是如何在卷積層中起作用的。現在假設你已經對卷積神經網路有了深刻的理論理解,下面讓我們用TensorFlow構建的第一個卷積神經網路吧。
TensorFlow實現卷積神經網路:
什麼是Tensorflow?
是一個使用資料流圖進行數值計算的開源軟體庫。它最初由谷歌機器智慧研究機構谷歌大腦團隊開發,用於機器學習和深度神經網路的研究。
什麼是張量?
張量 是一個有組織的多維陣列,張量的順序是表示它所需陣列的維數。
張量的型別
什麼是計算圖?
計算圖 是計算代數中的一個基礎處理方法,在機器學習中的神經網路和其他模型推導演算法和軟體包方面非常富有成效。計算圖中的基本思想是表達一些模型——例如前饋神經網路,計算圖作為表示計算步驟序列的一個有向圖。序列中的每個步驟對應於計算圖中的頂點, 每個步驟對應一個簡單的操作,每個操作接受一些輸入並根據其輸入產生一些輸出。
在下面的圖示中,我們有兩個輸入w1 = x和w2 = y,這個輸入將流經圖形,其中圖形中的每個節點都是數學運算,為我們提供以下輸出:
- w3 = cos(x),餘弦三角函式操作
- w4 = sin(x),正弦三角函式操作
- w5 = w3∙w4,乘法操作
- w6 = w1 / w2,除法操作
- w7 = w5 + w6,加法操作
現在我們瞭解了什麼是計算圖,下面讓我們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 最大的優勢之一。
上面的程式碼在Tensorboard中進行視覺化
在卷積神經網路、TensorFlow和TensorBoard有了深刻的理解,下面讓我們一起構建我們的第一個使用MNIST資料集識別手寫數字的卷積神經網路。
MNIST資料集
我們的卷積神經網路模型將似於 LeNet-5 架構,由卷積層、最大池化和非線性操作層。
卷積神經網路三維模擬
程式碼:
# 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中視覺化構建的卷積神經網路模型:
視覺化卷積神經網路
準確性和損失評估
結論:
卷積神經網路是一個強大的深度學習模型,應用廣泛,效能優異。卷積神經網路的使用只會隨著資料變大和問題變得更加複雜變得更加具有挑戰性。
注意:
可以在以下位置找到本文的Jupyter筆記本:
參考文獻:
- https://en.wikipedia.org/wiki/Convolutional_neural_network
- https://en.wikipedia.org/wiki/Yann_LeCun
* http://yann.lecun.com/exdb/mnist/ - https://opensource.com/article/17/11/intro-tensorflow
- https://en.wikipedia.org/wiki/Tensor
- http://www.cs.columbia.edu/~mcollins/ff2.pdf
- https://github.com/tensorflow/tensorboard
- http://yann.lecun.com/exdb/lenet/
數十款阿里雲產品限時折扣中,趕緊點選領劵開始雲上實踐吧!
作者資訊
Lightning Blade,機器學習熱愛者
本文由阿里云云棲社群組織翻譯。
文章原標題《Demystifying Convolutional Neural Networks》,譯者:海棠,審校:Uncle_LLD。
文章為簡譯,更為詳細的內容, 請檢視原文 。