13

空域 · 5月21日

Tengine Debug 技巧

最近一直在运用Tengine做前端推理。在运用与适配模型中遇到了很多的问题,如何对一个框架进行Debug在本人觉得是一个很重要的技巧,好的 Debug技巧会大大缩减开发周期。下面就基于本人的Tengine使用经验来分享下如何对Tengine框架进行Debug。

1. 环境变量的设置:

Tengine中采用了两套算子的实现,对于大量计算操作的算子,例如Convolution,Softmax,Pooling等之类的算子在对应的平台上有对应的性能算子的实现。一般而言,如果一个推理模型发生错误,首先就是定位是否在性能算子,功能性算子发生错误。

如果需要单独运行功能性算子,屏蔽性能算子,则只需要输入下列指令:

export OPS_REGISTRY=reference

如果需要对某一个性能算子进行屏蔽,则需要另一条指令进行搭配操作:

export OPS_REGISTRY=reference
export OP_NAME=Convolution

上述两行命令则是表明只设置Convolution算子到功能性算侧进行计算。

因为Tengine中的性能部分有两套实现,虽然都是运用arm 汇编进行的性能优化,但是有一套相对于普通性能的更加优秀的优化算法Winograd。但是Winograd有时候对于精度的支持会有限制,但是模型推理结果在精度上有偏差时,可用下列命令来屏蔽Winograd算法:

export NO_WINO=1

在模型推理的运行时,我们需要对每一层算子的计算时间进行统计或者通过观察每一层算子的运行时间来确定是否发生异常,则可用下一条指令来答应全部算子的运行时间:

export PROF_TIME=1

上述几种环境变量的设置可以简单的定位在哪个算子层出现错误。但是往往模型出现问题的时候,是里面的数据发生了变化,那需要通过下列的方法:

2. Tengine代码的修改:

在Tengine代码中,有一个文件driver/cpu/cpu_runner.cpp,此文件为Tengine框架运行算子层的上层文件,在此文件中可以看到是cpu是如何调用node来进行计算的。

修改此文件中的Run函数,则可以进行一下两个操作:

对图进行切图:

    for(unsigned int i = 0; i < seq_nodes.size(); i++)
    {
        Node* node = seq_nodes[i];

        if(!node->ExistAttr(ATTR_NODE_OPS))
            continue;

        NodeOps* node_ops = any_cast<NodeOps*>(node->GetAttr(ATTR_NODE_OPS));

......

在for loop的循环中,可以设置Tengine运行到哪一个算子进行跳出,只要指导算子的名字即可。添加代码如下:

if(node->GetName() == "XXX"){
    return true;
}

返回true值则是表示Run循环成功结束,所以只需要加入次判断便可对图进行截断。

打印Tengine每个算子的输出数据:

//#define DUMP_NODE_OUTPUT
#ifdef DUMP_NODE_OUTPUT
        {
            std::string fname = "/tmp/debug/node" + std::string(i < 10 ? "0" : "") + std::to_string(i);

            for(unsigned int i = 0; i < node->GetOutputNum(); i++)
            {
                Tensor* t = node->GetOutputTensor(i);
                int size = t->GetTotalSize();
                void* mem = get_tensor_mem(t);

                fname = fname + "." + std::to_string(i);

                DumpFloat(fname.c_str(), ( float* )mem, size / sizeof(float));
            }
        }
#endif

上述部分函数则是会对Tengine的每个算子的输出数据进行打印输出。其打印目录结果可参考如下:

每个node的名字都是node+数字来表示,对于此文件则需要通过打印出Tengine计算图的结果来对应表示。

对于dump_graph(graph)的添加有两种:

直接在create_graph函数后添加,则会打印出解析模型的原始计算图。

在prerun之后添加,则会打印出Tengine优化后的计算图。

对于最终的node数据结果,则是查看在prerun之后的计算图来进行比对。

上述的基本Debug方法已经能解决大部分在Tengine运行中遇到的模型推理问题。

Tengine github:
https://github.com/OAID/Tengine


推荐阅读

更多Tengine框架相关请关注Tengine-边缘AI推理框架专栏 及作者知乎(@空域)
13 阅读 223
推荐阅读
0 条评论
关注数
137
文章数
25
Tengine是一款轻量级模块化高性能的神经网络推理引擎 ;欢迎体验Tengine,[链接] 《Tengine开发者入门资料包》[链接]
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
Arm中国学堂公众号
关注Arm中国学堂
实时获取免费 Arm 教学资源信息
Arm中国招聘公众号
关注Arm中国招聘
实时获取 Arm 中国职位信息