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

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Azure Blog
Microsoft Azure Blog
Cloudbric
Cloudbric
I
InfoQ
V
V2EX
博客园_首页
The Register - Security
The Register - Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
S
Secure Thoughts
Vercel News
Vercel News
Forbes - Security
Forbes - Security
云风的 BLOG
云风的 BLOG
PCI Perspectives
PCI Perspectives
L
LINUX DO - 最新话题
D
DataBreaches.Net
H
Hacker News: Front Page
Application and Cybersecurity Blog
Application and Cybersecurity Blog
B
Blog RSS Feed
A
About on SuperTechFans
N
News and Events Feed by Topic
Apple Machine Learning Research
Apple Machine Learning Research
Help Net Security
Help Net Security
Attack and Defense Labs
Attack and Defense Labs
N
Netflix TechBlog - Medium
Spread Privacy
Spread Privacy
F
Full Disclosure
Recorded Future
Recorded Future
AWS News Blog
AWS News Blog
博客园 - 【当耐特】
The Cloudflare Blog
T
Threatpost
T
Tor Project blog
Google DeepMind News
Google DeepMind News
C
CXSECURITY Database RSS Feed - CXSecurity.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Recent Announcements
Recent Announcements
M
MIT News - Artificial intelligence
A
Arctic Wolf
C
Check Point Blog
Stack Overflow Blog
Stack Overflow Blog
T
Threat Research - Cisco Blogs
Security Archives - TechRepublic
Security Archives - TechRepublic
Hacker News - Newest:
Hacker News - Newest: "LLM"
WordPress大学
WordPress大学
Cyberwarzone
Cyberwarzone
小众软件
小众软件
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Proofpoint News Feed
Security Latest
Security Latest
The Last Watchdog
The Last Watchdog

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

【琐记】烟火与尘埃 【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,并指明哪一篇博客,我看到一定及时回复!