---
title: 分离模式
description: "本节内容为针对分离模式，使用基础API进行矩阵乘法的编程指导。"
url: https://www.hiascend.com/document/detail/zh/canncommercial/latest/programug/Ascendcopdevg/atlas_ascendc_10_00007.html
sourcePath: /source/zh/canncommercial/900/programug/Ascendcopdevg/atlas_ascendc_10_00007.html
indexId: 5140d1bebea9736c286b217f1d8be2659910e9ae97f03df157d892f1bbf3533381
---
# 分离模式

本节内容为针对分离模式，使用基础API进行矩阵乘法的编程指导。

如下章节内容暂不支持Atlas 350 加速卡。


针对分离模式，使用基础API进行矩阵乘法算子实现的编程范式和耦合模式一致，由于硬件架构不同，具体实现有一些差异，本节仅提供差异点说明。完整代码请参见Mmad样例(https://gitee.com/ascend/samples/tree/master/operator/ascendc/0_introduction/20_mmad_kernellaunch/MmadInvocation)。

- CopyIn阶段差异

  - 耦合模式
    在CopyIn阶段，即从GM->A1/B1（L1 Buffer）的阶段，耦合模式下可以使用DataCopy接口直接将数据从GM搬入L1 Buffer，也可以将数据从GM搬入UB，再搬入L1 Buffer。若需要ND2NZ的格式转换，需要开发者自行完成；或使用DataCopy接口提供的随路格式转换(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/ascendcopapi/atlasascendc_api_07_00127.html)功能，但该功能会使用UB临时空间。

    如下示例，直接使用了GM->A1/B1的数据搬运指令，自行完成ND2NZ的格式转换。

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 __aicore__ inline void CopyND2NZ(const AscendC::LocalTensor<half>& dst, const AscendC::GlobalTensor<half>& src, const uint16_t height, const uint16_t width) { for (int i = 0; i < width / 16; ++i) { int srcOffset = i * 16; int dstOffset = i * 16 * height; AscendC::DataCopy(dst[dstOffset], src[srcOffset], { height, 1, uint16_t(width / 16 - 1), 0 }); } } __aicore__ inline void CopyIn() { AscendC::LocalTensor<half> a1Local = inQueueA1.AllocTensor<half>(); AscendC::LocalTensor<half> b1Local = inQueueB1.AllocTensor<half>(); CopyND2NZ(a1Local, aGM, m, k); CopyND2NZ(b1Local, bGM, k, n); inQueueA1.EnQue(a1Local); inQueueB1.EnQue(b1Local); }

  - 分离模式
    分离模式下数据无法经过VECIN/VECCALC/VECOUT (UB) 直接搬运到A1/B1 (L1 Buffer) ，但是使用DataCopy接口提供的随路格式转换(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/ascendcopapi/atlasascendc_api_07_00127.html)功能一条指令即可完成格式转换，无需UB作为临时空间。

    示例如下：

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 __aicore__ inline void CopyIn() { AscendC::LocalTensor<half> a1Local = inQueueA1.AllocTensor<half>(); AscendC::LocalTensor<half> b1Local = inQueueB1.AllocTensor<half>(); AscendC::Nd2NzParams nd2nzA1Params; nd2nzA1Params.ndNum = 1; nd2nzA1Params.nValue = m; nd2nzA1Params.dValue = k; nd2nzA1Params.srcNdMatrixStride = 0; nd2nzA1Params.srcDValue = k; nd2nzA1Params.dstNzC0Stride = CeilCubeBlock(m) * CUBE_BLOCK; nd2nzA1Params.dstNzNStride = 1; nd2nzA1Params.dstNzMatrixStride = 0; AscendC::DataCopy(a1Local, aGM, nd2nzA1Params); AscendC::Nd2NzParams nd2nzB1Params; nd2nzB1Params.ndNum = 1; nd2nzB1Params.nValue = k; nd2nzB1Params.dValue = n; nd2nzB1Params.srcNdMatrixStride = 0; nd2nzB1Params.srcDValue = n; nd2nzB1Params.dstNzC0Stride = CeilCubeBlock(k) * CUBE_BLOCK; nd2nzB1Params.dstNzNStride = 1; nd2nzB1Params.dstNzMatrixStride = 0; AscendC::DataCopy(b1Local, bGM, nd2nzB1Params); inQueueA1.EnQue(a1Local); inQueueB1.EnQue(b1Local); }


- Aggregate及CopyOut阶段差异

  - 耦合模式
    耦合模式中，完成矩阵乘计算后数据存放于CO1（L0C Buffer），最终搬入GM需要通过CO2（UB），且NZ2ND的格式转换需要在CO1->CO2->GM阶段中手动完成。如下样例，在Aggregate阶段将NZ格式数据从CO1搬入CO2中，在CO2->GM的阶段使用for循环调用DataCopy完成了格式转换。

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 __aicore__ inline void Aggregate(const AscendC::LocalTensor<float>& c2Local, const int bSplitIdx) { AscendC::LocalTensor<float> c1Local = outQueueCO1.DeQue<float>(); AscendC::DataCopyParams dataCopyParams; dataCopyParams.blockCount = 1; dataCopyParams.blockLen = 2; AscendC::DataCopyEnhancedParams enhancedParams; enhancedParams.blockMode = AscendC::BlockMode::BLOCK_MODE_MATRIX; AscendC::DataCopy(c2Local[bSplitIdx * cSize / 2], c1Local, dataCopyParams, enhancedParams); outQueueCO1.FreeTensor(c1Local); } __aicore__ inline void CopyOut() { AscendC::LocalTensor<float> c2Local = outQueueCO2.DeQue<float>(); // transform nz to nd for (int i = 0; i < nBlocks; ++i) { AscendC::DataCopy(cGM[i * 16], c2Local[i * m * 16], { m, 2, 0, uint16_t((nBlocks - 1) * 2) }); } outQueueCO2.FreeTensor(c2Local); }

  - 分离模式
    分离模式下，矩阵乘的计算结果从CO1（L0C Buffer）可以通过Fixpipe通路直接写入GM，而且Fixpipe(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/ascendcopapi/atlasascendc_api_07_0251.html)提供了随路NZ2ND的功能，方便用户做格式转换。样例如下，样例中省去了Aggregate阶段，直接CopyOut。

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 __aicore__ inline void CopyOut() { AscendC::LocalTensor<float> c1Local = outQueueCO1.DeQue<float>(); AscendC::FixpipeParamsV220 fixpipeParams; fixpipeParams.nSize = n; fixpipeParams.mSize = m; fixpipeParams.srcStride = m; fixpipeParams.dstStride = n; fixpipeParams.ndNum = 1; fixpipeParams.srcNdStride = 0; fixpipeParams.dstNdStride = 0; AscendC::Fixpipe(cGM, c1Local, fixpipeParams); outQueueCO1.FreeTensor(c1Local); }
