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

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LINUX DO - 最新话题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Forbes - Security
Forbes - Security
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
W
WeLiveSecurity
Jina AI
Jina AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
N
News and Events Feed by Topic
V
V2EX
Stack Overflow Blog
Stack Overflow Blog
Engineering at Meta
Engineering at Meta
PCI Perspectives
PCI Perspectives
Martin Fowler
Martin Fowler
T
The Exploit Database - CXSecurity.com
F
Full Disclosure
WordPress大学
WordPress大学
S
Security Affairs
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
S
SegmentFault 最新的问题
P
Privacy International News Feed
IT之家
IT之家
M
MIT News - Artificial intelligence
G
GRAHAM CLULEY
Hacker News: Ask HN
Hacker News: Ask HN
D
DataBreaches.Net
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
Check Point Blog
美团技术团队
Security Latest
Security Latest
Cyberwarzone
Cyberwarzone
N
News and Events Feed by Topic
MyScale Blog
MyScale Blog
H
Help Net Security
宝玉的分享
宝玉的分享
The Hacker News
The Hacker News
The Last Watchdog
The Last Watchdog
The Cloudflare Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
爱范儿
爱范儿
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
I
Intezer
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
AI
AI
I
InfoQ
N
News | PayPal Newsroom
TaoSecurity Blog
TaoSecurity Blog

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

【琐记】烟火与尘埃 【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】 【Tengine】推理流程脑图【1】 【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】模型转换 【感想】写作进度报告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
【TVM】通过代码学习编译流程【1】必要知识
Post author: XianMu@Пусть этот камень будет более крепким, чем ч · 2024-10-10 · via Пусть этот камень будет более крепким, чем человек

# 前言

本系列文章将从代码和流程图入手,详细介绍 TVM AI 编译器的编译流程。本文章为第一篇,取名为 “必要知识”,约等于 “大杂烩”。食之无味,弃之可惜。但基于我个人的主观喜好和偏见,这些知识值得在整个代码讲解之前声明。

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

# 工程结构

TVM 主要由 C++ 语言和 Python 语言实现。

  • a.TVM C++ 后端核心代码 位于 /home/user/tvm/src
    C++ 后端核心代码的功能是生成 libtvm.so libtvm_runtime.so,分别是模型编译过程中的需要的 libtvm.so 库,和模型部署运行时需要的 libtvm_runtime.so 库。对应的头文件位于 /home/user/tvm/include.

    • 1. 其中 src/runtime 是模型部署相关 CPP 文件
      • src/runtime/graph_executor 最基本的图执行器
      • src/runtime/module.cpp 运行时 Module 基类
      • src/runtime/contrib BYOC 第三方设备运行及实现 包括 dnnl cblas cudnn ethosu 等等
      • srd/runtime/cuda CUDA 运行时 Module
      • 还有其他设备的运行时 Module 如 opencl hexagon metal 等,以及一些接口文件
    • 2.src/relay 是 TVM 高级中间表示 IR 的相关 CPP 文件
    • 3.src/relax TVM 正在发展的高级中间表示 IR,功能上等同于 Relay
    • 4.src/te TVM 的 TE 表达式
    • 5.src/topi 算子的计算定义和后端调度
    • 6.src/tir TVM 低级中介表示 IR,接近于硬件表示
    • 7.src/auto_shedule TVM 自动优化调度相关
  • b. TVM Python 前端代码 位于 /home/user/tvm/python
    Python 前端代码为 C++ API 和执行编译的驱动代码,提供 Python 绑定。

表面上看 TVM 工程应当是 Python 前端调用 C++ 后端生成的 libtvm.so libtvm_runtime.so ,实际上 TVM 支持 Python 和 C++ 的相互调用。例如一些算子的 compute 计算公式和 schedule 调度位于 Python 代码中,由 C++ 进行调用。

在编译阶段,开发者编写 Python 代码,调用 TVM Python 前端,而 TVM 的 Python 前端又依赖于 C++ 后端生成的 libtvm.so libtvm_runtime.so 动态库。

部署运行阶段即可以编写 Python 来执行,也可以直接编译 C++ 为可执行文件,参考 TVM C++ 部署

# 编译

编译过程可以参考 TVM 英文文档和中文文档。文档中内容全面,这里只摘必要步骤,是最简单的部署安装方式。

1. 编译 libtvm.so libtvm_runtime.so

mkdir build  
cp cmake/config.cmake ./build
    
cd build
cmake ..
    
make -j32

2. 配置临时运行环境

个人喜欢用临时环境运行项目,可以避免 .bashrc 文件中添加过多环境路径;特别是开发人员有多个 TVM 项目的时候,可以避免项目的混淆。

export PATH=/home/user/tvm/build:$PATH
export PYTHONPATH=/home/user/tvm/python:${PYTHONPATH}
python3 ***.py

大概从事工程项目开发的人员对 Object, ObjectPtr, ObjectRef 等写法相对熟悉,但是没有相关经验的算法研究人员,还是先认识一下 TVM 中的这三个基类。

TVM 中大部分类都继承自三大基础类 Object, ObjectPtr, ObjectRef。想多了解一下的话,可以学习博客 TVM: Object, ObjectPtr, ObjectRef (以 tir.sch 为例)

可能比较粗显的总结一下:TVM 中以 "Node" 结尾的类是 Object 的派生类,去掉 "Node" 的类是 ObjectRef 的派生类,Object 的派生类负责 "做事",ObjectRef 的派生类方便程序员引用,ObjectPtr 是桥梁。但总之这三者是一个东西(刚学时我就被这搞晕了:( )。

举例说明如何使用 TVM 的三大基础类构造对象:

class Anode: public tvm::runtime::Object{   
    public:
        Anode(){};
        ~Anode(){};
        std::string a(){return "instance";}
};
class A: public tvm::runtime::ObjectRef{       
    public:    
    TVM_DEFINE_MUTABLE_OBJECT_REF_METHODS(A, tvm::runtime::ObjectRef, Anode);
}; 
int main(){    
   tvm::runtime::ObjectPtr<Anode> n = tvm::runtime::make_object<Anode>();  
   A ref(std::move(n));  
   ref->a();          
   
}

Object 应用例子

可以再看一下 TVM 工程中的例子,这段代码创建了本体 CallNode ,通过 make_object 生成桥梁 ObjectPtr<CallNode> ,最后赋值给指针 Calldata_ 字段。

# Python 和 C++ 相互调用

TVM 实现了 FFI (Foreign Function Interface) 机制,目标是使得任意语言下定义的函数都可以被任意其他语言调用。

宏 TVM_REGISTER_GLOBAL

 * \brief Register a function globally.
 * \code
 *   TVM_REGISTER_GLOBAL("MyPrint")
 *   .set_body([](TVMArgs args, TVMRetValue* rv) {
 *   });
 * \endcode
 */
 #define TVM_REGISTER_GLOBAL(OpName) \
  TVM_STR_CONCAT(TVM_FUNC_REG_VAR_DEF, __COUNTER__) = ::tvm::runtime::Registry::Register(OpName)

在 C++ 后端同过 “TVM_REGISTER_GLOBAL” 这个宏将函数注册为全局函数,该全局函数的类型为 PackedFunc。

TVM_REGISTER_GLOBAL("tvm.graph_executor_factory.create")  
    .set_body([](TVMArgs args, TVMRetValue* rv) {      
        *rv = Module(exec);
    });

在 Python 前端可以通过 get_global_func () 函数来获取全局函数 PackedFunc 并执行

fcreate = get_global_func("tvm.graph_executor_facttory.create")
self.module = fcreate(graph_json_str, libmod, libmod_name, *args)

在 C++ 端也可以通过名字获取 全局函数 PackedFunc

PackedFunc pf = it.GetFunction(name)

python 端有大量如下类似代码,将有相同后缀的 PackedFunc 注册到 Python 端

"""FFI APIs for tvm.ir"""
import tvm._ffi
tvm._ffi._init_api("ir", __name__)

Python 端获取并执行 PackedFunc

_ffi_api.Module_UpdateGlobalInfo(self, name, global_info)

# 后记

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