TensorFlow-Slim圖像分類Mobilenet量化模型並移植至安卓客戶端
1. 配置
基本配置 | 版本號 |
---|---|
CPU | Intel® Core™ i5-8400 CPU @ 2.80GHz × 6 |
GPU | GeForce RTX 2070 SUPER/PCIe/SSE2 |
OS | Ubuntu18.04 |
openjdk | 1.8.0_242 |
python | 3.6.9 |
bazel | 0.21.0 |
gcc | 4.8.5 |
g++ | 4.8.5 |
hint:
- bazel會在轉換模型的時候用到, 我的另一篇博客有講如何配置.
https://blog.csdn.net/weixin_43056275/article/details/105124979 - bazel編譯時, gcc和g++版本需要一致.
2. 準備工作
2.1 下載
2.1.1 下載models-1.12.0
https://github.com/tensorflow/models/tree/v1.12.0
在~/.bashrc中加入配置
export PYTHONPATH=$PYTHONPATH:pwd
:pwd
/slim
2.1.2 下載模型
https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md
紅框內的模型用於需要對模型進行量化處理的
2.1.3 下載tensorflow-r1.13源碼
https://github.com/tensorflow/tensorflow/tree/r1.13
2.2 使用bazel編譯tensorflow-r1.13源碼
我的另一篇博客寫的很詳細
https://blog.csdn.net/weixin_43056275/article/details/105124979
3. 訓練Mobilenet v1 quantized 模型
3.1 製作數據集
我的數據集文件結構和生成tfrecord的代碼可供下載: https://download.csdn.net/download/weixin_43056275/12314008
我做的是二分類, 所以我的數據集只有兩個類別, bad 和 good.
以下是我製作tfrecord的文件目錄:
data_prepare/
pic/
train/
bad/
good/
validation
bad/
good/
src/
tfrecord.py/
data_convert.py
- pic裏面有train和validation兩個目錄, 分別是訓練和驗證使用的圖片. 在目錄中,分別以類別名分類保存圖像. 比如我是二分類, 標籤是bad, good. 文件名就是以這個分類.
- src 裏面保存tfrecord.py 這個python文件提供給data_convert.py 調用.
- data_convert.py, 可以調用這個文件來生成tfrecord和標籤txt, 生成的tfrecord被保存在pic目錄下.
運行data_convert.py生成tfrecord文件
python data_convert.py -t pic/ \
--train-shards 2 \
--validation-shards 2 \
--num-threads 2 \
--dataset-name mydata
參數含義解釋:
- -t pic/:表示轉換pic文件夾中的數據。pic文件夾中必須有一個train目錄和一個validation目錄,分別代表訓練和驗證數據集。每個目錄下按類別存放了圖像數據。
- −−train-shards 2:將訓練數據集分爲兩塊,即最後的訓練數據就是兩個tfrecord格式的文件。如果讀者的數據集較大,可以考慮將其分爲更多的數據塊。
- −−validation-shards 2:將驗證數據集分爲兩塊。
- −−num-threads 2:採用兩個線程產生數據。注意線程數必須要能整除train-shards 和validation-shards,來保證每個線程處理的數據塊數是相同的。
- −−dataset-name mydata:給生成的數據集起一個名字。這裏將數據集起名叫“satellite”,最後生成文件的開頭就是satelite_train 和satelite_validation。
運行上述命令後,就可以在pic文件夾中找到5個新生成的文件,分別是訓練數據 mydata_train_00000-of-00002.tfrecord、mydata_train_00001-of-00002.tfrecord,以及驗證數據 mydata_validation_00000-of-00002.tfrecord、mydata_validation_00001-of-00002.tfrecord。另外,還有一個文本文件label.txt,它表示圖片的內部標籤(數字)到真實類別(字符串)之間的映射順序。如在tfrecord中的標籤爲0,那麼就對應label.txt 第一行的類別,在tfrecord的標籤爲1,就對應label.txt中第二行的類別,依此類推。
3.2 定義新的datasets文件
找到models/research/目錄中的slim文件夾, 這就是要用到的TensorFlow Slim的源代碼。這裏簡單介紹TensorFlow Slim的代碼結構,見下表。
文件夾或文件名 | 用途 |
---|---|
datasets/ | 定義一些訓練時使用的數據集。如果需要訓練自己的數據,必須同樣在datasets文件夾中進行定義,會在下面對此進行介紹 |
nets/ | 定義了一些常用的網絡結構,如AlexNet、VGGl6、VGG19、Inception 系列、ResNet、MobileNet等 |
preprocessing/ | 在模型讀入圖片前,常常需要對圖像做預處理和數據增強。這個文件夾針對不同的網絡,分別定義了它們的預處理方法 |
scripts | 包含了一些訓練的示例腳本 |
train_ image_classifier.py | 訓練模型的入口代碼 |
eval_image_classifier.py | 驗證模型性能的入口代碼 |
download_and _convert data.py | 下載並轉換數據集格式的入口代碼 |
首先,在datasets/目錄下新建一個文件mydata.py,並將flowers.py文件中的內容複製到satellite.py中。接下來,需要修改以下幾處內容。
- 第一處是_FILE_PATTERN、SPLITS_TO_SIZES、_NUM_CLASSES,將其進行以下修改:
_FILE_PATTERN 變量定義了數據的文件名的格式
SPLITS_TO_SIZES變量定義訓練集、驗證集的數量
_NUM_CLASSES 變量定義了數據集中圖片的類別數目 - 第二處修改爲image/format部分,將之修改爲:
- 修改datasets目錄下另一個文件dataset_factory.py, 註冊自己的數據名
3.3 修改mobilenet_v1結構參數
因爲我下載的是 mobilenet_v1_0.75_224_quant, 所以 slim/nets/mobilenet_v1.py中有兩個地方要修改.
3.4 準備訓練文件夾
- 將上文下載的預訓練模型解壓到slim文件夾下, 作爲checkpoint_path參數
- 在slim新建train_dir, 作爲訓練模型後生成ckpt的存儲文件夾
3.5 開始訓練
python train_image_classifier.py \
--train_dir=./train_dir \
--dataset_dir=./data_prepare/pic \
--dataset_name=mydata \
--dataset_split_name=train \
--model_name=mobilenet_v1 \
--checkpoint_path=./mobilenet_v1_0.75_224_class/mobilenet_v1_0.75_224_quant.ckpt \
--checkpoint_exclude_scopes=MobilenetV1/Logits,MobilenetV1/AuxLogits \
--max_number_of_steps=100000 \
--train_image_size=224 \
--trainable_scopes=MobilenetV1/Logits,MobilenetV1/AuxLogits \
--quantize_delay=0
- train_dir: 存儲訓練生成的日誌和ckpt
- dataset_dir: tfrecord和txt的目錄
- dataset_name: 上文定義的數據集的名字
- max_number_of_steps=100000: 最大的執行步數
3.6 驗證模型
python eval_image_classifier.py \
--alsologtostderr \
--checkpoint_path=./train_dir/model.ckpt-100000 \
--dataset_dir=./data_prepare/pic \
--dataset_name=mydata \
--dataset_split_name=validation \
--model_name=mobilenet_v1 \
--eval_image_size=224
4. 將訓練結果轉換爲tflite量化模型
4.1 導出推理圖
python export_inference_graph.py \
--alsologtostderr \
--model_name=mobilenet_v1 \
--dataset_dir=./data_prepare/pic \ #數據集路徑
--dataset_name=mydata \ #數據集名字
--image_size=224 \
--output_file=./test.pb \
--quantize=True
如果不設置好數據集路徑和名字會導致 Assign requires shapes of both tensors to match. lhs shape= [1001] rhs shape= [2].
如何解決請看, https://blog.csdn.net/weixin_43056275/article/details/105405751
4.2 獲取pb文件的輸入輸出
有兩種方式
4.2.1 通過netron
https://lutzroeder.github.io/netron/
可以在線上傳模型, 得到輸入輸出
輸入:
輸出:
4.2.2 通過summarize_graph命令
在./tensorflow-r1.13運行
bazel build tensorflow/tools/graph_transforms:summarize_graph
bazel-bin/tensorflow/tools/graph_transforms/summarize_graph \
--in_graph=/home/ying/usb/models/models-1.12.0/research/slim/test.pb
4.3 凍結導出的模型
在./tensorflow-r1.13運行
bazel build tensorflow/python/tools:freeze_graph
bazel-bin/tensorflow/python/tools/freeze_graph \
--input_graph=/home/ying/usb/models/models-1.12.0/research/slim/test.pb \
--input_checkpoint=/home/ying/usb/models/models-1.12.0/research/slim/train_dir/model.ckpt-100000 \
--input_binary=true --output_graph=/home/ying/usb/models/models-1.12.0/research/slim/frozen1.pb \
--output_node_names=MobilenetV1/Predictions/Reshape_1
4.4 轉換pb模型爲tflite模型
在./tensorflow-r1.13運行
bazel build tensorflow/lite/toco:toco
bazel-bin/tensorflow/lite/toco/toco --input_file=/home/ying/usb/models/models-1.12.0/research/slim/frozen1.pb \
--input_format=TENSORFLOW_GRAPHDEF \
--output_format=TFLITE \
--output_file=/home/ying/usb/models/models-1.12.0/research/slim/frozen1.tflite \
--inference_type=QUANTIZED_UINT8 \
--input_arrays=input \
--output_arrays=MobilenetV1/Predictions/Reshape_1 \
--input_shapes=1,224,224,3
4.5 測試tflite模型
在./tensorflow-r1.13運行
bazel build tensorflow/lite/examples/label_image:label_image
bazel-bin/tensorflow/lite/examples/label_image/label_image
--tflite_model=/home/ying/usb/models/models-1.12.0/research/slim/frozen1.tflite
--input_mean=128
--input_std=128
--labels="/home/ying/usb/models/models-1.12.0/research/slim/data_prepare/pic/label.txt"
--image="/home/ying/usb/deep-learning-for-image-processing-master/deep-learning-for-image-processing-master/pytorch_learning/Test5_resnet/test1/bad15.bmp"
結果:
根據tensorflow版本不同, 參數可能也會有所不同, 請根據情況進行調整.
5. 部署到Android
打開./tensorflow-r1.13/tensorflow/lite/examples/android
將tflite和txt放到./tensorflow-r1.13/tensorflow/lite/examples/android/app/src/main/assets文件下
5.1 修改ClassifierActivity
5.2 修改RecognitionScoreView(可改可不改)
修改之後, 在運行app時, 屏幕上只會顯示最相似的一類. 不修改之前會顯示多項分類, 有不同的分數, 根據需求進行修改.
以下爲配置文件的更改
5.2 配置文件的更改
5.2.1 build.gradle(Project: android)
5.2.2 build.gradle(Module: app)
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "org.tensorflow.lite.demo"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
// Remove this block.
// jackOptions {
// enabled true
// }
}
lintOptions {
abortOnError false
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
aaptOptions {
noCompress "tflite"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
repositories {
maven {
url 'https://google.bintray.com/tensorflow'
}
}
// import DownloadModels task
project.ext.ASSET_DIR = projectDir.toString() + '/src/main/assets'
project.ext.TMP_DIR = project.buildDir.toString() + '/downloads'
// Download default models; if you wish to use your own models then
// place them in the "assets" directory and comment out this line.
apply from: "download-models.gradle"
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'org.tensorflow:tensorflow-lite:0.1.2-nightly'
implementation 'org.tensorflow:tensorflow-lite:2.0.0'
}
5.2.3 配置文件的更改 AndroidManifest.xml
註釋掉目標檢測和語音的app的內容, 只留下分類.
參考:
https://blog.csdn.net/qq_33200967/article/details/82773677#commentBox
https://www.cnblogs.com/Terrypython/p/10858803.html
https://zhuanlan.zhihu.com/p/44437031
https://www.imooc.com/article/details/id/28871