[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

Starrier發表於2018-06-09

真實世界帶來的挑戰,是有限的資料以及小型硬體,諸如手機和樹莓派等,這些硬體無法執行復雜的深度學習模型。這篇文章演示瞭如何使用樹莓派進行物件檢測,就像公路上的汽車,冰箱裡的橘子,檔案上的簽名,太空中的特斯拉。

免責宣告:我正在用更少的資料和無硬體的方式構建 nanonets.com 來幫助建立機器學習。

如果你沒有耐心繼續閱讀下去,可以直接翻閱到底部檢視 Github 的倉庫。

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

檢測孟買路上的車輛。

為什麼要檢測物件?為什麼使用樹莓派?

樹莓派是一款優秀的硬體,它已經捕獲了與售賣 1500 萬臺裝置同時代的人的心,甚至於黑客用其構建了更酷的專案。鑑於深度學習和樹莓派相機的流行,我們認為如果能夠通過樹莓派進行深度學習來檢測任何物件,會是一件非常有意義的事情。

現在你將能夠在你的自拍中發現一個 potobomber,有人進入 Harambe 的籠子,在那裡有人讓 Sriracha 或 Amazon 送貨員進入你的房子。

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

什麼是物件檢測?

20M 年的進化使人類的視覺得到了相當大的進化。人類大腦有 30% 的神經元負責處理視覺(相比之下,觸覺和聽覺分別為 8% 和 3%)。與機器相比,人類有兩大優勢。一是立體視覺,二是近乎無限的訓練資料(一個 5 歲的嬰兒,以 30fps 的速度獲取大約 2.7B 的影象)。

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

為了模仿人類層次的表現水平,科學家將視覺感知任務分解為四個不同的類別。

  1. 分類,為整個影象指定一個標籤
  2. Localization,為特定標籤指定一個邊框
  3. 物件檢測,在影象中繪製多個邊界框
  4. 影象分割,建立影象中物體所在位置的精確部分

對於各種應用來說,物件檢測已經足夠好了(即使影象分割結果更為精確,但它受到建立訓練資料的複雜性影響。對於一個人類標註者來說,分割影象所花的時間比繪製邊界框要多 12 倍;這是更多的軼事,但缺乏一個來源)。而且在檢測物件之後,可以單獨從邊界框中分割物件。

使用物件檢測:

物件檢測具有重要的現實意義,已經在各行業中被廣泛使用。以下是相關示例:

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

我如何使用物件檢測來解決我自己的問題?

物件檢測可用來回答各種問題。這是粗略的分類:

  1. 在我的影象中是否存在物件?例如,我家有入侵者麼。
  2. 物件在哪裡,在影象中?例如,當一輛汽車試圖在世界各地行駛時,知道物體在哪裡是很重要的。
  3. 有多少個物件,它們都在影象中麼? 物件檢測是計算物體的最有效的方法之一。例如,一個倉庫裡的架子上有多少箱子。
  4. 什麼是不同型別的物件在影象中?比如哪個動物在動物園的哪個地方?
  5. 物件的大小是多少? 尤其是使用靜態相機時,很容易計算出物體的大小。比如芒果的大小是多少?
  6. **不同物件如何相互作用?**足球場上的陣型如何影響結果?
  7. 與時間有關的物件在何處(追蹤物件)比如追蹤像火車這樣的移動物體,並計算它的速度等。

20 行以下程式碼中的物件檢測

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

YOLO 演算法視覺化。

有多種用於物件檢測的模型/體系結構。在速度、尺寸和精度之間進行權衡。我們選了一個最受歡迎的:YOLO(您只看了一次)。並在 20 行以下的程式碼中展示了它的工作原理(如果忽略註釋的 haunted)。

注意:這是虛擬碼,不會成為一個有用的例子。它有一個接近 CNN 標準的部分黑盒,如下所示

你可以在這裡閱讀全文:pjreddie.com/media/files…

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

YOLO 中的卷積神經網路結構。

#this is an Image of size 140x140. We will assume it to be black and white (ie only one channel, it would have been 140x140x3 for rgb)
image = readImage()

#We will break the Image into 7 coloumns and 7 rows and process each of the 49 different parts independently
NoOfCells = 7

#we will try and predict if an image is a dog, cat, cow or wolf. Therfore the number of classes is 4
NoOfClasses = 4
threshold = 0.7

#step will be the size of step to take when moving across the image. Since the image has 7 cells step will be 140/7 = 20
step = height(image)/NoOfCells

#stores the class for each of the 49 cells, each cell will have 4 values which correspond to the probability of a cell being 1 of the 4 classes
#prediction_class_array[i,j] is a vector of size 4 which would look like [0.5 #cat, 0.3 #dog, 0.1 #wolf, 0.2 #cow]
prediction_class_array = new_array(size(NoOfCells,NoOfCells,NoOfClasses))

#stores 2 bounding box suggestions for each of the 49 cells, each cell will have 2 bounding boxes, with each bounding box having x, y, w ,h and c predictions. (x,y) are the coordinates of the center of the box, (w,h) are it's height and width and c is it's confidence
predictions_bounding_box_array = new_array(size(NoOfCells,NoOfCells,NoOfCells,NoOfCells))

#it's a blank array in which we will add the final list of predictions
final_predictions = []

#minimum confidence level we require to make a prediction
threshold = 0.7

for (i<0; i<NoOfCells; i=i+1):
	for (j<0; j<NoOfCells;j=j+1):
		#we will get each "cell" of size 20x20, 140(image height)/7(no of rows)=20 (step) (size of each cell)"
		#each cell will be of size (step, step)
		cell = image(i:i+step,j:j+step) 

		#we will first make a prediction on each cell as to what is the probability of it being one of cat, dog, cow, wolf
		#prediction_class_array[i,j] is a vector of size 4 which would look like [0.5 #cat, 0.3 #dog, 0.1 #wolf, 0.2 #cow]
		#sum(prediction_class_array[i,j]) = 1
		#this gives us our preidction as to what each of the different 49 cells are
		#class predictor is a neural network that has 9 convolutional layers that make a final prediction
		prediction_class_array[i,j] = class_predictor(cell)

		#predictions_bounding_box_array is an array of 2 bounding boxes made for each cell
		#size(predictions_bounding_box_array[i,j]) is [2,5]
		#predictions_bounding_box_array[i,j,1] is bounding box1, predictions_bounding_box_array[i,j,2] is bounding box 2
		#predictions_bounding_box_array[i,j,1] has 5 values for the bounding box [x,y,w,h,c]
		#the values are x, y (coordinates of the center of the bounding box) which are whithin the bounding box (values ranging between 0-20 in your case)
		#the values are h, w (height and width of the bounding box) they extend outside the cell and are in the range of [0-140]
		#the value is c a confidence of overlap with an acutal bounding box that should be predicted
		predictions_bounding_box_array[i,j] = bounding_box_predictor(cell)

		#predictions_bounding_box_array[i,j,0, 4] is the confidence value for the first bounding box prediction
		best_bounding_box =  [0 if predictions_bounding_box_array[i,j,0, 4] > predictions_bounding_box_array[i,j,1, 4] else 1]

		# we will get the class which has the highest probability, for [0.5 #cat, 0.3 #dog, 0.1 #wolf, 0.2 #cow], 0.5 is the highest probability corresponding to cat which is at position 0. So index_of_max_value will return 0
		predicted_class = index_of_max_value(prediction_class_array[i,j])

		#we will check if the prediction is above a certain threshold (could be something like 0.7)
		if predictions_bounding_box_array[i,j,best_bounding_box, 4] * max_value(prediction_class_array[i,j]) > threshold:

			#the prediction is an array which has the x,y coordinate of the box, the height and the width
			prediction = [predictions_bounding_box_array[i,j,best_bounding_box, 0:4], predicted_class]

			final_predictions.append(prediction)


print final_predictions
複製程式碼

YOLO 在 <20 行程式碼中的解釋。

我們如何構建用於物件檢測的深度學習模型?

深度學習工作流的 6 個主要步驟將分成 3 個階段

  1. 收集訓練資料
  2. 訓練模型
  3. 預測新影象

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件


階段 1 —— 收集訓練資料

第 1 步 收集影象(每個物件至少有 100 張影象):

在這個任務中,每個物件需要幾百張影象。嘗試將資料捕獲到您最終要對其進行預測的資料上。

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

第 2 步 註解(手動繪製這些影象):

在影象上繪製邊界框。您可以使用像 labelImg 這樣的工具。您需要一些人來註釋您的影象。這是一個相當密集且耗時的任務。

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件


階段 2 — 在 GPU 機器上訓練模型

第 3 步 尋找可以遷移學習的預訓練模型

您可以在 medium.com/nanonets/na… 中閱讀到更多有關這方面的資訊。您需要一個預訓練模型,這樣您就可以減少訓練所需的資料量。沒有它,您可能需要幾十萬張的影象來訓練模型。

你可以在這裡找到一些預訓練的模型

第 4 步驟, 在 GPU 上訓練(像 AWS/GCP 等雲服務或您自己的 GPU 機器):

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

Docker 映象

訓練模型的過程不是必要的,但建立 docker 映象使得訓練變得更加簡單的過程很難簡化。

你可以通過執行如下內容來開始訓練模型:

sudo nvidia-docker run -p 8000:8000 -v `pwd`:data docker.nanonets.com/pi_training -m train -a ssd_mobilenet_v1_coco -e ssd_mobilenet_v1_coco_0 -p '{"batch_size":8,"learning_rate":0.003}' 
複製程式碼

有關如何使用的詳細資訊,請參閱此連結

docker 映象擁有一個可以用以下引數呼叫的 run.sh 指令碼

run.sh [-m mode] [-a architecture] [-h help] [-e experiment_id] [-c checkpoint] [-p hyperparameters]

-h          display this help and exit
-m          mode: should be either `train` or `export`
-p          key value pairs of hyperparameters as json string
-e          experiment id. Used as path inside data folder to run current experiment
-c          applicable when mode is export, used to specify checkpoint to use for export
複製程式碼

您可以在以下找到更多細節:

為了訓練模型,您需要選擇正確的超引數。

找到正確的引數

“深度學習”的藝術含有一點點諷刺,但它會嘗試找出哪些會為您的模型獲得最高精度的最佳引數。與此相關的是某些程度的黑魔法以及一點理論。這是找到正確引數的好資源

量化模型(使其更小以適應像樹莓派或手機這樣的小型裝置)

諸如手機和樹莓派這樣的小型裝置,記憶體和計算能力都很小。

訓練神經網路是通過對權重施加許多微小推進完成的,而這些微小的增量通常需要浮點精度才能工作(儘管這裡也有研究努力使用量化表示)。

採用預先訓練模型並執行推理是非常不同的。深度神經網路的神奇特性之一是,它們往往能很好地處理輸入中的高噪聲。

為什麼要量化?

例如,神經網路模型會佔用大量磁碟空間,起初 AlexNet 是 200 MB 以上的浮點格式。因為在單個模型中經常有數百萬個神經連線,因此幾乎所有大小都被神經連線的權重所決定。

神經網路的節點和權重起初被儲存為 32-bit 浮點數,最簡單的量化動機是通過儲存每個層的最小和最大值來縮小檔案大小,然後將每個浮點值壓縮為一個 8 位整數,檔案大小因此減小了 75%。

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

量化程式碼:

curl -L "https://storage.googleapis.com/download.tensorflow.org/models/inception_v3_2016_08_28_frozen.pb.tar.gz" |
  tar -C tensorflow/examples/label_image/data -xz
bazel build tensorflow/tools/graph_transforms:transform_graph
bazel-bin/tensorflow/tools/graph_transforms/transform_graph \
--in_graph=tensorflow/examples/label_image/data/inception_v3_2016_08_28_frozen.pb \
  --out_graph=/tmp/quantized_graph.pb \
  --inputs=input \
  --outputs=InceptionV3/Predictions/Reshape_1 \
  --transforms='add_default_attributes strip_unused_nodes(type=float, shape="1,299,299,3")
    remove_nodes(op=Identity, op=CheckNumerics) fold_constants(ignore_errors=true)
    fold_batch_norms fold_old_batch_norms quantize_weights quantize_nodes
    strip_unused_nodes sort_by_execution_order
複製程式碼

第 3 階段:使用樹莓派預測新影象

第 5 步,通過相機捕捉新影象

你需要樹莓派生活和工作。然後捕獲一個新影象

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

安裝說明參見此連結

import picamera, os
from PIL import Image, ImageDraw
camera = picamera.PiCamera()
camera.capture('image1.jpg')
os.system("xdg-open image1.jpg")
複製程式碼

捕獲新影象的程式碼。

第 6 步,預測新影象

下載模型

一旦你完成了模型的訓練,你就可以把它下載到你的樹莓派上了。要匯出模型執行:

sudo nvidia-docker run -v `pwd`:data docker.nanonets.com/pi_training -m export -a ssd_mobilenet_v1_coco -e ssd_mobilenet_v1_coco_0 -c /data/0/model.ckpt-8998
複製程式碼

然後將模型下載到樹莓派上。

在樹莓派上下載 Tensorflow

根據裝置的不同,您可能需要稍微更改安裝

sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools libjpeg-dev

sudo pip install Pillow

sudo pip install http://ci.tensorflow.org/view/Nightly/job/nightly-pi-zero/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl

git clone [https://github.com/tensorflow/models.git](https://github.com/tensorflow/models.git)

sudo apt-get install -y protobuf-compiler

cd models/research/protoc object_detection/protos/*.proto --python_out=.

export PYTHONPATH=$PYTHONPATH:/home/pi/models/research:/home/pi/models/research/slim
複製程式碼

執行模型以預測新影象

python ObjectDetectionPredict.py --model data/0/quantized_graph.pb --labels data/label_map.pbtxt --images /data/image1.jpg /data/image2.jpg
複製程式碼

樹莓派的效能基準測試

樹莓派對記憶體和計算都有限制(與樹莓派 GPU 相容的 Tensorflow 版本仍然不可用)。因此,對基準測試來說,每個模型需要多少時間才能對新影象進行預測非常重要。

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

在樹莓派中執行不同物件檢測的基準測試。


[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

我們在 NanoNets 的目標是使深度學習工作更加簡單。物件檢測是我們關注的一個主要領域,我們已經制定了一個工作流來解決實現深度學習模型的許多挑戰。

NanoNets 如何使過程更簡單:

1. 無需註解

我們已經刪除了註釋影象的需求,我們有專業的註釋人員為為您的影象註釋

2. 自動優化模型與超引數的選擇

我們為您自動化訓練最好的模型。為了實現這個,我們執行一組具有不同引數的模型,來為您的資料選擇最佳模型。

3. 不需要昂貴的硬體和 GPU

NanoNets 完全在雲端執行而且無需任何硬體。這使得它更容易使用。

4. 適合像樹莓派這樣的移動裝置

因為像樹莓派和手機這樣的裝置並不是為了執行復雜的計算任務而構建的,所以您可以把工作量外包給我們的雲,它會為您完成所有的計算

這裡是使用 NanoNets API 對影象進行預測的簡單片段

import picamera, json, requests, os, random
from time import sleep
from PIL import Image, ImageDraw

#capture an image
camera = picamera.PiCamera()
camera.capture('image1.jpg')
print('caputred image')

#make a prediction on the image
url = 'https://app.nanonets.com/api/v2/ObjectDetection/LabelFile/'
data = {'file': open('image1.jpg', 'rb'), \
    'modelId': ('', 'YOUR_MODEL_ID')}
response = requests.post(url, auth=requests.auth.HTTPBasicAuth('YOUR_API_KEY', ''), files=data)
print(response.text)

#draw boxes on the image
response = json.loads(response.text)
im = Image.open("image1.jpg")
draw = ImageDraw.Draw(im, mode="RGBA")
prediction = response["result"][0]["prediction"]
for i in prediction:
    draw.rectangle((i["xmin"],i["ymin"], i["xmax"],i["ymax"]), fill=(random.randint(1, 255),random.randint(1, 255),random.randint(1, 255),127))
im.save("image2.jpg")
os.system("xdg-open image2.jpg")
複製程式碼

使用 NanoNets 對新影象進行預測的程式碼

構建您自己的 NanoNet

[譯] 如何輕鬆地在樹莓派上使用深度學習檢測物件

您可以嘗試從以下幾點來構建屬於自己的模型:

1. 使用 GUI(也可以自動註釋影象):nanonets.com/objectdetec…

2. 使用我們的 API:github.com/NanoNets/ob…

第 1 步:克隆倉庫

git clone [https://github.com/NanoNets/object-detection-sample-python.git](https://github.com/NanoNets/object-detection-sample-python.git)
cd object-detection-sample-python
sudo pip install requests
複製程式碼

第 2 步:獲取您的免費 API 的金鑰

app.nanonets.com/user/api_ke… 中獲取您的免費 API 金鑰

第 3 步:將 API 金鑰設定為環境變數

export NANONETS_API_KEY=YOUR_API_KEY_GOES_HERE
複製程式碼

第 4 步:建立新模型

python ./code/create-model.py
複製程式碼

注意:這將生成下一步所需的模型 ID

第 5 步:新增模型 ID 作為環境變數

export NANONETS_MODEL_ID=YOUR_MODEL_ID
複製程式碼

第 6 步:上傳訓練資料

收集您想要檢測物件的影象。您可以使用我們的 web UI(https://app.nanonets.com/ObjectAnnotation/?appId=YOUR_MODEL_ID) 對其進行註釋,或者使用像 labelImg 這樣的開源工具。一旦在資料夾中準備好資料集,images(影象檔案)和 annotations(影象檔案註解),就可以開始上傳資料集了。

python ./code/upload-training.py
複製程式碼

第 7 步:訓練模型

一旦影象上傳完畢,就開始訓練模型

python ./code/train-model.py
複製程式碼

第 8 步:獲取模型狀態

模型訓練需要 2 個小時。一旦模型被訓練,您將收到一封電子郵件。同時檢查模型的狀態

watch -n 100 python ./code/model-state.py
複製程式碼

第 9 步:預測

一旦模型訓練好了,您就可以使用來進行預測

python ./code/prediction.py PATH_TO_YOUR_IMAGE.jpg
複製程式碼

程式碼(GitHub 倉庫)

訓練模型的 Github 倉庫:

  1. 用於模型訓練和量化的 Tensorflow 程式碼
  2. NanoNets 模型訓練程式碼

為樹莓派做出預測的 GitHub 倉庫(即檢測新物件):

  1. 在樹莓派上用於預測的 Tensorflow 程式碼
  2. 在樹莓派上用於預測的 NanoNets 程式碼

帶有註釋的資料集:

  1. 印度公路可見的車輛,從印度道路影象中提取車輛的資料集
  2. Coco 資料集

掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章