卷積神經網絡這個詞,應該在你開始學習人工智能不久後就聽過了,那究竟什麼叫卷積神經網絡,今天咱們就聊一聊這個問題。
不用思考,左右兩張圖就是兩隻可愛的小狗狗,可是兩張圖中小狗狗所處的位置是不一樣的,左側圖片小狗在圖片的左側,右側圖片小狗在圖片的右下方,這樣若是去用圖片特徵識別出來的結果,兩張圖的特徵很大部分是不一樣的,這不是咱們但願的,那思考一下,爲何咱們人就能夠把它們都當作是可愛的小狗狗呢?這是由於平移不變性和空間層次結構,這兩個概念是卷積神經網絡中的概念。python
平移不變性與模式的空間層次結構網絡
這很好理解,咱們要觀察或者識別的物體,在圖片上平行移動,咱們均可以識別出來,由於不管他們在任何地方,都有相同的特徵;咱們識別物體的時候,先識別物體的局部特徵信息,而後再腦殼中將局部信息組合起來,組合而成更高層次的特徵信息,最終造成總體信息。好比上圖,咱們認出他們是可愛的狗狗,但腦殼在實際運轉的過程當中,是先看到了一些像素點(黑白紅等),而後將像素點鏈接起來造成輪廓或特徵(耳朵、眼睛、舌頭),最後組合這些特徵造成最後的結論(可愛的狗狗)。這就給咱們了啓發,咱們在計算機圖片識別的識別的時候,是否是能夠借鑑這種機制呢,不必定須要圖片所有的信息,而是識別圖片的特徵信息,再由這些特徵,咱們會將其組合成更大的特徵,再組合,最終得出總體的特徵信息,以下看一個經典的圖:
咱們的人腦在識別人臉的時候,腦神經不一樣部分也處理的是不一樣的信息,像素點-線條邊緣-對象部分-對象總體。架構
上面這種識別方式就與以前咱們採用的各類識別方式不一樣了,咱們以前都是將每張圖做爲一個總體,去識別其特徵,這裏更多的分析局部信息,這種方式叫卷積運算。函數
卷積運算學習
給了咱們一張彩色圖片,咱們用長、寬和深度(用於存儲每一個像素點 RGB 三種顏色的值)三個維度的張量去表示,用一個小的過濾器分別去取特徵值:
這裏面的黃色的小框是一種過濾器,咱們在作卷積運算的時候,每每須要選擇多種過濾器,這樣就能夠獲得不一樣的卷積特徵,這裏的過濾器是一個權重矩陣,與每一個圖片小塊作張量積,獲得的就是一維向量,過濾器在卷積神經網絡中的術語叫卷積核。咱們還能夠看到,原圖的尺寸是 5x5,處理後的尺寸是 3x3,縮小了一些,若是咱們每次把黃色的小格子向右移動兩個格子,那咱們就會獲得 2x2 的輸出,這種移動幾個格子的影響輸出尺寸的術語叫作步幅。優化
咱們這裏卷積層能夠處理學習圖片特徵的問題,可是這些特徵如何去進行學習獲得這是一隻可愛的小狗狗的結論,仍是須要之前咱們用到的全鏈接的方法,但是對於圖片來講,全鏈接的方法要用到的參數太多了,看下圖中密密麻麻的線,這每一層還不到十個節點神經元,換成圖片,動輒幾千個元素,幾百萬幾千萬個參數,這樣訓練出的網絡,只會得出過擬合的結果,須要調整,改變步幅能夠,可是效果很差,所以這裏咱們引入一個新的概念——池化。
池化人工智能
池化能夠理解爲某種狀況的採樣。好比最大池化的操做方法是:從輸入的特徵值中,提取窗口,輸出每一個通道的最大值,這樣說有點很差理解,能夠理解爲就是卷積層輸出的結果,再用一個上面黃色的 2x2 的小窗口,步幅是 2,每次取窗口中最大值,這樣就能夠減小很大一部分數據量。固然,還有不少池化的方法,好比最大池化改成平均值等,固然其目的都是同樣的,減小數據量。lua
隨後,數據就能夠交給全鏈接層,進行學習,輸出結果了。code
這裏咱們說明幾個問題:咱們的網絡通常不會只有一個卷積層和池化層,就像全鏈接層不會只有一個 Dense 層,每每是:卷積層-池化層-卷積層-池化層-卷積層-全鏈接層(多個 Dense);咱們上面雖然拿圖片識別舉例子,可是卷積神經網絡的應用可不只僅是圖片識別,還包括目標定位、人臉識別和目標分割等,應用很是普遍;卷積神經網絡的簡稱是 CNN,日常與他人交流的時候,不少人喜歡用 CNN。對象
手寫數字圖片識別例子優化
咱們以前多分類問題中就提到了手寫圖片數字識別的例子,當時的準確率不到 97.8%,這裏咱們將其優化爲卷積神經網絡的寫法,精度會達到 99.3%,這個提高仍是很可觀的呀,具體的代碼解釋上面都已經將理論講清楚了,這裏我就不寫那麼多代碼的解釋了,直接寫在註釋中,還有不少代碼是以前代碼,再也不贅述了,看網絡架構:
看代碼:
#!/usr/bin/env python3 import time from keras import layers from keras import models from keras.datasets import mnist from keras.utils import to_categorical def cat(): model = models.Sequential() # filters 輸出空間的維數 # kernel_size 窗口大小,就是上面黃色窗口的大小 # activation 激活函數 # input_shape 輸入 model.add(layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1))) # 最大池化 # pool_size 窗口大小 model.add(layers.MaxPooling2D(pool_size=(2, 2))) model.add(layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu')) model.add(layers.MaxPooling2D(pool_size=(2, 2))) model.add(layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu')) # 展平一個張量 model.add(layers.Flatten()) model.add(layers.Dense(64, activation='relu')) model.add(layers.Dense(10, activation='softmax')) # 查看神經網絡架構 # model.summary() (train_images, train_labels), (test_images, test_labels) = mnist.load_data() train_images = train_images.reshape((60000, 28, 28, 1)) train_images = train_images.astype('float32') / 255 test_images = test_images.reshape((10000, 28, 28, 1)) test_images = test_images.astype('float32') / 255 train_labels = to_categorical(train_labels) test_labels = to_categorical(test_labels) model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy']) model.fit(train_images, train_labels, epochs=5, batch_size=64) test_loss, test_acc = model.evaluate(test_images, test_labels) print(test_acc) if __name__ == "__main__": time_start = time.time() cat() time_end = time.time() print('Time Used: ', time_end - time_start)