code:https://github.com/OAID/Tengine
图片,代码都来自以上项目。
1. 简介
Tengine 由 OPEN AI LAB 主导开发,该项目实现了深度学习神经网络模型在嵌入式设备上的快速、高效部署需求。为实现在众多 AIoT 应用中的跨平台部署,本项目使用 C 语言进行核心模块开发,针对嵌入式设备资源有限的特点进行了深度框架裁剪。同时采用了完全分离的前后端设计,有利于 CPU、GPU、NPU 等异构计算单元的快速移植和部署,降低评估、迁移成本。
2. Content
因为Tengine是由C语言开发的,和ncnn,mnn等用C++开发的框架有一定的区别。因为只能用函数,所以op,serializer(模型解析器)等的注册都是要在程序的时候进行的。而且对op,serializer等组织需要使用函数指针来模拟C++的多态性。
这里对op的注册机制进行解读。
首先给出数据结构之间的关系图:
2.1 流程
这里只是对op_method
和op_name
的注册梳理,以absval
的注册为例
- 定义好
absval
的op_method
和op_name
struct method m;
m.version = 1;
m.init = init_op;
m.release = release_op; return register_op(OP_ABSVAL, OP_ABSVAL_NAME, &m);
- 初始化
static vector_t* internal_op_method_registry
和static vector_t* internal_op_name_registry
这里可以就着上面的关系图进行梳理
这里最外面的容器是vector_t
, 然后vector_t
中mem
才是指向注册数据的位置。mem
指向8个vector_entry_t
空间(初始为8个,如果不够了按8个递增申请),valid
指示数据是否写入,这里的unsigned char data[]
指明method
,op_name
在内存的初始位置。后面在使用的时候,就在internal_op_method_registry
和internal_op_name_registry
去找。
vector_t* v &#61; (vector_t*)sys_malloc(sizeof(vector_t));if (v &#61;&#61; NULL){return NULL;}v->elem_num &#61; 0;v->elem_size &#61; elem_size;v->free_func &#61; free_data;v->entry_size &#61; align(elem_size &#43; (int)sizeof(vector_entry_t), TE_VECTOR_ALIGN_SIZE); v->ahead_num &#61; 8; v->space_num &#61; v->ahead_num;v->real_mem &#61; sys_malloc(v->entry_size * v->space_num &#43; TE_VECTOR_ALIGN_SIZE); v->mem &#61; align_address(v->real_mem, TE_VECTOR_ALIGN_SIZE); for (int i &#61; 0; i < v->space_num; i&#43;&#43;){vector_entry_t* e &#61; get_vector_entry(v, i); e->valid &#61; 0; }return v;
- 注册
op_name
下面的 push_vector_data , 会用 memcpy 把栈上的数据内容 copy 到已申请的堆内存上memcpy(e->data, data, v->elem_size);
ir_op_name_entry_t op_map;op_map.type &#61; type;op_map.name &#61; name;return push_vector_data(internal_op_name_registry, &op_map);
- 同理注册
method
这里在注册前会internal_op_method_registry
遍历&#xff0c;看是否已经注册
static int register_op_registry(ir_method_t* method)
{if (find_op_method(method->type, method->version)) {return -1;}return push_vector_data(internal_op_method_registry, method);
}
总结
- 总结起来就是把各个
op
的ir_method_t
数据保存到internal_op_method_registry
&#xff0c; ir_op_name_entry_t
数据保存到internal_op_name_registry
- 对照着上面的数据关系图来梳理