記錄一下昨天半夜學的東西,以下代碼均通過tensorflow2自帶的keras實現。
卷積神經網絡(CNN)
- 爲什麼要使用卷積神經網絡?
卷積神經網絡常用於圖像處理。它可以提取關鍵信息,如圖片輪廓、主色調等信息,在減少喂入數據量的同時,又能增加模型深度,提高準確率。其具體實現筆者將在下文中介紹。
概念
卷積
卷積是通過兩個函數f 和g 生成第三個函數的一種數學算子,可以理解爲,在原函數f上,通過函數g進行處理,得到結果函數。這個處理卷積過程的g,就是卷積核。
爲了便於理解,舉一種簡單情況(選用離散數列進行演示,連續數列會更加麻煩):
接下來,卷積核從左向右移動,每三個元素通過卷積核得到結果,如:
最終得到的數列就是卷積後的結果。
上面的例子是一維矩陣(數列)的卷積,對於二維、三維甚至更高維的矩陣,都可以這樣類比。
舉一個例子:
同樣,卷積核需要逐個移動,例如先從左往右,再從上往下,遍歷每一塊元素:
最終結果:
動圖演示:
更高維的卷積都可以用這種方法推廣。
卷積核
上面的例子已經介紹了卷積核,卷積核非常神奇,圖像像素排列成的矩陣在通過卷積核可以實現銳化、模糊、邊緣、浮雕等效果,因此,我們可以使用卷積核提取關鍵信息。
下面是一些圖像處理常用卷積核:
這裏筆者使用OpenCV2演示效果,代碼如下:
# !usr/bin/env python
# -*- coding: utf-8 -*-
# @Date: 2020/6/15
# @Author: Koorye
import cv2
import numpy as np
if __name__ == '__main__':
img = cv2.imread('data/img/lena.jpg')
cv2.imshow('Lena', img)
blur = np.array([[1 / 9, 1 / 9, 1 / 9], [1 / 9, 1 / 9, 1 / 9], [1 / 9, 1 / 9, 1 / 9]], np.float32)
sharp = np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]], np.float32)
soble = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], np.float32)
blur_dst = cv2.filter2D(img, -1, kernel=blur)
sharp_dst = cv2.filter2D(img, -1, kernel=sharp)
soble_dst = cv2.filter2D(img, -1, kernel=soble)
cv2.imshow('blur', blur_dst)
cv2.imshow('sharp', sharp_dst)
cv2.imshow('soble', soble_dst)
cv2.waitKey(0)
運行結果:
通過修改卷積核的數值和尺寸,還可以得到不同效果的圖片。
全零填充
之前卷積的例子,在卷積之後都會丟失寬度(高度),原來7個元素的數列變成了5個元素,原來4x3的矩陣變成了3x2,這與原函數和卷積核的維度和尺寸有關。
要解決寬度(高度)的丟失問題,有一個解決思路,就是使用全零填充,即在邊緣加上0.
如:
卷積的結果是:.
但如果使用全零填充,就變成:
卷積的結果是:.
通過全零填充,梳理(矩陣)的尺寸得以保留,這可以有效緩解網絡層數加深後數據量減少的問題。
批標準化
批標準化(Batch Normalization)是一種用於改善人工神經網絡的性能和穩定性的技術,簡稱BN算法。
批標準化和標準化類似,用於將數據規範到一定的範圍內,以便計算。
筆者非該專業,無法深入講解,僅在此簡單介紹其作用。
池化
池化是一種採樣方法,它可以提取數據特徵,減少數據量並緩解過擬合。下面介紹一下兩種池化方法:
均值池化
顧名思義,即取平均值。
首先將源數據分塊,然後取每塊的平均值,如:
最大值池化
最大值池化也很好理解,即取最大值:
失活
隨機失活(Dropout)是對具有深度結構的人工神經網絡進行優化的方法,在學習過程中通過將隱含層的部分權重或輸出隨機歸零,降低節點間的相互依賴性從而實現神經網絡的正則化,降低其結構風險。
如何實現呢?每次,我們可以選用神經層中的部分神經元,下次訓練時再選用其他部分,通過這樣的選取,可以有效緩解過擬合等問題。
圖例:
接下來,Dropout層會隨機失活,例如,使b1失活,構成的神經網絡:
通過每次隨機選擇神經元失活,就可以保持神經網絡的穩定性和活性。
CNN結構
有了上面的介紹,概括CNN卷積神經網絡的結構:
卷積(Convolutional) → 批標準化(BN) → 激活(Activation) → 池化(Pooling) → 失活(Dropout)* → 全連接(FC)
概括爲CBAPD.
簡單演示tensorflow2的keras搭建CNN神經網絡,以下是一個典型的解決多分類問題(如圖片內容分類)的代碼:
# !usr/bin/env python
# -*- coding: utf-8 -*-
# @Date: 2020/6/15
# @Author: Koorye
import tensorflow as tf
import numpy as np
if __name__ == '__main__':
# 需要提供數據集
# x_train, x_test, y_train, y_test = ...
model = tf.keras.Sequential(
# 卷積層,filters指定卷積核數量,kernal_size指定卷積核尺寸
# padding指定是否使用全零填充
tf.keras.layers.Conv2D(filters=6, kernal_size=(5, 5), padding='same'),
# 批標準化
tf.keras.layers.BatchNormalization(),
# relu激活函數
tf.keras.layers.Activation('relu'),
# 池化,pool_size指定池尺寸,strides指定池間隔,默認與尺寸一致
tf.keras.layers.MaxPool2D(pool_size=(2, 2), strides=2, padding='same'),
# 隨機失活,指定每次失活20%的神經元
tf.keras.layers.Dropout(0.2),
# 數據平鋪成一維數組
tf.keras.layers.Flatten(),
# 全連接,128個神經元,relu激活函數
tf.keras.layers.Dense(128, activation='relu'),
# 隨機失活
tf.keras.layers.Dropout(0.2),
# 全連接,10個神經元,softmax激活函數,用於解決多分類問題
tf.keras.layers.Dense(10, activation='softmax')
)
# 模型編譯,optimize指定adam優化器,loss指定損失函數爲均方差
model.compile(optimize='adam', loss='mse')
# 模型訓練,batch_size指定每次喂入的數據量,epochs指定訓練次數
# validation_data指定驗證集,validation_freq指定多少次訓練進行一次驗證
model.fit(x_train, y_train, batch_size=32, epochs=5, validation_data=(x_test, y_test), validation_freq=1)