惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
S
Secure Thoughts
月光博客
月光博客
美团技术团队
雷峰网
雷峰网
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
N
News and Events Feed by Topic
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Forbes - Security
Forbes - Security
W
WeLiveSecurity
P
Proofpoint News Feed
阮一峰的网络日志
阮一峰的网络日志
爱范儿
爱范儿
G
GRAHAM CLULEY
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AI
AI
Last Week in AI
Last Week in AI
Google Online Security Blog
Google Online Security Blog
Schneier on Security
Schneier on Security
云风的 BLOG
云风的 BLOG
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Recent Announcements
Recent Announcements
Webroot Blog
Webroot Blog
T
Tor Project blog
Cisco Talos Blog
Cisco Talos Blog
N
News and Events Feed by Topic
罗磊的独立博客
The Register - Security
The Register - Security
Blog — PlanetScale
Blog — PlanetScale
T
Threat Research - Cisco Blogs
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
人人都是产品经理
人人都是产品经理
T
The Exploit Database - CXSecurity.com
www.infosecurity-magazine.com
www.infosecurity-magazine.com
B
Blog
腾讯CDC
Microsoft Azure Blog
Microsoft Azure Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Engineering at Meta
Engineering at Meta
Latest news
Latest news
IT之家
IT之家
D
DataBreaches.Net
博客园 - 司徒正美
N
Netflix TechBlog - Medium
V
V2EX
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

Пусть этот камень будет более крепким, чем человек

【琐记】烟火与尘埃 【Triton】Triton实现矩阵乘 【LLM推理加速】FlashAttention 【LLM推理加速】PagedAttention 【LLM推理加速】Online Softmax LLM基础知识【1】 Transformer模型 【AI编译】LayerGroup Tiling Tile的疑惑和思考 【AI编译】深度优先的Tile调度,万事大吉? 【AI编译】多级流水线Tile调度策略 【CUDA C++】GPU内存使用【3】 【AI编译】Cache缓存地址映射 【CUDA C++】GPU存储【2】 【CUDA C++】GPU基本介绍【1】 【00】0序章-不受欢迎的来客 【转载】我来了——持续低熵 【Halide】调度优化【2】 【感想】写作进度报告5 【Halide】调度优化【1】 【转载】北大中文男足战报2 【BYOC】TVM切分子图 【转载】北大中文男足战报1 【AI编译】张量生命周期管理 SystemC 用寄存器同步建模方法 【脉动阵列】脉动阵列类型 【im2col】AScend conv accelerate 【感想】写作进度报告4 【BYOC】TVM添加自定义编译器 ccompiler 【感想】写作进度报告3 【Tengine】推理流程脑图【2】 【NCNN】学习ncnn模型转换 【编译器】使用llvm编译自定义语言【3】编译 object 【编译器】使用llvm编译自定义语言【2】转llvm IR 【编译器】使用llvm编译自定义语言【1】构建AST 【AI编译】如何进行内存分配 【感想】写作进度报告2 【AI编译】layer-group之后如何tiling 【AI编译】如何进行layer-group 【量化】连续卷积层首尾量化的可行性 【Gemm】内存对齐 【gemm】Gemm计算加速 【TVM】通过代码学习编译流程【5】FuseOps 【TVM】通过代码学习编译流程【6】CodeGen 【TVM】通过代码学习类【3.5】Pass 【TVM】通过代码学习编译流程【4】BuildRelay 【AI编译】Tiling操作能优化什么时间 【TVM】通过代码学习编译流程【3】模型编译 【TVM】通过代码学习编译流程【2】模型转换 【TVM】通过代码学习编译流程【1】必要知识 【感想】写作进度报告1 【Winograd】卷积加速算法原理及实现 SystemC 等待异步事件解决方案 【TVM】Python脚本实现模型编译和保存 【推理引擎】常见AI推理框架 【3D建模】T110E3卡迪夫蓝调皮肤模型 【TVM】C++部署运行TVM 【推理引擎】NCNN和Tengine量化推理逻辑对比 【3D建模】IS-7攻城锤流纹岩皮肤展示 【TVM】根据例子走通代码库 博客汇总目录 【Im2Col】卷积加速算法【2】NHWC 【Im2Col】卷积加速算法【1】 NCHW openBlas库的安装与简单使用 C语言工程调用Cpp库解决方案 foo Hello World
【Tengine】推理流程脑图【1】
Post author: XianMu@Пусть этот камень будет более крепким, чем ч · 2025-04-24 · via Пусть этот камень будет более крепким, чем человек

# 前言

本篇通过流程脑图和代码介绍 Tengine 推理引擎的推理流程。本篇是第一部分。Tengine 工程地址

作为初学者,错误在所难免,还望不吝赐教。

# 介绍

Tengine

Tengine 由 OPEN AI LAB 主导开发,该项目实现了深度学习神经网络模型在嵌入式设备上的快速、高效部署需求。为实现在众多 AIoT 应用中的跨平台部署,该项目使用 C 语言进行核心模块开发,针对嵌入式设备资源有限的特点进行了深度框架裁剪。同时采用了完全分离的前后端设计,有利于 CPU、GPU、NPU 等异构计算单元的快速移植和部署,降低评估、迁移成本。

# 推理流程

不了解 AI 推理引擎的人,可能难以理解推理引擎做了哪些工作。所以我画了一张流程图,该流程图介绍了 Tengine 推理引擎在推理神经网络的时候做了哪些事情。通过这张图,不仅能全局掌握 Tengine 的推理流程,还能对推理引擎有更深刻的认识。

直接上图:

Tengine推理流程图

图中是一大批函数名字和他们之间的链接关系。我们先从左边入手,左边红色连线分别是 init_tengine()Create_graph()prerun_graph_multithread()run_graph()get_graph_output_tensor()postrun_graoh()destroy_graph() 。这些函数名通俗易懂,我们挨个来描述他们的详细功能。

# init_tengine()

init_tengine推理流程图

顾名思义,该函数完成推理引擎的初始化。分为三个步骤:注册算子原型、注册序列化工具、注册设备。

# 1. 注册算子原型:register_all_op_prototype ()

该函数将在编译的过程中生成在 build 文件夹里。该函数将调用一百多个算子原型的注册函数。如下:

int register_all_op_prototype(){
    ...
    ret = register_argmax_op();
    ret = register_const_op();
    ret = register_convolution_op();
    ret = register_crop_op();
    ret = register_deconvolution_op();
    ...
}

以注册卷积算子为例, register_convolution_op() 函数注册了卷积算子对应的初始化函数 init_op 和释放函数 release_op

int register_convolution_op()
{
    ir_method_t m;
    m.version = 1;
    m.init = init_op;
    m.release = release_op;
    return register_op(OP_CONV, OP_CONV_NAME, &m);
}

初始化函数 init_op 为卷积参数 conv_param 开辟空间(保存 kernel shape、pad 等信息),同时注册了维度推理函数 infer_shape (根据输入 tensor 和 kernel 维度推理输出 tensor 维度)。

# 2. 注册序列化工具:register_all_serializer ()

它调用了两个函数。

1. register_tm2_serializer() ,就是注册序列化 tmfile 模型文件的工具。该工具静态结构体 tm2_serializer 如下所示,可用来读取内存,加载模型等。

static struct tm2_serializer tm2_serializer = {
    .base = {
        .get_name = get_name,
        .load_model = load_model,
        .load_mem = load_mem,
        .unload_graph = unload_graph,
        .register_op_loader = register_op_loader,
        .unregister_op_loader = unregister_op_loader,
        .init = init_tm2_serializer,
        .release = release_tm2_serializer,
    },
    .loader_list = NULL,
};

2. register_all_tm2_ops() 函数用于注册所有算子的加载工具。不同的算子参数不同,数据不同,需要注册不同的加载函数。

int register_all_tm2_ops(){
    ...
    ret = register_tm2_concat_op();
    ret = register_tm2_conv_op();
    ret = register_tm2_crop_op();
    ...
}

以卷积算子为例, register_tm2_conv_op() 函数的内容是:调用前述静态结构体 tm2_serializerregister_op_loader() 函数,将卷积算子的加载函数 tm2_load_conv 注册进去,用于模型中卷积节点的加载。

# 3. 注册设备:register_all_devices ()

作为支持多平台设备的推理引擎,设备管理也必不可少。编译阶段需要指定目标设备,我们以 CPU 为例,该函数将调用 register_cpu_device() 来注册 CPU 设备。

cpu_device 是个静态结构体,其包含了接口 interface 、分配器 allocator 、优化器 optimizer

static struct cpu_device cpu_dev = {
    .base = {
        .name = CPU_DEVICE_NAME,
        .interface = &cpu_interface,
        .allocator = &cpu_allocator,
        .optimizer = &cpu_optimizer,
        .scheduler = NULL,
        .privacy = NULL,
    },
    .master_cpu = 0,
    .cpu_model = 0,
};

着重看一下 CPU 设备的接口,接口 cpu_interface 也是一个静态结构体:

static struct interface cpu_interface = {
    .init = init_cpu,
    .pre_run = prerun,
    .run = run,
    .post_run = postrun,
    .async_run = NULL,
    .async_wait = NULL,
    .release_graph = cpu_dev_release_exec_graph,
    .release_device = release_cpu,
};

接口包含 CPU 设备初始化 init 、预运行 pre_run 、运行 run 、后运行 post_run

当前会调用 CPU 设备初始化 init ,其余的会在后续调用到。

CPU 设备初始化函数 init_cpu 会调用 register_all_cpu_ops() 函数,来注册所有 CPU 算子实现。

int register_all_cpu_ops(){
    ...
    ret = register_concat_ref_op();
    ret = register_conv_ref_op();
    ret = register_conv_dw_hcl_x86_op();
    ret = register_conv_hcl_x86_op();
    ret = register_crop_ref_op();
    ...
}

从这段代码中看到,卷积算子的推理方式注册了三个。这是因为即使同一个设备的同一个算子,也可能有不同的实现方法,有些推理方法速度更快,但是有限制条件。所以具体使用哪个方法,会在后续流程中介绍。

# Create_graph()

Create_graph推理流程图

该函数完成模型图结构的创建过程。

# 1. 创建上下文:create_context ()

Context 是图执行的上下文,它会绑定调度器、设备等信息。这里不过多解释。

typedef struct context
{
    char* name;
    struct scheduler* scheduler; 
    struct device* device;       
    void* default_options;       
    void* device_options;        
} ir_context_t;

# 2. 创建图:create_ir_graph ()

该函数主要创建一个新的图,并调用 init_ir_graph() 初始化一些信息,如图的节点数量、tensor 数量、输入输出等,做的事情相当有限。

# 3. 加载图结构:load_mem ()

通过 find_serializer_via_name() 函数找到前述的序列化工具 serializer ,调用其
运行序列化工具的 load_mem() 函数,解析 tmfile 文件。其中 load_graph 函数会依次调用加载 tensor load_graph_tensors() 、加载节点 load_graph_nodes() 、加载输入输出节点 load_graph_io_nodes() 、加载子图信息 load_graph_sub_info()

后半部分的流程介绍将在下一篇完成。

# 后记

本博客目前以及可预期的将来都不会支持评论功能。各位大侠如若有指教和问题,可以在我的 github 项目 或随便一个项目下提出 issue,并指明哪一篇博客,我看到一定及时回复!