#ifndef MSDA_H
#define MSDA_H
* Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
* \file msda.h
* \brief msda & msda_grad operator
*/
#include "kernel_operator.h"
#include "kernel_tpipe_impl.h"
#include "kernel_utils.h"
using namespace AscendC;
template<bool aligned, bool forward, bool fastMode>
class MSDABaseKernel {
public:
__aicore__ inline MSDABaseKernel() = delete;
__aicore__ inline MSDABaseKernel(GM_ADDR value, GM_ADDR valueSpatialShapes, GM_ADDR valueLevelStartIndex,
GM_ADDR samplingLocations, GM_ADDR attentionWeights, GM_ADDR user, const MultiScaleDeformableAttnTilingData* tilingData,
TPipe* pipe)
: pipe_(pipe), blkIdx_(GetBlockIdx())
{
InitTiling(tilingData, user);
InitGM(value, valueSpatialShapes, valueLevelStartIndex, samplingLocations, attentionWeights);
InitBuffer();
ResetMask();
SetAtomicNone();
}
protected:
__aicore__ inline uint32_t GetInnerLoops(uint32_t x)
{
uint32_t candicateList[4] = {8, 16, 32, 64};
uint32_t i;
for (i = 1; i < 4; i++) {
if (x / candicateList[i] == 0) {
break;
}
}
return candicateList[i - 1];
}
__aicore__ inline void InitTiling(const MultiScaleDeformableAttnTilingData* tilingData, GM_ADDR user)
{
batchSize_ = tilingData->batchSize;
numKeys_ = tilingData->numKeys;
numHeads_ = tilingData->numHeads;
embedDims_ = tilingData->embedDims;
numLevels_ = tilingData->numLevels;
numQueries_ = tilingData->numQueries;
numPoints_ = tilingData->numPoints;
coreNum_ = tilingData->coreNum;
realLevels_ = tilingData->realLevels;
aicNum_ = tilingData->aicNum;
locationSwap = user + tilingData->locationWorkSpaceOffset;
validFlagSwap = user + tilingData->validFlagWorkSpaceOffset;
assemble = user + tilingData->assembleWorkSpaceOffset;
zero = user + tilingData->zeroWorkSpaceOffset;
oneQueryNum_ = numHeads_ * realLevels_ * numPoints_;
oneHeadNum_ = numLevels_ * numPoints_;
alignedEmbedDims_ = AlignUp(embedDims_, B32_DATA_NUM_PER_BLOCK);
if constexpr (fastMode) {
outerLoops_ = 1;
innerLoops_ = numHeads_ * oneHeadNum_;
innerLoopsAligned_ = AlignUp(innerLoops_, 8);
innerLoopsAligned_ = B32_DATA_NUM_PER_REPEAT / (B32_DATA_NUM_PER_REPEAT / innerLoopsAligned_);
alignedOneHeadNum_ = oneHeadNum_;
alignedOneQueryNum_ = innerLoopsAligned_;
alignedCornerEmbedDims_ = innerLoops_ * alignedEmbedDims_;
innerTotal_ = numHeads_ * oneHeadNum_;
innerTotalGroup_ = 1;
innerEmbedDims_ = numHeads_ * alignedEmbedDims_;
brcRpt_ = DivCeil(4 * innerLoops_ * B32_DATA_NUM_PER_BLOCK, B32_DATA_NUM_PER_REPEAT);
} else {
uint32_t maxInnerDims = 2048;
innerLoops_ = oneHeadNum_ * alignedEmbedDims_ <= maxInnerDims ? oneHeadNum_ : GetInnerLoops(maxInnerDims / alignedEmbedDims_);
innerLoopsAligned_ = AlignUp(innerLoops_, 8);
innerLoopsAligned_ = B32_DATA_NUM_PER_REPEAT / (B32_DATA_NUM_PER_REPEAT / innerLoopsAligned_);
outerLoops_ = numHeads_ * DivCeil(oneHeadNum_, innerLoopsAligned_);
alignedOneHeadNum_ = AlignUp(oneHeadNum_, innerLoopsAligned_);
alignedOneQueryNum_ = numHeads_ * alignedOneHeadNum_;
alignedCornerEmbedDims_ = innerLoops_ * alignedEmbedDims_;
innerTotal_ = oneHeadNum_;
innerTotalGroup_ = DivCeil(oneHeadNum_, innerLoopsAligned_);
innerEmbedDims_ = alignedEmbedDims_;
brcRpt_ = DivCeil(4 * innerLoops_ * B32_DATA_NUM_PER_BLOCK, B32_DATA_NUM_PER_REPEAT);
}
alignedHeadEmbedDims_ = numHeads_ * alignedEmbedDims_;
outDims_ = numHeads_ * embedDims_;
embedBlk_ = DivCeil(embedDims_, B32_DATA_NUM_PER_BLOCK);
outBlk_ = numHeads_ * embedBlk_;
embedLoops_ = DivCeil(embedDims_, B32_DATA_NUM_PER_REPEAT);
embedTail_ = embedDims_ % B32_DATA_NUM_PER_REPEAT;
embedMask_ = embedTail_ == 0 ? FULL_MASK : (1UL << embedTail_) - 1;
cornerRpt_ = DivCeil(4 * alignedCornerEmbedDims_, B32_DATA_NUM_PER_REPEAT);
uint32_t totalUbSize = 192 * 1024;
uint32_t reservedUbSize = 16 * 1024;
uint32_t usedUbSize = 8 * validFlagMaskLen_ + 3 * cornerRpt_ * B32_DATA_NUM_PER_REPEAT * B32_BYTE_SIZE;
uint32_t queryUbSize = 26 * alignedOneQueryNum_ * B32_BYTE_SIZE + alignedHeadEmbedDims_ * B32_BYTE_SIZE;
if (!forward) {
queryUbSize = queryUbSize + 7 * alignedOneQueryNum_ * B32_BYTE_SIZE;
}
uint32_t avgTasks = (batchSize_ * numQueries_) / coreNum_;
uint32_t remainTasks = (batchSize_ * numQueries_) % coreNum_;
startOffset_ = avgTasks * blkIdx_ + (blkIdx_ < remainTasks ? blkIdx_ : remainTasks);
endOffset_ = startOffset_ + avgTasks + (blkIdx_ < remainTasks ? 1 : 0);
uint32_t modeUpperNum_ = 1024 / alignedOneQueryNum_;
compTaskNum_ = (totalUbSize - reservedUbSize - usedUbSize) / queryUbSize;
compTaskNum_ = min(compTaskNum_, modeUpperNum_);
compTaskNum_ = max(compTaskNum_, (uint32_t)1);
taskLoops_ = (batchSize_ * numQueries_) / (coreNum_ * compTaskNum_);
coopRound = taskLoops_;
tailStart_ = taskLoops_ * (coreNum_ * compTaskNum_);
uint32_t tailBlocks = batchSize_ * numQueries_ - tailStart_;
taskLoops_ += tailBlocks > 0 ? 1 : 0;
uint32_t tailAvgTasks = tailBlocks / coreNum_;
uint32_t tailRemainTasks = tailBlocks % coreNum_;
blockTailStart_ = tailStart_ + tailAvgTasks * blkIdx_ + (blkIdx_ < tailRemainTasks ? blkIdx_ : tailRemainTasks);
blockTailTask_ = tailAvgTasks + (blkIdx_ < tailRemainTasks ? 1 : 0);
outerLoops_ = outerLoops_ * compTaskNum_;
alignedOneTaskNum_ = AlignUp(compTaskNum_ * alignedOneQueryNum_, B32_DATA_NUM_PER_REPEAT);
taskRpt_ = DivCeil(alignedOneTaskNum_, B32_DATA_NUM_PER_REPEAT);
cpRowDoubleParams_.dstStride =
alignedCornerEmbedDims_ / B32_DATA_NUM_PER_BLOCK - DivCeil(embedDims_, B32_DATA_NUM_PER_BLOCK);
cpOutParams_.blockCount = compTaskNum_ * numHeads_;
if constexpr (aligned) {
cpOneValParams_.blockLen = embedBlk_;
cpRowDoubleParams_.blockLen = embedBlk_;
cpRowDoubleParams_.srcStride = outBlk_ - embedBlk_;
cpOutParams_.blockLen = embedBlk_;
} else {
cpOneValParams_.blockLen = embedDims_ * B32_BYTE_SIZE;
cpRowDoubleParams_.blockLen = embedDims_ * B32_BYTE_SIZE;
cpRowDoubleParams_.srcStride = (outDims_ - embedDims_) * B32_BYTE_SIZE;
cpOutParams_.blockLen = embedDims_ * B32_BYTE_SIZE;
}
if (fastMode) {
cpSampleParams_.blockCount = compTaskNum_;
cpSampleParams_.blockLen = numHeads_ * oneHeadNum_ * B32_BYTE_SIZE;
cpSampleParams_.dstStride =
alignedOneQueryNum_ / B32_DATA_NUM_PER_BLOCK - DivCeil(innerLoops_, B32_DATA_NUM_PER_BLOCK);
cpSampleParams_.srcStride = (oneQueryNum_ - numHeads_ * oneHeadNum_) * B32_BYTE_SIZE;
cpDoubleSampleParams_.blockCount = compTaskNum_;
cpDoubleSampleParams_.blockLen = 2 * numHeads_ * oneHeadNum_ * B32_BYTE_SIZE;
cpDoubleSampleParams_.dstStride =
2 * alignedOneQueryNum_ / B32_DATA_NUM_PER_BLOCK - DivCeil(2 * innerLoops_, B32_DATA_NUM_PER_BLOCK);
cpDoubleSampleParams_.srcStride = (2 * oneQueryNum_ - 2 * numHeads_ * oneHeadNum_) * B32_BYTE_SIZE;
} else {
cpSampleParams_.blockCount = compTaskNum_ * numHeads_;
cpSampleParams_.blockLen = oneHeadNum_ * B32_BYTE_SIZE;
cpSampleParams_.dstStride =
alignedOneHeadNum_ / B32_DATA_NUM_PER_BLOCK - DivCeil(oneHeadNum_, B32_DATA_NUM_PER_BLOCK);
cpDoubleSampleParams_.blockCount = compTaskNum_ * numHeads_;
cpDoubleSampleParams_.blockLen = 2 * oneHeadNum_ * B32_BYTE_SIZE;
cpDoubleSampleParams_.dstStride =
2 * alignedOneHeadNum_ / B32_DATA_NUM_PER_BLOCK - DivCeil(2 * oneHeadNum_, B32_DATA_NUM_PER_BLOCK);
}
gatherParams_.repeatTimes = taskRpt_ * 2;
}
__aicore__ inline void InitGM(GM_ADDR value, GM_ADDR valueSpatialShapes, GM_ADDR valueLevelStartIndex,
GM_ADDR samplingLocations, GM_ADDR attentionWeights)
{
valueGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(value));
locationGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(samplingLocations));
attentionWeightsGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(attentionWeights));
valueSpatialShapesGm_.SetGlobalBuffer(reinterpret_cast<__gm__ int32_t*>(valueSpatialShapes));
valueLevelStartIndexGm_.SetGlobalBuffer(reinterpret_cast<__gm__ int32_t*>(valueLevelStartIndex));
assembleGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(this->assemble));
locationSwapGm_.SetGlobalBuffer(reinterpret_cast<__gm__ int32_t*>(this->locationSwap));
validFlagSwapGm_.SetGlobalBuffer(reinterpret_cast<__gm__ uint64_t*>(this->validFlagSwap));
zeroGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(this->zero));
}
__aicore__ inline void InitBuffer()
{
if constexpr (!forward) {
pipe_->InitBuffer(gatherOffsetBuf_, 2 * alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(gradLocationQue_, 4 * alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(gradAttentionWeightsQue_, alignedOneTaskNum_ * B32_BYTE_SIZE);
}
pipe_->InitBuffer(shapeQue_, AlignUp(numLevels_ * 2, B32_DATA_NUM_PER_BLOCK) * B32_BYTE_SIZE);
pipe_->InitBuffer(offsetQue_, AlignUp(numLevels_, B32_DATA_NUM_PER_BLOCK) * B32_BYTE_SIZE);
pipe_->InitBuffer(shapeIntBuf_, 2 * alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(shapeFloatBuf_, 2 * alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(offsetIntBuf_, alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(locIntBuf_, 2 * alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(locFloatBuf_, 6 * alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(validFlagBuf_, 8 * validFlagMaskLen_);
pipe_->InitBuffer(productionBuf_, 4 * alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(weightBuf_, 4 * alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(locationQue_, 4 * alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(attentionWeightsQue_, alignedOneTaskNum_ * B32_BYTE_SIZE);
pipe_->InitBuffer(valueQue_, 2 * cornerRpt_ * B32_DATA_NUM_PER_REPEAT * B32_BYTE_SIZE);
pipe_->InitBuffer(outputQue_, compTaskNum_ * alignedHeadEmbedDims_ * B32_BYTE_SIZE);
pipe_->InitBuffer(cornerWeightBrcBuf_, cornerRpt_ * B32_DATA_NUM_PER_REPEAT * B32_BYTE_SIZE);
}
__aicore__ inline void PrepareShape(const LocalTensor<int32_t>& shapes, const LocalTensor<int32_t>& shapeInt,
const LocalTensor<float>& shapeFloat, const LocalTensor<int32_t>& offset, const LocalTensor<int32_t>& offsetInt)
{
DataCopy(shapes, valueSpatialShapesGm_,
{1, static_cast<uint16_t>(DivCeil(2 * numLevels_, B32_DATA_NUM_PER_BLOCK)), 0, 0});
DataCopy(offset, valueLevelStartIndexGm_,
{1, static_cast<uint16_t>(DivCeil(numLevels_, B32_DATA_NUM_PER_BLOCK)), 0, 0});
for (uint32_t head = 0; head < numHeads_; ++head) {
uint32_t idx = head * alignedOneHeadNum_;
for (uint32_t level = 0; level < numLevels_; ++level) {
int32_t w = shapes.GetValue(2 * level + 1);
int32_t h = shapes.GetValue(2 * level);
int32_t o = offset.GetValue(level);
for (uint32_t point = 0; point < numPoints_; ++point) {
shapeInt.SetValue(idx, w);
shapeInt.SetValue(idx + alignedOneTaskNum_, h);
offsetInt.SetValue(idx, o * numHeads_ + head);
++idx;
}
}
}
for (uint32_t query = 1; query < compTaskNum_; ++query) {
uint32_t queryOffset = query * alignedOneQueryNum_;
Adds<int32_t>(shapeInt[queryOffset], shapeInt, 0, alignedOneQueryNum_);
Adds<int32_t>(shapeInt[queryOffset + alignedOneTaskNum_], shapeInt[alignedOneTaskNum_], 0, alignedOneQueryNum_);
Adds<int32_t>(offsetInt[queryOffset], offsetInt, 0, alignedOneQueryNum_);
}
Cast<float, int32_t, false>(
shapeFloat, shapeInt, RoundMode::CAST_NONE, MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 8, 8});
}
__aicore__ inline void CopyInSample(
const LocalTensor<float>& location, const LocalTensor<float>& attentionWeight, uint32_t taskIdx)
{
uint64_t sampleOffset = taskIdx * oneQueryNum_;
WaitFlag<HardEvent::V_MTE2>(copyEvt_);
DataCopyPad(location, locationGm_[sampleOffset * 2], cpDoubleSampleParams_, {});
DataCopyPad(attentionWeight, attentionWeightsGm_[sampleOffset], cpSampleParams_, {});
SetFlag<HardEvent::MTE2_V>(copyEvt_);
}
__aicore__ inline void ComputeLocation(uint32_t taskIdx, const LocalTensor<float>& locationFloat,
const LocalTensor<float>& attentionWeight, const LocalTensor<int32_t>& locationInt, const LocalTensor<float>& shapeFloat,
const LocalTensor<int32_t>& shapeInt, const LocalTensor<float>& locFloat, const LocalTensor<int32_t>& locInt,
const LocalTensor<int32_t>& offsetInt, const LocalTensor<uint8_t>& validFlag);
__aicore__ inline void ComputeWeight(const LocalTensor<float>& locFloat, const LocalTensor<float>& shapes,
const LocalTensor<float>& production, const LocalTensor<float>& weight,
const LocalTensor<float>& attentionWeight);
__aicore__ inline void CopyInValue(
const LocalTensor<float>& dst, const GlobalTensor<float>& src, const DataCopyParams& cpParams)
{
if constexpr (aligned) {
DataCopy(dst, src, cpParams);
} else {
DataCopyPad(dst, src, cpParams, {});
}
}
__aicore__ inline void CopyOutValue(
const GlobalTensor<float>& dst, const LocalTensor<float>& src, const DataCopyParams& cpParams)
{
if constexpr (aligned) {
DataCopy(dst, src, cpParams);
} else {
DataCopyPad(dst, src, cpParams);
}
}
__aicore__ inline void SetVectorMask4MSDA(uint32_t embedIdx)
{
if (embedIdx == (embedLoops_ - 1)) {
SetVectorMask<float>(0, embedMask_);
}
}
protected:
TPipe* pipe_;
GlobalTensor<float> valueGm_, locationGm_, attentionWeightsGm_;
GlobalTensor<int32_t> valueSpatialShapesGm_, valueLevelStartIndexGm_;
GlobalTensor<float> assembleGm_;
GlobalTensor<int32_t> locationSwapGm_;
GlobalTensor<uint64_t> validFlagSwapGm_;
GlobalTensor<float> zeroGm_;
TBuf<TPosition::VECCALC> locationQue_, attentionWeightsQue_, shapeQue_, offsetQue_, valueQue_;
TBuf<TPosition::VECCALC> outputQue_;
TBuf<TPosition::VECCALC> locIntBuf_, locFloatBuf_, shapeIntBuf_, shapeFloatBuf_, offsetIntBuf_, productionBuf_,
weightBuf_, cornerWeightBrcBuf_, validFlagBuf_, gatherOffsetBuf_;
TBuf<TPosition::VECCALC> gradLocationQue_, gradAttentionWeightsQue_;
GM_ADDR assemble;
GM_ADDR locationSwap;
GM_ADDR validFlagSwap;
GM_ADDR zero;
TBuf<TPosition::VECCALC> zeroQue_;
int32_t blkIdx_;
uint32_t coreNum_, aicNum_, compTaskNum_;
uint32_t startOffset_, endOffset_, tailStart_, blockTailStart_, blockTailTask_, taskLoops_;
uint32_t firstCoreStartOffset_, firstCoreEndOffset_, secondCoreStartOffset_, secondCoreEndOffset_;
uint32_t coopRound;
uint64_t batchSize_, numKeys_, numHeads_, embedDims_, outDims_, numLevels_, numQueries_, numPoints_, realLevels_;
uint32_t alignedOneTaskNum_, alignedOneHeadNum_, alignedOneQueryNum_, alignedEmbedDims_, alignedCornerEmbedDims_, alignedHeadEmbedDims_;
uint32_t oneHeadNum_, oneQueryNum_;
uint32_t outerLoops_, innerLoops_, innerTotal_, innerTotalGroup_, innerLoopsAligned_, innerEmbedDims_;
uint16_t tailBrcBlk_, queryBlk_, embedBlk_, outBlk_;
uint16_t brcRpt_, cornerRpt_, taskRpt_;
uint64_t embedLoops_, embedTail_, embedMask_;
uint32_t validFlagMaskLen_ {256};
TEventID copyEvt_ {2}, biEvt_ {3};
DataCopyParams cpOneValParams_, cpRowDoubleParams_ {2, 0, 0, 0}, cpSampleParams_, cpDoubleSampleParams_,
cpOutParams_;
GatherMaskParams gatherParams_;
};
template<bool aligned, bool forward, bool fastMode>
__aicore__ inline void MSDABaseKernel<aligned, forward, fastMode>::ComputeLocation(uint32_t taskIdx,
const LocalTensor<float>& locationFloat, const LocalTensor<float>& attentionWeight, const LocalTensor<int32_t>& locationInt,
const LocalTensor<float>& shapeFloat, const LocalTensor<int32_t>& shapeInt, const LocalTensor<float>& locFloat,
const LocalTensor<int32_t>& locInt, const LocalTensor<int32_t>& offsetInt, const LocalTensor<uint8_t>& validFlag)
{
uint64_t cnt;
int32_t baseSrcOffset = taskIdx / numQueries_ * numKeys_ * numHeads_;
int32_t tailSrcOffset = (taskIdx + compTaskNum_ - 1) / numQueries_ * numKeys_ * numHeads_;
WaitFlag<HardEvent::MTE2_V>(copyEvt_);
GatherMask(locationFloat, locationFloat[2 * alignedOneTaskNum_], 1, false, MASK_PLACEHOLDER, gatherParams_, cnt);
GatherMask(locationFloat[alignedOneTaskNum_], locationFloat[2 * alignedOneTaskNum_], 2, false, MASK_PLACEHOLDER,
gatherParams_, cnt);
ResetMask();
Mul<float, false>(locationFloat, locationFloat, shapeFloat, MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 1, 8, 8, 8});
Adds<float, false>(locFloat, locationFloat, -0.5f, MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 8, 8});
CompareScalar<float, uint8_t, false>(validFlag[4 * validFlagMaskLen_], locFloat, -1.f,
CMPMODE::GT, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
CompareScalar<float, uint8_t, false>(validFlag[5 * validFlagMaskLen_], locFloat[alignedOneTaskNum_], -1.f,
CMPMODE::GT, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
Compare<float, uint8_t, false>(validFlag[6 * validFlagMaskLen_], locFloat, shapeFloat,
CMPMODE::LT, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Compare<float, uint8_t, false>(validFlag[7 * validFlagMaskLen_], locFloat[alignedOneTaskNum_], shapeFloat[alignedOneTaskNum_],
CMPMODE::LT, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
And<uint16_t, false>(validFlag[4 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[4 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[6 * validFlagMaskLen_].ReinterpretCast<uint16_t>(), MASK_PLACEHOLDER, 2, {1, 1, 1, 8, 8, 8});
And<uint16_t, false>(validFlag[5 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[4 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[5 * validFlagMaskLen_].ReinterpretCast<uint16_t>(), MASK_PLACEHOLDER, 1, {1, 1, 1, 8, 8, 8});
Select<float, uint8_t, false>(locFloat, validFlag[5 * validFlagMaskLen_], locFloat,
-2.0f, SELMODE::VSEL_TENSOR_SCALAR_MODE, 64, taskRpt_, {1, 1, 1, 8, 8, 8});
Select<float, uint8_t, false>(locFloat[alignedOneTaskNum_], validFlag[5 * validFlagMaskLen_], locFloat[alignedOneTaskNum_],
-2.0f, SELMODE::VSEL_TENSOR_SCALAR_MODE, 64, taskRpt_, {1, 1, 1, 8, 8, 8});
Select<float, uint8_t, false>(attentionWeight, validFlag[5 * validFlagMaskLen_], attentionWeight,
0.0f, SELMODE::VSEL_TENSOR_SCALAR_MODE, 64, taskRpt_, {1, 1, 1, 8, 8, 8});
Adds<float, false>(locFloat, locFloat, 1.0f, MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 8, 8});
Cast<int32_t, float, false>(locInt, locFloat, RoundMode::CAST_FLOOR, MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 8, 8});
Cast<float, int32_t, false>(
locFloat[2 * alignedOneTaskNum_], locInt, RoundMode::CAST_NONE, MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 8, 8});
Compare<float, uint8_t, false>(validFlag, locFloat[2 * alignedOneTaskNum_], locFloat, CMPMODE::GT,
MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 1, 8, 8, 8});
Adds<int32_t, false>(locFloat[2 * alignedOneTaskNum_].ReinterpretCast<int32_t>(), locInt, 0, MASK_PLACEHOLDER,
2 * taskRpt_, {1, 1, 8, 8});
Adds<int32_t, false>(locInt, locInt, -1, MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 8, 8});
Select<float, uint8_t, false>(locInt.ReinterpretCast<float>(), validFlag, locInt.ReinterpretCast<float>(),
locFloat[2 * alignedOneTaskNum_], SELMODE::VSEL_TENSOR_TENSOR_MODE, 64, 2 * taskRpt_, {1, 1, 1, 8, 8, 8});
Cast<float, int32_t, false>(
locFloat[2 * alignedOneTaskNum_], locInt, RoundMode::CAST_NONE, MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 8, 8});
Adds<int32_t, false>(locInt, locInt, -1, MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 8, 8});
Mul<int32_t, false>(
locationInt, locInt[alignedOneTaskNum_], shapeInt, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Add<int32_t, false>(locationInt, locInt, locationInt, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Muls<int32_t, false>(locationInt, locationInt, numHeads_, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
Add<int32_t, false>(locationInt, locationInt, offsetInt, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
if (unlikely(baseSrcOffset != tailSrcOffset)) {
for (uint32_t baseBatchNum = 0; baseBatchNum < compTaskNum_;) {
uint32_t currentBatchIdx = (taskIdx + baseBatchNum) / numQueries_;
uint32_t currentSrcOffset = currentBatchIdx * numKeys_ * numHeads_;
uint32_t currentBatchNum = (currentBatchIdx + 1) * numQueries_ - (taskIdx + baseBatchNum);
currentBatchNum = min(currentBatchNum, compTaskNum_ - baseBatchNum);
Adds<int32_t>(locationInt[baseBatchNum * alignedOneQueryNum_],
locationInt[baseBatchNum * alignedOneQueryNum_], currentSrcOffset, currentBatchNum * alignedOneQueryNum_);
baseBatchNum += currentBatchNum;
}
} else {
Adds<int32_t, false>(locationInt, locationInt, baseSrcOffset, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
}
Muls<int32_t, false>(locationInt, locationInt, embedDims_, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
Muls<int32_t, false>(locationInt[alignedOneTaskNum_], shapeInt, outDims_, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
Add<int32_t, false>(locationInt[alignedOneTaskNum_], locationInt, locationInt[alignedOneTaskNum_], MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Adds<float, false>(locFloat[4 * alignedOneTaskNum_], locFloat[2 * alignedOneTaskNum_], -1.f, MASK_PLACEHOLDER,
2 * taskRpt_, {1, 1, 8, 8});
CompareScalar<float, uint8_t, false>(
validFlag, locFloat[4 * alignedOneTaskNum_], 0.f, CMPMODE::GE, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
CompareScalar<float, uint8_t, false>(validFlag[validFlagMaskLen_], locFloat[5 * alignedOneTaskNum_], 0.f,
CMPMODE::GE, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
Compare<float, uint8_t, false>(validFlag[2 * validFlagMaskLen_], locFloat[2 * alignedOneTaskNum_], shapeFloat,
CMPMODE::LT, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Compare<float, uint8_t, false>(validFlag[3 * validFlagMaskLen_], locFloat[3 * alignedOneTaskNum_],
shapeFloat[alignedOneTaskNum_], CMPMODE::LT, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
And<uint16_t, false>(validFlag.ReinterpretCast<uint16_t>(), validFlag.ReinterpretCast<uint16_t>(),
validFlag[2 * validFlagMaskLen_].ReinterpretCast<uint16_t>(), MASK_PLACEHOLDER, 2, {1, 1, 1, 8, 8, 8});
And<uint16_t, false>(validFlag.ReinterpretCast<uint16_t>(), validFlag.ReinterpretCast<uint16_t>(),
validFlag[validFlagMaskLen_].ReinterpretCast<uint16_t>(), MASK_PLACEHOLDER, 1, {1, 1, 1, 8, 8, 8});
Compare<float, uint8_t, false>(validFlag[validFlagMaskLen_], locFloat[4 * alignedOneTaskNum_], shapeFloat,
CMPMODE::GE, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
CompareScalar<float, uint8_t, false>(validFlag[2 * validFlagMaskLen_], locFloat[2 * alignedOneTaskNum_], 0.f,
CMPMODE::LT, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
Or<uint16_t, false>(validFlag[validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[2 * validFlagMaskLen_].ReinterpretCast<uint16_t>(), MASK_PLACEHOLDER, 1, {1, 1, 1, 8, 8, 8});
Or<uint16_t, false>(validFlag[validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[validFlagMaskLen_].ReinterpretCast<uint16_t>(), validFlag.ReinterpretCast<uint16_t>(),
MASK_PLACEHOLDER, 1, {1, 1, 1, 8, 8, 8});
Compare<float, uint8_t, false>(validFlag[2 * validFlagMaskLen_], locFloat[5 * alignedOneTaskNum_],
shapeFloat[alignedOneTaskNum_], CMPMODE::GE, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
CompareScalar<float, uint8_t, false>(validFlag[3 * validFlagMaskLen_], locFloat[5 * alignedOneTaskNum_], 0.f,
CMPMODE::LT, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
Or<uint16_t, false>(validFlag[2 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[2 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[3 * validFlagMaskLen_].ReinterpretCast<uint16_t>(), MASK_PLACEHOLDER, 1, {1, 1, 1, 8, 8, 8});
Or<uint16_t, false>(validFlag[2 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[2 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[validFlagMaskLen_].ReinterpretCast<uint16_t>(), MASK_PLACEHOLDER, 1, {1, 1, 1, 8, 8, 8});
Compare<float, uint8_t, false>(validFlag[3 * validFlagMaskLen_], locFloat[3 * alignedOneTaskNum_],
shapeFloat[alignedOneTaskNum_], CMPMODE::GE, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
CompareScalar<float, uint8_t, false>(validFlag[4 * validFlagMaskLen_], locFloat[3 * alignedOneTaskNum_], 0.f,
CMPMODE::LT, MASK_PLACEHOLDER, taskRpt_, {1, 1, 8, 8});
Or<uint16_t, false>(validFlag[3 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[3 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[4 * validFlagMaskLen_].ReinterpretCast<uint16_t>(), MASK_PLACEHOLDER, 1, {1, 1, 1, 8, 8, 8});
Or<uint16_t, false>(validFlag[3 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[3 * validFlagMaskLen_].ReinterpretCast<uint16_t>(),
validFlag[validFlagMaskLen_].ReinterpretCast<uint16_t>(), MASK_PLACEHOLDER, 1, {1, 1, 1, 8, 8, 8});
SetFlag<HardEvent::V_MTE2>(biEvt_);
if (forward) {
SetFlag<HardEvent::V_MTE3>(biEvt_);
}
}
template<bool aligned, bool forward, bool fastMode>
__aicore__ inline void MSDABaseKernel<aligned, forward, fastMode>::ComputeWeight(const LocalTensor<float>& locFloat,
const LocalTensor<float>& shapes, const LocalTensor<float>& production, const LocalTensor<float>& weight,
const LocalTensor<float>& attentionWeight)
{
Sub<float, false>(locFloat, locFloat, locFloat[2 * alignedOneTaskNum_], MASK_PLACEHOLDER, 2 * taskRpt_,
{1, 1, 1, 8, 8, 8});
Mul<float, false>(production[3 * alignedOneTaskNum_], locFloat, locFloat[alignedOneTaskNum_], MASK_PLACEHOLDER,
taskRpt_, {1, 1, 1, 8, 8, 8});
Duplicate<float, false>(production, 1.f, MASK_PLACEHOLDER, 2 * taskRpt_, 1, 8);
Sub<float, false>(
locFloat[2 * alignedOneTaskNum_], production, locFloat, MASK_PLACEHOLDER, 2 * taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(production, locFloat[2 * alignedOneTaskNum_], locFloat[3 * alignedOneTaskNum_],
MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(production[alignedOneTaskNum_], locFloat, locFloat[3 * alignedOneTaskNum_], MASK_PLACEHOLDER,
taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(production[2 * alignedOneTaskNum_], locFloat[alignedOneTaskNum_],
locFloat[2 * alignedOneTaskNum_], MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(production[3 * alignedOneTaskNum_], locFloat[alignedOneTaskNum_], locFloat, MASK_PLACEHOLDER,
taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(weight, production, attentionWeight, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(weight[alignedOneTaskNum_], production[alignedOneTaskNum_], attentionWeight, MASK_PLACEHOLDER,
taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(weight[2 * alignedOneTaskNum_], production[2 * alignedOneTaskNum_], attentionWeight,
MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(weight[3 * alignedOneTaskNum_], production[3 * alignedOneTaskNum_], attentionWeight,
MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
if constexpr (!forward) {
Mul<float, false>(
locFloat, locFloat, shapes[alignedOneTaskNum_], MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(locFloat[alignedOneTaskNum_], locFloat[alignedOneTaskNum_], shapes, MASK_PLACEHOLDER,
taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(locFloat[2 * alignedOneTaskNum_], locFloat[2 * alignedOneTaskNum_],
shapes[alignedOneTaskNum_], MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(locFloat[3 * alignedOneTaskNum_], locFloat[3 * alignedOneTaskNum_], shapes,
MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(locFloat, locFloat, attentionWeight, MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(locFloat[alignedOneTaskNum_], locFloat[alignedOneTaskNum_], attentionWeight,
MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(locFloat[2 * alignedOneTaskNum_], locFloat[2 * alignedOneTaskNum_], attentionWeight,
MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
Mul<float, false>(locFloat[3 * alignedOneTaskNum_], locFloat[3 * alignedOneTaskNum_], attentionWeight,
MASK_PLACEHOLDER, taskRpt_, {1, 1, 1, 8, 8, 8});
}
SetFlag<HardEvent::V_MTE2>(copyEvt_);
}
template<bool aligned, bool fastMode>
class MultiScaleDeformableAttnKernel : MSDABaseKernel<aligned, true, fastMode> {
public:
__aicore__ inline MultiScaleDeformableAttnKernel() = delete;
__aicore__ inline MultiScaleDeformableAttnKernel(GM_ADDR value, GM_ADDR valueSpatialShapes,
GM_ADDR valueLevelStartIndex, GM_ADDR samplingLocations, GM_ADDR attentionWeights, GM_ADDR output,
GM_ADDR user, const MultiScaleDeformableAttnTilingData* tilingData, TPipe* pipe)
: MSDABaseKernel<aligned, true, fastMode>(
value, valueSpatialShapes, valueLevelStartIndex, samplingLocations, attentionWeights, user, tilingData, pipe)
{
outputGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(output));
}
__aicore__ inline void Process();
private:
GlobalTensor<float> outputGm_;
__aicore__ inline void CopyOut(const LocalTensor<float>& output, uint32_t taskIdx)
{
WaitFlag<HardEvent::V_MTE3>(0);
if constexpr (aligned) {
DataCopy(outputGm_[taskIdx * this->outDims_], output, this->cpOutParams_);
} else {
DataCopyPad(outputGm_[taskIdx * this->outDims_], output, this->cpOutParams_);
}
SetFlag<HardEvent::MTE3_V>(0);
}
__aicore__ inline void UpdateParams(uint32_t tailCompNum);
__aicore__ inline void CopyFullPoint(
const LocalTensor<int32_t>& location, const LocalTensor<float>& value,
uint64_t valid, uint32_t baseIdx, uint32_t innerLoops);
__aicore__ inline void CopyBorderPoint(
const LocalTensor<int32_t>& location, const LocalTensor<float>& value,
const LocalTensor<int32_t>& shapeInt, const LocalTensor<int32_t>& loc,
uint64_t valid, uint32_t baseIdx, uint32_t innerLoops);
__aicore__ inline void CumsumOutput(
const LocalTensor<float>& output, const LocalTensor<float>& cornerWeightBrc,
uint32_t outOffset, uint32_t innerLoops);
__aicore__ inline void BroadEmbedBlk(
const LocalTensor<float>& cornerWeightBrc, uint32_t innerLoops);
__aicore__ inline void ComputeBilinearInterpolation(const LocalTensor<uint64_t>& validFlag,
const LocalTensor<int32_t>& shapeInt, const LocalTensor<int32_t>& location, const LocalTensor<int32_t>& loc,
const LocalTensor<float>& shapeFloat, const LocalTensor<float>& production, const LocalTensor<float>& value,
const LocalTensor<float>& locFloat, const LocalTensor<float>& weight, const LocalTensor<float>& attentionWeight,
const LocalTensor<float>& cornerWeightBrc, const LocalTensor<float>& output, uint32_t round);
};
template<bool aligned, bool fastMode>
class MultiScaleDeformableAttnGradKernel : MSDABaseKernel<aligned, false, fastMode> {
public:
__aicore__ inline MultiScaleDeformableAttnGradKernel() = delete;
__aicore__ inline MultiScaleDeformableAttnGradKernel(GM_ADDR value, GM_ADDR valueSpatialShapes,
GM_ADDR valueLevelStartIndex, GM_ADDR samplingLocations, GM_ADDR attentionWeights, GM_ADDR gradOutput,
GM_ADDR gradValue, GM_ADDR gradSamplingLocations, GM_ADDR gradAttentionWeights, GM_ADDR user,
const MultiScaleDeformableAttnTilingData* tilingData, TPipe* pipe)
: MSDABaseKernel<aligned, false, fastMode>(
value, valueSpatialShapes, valueLevelStartIndex, samplingLocations, attentionWeights, user, tilingData, pipe)
{
gradOutGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(gradOutput));
gradValueGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(gradValue));
gradLocGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(gradSamplingLocations));
gradAttentionWeightsGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(gradAttentionWeights));
cpGradRowDoubleParams_.srcStride =
this->alignedCornerEmbedDims_ / B32_DATA_NUM_PER_BLOCK - DivCeil(this->embedDims_, B32_DATA_NUM_PER_BLOCK);
if constexpr (aligned) {
cpGradOneValParams_.blockLen = this->embedBlk_;
cpGradRowDoubleParams_.blockLen = this->embedBlk_;
cpGradRowDoubleParams_.dstStride = this->outBlk_ - this->embedBlk_;
} else {
cpGradOneValParams_.blockLen = this->embedDims_ * B32_BYTE_SIZE;
cpGradRowDoubleParams_.blockLen = this->embedDims_ * B32_BYTE_SIZE;
cpGradRowDoubleParams_.dstStride = (this->outDims_ - this->embedDims_) * B32_BYTE_SIZE;
}
if (fastMode) {
cpGradSampleParams_.blockCount = 1;
cpGradSampleParams_.blockLen = this->numHeads_ * this->oneHeadNum_ * B32_BYTE_SIZE;
cpGradSampleParams_.dstStride = (this->oneQueryNum_ - this->numHeads_ * this->oneHeadNum_) * B32_BYTE_SIZE;
cpGradSampleParams_.srcStride =
this->alignedOneQueryNum_ / B32_DATA_NUM_PER_BLOCK - DivCeil(this->innerLoops_, B32_DATA_NUM_PER_BLOCK);
cpGradDoubleSampleParams_.blockCount = 1;
cpGradDoubleSampleParams_.blockLen = 2 * this->numHeads_ * this->oneHeadNum_ * B32_BYTE_SIZE;
cpGradDoubleSampleParams_.dstStride = (2 * this->oneQueryNum_ - 2 * this->numHeads_ * this->oneHeadNum_) * B32_BYTE_SIZE;
cpGradDoubleSampleParams_.srcStride = 2 * this->alignedOneQueryNum_ / B32_DATA_NUM_PER_BLOCK -
DivCeil(2 * this->innerLoops_, B32_DATA_NUM_PER_BLOCK);
} else {
cpGradSampleParams_.blockCount = this->numHeads_;
cpGradSampleParams_.blockLen = this->oneHeadNum_ * B32_BYTE_SIZE;
cpGradSampleParams_.srcStride =
this->alignedOneHeadNum_ / B32_DATA_NUM_PER_BLOCK - DivCeil(this->oneHeadNum_, B32_DATA_NUM_PER_BLOCK);
cpGradDoubleSampleParams_.blockCount = this->numHeads_;
cpGradDoubleSampleParams_.blockLen = 2 * this->oneHeadNum_ * B32_BYTE_SIZE;
cpGradDoubleSampleParams_.srcStride = 2 * this->alignedOneHeadNum_ / B32_DATA_NUM_PER_BLOCK -
DivCeil(2 * this->oneHeadNum_, B32_DATA_NUM_PER_BLOCK);
}
cpGradSampleParams_.blockCount = cpGradSampleParams_.blockCount * this->compTaskNum_;
cpGradDoubleSampleParams_.blockCount = cpGradDoubleSampleParams_.blockCount * this->compTaskNum_;
}
__aicore__ inline void Process();
private:
GlobalTensor<float> gradOutGm_, gradValueGm_, gradAttentionWeightsGm_, gradLocGm_;
DataCopyParams cpGradOneValParams_, cpGradRowDoubleParams_ {2, 0, 0, 0}, cpGradSampleParams_,
cpGradDoubleSampleParams_;
__aicore__ inline void PrepareGatherOffset(const LocalTensor<uint32_t>& gatherOffset)
{
for (uint32_t i = 0; i < this->alignedOneTaskNum_; ++i) {
gatherOffset.SetValue(2 * i, (i + this->alignedOneTaskNum_) * 4);
gatherOffset.SetValue(2 * i + 1, i * 4);
}
}
__aicore__ inline void CopyInGradOut(const LocalTensor<float>& gradOut, uint32_t taskIdx)
{
WaitFlag<HardEvent::V_MTE2>(1);
if constexpr (aligned) {
DataCopy(gradOut, gradOutGm_[taskIdx * this->outDims_], this->cpOutParams_, {});
} else {
DataCopyPad(gradOut, gradOutGm_[taskIdx * this->outDims_], this->cpOutParams_, {});
}
SetFlag<HardEvent::MTE2_V>(1);
}
__aicore__ inline void GradMul(const LocalTensor<float>& dst, const LocalTensor<float>& src, const LocalTensor<float>& gradOut, uint32_t outOffset)
{
if (fastMode) {
for (uint32_t embedIdx = 0; embedIdx < this->embedLoops_; ++embedIdx) {
uint32_t embedOffset = embedIdx * B32_DATA_NUM_PER_REPEAT;
this->SetVectorMask4MSDA(embedIdx);
for (uint32_t i = 0; i < 4; ++i) {
uint32_t outerOffset = i * this->alignedCornerEmbedDims_ + embedOffset;
uint32_t offset = outOffset + embedOffset;
for (uint32_t j = 0; j < this->numHeads_; ++j) {
uint32_t innerOffset = outerOffset + j * this->oneHeadNum_ * this->alignedEmbedDims_;
Mul<float, false>(dst[innerOffset], src[innerOffset], gradOut[offset], MASK_PLACEHOLDER,
this->oneHeadNum_, {1, 1, 1, static_cast<uint8_t>(this->embedBlk_), static_cast<uint8_t>(this->embedBlk_), 0});
offset += this->alignedEmbedDims_;
}
}
}
ResetMask();
} else {
for (uint32_t embedIdx = 0; embedIdx < this->embedLoops_; ++embedIdx) {
uint32_t embedOffset = embedIdx * B32_DATA_NUM_PER_REPEAT;
this->SetVectorMask4MSDA(embedIdx);
for (uint32_t i = 0; i < 4; ++i) {
uint32_t outerOffset = i * this->alignedCornerEmbedDims_ + embedOffset;
uint32_t offset = outOffset + embedOffset;
Mul<float, false>(dst[outerOffset], src[outerOffset], gradOut[offset], MASK_PLACEHOLDER,
this->innerLoops_, {1, 1, 1, static_cast<uint8_t>(this->embedBlk_), static_cast<uint8_t>(this->embedBlk_), 0});
}
}
ResetMask();
}
}
__aicore__ inline void UpdateParams(uint32_t tailCompNum);
__aicore__ inline void CopyFullPoint(
const LocalTensor<int32_t>& location,
const LocalTensor<float>& value, const LocalTensor<float>& gradValue,
uint64_t& valid, uint32_t baseIdx, uint32_t innerLoops);
__aicore__ inline void CopyBorderPoint(
const LocalTensor<int32_t>& location, const LocalTensor<float>& value,
const LocalTensor<float>& gradValue,
const LocalTensor<int32_t>& shapeInt, const LocalTensor<int32_t>& loc,
uint64_t& valid, uint32_t baseIdx, uint32_t innerLoops);
__aicore__ inline void PrepareOutTensor(
const LocalTensor<float>& weight, const LocalTensor<float>& dst,
const LocalTensor<float>& gradOut, const LocalTensor<float>& gradMulTmp,
uint32_t baseIdx, uint32_t outOffset);
__aicore__ inline void ReduseSumValue(
const LocalTensor<float>& weight, const LocalTensor<float>& cornerWeightBrc, uint32_t baseIdx);
__aicore__ inline void ComputeBilinearInterpolation(const LocalTensor<uint64_t>& validFlag,
const LocalTensor<int32_t>& shapeInt, const LocalTensor<int32_t>& location, const LocalTensor<int32_t>& loc,
const LocalTensor<float>& shapeFloat, const LocalTensor<float>& production, const LocalTensor<float>& value,
const LocalTensor<float>& locFloat, const LocalTensor<float>& weight, const LocalTensor<float>& attentionWeight,
const LocalTensor<float>& cornerWeightBrc, const LocalTensor<float>& gradOut, const LocalTensor<float>& gradValue);
__aicore__ inline void ComputeGrad(const LocalTensor<float>& production, const LocalTensor<float>& locFloat,
const LocalTensor<float>& weight, const LocalTensor<float>& attentionWeight,
const LocalTensor<float>& gradLocation, const LocalTensor<float>& gradAttentionWeight,
const LocalTensor<uint32_t>& gatherOffset, const LocalTensor<uint64_t>& validFlag, uint32_t taskIdx);
};
template<bool aligned, bool forward, bool fastMode>
class MSDABaseCubeKernel {
public:
__aicore__ inline MSDABaseCubeKernel() = delete;
__aicore__ inline MSDABaseCubeKernel(GM_ADDR value, GM_ADDR valueSpatialShapes, GM_ADDR valueLevelStartIndex,
GM_ADDR samplingLocations, GM_ADDR attentionWeights, GM_ADDR user, const MultiScaleDeformableAttnTilingData* tilingData,
TPipe* pipe)
: pipe_(pipe), blkIdx_(GetBlockIdx())
{
InitTiling(tilingData, user);
InitGM(value);
InitBuffer();
}
protected:
__aicore__ inline uint32_t GetInnerLoops(uint32_t x)
{
uint32_t candicateList[4] = {8, 16, 32, 64};
uint32_t i;
for (i = 1; i < 4; i++) {
if (x / candicateList[i] == 0) {
break;
}
}
return candicateList[i - 1];
}
__aicore__ inline void InitTiling(const MultiScaleDeformableAttnTilingData* tilingData, GM_ADDR user)
{
batchSize_ = tilingData->batchSize;
numKeys_ = tilingData->numKeys;
numHeads_ = tilingData->numHeads;
embedDims_ = tilingData->embedDims;
numLevels_ = tilingData->numLevels;
numQueries_ = tilingData->numQueries;
numPoints_ = tilingData->numPoints;
coreNum_ = tilingData->coreNum;
realLevels_ = tilingData->realLevels;
aicNum_ = tilingData->aicNum;
assemble = user + tilingData->assembleWorkSpaceOffset;
location = user + tilingData->locationWorkSpaceOffset;
validFlag = user + tilingData->validFlagWorkSpaceOffset;
zero = user + tilingData->zeroWorkSpaceOffset;
oneQueryNum_ = numHeads_ * realLevels_ * numPoints_;
oneHeadNum_ = numLevels_ * numPoints_;
alignedEmbedDims_ = AlignUp(embedDims_, B32_DATA_NUM_PER_BLOCK);
if constexpr (fastMode) {
outerLoops_ = 1;
innerLoops_ = numHeads_ * oneHeadNum_;
innerLoopsAligned_ = AlignUp(innerLoops_, 8);
innerLoopsAligned_ = B32_DATA_NUM_PER_REPEAT / (B32_DATA_NUM_PER_REPEAT / innerLoopsAligned_);
alignedOneHeadNum_ = oneHeadNum_;
alignedOneQueryNum_ = innerLoopsAligned_;
alignedCornerEmbedDims_ = innerLoops_ * alignedEmbedDims_;
innerTotal_ = numHeads_ * oneHeadNum_;
innerTotalGroup_ = 1;
innerEmbedDims_ = numHeads_ * alignedEmbedDims_;
brcRpt_ = DivCeil(4 * innerLoops_ * B32_DATA_NUM_PER_BLOCK, B32_DATA_NUM_PER_REPEAT);
} else {
uint32_t maxInnerDims = 2048;
innerLoops_ = oneHeadNum_ * alignedEmbedDims_ <= maxInnerDims ? oneHeadNum_ : GetInnerLoops(maxInnerDims / alignedEmbedDims_);
innerLoopsAligned_ = AlignUp(innerLoops_, 8);
innerLoopsAligned_ = B32_DATA_NUM_PER_REPEAT / (B32_DATA_NUM_PER_REPEAT / innerLoopsAligned_);
outerLoops_ = numHeads_ * DivCeil(oneHeadNum_, innerLoopsAligned_);
alignedOneHeadNum_ = AlignUp(oneHeadNum_, innerLoopsAligned_);
alignedOneQueryNum_ = numHeads_ * alignedOneHeadNum_;
alignedCornerEmbedDims_ = innerLoops_ * alignedEmbedDims_;
innerTotal_ = oneHeadNum_;
innerTotalGroup_ = DivCeil(oneHeadNum_, innerLoopsAligned_);
innerEmbedDims_ = alignedEmbedDims_;
brcRpt_ = DivCeil(4 * innerLoops_ * B32_DATA_NUM_PER_BLOCK, B32_DATA_NUM_PER_REPEAT);
}
alignedHeadEmbedDims_ = numHeads_ * alignedEmbedDims_;
outDims_ = numHeads_ * embedDims_;
embedBlk_ = DivCeil(embedDims_, B32_DATA_NUM_PER_BLOCK);
outBlk_ = numHeads_ * embedBlk_;
embedLoops_ = DivCeil(embedDims_, B32_DATA_NUM_PER_REPEAT);
embedTail_ = embedDims_ % B32_DATA_NUM_PER_REPEAT;
embedMask_ = embedTail_ == 0 ? FULL_MASK : (1UL << embedTail_) - 1;
cornerRpt_ = DivCeil(4 * alignedCornerEmbedDims_, B32_DATA_NUM_PER_REPEAT);
uint32_t totalUbSize = 192 * 1024;
uint32_t reservedUbSize = 16 * 1024;
uint32_t usedUbSize = 8 * validFlagMaskLen_ + 3 * cornerRpt_ * B32_DATA_NUM_PER_REPEAT * B32_BYTE_SIZE;
uint32_t queryUbSize = 26 * alignedOneQueryNum_ * B32_BYTE_SIZE + alignedHeadEmbedDims_ * B32_BYTE_SIZE;
if (!forward) {
queryUbSize = queryUbSize + 7 * alignedOneQueryNum_ * B32_BYTE_SIZE;
}
uint32_t avgTasks = (batchSize_ * numQueries_) / coreNum_;
uint32_t remainTasks = (batchSize_ * numQueries_) % coreNum_;
startOffset_ = avgTasks * blkIdx_ + (blkIdx_ < remainTasks ? blkIdx_ : remainTasks);
endOffset_ = startOffset_ + avgTasks + (blkIdx_ < remainTasks ? 1 : 0);
uint32_t modeUpperNum_ = 1024 / alignedOneQueryNum_;
compTaskNum_ = (totalUbSize - reservedUbSize - usedUbSize) / queryUbSize;
compTaskNum_ = min(compTaskNum_, modeUpperNum_);
compTaskNum_ = max(compTaskNum_, (uint32_t)1);
taskLoops_ = (batchSize_ * numQueries_) / (coreNum_ * compTaskNum_);
coopRound = taskLoops_;
tailStart_ = taskLoops_ * (coreNum_ * compTaskNum_);
uint32_t tailBlocks = batchSize_ * numQueries_ - tailStart_;
taskLoops_ += tailBlocks > 0 ? 1 : 0;
uint32_t tailAvgTasks = tailBlocks / coreNum_;
uint32_t tailRemainTasks = tailBlocks % coreNum_;
blockTailStart_ = tailStart_ + tailAvgTasks * blkIdx_ + (blkIdx_ < tailRemainTasks ? blkIdx_ : tailRemainTasks);
blockTailTask_ = tailAvgTasks + (blkIdx_ < tailRemainTasks ? 1 : 0);
outerLoops_ = outerLoops_ * compTaskNum_;
alignedOneTaskNum_ = AlignUp(compTaskNum_ * alignedOneQueryNum_, B32_DATA_NUM_PER_REPEAT);
taskRpt_ = DivCeil(alignedOneTaskNum_, B32_DATA_NUM_PER_REPEAT);
cpRowDoubleParams_.dstStride =
alignedCornerEmbedDims_ / B32_DATA_NUM_PER_BLOCK - DivCeil(embedDims_, B32_DATA_NUM_PER_BLOCK);
if constexpr (aligned) {
cpRowDoubleParams_.blockLen = embedBlk_;
cpRowDoubleParams_.srcStride = outBlk_ - embedBlk_;
} else {
}
if (fastMode) {
} else {
cpSampleParams_.blockCount = compTaskNum_ * numHeads_;
cpSampleParams_.blockLen = oneHeadNum_ * B32_BYTE_SIZE;
cpSampleParams_.dstStride =
alignedOneHeadNum_ / B32_DATA_NUM_PER_BLOCK - DivCeil(oneHeadNum_, B32_DATA_NUM_PER_BLOCK);
cpDoubleSampleParams_.blockCount = compTaskNum_ * numHeads_;
cpDoubleSampleParams_.blockLen = 2 * oneHeadNum_ * B32_BYTE_SIZE;
cpDoubleSampleParams_.dstStride =
2 * alignedOneHeadNum_ / B32_DATA_NUM_PER_BLOCK - DivCeil(2 * oneHeadNum_, B32_DATA_NUM_PER_BLOCK);
}
}
__aicore__ inline void InitGM(GM_ADDR value)
{
valueGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(value));
assembleGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(this->assemble));
locationGm_.SetGlobalBuffer(reinterpret_cast<__gm__ int32_t*>(this->location));
validFlagGm_.SetGlobalBuffer(reinterpret_cast<__gm__ uint64_t*>(this->validFlag));
zeroGm_.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(this->zero));
}
__aicore__ inline void InitBuffer()
{
pipe_->InitBuffer(assembleMBuf_, 2 * cornerRpt_ * B32_DATA_NUM_PER_REPEAT * B32_BYTE_SIZE);
}
__aicore__ inline void CopyInValue(
const LocalTensor<float>& dst, const GlobalTensor<float>& src, const DataCopyParams& cpParams)
{
if constexpr (aligned) {
DataCopy(dst, src, cpParams);
} else {
DataCopyPad(dst, src, cpParams, {});
}
}
protected:
TPipe* pipe_;
GlobalTensor<float> valueGm_;
GlobalTensor<float> assembleGm_;
GlobalTensor<float> zeroGm_;
GlobalTensor<int32_t> locationGm_;
GlobalTensor<uint64_t> validFlagGm_;
GM_ADDR assemble;
GM_ADDR location;
GM_ADDR validFlag;
GM_ADDR zero;
TBuf<TPosition::A1> assembleMBuf_;
int32_t blkIdx_;
uint32_t coreNum_, aicNum_, compTaskNum_;
uint32_t startOffset_, endOffset_, tailStart_, blockTailStart_, blockTailTask_, taskLoops_;
uint32_t firstCoreStartOffset_, firstCoreEndOffset_, secondCoreStartOffset_, secondCoreEndOffset_;
uint32_t coopRound;
uint64_t batchSize_, numKeys_, embedDims_, numLevels_, numQueries_, numPoints_, realLevels_, numHeads_, outDims_;
uint32_t oneHeadNum_, oneQueryNum_;
uint32_t alignedOneTaskNum_, alignedOneHeadNum_, alignedOneQueryNum_, alignedEmbedDims_, alignedCornerEmbedDims_, alignedHeadEmbedDims_;
uint32_t outerLoops_, innerLoops_, innerLoopsAligned_, innerLoopsOffset_, innerTotal_, innerTotalGroup_, innerEmbedDims_;
uint16_t embedBlk_, outBlk_, brcRpt_, cornerRpt_, taskRpt_;
uint64_t embedLoops_, embedTail_, embedMask_;
uint32_t validFlagMaskLen_ {256};
DataCopyParams cpSampleParams_, cpDoubleSampleParams_, cpRowDoubleParams_ {2, 0, 0, 0};
};
template<bool aligned, bool fastMode>
class MultiScaleDeformableAttnCubeKernel : MSDABaseCubeKernel<aligned, true, fastMode> {
public:
__aicore__ inline MultiScaleDeformableAttnCubeKernel() = delete;
__aicore__ inline MultiScaleDeformableAttnCubeKernel(GM_ADDR value, GM_ADDR valueSpatialShapes,
GM_ADDR valueLevelStartIndex, GM_ADDR samplingLocations, GM_ADDR attentionWeights, GM_ADDR output,
GM_ADDR user, const MultiScaleDeformableAttnTilingData* tilingData, TPipe* pipe)
: MSDABaseCubeKernel<aligned, true, fastMode>(
value, valueSpatialShapes, valueLevelStartIndex, samplingLocations, attentionWeights, user, tilingData, pipe){}
__aicore__ inline void Process();
private:
__aicore__ inline void UpdateParams(uint32_t tailCompNum);
__aicore__ inline void CopyFullPointToCube(uint64_t valid, uint32_t baseIdx, uint32_t innerLoops, uint32_t vecCoreIdx, uint32_t bufferFlag, const LocalTensor<float>& value);
__aicore__ inline void CopyFullPointFromCube(uint32_t head, uint32_t innerLoops, uint32_t assembleOffsetFromTbuf, uint32_t vecCoreIdx, const LocalTensor<float>& value);
};
#endif