96 lines
12 KiB
Plaintext
96 lines
12 KiB
Plaintext
|
||
《BMM最优软件实现方案设计.md》的第六章给出了BMM最优性能的4大分支,《BMM分块计算数学公式.html》从公式原理角度给出了分块计算的定义,但是这两个之间还差一层逻辑,就是如何从分块计算+最优实现推导出需要这4大分支呢?请帮我好好思考分析这个问题;另外《BatchMatMulV3算子分支实现分析.html》里面有当前BMM算子实现的分析供参考
|
||
|
||
-------------------------------------
|
||
|
||
需要补充修正一下,在问题定义里说的BMM 的语义是元素级运算,这个写的很好很清楚,但是我们在NPU上是使用Cube核进行分块矩阵乘的计算,请再补充一个分块矩阵乘的公式及其说明,注意4个维度都可以切,直接补充到《BMM分块计算数学公式.html》、《BMM分块计算数学公式.md》这两个文件里去
|
||
|
||
--------------------------------------
|
||
|
||
BMM分块计算的本质用数学公式要如何表示?注意4个维度都可以切;你直接输出的公式都是没有渲染的,生成格式规范的markdown文档和html文件输出到本地吧
|
||
|
||
-------------------------------------
|
||
|
||
《BatchMatMulV3算子分支实现分析.html》文件的第五章逐分支详解的描述不够清晰、不够细致,也没有为什么这么做,为什么设置这个参数,这个参数为什么是这个值的分析,请把第五章好好完善,首先要要把代码实现过程清晰的描述出来,可以配套画一些流程图或架构图,每个分支都要清晰的、详细的描述条件、实现过程、步骤,并进行必要分析为什么这么做;注意参考NPU知识库中的其他资料或者上网搜集其他资料辅助分析
|
||
|
||
------------------------------------
|
||
|
||
详细分析下NPU知识库中ops-nn/matmul/batch_mat_mul_v3的算子代码实现,为了高性能的实现BMM算子的所有case,当前BMM算子有哪些分支,为什么是这些分支,这些分支具体是怎么实现的?形成html格式的分析说明文档输出到本地,可以参考NPU知识库中的其他资料或者上网搜集其他资料辅助分析
|
||
tips1:算子软件实现方案设计主要是结合芯片微架构特征和规格,设计分块到各个AiC核上的搬移、计算的tiling和swizzle(所谓swizzle简单说就是分块执行的顺序,以及哪个分块在哪个核上做)
|
||
|
||
--------------------------------
|
||
|
||
分析还是有漏洞,不够细致
|
||
1、在6.2的排除规则1中,你说“核间再切 B/M/N 不会增加并行度,只会减少每核的 K 范围”,这句话不理解,当一个case输入后,case本身的B\M\K\N是固定的,只切K分到所有核,和切K又切另外维度分到所有核相比,显然前者的K会切的更小,后者的K会切的更大,对应的K的范围会更大才对吧,怎么会“只会减少每核的 K 范围”呢?例如case的B=4,K=4096,如果只切K,每核分得B=4,K=4096/32=128,如果切K又切B,每核分的B=1,K=512,K变大了啊,中间矩阵写出的次数更少了吧,此时Reduce开销会比只切K时更多吗?
|
||
注意在做本项目时,在分析思考时,如果有不确定的信息或困惑要多参考知识库(/storage/Users/currentUser/WorkBuddy/昇腾NPU/昇腾NPU知识库)的资料,或者从网上查询,不要局限于当前编辑的文档本身;
|
||
请进一步完善第六章
|
||
|
||
--------------------------------
|
||
|
||
分析还是不仔细不完备漏洞很多,还是重点先修改第六章的内容:
|
||
1、转普通Matmul还叫TO_MUL分支合适吗?当前算子源码中TO_MUL是针对K==1,且只用AIV去计算,跟转普通Matmul意义差别很大,转普通Matmul后只是没有B维度了,如何做最优实现是另一大问题,只是不在当前BMM算子下研究,这个分支是将BMM的case中的某一类问题通过转换的方式借助Matmul的分析优化成果,站在Matmul优化的巨人肩膀上高效实现BMM的case,BMM算子优化分析只关注相对Matmul差异化的case的最优实现
|
||
2、在第6.1章节,对于分支完备性的分析还有很多欠考虑的地方,ASW_Basic不只是B=1吧,B较小时是不是都可以cover?甚至B较大时,单Batch的输出MN超过L0C的大小,此时ASW_Basic(核间切B\M\N)的性能和IterBatch(核间切B,核内可切M\K\N)的性能究竟哪个好,要如何分辨呢?
|
||
3、在第6.1章节,你说“不存在第六种独立分支——例如"同时切 K 和 M/N"是 StreamK 与 ASW_Basic 的组合,但可归入 StreamK(核间切 K 后,核内自然切 M/N)”,从完备性角度是可能存在核间同时切 K 和 M/N的,从性能最优角度也可以考虑排除一些分支,但为什么排除掉这个分支需要有充分理由说明,当完备性角度考虑的某个分支明确明显不如性能最优角度的候选分支才可以完全排除,性能最优角度列出的分支应该是完备性角度分支的子集,应该是性能最优角度的全集,即任何case若想达到最优性能必然要按性能最优角度的某个分支中的实现方案实现,如果某些case可以在完备性的某个分支中可达到性能最优则不能排除该分支;你定义的StreamK分支是严格限制只切K吗?核间完全不切B\M\N?那这个分支要要求K必须很大?K多大合适进入StreamK分支?
|
||
|
||
-----------------------------
|
||
|
||
问题还是很多,没有细致考虑数据块在硬件上流转实现的细节,还是重点先修改第六章的内容;
|
||
1、按我的设想,还应该有个可转普通Matmul的分支,即当左矩阵或者右矩阵中有一个的B=1即BatchA=1或BatchB=1,则可以把另一个B合并到非K的维度上,例如左矩阵的BatchA=1,此时可以将矩阵变为[M,K]@[K,BatchB*N]这样的二维矩阵相乘,只是输出后要做一个按Batch的split,从而转换普通Matmul的软件实现;
|
||
2、请先从系统角度分析下为什么是这几个分支?这些分支可以把所有BMM的case都覆盖全面?还有没有其他分支的可能?理由要充分和逻辑要清晰
|
||
3、第6.3 MergeBatch 不是每次计算都“将单核负责的 全部B_core 个 batch 的 A 矩阵沿 M 维拼接为 [B_core×M, K]、B 矩阵沿 N 维拼接为 [K, B_core×N],调用一次 Matmul 得到 [B_core×M, B_core×N] 的等效大矩阵”,假设单核分到B_core 个 batch ,Cube->L0C 单次计算时,可以只进行b个batch,b<=B_core,假设L1上放的Batch是bL1,L0上放的是bL0,单次实际计算的Batch数是b,那么b<=bL0<=bL1<=B_core;而且核内计算和搬移时,是可以切K的,切K后进行[bM,kL0]@[kL0,bN]=[bM,bN],多个K可以在L0C上直接累加得到最终的[bM,bN]再取BlockTrace从L0C搬移输出到L2或GM
|
||
先基于我上面的提示,进一步完善第六章内容
|
||
|
||
----------------------------
|
||
|
||
补充几点:
|
||
1、当前文档有很多描述很不专业,本机有一些昇腾NPU软硬件知识库可参考,路径是 /storage/Users/currentUser/WorkBuddy/昇腾NPU/昇腾NPU知识库
|
||
2、数据可以直接从GM读取到L1(GM带宽),在L2是cache配置时会随路驻留在L2,同样的数据下次AIC再需要用的时候如果L2 cache中有就可以命中并以L2的速率读取;L0C可以直接写出到L2,也可以直接写出到GM;注意L2容量有限,而且可能读写数据都会占用L2容量,如果L2容量被占满了,再从GM来读入或从L0C写出新数据时,L2 cache的内容会发生替换,L2腾空间有两个办法,一是对于L2已有的L0C写出的数据要先写回GM(写GM带宽)才能腾出空间,二是对之前从GM读入的在L2 cache的数据进行替换以腾出空间;在L2容量足够的情况下,一般只会从GM读一次,数据块的重复读取会发生在从L2读取,因此L1容量大小会直接影响重复读的数据量和性能
|
||
3、从GM读取数据时存在访存效率问题,影响访存效率的主要有几个因素,重要性依次递减,一是参与核数,GM带宽所有核共享并发读取才能尽量充分利用带宽,至少要3/4的核并发才能达到90%以上的带宽利用率,二是单核读取的数据量越大越能达到高带宽利用率,三是单次搬移的数据块越大越能达到高带宽利用率,四是ND2NZ指令的dValue要128Byte最好是256Byte或512Byte(例如在GM以ND排布的非转置左矩阵的K维度、非转置右矩阵的N维度上所搬移的数据量对应单次搬移的dValue)
|
||
4、BMM算子当前主要是MergeBatch、IterBatch、StreamK、ASW_Basic这几个软件实现分支
|
||
5、关于tiling和swizzle的描述可以参考当前算子结构体中的描述,MatmulConfig参数说明,L0C的大小影响M、N的切分
|
||
6、给定具体case,要能给出最优软件实现方案,并能评估端到端算子时延;给定具体case,并给定具体tiling和swizzle方案也要能评估端到端算子时延
|
||
另外单独补充说明下MergeBatch、IterBatch、StreamK、ASW_Basic这几个软件实现分支,可参考ops-nn/matmul/batch_mat_mul_v3算子源码,我要强调的是源码未必是最优的,要以批判的眼光审视源码,参考并优化方案:
|
||
1、其中MergeBatch和IterBatch都是先按Batch分核,核内计算时MergeBatch会进行[bM,K]@[K,bN]的计算,然后按[M,N]的Block取Trace,会存在算力浪费,不过一般访存Bound,计算时延可以被掩盖,浪费一点也没关系,IterBatch在核内计算时就是逐个Batch的进行计算
|
||
2、StreamK是在B、M、N切分无法有效利用核数并行计算时,通过切K达到多核有效计算,提升核负载利用率的目的,但存在核间的Reduce的额外开销
|
||
3、实践中,大多数case会走ASW_Basic分支,该分支不切K,对于B、M、N都可以切
|
||
请参考我的补充说明,重新审视并优化《BMM最优软件实现方案设计.md》
|
||
|
||
-------------------------
|
||
|
||
我想设计BMM算子在NPU(昇腾950PR)上的最优软件实现,算子接口大致与batch_mat_mul_v3类似,目标是任何shape、dtype的BMM case来了,都能得到最优的软件实现方案,所谓最优就是最终可以达成在该芯片上最短的端到端算子时延,你先拿出个设计方案输出到本地,要有理有据,下面有一些tips供参考
|
||
|
||
tips1:算子软件实现方案设计主要是结合芯片微架构特征和规格,设计分块到各个AiC核上的搬移、计算的tiling和swizzle(所谓swizzle简单说就是分块执行的顺序,以及哪个分块在哪个核上做)
|
||
|
||
tips2:据我了解GM带宽1.6TB/s是读写共享,L2的带宽5.2TB/s是读写各自独享,Cube计算的输出是可以直接写到L2的,所有最终输出都写到L2也算计算完成。
|
||
|
||
tips3:关于核间切分的一些想法如下
|
||
核间切分
|
||
切B
|
||
读入
|
||
每个数据块都有对应的核,且每个数据块只会被固定的1个核读取
|
||
每核独立读取各自的多个数据块,不会读取其他核的数据块
|
||
计算
|
||
每个最终结果数据块由每个核独立计算产生,不依赖其他核的结果
|
||
在单核内,该核的任意输入数据块可以产生该输入数据块能产生的全部输出数据块
|
||
写出
|
||
每个核只写出最终结果,没有中间结果写出
|
||
切M或N
|
||
读入
|
||
若是切M后左矩阵分块被分到不同核,则存在同一右矩阵分块被不同核(重复)读取
|
||
若是切N后右矩阵分块被分到不同核,则存在同一左矩阵分块被不同核(重复)读取
|
||
单核会读取多个数据块,单个数据块可能会被一个或多个核读取
|
||
计算
|
||
每个最终结果数据块由每个核独立计算产生,不依赖其他核的结果
|
||
在单核内,该核的某个输入数据块只可以产生该输入数据块能产生的部分输出数据块
|
||
写出
|
||
每个核只写出最终结果,没有中间结果写出
|
||
切K
|
||
读入
|
||
每个数据块只会被固定的1个核读取
|
||
每核独立读取各自的多个数据块,不会读取其他核的数据块
|
||
计算
|
||
每个最终结果数据块由多个核计算产生,依赖多个核的结果,且需要Reduce
|
||
在单核内,该核的任意输入数据块可以产生该输入数据块能产生的全部输出数据块的中间结果
|
||
写出
|
||
单核存在中间结果写出,需要与其他核的中间结果一起做reduce才能产生最终输出数据分块
|
||
|