cann-samples是CANN社区提供的高性能实操样例库,致力于为开发者提供可复用的优化方法论和最佳实践代码。本系列文章将陆续介绍仓库中的典型样例,分享我们在算子优化过程中的思考与经验。


本文将帮助你

  • 理解MX量化的硬件加速机制:MX量化相较传统量化实现优势
  • 掌握性能建模方法:如何定量分析Bound类型,针对性优化,避免盲目调优
  • 理解核心优化思路:SWAT等关键策略的原理与应用
  • 了解TensorAPI范式:如何用Layout抽象简化坐标计算,代码量减少60%+

算子功能说明

对比项 MXFP8 MXFP4
A/B数据类型 float8_e4m3fn float4_e2m1
量化方式 GroupSize=32的pergroup量化 GroupSize=32的pergroup量化
scaleA/B数据类型 float8_e8m0 float8_e8m0
显存压缩比 相比 FP16/BF16 内存占用减少约 50% 相比 FP16/BF16 内存占用减少约 75%
典型应用场景 训推场景,兼顾训推速度与精度的平衡 模型推理,侧重显存效率与推理速度

计算公式
c i , j = ∑ g = 0 c e i l ( K / G ) − 1 ( s c a l e A i , g ⋅ s c a l e B g , j ⋅ ∑ k ′ = 0 G − 1 ( a i , g G + k ′ ⋅ b g G + k ′ , j ) ) c_{i, j} = \sum^{ceil(K/G)-1}_{g=0}\left(scaleA_{i, g} \cdot scaleB_{g, j} \cdot \sum^{G-1}_{k'=0} (a_{i, gG+k'} \cdot b_{gG + k', j}) \right) ci,j=g=0ceil(K/G)1(scaleAi,gscaleBg,jk=0G1(ai,gG+kbgG+k,j))

MX量化原理

技术背景

MX量化是一种GroupSize=32、Scale类型为float8_e8m0的分组量化方案。从效果上看,它等价于传统的PerGroup量化;但在实现层面,两者存在显著差异:

特性 MX量化
量化效果 分组量化(等价)
Scale粒度 固定GroupSize=32
执行方式 纯Cube核计算
硬件自动完成Scale乘法
易用性
仅需搬运数据至指定缓冲区,无需Scale乘法代码
性能影响 无额外开销
Scale乘法融合到MMAD指令,零额外耗时
Block代码量 ~350行(TensorAPI)
仅需基于layout+坐标简易实现搬运计算
Scale坐标计算 需要手动对齐L0 Buffer层级上的坐标

硬件加速机制

MX量化的核心优势在于硬件支持自动乘Scale操作,带来显著的易用性和性能提升。传统PerGroup量化需要AIC(Cube核)和AIV(Vector核)协同处理:

// 传统PerGroup量化:AIC+AIV协同处理(复杂且性能受限)
// AIC(Cube核):执行量化矩阵乘
for (int g = 0; g < K/G; g++) {
    // MMAD计算:量化后的A × 量化后的B,输出int32结果到L0C
    MMAD(l0c, a_quantized[g], b_quantized[g]);
    // Fixpipe自动搬运L0C → UB(供AIV读取)
}

// AIV(Vector核):显式执行Scale乘法和累加(性能瓶颈)
for (int g = 0; g < K/G; g++) {
    // 需搬运Scale到UB(额外的数据搬运开销)
    CopyIn(scaleA_ub[g], scaleA[g]);
    CopyIn(scaleB_ub[g], scaleB[g]);
    
    // 显式执行scale乘法(计算耗时 + AIC-AIV同步开销)
    temp = scaleA_ub[g] * scaleB_ub[g];  // broadcast乘法
    output += l0c_ub[g] * temp;          // 逐元素乘法+累加
    
    // 同步等待AIC下一轮数据
    SyncWait(aic_signal);
}

而MX量化的MMAD指令硬件自动完成Scale乘法

// MX量化:纯Cube核计算(硬件自动融合Scale乘法)
// 仅需搬运数据到指定缓冲区,无需Scale乘法代码
for (int g = 0; g < K/G; g++) {
    // 数据搬运:A/B → L0A/L0B,Scale → L0A_MX/L0B_MX
    LoadData(l0a, a[g], scaleA[g]);  // 数据+Scale一起搬运
    LoadData(l0b, b[g], scaleB[g]);
    
    // MMAD指令自动执行:A × B × ScaleA × ScaleB
    // 无需AIV参与,无需显式Scale乘法,零额外开销
    MMAD(l0c, l0a, l0b);  // 输出已包含Scale乘法的结果
}

Scale被预先搬运至独立的缓冲区L0A_MXL0B_MX,MMAD指令执行时硬件自动完成scale乘法,无需AIV参与、无需额外计算、无需同步等待

易用性与性能提升

易用性提升
维度 MX量化 提升效果
核间协作 仅需Cube核 开发复杂度降低50%
同步管理 无需同步 代码量减少30%+
Scale搬运 自动搬运至L0_MX 无需额外搬运逻辑
Scale乘法 硬件自动完成 无需Scale乘法代码

开发效率提升:MX量化不需要理解AIC和AIV的流水线、同步机制、缓冲区管理等复杂概念;仅需掌握数据搬运和坐标映射,开发者学习曲线大幅缩短。

性能提升
维度 MX量化 性能提升
计算单元 纯AIC(MMAD融合Scale) 零额外计算开销
流水并行 纯Cube流水,无断流 流水线并行度提升
总耗时 仅MMAD 整体耗时减少60%

性能瓶颈消除:MX量化通过硬件融合彻底消除AIV处理这一性能瓶颈,实现纯Cube模板实现的理想状态。

数据搬运流程

MX量化执行时的完整数据搬运流程如下图所示:

在这里插入图片描述

Figure 2. MX量化数据搬运流程:GM → L1 → L0/L0_MX → MMAD计算

关键要点

  • 输入矩阵A/B:GM → L1 → L0A/L0B
  • Scale张量:GM → L1 → L0A_MX/L0B_MX(独立缓冲区)
  • MMAD指令:自动完成 A × B × ScaleA × ScaleB

开发者的核心任务:精确控制输入矩阵与Scale的坐标对应关系。

实现约束

开发MX量化算子时需要注意以下关键约束:

  1. K维度对齐约束:由于scale在L0_MX缓冲区上的最小分形为(16, 2),对应输入矩阵在K方向的最小单位为64,要求baseK是64的整数倍

  2. K维度补零处理:基于约束1,当K轴非64对齐时,存在两类场景:

    • 当输入矩阵的K维度在内轴,即输入排布为(m, k)(n, k)时,ND2NZ指令可自动完成K方向补零;仅在MXFP8且Ceil(K/32)是奇数时,需要补零
  • 当输入矩阵的K维度在外轴,即输入排布为(k, m)(k, n)时,ND2NZ指令无法完成K方向补零,需在K对齐16后依然非64对齐时手动处理K方向补零

    推荐补零方法:使用SET2D对L1缓冲区目标地址清零 + ND2NZ跳写目标地址。

  1. 指令约束MMAD指令需关闭gemv功能。

开发者提示:违反约束可能导致运行时错误或性能下降,建议在开发前充分理解硬件限制。

性能建模方法

为什么需要性能建模?

传统调优方式往往依赖经验或大量试错。性能建模的核心价值在于将调优过程量化、可预测、可迁移

方式 特点 问题
凭经验调优 根据直觉选择优化策略 经验难以复用,新场景需重新摸索
大量试错 尝试多种配置选最优 时间成本高,可能错过最优解
性能建模 量化分析各流水耗时 针对性优化,方法可迁移

理论耗时公式

样例建立了完整的性能建模体系,各流水的理论耗时如下:

MMAD计算时间
T c u b e = M × K × N 16 × C 0 × 16 × 核数 × 频率 T_{cube} = \frac{M \times K \times N}{16 \times C0 \times 16 \times 核数 \times 频率} Tcube=16×C0×16×核数×频率M×K×N

其中16 × C0 × 16表示MX量化在Cube核上每拍的计算量。其中,MXFP8场景下C0 = 32,MXFP4场景下C0 = 64

MTE2搬运时间(GM到L1):
T m t e 2 ≈ ( M × N b a s e N + N × M b a s e M ) × K × ( s i z e o f ( d t y p e ) + 1 32 ) B a n d W i d t h m t e 2 T_{mte2} \approx \frac{(M \times \frac{N}{baseN} + N \times \frac{M}{baseM}) \times K \times (sizeof(dtype) + \frac{1}{32})}{BandWidth_{mte2}} Tmte2BandWidthmte2(M×baseNN+N×baseMM)×K×(sizeof(dtype)+321)

MTE1搬运时间(L1到L0):
T m t e 1 ≈ b a s e M × b a s e K × ( s i z e o f ( d t y p e ) + 1 32 ) B a n d W i d t h L 0 A + b a s e N × b a s e K × ( s i z e o f ( d t y p e ) + 1 32 ) B a n d W i d t h L 0 B T_{mte1} \approx \frac{baseM \times baseK \times (sizeof(dtype) + \frac{1}{32})}{BandWidth_{L0A}} + \frac{baseN \times baseK \times (sizeof(dtype) + \frac{1}{32})}{BandWidth_{L0B}} Tmte1BandWidthL0AbaseM×baseK×(sizeof(dtype)+321)+BandWidthL0BbaseN×baseK×(sizeof(dtype)+321)

FIXPIPE搬出时间(L0C到GM):
T f i x p = M × N × s i z e o f ( d t y p e ) B a n d W i d t h f i x p T_{fixp} = \frac{M \times N \times sizeof(dtype)}{BandWidth_{fixp}} Tfixp=BandWidthfixpM×N×sizeof(dtype)

Bound类型判断

通过比较各流水耗时,可以定量判断性能瓶颈类型:

Bound类型 判断条件 特征 优化方向
Cube Bound T c u b e ≥ max ⁡ ( T m t e 2 , T m t e 1 , T f i x p ) T_{cube} \geq \max(T_{mte2}, T_{mte1}, T_{fixp}) Tcubemax(Tmte2,Tmte1,Tfixp) 计算已达极限 关注负载均衡
MTE2 Bound T m t e 2 > T c u b e T_{mte2} > T_{cube} Tmte2>Tcube GM到L1搬运受限 减少搬运量、提高带宽利用率
MTE1 Bound T m t e 1 > T c u b e T_{mte1} > T_{cube} Tmte1>Tcube L1到L0搬运受限 消除Bank冲突、优化搬运效率
FIXPIPE Bound T f i x p > T c u b e T_{fixp} > T_{cube} Tfixp>Tcube L0C到GM搬出受限 小K场景需重点关注,提高带宽利用率

Bound判断思路

以MTE2 Bound为例说明判断过程:

步骤1:计算理论MMAD耗时
T c u b e = M × K × N 16 × C 0 × 16 × 核数 × 频率 T_{cube} = \frac{M \times K \times N}{16 \times C0 \times 16 \times 核数 \times 频率} Tcube=16×C0×16×核数×频率M×K×N

步骤2:计算MTE2搬运耗时
T m t e 2 ≈ S i z e D D R B a n d W i d t h D D R + S i z e L 2 B a n d W i d t h L 2 T_{mte2} \approx \frac{Size_{DDR}}{BandWidth_{DDR}} + \frac{Size_{L2}}{BandWidth_{L2}} Tmte2BandWidthDDRSizeDDR+BandWidthL2SizeL2

步骤3:对比判断

  • T c u b e ≥ T m t e 2 T_{cube} \geq T_{mte2} TcubeTmte2 → Cube Bound(计算已达极限)
  • T c u b e < T m t e 2 T_{cube} < T_{mte2} Tcube<Tmte2 → MTE2 Bound(搬运受限)

关键洞察:通过定量分析,精准定位瓶颈因素,避免"盲人摸象"式的调优。上述公式可以分析出:增大baseM/baseN可降低重复搬运比例,更容易达成Cube Bound。

详细的推导过程和参数说明,参见性能建模章节

性能示例:8192×8192矩阵

以M=N=K=8192、MXFP4、32核、1.65GHz,全局内存带宽1.6T/s,L2带宽5.2T/s,baseM=baseN=baseK=256为例,各流水理论耗时:

流水 公式计算 理论耗时
MMAD 8192³ / (16 × 64 × 16 × 32 × 1.65GHz) ~635 us
MTE2 全局内存搬运量 / 全局内存带宽 + L2搬运量 / L2带宽 ~455 us
MTE1 单核MTE1搬运量 / 单核MTE1速率 ~163 us
FIXPIPE 输出搬运 / L2带宽 ~25 us

结论:此场景为Cube Bound,可重点关注SWAT优化提升L2命中率。

核心优化策略

本样例实现了完整的优化策略体系(详见性能优化指南),以下重点介绍最具代表性的几种。

下述优化策略并不局限于MX量化场景,Matmul算子均可适配使能

SWAT:自适应滑动窗口模板

解决问题:多核场景下首轮L2缓存命中率低

核心原理:传统按列优先分配任务,每个核处理的区域呈窄条状,存在首轮L2缓存利用率低,后续L2命中率过高导致的整体不均衡,从而无法在初期从全局内存中访问数据时达成CubeBound。SWAT通过方正切分的策略来实现首轮即可CubeBound,并结合"Z型滑动"策略,显著改善每轮L2命中率。即使数据从全局内存获取,也依然可以具备CubeBound的能力。

在这里插入图片描述

Figure 3. SWAT原理图:优化首轮的L2命中率,实现Cube Ratio优化

仿真效果:图中展示了(1024, 1024)x(1024, 8192)矩阵乘使能SWAT前后的仿真流水对比结果。可以明显看到,同样的基本块切分下,因排布方式的差异,优化了首轮的MTE2综合带宽,从而实现算子Cube Ratio从79.1%提升到86.7%

在这里插入图片描述

Figure 4. SWAT流水效果对比:上部分是传统行/列优先实现;下部分是SWAT实现。

尾轮负载均衡

解决问题:多核分配基本快中,最后一轮基本快分配不均导致的计算负载不均衡

核心原理:将最后一轮的基本快进行二次切分,实现计算再分配,从而实现整体的计算负载均衡

在这里插入图片描述

Figure 5. 尾轮负载均衡原理图:通过二次切分实现多核负载均衡,消除最后轮核算力浪费。

仿真效果:图中展示了(2560, 1024)x(1024, 2560)矩阵乘的对比结果,按照基本块(256, 256)进行切分,会产生100个基本块,基于32核进行划分时,最后一轮仅有4个核。为此可以对其进行二次切分,将基本块缩小8倍,从而重新分配到32核上均衡计算,减少最长核的耗时。

在这里插入图片描述

Figure 6. 尾轮负载均衡流水效果对比:上部分未使能,下部分对尾块进行二次负载均衡。

UnitFlag

解决问题:当为了追求计算掩盖搬入访存,需要尽量的提高基本快的Size,从而降低重复搬入量。为此无法开启L0C的Double Buffer,导致MMAD和FIXP断流。通过Unitflag能力即可实现两者block级的同步能力。

在这里插入图片描述

Figure 7. UnitFlag流水原理图:提供512B粒度的细粒度同步,在无法开启L0C Double Buffer时提升并行度。

仿真效果:图中展示了(1024, 1024)x(1024, 4096)矩阵乘使能Unitflag前后仿真流水对比结果。Unitflag开启后提高了MMAD和FIXP流水的并行度,Cube Ratio从89.5%提升到90.9%。

在这里插入图片描述

Figure 8. Unitflag流水效果对比:上部分是未开启Unitflag实现;下部分是开启Unitflag实现。

更多优化策略

除上述重点介绍外,仓库还包含以下优化技术:

优化策略 解决问题 适用场景
Scale缓存优化 Scale带宽打不满 小矩阵、MTE2 Bound
全载优化 MTE2 Bound Decode场景
Double Buffer 流水停顿 缓冲区充足
L1 Bank冲突优化 MTE1速率下降 Bank冲突场景

详细的原理说明、代码实现和效果对比,请参考仓库中的性能优化指南示例代码

代码实现:TensorAPI范式

传统实现的痛点

量化矩阵乘涉及复杂的数据搬运:GM→L1→L0,且每个层级的排布规则不同:

缓冲区 排布规则 坐标计算复杂度
GM ND排布 简单
L1 NZ/ZN排布 复杂,需手算偏移
L0 ZN/Zz/Nn排布 复杂,规则各不相同

传统实现需要为每次搬运手动设置大量参数。以GM到L1的ND2NZ搬运为例:

// 传统方式:手动设置ND2NZ参数(多达10个参数)
AscendC::Nd2NzParams nd2nzParams;
nd2nzParams.ndNum = 1;
nd2nzParams.nValue = nDim;
nd2nzParams.dValue = dDim;
nd2nzParams.srcNdMatrixStride = 1;
nd2nzParams.srcDValue = transA ? m_ : k_;
nd2nzParams.dstNzC0Stride = transA ? curPadAKL1 : curAlignM;
nd2nzParams.dstNzNStride = 1;
nd2nzParams.dstNzMatrixStride = 1;
AscendC::DataCopy(al1Local, aGlobal, nd2nzParams);

// 手动计算L1缓冲区偏移(复杂且易错)
uint64_t l1Offset = IS_FP4 
    ? AscendC::TOTAL_L1_SIZE * (bufferId & 1)
    : (AscendC::TOTAL_L1_SIZE >> 1) * (bufferId & 1);
l1BufferAOffset_[bufferId] = l1Offset + aL1OneBuffer_ * (bufferId >> 1);
l1BufferBOffset_[bufferId] = 
    l1Offset + aL1OneBuffer_ * (l1BufNum_ >> 1) + bL1OneBuffer_ * (bufferId >> 1);

L1到L0的搬运更加复杂,需要同时处理数据张量和Scale张量,并且不同的模板无法有效复用,导致重复造轮子:

// 传统方式:手动设置LoadData参数(多达8个参数)
AscendC::LoadData2DParamsV2 loadDataParams;
loadDataParams.mStartPosition = 0;
loadDataParams.kStartPosition = CeilDiv(iter * baseK_, C0_SIZE);
loadDataParams.mStep = m1;
loadDataParams.kStep = CeilDiv(curKL0, C0_SIZE);
loadDataParams.srcStride = loadDataParams.mStep;
loadDataParams.dstStride = loadDataParams.mStep;
loadDataParams.ifTranspose = false;

// Scale张量需要额外设置LoadData2DMxParams
AscendC::LoadData2DMxParams loadData2DMxParams;
loadData2DMxParams.xStartPosition = 0;
loadData2DMxParams.yStartPosition = CeilDiv(iter * baseK_, MXFP_DIVISOR_SIZE);
loadData2DMxParams.xStep = m1;
loadData2DMxParams.yStep = CeilDiv(curKL0, MXFP_DIVISOR_SIZE);
loadData2DMxParams.srcStride = CeilDiv(curScaleKL1, MXFP_DIVISOR_SIZE);
loadData2DMxParams.dstStride = loadData2DMxParams.yStep;

// 执行搬运(需要同时传入数据张量和Scale张量)
AscendC::LoadData(l0aLocal, al1Local, scaleAl1Local, loadDataParams, loadData2DMxParams);

问题总结

  • 参数众多,不同排布规则参数组合不同
  • 偏移计算复杂,涉及bufferId、切分大小、对齐要求等多个因素
  • 数据张量和Scale张量需要分别处理,代码重复

TensorAPI的核心范式

样例采用TensorAPI的"Layout抽象 + 自动坐标映射"范式,将复杂性封装到底层:

Step 1:创建Layout描述排布

// 一行代码描述L1的NZ排布(替代手动设置10个ND2NZ参数)
auto layoutAL1 = AscendC::Te::MakeNzLayout<AType>(curM, curKL0);

// 创建L0的ZN排布
auto layoutBL0 = AscendC::Te::MakeZnLayout<BType>(curKL0, curN);

// 创建Scale的Zz排布
auto layoutScaleAL0 = AscendC::Te::MakeZzLayout<fp8_e8m0_t>(
    curM, CeilDiv(curKL0, MXFP_DIVISOR_SIZE) * MXFP_MULTI_BASE_SIZE);

Step 2:创建Tensor绑定地址与Layout

// 绑定L1缓冲区地址与Layout
auto tensorAL1 = AscendC::Te::MakeTensor(
    AscendC::Te::MakeL1memPtr<AType>(l1BufferAOffset_[l1BufId]), 
    layoutAL1);

Step 3:切片获取子张量(框架自动计算坐标映射)

// 从GM张量切片,框架自动处理ND→NZ的坐标映射
auto gmBlockA = gmA(
    AscendC::Te::MakeCoord(0, kL1Offset),      // 起始坐标
    AscendC::Te::MakeShape(curM, curGmAKL1));  // 子张量形状

// 从L1张量切片
auto tensorBlockAL1 = tensorAL1(
    AscendC::Te::MakeCoord(0, kL0Offset),
    AscendC::Te::MakeShape(curM, curKL0));

Step 4:执行操作(框架自动处理跨层级坐标转换)

// GM到L1的搬运(框架自动填充DataCopy参数)
auto copyGM2L1 = AscendC::Te::MakeCopy(AscendC::Te::CopyGM2L1{});
AscendC::Te::Copy(copyGM2L1, tensorAL1, gmBlockA);

// L1到L0的搬运(框架自动处理数据张量和Scale张量的坐标对齐)
auto copyL12L0 = AscendC::Te::MakeCopy(AscendC::Te::CopyL12L0{});
AscendC::Te::Copy(copyL12L0, tensorAL0, tensorBlockAL1);

代码量对比

以核心数据搬运逻辑为例:

实现方式 代码行数 参数数量 关键特点
传统方式 ~80行 10+参数/次 手算偏移,易出错
TensorAPI范式 ~30行 3-4参数/次 Layout抽象,逻辑清晰

完整代码示例:参见仓库中的quant_matmul_mxfp4_swat.cpp,展示了SWAT模板的完整TensorAPI实现,包含数据搬运、坐标映射、优化策略应用等核心逻辑。

TensorAPI的核心价值

1. 声明式编程:开发者只需声明"数据的排布是什么",而非"如何计算坐标偏移"

2. 类型安全:Layout信息编码在类型系统中,编译期即可发现排布不匹配

3. 可复用:同一套代码可适配不同排布(ND/Nz/Zn/Zz/Nn)

4. 可维护:核心逻辑简洁,便于理解和修改

5. 可扩展:支持自定义搬运逻辑,高度定制

快速上手与性能验证

cd Samples/2_Performance/matmul_story/matmul_recipes/examples/quant_matmul_mxfp4

# 自动构建 + 自动推荐最优算法 + 运行
bash scripts/run.sh 16 2048 16384

# 指定目标可执行文件,跳过重新构建
bash scripts/run.sh \
  --target quant_matmul_mxfp4_a_full_load --skip-build 16 2048 16384

# 查看完整帮助
bash scripts/run.sh --help

性能效果验证

读者可以通过以下方式体验优化效果:

  1. 对比不同优化策略:运行不同的可执行文件(如quant_matmul_mxfp4_swatquant_matmul_mxfp4_a_full_load
  2. 测试不同矩阵规模:尝试8192×8192、4096×4096、1024×1024等不同规模,观察性能差异
  3. 分析Bound类型:结合性能建模公式,理解不同规模下的性能瓶颈
  4. Profiling分析:使用昇腾Profiling工具分析各流水线耗时,验证理论建模

典型效果参考

[Profile Breakdown]
+--------------------------------+----------+---------+----------+---------+---------+------------+--------------+
| candidate                      |kernel(us)| mac(us) |scalar(us)| mte1(us)| mte2(us)|fixpipe(us) |icache_miss(%)|
+================================+==========+=========+==========+=========+=========+============+==============+
| quant_matmul_mxfp4_swat        |    12.345|   1.234 |     0.567|   0.123 |   0.456 |     0.789 |        0.100 |
| quant_matmul_mxfp4_a_full_load |    15.678|   2.100 |     0.800|   0.200 |   0.300 |     0.500 |        0.250 |
+--------------------------------+----------+---------+----------+---------+---------+------------+--------------+

小结

quant_matmul_mxfp8quant_matmul_mxfp4样例提供了MXFP8/MXFP4量化矩阵乘的完整解决方案,相比传统方案具有显著提升:

易用性提升

  • 硬件融合设计:MMAD指令自动完成Scale乘法,无需AIV参与,开发复杂度降低50%+
  • 纯Cube核计算:无需编写双核代码、管理同步逻辑,代码量减少60%+
  • TensorAPI范式:Layout抽象 + 自动坐标映射,大幅降低开发门槛,新手学习周期缩短

性能提升

  • 零额外开销:Scale乘法融合到MMAD指令
  • 纯Cube实现:消除传统方案的AIV瓶颈
  • 内存高效:减少输入的内存占用

开发支持

  • 性能建模方法:帮助开发者科学分析瓶颈,针对性优化,避免盲目调优
  • 系统化优化策略:SWAT、Double Buffer、UnitFlag等覆盖不同Bound类型场景,详见性能优化指南
  • 完整示例代码:提供TensorAPI实现参考,快速上手开发

我们希望这份样例能够帮助开发者快速掌握量化矩阵乘的优化方法,也期待社区的反馈与建议。如有问题,欢迎在GitCode Issues提出。


相关资源

  • 性能优化指南:Samples/2_Performance/matmul_story/docs/quant_matmul_mx_performance.md
  • MXFP8样例代码:Samples/2_Performance/matmul_story/matmul_recipes/examples/quant_matmul_mxfp8/
  • MXFP4样例代码:Samples/2_Performance/matmul_story/matmul_recipes/examples/quant_matmul_mxfp4/
Logo

CANN开发者社区旨在汇聚广大开发者,围绕CANN架构重构、算子开发、部署应用优化等核心方向,展开深度交流与思想碰撞,携手共同促进CANN开放生态突破!

更多推荐