Openvino中支持Paddle算子
如何在Openvino中增加Paddle的算子,让Paddle模型顺利在Openvino中跑起来
Openvino支持PaddlePaddle的算子开发
1、背景
现在用PaddlePaddle框架训练的越来越多,Paddle框架中,算子和openvino的算子有些计算不一样,需要做一个映射,才能在Openvino上跑推理,所以需要在Openvino上支持更多的Paddle的算子。
2、项目开发过程
2.1 Openvino支持Paddle的elementwise_floordiv算子
- Paddle中的elementwise_floordiv算子,在Openvino中没有,需要根据Paddle这边elementwise_floordev的定义,在Openvino中实现同样的功能。
2.2 任务介绍
- 在Openvino侧完成elementwise_floordiv的功能,并能跑通单测
2.3 前期准备工作
2.3.1 对Paddle elementwise_floordiv算子的调研
-
困惑?
看到这个算子,首先在PaddlePaddle API 文档中 查找python 接口 elementwise_floordiv, 发现对应的版本Paddle版本是1.8的(Paddle已经不支持的版本), 怀疑出题的人是不是搞错了? 先在Paddle官网上查找下1.8和2.x对应的接口,在2.x版本中对应的名字是 floor_divide.
-
对新旧版本elementwise_floordiv的分析(从文档上分析)
相同点:
- 计算功能都是 z = x // y (文档定义,后面有坑)
- 支持的类型都是int32, int64
不同点:
- 参数不同,elementwise_floordiv 多了一个参数axis,axis是指 y shape 在 x shape 上的起点,在floor_divide中少了axis
- broadcast 方式不一样,在elementwise_floordiv中,broadcast是根据axis 的值来做broadcast, 是paddle的broadcast机制,比如:x_shape = [2, 3, 4, 5], y_shape = [3, 4] ,axis = 1, 在调用该函数,则会 按照 y_shape = [1, 3, 4, 1] 来做broadcast; 然而 floor_divide 不支持上面这种broadcast, 它则是按照Numpy的broadcast的机制;所以其实floor_divide 是 elementwise_floordiv 在axis = -1的这种特殊形式
2.3.2 对Openvino算子的调研
-
功能拆分
Openvino算子是基本的数学公式组成,而Paddle一般是大算子,几个小的组合而成。如果Openvino有对应的算子,就直接映射调用,如果没有则需要对Paddle的算子做拆分,先做拆分,再去查找文档,这样比较明确目标。elementwise_floordiv 则可以分成:broadcast, divide, floor 三个小算子。
-
查找对应算子
在openvino文档中查看上面的拆分的小算子
- broadcast: Openvino的文档中介绍,支持Numpy的机制,也支持PDPD的机制,满足要求,不需要做shape的转换,可以直接传参数来做PDPD的broadcast
- divide: 在文档中发现,它有m_pythondiv, auto_broadcast 这两个属性,在调用的时候,设置这两个属性,就满足了Paddle的elementwise_floordiv的功能。于是锁定这个算子。
2.3.3 版本兼容
Paddle 有两个版本,为了兼容性,在设计接口的时候,应该考虑增加属性axis, 如果没有这个属性的时候,默认-1.
2.4 开发过程
2.4.1 环境搭建
-
选择开发环境,可以直接用物理机,我选择的是docker, 用Paddle提供的镜像(自带安装了paddle2.1版本)registry.baidubce.com/paddlepaddle/paddle:2.1.0, 也可以到Paddle的镜像列表 中去选择其他的镜像。
-
通过下面的命令创建容器
docker run --net host --name=openvino --user root -it -v `pwd`:/workspace -w /workspace registry.baidubce.com/paddlepaddle/paddle:2.1.0 /bin/bash
-
现在github上面,fork openvino 到自己的github上面
-
在进入容器后,git pull 自己github上面Openvino的代码到本地, 设置upstream, 并创建自己本地的开发分支。通过下面的命令来完成
git remote add upstream https://github.com/openvinotoolkit/openvino
git pull --rebase master:master
git checkout branch dev
git checkout dev
git rebase master
- 按照openvino的官网文档编译
cd openvino
git submodule update --init --recursive
chmod +x install_build_dependencies.sh
./install_build_dependencies.sh
export OPENVINO_BASEDIR=`pwd`
mkdir build
cd build
cmake \
-DCMAKE_BUILD_TYPE= Release -DCMAKE_INSTALL_PREFIX="${OPENVINO_BASEDIR}/openvino_dist" \
-DPYTHON_EXECUTABLE=$(which python3) \
-DENABLE_MYRIAD=OFF \
-DENABLE_VPU=OFF \
-DENABLE_PYTHON=ON \
-DNGRAPH_PYTHON_BUILD_ENABLE=ON \
-DENABLE_DEBUG_CAPS=ON \
-DENABLE_CPU_DEBUG_CAPS=ON \
-DENABLE_TESTS=ON \
..
make -j30 && make install
- 在编译执行过程中,遇到下面的问题,然后按照下面的指令解决即可
1. libusb is required, please install it ( apt-get install libusb-1.0-0-dev)
2. lfs is not found (apt-get install git-lfs 或者 git lfs install --system)
3. shell check的问题 (apt-get install shellcheck)
4. Cython的问题 (pip install Cython --install-option="--no-cython-compile")
5. 找不到python头文件的问题,可以把上面的cmake命令按照下面命令执行即可:
cmake .. \
-DPYTHON_INCLUDE_DIR=$(python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \
-DPYTHON_LIBRARY=$(python -c "import distutils.sysconfig as sysconfig; print(sysconfig.get_config_var('LIBDIR'))") \
-DCMAKE_BUILD_TYPE= Release -DCMAKE_INSTALL_PREFIX="${OPENVINO_BASEDIR}/openvino_dist" \
-DPYTHON_EXECUTABLE=$(which python3) \
-DENABLE_MYRIAD=OFF \
-DENABLE_VPU=OFF \
-DENABLE_PYTHON=ON \
-DNGRAPH_PYTHON_BUILD_ENABLE=ON \
-DENABLE_DEBUG_CAPS=ON \
-DENABLE_CPU_DEBUG_CAPS=ON \
-DENABLE_TESTS=ON \
- 编译完成后,跑下openvino里面本来就有的paddle单测
cd bin/intel64/Release
./paddle_tests --gtest_filter=PaddleFuzzyOpTest/FrontEndFuzzyOpTest.testOpFuzzy/*
2.4.2 开发写代码
- openvino工程中有paddle的目录,paddle的目录结构如下
- 在op_table.cpp中注册函数如下,第一个是注册Paddle的OP,第二个是绑定的OP到对应的实现函数名:
-
elementwise_floordiv 函数功能的实现以及功能
-
代码实现:在op目录下面的 elementwise_ops.cpp中增加 elementwise_floordiv 的实现,代码以及代码含义如下图
-
参数设置以及出现的问题:按照前期对Openvino中Divide的分析,需要设置m_pythondiv = true 和 auto_broadcast = PDPD, 就可以满足要求; 实际上m_pythondiv = true 是实现了 z = x//y的功能,和Paddle 的文档一致,但是在单测中,输入负数的时候,他们的结果计算是不一致的,比如:x = [-3], y = [2] 的时候,Paddle的z = -1, Openvino 的z = -2, Paddle的行为和文档预期不符合;最后查看Paddle底层的调用,实际调用的static_cast(x/y);要和Paddle实际逻辑一致,需要 m_pythondiv = false.
-
-
增加单测代码
-
代码实现:在目录src/core/tests/frontend/paddle/test_models/gen_scripts下面增加单测代码,原工程中本来就有elementwise相关的单测文件,直接在原来的文件中增加foor_div的单测, 代码以及含义如下图
-
遇到的问题以及考虑:数据测试范围设置,如果不设置负数的输入的话,上面Paddle的问题无法出现
-
-
注册单测实例,在src/core/tests/frontend/paddle/op_fuzzy.cpp 中注册
-
完成后,编译,跑单测:
-
单测完成后,就提交代码,按照下面的命令提交, 然后在github上面写PR信息就可以了,等待反馈,有问题修改
git checkout master
git pull --rebase upstream master:master
git chekcout dev
git rebase master
git push origin -f dev:dev
2.5 总结
Openvino的这次比赛,主要是做Paddle算子到Openvino上的映射,Paddle的算子丰富后,Paddle的模型直接可以在Openvino上面跑。要完成这样的题目,首先要对Paddle和Openvino都要有一定的了解。参加这次比赛,收获颇多,对做这样算子映射的一些思考:
- 开始写代码前的调研很重要,对算子在Paddle上逻辑实现,参数,版本等都要深入分析,然后再根据Openvino的特点做算子拆分或者合并;如果我前期没有深入调研,在Openvino上的实现,可能就用小算在来组合,这样效率就比较低了。
- 单测的数据范围和类型要尽量全,对于这个算子,如果没有负数的测试,就不会发现Paddle的文档和实际逻辑不一致的问题。
此文章为搬运
原项目链接
更多推荐
所有评论(0)