TShopping

 找回密碼
 註冊
搜索
查看: 1154|回復: 0
打印 上一主題 下一主題

[分享] [機器學習 ML ]Convolution Neural Network 卷積神經網路

[複製鏈接]
跳轉到指定樓層
1#
發表於 2021-2-5 15:23:28 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
 
Push to Facebook

Convolution Neural Network (卷積神經網路)

CNN一直以來是DL中最重要的一部份,CNN 在影像辨識中甚至可以超越人類辨識的精準度,把CNN的概念理解過一遍之後,會發現其實CNN是一個很直觀的演算法,而且仔細想想,其實跟人類用眼睛去辨識有87%的相似,接下來我用CNN始祖Model => LeNet 來介紹CNN是怎麼運作的,以下是LeNet的模型架構 ( 源自Yann LeCun 1998年論文 )



LeNet Architecture, 1998

可以從上面的LetNet架構中,對於輸入的圖片做了2次Convolutions(卷積),2次Subsampling(采樣),跟2次的Full connection(全連結)還有1次的Gaussian connections (高斯連結),中間的Convolution跟Subsampling在對圖片做特徵擷取的動作,最後把特徵擷取出來後,後面再展開用Full connection做分類,在這裡我就不介紹Full connection了,Full connection就是所謂的分類器,而他就是跟最原始DNN 分類的概念是一樣的,如果對DNN 逆向傳播不熟的可以參考這篇文章,下面我主要Focus在卷積層跟采樣層,也就是特徵擷取的那一段。

Convolution Layers (卷積層)

什麼是卷積呢?我們先來講一些computer vision的東西,我們都知道一張圖片都可以表示成由像素值(pixel)組成的矩陣。以下是一張長毛的皮卡丘的圖片(來自即將上映的神奇寶貝真人版電影,老實說,這隻真的很不討喜… 哈哈)





大家應該都有用過美圖軟體,或是修圖軟體,有一些基本的特效像是”銳化”或是浮雕的特效,然而這些基本的特效跟美圖都是怎麼做到的呢?

沒錯,就是利用卷積(Convolution) 來達成的



銳化特效,可以看出皮卡丘的邊緣跟毛都變得更細更清楚了,有一點點怪怪的XD


浮雕特效,看得出來除了皮卡丘的邊緣以外都變成灰色的了,變成浮雕的感覺了

這裡你可能會想,為什麼講CNN要講到美圖,而美圖跟類神經網路又有什麼關係呢?我相信大家對於”特徵”(Feature)這二個字應該都不陌生,在訓練ML的模型或是NN的模型時,我們需要不斷的擷取”資料”的特徵,最後再進行分類或是預估的動作。

========================================

之所以我們可以做過出不同的美圖效果,是在對圖片做不同的卷積(銳化和模糊或是邊緣增強等操作),我們用銳化來舉例好了,銳化過後的圖片,我們可以看出圖片裡面物件的”邊緣”被強化了,而”邊緣”就是圖片的其中一個有效的特徵,所以我們來思考一下,不同的卷積動作是不是就可以從圖片擷取出各種不同的特徵,像是”邊緣”,”曲線”等等的特徵呢?然後我們再去對特徵做選擇,並且利用特徵來做分類跟預估,沒錯!!所以這就是為什麼Convolution Neural Network的由來,卷積就是在對圖片去做擷取特徵的動作,找出最好的特徵最後再進行分類

========================================

那卷積又是怎麼達成的呢?圖片的卷積運算其實很簡單,只要你會小學教的加減乘除就可以做到,假設我們有張圖,5X5的像素圖,和一個3X3的矩陣



接下來我再放上一張利用3X3矩陣做卷積的GIF圖




基本卷積運算(來自網站)

看完上面動圖後,可能有眼尖的人已經看出圖片卷積怎麼運作的了,沒錯,就是將3X3的矩陣在圖片上的像素一步一步移動(在卷積層中移動的步數稱為Stride步數),在每個位置的時候,計算兩個矩陣相對元素的乘積並相加,輸出一個值然後放在一個矩陣(右邊粉色的矩陣),這就是基本的卷積運算。

橘色的矩陣就是所謂的”卷積核(Kernel)”,也是所謂的Filter,然而美圖修修也就是用不同的Kernel做卷積所達成的,不過在這裡你可能會有一個問題?

★ 如果以上面那種運算方式,是不是每做一次卷積,出來後的特徵圖會越來越小呢?原本5X5的圖片跟3X3的矩陣做卷積出來後的圖變成3X3的了,如果不想經過卷積後圖變小的話,有個技術是Zero Padding,他可以將圖片向外擴張補0後再進行卷積,這樣卷積過後的特徵圖就會跟原本的圖一樣了,對於Padding有興趣的話,可以參考Tommy大寫的這篇文章,寫得非常好。

不同的卷積核對不同的圖片做出不同的效果,我們直接用openCV的code來實作一遍convolution



下面是我用不同的3X3 的卷積核做出來的效果




現在大家應該都懂卷積在圖片上的原理了,而在CNN上卷積其實就是在對圖片做特徵擷取,那我們回到LeNet的架構圖上看一下,我們來看第一層的卷積層,Input為32x32的image,然而經過Convolutions的時候出現6張28X28的Feature map,這是怎麼做到的呢?



  • 為什麼會出現6張Feature map呢?


其實很簡單的去想,就是用6個”不同的卷積核”去對Input 做卷積

★深度 = 卷積核數量

第一個卷積層出來後的feature map為 6張,因為卷積核數量為6
第二個卷積層出來後的feature map為16張,因為卷積核數量為16
P.S. 這裡妳/你可能會想,第二次的卷積層出來的深度怎麼不是6*16呢?不是應該是每張圖做16個不同的卷積核卷積嗎?=>對於卷積核來說,是有深度的,看下面這張圖應該就很好理解,然而第二個卷積層就的卷積核就是有深度的,16個深度為6的卷積核,所以出來的feature map深度就是16



來自此網站

2. 那為什麼做完卷積後的每一個Feature map都是28X28呢?

讓我們從上面的那個簡單例子來思考,3X3的卷積核對5X5的圖片出來的Feature map是3X3,因為卷積核由最左邊到最右邊只能走3步,這是步數為1的情況,那如果步數為2的情況呢?出來的Feature map是2X2,我們可以推測出一個公式

★Feature map width=[(Original width-Kernel width)/(Stride+1)]+1

所以5X5的Kernel,步數為1的情況出來的Feature map 就是28X28(沒有做Zero Padding的情況下)

接下來介紹什麼是Subsampling(采樣)

Subsampling/ Pooling Layer(采樣/池化層)

Subsampling,也可以稱為Pooling(池化),這次我先直接來介紹池化的基本運算方式,Pooling常用的方式有二種,Max Pooling,Mean Pooling,我這裡介紹Max Pooling的運作方式,看完應該會馬上就可以理解Mean Pooling是怎麼做的。

池化層跟卷積層一樣,有個Kernel(大多為2X2),對卷積層出來的feature map做運算,我們來看下面這張圖:




Max Pooling運作方式

這張圖是利用2X2的Kernel 在image上用”步數”2(Stride)進行Pooling的基本運算,沒錯,就是很直觀也很簡單的,在Kernel經過的地方,取出最大值,就達成降維了。

看懂Pooling的基本運算後,我們來講一下為什麼要做池化層:

  • 對特徵圖(Feature map)降維,並且保留重要的特徵,參數減少,可防止Overfitting。


對於Overfitting不熟的人,可以參考我之前的寫的文章,我們知道,越複雜或是參數越多的模型容易造成Overfitting,Pooling層有效降低我們的參數,而且還可以保留重要的特徵,也可以使模型對圖像微小的變換或是一些失真變得更沉穩(因為我們取了Kernel的最大值,微小的失真並不會改變結果,最大值還是最大值)。

2. 卷積跟Pooling後可對”微小”的變化保持不變性(invariance), 旋轉、平移、伸縮等的不變性。

那這是什麼意思呢?這個討論版對這部份寫得非常好,大家參考看看
https://www.zhihu.com/question/36686900

LeNet(論文連結)實作

沒錯,LetNet就是所謂的CNN之父,前面也用了LetNet來介紹了卷積跟池化,然後LeNet整個架構就是利用了卷積跟池化把圖片特徵擷取出來後,並接上全連結層做訓練,看下面的架構圖就可以簡單的把LetNet實作出來,這裡我們用簡單Mnist data來實作LeNet 模型的分類器,



LeNet Architecture, 1998
  1. import numpy as np
  2. import keras
  3. from keras.datasets import mnist
  4. from keras.utils import np_utils
  5. from keras.models import Sequential
  6. from keras.layers import Dense, Activation, Conv2D, MaxPooling2D, Flatten
  7. from keras.optimizers import Adam

  8. #load the MNIST dataset from keras datasets
  9. (X_train, y_train), (X_test, y_test) = mnist.load_data()

  10. #Process data
  11. X_train = X_train.reshape(-1, 28, 28, 1) # Expend dimension for 1 cahnnel image
  12. X_test = X_test.reshape(-1, 28, 28, 1)  # Expend dimension for 1 cahnnel image
  13. X_train = X_train / 255 # Normalize
  14. X_test = X_test / 255 # Normalize

  15. #One hot encoding
  16. y_train = np_utils.to_categorical(y_train, num_classes=10)
  17. y_test = np_utils.to_categorical(y_test, num_classes=10)

  18. #Build LetNet model with Keras
  19. def LetNet(width, height, depth, classes):
  20.     # initialize the model
  21.     model = Sequential()

  22.     # first layer, convolution and pooling
  23.     model.add(Conv2D(input_shape=(width, height, depth), kernel_size=(5, 5), filters=6, strides=(1,1), activation='tanh'))
  24.     model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

  25.     # second layer, convolution and pooling
  26.     model.add(Conv2D(input_shape=(width, height, depth), kernel_size=(5, 5), filters=16, strides=(1,1), activation='tanh'))
  27.     model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

  28.     # Fully connection layer
  29.     model.add(Flatten())
  30.     model.add(Dense(120,activation = 'tanh'))
  31.     model.add(Dense(84,activation = 'tanh'))

  32.     # softmax classifier
  33.     model.add(Dense(classes))
  34.     model.add(Activation("softmax"))

  35.     return model

  36. LetNet_model = LetNet(28,28,1,10)
  37. LetNet_model.summary()
  38. LetNet_model.compile(optimizer=Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08),loss = 'categorical_crossentropy',metrics=['accuracy'])

  39. #Strat training
  40. History = LetNet_model.fit(X_train, y_train, epochs=5, batch_size=32,validation_data=(X_test, y_test))

  41. #Plot Loss and accuracy
  42. import matplotlib.pyplot as plt
  43. plt.figure(figsize = (15,5))
  44. plt.subplot(1,2,1)
  45. plt.plot(History.history['accuracy'])
  46. plt.plot(History.history['val_accuracy'])
  47. plt.title('model accuracy')
  48. plt.ylabel('accuracy')
  49. plt.xlabel('epoch')
  50. plt.legend(['train', 'test'], loc='upper left')

  51. plt.subplot(1,2,2)
  52. plt.plot(History.history['loss'])
  53. plt.plot(History.history['val_loss'])
  54. plt.title('model loss')
  55. plt.ylabel('loss')
  56. plt.xlabel('epoch')
  57. plt.legend(['train', 'test'], loc='upper left')
  58. plt.show()
  59. plt.show()
複製代碼




Train 5 個epoch就可以達到98.69的精確率



Loss 跟 Accuracy

最後附上一個很厲害的網站,模擬了LeNet所有層的輸出結果,超酷的!

3D Visualization of a Convolutional Neural NetworkEdit description
scs.ryerson.ca

結論

CNN不外乎跟卷積還有池化脫離不了關係,卷積跟池化把一張圖片的特徵取出來後,就可以做很多的事情,不見得只能做分類,甚至可以把分類層改成Decoder進行圖像分割。CNN對於Deep learning 用在影像上面占了非常大的重要性,理解卷積跟池化會更容易理解CNN一直到現在的演化史,我也寫了另外一篇文章來簡單介紹CNN的演化史(分類的部份),並且利用Keras來簡易實作各個CNN的演化。


文章出處




 

臉書網友討論
*滑块验证:
您需要登錄後才可以回帖 登錄 | 註冊 |

本版積分規則



Archiver|手機版|小黑屋|免責聲明|TShopping

GMT+8, 2024-4-26 10:50 , Processed in 0.084474 second(s), 25 queries .

本論壇言論純屬發表者個人意見,與 TShopping綜合論壇 立場無關 如有意見侵犯了您的權益 請寫信聯絡我們。

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表