NNVM/TVM嵌入式初探

Published: 11 Nov 2017 Category: 深度学习-优化加速

NNVM/TVM

NNVM/TVM 是DMLC出品的又一利器,着眼于快速产生高效的,可以部署到多种target的DL库, 提高生产效率。众所周知,目前深度学习技术开始大量实用,除了在云上,可以使用nvidia的显卡以及cuDNN框架进行加速,其他平台,尤其是嵌入式平台,深度学习的应用还是受到了计算性能的限制,不同的部署平台的优化涉及到具体的底层细节, 优化工作耗时耗力。另外,现在深度学习训练框架也是多足鼎力的状态, 每个框架都去做一套优化也有些浪费。NNVM就为解决这个问题,提供了一整套工具栈。

距离NNVM/TVM的发布,已经过去几个月的时间。在这段时间里,一些教程、benchmark脚本也陆续开放。今天我就来在树莓派上和FireFly RK3288上测试一下。

测试平台

由于Android手机的系统性能的问题(多线程环境很不稳定), 我这次选用了树莓派和FireFly RK3288作为测试平台。搭建测试平台的过程简单过一下:

烧写合适的操作系统

* 树莓派:官方系统
* FireFly RK3288 :Ubuntu 16.04 ### 切换软件源,这样后续更新、安装软件速度都会快些
* 国内比较好的源:中科大, 清华。 注意是armhf的源。
* 树莓派的默认源速度还可以。 ### 更新系统,软件等。 #### 更新软件 ``` sudo apt update && sudo apt upgrade ``` #### 安装pip, numpy ### 下载NNVM的代码,编译,配置基本环境变量 #### 下载代码  ```shell git clone --recursive https://github.com/dmlc/nnvm.git ``` 注意: --recursive, 连同TVM,以及依赖的submodule,都一起下载。 #### 编译 TVM: ``` cd nnvm/tvm  make build make runtime -j2 ``` 注:我们通过rpc进行测试, 所以嵌入式端只编译runtime即可。

NNVM:

cd ..
mkdir build
make  -j2

环境配置

PYTHONPATH配置

echo export PYTHONPATH=${PYTHONPATH}:${NNVM_HOME}/python:${NNVM_HOME}/tvm/python:${NNVM_HOME}/tvm/topi/python >> ~/.bashrc
source ~/.bashrc

好啦,嵌入式端测试环境完成。 启动rpc server调用测试一下。

python -m tvm.exec.rpc_server

主机端

主机端系统我用的是Ubuntu 16.04。(Windows还是不稳定, 有时候退出会卡死。)

基本环境搭建过程一致,不再赘述。 有几点不同:

  1. 由于需要交叉编译,需要安装LLVM。 建议采用prebuilt, 这样省去了源码编译安装LLVM的时间。
  2. 编译TVM的时候,整体编译。(嵌入式端只需要编译runtime)

测试

嵌入式端

  1. 启动rpc服务
    python -m tvm.exec.rpc_server
    
  2. 查看一下嵌入端的ip。(主机端rpc连接会用到)

主机端

目前提供了mobilenet1.0和resnet18的schedule了。我们就测试这两个网络。

树莓派

先看一下测试脚本的相关参数。

python examples/benchmark/rasp_imagenet_benchmark.py --help

测试

python examples/benchmark/rasp_imagenet_benchmark.py --model mobilenet --host your_device_ip --post 9090

your_device_ip 是指设备的ip, 端口号默认是9090, 如果要改变,启动rpc server的时候修改,主机端相应修改。

不出意外的话, mobilenet1.0 在树莓派3b上的时间是200ms左右。resnet-18 速度还是很不错的。

benchmark args: Namespace(host='192.168.0.105', model='mobilenet', num_iter=20, opt_level=3, port=9090)
ProfileResult(mean=0.20684018489999997)
ProfileResult(mean=0.20953467739999998)
ProfileResult(mean=0.2077883298)

benchmark args: Namespace(host='192.168.0.105', model='resnet', num_iter=20, opt_level=3, port=9090)
ProfileResult(mean=0.54514569005)
ProfileResult(mean=0.54719750785)
ProfileResult(mean=0.549796459)

FireFly RK3288

RK3288的cpu是cortex-a17, 树莓派的是cortex-a53, 临时的方案是修改target的参数,这样可以使用rasp的schedule。

以前是默认参数: tvm.target.rasp() 修改为 tvm.target.rasp(“-mcpu=cortex-a17”)

RK3288 主频1.8GHz, mobilenet1.0 可以跑到100ms左右,resnet-18 可以跑到280ms。速度还是很赞的。

汇总下速度

Device Mobilenet1.0 ResNetv-18 SqueezeNet-v1.1*
Raspberry 3b ~200 ms ~550 ms ~120 ms
Firefly RK3288 ~100 ms ~280 ms ~77 ms

*: Schedule work in progress.

后续

考虑到当下移动端的框架通常用SqueezeNet作为速度测试的模型,准备为SqueezeNet写个schedule, 然后测试下速度,以便和一些开源嵌入式端优化框架(ncnn, mdl等)作比较。

踩到的坑

  1. 树莓派电压不足会降频! 电压不足主频直接降到600MHz。我是从淘宝上买的树莓派,电源电压不足,找到问题之后我换了更强,更稳定的电源。如果性能跟我上述的结果差别很大, 可以确认下cpu的实时主频。(不要看百分比)。
  2. RK3288上烧不同的系统,居然cpu_max_frequency主频不一致, 有1.6GHz的。顺便吐槽一下RK3288的社区以及配套资源,真的不够好。
comments powered by Disqus