摘要
在计算图类项目中,不同模块对图节点、边的描述格式不统一,会导致数据交互成本高。CANN生态下的metadef仓库,是一套专注计算图元数据标准化定义的工具库,通过统一的结构体与接口,规范图节点、图结构的描述格式,降低跨模块图数据交互的复杂度。本文从代码结构、核心元定义实现、图构建示例三个维度,解读metadef的实用价值。
一、metadef仓库的定位:计算图的"统一描述器"
metadef是CANN生态中负责计算图元数据标准化定义的工具库,核心解决"跨模块图数据格式不兼容"的问题------通过预定义图节点、图结构的结构体,统一图元素(节点类型、输入输出、属性)的描述规则,让不同模块(如图优化、图执行)能基于同一套格式交互图数据。
其核心能力包括:
- 统一图节点的元数据结构(类型、参数、输入输出);
- 提供图结构的基础描述接口(节点添加、属性查询);
- 轻量无依赖,可直接嵌入各类计算图项目。
二、metadef的代码架构:极简元定义集合
metadef采用"结构定义+基础接口"的轻量架构,代码聚焦元数据描述,无冗余逻辑:
metadef/
├── include/ # 接口头文件:预定义图元数据结构
│ └── metadef_graph.h
├── src/ # 实现层:图元数据的基础操作接口
│ └── metadef_graph.c
└── examples/ # 集成示例:用metadef构建简单计算图
└── graph_meta_demo.c
三、核心实现:图元数据的标准化定义
以下是metadef中核心图元数据结构的代码逻辑:
1. 接口定义(include/metadef_graph.h)
c
#ifndef METADEF_GRAPH_H
#define METADEF_GRAPH_H
#include <stddef.h>
// 图节点类型枚举
typedef enum {
NODE_TYPE_ADD, // 加法节点
NODE_TYPE_MUL, // 乘法节点
NODE_TYPE_UNKNOWN
} NodeType;
// 图节点元数据结构体
typedef struct {
char name[32]; // 节点名称
NodeType type; // 节点类型
size_t in_num; // 输入端口数
size_t out_num; // 输出端口数
float params[8]; // 节点参数(如乘法系数)
} GraphNode;
// 计算图结构体
typedef struct {
GraphNode *nodes; // 节点数组
size_t node_cnt; // 节点数量
size_t max_nodes; // 最大节点容量
} GraphMeta;
/**
* @brief 创建计算图元数据结构
* @param max_nodes 图的最大节点数
* @return 图元数据句柄,失败返回NULL
*/
GraphMeta* metadef_graph_create(size_t max_nodes);
/**
* @brief 向图中添加节点
* @param graph 图元数据句柄
* @param node 待添加的节点
* @return 0表示成功,-1表示节点数已满
*/
int metadef_graph_add_node(GraphMeta* graph, const GraphNode* node);
/**
* @brief 获取图中指定节点
* @param graph 图元数据句柄
* @param idx 节点索引
* @return 节点指针,失败返回NULL
*/
GraphNode* metadef_graph_get_node(GraphMeta* graph, size_t idx);
/**
* @brief 销毁图元数据结构
* @param graph 图元数据句柄
*/
void metadef_graph_destroy(GraphMeta* graph);
#endif // METADEF_GRAPH_H
2. 核心实现(src/metadef_graph.c)
c
#include "metadef_graph.h"
#include <string.h>
#include <stdlib.h>
GraphMeta* metadef_graph_create(size_t max_nodes) {
if (max_nodes == 0) return NULL;
GraphMeta* graph = malloc(sizeof(GraphMeta));
graph->nodes = calloc(max_nodes, sizeof(GraphNode));
graph->node_cnt = 0;
graph->max_nodes = max_nodes;
return graph;
}
int metadef_graph_add_node(GraphMeta* graph, const GraphNode* node) {
if (!graph || !node || graph->node_cnt >= graph->max_nodes) {
return -1;
}
memcpy(&graph->nodes[graph->node_cnt], node, sizeof(GraphNode));
graph->node_cnt++;
return 0;
}
GraphNode* metadef_graph_get_node(GraphMeta* graph, size_t idx) {
if (!graph || idx >= graph->node_cnt) {
return NULL;
}
return &graph->nodes[idx];
}
void metadef_graph_destroy(GraphMeta* graph) {
if (graph) {
free(graph->nodes);
free(graph);
}
}
四、集成示例:用metadef构建计算图元数据
c
#include <stdio.h>
#include "metadef_graph.h"
int main() {
// 创建最大容量为2的计算图
GraphMeta* graph = metadef_graph_create(2);
if (!graph) {
printf("图元数据结构创建失败!\n");
return -1;
}
// 定义加法节点
GraphNode add_node = {
.name = "add_node1",
.type = NODE_TYPE_ADD,
.in_num = 2,
.out_num = 1
};
// 添加到图中
if (metadef_graph_add_node(graph, &add_node) != 0) {
printf("添加加法节点失败!\n");
metadef_graph_destroy(graph);
return -1;
}
// 获取节点并打印信息
GraphNode* node = metadef_graph_get_node(graph, 0);
printf("图节点信息:\n");
printf("名称:%s\n", node->name);
printf("类型:%s\n", node->type == NODE_TYPE_ADD ? "加法" : "未知");
metadef_graph_destroy(graph);
return 0;
}
五、总结
metadef通过标准化的图元数据结构,让计算图的描述格式在不同模块间统一,避免了自定义格式带来的兼容问题。其轻量无依赖的特性,可快速嵌入各类计算图相关项目,是降低跨模块交互成本的实用工具。
相关链接
- CANN组织链接:https://atomgit.com/cann
- metadef仓库链接:https://atomgit.com/cann/metadef