MatmulPolicy

Applicability

Product

MatmulPolicy

TrianUpperMatmulPolicy/TrianLowerMatmulPolicy

NBuffer33MatmulPolicy

MatmulWithScalePolicy/SplitMMatmulPolicy/SplitNMatmulPolicy

Atlas 350 Accelerator Card

Atlas A3 training product / Atlas A3 inference product

x

Atlas A2 training product / Atlas A2 inference product

x

Atlas 200I/500 A2 inference product

x

x

x

Atlas inference product AI Core

x

x

x

Atlas inference product Vector Core

x

x

x

x

Atlas training product

x

x

x

x

Function Usage

The template parameter MatmulPolicy is used to define the policy of the Matmul extensible module. Currently, the following Matmul built-in template policies are supported:
  • MatmulPolicy (default template policy)

    Enables the default implementation policy of the Matmul API.

  • TrianUpperMatmulPolicy (upper triangular template policy)

    The computation result of a matrix multiplication instruction is a matrix block of baseM × baseN. The matrix block is called a base block. If the base block in the Matmul result matrix C is located in the lower triangular position, the base block is ignored during data computation and data move-out in Matmul. The final matrix C is an upper triangular matrix. The following figure shows the upper triangular template policy. The matrix shape sizes are as follows: M = N = 512, K = 256, baseM = baseN = baseK = 32.

    Figure 1 Upper triangular template policy
  • TrianLowerMatmulPolicy (lower triangular template policy)

    The computation result of a matrix multiplication instruction is a matrix block of baseM × baseN. The matrix block is called a base block. If the base block in the Matmul result matrix C is located in the upper triangular position, the base block is ignored during data computation and data move-out in Matmul. The final matrix C is a lower triangular matrix. The following figure shows the lower triangular template policy. The matrix shape sizes are as follows: M = N = 512, K = 256, baseM = baseN = baseK = 32.

    Figure 2 Lower triangular template policy
  • NBuffer33MatmulPolicy (NBuffer33 template policy)

    The computation result of a matrix multiplication instruction is a matrix block of baseM × baseN. The matrix block is called a base block. The matrix A computed by a single core is divided into 3 × 3 base blocks. All the 3 × 3 base blocks of matrix A are loaded and stored in L1 Buffer. Each time, matrix multiplication is performed between the 3 × 3 base blocks of matrix A and the 3 × 1 base blocks of matrix B. At the same time, DoubleBuffer loads the 3 × 1 base blocks of matrix B required for the next computation in parallel until the matrix multiplication computation in the singleCoreN direction is complete. The following figure shows the NBuffer33 template policy. In the figure, singleCoreM, singleCoreN, and singleCoreK indicate the shape sizes of matrices A and B in a single core. Matrix A computed in a single core is divided into 3 × 3 base blocks, which are all loaded into L1 Buffer. These base blocks are multiplied by the 3 × 1 base blocks of matrix B each time.

    Figure 3 NBuffer33 template policy
  • MatmulWithScalePolicy (MxMatmul template policy)

    This policy implements matrix multiplication with quantization coefficients, where both the left and right matrices have corresponding quantization coefficient matrices (left quantization coefficient matrix scaleA and right quantization coefficient matrix scaleB). The left quantization coefficient matrix is multiplied by the left matrix, and the right quantization coefficient matrix is multiplied by the right matrix. The products of these multiplications are then subjected to matrix multiplication with each other.

    Figure 4 MxMatmul template policy

  • SplitMMatmulPolicy (SplitM template policy)

    When the computation result of one Iterate of Matmul is moved from L0C Buffer to Unified Buffer, the dual-output mode is used. That is, in the separated mode, when the ratio of the number of AIC cores to the number of AIV cores is 1:2, after the GetTensorC interface is called, the computation result of one Iterate of Matmul is split into two parts in the M direction of the matrix, and the two parts of result data are moved to the Unified Buffer of the two AIV cores, respectively. The following figure shows the template policy.

    Figure 4 SplitM template policy
  • SplitNMatmulPolicy (SplitN template policy)

    When the computation result of one Iterate of Matmul is moved from L0C Buffer to Unified Buffer, the dual-output mode is used. That is, in the separated mode, when the ratio of the number of AIC cores to the number of AIV cores is 1:2, after the GetTensorC interface is called, the computation result of one Iterate of Matmul is split into two parts in the N direction of the matrix, and the two parts of result data are moved to the Unified Buffer of the two AIV cores, respectively. The following figure shows the template policy.

    Figure 5 SplitN template policy

Restrictions

  • TrianUpperMatmulPolicy supports only the Norm template and MDL template.
  • TrianLowerMatmulPolicy supports only the Norm template and MDL template.
  • NBuffer33MatmulPolicy:
    • Currently, only the MDL template is supported.
    • The logical memory positions of matrices A and B support only TPosition::GM.
    • The MIX mode (including cube computation and vector computation) is not supported. Only the CUBE_ONLY mode (including only cube computation) is supported.
    • Only the IterateAll API can be used to obtain the computation result matrix C of Matmul.
    • The values of stepM, stepKa, and stepKb are less than or equal to 3, and the following condition is met: stepKa = stepKb = ceil(singleCoreK/baseK).
    • The sum of the base block size of matrix A (fully loaded) and the base block size of matrix B (loaded) does not exceed the size of L1 Buffer.
    • Before calling GetTiling to generate tiling parameters, you must call SetMatmulConfigParams to set scheduleTypeIn to ScheduleType::N_BUFFER_33 to enable the tiling generation logic of the NBuffer33 template policy.
  • MatmulWithScalePolicy:
  • SplitMMatmulPolicy:
    • Supported only on the Atlas 350 Accelerator Card.
    • Only matrix C can be output to Unified Buffer.
    • The IBSHARE parameter in MatmulType of matrices A and B must be set to true.
  • SplitNMatmulPolicy:
    • Supported only on the Atlas 350 Accelerator Card.
    • Only matrix C can be output to Unified Buffer.
    • The value of baseN must be a multiple of 16.
    • Tiling parameters must meet the following requirements: singleCoreM = baseM, singleCoreN = baseN, and singleCoreK = baseK.
    • The IBSHARE parameter in MatmulType of matrices A and B must be set to true.

Example

The default template policy MatmulPolicy is the default value of the template parameter. The following describes how to use TrianUpperMatmulPolicy and TrianLowerMatmulPolicy.

  • Example of using TrianUpperMatmulPolicy
    For details about the complete operator sample, see operator sample of using TrianUpperMatmulPolicy and TrianLowerMatmulPolicy.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include "lib/matmul_intf.h"
    
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half> aType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half> bType;
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> cType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> biasType;
    // Input TrianUpperMatmulPolicy when defining Matmul.
    AscendC::Matmul<aType, bType, cType, biasType, CFG_NORM, MatmulCallBackFunc<nullptr, nullptr, nullptr>, AscendC::Impl::Detail::TrianUpperMatmulPolicy> mm; 
    
    // Perform the regular Matmul computation and output the result in upper triangular format.
    TPipe pipe;
    TCubeTiling tiling;
    REGIST_MATMUL_OBJ(&pipe, GetSysWorkSpacePtr(), mm, &tiling);
    mm.SetTensorA(gmA, isTransposeA);
    mm.SetTensorB(gmB, isTransposeB);
    if (tiling.isBias) {
        mm.SetBias(gmBias);
    }
    mm.IterateAll(gmC);
    mm.End();
    
  • Example of using TrianLowerMatmulPolicy
    For details about the complete operator sample, see operator sample of using TrianUpperMatmulPolicy and TrianLowerMatmulPolicy.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include "lib/matmul_intf.h"
    
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half> aType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half> bType;
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> cType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> biasType;
    // Input TrianLowerMatmulPolicy when defining Matmul.
    AscendC::Matmul<aType, bType, cType, biasType, CFG_NORM, MatmulCallBackFunc<nullptr, nullptr, nullptr>, AscendC::Impl::Detail::TrianLowerMatmulPolicy> mm; 
    
    // Perform the regular Matmul computation and output the result in lower triangular format.
    TPipe pipe;
    TCubeTiling tiling;
    REGIST_MATMUL_OBJ(&pipe, GetSysWorkSpacePtr(), mm, &tiling);
    mm.SetTensorA(gmA, isTransposeA);
    mm.SetTensorB(gmB, isTransposeB);
    if (tiling.isBias) {
        mm.SetBias(gmBias);
    }
    mm.IterateAll(gmC);
    mm.End();
    
  • Example of using NBuffer33MatmulPolicy
    For details about the complete operator sample, see operator sample of enabling the NBuffer33 template policy.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #define ASCENDC_CUBE_ONLY
    #include "lib/matmul_intf.h"
    
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half> aType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half> bType;
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> cType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> biasType;
    // Input NBuffer33MatmulPolicy when defining Matmul.
    
    AscendC::Matmul<aType, bType, cType, biasType, CFG_MDL, MatmulCallBackFunc<nullptr, nullptr, nullptr>, AscendC::Impl::Detail::NBuffer33MatmulPolicy> mm; 
    
    // Use the NBuffer33 logic to perform Matmul computation and output the result.
    TPipe pipe;
    TCubeTiling tiling;
    REGIST_MATMUL_OBJ(&pipe, GetSysWorkSpacePtr(), mm, &tiling);
    mm.SetTensorA(gmA, isTransposeA);
    mm.SetTensorB(gmB, isTransposeB);
    if (tiling.isBias) {
        mm.SetBias(gmBias);
    }
    mm.IterateAll(gmC);
    mm.End();
    
  • Example of using MatmulWithScalePolicy
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include "lib/matmul_intf.h"
    typedef MatmulTypeWithScale<AscendC::TPosition::GM, AscendC::TPosition::GM, CubeFormat::ND, AType, isTransposeA> aType;
    typedef MatmulTypeWithScale<AscendC::TPosition::GM, AscendC::TPosition::GM, CubeFormat::ND, BType, isTransposeB> bType;
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> cType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> biasType;
    // Input MatmulWithScalePolicy when defining Matmul.
    AscendC::Matmul<aType, bType, cType, biasType, CFG_NORM, MatmulCallBackFunc<nullptr, nullptr, nullptr>, AscendC::Impl::Detail::MatmulWithScalePolicy> mm; 
    
    // MxMatmul calculation logic and final output result
    TPipe pipe;
    TCubeTiling tiling;
    REGIST_MATMUL_OBJ(&pipe, GetSysWorkSpacePtr(), mm, &tiling);
    mm.SetTensorA(gmA, isTransposeA);
    mm.SetTensorB(gmB, isTransposeB);
    mm.SetTensorScaleA(gm_scaleA, isTransposeScaleA);
    mm.SetTensorScaleB(gm_scaleB, isTransposeScaleB);
    if (tiling.isBias) {
        mm.SetBias(gmBias);
    }
    mm.IterateAll(gmC);
    mm.End();
    
  • Example of using SplitMMatmulPolicy
    For more operator examples, see matmul_splitm sample.
    #include "lib/matmul_intf.h"
    
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half, LayoutMode::NONE, true> aType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half, LayoutMode::NONE, true> bType;
    typedef AscendC::MatmulType<AscendC::TPosition::VECCALC, CubeFormat::ND, float> cType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> biasType;
    // Input SplitMMatmulPolicy when defining Matmul.
    AscendC::Matmul<aType, bType, cType, biasType, CFG_NORM, MatmulCallBackFunc<nullptr, nullptr, nullptr>, AscendC::Impl::Detail::SplitMMatmulPolicy> mm;
    // Matmul computation
    TPipe pipe;
    TCubeTiling tiling;
    REGIST_MATMUL_OBJ(&pipe, GetSysWorkSpacePtr(), mm, &tiling);
    mm.SetTensorA(gmA, isTransposeA);
    mm.SetTensorB(gmB, isTransposeB);
    if (tiling.isBias) {
        mm.SetBias(gmBias);
    }
    
    // After the GetTensorC API is called, the computation result of one Matmul Iterate is divided into two parts and moved to the Unified Buffer of the two AIV cores.
    pipe.InitBuffer(resultCMatrix, 1, tiling.M * tiling.N * sizeof(C_T));
    mm.template Iterate<false>();
    bufferC = resultCMatrix.AllocTensor<C_T>();
    uint16_t nIter_ = Ceil(tiling.singleCoreN, tiling.baseN);
    uint16_t mIter_ = Ceil(tiling.singleCoreM, tiling.baseM);
    uint16_t mnIter_ = nIter_ * mIter_;
    uint16_t size = tiling.baseM / 2 * tiling.baseN;
    for (int i = 0; i < mnIter_; i++) {
         mm.template GetTensorC<false>(bufferC, false, false);  // false // kfc vec0 iterate             
         PipeBarrier<PIPE_ALL>();
    }
    mm.End();
    resultCMatrix.EnQue(bufferC);
    bufferC = resultCMatrix.DeQue<C_T>();
    
    uint16_t baseOffset = tiling.M / 2 * tiling.N;
    uint16_t stride = tiling.M / 2 * tiling.N * sizeof(C_T) / 32;  // 32B
    const uint16_t blockCount = tiling.M / tiling.M;
    if (GetSubBlockIdxImpl() == 0) {
        DataCopy(gmC, bufferC, {blockCount, stride, stride, stride});
    } else {
        DataCopy(gmC[baseOffset], bufferC, {blockCount, stride, stride, stride});
    }
  • Example of using SplitNMatmulPolicy
    #include "lib/matmul_intf.h"
    
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half, LayoutMode::NONE, true> aType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, half, LayoutMode::NONE, true> bType;
    typedef AscendC::MatmulType<AscendC::TPosition::VECCALC, CubeFormat::ND, float> cType; 
    typedef AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, float> biasType;
    // Input SplitNMatmulPolicy when defining Matmul.
    AscendC::Matmul<aType, bType, cType, biasType, CFG_NORM, MatmulCallBackFunc<nullptr, nullptr, nullptr>, AscendC::Impl::Detail::SplitNMatmulPolicy> mm;
    // Matmul computation
    TPipe pipe;
    TCubeTiling tiling;
    REGIST_MATMUL_OBJ(&pipe, GetSysWorkSpacePtr(), mm, &tiling);
    mm.SetTensorA(gmA, isTransposeA);
    mm.SetTensorB(gmB, isTransposeB);
    if (tiling.isBias) {
        mm.SetBias(gmBias);
    }
    
    // After the GetTensorC API is called, the computation result of one Matmul Iterate is divided into two parts and moved to the Unified Buffer of the two AIV cores.
    pipe.InitBuffer(resultCMatrix, 1, tiling.M * tiling.N * sizeof(C_T));
    mm.template Iterate<false>();
    bufferC = resultCMatrix.AllocTensor<C_T>();
    uint16_t nIter_ = Ceil(tiling.singleCoreN, tiling.baseN);
    uint16_t mIter_ = Ceil(tiling.singleCoreM, tiling.baseM);
    uint16_t mnIter_ = nIter_ * mIter_;
    uint16_t size = tiling.baseM / 2 * tiling.baseN;
    for (int i = 0; i < mnIter_; i++) {
         mm.template GetTensorC<false>(bufferC, false, false);  // false // kfc vec0 iterate             
         PipeBarrier<PIPE_ALL>();
    }
    mm.End();
    resultCMatrix.EnQue(bufferC);
    bufferC = resultCMatrix.DeQue<C_T>();
    
    uint16_t baseOffset = tiling.N / 2;
    uint16_t blockCount = tiling.M;
    uint16_t blockLen = (tiling.N / 2 * sizeof(C_T)) / 32;
    uint16_t srcStride = 0;
    uint16_t dstStride = (tiling.N / 2 * sizeof(C_T)) / 32;
    if (GetSubBlockIdxImpl() == 0) {
        DataCopy(gmC, bufferC, {blockCount, blockLen, srcStride, dstStride});
    } else {
        DataCopy(gmC[baseOffset], bufferC, {blockCount, blockLen, srcStride, dstStride});
    }