PaddlePaddle 移動(dòng)端(一),在Android shell下運(yùn)行PaddlePaddle
我們可以在https://github.com/PaddlePaddle/Mobile/ 找到關(guān)于PaddlePaddle應(yīng)用于移動(dòng)端的demo和例子。這篇文章以Android shell下運(yùn)行圖像分類模型為例子來講述如何入門PaddlePaddle移動(dòng)端。
內(nèi)容
- PaddlePaddle訓(xùn)練移動(dòng)端的分類模型
- 對(duì)PaddlePaddle進(jìn)行Android 交叉編譯
- Android shell 下運(yùn)行分類模型
PaddlePaddle訓(xùn)練移動(dòng)端的分類模型
在Android shell下運(yùn)行PaddlePaddle 模型,我們要準(zhǔn)備一個(gè)適用于一個(gè)移動(dòng)端的分類模型。Repo 下提供了適用于移動(dòng)端的mobilenet模型,我們用這個(gè)模型來對(duì)花卉進(jìn)行分類。
一,下載mobilenet配置文件
wget https://raw.githubusercontent.com/PaddlePaddle/Mobile/develop/models/standard_network/mobilenet.py
二,下載pre-trained 模型參數(shù)文件
在百度云上下載在imagenet上預(yù)訓(xùn)練的mobilenet模型參數(shù) imagenet_pretrained_mobilenet.tar.gz
三,在imagenet模型上對(duì)flower102數(shù)據(jù)集進(jìn)行微調(diào)(fine-tune)
拷貝以下代碼,然后運(yùn)行,會(huì)在每個(gè)epoch 后保存參數(shù)文件??梢渣c(diǎn)擊此處 下載好我已經(jīng)訓(xùn)練的模型參數(shù)。
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訓(xùn)練并使用***塊卡 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 預(yù)訓(xùn)練的模型參數(shù) 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()
經(jīng)過微調(diào)我們的分類精度可以達(dá)到98% 左右。 現(xiàn)在我們有了一個(gè).py
文件,表示模型的配置文件, 還有一個(gè).tar.gz
文件,表示模型的參數(shù)文件, 這兩個(gè)文件組成了***的一個(gè)模型。
Android 交叉編譯PaddlePaddle
我們需要讓PaddlePaddle運(yùn)行在Android平臺(tái),需要在linux或者mac下編譯出能在android或者ios平臺(tái)下運(yùn)行的PaddlePaddle庫文件。這個(gè)過程為交叉編譯。
Paddle repo下提供了關(guān)于如何在android平臺(tái)下進(jìn)行交叉編譯PaddlePaddle:
在鏈接相關(guān)頁面中提供了兩種方式, 一種是通過docker的方式,一種基于自定義獨(dú)立工具鏈編譯方式, 這兩種方式,我都進(jìn)行了實(shí)驗(yàn),個(gè)人比較傾向于自定義的方式,因?yàn)楸容^直接透明。具體的使用方式如下:
一, 下載 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
假設(shè)當(dāng)前目錄為 $CURRENT_DIR
二, 自定義工具鏈(--install-dir 表示安裝路徑,根據(jù)自己的需求設(shè)置,假設(shè)安裝路徑為$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
目錄下的內(nèi)容為我們剛剛生成的工具鏈。
三, 交叉編譯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
編譯結(jié)束后,會(huì)在 install/lib
目錄下生成動(dòng)態(tài)庫libpaddle_capi_shared.so
, 這個(gè)動(dòng)態(tài)庫提供了模型程序調(diào)用PaddlePaddle的所有入口。
Android shell 下運(yùn)行分類模型
一, 下載預(yù)測(cè)程序
該程序功能是用來測(cè)試模型的運(yùn)行速度,主要包括加載模型,隨機(jī)化輸入,多次進(jìn)行模型前向運(yùn)算并統(tǒng)計(jì)時(shí)間,然后輸出模型的平均前向運(yùn)行時(shí)間。
wget https://raw.githubusercontent.com/PaddlePaddle/Mobile/develop/benchmark/tool/C/inference.cc
二, 將libpaddle_capi_shared.so
copy至當(dāng)前目錄
三, 編譯預(yù)測(cè)腳本
export PATH=$TOOLCHAIN_PATH/v7_standalone_toolchain/bin/:$PATH arm-linux-androideabi-g++ inference.cc -L./ -lpaddle_capi_shared -o inference -pie -fPIE
我們可以看到,目錄中多了一個(gè)inference
可運(yùn)行的二進(jìn)制文件。
四,將之前提到的模型配置文件.py 和模型參數(shù)文件.tar.gz融合成一個(gè)文件
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 手機(jī)的shell,讓我們像使用linux shell一樣來操作android。
adb安裝之后,我們使用數(shù)據(jù)線將android手機(jī)和電腦鏈接。
六, Android shell下運(yùn)行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,說明程序運(yùn)行成功:
可以看到,paddle初始化的時(shí)間是1.78015ms, 加載模型的時(shí)間是113.749ms, 模型前向的時(shí)間是337.754ms.