本期讲解便是基于 Tengine 实现 yolov4的 cpu推理。
完成动机:
主要是为了熟悉tengine的推理部署流程
一、模型转换
采用下面链接中yolov4的模型权重和配置文件
https://github.com/ultralytics/yolov3github.com
源模型使用的是darknet格式,因为yolov4新增了mish算子,所以需要增加对应算子的序列化代码才能正常转换,下面是我的代码改动,基本按照tanh算子进行相应增加。
https://github.com/zjd1988/Tengine-Convert-Toolsgithub.com
convert tools增加算子的详细流程,参考官方增加自定义算子步骤:
(1)在operator/include/operator目录下增加mish.hpp 和mish\_param.hpp\_文件,\_由于mish算子不需要额外的参数配置,因此mish\_para.hpp并没有添加。mish.hpp内容可以参考其他类似没有参数配置的算子(比如tanh),在operator/operator 目录下增加mish.cpp,增加算子实现代码;
(2)在operator/operator目录下增加mish算子内存分配的代码,因为mish算子不涉及这部分修改,并未做任何修改
(3)在operator/operator/plugin/init.cpp文件中的operator\_plugin\_init函数中增加算子的注册函数调用
(4)增加mish算子序列化和解析代码
(4-1)在serializer/include/tengine/v2/tm2\_format.h中增加mish的类型宏定义和字符串宏定义 ;
(4-2)在serializer/tengine/v2/tm2\_op\_load.cpp文件中增加LoadTmMishOp函数实现,同时在LoadTmOpFunc函数中增加调用LoadTmMishOp的逻辑代码;
(4-3)在serializer/tengine/v2/tm2\_op\_save.cpp文件中增加SaveTmMishOp函数实现,同时在SaveTmReorgOp函数中增加调用SaveTmMishOp的逻辑代码;
(4-4)在serializer/tengine/v2/tm2\_op\_serializer.hpp,增加LoadTmMishOp和 SaveTmMishOp的函数声明
(4-5)本次转换模型针对darknet,所以需要对tools/darknet/darknet\_serializer.cpp文件中增加mish算子解析的相应逻辑。 因为mish没有单独使用,而是作为conv的激活函数调用,所以是在LoadConv2D函数参照leaky增加相应的代码。其他单独算子的实现也可以参考其他类似算子的实现方式
完成代码改动后,按照如下操作进行编译,即可生成转换工具
mkdir build && cd build
cmake ..
make -j4 && make install
最后执行转换动作(提前准备好模型文件)
./install/bin/tm_convert_tool -f darknet -p yolov4.cfg -m yolov4.weights -o yolov4.tmfile
二、推理
官方代码链接下的readme并没有找到介绍如何新增算子,但是可以参考类似算子进行修改添加,下面是我参考tanh算子的实现,进行的修改
(1-1)在inlcude/tengine\_op.h中增加mish的枚举定义,include/tengine\_op\_name.h中增加mish的字符串宏定义
(1-2)在src/op/mish.c中增加mish算子的注册函数
(1-3)在src/serializer/tm/tm2\_format.h 和src/serializer/tm/op/tm2\_mish.c 中增加序列化相关代码,
note:src/serializer/tm/tm2\_format.h中定义算子的类型数值需要跟convert\_tools下的serializer/include/tengine/v2/tm2\_format.h代码保持一致
(1-4)在src/dev/cpu/op/目录下增加mish算子实现代码目录,包括mish\_ref.c(x86)、mish\_hcl\_arm.c(arm),其中contex-a目录下的文件为具体的kernel实现代码
也可以参考下面的链接,查看有哪些代码改动和文件增加:
https://github.com/zjd1988/Tenginegithub.com
测试
测试图片使用的是标题中的图片(512x384)test.jpg
测试代码使用的官方代码
examples/tm_yolov3_tiny.cpp
做了简单修改。
测试结果如下图
三、后续
(1)合并conv和mish算子
(2)后续抽空新增一个需要配置参数的算子
四、使用感受
(1)模型转换和推理分离,新增算子需要增加两次,官方回复会后续考虑合并,希望会越来越方便
(2)推理引擎编译速度快(本文目的不在于测试性能,只是验证tengine在推理yolov4的正确性)
(3)代码结构清晰,便于阅读和调试
以上便是解答过程以及使用感受。
更多Tengine相关内容请关注Tengine-边缘AI推理框架专栏。