SoftmaxFlashV2
Applicability
|
Product |
Supported |
|---|---|
|
Atlas 350 Accelerator Card |
√ |
|
|
√ |
|
|
√ |
|
|
√ |
|
|
√ |
|
|
x |
|
|
x |
Function Usage
Serves as the enhanced version of SoftmaxFlash, corresponding to the FlashAttention-2 algorithm. If the product of non-last axis lengths of the input tensor [m0, m1, ..., mt, n] (t ≥ 0) is considered as m, the shape of the input tensor is [m, n]. This API performs the following computation on the input tensor [m, n] by row. Different values of update correspond to different formulas, where x, inmax, and insum are inputs, and M, S, and E are outputs.
- If update is false, the formulas are as follows.

- If update is true, the formulas are as follows.

When the input shape is in ND format, the internal reduction process is performed along the last axis. When the input shape is in NZ format, the internal reduction process is performed along the last and first axes. For details about the reduction process, see the figures in SoftMax.
For ease of understanding, the formula expressed through a Python script is as follows, where src, inmax, insum, and update are inputs, and dst, x_sum, x_max, and exp_max are outputs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def softmax_flash_2(src, inmax=None, insum=None, update=None): if update is None: x_max = np.max(src, axis=-1, keepdims=True) x_sub = src - x_max dst = np.exp(x_sub) x_sum = np.sum(dst, axis=-1, keepdims=True) exp_max = None return dst, x_max, x_sum, exp_max else: x_max = np.max(np.concatenate((inmax, src), axis=-1), axis=-1, keepdims=True) dst = np.exp(src - x_max) exp_max = np.exp(inmax - x_max) x_sum = np.sum(dst, axis=-1, keepdims=True) x_sum = exp_max * insum + x_sum return dst, x_max, x_sum, exp_max |
Principles
The following figure shows the internal algorithm diagram of the SoftmaxFlashV2 high-level APIs by taking the input tensor of the float type, in ND format, and with shape [m, k] as an example.
The computation process is divided into two branches based on whether isUpdate is enabled, which are both performed on vectors.
- When isUpdate is set to False, the process is as follows:
- reducemax: Compute the maximum value of each row of input x to obtain [m, 1]. The computation result is saved to a temporary space (temp).
- broadcast: Pad the data [m, 1] in temp by data block. For example, for the float type, extend [m, 1] to [m, 8] and output max.
- sub: Subtract max from all data of input x by row.
- exp: Calculate exp for all data after sub and output y.
- reducesum: Sum over each row of data after exp is performed to obtain [m, 1]. The computation result is saved to temp.
- broadcast: Pad [m, 1] in temp by data block. For example, for the float type, extend [m, 1] to [m, 8] and output sum.
- When isUpdate is set to True, the process is as follows:
- reducemax: Compute the maximum value of each row of input x to obtain [m, 1]. The computation result is saved to a temporary space (temp).
- broadcast: Pad the data [m, 1] in temp by data block. For example, for the float type, extend [m, 1] to [m, 8] and save the result as max.
- max: Perform the max operation on the input inmax and the max obtained in the previous step to obtain a new max and output it.
- sub: Subtract the input inmax from the new max, perform exp to obtain expmax, and output it.
- subs: Subtract the input x from the new max by row.
- exp: Calculate exp for all data after sub and output y.
- reducesum: Sum over each row of data after exp is performed to obtain [m, 1]. The computation result is saved to temp.
- broadcast: Pad the data [m, 1] in temp by data block. For example, for the float type, extend [m, 1] to [m, 8] and save the result to sum.
- mul: Multiply insum and expmax.
- add: Add the multiplication result and sum, save the result to sum, and output the result.
Prototype
- Allocate the temporary space through the API framework.
- The data types of LocalTensor are the same, and ReduceMax is not output.
1 2
template <typename T, bool isUpdate = false, bool isReuseSource = false, bool isBasicBlock = false, bool isDataFormatNZ = false, const SoftmaxConfig& config = SOFTMAX_DEFAULT_CFG> __aicore__ inline void SoftmaxFlashV2(const LocalTensor<T>& dstTensor, const LocalTensor<T>& expSumTensor, const LocalTensor<T>& maxTensor, const LocalTensor<T>& srcTensor, const LocalTensor<T>& expMaxTensor, const LocalTensor<T>& inExpSumTensor, const LocalTensor<T>& inMaxTensor, const SoftMaxTiling& tiling, const SoftMaxShapeInfo& softmaxShapeInfo = {})
- The data types of LocalTensor are the same, and ReduceMax is output.
1 2
template <typename T, bool isUpdate = false, bool isReuseSource = false, bool isBasicBlock = false, bool isDataFormatNZ = false, const SoftmaxConfig& config = SOFTMAX_DEFAULT_CFG> __aicore__ inline void SoftmaxFlashV2(const LocalTensor<T>& dstTensor, const LocalTensor<T>& outReduceMax, const LocalTensor<T>& outExpSum, const LocalTensor<T>& outMax, const LocalTensor<T>& srcTensor, const LocalTensor<T>& outExpMax, const LocalTensor<T>& inExpSum, const LocalTensor<T>& inMax, const SoftMaxTiling& tiling, const SoftMaxShapeInfo& softmaxShapeInfo = {})
Atlas 200I/500 A2 inference product : This API is not supported.Atlas inference product AI Core: This API is not supported.
- The data types of LocalTensor are not the same, and ReduceMax is not output.
1 2
template <typename T, bool isUpdate = false, bool isReuseSource = false, bool isBasicBlock = false, bool isDataFormatNZ = false, const SoftmaxConfig& config = SOFTMAX_DEFAULT_CFG> __aicore__ inline void SoftmaxFlashV2(const LocalTensor<half>& dstTensor, const LocalTensor<float>& expSumTensor, const LocalTensor<float>& maxTensor, const LocalTensor<half>& srcTensor, const LocalTensor<half>& expMaxTensor, const LocalTensor<float>& inExpSumTensor, const LocalTensor<float>& inMaxTensor, const SoftMaxTiling& tiling, const SoftMaxShapeInfo& softmaxShapeInfo = {})
- The data types of LocalTensor are the same, and ReduceMax is not output.
- Pass the temporary space through the sharedTmpBuffer input parameter.
- The data types of LocalTensor are the same, and ReduceMax is not output.
1 2
template <typename T, bool isUpdate = false, bool isReuseSource = false, bool isBasicBlock = false, bool isDataFormatNZ = false, const SoftmaxConfig& config = SOFTMAX_DEFAULT_CFG> __aicore__ inline void SoftmaxFlashV2(const LocalTensor<T>& dstTensor, const LocalTensor<T>& outExpSum, const LocalTensor<T>& outMax, const LocalTensor<T>& srcTensor, const LocalTensor<T>& outExpMax, const LocalTensor<T>& inExpSum, const LocalTensor<T>& inMax, const LocalTensor<uint8_t>& sharedTmpBuffer, const SoftMaxTiling& tiling, const SoftMaxShapeInfo& softmaxShapeInfo = {})
- The data types of LocalTensor are the same, and ReduceMax is output.
1 2
template <typename T, bool isUpdate = false, bool isReuseSource = false, bool isBasicBlock = false, bool isDataFormatNZ = false, const SoftmaxConfig& config = SOFTMAX_DEFAULT_CFG> __aicore__ inline void SoftmaxFlashV2(const LocalTensor<T>& dstTensor, const LocalTensor<T>& outReduceMax, const LocalTensor<T>& expSumTensor, const LocalTensor<T>& maxTensor, const LocalTensor<T>& srcTensor, const LocalTensor<T>& expMaxTensor, const LocalTensor<T>& inExpSumTensor, const LocalTensor<T>& inMaxTensor, const LocalTensor<uint8_t>& sharedTmpBuffer, const SoftMaxTiling& tiling, const SoftMaxShapeInfo& softmaxShapeInfo = {})
Atlas 200I/500 A2 inference product : This API is not supported.Atlas inference product AI Core: This API is not supported.
- The data types of LocalTensor are not the same, and ReduceMax is not output.
1 2
template <typename T, bool isUpdate = false, bool isReuseSource = false, bool isBasicBlock = false, bool isDataFormatNZ = false, const SoftmaxConfig& config = SOFTMAX_DEFAULT_CFG> __aicore__ inline void SoftmaxFlashV2(const LocalTensor<half>& dstTensor, const LocalTensor<float>& expSumTensor, const LocalTensor<float>& maxTensor, const LocalTensor<half>& srcTensor, const LocalTensor<half>& expMaxTensor, const LocalTensor<float>& inExpSumTensor, const LocalTensor<float>& inMaxTensor, const LocalTensor<uint8_t>& sharedTmpBuffer, const SoftMaxTiling& tiling, const SoftMaxShapeInfo& softmaxShapeInfo = {})
- The data types of LocalTensor are the same, and ReduceMax is not output.
Due to the complex computation involved in the internal implementation of this API, additional 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 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 and 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 the tensor. The method of obtaining the temporary space size (BufferSize) is as follows: Obtain the required maximum and minimum temporary space sizes using the GetSoftMaxFlashV2MinTmpSize/GetSoftMaxFlashV2MaxTmpSize API provided in SoftmaxFlashV2 Tiling. The minimum space can ensure correct functionality, while the maximum space is used to improve performance.
In addition, an API for tiling computation in the kernel provided. When the input shape in the kernel is different from the shape transferred through TilingData on the host, this API can be used to recompute tiling in the kernel. For details about the parameters of this API, see SoftmaxFlashV2 Tiling.
- Tiling computation API in the kernel
1__aicore__ inline constexpr SoftMaxTiling SoftMaxFlashV2TilingFunc(const SoftMaxShapeInfo& shapeInfo, const uint32_t dataTypeSize1, const uint32_t dataTypeSize2, const uint32_t localWorkSpaceSize, const bool isUpdate = false, const bool isBasicBlock = false, const bool isDataFormatNZ = false, const bool isFlashOutputBrc = false)
Parameters
|
Parameter |
Description |
||||
|---|---|---|---|---|---|
|
T |
Data type of the operand. For the Atlas 350 Accelerator Card, the supported data types are half and float. For the For the For the For the |
||||
|
isUpdate |
Whether to enable update. |
||||
|
isReuseSource |
This parameter is reserved. Pass the default value false. |
||||
|
isBasicBlock |
If the shape information and tiling strategy of both srcTensor and dstTensor meet the base block requirements, this parameter can be enabled to improve performance. By default, this parameter is disabled. Use either of the following methods to determine whether the base block requirements are met:
For the |
||||
|
isDataFormatNZ |
Whether the current input and output data is in NZ format. The default data format is ND, that is, the default value of this parameter is false. For the |
||||
|
config |
(Optional) structure template parameter, which is of the SoftmaxConfig type. The definition is as follows:
The mode parameter indicates the processing mode of the output shape. This parameter is not supported when the input and output data is in NZ format. The type is SoftmaxMode. The options are as follows.
A configuration example is as follows:
This parameter is used together with the tiling computation API on the kernel. Note: After oriSrcM and oriSrcK are set, isBasicBlock does not take effect. In this case, whether the computation data is a base block is determined and processed by the API. For the Atlas 350 Accelerator Card, this parameter is supported. For the For the For the For the |
|
Parameter |
Input/Output |
Description |
||
|---|---|---|---|---|
|
dstTensor |
Output |
Destination operand. The type is LocalTensor, and TPosition can be VECIN, VECCALC, or VECOUT. The shape of dstTensor is the same as that of the source operand srcTensor. |
||
|
outReduceMax |
Output |
Destination operand. It is used to store the result of the first reducemax computation in the softmax computation. The type is LocalTensor, and TPosition can be VECIN, VECCALC, or VECOUT. The shape of outReduceMax is the same as that of the destination operand maxTensor. For the API that outputs the result:
|
||
|
expSumTensor, outExpSum |
Output |
Destination operand. It is used to store the reducesum result during softmax computation. The type is LocalTensor, and TPosition can be VECIN, VECCALC, or VECOUT.
|
||
|
maxTensor, outMax |
Output |
Destination operand. It is used to store the reducemax result during softmax computation. 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. The length of the last axis must be 32-byte aligned. |
||
|
expMaxTensor, outExpMax |
Output |
Destination operand. It is used to store the exponentiation (base e) of the difference between inmax and reducemax. The type is LocalTensor, and TPosition can be VECIN, VECCALC, or VECOUT.
|
||
|
inExpSumTensor, inExpSum |
Input |
Source operand. This parameter indicates the sum value required for softmax computation. The type is LocalTensor, and TPosition can be VECIN, VECCALC, or VECOUT.
|
||
|
inMaxTensor, inMax |
Input |
Source operand. This parameter indicates the max value required for softmax computation. The type is LocalTensor, and TPosition can be VECIN, VECCALC, or VECOUT.
|
||
|
sharedTmpBuffer |
Input |
Temporary space. The type is LocalTensor, and TPosition can be VECIN, VECCALC, or VECOUT. The data type of this operand is fixed at uint8_t. This parameter is used to store intermediate variables during complex internal API computation and is provided by developers. For details about how to obtain the temporary space size (BufferSize), see SoftmaxFlashV2 Tiling. |
||
|
tiling |
Input |
Tiling information required for softmaxflashv2 computation. For details about how to obtain the tiling information, see SoftmaxFlashV2 Tiling. |
||
|
softmaxShapeInfo |
Input |
Shape of srcTensor, SoftMaxShapeInfo type. The specific definition is as follows:
Note that when the input and output data is in NZ format, the last axis length is the length of the reduce axis, that is, W0 × W1 in Figure 2 and the length of each non-last axis is H0 × H1. |
Returns
None
Restrictions
- The tensor space of srcTensor and dstTensor, maxTensor and inMaxTensor, and expSumTensor and inExpSumTensor can be reused.
- Except when the template parameter config is set to a non-extended mode (SoftmaxMode::SOFTMAX_OUTPUT_WITHOUT_BRC), the length of the last axis must be fixed at 32 bytes for the tensor space of expSumTensor, maxTensor, expMaxTensor, inExpSumTensor, and inMaxTensor.
- For the API that outputs ReduceMax:
- The template parameters isReuseSource, isDataFormatNZ, and config.isCheckTiling are reserved.
- config.mode can only be set to the non-extended mode SOFTMAX_OUTPUT_WITHOUT_BRC. If it is set to the SOFTMAX_NORMAL mode, the API function is not executed, and the outputs are not saved.
- When the template parameter isUpdate is set to false, outReduceMax is not output.
- Except outReduceMax, the computation result of each output is the same as that of the API that does not output ReduceMax.
- For details about the operand address alignment requirements, see General Address Alignment Restrictions.
- The address of sharedTmpBuffer cannot overlap that of the source or destination operand.
- When srcM ! is set to oriSrcM or srcK ! is set to oriSrcK in softmaxShapeInfo, for the original input (oriSrcM, oriSrcK) on the GM, you need to pad data to (srcM, srcK) in the M or K direction. The padded data will be involved in some computation. In the scenario where the input and output are reused, the computation result of the API will overwrite the original data padded to the srcTensor. In the scenario where the input and output are not reused, the computation result of the API will overwrite the data in dstTensor corresponding to the padded position of srcTensor.
Examples
- srcK aligned
In this example, the shape size of the input srcTensor and output dstTensor is [320, 64], the shape size of the input inSumTensor, input inMaxTensor, and output expMaxTensor is [320, 16]. The data type is half, and the format of the input and output data is ND. The space of srcTensor and dstTensor cannot be reused, the base block is disabled, and isUpdate is set to true. For details about the complete operator sample, see softmaxflashv2 operator sample.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// dstLocal: tensor for storing the SoftMax computation result // expSumLocal: stores the reducesum result during SoftMax computation // maxLocal: stores the reducemax result during SoftMax computation // srcLocal: input tensor for storing data for SoftMax computation // expMaxLocal: stores the exponentiation (base e) of the difference between inmax and reducemax // inExpSumLocal: stores the sum value required for SoftMax computation // inMaxLocal: stores the max value required for SoftMax computation // sharedTmpBuffer: tensor for storing the temporary buffer during SoftMax computation // softmaxTiling: structure for storing the tiling information required for SoftMax computation, which can be obtained through the SoftMaxFlashV2TilingFunc API AscendC::SoftMaxShapeInfo softmaxInfo( /* Product of lengths of non-last axes */ 320, /* Length of the last axis, which must be 32-byte aligned */ 64, /* Product of lengths of original non-last axes */ 320, /* Length of the original last axis */ 64 ); // Pass the temporary space through the sharedTmpBuffer input parameter, with ReduceMax not output. Pass the template parameter to turn the shape into a constant value. AscendC::SoftmaxFlashV2<T, true, false, false, false, static_config>(dstLocal, expSumLocal, maxLocal, srcLocal, expMaxLocal, inExpSumLocal, inMaxLocal, sharedTmpBuffer, tiling, softmaxInfo); // Pass the temporary space through the sharedTmpBuffer input parameter, with ReduceMax not output. AscendC::SoftmaxFlashV2<T, true>(dstLocal, expSumLocal, maxLocal, srcLocal, expMaxLocal, inExpSumLocal, inMaxLocal, sharedTmpBuffer, tiling, softmaxInfo); // Allocate the temporary space through the API framework, with sumTensor and maxTensor. AscendC::SoftmaxFlashV2<T, true>(dstLocal, expSumLocal, maxLocal, srcLocal, expMaxLocal, inExpSumLocal, inMaxLocal, tiling, softmaxInfo);
Result example:
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 31 32
Input (srcLocal): [[-10. -10. -10. ... -9.94 -9.94 -9.94 ] [ -9.94 -9.94 -9.94 ... -9.875 -9.875 -9.875] [ -9.875 -9.875 -9.875 ... -9.81 -9.81 -9.81 ] ... [ 9.81 9.81 9.81 ... 9.875 9.875 9.875] [ 9.875 9.875 9.875 ... 9.94 9.94 9.94 ] [ 9.94 9.94 9.94 ... 10. 10. 10. ]] Output (expSumLocal): [[62.03 62.03 62.03 ... 62.03 62.03 62.03] [62.03 62.03 62.03 ... 62.03 62.03 62.03] [62.03 62.03 62.03 ... 62.03 62.03 62.03] ... [62.03 62.03 62.03 ... 62.03 62.03 62.03] [62.03 62.03 62.03 ... 62.03 62.03 62.03] [62.03 62.03 62.03 ... 62.03 62.03 62.03]] Output (maxLocal): [[-9.94 -9.94 -9.94 ... -9.94 -9.94 -9.94 ] [-9.875 -9.875 -9.875 ... -9.875 -9.875 -9.875] [-9.81 -9.81 -9.81 ... -9.81 -9.81 -9.81 ] ... [ 9.875 9.875 9.875 ... 9.875 9.875 9.875] [ 9.94 9.94 9.94 ... 9.94 9.94 9.94 ] [10. 10. 10. ... 10. 10. 10. ]] Output (dstLocal): [[0.015144 0.015144 0.015144 ... 0.01611 0.01611 0.01611 ] [0.015144 0.015144 0.015144 ... 0.01611 0.01611 0.01611 ] [0.015144 0.015144 0.015144 ... 0.01611 0.01611 0.01611 ] ... [0.015144 0.015144 0.015144 ... 0.01611 0.01611 0.01611 ] [0.015144 0.015144 0.015144 ... 0.01611 0.01611 0.01611 ] [0.015144 0.015144 0.015144 ... 0.01611 0.01611 0.01611 ]]
- srcK unaligned
In this example, the shape size of input srcTensor and output dstTensor is [320, 63], the data type is half, and the input and output data layout is ND. This example shows the data movement and API usage under non-aligned padding scenarios.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include "kernel_operator.h" // Init phase: height = 320, width = 63 padWidth = AlignUp(width * sizeof(T), 32) / sizeof(T); // Copyin phase AscendC::DataCopyExtParams copyParams{static_cast<uint16_t>(height), static_cast<uint32_t>(width * sizeof(T)), 0, 0, 0}; AscendC::DataCopyPadExtParams<T> padParam = {true, 0, static_cast<uint8_t>(padWidth - width), 0}; AscendC::DataCopyPad(srcLocal, srcGlobal, copyParams, padParam); // Compute phase // Due to padding, the shape during API calling is inconsistent with the original shape. AscendC::SoftMaxShapeInfo srcShape = {height, padWidth, height, width}; AscendC::SoftmaxFlashV2<T, true>(dstLocal, expSumLocal, maxLocal, srcLocal, expMaxLocal, inExpSumLocal, inMaxLocal, tiling, srcShape); // Copyout phase AscendC::DataCopyExtParams copyParams{static_cast<uint16_t>(height), static_cast<uint32_t>(width * sizeof(T)), 0, 0, 0}; AscendC::DataCopyPad(dstGlobal, dstLocal, copyParams);
Result example:
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 31 32
Input (srcLocal): [[-10. -10. -10. ... -9.94 -9.94 0. ] [ -9.94 -9.94 -9.94 ... -9.875 -9.875 0. ] [ -9.875 -9.875 -9.875 ... -9.81 -9.81 0. ] ... [ 9.81 9.81 9.81 ... 9.875 9.875 0. ] [ 9.875 9.875 9.875 ... 9.94 9.94 0. ] [ 9.94 9.94 9.94 ... 10. 10. 0. ]] Output (expSumLocal): [[61.03 61.03 61.03 ... 61.03 61.03 61.03] [61.03 61.03 61.03 ... 61.03 61.03 61.03] [61.03 61.03 61.03 ... 61.03 61.03 61.03] ... [61.1 61.1 61.1 ... 61.1 61.1 61.1 ] [61.1 61.1 61.1 ... 61.1 61.1 61.1 ] [61.1 61.1 61.1 ... 61.1 61.1 61.1 ]] Output (maxLocal): [[-9.94 -9.94 -9.94 ... -9.94 -9.94 -9.94 ] [-9.875 -9.875 -9.875 ... -9.875 -9.875 -9.875] [-9.81 -9.81 -9.81 ... -9.81 -9.81 -9.81 ] ... [ 9.875 9.875 9.875 ... 9.875 9.875 9.875] [ 9.94 9.94 9.94 ... 9.94 9.94 9.94 ] [10. 10. 10. ... 10. 10. 10. ]] Output (dstLocal): [[0.015396 0.015396 0.015396 ... 0.01639 0.01639 0.01639 ] [0.015396 0.015396 0.015396 ... 0.01639 0.01639 0.01639 ] [0.015396 0.015396 0.015396 ... 0.01639 0.01639 0.01639 ] ... [0.01538 0.01538 0.01538 ... 0.01637 0.01637 0.01637 ] [0.01538 0.01538 0.01538 ... 0.01637 0.01637 0.01637 ] [0.01538 0.01538 0.01538 ... 0.01637 0.01637 0.01637 ]]