深度學習應用系列(四)| 使用 TFLite Android構建自己的圖像識別App


        深度學習要想落地實踐,一個少不了的路徑即是朝着智能終端、嵌入式設備等方向發展。但終端設備沒有GPU服務器那樣的強大性能,那如何使得終端設備應用上深度學習呢?

所幸谷歌已經推出了TFMobile,去年又更進一步,推出了TFLite,其應用思路為在GPU服務器上利用遷移學習訓練自己的模型,然后將定制化模型移植到TFLite上,

終端設備僅利用模型做前向推理,預測結果。本文基於以下三篇文章而成:

      相信大家掌握后,也能輕松定制化自己的圖像識別應用。

第一步. 准備數據

  數據下載地址為:http://download.tensorflow.org/example_images/flower_photos.tgz  

  這是一個關於花分類的圖片集合,下載解壓后,可以看出有5個品種分類:daisy(雛菊)、dandelion(蒲公英)、rose(玫瑰)、sunflower(向日葵)、tulip(郁金香)。

  我們的目的即是通過重新訓練預編譯模型,得到一個花類識別的模型。

第二步. 重新訓練

  1. 挑選預編譯模型

        從上述“谷歌提供的預編譯模型”列表中,我們大體可以看出分為兩類模型,一種是Float Models(浮點數模型),一種是Quantized Models(量化模型),什么區別呢?

  其實Float Models表示為一種高精度值的模型,該模型意味着模型size較大,識別精度更高、識別時長更長,適合高性能終端設備;而Quantized Models則反之,是低精度值的模型,其精度采取固定的8位大小,故其模型size較小,識別精度低、識別時長較短,適合低性能終端設備,更細的說明可以參見 https://www.tensorflow.org/performance/quantization  。

  我們的手機設備更新換代很快,一般可以使用Float Models。在這個模型下,有不少預編譯模型可選,對於本文來說,主要集中為Inception 和Mobilenet兩種架構。  

       注意Mobilenet其實也分為很多種類,如Mobilenet_V1_0.50_224,其中第三個參數為模型大小比例值(只能算是近似,不准確),分為0.25/0.50/0.75/1.0四個比例值,第四個參數為圖片大小,其值有128/160/192/224四種值。

  有興趣想觀察各模型層次結構的可通過以下代碼查看:  

import tensorflow as tf
import tensorflow.gfile as gfile

MODEL_PATH = '/home/yourname/Documents/mobilenet_v1_1.0_224/frozen_graph.pb'

def main(unusedArgv):
    with tf.Graph().as_default() as graph:
        with gfile.FastGFile(MODEL_PATH, 'rb') as f:
            graph_def = tf.GraphDef()
            graph_def.ParseFromString(f.read())
            tf.import_graph_def(graph_def, name='')
    for op in graph.get_operations():
        for tensor in op.values():
            print(tensor)

if __name__ == '__main__':
    tf.app.run()

  考慮到測試手機性能還不賴,我們選擇mobilenet_v1_1.0_224這個版本作為我們的預編譯模型。

  2. 下載訓練代碼

  需要下載訓練模型代碼和android相關代碼,如下:

git clone https://github.com/googlecodelabs/tensorflow-for-poets-2

cd tensorflow-for-poets-2

  其中,scripts目錄下的retrain.py是我們需要關注的,這個代碼目前僅支持Inception_v3和Mobilenet兩種預編譯模型,默認的訓練模型為Inception_v3。

  3. 重新訓練模型

  兩種模型的訓練命令不同,若走默認的Inception_v3模型,可通過如下命令: 

python -m scripts.retrain \
--learning_rate=0.01 \
--bottleneck_dir=tf_files/bottlenecks \ --how_many_training_steps=4000 \ --model_dir=tf_files/models/ \ --output_graph=tf_files/retrained_graph.pb \ --output_labels=tf_files/retrained_labels.txt \ --image_dir=tf_files/flower_photos \

  若走Mobilenet模型,可通過如下命令:

python -m scripts.retrain \
 --learning_rate=0.01 \  
--bottleneck_dir=tf_files/bottlenecks \ --how_many_training_steps=4000 \ --model_dir=tf_files/models/ \ --output_graph=tf_files/retrained_graph.pb \ --output_labels=tf_files/retrained_labels.txt \ --image_dir=tf_files/flower_photos \ --architecture=mobilenet_1.0_224

  模型命令解釋如下:

 --architecture 為架構類型,支持mobilenet和Inception_v3兩種
   --image_dir 為數據地址,假定你在tensorflow-for-poets-2目錄下建立了tflite目錄,把花圖片集放入其中
   --output_labels 最后訓練生成模型的標簽,由於花圖片集合已經按照子目錄進行了分類,故retrained_labels.txt最后包含了上述五種花的分類名稱
   --output_graph 最后訓練生成的模型
   --model_dir 命令啟動后,預編譯模型的下載地址
   --how_many_training_steps 訓練步數,不指定的話默認為4000
   --bottleneck_dir用來把top層的訓練數據緩存成文件
   --learning_rate 學習率
   此外,還有些參數可以根據需要進行調整:
   --testing_percentage 把圖片按多少比例划分出來當做test數據,默認為10
   --validation_percentage 把圖片按多少比例划分出來當做validation數據,默認為10,這兩個值設置完后,training數據占比80%
   --eval_step_interval 多少步訓練后進行一次評估,默認為10
   --train_batch_size 一次訓練的圖片數,默認為100
   --validation_batch_size 一次驗證的圖片數,默認為100
   --random_scale 給定一個比例值,然后隨機擴大訓練圖片的大小,默認為0
   --random_brightness 給定一個比例值,然后隨機增強或減弱訓練圖片的明亮程度,默認為0
   --random_crop 給定一個比例值,然后隨機裁剪訓練圖片的邊緣值,默認為0 

    4. 檢驗訓練效果

    我們用Mobilenet_1.0_224進行訓練,完成后找一張圖片看看是否能正確識別:

python -m scripts.label_image \
  --graph=tf_files/retrained_graph.pb  \
  --image=tf_files/flower_photos/daisy/3475870145_685a19116d.jpg

結果為:

Evaluation time (1-image): 1.010s

daisy (score=0.62305)
tulips (score=0.22490)
dandelion (score=0.14169)
roses (score=0.00966)
sunflowers (score=0.00071)

還是准確地識別了daisy出來。

    5. 轉換模型格式

      pb格式是不能運行在TFLite上的,TFLite吸收了谷歌的protobuffer優點,創造了FlatBuffer格式,具體表現就是后綴名為.tflite的文件。

     上述TOCO的官網已經介紹了如何通過命令行把pb格式轉成為tflite文件,或者在代碼里也可以轉換格式。不僅支持pb格式,也支持HDF5文件格式轉換成tflite,實現了與其他框架的模型共享。

     那如何轉呢?本例通過命令行方式轉換。若訓練模型為Inception_v3,命令行方式如下:

toco \
  --graph_def_file=tf_files/retrained_graph.pb \
  --output_file=tf_files/optimized_graph.lite \
  --input_format=TENSORFLOW_GRAPHDEF \
  --output_format=TFLITE \
  --input_shape=1,299,299,3 \
  --input_array=Mul \
  --output_array=final_result \
  --inference_type=FLOAT \
  --input_data_type=FLOAT

     若訓練模型為mobilenet,命令行方式則如下:

toco \
  --graph_def_file=tf_files/retrained_graph.pb \
  --output_file=tf_files/optimized_graph.lite \
  --input_format=TENSORFLOW_GRAPHDEF \
  --output_format=TFLITE \
  --input_shape=1,224,224,3 \
  --input_array=input \
  --output_array=final_result \
  --inference_type=FLOAT \
  --input_data_type=FLOAT

  需要說明幾點:

       --input_array 參數表示模型圖結構的入口tensor op名稱,mobilenet的入口名稱為input,Inception_v3的入口名稱為Mul,為什么這樣?可查看scripts/retrain.py代碼里內容:

  if architecture == 'inception_v3':
    # pylint: disable=line-too-long
    data_url = 'http://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz'
    # pylint: enable=line-too-long
    bottleneck_tensor_name = 'pool_3/_reshape:0'
    bottleneck_tensor_size = 2048
    input_width = 299
    input_height = 299
    input_depth = 3
    resized_input_tensor_name = 'Mul:0'
    model_file_name = 'classify_image_graph_def.pb'
    input_mean = 128
    input_std = 128
elif architecture.startswith('mobilenet_'):
... data_url
= 'http://download.tensorflow.org/models/mobilenet_v1_' data_url += version_string + '_' + size_string + '_frozen.tgz' bottleneck_tensor_name = 'MobilenetV1/Predictions/Reshape:0' bottleneck_tensor_size = 1001 input_width = int(size_string) input_height = int(size_string) input_depth = 3 resized_input_tensor_name = 'input:0'

  其中的resized_input_tensor_name即是新生成模型的入口名稱,大家也可以通過上面“1.挑選預編譯模型”的代碼可視化查看新生成的模型層次結構。所以名稱必須正確寫對,否則運行該命令會拋出“ValueError: Invalid tensors 'input' were found” 的異常。

       --output_array則是模型的出口名稱。為什么是final_result這個名稱,因為在scripts/retrain.py里有:

parser.add_argument(
      '--final_tensor_name',
      type=str,
      default='final_result',
      help="""\
      The name of the output classification layer in the retrained graph.\
      """
  )

       即出口名稱默認為final_result。

       --input_shape 需要注意的是mobilenet的訓練圖片大小為224,而Inception_v3的訓練圖片大小為299。

       最后optimized_graph.lite即是我們要移植到android上的模型文件啦。

 

第三步. Android TFLite 

       1. 下載Android Studio

         這一步驟不是本文重點,請大家自行在 https://developer.android.com/studio/ 進行下載安裝,安裝最新的SDK和NDK。

  2. 引入工程

  從android studio上引入 tensorflow-for-poets-2/android/tflite 下的代碼,共有四個類,有三個類是跟布局打交道,而我們只需要關注ImageClassifier.java類。

        3. 導入模型

  可通過命令行方式把生成的模型導入上述工程的資源目錄下:

cp tf_files/optimized_graph.lite android/tflite/app/src/main/assets/mobilenet.lite 
cp tf_files/retrained_labels.txt android/tflite/app/src/main/assets/mobilenet.txt

   4. 修改ImageClassifier.java類

  注意修改四個地方即可:

 /** Name of the model file stored in Assets. */
  private static final String MODEL_PATH = "mobilenet.lite";

  /** Name of the label file stored in Assets. */
  private static final String LABEL_PATH = "mobilenet.txt";

  static final int DIM_IMG_SIZE_X = 224; //若是inception,改成299
  static final int DIM_IMG_SIZE_Y = 224; //若是inception,改成299

  5. 運行觀看效果

  連上手機后,點擊“Run”->"Run app"即會部署app到手機上,此時任何被攝像頭捕獲的圖片都會按照標簽里的5個分類進行識別排名。

       我們可以通過百度搜一些這五種類別的花進行識別,以看看其識別的正確率。

 

后記:根據我的測試結果,在花的圖片集上,mobilenet_1.0_244模型生成的新模型識別率較高,而inception_v3模型生成的新模型識別率較低或不准。

       建議大家新的數據集可在兩種模型間進行比較,以找到最適合自己的模型。

 

  

  

       

  

 

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM