AI编译器的后端优化策略

背景

        工作领域是AI芯片工具链相关,很多相关知识的概念都是跟着项目成长建立起来,但是比较整个技术体系在脑海中都不太系统,比如项目参与中涉及到了很多AI编译器开发相关内容,东西比较零碎,工作中也没有太多时间去做复盘与查漏补缺。但是最近比较闲,发现了一个宝藏级的B站博主,系统的讲了很多AI芯片领域的知识,并把课程资源开源维护,极力推荐大家多多关注。在这里当个搬运工,传播一下。

     

总结

后端优化与前端优化的区别
• 前端优化:输入计算图,关注计算图整体拓扑结构,而不关心算子的具体实现。在 AI 编译器的
前端优化,对算子节点进行融合、消除、化简等操作,使计算图的计算和存储开销最小。
• 后端优化:关注算子节点的内部具体实现,针对具体实现使得性能达到最优。重点关心节点的
输入,输出,内存循环方式和计算的逻辑。 

AI编译器后端部分:

  • 生成低级IR;
  • 后端优化;
  • 代码生成;

1)生成低级IR:不同 AI 编译器内部低级 IR 形式和定义不同,但是对于同一算子,算法的原理
实质相同。对于每个具体的算子,需要用AI编译器底层的接口来定义算法,再由编译器来生成
内部的低级IR。

2)后端优化:针对不同的硬件架构/微架构,不同的算法实现的方式有不同的性能,目的是找
到算子的最优实现方式,达到最优性能。同一算子不同形态如Conv1x1、 Conv3x3、 Conv7x7
都会有不同的循环优化方法。

3)代码生成:对优化后的低级 IR 转化为机器指令执行,现阶段最广泛的借助成熟的编译工具
来实现,非AI 编译器的核心内容。如把低级IR 转化成为 LLVM、NVCC 等成功编译工具的输入
形式,然后调用其生成机器指令。

优化策略

算子概念

算子:深度学习算法由一个个计算单元组成,我们称这些计算单元为算子(Operator,简称Op)。算子是一个函数空间到函数空间上的映射O:X→Y;从广义上讲,对任何函数进行某一项操作都可以认为是一个算子。于AI 框架而言,所开发的算子是网络模型中涉及到的计算函数。

算法:算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。

算子分类:

  • 访存密集型:如 RNN 训练任务,由于 RNN 网络模型结构的计算密度更低,瓶颈转移到host端的 Op Launch 上,因此kernel之间甚至出现了大量空白。对于访存密集型算子部分的工作来说,新硬件带来了更大的性能优化空间。
  • 计算密集型:计算密度是指一个程序在单位访存量下所需的计算量,单位是 FLOPs/Byte,计算密度较大,程序性能受硬件最大计算峰值(下文简称为算力)限制,称为计算密集型程序。

 算子优化的挑战:

  • 优化手段多样:要在不同情况下权衡优化及其对应参数,对于优化专家来说也是相当耗费精力
  • 通用性与移植性:不同类型的硬件架构差异,使得优化方法要考虑的因素也有很大不同
  • 优化间相互影响:各种优化之间可能会相互制约,相互影响。这意味着找到最优的优化方法组合与序列就是一个困难的组合优化问题,甚至是 NP 问题。

算子库:
• 目的:针对访存密集型和计算密集型的算子进行优化。对于一个算子,要实现正确的逻辑计算
或许不难,但要结合硬件能力达到高性能就比较难了,要达到极致的性能更是难上加难。
• 业界一个最为常见的方式是将预置的算子实现封装成计算库。如 CuDNN、CuBLAS、OpenBLA
S、Eigen 这样优秀的计算库。

算子计算与调度

• 计算是算子的定义,回答算子是什么,如何通过具体的算法得到正确的定义结果。
• 调度是算子的执行策略和具体实现,回答系统具体如何执行算子的计算定义。
• 同一算子会有不同的实现方式(即不同的调度方式),但是只会有一种计算形态(具体定义)。
• 计算实现(Function / Expression)和计算在硬件单元上的调度(Schedule)是分离。

        算子调度具体执行的所有可能的调度方式称为调度空间,AI 编译器优化的目的就是为算子提供一种最优的调度,使得算子在硬件上运行时间最优。

循环优化

循环展开Loop Unrolling

• 对循环进行展开,以便每次迭代多次使用加载的值,使得一个时钟周期的流水线上尽可能满负荷计算。在流水线中,会因为指令顺序安排不合理而导致NPU等待空转,影响流水线效率。循环展开为编译器进行指令调度带来了更大的空间。

循环分块 Loop tiling
• 由于内存空间有限,代码访问的数据量过大时,无法一次性将所需要的数据加载到设备内存,
循环分块能有效提高NPU cache 上的访存效率,改善数据局部性。
• 如果分块应用于外部循环,会增加计算的空间和时间局部性;分块应与缓存块一起作用,可以
提高流水线的效率。

• Loop Tiling 的目的是确保一个 Cache 在被用过以后,后面再用的时候其仍然在 cache 中。
实现思路:当一个数组总的数据量无法放在 cache 时,把总数据分成一个个 tile 去访问,令每
个 tile 都可以满足 Cache
具体做法:把一层内层循环分成 outer loop * inner loop。然后把 outer loop 移到更外层去,
从而确保 inner loop 一定能满足 Cache

在我之前写的博文CUDA编程的矩阵乘优化中,有一个优化思想就是循环分块。

循环重排 Loop Reorder
• 内外层循环重排,改善空间局部性,并最大限度地利用引入缓存的数据。对循环进行重新排序,
以最大程度地减少跨步并将访问模式与内存中的数据存储模式对齐

循环融合 Loop Fusion
• 循环融合将相邻或紧密间隔的循环融合在一起,减少的循环开销和增加的计算密度可改善软件
流水线,数据结构的缓存局部性增加。

循环拆分 Loop Split
• 拆分主要是将循环分成多个循环,可以在有条件的循环中使用,分为无条件循环和含条件循环。

指令优化

向量化 Vectorization

SIMD 寄存器先保持vec_sum的值,在reduction 步骤,,vec_sum 再逐个求总和。

张量化 Tensorization

• Volta 架构中,一个SM由8个FP64 Cuda Cores,16个INT32 Cuda Core,16个FP32 Cuda Core,和128个Tensor Core组成,一共有4个SM。

        主流CPU/GPU硬件厂商都提供了专门用于张量化计算的张量指令,如英伟达的张量核指令、
英特尔的VN。利用张量指令的一种方法是调用硬件厂商提供的算子库,如英伟达的cuBLAS和
cuDNN,以及英特尔的oneDNN等。然而,当模型中出现新的算子或需要进一步提高性能时,这种方法的局限性便显露无遗。

1. 新的硬件体系带来了超越向量运算的新指令集,调度必须使用这些指令才能从加速中获益
2. 张量计算基元的输入是多维的,具有固定的或可变的长度,并指示不同的数据布局
3. 新的 AI 加速器正以它们自己的张量指令出现

存储优化

访存延迟 Latency Hiding
• 延迟隐藏(Latency Hiding)是指将内存操作与计算重叠,最大限度地提高内存和计算资源利用
率的过程。

CPU:
• 延迟隐藏可以通过多线程,或者硬件隐式数据预取实现
GPU:
• 依赖于 Wrap Schedule 对多线程的管理调度和上下文切换实现
NPU/TPU:
• 采用解耦访问/执行(Decoupled Access/Execute,DAE)架构

内存分配

        传统编译器通过将内存逻辑划分为不同区段来提供程序员访问内存的权限(栈、堆、静态存储区),而每段空间都有各自的大小,一旦开发者在使用过程中将该大小耗尽,就会出现内存不足错误。
        AI芯片上内存分为:Shared Memory, Local Momory。如下是GPU chip的内存层级示意图:

自动调优

        AI编译器的Ato tuning是指对于给定的程序和目标架构,自动调优算法的方式找到最优的编译优化方法。需要考虑的问题是:使用哪些优化方法?选择什么参数集?用什么顺序应用优化方法以达到最佳性能?

步骤:

1) 参数化 Parameterization
2)成本模型 Cost Model
3)搜索算法 Search Algorithm

参数化 Parameterization:对调度优化问题进行建模,参数化优化空间一般由可参数化变换(Lo
op)的可能参数取值组合构成,因此需要调度原语进行参数化表示。Halide 将算法和调度解耦,
TVM 提供调度模板。

成本模型 Cost Model:用来评价某一参数化下的调度性能,根据对调度额评价来指导最搜索到
最优的调度策略。可以从运行时间、内存占用、编译后指令数来评价。实现方式主要有1)基
于NPU硬件的黑盒模型;2)基于模拟的预定义模型;3)ML-Base 模型,通过机器学习模型来
对调度性能进行预测

搜索算法 Search Algorithm:确定初始化和搜索空间后,在搜索空间找找到达到性能最优的参数
配置。常用的搜索算法有1)遗传算法、2)模拟退火算法、3)强化学习等。

系列:AI编译器的前端优化策略-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/245993.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【GitHub项目推荐--不错的Flutter项目】【转载】

01 可定制的图表库 FL Chart是一个高度可定制的 Flutter 图表库,支持折线图、条形图、饼图、散点图和雷达图 。 项目地址:https://github.com/imaNNeoFighT/fl_chart LineChart BarChart PieChart Sample1 Sample2 Sample3 …

element-ui 树形控件 通过点击某个节点,遍历获取上级的所有父节点和本身节点

1、需求&#xff1a;点击树形控件的某个节点&#xff0c;需要拿到它上级的所有父节点进行操作 2、代码&#xff1a; 树形控件代码 <el-tree:data"deptOptions"node-click"getVisitCheckedNodes"ref"target_tree_Speech"node-key"id&qu…

勤学苦练“prompts“,如沐春风“CodeArts Snap“

前言 CodeArts Snap 上手一段时间了&#xff0c;对编程很有帮助。但是&#xff0c;感觉代码编写的不尽人意。 我因此也感到困惑&#xff0c;想要一份完整的 CodeArts Snap 手册看看。 就在我感觉仿佛"独自彷徨在这条悠长、悠长又寂寥的雨巷"时&#xff0c;我听了大…

JVM系列-7内存调优

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术、JVM原理&#x1f525;如果感觉博主的文…

【学网攻】 第(10)节 -- 路由器单臂路由配置

系列文章目录 目录 系列文章目录 文章目录 前言 一、单臂路由是什么&#xff1f; 二、实验 1.引入 实验拓扑图 PC配置 Sw配置 Router配置 实验验证 总结 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交…

Windows打开IE浏览器命令最简单的方法

问题场景&#xff1a; 许多插件或特定版本的系统需要使用ie浏览器来访问&#xff0c;window默认的ie浏览器是被禁用的如何快速打开ie浏览器解决问题 目录 问题场景&#xff1a; 测试环境&#xff1a; 检查环境是否支持&#xff1a; 问题解决&#xff1a; 方法一 方法二 方法…

IO多路复用-epoll

IO多路复用-epoll 1. 概述 epoll 全称 eventpoll&#xff0c;是 linux 内核实现IO多路转接/复用&#xff08;IO multiplexing&#xff09;的一个实现。 epoll是select和poll的升级版&#xff0c;相较于这两个前辈&#xff0c;epoll改进了工作方式&#xff0c;因此它更加高效…

docker之部署青龙面板

青龙面板是一个用于管理和监控 Linux 服务器的工具&#xff0c;具有定时运行脚本任务的功能。在实际情况下也可以用于一些定期自动签到等任务脚本的运行。 本次记录下简单的安装与使用&#xff0c;请提前安装好docker&#xff0c;参考之前的文章。 一、安装部署 1、拉取镜像 # …

MySQL Connect

文章目录 前言一、Connector/C使用1、下载MySQL连接所需库第一种方法第二种方法 2、MySQL库链接3、MySQL接口介绍连接执行sql语句执行查询语句 前言 一、Connector/C使用 MySQL数据库的基础知识我们前面已经学习了&#xff0c;下面我们就开始学习怎么将MySQL数据库和我们学习的…

代码随想录算法刷题训练营day16

代码随想录算法刷题训练营day16&#xff1a;LeetCode(104)二叉树的最大深度 、LeetCode(559)n叉树的最大深度、LeetCode(111)二叉树的最小深度、LeetCode(222)完全二叉树的节点个数 LeetCode(104)二叉树的最大深度 题目 代码 /*** Definition for a binary tree node.* publ…

架构整洁之道-设计原则

4 设计原则 通常来说&#xff0c;要想构建一个好的软件系统&#xff0c;应该从写整洁的代码开始做起。这就是SOLID设计原则所要解决的问题。 SOLID原则的主要作用就是告诉我们如何将数据和函数组织成为类&#xff0c;以及如何将这些类链接起来成为程序。请注意&#xff0c;这里…

c++24.1.26嵌套if语句

嵌套if语句&#xff1a;if语句中的if语句 实践&#xff1a;

2024最新幻兽帕鲁服务器多少钱一个?

幻兽帕鲁服务器多少钱&#xff1f;价格便宜&#xff0c;阿里云4核16G幻兽帕鲁专属服务器32元1个月、66元3个月&#xff0c;4核32G配置113元1个月、339元3个月&#xff1b;腾讯云4核16G14M服务器66元1个月、277元3个月、1584元一年。阿腾云atengyun.com分享阿里云和腾讯云palwor…

BAT学习笔记:详解环境变量及其所有创建方法

文章目录 一、初识环境变量二、什么是环境变量三、为什么需要环境变量四、环境变量的分类五、环境变量的设置 一、初识环境变量 1.windows 的搜索框中输入 查看高级系统设置。点击打开系统属性窗口。 2. 在系统属性窗口中&#xff0c;点击右下方的“环境变量”打开环境变量设…

RHCE第五次作业

1.写一个脚本&#xff0c;完成如下功能 传递一个参数给脚本&#xff0c;此参数为gzip、bzip2或者xz三者之一&#xff1b; (1) 如果参数1的值为gzip&#xff0c;则使用tar和gzip归档压缩/etc目录至/backups目录中&#xff0c;并命名为/backups/etc-20160613.tar.gz&#xff1b; …

OpenGL 入门(一)— 创建窗口

文章目录 前言创建一个窗口视口动态调整输入控制渲染 完整代码 前言 关键词介绍&#xff1a; OpenGL&#xff1a; 一个定义了函数布局和输出的图形API的正式规范。GLFW&#xff1a;一个专门针对OpenGL的C语言库&#xff0c;它提供了一些渲染物体所需的最低限度的接口。它允许…

C#使用RabbitMQ-2_详解工作队列模式

简介 &#x1f340;RabbitMQ中的工作队列模式是指将任务分配给多个消费者并行处理。在工作队列模式中&#xff0c;生产者将任务发送到RabbitMQ交换器&#xff0c;然后交换器将任务路由到一个或多个队列。消费者从队列中获取任务并进行处理。处理完成后&#xff0c;消费者可以向…

C#,打印漂亮杨辉三角形(帕斯卡三角形)的源代码

杨辉 Blaise Pascal 这是某些程序员看完会哭的代码。 杨辉三角形&#xff08;Yanghui Triangle&#xff09;&#xff0c;是一种序列数值的三角形几何排列&#xff0c;最早出现于南宋数学家杨辉1261年所著的《详解九章算法》一书。 欧洲学者&#xff0c;最先由帕斯卡&#x…

VsCode提高生产力的插件推荐-持续更新中

别名路径跳转 自定义配置// 文件名别名跳转 "alias-skip.mappings": { "~/": "/src", "views": "/src/views", "assets": "/src/assets", "network": "/src/network", "comm…

Go语言指针变量

1. 指针变量 区别于C/C中的指针&#xff0c;Go语言中的指针不能进行偏移和运算&#xff0c;是安全指针。 Go语言中的指针3个概念&#xff1a;指针地址、指针类型和指针取值。 1.1. Go语言中的指针 Go语言中的函数传参都是值拷贝&#xff0c;当我们想要修改某个变量的时候&a…