动态尺寸模型优化实践之Shape Constraint IR Part I
简介: 在本系列分享中我们将介绍BladeDISC在动态shape语义下做性能优化的一些实践和思考。本次分享的是我们最近开展的有关shape constraint IR的工作,Part I 中我们将介绍问题的背景,面临的主要挑战和以及我们做shape constraint IR的动机。
在本系列分享中我们将介绍BladeDISC在动态shape语义下做性能优化的一些实践和思考。本次分享的是我们最近开展的有关shape constraint IR的工作,鉴于篇幅较长,为了提升阅读体验,我们将分享拆分为两个部分:
- Part I 中我们将介绍问题的背景,面临的主要挑战和以及我们做shape constraint IR的动机;
- Part II 中我们将介绍shape constraint IR的设计,实现以及一些初步的实验结果;
本篇是关于Part I的介绍,Part II的介绍将后续发出。
背景和挑战
主流的AI模型在部署时一般都具备不同程度的动态shape问题,比如输入图片尺寸,batch size 或者序列长度的变化等。与静态shape语义下做优化相比,在动态shape语义下做优化由于缺少具体的shape信息往往具有更大的难度,主要体现在以下几个方面:
挑战1:优化目标的转变。在静态shape下,我们的优化目标是希望在给定的shape下,尽可能逼近理论上限的速度,针对不同的shape可以使用不同的优化手段,而在动态shape语义下,我们优化目标是希望使用一套方法提升在整个shape分布上的平均性能,更强调的是优化方法的跨shape可迁移性和稳定性。因此很多在静态shape下常用的优化,比如profling驱动的策略,将不再简单可用。
挑战2:更少的有效信息。优化AI模型时很多常见的手段都把一些shape关系的断言是否成立作为优化触发的前置条件。比如在计算图化简时消除冗余的broadcast op,需要依赖于判断输入和输出是否具有相同的shape。在静态shape语义下,判断常量shape是否相等是显然的,而动态shape语义下,判断symbolic shape相等则困难的多,而一旦我们无法有效判断这些前置的shape关系断言是否成立,后续优化都无法进行,因而丢失很多优化机会,拉大与静态shape情况下性能的差异。
挑战3:更复杂的计算图。在动态shape语义下,由于shape不再是编译(或者优化)期间的常量,整个计算图中混杂着计算shape的IR以及计算data的IR,使得整个计算图的分析和优化都变得更复杂,同时也会引入更多shape相关计算的开销。
下图中展示了一个支持numpy语义implicit broadcast (IB)的Add OP的例子以说明计算图变复杂的具体过程。在IB语义下,Add OP在运行时会根据输入shape之间的关系,隐式的插入broadcast运算,所以下图左侧中展示的三种可能输入都是合法的。在静态shape语义下我们很容易在编译期就区分开实际是那种情况,故而在编译时只需要对一种具体情况进行处理,而在动态shape语义下,由于编译期间无法进行区分,我们需要确保编译的结果在三种情况下都可以工作,因而会在计算图中引入显示的shape 计算的IR以及broadcast操作(如下图右侧所示)。在这个例子中上层框架中一个普通的Add OP在动态shape语义下,也会被展开成一个复杂的子图。
也正因为上述的这些挑战,目前成熟的优化工具(如TensorRT,XLA/TVM)对于动态shape支持都还比较有限。BladeDISC是阿里云计算平台PAI团队自研的一款原生支持动态shape的AI编译器。在过往一段时间我们开发BladeDISC优化动态shape模型的过程中,我们发现尽管不知道shape的具体的数值,但是通过充分发掘和利用Tensor的shape之间的结构化关系或者Tensor shape自身的分布特点,可以有效的解决上述挑战。在这里我们把Tensor的shape之间的结构化关系或者Tensor shape自身的分布统称为shape constraint。更进一步的,我们发现通过将shape constraint作为第一等公民引入到IR中,可以最大化的发挥shape constraint的效能。本文中我们将介绍BladeDISC中shape constraint IR的定义以及如何利用它来辅助完成一系列动态shape语意下的优化以解决上述挑战,缩小与静态shape之间的性能差异。
动机
为什么选择shape constraint?
在上一章节中我们分析了在动态shape语义下给做优化所带来的一系列挑战。我们发现使用shape constraint可以有效的解决这些优化上面临的困难。以下我们将分别介绍使用shape constraint如何有效解决上述的三个挑战。
应对挑战1:跨shape可迁移性
在具体分析之前,我们先看shape constraint在本文中的定义。假设一个tensor的rank是N,则该tensor的shape可以记为(d0, d1, ... dN-1)
,其中di
表示的是该tensor在第i
个轴上所具有的大小,也记为第i
个轴的dimension size
。文本中讨论的shape constraint可以分为以下两类:
- shape结构化约束。该类约束描述的是dimension size之间的相关关系,比如:
- dimension size相等关系:某一个tensor的
di
与另外一个tensor的dj
具有相同的大小,或者同一个tensor的di
与dj
具有相同的大小; - tensor元素个数相等:即一个tensor和另外一个tensor具有相同数量的元素;
- dimension size乘积相等关系:比如
reshape([a, b, c, d]) -> [a*b, c*d]
- shape分布约束。该类约束描述的是某个或某几个dimension size的(联合)分布,比如:
di % 4 = 0
,di != 0
,di * dj=10
;- likely values: 即描述某个dimension size更大概率可能取到的值;
- value range:即描述某个dimension size可能的取值区间;
由上述定义本身我们可以立刻得到一个结论:由于无论是shape结构化约束还是分布约束都不依赖于具体的shape值,因此基于shape constraint而构建的优化策略天然具备跨shape可迁移性。
应对挑战2:shape关系断言分析
很多重要的优化都将一些shape关系的断言是否成立作为优化触发的前置条件,比如:
- 计算图化简。比如上文提到的消除冗余的broadcast节点的例子。
- 计算图layout全局优化。计算密集型算子的性能和其输入输出的数据排布(layout)有很强的关系,一个更合适的layout往往具有更好的性能。而一般最优的layout是随着shape而变化的,导致在动态shape语意下无法静态确定最优的layout;这里一种优化策略是:将shape兼容的计算密集算子分到一组,只需要在组间插入layout转化的算子,而组内由于可以确认使用同一种layout而不必再插入layout转化的算子,从而提升性能;这里shape兼容的断言是优化触发的前置条件。
- fusion决策。在做算子融合时并不是越多越好,只有将shape兼容的算子进行融合才会取得比较好的效果,同样里shape兼容的断言的判定是做算子融合的前置条件。
在动态shape语义下,由于不知道shape具体的值,symbolic shape关系的断言的分析往往是困难的。symbolic shape关系的断言可以看成是symbolic dimension size间的关系断言的逻辑关系表达式,因而问题可以转换成对于symbolic dimension size间的关系断言的判定。而由前述shape constraint定义可知,symbolic dimension size间的关系断言本身是shape constraint一个实例。在这里我们把判定symbolic dimension size间的关系断言是否成立的这个问题转换成该断言是否是已知原子shape constraint的组合。这里“原子”的定义是不能够通过其他shape constraint 的实例的组合得到。举个例子,假设我们需要判定tensor A: tensor
是否比tensor B: tensor
具有更多的元素个数,这个问题经过转换过之后可以变成dimension size关系a > b
是否成立。
在完成上述问题的转换之后,目前剩下的未解决的问题是:如何获得已知结果的原子shape constraint。具体来说有以下几种方式:
- 由用户提供或在JIT编译期间自动捕获。比如用户可以提供关于模型输入shape range,JIT编译期间可以将捕获到的一组输入shape当作likely value 注入编译流程等。
- 由op定义所携带的shape consraint信息。比如:
- elementwise op的输入和输出应该具有相同的大小;
mhlo.dynamic_reshape
op的输入和输出应该具有相同的元素个数;mhlo.concatenate
op 的输入和输出在非拼接的轴上应该具有相同的大小;
- 分析shape计算的IR或者通过传播已有的shape constraint来获得新的信息,比如:
在充分利用上述来源原子shape contraint的基础上,我们可以大幅减少由于shape未知导致一些优化前置条件无法判断,进而导致优化无法生效的问题。
应对挑战3:shape计算开销及更复杂的计算图
在动态shape语义下,会引入更多的shape计算的开销,整个计算图会变得更复杂。
对于shape计算开销,shape结构化约束我们可以抵消大量重复的symbolic计算,从而尽可能减小额外的开销。
对于计算图化简而言,我们一方面可以通过利用shape结构化约束消除一部分的冗余计算,比如前文中提到的由于IB问题引入的大量broadcast op可以在计算图化简中消除。剩下的无法利用shape结构化约束消除的broadcast可以进一步利用以下shape分布约束进行优化:IB触发(即需要插入隐式的broadcast)的概率远小于IB不触发的概率。通过生成带IB和不带IB两个版本的(如下图所示),让common case变得更快,从而提升期望性能;
为什么需要shape constraint IR?
shape constraint在动态shape语义下很有用,但是要用好它却并不容易。由于在整个pass pipeline中都可能会使用到shape constraint信息,因此我们需要一种方式将shape constraint信息在不同的pass之间进行传递。BladeDISC早期时使用是一种隐式传递的策略,即每个pass在需要使用shape constraint信息时会通过分析一遍IR来重建shape constraint信息。不难看出在上述的方案中shape constraint本身并不是IR一部分,这种策略带来的问题是:
- 通过分析IR的方式一般只能够重建(部分)结构化约束信息,大部分的分布约束信息无法通过直接分析data计算IR来重建,而分布约束对于动态shape语义下的性能优化同样很重要;
- 在整个pass pipeline中IR会经历多次的lowering (如TF/Torch dialect -> mhlo -> lmhlo -> ...),在每次lowering的过程中都可能会丢失一部分shape constraint信息,比如下图中所展示的
tf.SplitOp
的例子。在这个例子中上层的tf.SplitOp
会被lower成一系列的mhlo的SliceOp
。根据tf.SplitOp
的定义我们可以知道它的所有输出(假设有N
个)应该具有相同的shape,且输入在被拆分的轴上的dimension size可以被N
整除,这些信息在我们lower到mhlo时如果只进行data computation的转换,而不进行shape constraint信息的转换,将会被丢失,从而使得后续的pass无法再利用相应的信息进行优化;
为了解决上述的问题,我们更进一步将shape constraint 作为第一等公民引入到IR中,使得可以对结构化约束信息和分布约束信息进行统一的建模,同时也确保在整个pass pipeline中各个pass可以看到一致的shape constraint信息,进而更好的支持在不同的阶段完成各自适合的优化。
动态尺寸模型优化实践之Shape Constraint IR Part I的更多相关文章
- HBase实践案例:知乎 AI 用户模型服务性能优化实践
用户模型简介 知乎 AI 用户模型服务于知乎两亿多用户,主要为首页.推荐.广告.知识服务.想法.关注页等业务场景提供数据和服务, 例如首页个性化 Feed 的召回和排序.相关回答等用到的用户长期兴趣特 ...
- 百度APP移动端网络深度优化实践分享(一):DNS优化篇
本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<一>DNS优化>,感谢原作者的无私分享. 一.前言 网络优化是客户端几大技术方 ...
- 腾讯技术分享:GIF动图技术详解及手机QQ动态表情压缩技术实践
本文来自腾讯前端开发工程师“ wendygogogo”的技术分享,作者自评:“在Web前端摸爬滚打的码农一枚,对技术充满热情的菜鸟,致力为手Q的建设添砖加瓦.” 1.GIF格式的历史 GIF ( Gr ...
- Unreal Engine 4 动态切割模型实现
转自:http://gad.qq.com/article/detail/33199 <合金装备:复仇>里面,有一个很有趣的设定,游戏里大部分的场景和物件都可以用主角的刀动态切割. UE4中 ...
- etcd 性能优化实践
https://mp.weixin.qq.com/s/lD2b-DZyvRJ3qWqmlvHpxg 从零开始入门 K8s | etcd 性能优化实践 原创 陈星宇 阿里巴巴云原生 2019-12-16 ...
- vivo版本发布平台:带宽智能调控优化实践-平台产品系列03
vivo 互联网平台产品研发团队 - Peng Zhong 随着分发规模地逐步增长,各企业对CDN带宽的使用越来越多.并且,各类业务使用CDN的场景各式各样,导致带宽会不断地出现骤增骤降等问题.基于成 ...
- 直播推流端弱网优化策略 | 直播 SDK 性能优化实践
弱网优化的场景 网络直播行业经过一年多的快速发展,衍生出了各种各样的玩法.最早的网络直播是主播坐在 PC 前,安装好专业的直播设备(如摄像头和麦克风),然后才能开始直播.后来随着手机性能的提升和直播技 ...
- 携程App的网络性能优化实践
首先介绍一下携程App的网络服务架构.由于携程业务众多,开发资源导致无法全部使用Native来实现业务逻辑,因此有相当一部分频道基于Hybrid实现.网络通讯属于基础&业务框架层中基础设施的一 ...
- Glow Android 优化实践
了解 Glow 的朋友应该知道,我们主营四款 App,分别是Eve.Glow.Nuture和Baby.作为创业公司,我们的四款 App 都处于高速开发中,平均每个 Android App 由两人负责开 ...
- Unity3D游戏GC优化总结---protobuf-net无GC版本优化实践
protobuf-net优化效果图 protobuf-net是Unity3D游戏开发中被广泛使用的Google Protocol Buffer库的c#版本,之所以c#版本被广泛使用,是因为c++版本的 ...
随机推荐
- python中记录打印的log模块logging的用法实例
日志基础教程 日志是对软件执行时所发生事件的一种追踪方式.软件开发人员对他们的代码添加日志调用,借此来指示某事件的发生.一个事件通过一些包含变量数据的描述信息来描述(比如:每个事件发生时的数据都是 ...
- JavaXMail发送邮件功能实现
原文:JavaXMail发送邮件功能实现 | Stars-One的杂货小窝 好久之前实现的邮件发送功能,一直没整理出来,考虑到之后有个项目需要,先整理一波 提示: 本文代码例子是使用Kotlin语言编 ...
- Android混淆后的bug日志通过mapping文件找对应行号
背景 由于项目中提测以及线上的apk都是经过混淆处理的,因此拿到日志后也无法正常查看崩溃日志的行号 这个原因是因为混淆了文件,输出的日志是对应不上源文件的,为了正确找到行号需要用到mapping.tx ...
- isPrimitive()方法和包装类
java.lang.Class.isprimitive()是说:确定指定的Class对象是基本类型,其返回是个boolean值,true代表你指定的这个Class对象是基本类型,false代表这个Cl ...
- Java valueOf() 方法---->摘抄
valueOf(boolean b): 返回 boolean 参数的字符串表示形式.. valueOf(char c): 返回 char 参数的字符串表示形式. valueOf(char[] data ...
- Linux输入输出
1.重定向概述 1.什么是重定向 将原本要输出到屏幕的数据信息,重新定向到某个指定的文件中.比如:每天凌晨定时备份数据,希望将备份数据的结果保存到某个文件中. 这样第二天通过查看文件的内容就知道昨天备 ...
- 记录--Vue开发历程---音乐播放器
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 一.audio标签的使用 1.Audio 对象属性 2.对象方法 二.效果 效果如下: 三.代码 代码如下: MusicPlayer.vu ...
- ET介绍——为什么使用C# .net core做服务端?
为什么使用C# .net core做服务端? 游戏服务端从早期的单服到分布式,开发越来越复杂,对稳定性,开发效率要求越来越高.开发语言的选择也逐步发生了变化,C 到 C++ 到 C++ + PYTHO ...
- 3D Object Detection Essay Reading 2024.04.05
EMIFF 论文:https://arxiv.org/abs/2303.10975 代码:https://github.com/Bosszhe/EMIFF 本文提出了一种新的基于摄像机的三维检测框 ...
- CTFshow pwn49 wp
PWN49 用ida打开我们发现是静态编译的,所以先要通过libc库来打是不可能的了,程序里面有一个栈溢出点,找一下有没有system函数,发现并没有 那么我们找一下有没有mprotect函数如果有这 ...