我们可以在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.