Python-OpenCV深度學習入門示例詳解

0. 前言

深度學習已經成為機器學習中最受歡迎和發展最快的領域。自 2012 年深度學習性能超越機器學習等傳統方法以來,深度學習架構開始快速應用於包括計算機視覺在內的眾多領域。深度學習的常見應用包括語音識別、圖像識別、自然語言處理、推薦系統等等。大多數現代深度學習架構都基於人工神經網絡,深度學習中的“深”是指架構的層數。在本文中,首先介紹傳統機器學習方法與深度學習間的差異,然後將介紹圖像分類和對象檢測中常見的深度學習架構,最後,將介紹深度學習 Python 庫 Keras,並通過實戰來推開深度學習的大門。

1. 計算機視覺中的深度學習簡介

深度學習推動瞭計算機視覺領域的深刻變革,我們首先解釋深度學習中的關鍵概念,以便更好的瞭解深度學習的廣袤世界。

1.1 深度學習的特點

深度學習在許多計算機視覺任務中的性能超越瞭傳統的機器學習方法,但在選擇何種方法完成特定的計算任務時,應該明確深度學習與傳統的機器學習方法之間的區別,以選擇合適的方法:

  • 傳統的機器學習算法大多可以在低端機器上運行,而深度學習算法需要較高的算力才能正確訓練,通常這些計算可以使用 GPU 進行優化並行計算
  • 當對特征工程缺乏領域理解時,深度學習技術將是首選方法,這是由於在深度學習中,尋找相關特征的任務是算法的一部分,它通過減少問題的特征工程來實現自動化。特征工程是將領域知識應用於創建特征檢測器和提取器的過程,目的是降低數據的復雜性,使傳統的機器學習方法能夠正確學習。因此,傳統機器學習算法的性能取決於識別和提取特征的準確程度,而深度學習技術試圖從數據中自動提取高級特征。
  • 傳統機器學習和深度學習都能夠處理海量數據集。但兩種方法之間的主要區別在於隨著數據規模的增加其性能的變化程度。例如,在處理小數據集時,深度學習算法難以在數據中找到映射關系,因此可能表現不佳,因為深度學習通常需要大量數據來調整其內部參數。根據經驗法,如果數據集很大,深度學習會優於其他技術,而當數據集很小時,傳統的機器學習算法更可取。

可以使用下圖來總結機器學習與深度學習的主要區別:

機器學習與深度學習的區別

由上圖可知,機器學習與深度學習的關鍵選擇要點如下:

  • 計算資源(深度學習<——高算力計算機;機器學習<——低算力計算機)
  • 特征工程(深度學習<——特征提取和目標任務在同一步驟中;機器學習<——特征提取和目標任務在不同步驟中)
  • 數據集大小(深度學習<——大型或超大型數據集;機器學習<——小型或中型數據集)

1.2 深度學習大爆發

深度學習的概念可以追溯至 1986 年,但直到 2012 年深度學習性能超越傳統機器學習時,才出現瞭深度學習的大爆發。 ImageNet 是一個大型視覺數據庫,包含超過 1400 萬張帶有標簽的高分辨率圖像,包含 20,000 多個類別。因此,2012 年 AlexNet 架構在解決 ImageNet 大規模視覺識別挑戰賽 (ILSVRC) 上的突破性進展通常被認為是深度學習大爆發的開始。

2. 用於圖像分類的深度學習簡介

繼 AlexNet 在 ILSVRC 比賽中取得成功之後,更多深度學習架構開始被應用於 ImageNet 挑戰賽中,下圖顯示瞭在 ImageNet 挑戰賽中的最相關深度學習模型的準確率和模型的參數量:

性能對比

接下來,對深度學習模型架構進行介紹,以瞭解它們的發展脈絡及其關鍵點:

AlexNet:AlexNet 是 LSVRC-2012 的獲勝者,是一種簡單但功能強大的網絡架構,其通過堆疊卷積層和池化層,最後頂部使用全連接層。

VGG:VGGNet 由 Visual Geometry Group (VGG) 提出,在 LSVRC-2014 中排名第二,與 AlexNet 相比其在整個網絡中僅使用 3 x 3 卷積核,而不是使用大尺寸卷積核(例如 7 x 7 和 11 x 11),主要貢獻在於它表明網絡的深度是在卷積神經網絡中實現更好的識別或分類準確率的關鍵。它的主要缺點是訓練速度非常慢,並且其網絡架構權重參數量非常大(可以從上圖看出)。

GoogLeNet/Inception V1:GoogLeNet (也稱 Inception V1) 是 LSVRC-2014 的獲勝者,其 top-5 錯誤率僅為 6.67%,非常接近人類水平的表現。這種架構比 VGGNet 更深,但由於其使用 9 個並行的 Inception 模塊,Inception 模塊基於幾個非常小的卷積,極大的減少瞭參數數量。

ResNet:ResNets 是 LSVRC-2015 的獲勝者,是迄今為止最深的網絡,其包含 153 個卷積層 top-5 分類錯誤率僅為 4.9% (使深度學習模型準確率首次高於人類)。該架構使用跳躍連接,可實現增量學習修改。

Inception V3:Inception V2 在 Inception 模塊中引入瞭批歸一化,Inception V3 架構包含瞭分解思想,其目標是在不降低網絡效率的情況下減少參數的數量。

Inception V4:Inception V4 具有比 Inception-V3 更統一的簡化架構和更多的 Inception 模塊,在 LSVRC 上達到瞭 80.2% 的 top-1 準確率和 95.2% 的 top-5 準確率。

3. 用於目標檢測的深度學習簡介

目標檢測是深度學習中的一個熱門話題,其用於識別和定位圖像中的多個對象。目標檢測算法通常使用以下三個數據集進行基準測試:1) PASCAL Visual Object (PASCAL VOC) 數據集,包含 20 個類別的 10,000 張圖像,數據集中包含目標的邊界框;2) ImageNet 在 2013 年發佈瞭一個目標檢測數據集,它由大約 500,000 張圖像和 200 個類別組成;3) Common Objects in Context (COCO) 是一個大規模的對象檢測、分割數據集,其包括 328,000 張圖像以及 250 萬個標記目標。為瞭評估目標檢測算法,通常使用平均精度均值 (mean Average Precision, mAP),用於目標檢測深度學習算法:

R-CNN:Region-based Convolutional Network (R-CNN) 是最早使用卷積神經網絡進行目標檢測的算法之一,與基於 HOG 特征的系統相比,卷積神經網絡可以帶來更高的對象檢測性能。該算法可以分解為以下三個步驟:

  1. 創建一組候選區域
  2. 對每個候選區域通過基於 AlexNet 的模型執行前向傳遞以提取特征向量
  3. 潛在對象通過 SVM 分類器預測類別,利用線性回歸器預測邊界框的坐標

Fast R-CNN:Fast Region-based Convolutional Network (Fast R-CNN) 是對 R-CNN的改進,以有效地對目標提議進行分類。此外,Fast R-CNN 采用多項創新來提高訓練和測試速度,同時提高檢測精度。

Faster R-CNN:Faster R-CNN 是對 Fast R-CNN 的改進,它引入瞭候選區域網絡 (region proposal network, RPN),與檢測網絡共享圖像的卷積特征。

R-FCN:Region-based Fully Convolutional Network (R-FCN) 是一個隻有卷積層的框架,以實現準確高效的目標檢測。

YOLO: You only look once (YOLO) 可以在一個步驟中同時預測邊界框和類別概率。與其他深度學習檢測器相比,YOLO 產生更多的定位誤差,但其產生假陽性的概率較小。

SSD:Single Shot MultiBox Detector (SSD) 同樣通過單一端到端卷積神經網絡架構同時預測邊界框和類別概率。

YOLO V2: YOLO V2 是 YOLO 的改進版本,專註於提高準確性,同時是一個實時快速檢測器。

NASNet: NASNet 的作者介紹瞭神經網絡搜索,通過使用循環神經網絡來組成神經網絡架構,NASNet 學習模型模型架構的同時提高準確性。

Mask R-CNN:Mask Region-based Convolutional Network (Mask R-CNN) 是 Faster R-CNN 模型的改進,它為邊界框檢測添加瞭一個並行分支,目的是預測目標掩碼。目標掩碼是它在圖像中按像素進行的分割,允許進行目標實例分割。

YOLO V3:YOLO V3 是以 YOLO V1 和 YOLO V2 為基礎調整瞭網絡結構;利用多尺度特征進行對象檢測。

YOLO V4:YOLO-V4 算法是在原有 YOLO 目標檢測架構的基礎上,采用瞭 CNN 領域中優秀的優化策略,從數據處理、主幹網絡、網絡訓練、激活函數、損失函數等各個方面都有著不同程度的優化。

4. 深度學習框架 keras 介紹與使用

在本節中,我們將通過兩個簡單示例來一窺深度學習的神秘面紗。在第一個示例中,構造輸入數據來解決線性回歸問題;在第二個示例中,使用 MNIST 數據集對手寫數字進行分類。

4.1 keras 庫簡介與安裝

Keras 是用 Python 編寫的開源高級神經網絡 API,它能夠在 TensorFlow、或 Theano 之上運行,其最大的特點是能夠實現快速實驗,因此本文利用它來進行深度學習實戰。

要安裝 Keras,首先進行安裝:

pip install keras

4.2 使用 keras 實現線性回歸模型

首先創建用於訓練/測試算法的數據,如下所示:

# 產生一百個隨機數據點作為訓練數據
Number = 100
x = np.linspace(0, Number, Number)
y = 3 * np.linspace(0, Number, Number) + np.random.uniform(-12, 12, Number)

接下來創建模型:

def create_model():
    # 創建 Sequential 模型
    model = Sequential()
    # 使用具有線性激活函數的全連接層
    model.add(Dense(input_dim=1, units=1, activation='linear', kernel_initializer='uniform'))
    # 使用均方差(mse)作為損失函數,Adam作為優化器編譯模型 
    model.compile(loss='mse', optimizer=Adam(lr=0.1))
    return model

使用 Keras 時,最簡單的模型類型是 Sequential 模型,可以將其視為網絡層的線性堆棧,對於更復雜的架構,可以使用 Keras 函數式 API,以創建任意網絡架構。

作為簡單示例,此處使用 Sequential 模型,然後利用 model.add() 方法堆疊層來構建模型。在此示例中,使用瞭具有線性激活函數的單個全連接層。定義模型之後,需要使用損失函數與優化器編譯模型,示例中使用均方差 (mean squared error, MSE) 作為損失函數,使用 Adam 作為優化器並設置學習率為 0.1。

編譯模型完成後,就可以使用 model.fit() 方法使用訓練數據的訓練模型:

linear_reg_model.fit(x, y, epochs=100, validation_split=0.2, verbose=2)

訓練後,就可以獲得可學習參數 w 和 b,這些值將用於接下來的:

def get_weights(model):
    w = model.get_weights()[0][0][0]
    b = model.get_weights()[1][0]
    return w, b
w_final, b_final = get_weights(linear_reg_model)

接下來,我們可以用以下方式進行預測:

predictions = w_final * x + b_final

還可以保存模型:

linear_reg_model.save_weights("my_model.h5")

最後可以將訓練數據集和訓練完成後線性模型進行可視化:

plt.subplot(1, 2, 1)
plt.plot(x, y, 'ro', label='Original data')
plt.xlabel('x')
plt.ylabel('y')
plt.title("Training Data")

plt.subplot(1, 2, 2)
plt.plot(x, y, 'ro', label='Original data')
plt.plot(x, predictions, label='Fitted line')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Linear Regression Result', fontsize=10)
plt.legend()
plt.show()

線性回歸

如上圖所示,可以看到左側圖像顯示的是訓練數據,右側圖像顯示瞭線性回歸模型對應的擬合線。

如果我們已經擁有訓練完成的模型權重文件,就可以直接加載預先訓練的模型來進行預測:

# 加載模型
linear_reg_model.load_weights('my_model.h5')
# 構建測試數據集
M = 3
new_x = np.linspace(Number + 1, Number + 10, M)
# 使用模型進行預測
new_predictions = linear_reg_model.predict(new_x)

程序的運行結果如下圖所示:

線性回歸預測

4.3 使用 keras 進行手寫數字識別

接下來,我們使用 Keras 識別手寫數字,與第一個示例相同,首先需要構建模型:

def create_model():
    model = Sequential()
    model.add(Dense(units=128, activation='relu', input_shape=(784,)))
    model.add(Dense(units=128, activation='relu'))
    model.add(Dense(units=64, activation='relu'))
    model.add(Dense(units=10, activation='softmax'))
    # 使用分類交叉熵(categorical_crossentropy)作為損失函數和隨機梯度下降作為優化器編譯模型
    model.compile(optimizer=SGD(0.001), loss='categorical_crossentropy', metrics=['acc'])

    return model

使用 categorical_crossentropy 損失函數編譯模型,該損失函數非常適合比較兩個概率分佈,使用隨機梯度下降 (stochastic gradient descent, SGD) 作為優化器。

接下來加載 MNIST 數據集:

(train_x, train_y), (test_x, test_y) = mnist.load_data()

此外,由於我們使用的是全連接層,因此必須對加載的數據進行整形以輸入網絡:

train_x = train_x.reshape(60000, 784)
test_x = test_x.reshape(10000, 784)
train_y = keras.utils.to_categorical(train_y, 10)
test_y = keras.utils.to_categorical(test_y, 10)

創建模型完成後,就可以訓練模型,並保存創建的模型,也可以評估模型在測試數據集上的表現:

# 模型創建
model = create_model()
# 模型訓練
model.fit(train_x, train_y, batch_size=32, epochs=10, verbose=1)
# 模型保存
model.save("mnist-model.h5")
# 評估模型在測試數據集上的表現
accuracy = model.evaluate(x=test_x, y=test_y, batch_size=32)
# 打印準確率
print("Accuracy: ", accuracy[1])

接下來,可以使用訓練完成的模型來預測圖像中的手寫數字:

def load_digit(image_name):
    gray = cv2.imread(image_name, cv2.IMREAD_GRAYSCALE)
    gray = cv2.resize(gray, (28, 28))
    gray = gray.reshape((1, 784))
    return gray
# 加載圖片
test_digit_0 = load_digit("digit_0.png")
test_digit_1 = load_digit("digit_1.png")
test_digit_2 = load_digit("digit_2.png")
test_digit_3 = load_digit("digit_3.png")
imgs = np.array([test_digit_0, test_digit_1, test_digit_2, test_digit_3])
imgs = imgs.reshape(4, 784)
# 預測加載圖像
prediction_class = model.predict_classes(imgs)
# 打印預測結果
print("Class: ", prediction_class)

加載的四張圖像如下圖所示:

圖像加載

使用經過訓練的模型來預測這些圖像,得到的輸出如下:

Class: [0 1 2 3]

小結

在本節中,使用流行的庫深度學習庫 Keras 對深度學習進行瞭介紹。我們首先概述瞭用於圖像分類和目標檢測的深度學習架構。然後,我們介紹瞭 Keras,並通過示例訓練瞭簡單線性回歸模型,介紹瞭如何利用 Keras 訓練全連接網絡識別手寫數字。

到此這篇關於Python-OpenCV深度學習入門示例詳解的文章就介紹到這瞭,更多相關Python OpenCV深度學習內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: