聖誕將至,你可能已經在商場、公園或自家的煙囪裡發現了聖誕老人。隨著機器識別技術的發展,用人工智慧來識別路過或來送禮物的聖誕老人似乎是個不錯的選擇。近日,Adrian Rosebrock 在 PyImageSearch 上發表了一篇教程,介紹了在樹莓派上使用 Keras 實現深度學習聖誕老人識別器的過程。你可透過文末連結訪問原文——也可在原文末尾留下電子郵箱地址向原作者索取本專案的完整程式碼。另外,本教程中還提及了很多其它的關聯教程和專案,為了更方便閱讀,機器之心對這些連結進行了縮短處理。
在我寫過的 PyImageSearch 教程中,這一篇是最有意思的!其中涉及到的內容包括:
- 深度學習
- 樹莓派開發板
- 3D 聖誕樹
- 參考 HBO 電視劇《矽谷》中的「Not Hotdog(不是熱狗)」檢測器
- 我打扮成聖誕老人
為了不辜負這個聖誕假期,我將在這裡介紹如何將一個使用 Keras 訓練的深度學習模型部署到樹莓派上。
但這可不是隨便什麼機器學習模型……
這個影像分類器是專門為檢測我們的影片流中是否存在聖誕老人而設計的。
如果我們確實檢測到了聖誕老人……
好吧,我現在還不想劇透(但確實和 3D 聖誕樹以及一首歡快的曲子有關)。
請享受這個教程,下載程式碼,然後自己動手實現吧!
最重要的是:要玩得開心喲!
在樹莓派上用 Keras 做深度學習
這篇文章將完整地介紹使用 Keras 在樹莓派上執行深度神經網路的過程。本專案的目標是實現一個 Not Santa(不是聖誕老人)檢測器,這樣可以具體地進行演示,也能讓我們玩得開心。
在本文正文的第一部分,我們將談論 Not Santa 檢測器是什麼(因為你可能並不瞭解 HBO 的《矽谷》電視劇中的 Not Hotdog 檢測器,這東西已經圈粉了很多人)。
然後我們會配置我們的樹莓派使其能夠執行深度學習任務——我們要安裝 TensorFlow、Keras 和其它一些必備軟體包和庫。
在我們的樹莓派為深度學習做好了準備之後,我們將建立一個 Python 指令碼,該指令碼能夠:
1. 從磁碟載入我們的 Keras 模型
2. 訪問我們的樹莓派相機模組/USB 網路攝像頭
3. 應用深度學習來檢測影片幀中是否存在聖誕老人
4. 如果存在聖誕老人,就訪問我們的 GPIO 引腳並播放音樂
我在 PyImageSearch 上最喜歡寫這一類文章了,因為這種教程能將多種不同的技術聚集到一起,這篇文章包含:
- 在樹莓派上部署深度學習;可參閱:https://goo.gl/3MPJUp
- 訪問樹莓派相機模組/USB 網路攝像頭;可參閱:https://goo.gl/NEZrGK
- 操作樹莓派上的 GPIO 和計算機;可參閱:https://goo.gl/nwoS38
那我們就開始吧!
Not Santa 檢測器是什麼?
圖 1:來自《矽谷》電視劇的 Not Hotdog 檢測器應用
Not Santa 檢測器的靈感來自 HBO 的電視劇《矽谷》,其中有角色創造了一個可以檢測輸入的影像是「熱狗」或「不是熱狗」的智慧手機應用。
這個節目顯然是在用美國矽谷的創業公司文化製造笑料,其中包括:
1. 炒作機器學習/深度學習概念
2. 諷刺他們重做了大量用途很小的智慧應用(但其創造者卻相信他們的應用將會「改變世界」)。
我決定自己也來找點樂子。
今天我們要建立一個 Not Santa 檢測器,可以檢測影像或影片幀中是否存在聖誕老人。
如果你不知道聖誕老人是啥,簡單介紹一下。他是一個歡樂的、胖乎乎的、長著白鬍子的虛構的西方文化形象,他會在平安夜孩子們睡覺時給他們帶來禮物。
但是,我們這個應用不只是為了好玩或諷刺!
我們可以在這個過程中學習到很多實用的技能,包括:
1. 如何為深度學習任務配置你的樹莓派
2. 在你的樹莓派上安裝 Keras 和 TensorFlow
3. 在你的樹莓派上部署一個之前訓練的卷積神經網路(使用 Keras)
4. 在檢測到正例時執行給定的動作
但在深入程式碼之前,我們先看看我們需要的硬體。
需要什麼硬體?
圖 2:Not Santa 檢測器的硬體包含樹莓派 3、揚聲器、3D 聖誕樹和網路攝像頭(圖中沒有)。這個樹莓派中有用 Keras 實現的 LeNet 的 Python 指令碼,可以檢測聖誕老人。
如果你要按照這個教程進行操作(不加更改),你需要:
- 一塊樹莓派 3 開發板(或樹莓派 3 入門套件,強烈推薦)
- 一個樹莓派相機模組或一個 USB 攝像頭。在本教程中,我使用了 Logitech C920,因為它的價效比不錯(而且還有一條 USB 線能為你提供一點額外的操作空間,而不是樹莓派相機那種很短的帶線
- 樹莓派可用的 3D 聖誕樹(由 Rachel Rayns 設計):https://goo.gl/GSqxjs
- 一組揚聲器——我推薦 Pi Hut 的這個:https://goo.gl/A7MmR4;來自 Adafruit 的這個:https://www.adafruit.com/product/1363。或者你喜歡小而有力的,可以選擇這個:http://amzn.to/2AF920r
當然,你並不需要所有這些元件。
實際上只要有樹莓派和相機模組/USB 攝像頭就夠了(但這樣你就需要修改程式碼,使其不會試圖訪問 GPIO 引腳或透過揚聲器播放音樂)。
你的配置應該和我的類似,如上面的圖 2 所示,上面已經連線了揚聲器、3D 聖誕樹和網路攝像頭(但圖中看不到,因為它是 off camera)。
我還推薦在上面連線 HDMI 顯示器和鍵盤,以便測試和除錯你的指令碼。
圖 3:我的深度學習配置包含樹莓派及其元件,另外還有鍵盤、滑鼠和一個小型 HDMI 顯示器。使用這個配置,我們肯定能抓住在我的聖誕樹前送禮物的聖誕老人。
你可以在上圖中看到我的樹莓派、HDMI 顯示器、鍵盤以及聖誕小動物朋友,它在我完成這個教程的過程中一直陪伴著我。
如何在樹莓派上安裝 TensorFlow 和 Keras?
圖 4:我們將在樹莓派上使用後端為 TensorFlow 的 Keras 來實現深度學習 Not Santa 檢測器
我們之前介紹過如何使用 Keras 訓練一個能夠識別輸入影像中是否有聖誕老人的卷積神經網路,參閱:https://goo.gl/imxkrY
這裡我們將要之前訓練的模型部署到樹莓派上。
我之前也曾提到過,樹莓派並不適用於訓練神經網路(除了簡單的試玩案例)。但在神經網路訓練好了之後,我們可以使用樹莓派來部署(當然,這個模型必須足夠小,要能放進樹莓派的記憶體中)。
我假設你已經在你的樹莓派上安裝了 OpenCV。如果你還沒有在樹莓派上安裝 OpenCV,可以參考這個教程:https://goo.gl/ARPdYa。我在其中演示了為了提升速度而最佳化樹莓派+OpenCV 安裝的方法(可以實現 30% 的效能提升)。
注意:本教程不適用於 Python 3——你應該使用 Python 2.7。後面我會解釋原因。現在你就使用 Python 2.7 和 OpenCV 配置你的樹莓派吧。在樹莓派+OpenCV 安裝指南的第 4 步,一定要換成 -p python2 來建立一個虛擬環境。
現在,我建議你增加樹莓派的 swap 空間。增大 swap 讓你可以使用樹莓派 SD 卡來增加記憶體(當你想在記憶體有限的樹莓派上編譯和安裝大型庫時,這個步驟會很關鍵)。
要增大你的 swap 空間,先開啟 /etc/dphys-swapfile,然後編輯 CONF_SWAPSIZE 變數:
# set size to absolute value, leaving empty (default) then uses computed value
# you most likely don't want this, unless you have a special disk situation
# CONF_SWAPSIZE=100
CONF_SWAPSIZE=1024
注意這裡我將 swap 從 100MB 增大到了 1024MB。
現在,重啟 swap 服務:
$ sudo /etc/init.d/dphys-swapfile stop
$ sudo /etc/init.d/dphys-swapfile start
注:增大 swap 的大小會損傷你的記憶體卡,所以在你完事之後一定要撤銷這個更改並重啟 swap 服務。關於大 swap 損傷記憶體卡的資訊可參閱:https://goo.gl/ZpIuaI
現在你的 swap 空間已經增大了,該配置開發環境了。
首先,使用 Python 2.7 建立一個名為 not_santa 的虛擬環境(我會在安裝 TensorFlow 時解釋使用 Python 2.7 的原因):
$ mkvirtualenv not_santa -p python2
注意這裡的 -p 指向了 python2,表示這個虛擬環境將使用 Python 2.7。
如果你對 Python 虛擬環境不熟悉,不知道它們的工作方式和我們使用它的原因,請參閱這兩個連結:https://goo.gl/nwoS38 和 https://goo.gl/1vPU6b
你還需要確保你已經將你的 cv2.so 捆綁包符號連線(sym-link)到了你的 not_santa 虛擬環境(如果你還沒這樣做):
$ cd ~/.virtualenvs/not_santa/lib/python2.7/site-packages
$ ln -s /usr/local/lib/python2.7/site-packages/cv2.so cv2.so
同樣,要確保你已經使用 Python 2.7 捆綁包編譯了 OpenCV。你還需要仔細檢查你的 cv2.so 檔案的路徑,以防你的安裝路徑和我的路徑有所不同。
如果你已經編譯了 Python 3 + OpenCV 並且建立了 sym-link,那麼就嘗試 import cv2 到你的 Python shell 中,你會收到一個讓人困惑的 traceback 說這個匯入失敗了。
重要說明:對於接下來的幾個 pip 命令,要確保你在 not_santa 環境(或你選擇的 Python 環境)中,否則你就要把這些包安裝到你的樹莓派的系統 Python 上。
要進入該環境,只需在 bash 提示符使用 workon 命令:
$ workon not_santa
然後,你會看到「(not_santa)」出現在你的 bash 提示符的開始處。
確保你使用以下命令在 not_santa 環境中安裝了 NumPy:
$ pip install numpy
因為這個專案需要訪問 GPIO 引腳,所以我們需要安裝 RPi.GPIO 和 gpiozero:
$ sudo pip install RPi.GPIO gpiozero
現在在你的樹莓派上安裝 TensorFlow
這裡有一個問題:沒有合適的官方(谷歌釋出的)TensorFlow 版本。
我們可以從頭開始編譯適用於樹莓派的 TensorFlow,但這個過程非常漫長、麻煩和痛苦,可以參考:https://goo.gl/a2hnzK
或者我們也可以使用 Sam Abrahams 建立的預編譯後的二進位制檔案,GitHub 地址:https://goo.gl/WJzbL6
但問題是隻有兩種預編譯的 TensorFlow 二進位制檔案:
1. 用於 Python 2.7 的
2. 用於 Python 3.4 的
而 Raspbian Stretch 發行版(在本文寫作時的最新版 Raspbian 作業系統)採用的是 Python 3.5——所以這裡有個版本不匹配的問題。
為了避免 Python 3.4 和 Python 3.5 之間的麻煩,我決定還是使用 Python 2.7 好了。
儘管我很想在本教程中使用 Python 3,但這樣的話安裝過程就會變得更加複雜(而且因為本教程關注的重點不是安裝,所以我決定讓這個任務更簡單一點)。
讓我們使用以下命令安裝使用 Python 2.7 的 TensorFlow:
$ wget https://github.com/samjabrahams/tensorflow-on-raspberry-pi/releases/download/v1.1.0/tensorflow-1.1.0-cp27-none-linux_armv7l.whl
$ pip install tensorflow-1.1.0-cp27-none-linux_armv7l.whl
注:上面程式碼中的 URL 較長,注意識別。
編譯和安裝了 TensorFlow 之後(在我的樹莓派上用了大概一個小時),你需要安裝 HDF5 和 h5py。這些庫讓我們可以從磁碟載入我們之前訓練的模型:
$ sudo apt-get install libhdf5-serial-dev
$ pip install h5py
我安裝 HDF5 和 h5py 的時候沒有執行 time 命令,所以我不記得安裝它們用去了多少時間,我估計大概是 30-45 分鐘。
最後,讓我們安裝 Keras 和本專案所需的其它包:
$ pip install pillow imutils
$ pip install scipy --no-cache-dir
$ pip install keras
SciPy 的安裝需要幾個小時,所以你可以在工作時或晚上安裝它。
要測試你的配置,可在 not_santa 環境中開啟 Python shell,然後執行以下命令:
$ workon not_santa
$ python
>>> import h5py
>>> from gpiozero import LEDBoard
>>> from gpiozero.tools import random_values
>>> import cv2
>>> import imutils
>>> import keras
Using TesnsorFlow backend.
>>> print("OpenCV version: {}".format(cv2.__version__))
'3.3.1'
>>> print("Keras version: {}".format(keras.__version__))
'2.0.8'
>>> exit()
如果一切進展順利,你應該會看到使用 TensorFlow 後端匯入的 Keras。
正如上面的輸出演示的那樣,你應該再次檢查是否可以匯入你的 OpenCV 捆綁包(cv2)。
最後,不要忘記將你的 swap 大小從 1024MB 改回 100MB,步驟是:
1. 開啟 /etc/dphys-swapfile
2. 將 CONF_SWAPSIZE 重置為 100MB
3. 重啟 swap 服務(就像我們前面說的那樣)。
就像前面說的那樣,將 swap 大小改回 100MB 有利於記憶體卡的使用壽命。如果你跳過這個步驟,你可能會遇到記憶體受損問題,而且卡的使用壽命也會變短。
在樹莓派上執行 Keras 深度學習模型
圖 5:使用 Keras 和 Python 在樹莓派上執行深度學習模型
現在我們可以開始使用 Keras、TensorFlow 和樹莓派來編寫 Not Santa 檢測器的程式碼了。
再次重申,我會假設你的硬體配置和我的一樣(即 3D 聖誕樹和揚聲器),所以如果你的配置不一樣,你需要自己寫或修改下面的程式碼。
首先,建立一個新檔案,將其命名為 not_santa_detector.py,然後貼入以下程式碼:
其中第 2-12 行程式碼處理我們的匯入,需要說明的是:
- keras 用於預處理用於分類的輸入幀,以及用於從磁碟中載入訓練好的模型。
- gpiozero 用於訪問 3D 聖誕樹。
- imutils 用於訪問影片流(不管是樹莓派相機模組還是 USB)。
- threading 用於非阻塞(non-blocking)操作,尤其是當我們需要在點亮聖誕樹或播放音樂的同時不阻塞主執行緒的執行時。
為此,我們要定義一個用於點亮 3D 聖誕樹的函式:
我們的 light_tree 函式接受一個 tree 引數(這應該是一個 LEDBoard 物件)。
首先,我們在 tree 中迴圈所有的 LED 並隨機點亮每個 LED 以創造閃爍效果(第 17-19 行)。
我們讓燈保持亮一段時間(第 23 行),然後再次迴圈這些 LED,這一次是將它們關閉(第 26-28 行)。
3D 聖誕樹亮燈的效果如下:
圖 6:樹莓派控制的 3D 聖誕樹
我們的下一個函式會在檢測到聖誕老人時播放音樂:
在 play_christmas_music 函式中,我們做了一次對 aplay 命令的系統呼叫,這讓我們可以用命令列播放一個音樂檔案。
使用 os.system 呼叫需要花一點功夫,但透過純 Python 來播放音訊檔案(使用 Pygame 這樣的庫)對這個專案而言就有些大材小用了。
因此,讓我們硬編碼我們將用到的配置:
第 38 和 39 行硬編碼了我們訓練好的 Keras 模型與音訊檔案的路徑。
我們也初始化了用於檢測的引數,其中包括 TOTAL_CONSEC 和 TOTAL_THRESH。這兩個值分別表示包含聖誕老人的幀的數量以及我們播放音樂和開啟聖誕樹燈光的閾值。(第 43 和 44 行)
最後的初始化是 SANTA = False,這是一個布林值(第 47 行)。我們後面會在指令碼使用 SANTA 變數作為狀態標誌來輔助我們的邏輯。
接下來,我們載入我們之前訓練的 Keras 模型並初始化我們的聖誕樹:
Keras 讓我們可以將模型儲存下來以備後來使用。在 https://goo.gl/imxkrY 這個教程中,我們將 Not Santa 模型儲存到了磁碟,現在我們要將其載入到我們的樹莓派上。我們在第 51 行使用 Keras 的 load_model 函式載入了該模型。
我們的 tree 物件在第 54 行進行了例項化。可以看到,tree 是來自 gpiozero 包的 LEDBoard 物件。
現在我們初始化我們的影片流:
為了訪問相機,我們要使用來自 imutils 包的 VideoStream(第 58 或 59 行),參閱文件:https://goo.gl/NEZrGK
重要說明:如果你用的是 PiCamera 模組(而不是 USB 攝像頭),那就直接註釋掉第 58 行並去掉第 59 行的註釋。
我們 sleep 了 2 秒鐘,這樣我們可以在開始迴圈幀之間預熱我們的相機(第 60 行):
在第 63 行,我們開始迴圈影片幀,直到滿足停止條件(在指令碼後面給出)。
首先,我們透過呼叫 vs.read 抓取幀 frame(第 66 行)。
然後我們將 frame 的大小調整為 width=400,並保持原來的縱橫比(第 67 行)。我們會在預處理 frame 之後才將其傳送給我們的神經網路模型。之後我們會將該幀與一個文字標籤一起展示在螢幕上。
因此,讓我們預處理影像並將其傳遞給我們的 Keras 深度學習模型進行預測:
第 70-73 行是對 image 進行預處理,準備用於分類。更多有關深度學習預處理的資訊可參考我最新的書《Deep Learning for Computer Vision with Python》:https://goo.gl/jTYng4
然後,我們使用 image 作為引數來查詢 model.predict。這會將 image 傳送給神經網路,然後返回一個包含類機率的元組(第 77 行)。
我們將 label 初始化為 "Not Santa"(後面我們還會訪問 label),並將其機率 proba 初始化為 notSanta 的值(第 78 和 79 行)。
讓我們看看影像中是否有聖誕老人:
第 83 行是檢查 santa 的機率是否大於 notSanta。如果確實大於,我們繼續並更新 label 和 proba,之後 TOTAL_CONSEC 遞增(第 85-90 行)。
當有足夠多連續的有聖誕老人的幀透過之後,我們需要觸發聖誕老人警報:
如果 SANTA 是 False 且如果 TOTAL_CONSEC 達到了 TOTAL_CONSEC,會執行兩個動作:
1. 建立並啟動一個 treeThread 來閃爍聖誕樹的燈(第 98-100 行);
2. 建立並啟動一個 musicThread 來播放背景音樂(第 103-106 行)。
這些執行緒會獨立執行,而不會阻止該指令碼的前向執行(即:非阻塞操作)。
你也可以看到我們在第 95 行將我們的 SANTA 狀態標誌設定成了 True,表明我們在該輸入幀中找到了聖誕老人。在該迴圈的下一次透過中,我們將檢查這個值,如第 93 行所示。
否則(SANTA 是 True 或還未達到 TOTAL_THRESH),那麼我們就將 TOTAL_CONSEC 重置為零,將 SANTA 重置為 False:
最後,我們將帶有生成的文字標籤的幀展示在我們的螢幕上:
機率值也附加到了帶有「Santa」或「Not Santa」的 label 上(第 115 行)。
然後我們可以使用 OpenCV 的 cv2.putText 在幀上面寫上標籤(用聖誕主題的綠色),然後我們將該幀展示在螢幕上(第 116-120 行)。
我們的無限 while 迴圈的退出條件是按下鍵盤上的「q」鍵(第 121-125 行)。
如果該迴圈的退出條件得到滿足,我們就 break,並且在指令碼本身退出之間執行一些清理(第 129-130 行)。
這就是所有全部了。你應該整體回顧一下這 130 行程式碼——這個框架/模板也可以輕鬆用於樹莓派上的其它深度學習專案。
現在就讓我們找到那個胖乎乎、大鬍子的歡樂聖誕老人吧!
深度學習+Keras+樹莓派得到的結果
在之前開發 Not Santa 深度學習模型時,我們使用了從網上收集到的影像。
但那很沒意思——也不符合我們這篇文章的追求。
我一直都想打扮成聖誕老人的樣子,所以我上週訂購了一套便宜的聖誕老人套裝:
圖 7:我 Adrian Rosebrock 的聖誕老人扮相。我將親自上陣測試我們用深度學習、Keras、Python 和 OpenCV 創造的 Not Santa 檢測器。我的長相與真正的聖誕老人差距很大,但這個道具服應該就夠了。
然後我將樹莓派上連線的相機安裝到了我公寓裡的聖誕樹上:
圖 8:我自己的聖誕樹將作為我們的樹莓派 Not Santa 檢測器深度學習模型的測試背景。
如果聖誕老人來到這顆聖誕樹下給好孩子送禮物,我們要透過閃爍 3D 聖誕樹燈和播放聖誕曲子來歡迎他。
然後我使用以下命令啟動了 Not Santa 深度學習+Keras 檢測器:
$ python not_santa_detector.py
如果你想按照這個教程走,你可以在原文最後的下載環節下載原始碼、預訓練模型和音訊檔案。
Not Santa 啟動並執行之後,我開始行動了:
圖 9:使用深度學習、Python、Keras 和樹莓派成功檢測到影片流中的聖誕老人
當檢測到聖誕老人時,3D 聖誕樹燈點亮,音樂開始播放。
這是是帶聲音的演示影片地址::https://www.youtube.com/watch?v=RdK-8pSQIP0
每當聖誕老人進入視野時,你都可以看到 3D 聖誕樹燈開啟,同時伴隨著樹莓派揚聲器發出的歡樂笑聲。
我們的這個深度學習模型是一個很小的網路架構,但準確度和穩健性方面的表現很讓人驚喜。
我這一年來一直都乖乖的,所以我相信聖誕老人會到我的公寓來。
我也比以往更相信我的 Not Santa 檢測器會看到聖誕老人送禮物給我。
在聖誕節之前,我可能還會修改一下這個指令碼(呼叫一下 cv2.imwrite 或更好是儲存影片),以確保我將聖誕老人的影像儲存到磁碟上留作證據。要是有其他人在我的聖誕樹下放了禮物,我一定會知道的。
親愛的聖誕老人:要是你讀到了這篇文章,你就知道我用樹莓派逮到你了!
總結
在這篇文章中,你學習到了如何在樹莓派上執行 Keras 深度學習模型。
要實現這一目標,我們首先在膝上型電腦或桌面計算機上訓練了一個可以檢測影像中是否包含「Santa」或「Not Santa」的 Keras 深度學習模型。
然後我們將 TensorFlow 和 Keras 安裝到了我們的樹莓派上,這讓我們可以將我們之前訓練的深度學習影像分類器部署到這個樹莓派上。儘管樹莓派並不適合訓練深度神經網路,但可以用於部署這些網路——只要網路架構足夠簡單,我們甚至可以實時執行我們的模型。
為了演示這一點,我們在樹莓派上建立了一個 Not Santa 檢測器,可以分類影片流中的每一個輸入幀。
如果檢測到了聖誕老人,我們就訪問 GPIO 引腳來點亮 3D 聖誕樹和播放節日樂曲。
原文連結:https://www.pyimagesearch.com/2017/12/18/keras-deep-learning-raspberry-pi/