Quantize

Applicability

Product

Supported

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

Atlas inference product AI Core

x

Atlas inference product Vector Core

x

Atlas training product

x

Function Usage

Performs quantization computation by element to convert high-precision data into low-precision data. This API supports four types of quantization policies: PER_TENSOR, PER_CHANNEL, PER_TOKEN, and PER_GROUP. Each type of quantization policy supports the configuration of the rounding mode. This API supports only two-dimensional input data.

Quantize has similar function to AscendQuant. Quantize extends the function of configuring the rounding mode in the PER_TENSOR and PER_CHANNEL quantization scenarios. Therefore, you are advised to use this API.

  • PER_TENSOR quantization: srcTensor corresponds to a quantization parameter. The shape of scale and offset is [1].

  • PER_CHANNEL quantization: The shape of srcTensor is [m, n]. Each channel dimension corresponds to a quantization parameter. The shape of scale and offset is [1, n].

  • PER_TOKEN quantization: The elements in each group of tokens (m groups of tokens in the n direction) of srcTensor share a quantization parameter. When the shape of srcTensor is [m, n], the shape of scale and offset is [m, 1].

  • PER_GROUP quantization: The compute direction of groups is defined as k. In the k direction, each groupSize elements of srcTensor shares a group of scale and offset. When the shape of srcTensor is [m, n], if kDim is 0, k is in the m direction, and the shape of scale and offset is [(m + groupSize – 1)/groupSize, n]; if kDim is 1, k is in the n direction, and the shape of scale and offset is [m, (n + groupSize – 1)/groupSize].
    Based on the output data type, PER_GROUP is classified into two scenarios: fp4x2_e2m1_t/fp4x2_e1m2_t scenario (referred to as the float4 scenario) and int8_t/hifloat8_t/fp8_e5m2_t/fp8_e4m3fn_t scenario (referred to as the b8 scenario).
    • fp4x2_e2m1_t/fp4x2_e1m2_t scenario (float4 scenario)
      • kDim = 0:

      • kDim = 1:

    • int8_t/hifloat8_t/fp8_e5m2_t/fp8_e4m3fn_t scenario (b8 scenario)
      • kDim = 0:

      • kDim = 1:

Prototype

  • Pass the temporary space through the sharedTmpBuffer input parameter.
    1
    2
    template <const QuantizeConfig& config, typename DstT, typename SrcT, typename ScaleT, typename OffsetT>
    __aicore__ inline void Quantize(const LocalTensor<DstT>& dstTensor, const LocalTensor<SrcT>& srcTensor, const LocalTensor<uint8_t>& sharedTmpBuffer, const ScaleT& scale, const OffsetT& offset, const QuantizeParams& params)
    
  • Allocate the temporary space through the API framework.
    1
    2
    template <const QuantizeConfig& config, typename DstT, typename SrcT, typename ScaleT, typename OffsetT>
    __aicore__ inline void Quantize(const LocalTensor<DstT>& dstTensor, const LocalTensor<SrcT>& srcTensor,const ScaleT& scale, const OffsetT& offset, const QuantizeParams& params)
    

Due to the complex mathematical computation involved in the internal implementation of this API, extra temporary space is required to store intermediate variables generated during computation. The temporary space can be allocated through the API framework or passed by developers through the sharedTmpBuffer input parameter.

  • When the API framework is used for temporary space allocation, developers do not need to allocate the space, but must reserve the required size for the temporary space.
  • When the sharedTmpBuffer input parameter is used for passing the temporary space, the tensor serves as the temporary space. In this case, the API framework is not required for temporary space allocation. This enables developers to manage the sharedTmpBuffer space and reuse the buffer after calling the API, so that the buffer is not repeatedly allocated or deallocated, improving the flexibility and buffer utilization.

If the API framework is used, developers must reserve the temporary space. If sharedTmpBuffer is used, developers must allocate space for sharedTmpBuffer. To obtain the size of the temporary space (BufferSize) to be reserved, use the API provided in GetQuantizeMaxMinTmpSize.

Parameters

Table 1 Template parameters

Parameter

Description

config

Quantization configuration. The type is QuantizeConfig. The definition is as follows:

1
2
3
4
5
6
struct QuantizeConfig {
    QuantizePolicy policy;
    bool hasOffset;
    RoundMode roundMode = RoundMode::CAST_RINT;
    int32_t kDim = 1;
 }
  • policy: quantization policy, which is of the enumeration type. The definition is as follows:
    1
    2
    3
    4
    5
    6
    enum class QuantizePolicy : int32_t {
        PER_TENSOR,
        PER_CHANNEL,
        PER_TOKEN,
        PER_GROUP
    }
    
  • hasOffset: indicates whether offset is involved in the computation.
    • true: offset is involved in the computation.
    • false: offset is not involved in the computation.
  • roundMode: rounding mode for converting high-precision data into low-precision data during quantization. The value can be CAST_RINT, CAST_ROUND, CAST_FLOOR, CAST_CEIL, CAST_TRUNC, or CAST_HYBRID. For details about each rounding mode, see Precision conversion rules. Different data types support different rounding modes for quantization. If an unsupported rounding mode is used during quantization, the default rounding mode is used. For example, when the bfloat16_t type is quantized to the hifloat8_t type, if roundMode is set to CAST_RINT that is not supported, the default value CAST_ROUND of roundMode is used during quantization. For details about the rounding modes supported by different data types, see Table 3.
  • kDim: compute direction of groups, that is, the k direction. This parameter is valid only in the PER_GROUP scenario. The following values are supported:
    • 0: The k axis is axis 0. That means the compute direction of groups is m.
    • 1: The k axis is axis 1. That means the compute direction of groups is n.

DstT

Data type of the destination operand. The data type is automatically derived from the input parameter dstTensor in the API. You do not need to set this parameter. Ensure that dstTensor meets the data type combinations supported by the input and output in Table 3.

SrcT

Data type of the source operand. The data type is automatically derived from the input parameter srcTensor in the API. You do not need to set this parameter. Ensure that srcTensor meets the data type combinations supported by the input and output in Table 3.

ScaleT

Data type of scale. The data type is automatically derived from the input parameter scale in the API. You do not need to set this parameter. ScaleT can be a scalar or LocalTensor.

Note:

  • For the PER_TENSOR quantization policy, scale is a scalar, and ScaleT can only be a scalar.
  • For the PER_CHANNEL, PER_TOKEN, and PER_GROUP quantization policies, scale is a vector, and ScaleT can only be a LocalTensor.

OffsetT

Data type of offset. The data type is automatically derived from the input parameter offset in the API. You do not need to set this parameter. OffsetT can be a scalar or LocalTensor.

Note:

  • For the PER_TENSOR quantization policy, offset is a scalar, and OffsetT can only be a scalar.
  • For the PER_CHANNEL, PER_TOKEN, and PER_GROUP quantization policies, offset can be a scalar or vector, and OffsetT can be a scalar or LocalTensor.
Table 2 API parameters

Parameter

Input/Output

Description

dstTensor

Output

Destination operand.

The type is LocalTensor, and TPosition can be VECIN, VECCALC, or VECOUT.

srcTensor

Input

Source operand.

The type is LocalTensor, and TPosition can be VECIN, VECCALC, or VECOUT.

scale

Input

Scaling factor when the input data is quantized.

offset

Input

Offset when the input data is quantized.

For the Ascend 910_95 AI Processor, offset does not take effect in the PER_GROUP float4 scenario.

sharedTmpBuffer

Input

Temporary buffer.

The type is LocalTensor, and TPosition can be VECIN, VECCALC, or VECOUT.

For details about how to obtain the temporary space size (BufferSize), see GetQuantizeMaxMinTmpSize.

params

Input

Quantization API parameter, which is of the QuantizeParams type. The definition is as follows:

1
2
3
4
5
struct QuantizeParams {
        uint32_t m;
        uint32_t n;
        uint32_t groupSize = 0;
}
  • m: number of elements in the m direction.
  • n: number of elements in the n direction. The data size corresponding to the value of n must be 32-byte aligned, indicating that the input and output whose last dimension of the shape is n must be 32-byte aligned.
  • groupSize: The parameter is valid in the PER_GROUP scenario. It indicates that data in the groupSize row or column shares scale or offset. The value of groupSize must be greater than 0 and an integer multiple of 32.
Table 3 Data type groups supported by the input and output.

SrcT

ScaleT/OffsetT

DstT

roundMode

half

half

fp8_e5m2_t/fp8_e4m3fn_t

  • CAST_RINT (default)

bfloat16_t

bfloat16_t

float

float

half

float

bfloat16_t

float

half

half

hifloat8_t

  • CAST_ROUND (default)
  • CAST_HYBRID

bfloat16_t

bfloat16_t

float

float

half

float

bfloat16_t

float

half

half

int8_t

  • CAST_RINT (default)
  • CAST_ROUND
  • CAST_FLOOR
  • CAST_CEIL
  • CAST_TRUNC

bfloat16_t

bfloat16_t

float

float

half

float

bfloat16_t

float

half

half

fp4x2_e1m2_t/fp4x2_e2m1_t

(Currently, only the PER_GROUP scenario is supported.)

bfloat16_t

bfloat16_t

float

float

half

float

bfloat16_t

float

Returns

None

Constraints

  • The source operand address must not overlap the destination operand address.
  • For details about the operand address alignment requirements, see General Address Alignment Restrictions.
  • The length of the data involved in computation of the input and output operands must be 32-byte aligned.
  • The data volume in the continuous computation direction (n direction) must be 32-byte aligned.
  • In the PER_GROUP float4 scenario, offset is not supported. In this scenario, the hasOffset parameter in the template parameter config must be set to false.

Examples

  • PER_CHANNEL, PER_TOKEN, and PER_GROUP modes
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    constexpr static QuantizePolicy tokenPolicy = QuantizePolicy::PER_TOKEN;
    constexpr static QuantizePolicy channelPolicy = QuantizePolicy::PER_CHANNEL;
    constexpr static QuantizePolicy groupPolicy = QuantizePolicy::PER_GROUP;
    // The PER_TOKEN mode is used as an example. Enable the offset function and set the rounding mode to CAST_ROUND. kDim is valid only in the PER_GROUP scenario, indicating that the compute direction of groups is n.
    constexpr static QuantizeConfig config = {tokenPolicy, true, RoundMode::CAST_ROUND, 1};
    QuantizeParams params;
    // m and n are external input parameters, indicating the number of elements in the m and n directions involved in srcLocal.
    params.m = m;
    params.n = n;
    params.groupSize = n; // This is valid only in the PER_GROUP scenario. It indicates that all elements in the n direction share a group of scale and offset.
    // dstLocal is a LocalTensor of the int8_t type, and srcLocal, scale, and offset are a LocalTensor of the half type.
    Quantize<config>(dstLocal, srcLocal, scale, offset, params);
    
  • PER_TENSOR mode
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    constexpr static QuantizePolicy tensorPolicy = QuantizePolicy::PER_TENSOR;
    // Enable the offset function and set the rounding mode to CAST_ROUND.
    constexpr static QuantizeConfig config = {tensorPolicy, true, RoundMode::CAST_ROUND, -1};
    QuantizeParams params;
    // m and n are external input parameters, indicating the number of elements in the m and n directions involved in srcLocal.
    params.m = m;
    params.n = n;
    params.groupSize = 0; // This is valid only in the PER_GROUP scenario.
    // dstLocal is a LocalTensor of the int8_t type, srcLocal is a LocalTensor of the half type, and scale and offset are scalars of the half type.
    Quantize<config>(dstLocal, srcLocal, scale, offset, params);
    

Result example:

Input (srcLocal):
[-4.4, 2.5, -2.9, -3.1, -1.5, -4.8, 1.8, 3.5, 4.5, 1.1, -2.7, 0.5, ... 1.6]
Input (scale vector):
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... 1]
Input (scale scalar):
[1]
Input (offset vector):
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0]
Input (offset scalar):
[0]
Output (dstLocal):
[-4, 3, -3, -3, -1, -5, 2, 4, 5, 1, -3, 1, ... 2]