# RefactorGraph **Repository Path**: testworkvm/RefactorGraph ## Basic Information - **Project Name**: RefactorGraph - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-04-15 - **Last Updated**: 2024-05-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 重构图表示 [![Build](https://github.com/InfiniTensor/RefactorGraph/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/InfiniTensor/RefactorGraph/actions) [![issue](https://img.shields.io/github/issues/InfiniTensor/RefactorGraph)](https://github.com/InfiniTensor/RefactorGraph/issues) ![license](https://img.shields.io/github/license/InfiniTensor/RefactorGraph) ## 目录 - [安装](#安装) - [使用前端](#使用前端) - [调试功能](#调试功能) - [项目结构](#项目结构) - [构建系统](#构建系统) - [子项目简介](#子项目简介) - [第三方依赖](#第三方依赖) - [技术要点](#技术要点) - [图拓扑抽象](#图拓扑抽象) ## 安装 使用 `make install-python` 编译并安装 Python 前端到全局,安装的包名为 `refactor_grpah`。 环境变量: - 添加 `TYPE=Debug` 或 `TYPE=Release` 以启用指定的优化级别,默认为 `Debug`; - 添加 `CUDA=OFF` 或 `CUDA=ON` 以打开或关闭英伟达显卡支持,默认为 `OFF`; ## 使用前端 ```python import sys import numpy as np from onnx import load from refactor_graph.onnx import make_compiler, find_device from onnxruntime import InferenceSession model = load(sys.argv[1]) # ------------------------------------ 加载模型 input = np.random.random((10, 3, 224, 224)).astype(np.float32) # 加载测试样本 compiler = make_compiler(model) # ------------------------------ 模型导入到编译器 compiler.substitute("N", 10) # --------------------------------- 代换输入中的变量 find_device("nvidia", 0) # ------------------------------------- 初始化指定加速硬件 executor = compiler.compile("cuda", "default", []) # ----------- 编译模型(选择平台、分配器和优化选项) executor.set_input(0, input) # --------------------------------- 设置输入 executor.dispatch(find_device("nvidia", 1), "default") # ------- 执行器可以随时调度到另一个硬件 executor.run() # ----------------------------------------------- 推理 session = InferenceSession(model.SerializeToString()) # -------- 与 onnxruntime 对比结果以验证推理 answer = session.run(None, {session.get_inputs()[0].name: input}) print([(executor.get_output(i) - answer[i]).flatten() for i in range(len(answer))]) ``` 对于使用外部数据的模型,支持直接加载以减少一次拷贝: ```python import sys from pathlib import Path from onnx import load from refactor_graph.onnx import make_compiler model_path = Path(sys.argv[1]) # ---------------------------- 假设模型和数据保存在相同路径 model = load(model_path.as_uri(), load_external_data=False) # 不直接加载外部数据以避免额外拷贝 compiler = make_compiler(model, model_path.parent.as_uri()) # 导入时直接加载外部数据 executor = compiler.compile("cuda", "default", []) # -------- 编译模型 # 下同 ``` ### 调试功能 项目现已依托前端提供多种调试功能。 1. 列出算子信息 ```python executor.dbg() ``` 2. 保存运行中间结果 ```python executor.trace("path_to_store_files", "data_file_format") ``` 调用这个方法将启动一次模型推理,并在每个算子推理完成后将算子的所有输入输出张量保存到 `path_to_store_files` 参数指示的目录中。 如果目录不存在,将创建此目录。每个张量保存到一个文件,已存在的同名文件将被删除。 同时,为每个算子创建一个元信息文本文件,命名为 `node.meta`,其内容具有下述格式: ```plaintext \t \t\t\t[FileName] ``` - `NodeName`: 节点的名字; - `N`: 节点序号; - `input/output`: 张量是节点的输入/输出; - `K`: 输入/输出的序号; - `EdgeName`: 张量的名字; - `FileName`: (optional) 数据文件名。如果张量无效,不会保存数据文件,则文件名为空; 3. 逐算子计时 ```python executor.bench() ``` 对每次推理计时。`sync` 是一个指示是否在每次推理后插入同步的布尔参数,若设置为 `False`,则计时可能是推理异步启动的时间。 ## 项目结构 ### 构建系统 项目构建系统采用 CMake,方便集成一些第三方库。所有第三方库以 git submodule 的形式导入,公共的位于根目录下的 [3rd-party](/3rd-party/) 目录下,另有专用于 python 前端的 pybind11 位于 [src/09python_ffi](/src/09python_ffi/) 目录下。 整个项目的源码以子项目的形式解耦,放在 `src` 的子目录中,每个子项目有自己的 `CMakeLists.txt`,并由根目录的 `CMakeLists.txt` 调用。src 的每个子目录带有一个编号,其中编号大的可以依赖编号小的,方便维护子项目之间的依赖关系,避免循环依赖。当前已有 00-09 共 10 个子项目,它们之间的依赖关系如下图所示: ```plaintext ┌─────────┐ ┌──────────────┐ ┌───────────┐ ┌──────────┐ │ 00cmmon ├←┤ 01graph_topo ├←┤ 03runtime ├←┤ 04kernel │ └───┬─────┘ └──────────────┘ └─────┬─────┘ └─────┬────┘ ↑ │ ↑ │ ┌───────────────┐ │ ┌───────┴───────┐ └───────┤ 02mem_manager ├←─────┘ │ 05computation │ └───────────────┘ └───────┬───────┘ ┌────────────────────────────────────────────┐ ↑ │ ┌──────────────┐ ┌────────┐ ┌────────────┐ │ │ │ │ 09python_ffi ├→┤ 07onnx ├→┤ 06frontend ├─┼───┘ │ └─────┬────────┘ └────────┘ └──────┬─────┘ │ │ │ ┌─────────────────┐ ↑ │ │ └────→┤ 08communication ├────┘ │ │ frontend └─────────────────┘ │ └────────────────────────────────────────────┘ ``` 所有子项目使用 `PUBLIC` 依赖向下传递自己依赖,并使用 CMake 的 `target_include_directories` 机制使子项目头文件目录随依赖关系传递。 操作 CMake、构建目录和其他项目管理功能的命令和配置封装在根目录下的 `Makefile` 中,现有的命令包括: - `build`: 默认命令,构建项目。 - `install-python`: 将 Python 前端安装到系统路径。 - `reconfig`: 清除 CMake 缓存,以重新配置 CMake。 - `clean`: 删除构建目录。 - `clean-log`: 清除日志目录。 - `test`: 执行单元测试。 - `format`: 调用格式化工具。 ### 子项目简介 源码的 10 个子项目的简介如下: | 序号 | 项目 | 说明 |:---:|:----:|:- | 0 | [`common`](/src/00common/README.md) | 用于所有子项目的类型和函数定义。 | 1 | [`graph_topo`](/src/01graph_topo/README.md) | 与元素类型解耦的图拓扑结构表示,包括存储结构和变换算法。 | 2 | [`mem_manager`](/src/02mem_manager/README.md) | 存储空间管理抽象。 | 3 | [`runtime`](/src/03runtime/README.md) | 运行时,执行模型推理的图层。 | 4 | [`kernel`](/src/04kernel/README.md) | 核函数层,包含核函数库以及从核函数图层下降到运行时图层的算法。 | 5 | [`computation`](/src/05computation/README.md) | 计算图层,包含算子的语义表示定义,以及在算子语义层次进行图变换的规则定义。 | 6 | [`frontend`](/src/06frontend/README.md) | 前端图层,支持混合存储不同编程框架导入的前端算子,以及基于前端算子的张量形状推导和动态性消解、常量折叠机制。从前端图层下降到计算图层时,图中的动态性(即输出形状的计算还和形状中的变量)必须全部消解。 | 7 | [`onnx`](/src/07onnx/README.md) | onnx 前端算子库。 | 8 | [`communication`](/src/08communication/README.md) | 分布式通信算子库。 | 9 | [`python_ffi`](/src/09python_ffi/README.md) | Python 前端项目。 点击项目名可以跳转到各个项目的文档。 ### 第三方依赖 - [fmt 10.1.1](https://github.com/fmtlib/fmt/releases/tag/10.1.0) - [fmtlog v2.2.1](https://github.com/MengRao/fmtlog/releases/tag/v2.2.1) - [googletest v1.14.0](https://github.com/google/googletest/releases/tag/v1.14.0) - [backward-cpp master](https://github.com/bombela/backward-cpp) - [result master](https://github.com/willowell/result) - [abseil-cpp 20230802.1](https://github.com/abseil/abseil-cpp/releases/tag/20230802.1) ## 技术要点 ### 多层计算图表示 目前主流的深度学习框架几乎都应用了两种基本的设计,即计算图和多层 IR,本框架也应用了这两种设计。 计算图是 AI 模型计算的一种表示形式。在 AI 模型的高层表示中,通常使用以算子为节点、张量为边的图结构来表示模型,例如,ONNX 模型可视化后通常表现为这样的形式: ![onnx model](/docs/images/README-1.png) 计算图的本质在逻辑上是一张数据流图,在数据结构上是一张有向无环图。数据流图意味着其中的节点表示一种运算的过程,而边表示在数据在运算之间流动的起点和终点。与经典的数据结构意义上的有向无环图相比,计算图中节点的输入和输出是有序的,不可互换,例如某个节点入度为 3 不是对节点输入的完备描述,必须说明第 0 个、第 1 个、第 2 个入边分别是什么。 产品级的 AI 编译器总是具有较长的工作流程。首先,模型从多种框架的高层表示(Pytorch/ONNX/……)转化到编译器定义的计算图形式,然后应用各种图上的变换,在确定的硬件上选择合适的计算方法(kernel),最后实际执行。在流程的不同阶段,需要关注和维护的信息是不同的。举例来说,`Reshape` 算子表示改变张量形状的语义,在高层的模型表示中是必要的,但在 AI 应用程序实际执行时,`Reshape` 算子不会真正改变数据,甚至可以直接从图上删除。因此,最好使用多层 IR 表示模型,在不同的层级改变关注的信息,从而降低每层的复杂度。 ### 图拓扑抽象 灵活的多层 IR 表示要求层与层之间尽量使用无关的节点和边类型,以保证每层的自由设计,同时要尽量复用拓扑结构的表示,因为无论在哪一层,图结构的表示和操作方法是类似的,因此,本框架采用了拓扑结构与节点/边信息解耦的实现方式。拓扑结构以一系列模板类型的形式定义在 `graph_topo` 子项目中。这些拓扑结构表示被定义成类似容器类型的形式,只包含关键的节点和边的有向无环、出入有序的基本信息,对节点和边具体是什么没有约束,从而支持在不同的计算图中复用这些容器,并能在不与编译器的业务耦合的情况下编写、优化和测试,具有良好的工程特性。 目前,图拓扑表示包含以下主要的类型定义: - `GraphTopo`: 精简、连续存储的拓扑类型,用于持久化存储和、遍历和快速随机访问; - `Searcher`: 基于 `GraphTopo` 引用建立的查询缓存结构,用于包含图上一些冗余但常用的信息,使这些信息不必一直随着拓扑结构移动或拷贝; - `Builder`: 所有字段都公开可访问的结构体类型,可以表示拓扑结构并支持开发者自由操作,用于快速构建拓扑结构,并提供一个方法将拓扑信息压缩,转化成 `GraphTopo`; - `LinkedGraph`: 链式的拓扑表示,在这种表示中修改拓扑连接关系、增删节点具有 `O(1)` 时间复杂度,但空间复杂度更高、不保证维持拓扑序,访问时也更容易缓存不命中; 参考子项目依赖关系图,几乎所有依赖 `graph_topo` 的子项目(除了前端算子库和接口层)都定义了一套最适于表示其信息的节点和边定义,并复用上述拓扑结构类型来表示一种特定的计算图。