PaddlePaddle 移動端(一),在Android shell下運行PaddlePaddle
我們可以在https://github.com/PaddlePaddle/Mobile/ 找到關于PaddlePaddle應用于移動端的demo和例子。這篇文章以Android shell下運行圖像分類模型為例子來講述如何入門PaddlePaddle移動端。
內容
- PaddlePaddle訓練移動端的分類模型
- 對PaddlePaddle進行Android 交叉編譯
- Android shell 下運行分類模型
PaddlePaddle訓練移動端的分類模型
在Android shell下運行PaddlePaddle 模型,我們要準備一個適用于一個移動端的分類模型。Repo 下提供了適用于移動端的mobilenet模型,我們用這個模型來對花卉進行分類。
一,下載mobilenet配置文件
wget https://raw.githubusercontent.com/PaddlePaddle/Mobile/develop/models/standard_network/mobilenet.py
二,下載pre-trained 模型參數文件
在百度云上下載在imagenet上預訓練的mobilenet模型參數 imagenet_pretrained_mobilenet.tar.gz
三,在imagenet模型上對flower102數據集進行微調(fine-tune)
拷貝以下代碼,然后運行,會在每個epoch 后保存參數文件。可以點擊此處 下載好我已經訓練的模型參數。
import sys import gzip from paddle.trainer_config_helpers import * import paddle.v2 as paddle from mobilenet import mobile_net # batch 大小是40 BATCH = 40 def main(): datadim = 3 * 224 * 224 classdim = 102 # 采用gpu訓練并使用***塊卡 paddle.init(use_gpu=True, trainer_count=1, gpu_id=0) momentum_optimizer = paddle.optimizer.Momentum( momentum=0.9, regularization=paddle.optimizer.L2Regularization(rate=0.0005 * BATCH), learning_rate=0.001 / BATCH, learning_rate_schedule='constant') out = mobile_net(datadim, classdim, 1.0) lbl = paddle.layer.data( name="label", type=paddle.data_type.integer_value(classdim)) cost = paddle.layer.classification_cost(input=out, label=lbl) # Create parameters parameters = paddle.parameters.create(cost) # 加載imagenet 預訓練的模型參數 with gzip.open('imagenet_pretrained_mobilenet.tar.gz', 'r') as f: fparameters = paddle.parameters.Parameters.from_tar(f) for param_name in fparameters.names(): if param_name in parameters.names(): parameters.set(param_name, fparameters.get(param_name)) # End batch and end pass event handler def event_handler(event): if isinstance(event, paddle.event.EndIteration): if event.batch_id % 50 == 0: print "\nPass %d, Batch %d, Cost %f, %s" % ( event.pass_id, event.batch_id, event.cost, event.metrics) else: sys.stdout.write('.') sys.stdout.flush() if isinstance(event, paddle.event.EndPass): # save parameters with gzip.open('pruning_mobilenet_params_pass_%d.tar.gz' % event.pass_id, 'w') as f: parameters.to_tar(f) result = trainer.test( reader=paddle.batch( paddle.dataset.flowers.test(), batch_size=10), feeding={'image': 0, 'label': 1}) print "\nTest with Pass %d, %s" % (event.pass_id, result.metrics) # Create trainer trainer = paddle.trainer.SGD( cost=cost, parameters=parameters, update_equation=momentum_optimizer) trainer.train( reader=paddle.batch( paddle.reader.shuffle( paddle.dataset.flowers.train(), buf_size=50000), batch_size=BATCH), num_passes=100, event_handler=event_handler, feeding={'image': 0, 'label': 1}) if __name__ == '__main__': main()
經過微調我們的分類精度可以達到98% 左右。 現在我們有了一個.py
文件,表示模型的配置文件, 還有一個.tar.gz
文件,表示模型的參數文件, 這兩個文件組成了***的一個模型。
Android 交叉編譯PaddlePaddle
我們需要讓PaddlePaddle運行在Android平臺,需要在linux或者mac下編譯出能在android或者ios平臺下運行的PaddlePaddle庫文件。這個過程為交叉編譯。
Paddle repo下提供了關于如何在android平臺下進行交叉編譯PaddlePaddle:
在鏈接相關頁面中提供了兩種方式, 一種是通過docker的方式,一種基于自定義獨立工具鏈編譯方式, 這兩種方式,我都進行了實驗,個人比較傾向于自定義的方式,因為比較直接透明。具體的使用方式如下:
一, 下載 Android NDK
wget -q https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip unzip -q android-ndk-r14b-linux-x86_64.zip
假設當前目錄為 $CURRENT_DIR
二, 自定義工具鏈(--install-dir 表示安裝路徑,根據自己的需求設置,假設安裝路徑為$TOOLCHAIN_PATH )
$CURRENT_DIR/android-ndk-r14b-linux-x86_64/build/tools/make-standalone-toolchain.sh \ --arch=arm --platform=android-21 --install-dir=$TOOLCHAIN_PATH/v7_standalone_toolchain
$TOOLCHAIN_PATH/v7_standalone_toolchain
目錄下的內容為我們剛剛生成的工具鏈。
三, 交叉編譯PaddlePaddle
git clone https://github.com/PaddlePaddle/Paddle.git cd Paddle # 建立docker 鏡像 mkdir install mkdir build cd build cmake -DCMAKE_SYSTEM_NAME=Android \ -DANDROID_STANDALONE_TOOLCHAIN=$TOOLCHAIN_PATH/v7_standalone_toolchain \ -DANDROID_ABI=armeabi-v7a \ -DANDROID_ARM_NEON=ON \ -DANDROID_ARM_MODE=ON \ -DUSE_EIGEN_FOR_BLAS=ON \ -DCMAKE_INSTALL_PREFIX=./install \ -DWITH_C_API=ON \ -DWITH_SWIG_PY=OFF \ -DANDROID_TOOLCHAIN=gcc \ .. make -j `nproc` make install
編譯結束后,會在 install/lib
目錄下生成動態庫libpaddle_capi_shared.so
, 這個動態庫提供了模型程序調用PaddlePaddle的所有入口。
Android shell 下運行分類模型
一, 下載預測程序
該程序功能是用來測試模型的運行速度,主要包括加載模型,隨機化輸入,多次進行模型前向運算并統計時間,然后輸出模型的平均前向運行時間。
wget https://raw.githubusercontent.com/PaddlePaddle/Mobile/develop/benchmark/tool/C/inference.cc
二, 將libpaddle_capi_shared.so
copy至當前目錄
三, 編譯預測腳本
export PATH=$TOOLCHAIN_PATH/v7_standalone_toolchain/bin/:$PATH arm-linux-androideabi-g++ inference.cc -L./ -lpaddle_capi_shared -o inference -pie -fPIE
我們可以看到,目錄中多了一個inference
可運行的二進制文件。
四,將之前提到的模型配置文件.py 和模型參數文件.tar.gz融合成一個文件
from paddle.utils.merge_model import merge_v2_model # import your network configuration from mobilenet import mobile_net net = mobile_net(3*224*224, 102, 1.0) param_file = './mobilenet_flowers102.tar.gz' output_file = './mobilenet.paddle' merge_v2_model(net, param_file, output_file)
五,安裝adb
linux 安裝,查看教程
mac 安裝,查看教程
adb 工具可以登陸android 手機的shell,讓我們像使用linux shell一樣來操作android。
adb安裝之后,我們使用數據線將android手機和電腦鏈接。
六, Android shell下運行Paddle分類模型
adb push inference libpaddle_capi_shared.so mobilenet.paddle /sdcard/test_mobilenet adb shell cd /sdcard/test_mobilenet export LD_LIBRARY_PATH=./ ./inference --merged_model ./mobilenet.paddle --input_size 150528
其中input_size
表示模型輸入的大小,即3 * 224 * 224 等于 150528
如果看到以下的log,說明程序運行成功:
可以看到,paddle初始化的時間是1.78015ms, 加載模型的時間是113.749ms, 模型前向的時間是337.754ms.