上周末,量子位翻譯了一份MobileNet教程,其中講述了怎樣在一個新的數據集上重新訓練MobileNet,那篇文章的成果,是一個分類器,能在電腦上以每秒鐘400張的速度,識別圖片是否為道路。
MobileNet是為移動端量身打造的,因此這次我們準備把之前做的辨別道路的模型應用到一個Android App中,看看它在行動裝置上效果如何。
目標和計劃首先,讓我們明確目標和計劃,我們希望做到:
為了達到這些目標,我們的計劃是:
生成一個新的訓練數據集;
訓練多個MobileNet結構,從而尋找所能夠達到準確率目標(95%)的最小型網絡;
與在Android上運行的Inception V3做對比;
將TensorFlow上Android example App中的模型替換為我們的MobileNet;
大量的測試;
進行調試,從而將CPU的佔用調到5%以下。
建立數據集在前一篇推送中,我們為了辨認「道路/非道路」,從多個來源拉取了圖片作為訓練素材。
現在我們再來思考一下這樣做是否有必要。
如果你記得的話,這個項目的目標是為了保護用戶隱私,當車上的攝像頭打開的時候,如果它看見的不是道路,就應該自動關掉。
所以,為了建立我們的訓練數據集,我需要錄製一些(跟駕駛相關)日常生活中的場景:比說我家的周圍、我車子的外部,我在車上擺弄收音機、逗貓等等。這些會被當做非道路的數據用來訓練模型。
而訓練數據的「道路」部分,是從Coastline driving dataset中隨機取出的,這些圖片都是由車的前置攝像頭拍攝的。
為道路和非道路數據集各收集3000張圖片後,下一步就是開始訓練了。
用特定數據集訓練MobileNet下一步,是看看不同結構的MobileNet在經過訓練後能達到什麼樣的準確度。
我們先從最「寬」的MobileNet開始訓練:MobileNet 1.0 @ 128。 因為我們想把這個模型應用到行動裝置上,因此我們將會採用權值量化,從而進一步減少內存佔用。
關於重新訓練MobileNet的操作細節,可以看我的前一篇推送。
在TensorFlow的根目錄下,運行以下腳本:
python tensorflow/examples/image_retraining/retrain.py \ --image_dir ~/ml/blogs/road-not-road/data/ \ --learning_rate=0.0005 \ --testing_percentage=15 \ --validation_percentage=15 \ --train_batch_size=32 \ --validation_batch_size=-1 \ --flip_left_right True \ --random_scale=30 \ --random_brightness=30 \ --eval_step_interval=100 \ --how_many_training_steps=1000 \ --architecture mobilenet_1.0_128_quantized
在經歷1000步的訓練後,我們在測試集上達到了99.7%的準確率。
以下是模型做出了錯誤判斷的一些圖片:
接下來讓我們在最小的MobileNet上(0.25@128)訓練,同樣採用權值量化。在1000步訓練後,我們達到了92.6%的正確率,沒有達到我們的目標。
那麼讓它稍微變寬些呢,比如說0.5@128?
準確率達到了95%,最終的模型大小為1.6MB。值得一提的是我們訓練模型只用了10分鐘10fps的視頻,所以在訓練數據的收集上還有很大的提升空間。
接下來我們很快試一下看看模型是否能夠如預計般工作:
python tensorflow/examples/label_image/label_image.py \ --graph=/tmp/output_graph.pb \ --labels=/tmp/output_labels.txt \ --image=/home/harvitronix/ml/blogs/road-not-road/test-image.jpg \ --input_layer=input \ --output_layer=final_result \ --input_mean=128 \ --input_std=128 \ --input_width=128 \ --input_height=128
這個系統速度很快,在我們搭載NVIDIA GeForce 960m GPU的筆記本上,識別1,000張圖片只需要3.36秒,即每秒鐘能識別297.6張圖片。
把MobileNet應用到Android App中現在我們擁有了一個小巧、快速、足夠精確的模型,接下來我們準備把它搭載到一個Android App上,從而在真實環境中進行測試。
繼續使用TensorFlow提供的工具,我們馬上就會使用裡面的Android示例項目完成模型的搭載。
1. 建立項目如果你還沒有準備好,可以從TensorFlow的repository下載這個Android示例項目:
git clone https://github.com/tensorflow/tensorflow.git --depth 1
具體的文件夾是tensorflow/examples/android。用Android Studio打開這個文件夾,編譯,然後把生成的APK安裝包搭載到你的手機上,你就得到了一個搭載著在ImageNet數據集上訓練出的Inception V3模型的圖像分類器App,它能夠準確地把貓咪跟鴨嘴獸區分開來。
如果你編譯apk安裝包過程有問題,可以參考他們的readme文檔中的指示。(https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android)
我遇到的最大的挑戰是NDK(Native Developer Kit)的版本問題,降級到r12b版本後才能正常的編譯。
2. 評測搭載了Inception的App我們現在運行的app上搭載的是Inception模型,讓我們它做一些測評,從而可以與之後的MobileNet模型比較。
搭載了Inception的這個app的大小是53.9Mb,而搭載MobileNet的只有1.6Mb。它能夠以240ms的速度識別一張圖片(即4fps),CPU的佔用達到了40%。
讓我們把運行速度調到1fps試試:
現在,內存的佔用仍然在35%以上,讓我們盼著MobileNet能夠比這表現得好些,否則我們就達不到之前定下的目標了(內存佔用上限為5%)。
3. 換成MobileNet接下裡讓我們對這個Android project做一些小修改,從而搭載上我們的MobileNet。
首先,把你的模型和標籤文件複製到project的assets文件夾裡。我的是分別是/tmp/output_graph.pb 和 /tmp/output_labels.txt。
接下來,打開ClassifierActivity,具體地址是在:
tensorflow/examples/android/src/org/tensorflow/demo/ClassifierActivity.java
將這個文件中的開頭部分中定義的參數設置為我們的新模型。即從一打開時的這樣:
private static final int INPUT_SIZE = 224;private static final int IMAGE_MEAN = 117;private static final float IMAGE_STD = 1;private static final String INPUT_NAME = "input";private static final String OUTPUT_NAME = "output";private static final String MODEL_FILE = "file:///android_asset/tensorflow_inception_graph.pb";private static final String LABEL_FILE = "file:///android_asset/imagenet_comp_graph_label_strings.txt";
改為這樣:
private static final int INPUT_SIZE = 128;private static final int IMAGE_MEAN = 128;private static final float IMAGE_STD = 128;private static final String INPUT_NAME = "input";private static final String OUTPUT_NAME = "final_result";private static final String MODEL_FILE = "file:///android_asset/output_graph.pb";private static final String LABEL_FILE = "file:///android_asset/output_labels.txt";
點擊運行從而開始編譯,然後在你的手機上運行相應的apk安裝包,你就得到了自己的道路識別器。
結果下面是我實際使用我這個app的視頻,我對UI進行了一些小改動,從而使顯示結果更直觀。
那麼它運行速度和CPU佔用的情況怎樣呢?
在我的小米5上,它識別一張圖片需要55毫秒,也就是每秒18幀(18fps)。
不過,在這個識別速度下,CPU的佔用也比較大。在加足馬力運行的情況下,CPU的佔用大概為25到30%。
如果我們希望這個數字能到5%,那麼我們可以降低app的運行速度,因為在我們的使用場景中並不需要連續地進行圖像識別。將識別速度調整到每秒1張,CPU的佔用的平均值就下降到了5.5%。
△ 搭載MobileNet的App在1fps速度下運行時的內存佔用和CPU佔用情況總結一下,我們的MobileNet的模型只有Inception的1/30,而運行起來識別圖片的速度大概是後者的三倍,同時使用了佔用的CPU空間也更少。
相關連結教程原文:
https://hackernoon.com/building-an-insanely-fast-image-classifier-on-android-with-mobilenets-in-tensorflow-dc3e0c4410d4
下載作者訓練好的模型:
https://s3-us-west-1.amazonaws.com/coastline-automation/demo/mobilenet-road-not-road.tar.gz
這裡面包括一個.pb模型文件和一個存儲標籤(「road」,「not road」)的.txt文件。
8月9日(周三)晚,量子位邀請三角獸首席科學家王寶勳,分享基於對抗學習的生成式對話模型,歡迎掃碼報名 ▼
量子位AI社群6群即將滿員,歡迎對AI感興趣的同學加入,加群請添加微信號qbitbot2;
此外,量子位的專業細分群(自動駕駛、CV、NLP、機器學習等)正在招募,面向正在從事相關領域的工程師及研究人員。
進群請添加微信號qbitbot2,並務必備註相應群的關鍵詞~通過審核後我們將邀請進群。(專業群審核較嚴,敬請諒解)
量子位正在招募編輯/記者,工作地點在北京中關村。期待有才氣、有熱情的同學加入我們!相關細節,請在量子位公眾號(QbitAI)對話界面,回復「招聘」兩個字。