init v0.23.0

Signed-off-by: Sun Ruoxi <sunruoxi@4paradigm.com>
This commit is contained in:
2026-08-27 15:11:51 +08:00
parent b582a8e7d1
commit 7f8a1b1f7a
2849 changed files with 712887 additions and 22001 deletions

View File

@@ -0,0 +1,28 @@
# -----------------------------------------------------------------------------------------------------------
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
# CANN Open Software License Agreement Version 2.0 (the "License").
# Please refer to the License for details. You may not use this file except in compliance with the License.
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
# See LICENSE in the root of the software repository for the full text of the License.
# -----------------------------------------------------------------------------------------------------------
add_op_to_compiled_list()
if (BUILD_OPEN_PROJECT)
target_sources(op_host_aclnnExc PRIVATE
grouped_matmul_swiglu_quant_def.cpp
)
add_ops_compile_options(
OP_NAME GroupedMatmulSwigluQuant
OPTIONS --cce-auto-sync=on
-Wno-deprecated-declarations
)
endif()
if(NOT BUILD_OPS_RTY_KERNEL)
add_modules_sources(OPTYPE grouped_matmul_swiglu_quant ACLNNTYPE aclnn_exclude)
target_include_directories(${OPHOST_NAME}_tiling_obj PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
endif()

View File

@@ -0,0 +1,122 @@
/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
/*!
* \file grouped_matmul_swiglu_quant_def.cpp
* \brief
*/
#include "register/op_def_registry.h"
namespace ops {
class GroupedMatmulSwigluQuant : public OpDef {
public:
explicit GroupedMatmulSwigluQuant(const char *name) : OpDef(name)
{
this->Input("x")
.ParamType(REQUIRED)
.DataType({ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8})
.Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND});
this->Input("weight")
.ParamType(REQUIRED)
.DataType({ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT4, ge::DT_INT4})
.Format({ge::FORMAT_FRACTAL_NZ, ge::FORMAT_FRACTAL_NZ, ge::FORMAT_FRACTAL_NZ, ge::FORMAT_ND,
ge::FORMAT_FRACTAL_NZ});
this->Input("weight_scale")
.ParamType(REQUIRED)
.DataType({ge::DT_FLOAT, ge::DT_BF16, ge::DT_FLOAT16, ge::DT_UINT64, ge::DT_UINT64})
.Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND});
this->Input("x_scale")
.ParamType(REQUIRED)
.DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT})
.Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND});
this->Input("weight_assistance_matrix")
.ParamType(OPTIONAL)
.DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT})
.Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND});
this->Input("group_list")
.ParamType(REQUIRED)
.DataType({ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64})
.Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND});
this->Output("y")
.ParamType(REQUIRED)
.DataType({ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8})
.Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND});
this->Output("y_scale")
.ParamType(REQUIRED)
.DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT})
.Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND});
this->Attr("is_enable_weight_assistance_matrix").AttrType(OPTIONAL).Bool(true);
this->Attr("dequant_mode").AttrType(OPTIONAL).Int(0);
this->Attr("limited").AttrType(OPTIONAL).Float(0.0f);
OpAICoreConfig aicore_config;
aicore_config.DynamicCompileStaticFlag(true)
.DynamicFormatFlag(true)
.DynamicRankSupportFlag(true)
.DynamicShapeSupportFlag(true)
.NeedCheckSupportFlag(false)
.PrecisionReduceFlag(true);
this->AICore().AddConfig("ascend910b", aicore_config);
this->AICore().AddConfig("ascend910_93", aicore_config);
OpAICoreConfig config_kirin = GetKirinCoreConfig();
this->AICore().AddConfig("kirinx90", config_kirin);
this->AICore().AddConfig("kirin9030", config_kirin);
}
private:
OpAICoreConfig GetKirinCoreConfig() const
{
OpAICoreConfig config_kirin;
config_kirin.DynamicCompileStaticFlag(true)
.DynamicFormatFlag(true)
.DynamicRankSupportFlag(true)
.DynamicShapeSupportFlag(true)
.NeedCheckSupportFlag(false)
.PrecisionReduceFlag(true);
config_kirin.Input("x")
.ParamType(REQUIRED)
.DataType({ge::DT_INT8, ge::DT_INT8})
.Format({ge::FORMAT_ND, ge::FORMAT_ND});
config_kirin.Input("weight")
.ParamType(REQUIRED)
.DataType({ge::DT_INT8, ge::DT_INT8})
.Format({ge::FORMAT_FRACTAL_NZ, ge::FORMAT_FRACTAL_NZ});
config_kirin.Input("weight_scale")
.ParamType(REQUIRED)
.DataType({ge::DT_FLOAT, ge::DT_FLOAT16})
.Format({ge::FORMAT_ND, ge::FORMAT_ND});
config_kirin.Input("x_scale")
.ParamType(REQUIRED)
.DataType({ge::DT_FLOAT, ge::DT_FLOAT})
.Format({ge::FORMAT_ND, ge::FORMAT_ND});
config_kirin.Input("weight_assistance_matrix")
.ParamType(OPTIONAL)
.DataType({ge::DT_FLOAT, ge::DT_FLOAT})
.Format({ge::FORMAT_ND, ge::FORMAT_ND});
config_kirin.Input("group_list")
.ParamType(REQUIRED)
.DataType({ge::DT_INT64, ge::DT_INT64})
.Format({ge::FORMAT_ND, ge::FORMAT_ND});
config_kirin.Output("y")
.ParamType(REQUIRED)
.DataType({ge::DT_INT8, ge::DT_INT8})
.Format({ge::FORMAT_ND, ge::FORMAT_ND});
config_kirin.Output("y_scale")
.ParamType(REQUIRED)
.DataType({ge::DT_FLOAT, ge::DT_FLOAT})
.Format({ge::FORMAT_ND, ge::FORMAT_ND});
return config_kirin;
}
};
OP_ADD(GroupedMatmulSwigluQuant);
} // namespace ops

View File

@@ -0,0 +1,53 @@
/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
/*!
* \file grouped_matmul_swiglu_quant_proto.cpp
* \brief
*/
#include "register/op_impl_registry.h"
#include "log/log.h"
#include "platform/platform_info.h"
using namespace ge;
namespace ops {
const int64_t X_INDEX = 0;
const int64_t WEIGHTSCALE_INDEX = 2;
const int64_t M_DIM_INDEX = 0;
const int64_t DIM_LEN = 2;
const int64_t SPLIT_RATIO = 2;
static ge::graphStatus InferShape4GroupedMatmulSwigluQuant(gert::InferShapeContext *context)
{
const gert::Shape *xShape = context->GetInputShape(X_INDEX);
const gert::Shape *weightScaleShape = context->GetInputShape(WEIGHTSCALE_INDEX);
int64_t m = xShape->GetDim(M_DIM_INDEX);
int64_t N_DIM_INDEX = weightScaleShape->GetDimNum() - 1;
int64_t n = static_cast<int64_t>(weightScaleShape->GetDim(N_DIM_INDEX) / SPLIT_RATIO);
auto outShape = context->GetOutputShape(0);
outShape->SetDimNum(DIM_LEN);
outShape->SetDim(0, m);
outShape->SetDim(1, n);
auto outScaleShape = context->GetOutputShape(1);
outScaleShape->SetDimNum(1);
outScaleShape->SetDim(0, m);
return GRAPH_SUCCESS;
}
static graphStatus InferDataType4GroupedMatmulSwigluQuant(gert::InferDataTypeContext *context)
{
context->SetOutputDataType(0, DataType::DT_INT8);
context->SetOutputDataType(1, DataType::DT_FLOAT);
return GRAPH_SUCCESS;
}
IMPL_OP_INFERSHAPE(GroupedMatmulSwigluQuant)
.InferShape(InferShape4GroupedMatmulSwigluQuant)
.InferDataType(InferDataType4GroupedMatmulSwigluQuant);
} // namespace ops

View File

@@ -0,0 +1,288 @@
/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
/*!
* \file grouped_matmul_swiglu_quant_tiling.cpp
* \brief
*/
#include <climits>
#include <graph/utils/type_utils.h>
#include "register/op_impl_registry.h"
#include "log/log.h"
#include "err/ops_err.h"
#include "tiling_base/tiling_base.h"
#include "grouped_matmul_swiglu_quant_tiling.h"
using namespace ge;
using namespace AscendC;
using namespace GroupedMatmulSwigluQuantTiling;
using namespace Ops::Transformer::OpTiling;
namespace {
template <typename T>
static inline auto AlignUp(T a, T base) -> T
{
if (base == 0) {
return 0;
}
return (a + base - 1) / base * base;
}
} // namespace
namespace optiling {
struct GMMSwigluCompileInfo {
uint64_t ubSize_ = 0;
uint32_t aicNum_ = 0;
uint32_t baseM_ = 128;
uint32_t baseN_ = 256;
};
static int64_t CalMaxRowInUb_A8W4(const gert::TilingContext *context, const uint64_t ubSize, const uint64_t n)
{
const uint64_t ALIGNMENT = 8;
const float WEIGHT_FACTOR = 8.5;
const uint64_t ALIGNMENT_TERM_FACTOR = 4;
const uint64_t LINEAR_TERM_FACTOR = 6;
const uint64_t CONSTANT_TERM = 64;
const uint64_t MIN_ROW_THRESHOLD = 1;
// 表达式:8.5 * row * n + 4 * alignUp(row, 8) + 6n + 64 <= ubSize
// 忽略对齐项的初始估计
int64_t maxRowEstimate =
(ubSize - CONSTANT_TERM - LINEAR_TERM_FACTOR * n) / static_cast<int64_t>(WEIGHT_FACTOR * n);
// 考虑对齐影响
uint64_t alignedRow = (maxRowEstimate + ALIGNMENT - 1) / ALIGNMENT * ALIGNMENT;
uint64_t totalSize = static_cast<uint64_t>(WEIGHT_FACTOR * maxRowEstimate * n) +
ALIGNMENT_TERM_FACTOR * alignedRow + LINEAR_TERM_FACTOR * n + CONSTANT_TERM;
// 如果超过UB大小,逐步减少row直到满足条件
while (totalSize > ubSize && maxRowEstimate > 0) {
maxRowEstimate--;
alignedRow = (maxRowEstimate + ALIGNMENT - 1) / ALIGNMENT * ALIGNMENT;
totalSize = static_cast<uint64_t>(WEIGHT_FACTOR * maxRowEstimate * n) + ALIGNMENT_TERM_FACTOR * alignedRow +
LINEAR_TERM_FACTOR * n + CONSTANT_TERM;
}
if (maxRowEstimate < MIN_ROW_THRESHOLD) {
OP_LOGE(context->GetNodeName(), "GMM_SWIGLU_QUANT TILING: No valid row found for n = %lu, ubSize = %lu\n", n,
ubSize);
return 0;
}
return maxRowEstimate;
}
static int64_t CalMaxRowInUb(const gert::TilingContext *context, const uint64_t ubSize, const uint64_t n)
{
uint64_t tmpBufSize = (n / SWIGLU_REDUCE_FACTOR) * FP32_DTYPE_SIZE;
uint64_t perchannleBufSize = n * FP32_DTYPE_SIZE * DOUBLE_BUFFER;
uint64_t reduceMaxResBufSize = BLOCK_BYTE;
uint64_t reduceMaxTmpBufSize = BLOCK_BYTE;
const uint64_t CONSTANT_TERM = 64;
int64_t remainUbSize = ubSize - tmpBufSize - perchannleBufSize - reduceMaxResBufSize - reduceMaxTmpBufSize;
int64_t maxRowInUb =
remainUbSize / (n * INT32_DTYPE_SIZE + n / SWIGLU_REDUCE_FACTOR + FP32_DTYPE_SIZE) / DOUBLE_BUFFER;
int64_t curUb = DOUBLE_BUFFER * (maxRowInUb * (INT32_DTYPE_SIZE * n + n / SWIGLU_REDUCE_FACTOR) +
AlignUp(maxRowInUb, FP32_BLOCK_SIZE) * FP32_DTYPE_SIZE);
if (curUb > remainUbSize) {
// 64 : make sure ub does not excceed maxUbSize after align up to 8
maxRowInUb = (remainUbSize - CONSTANT_TERM) /
(n * INT32_DTYPE_SIZE + n / SWIGLU_REDUCE_FACTOR + FP32_DTYPE_SIZE) / DOUBLE_BUFFER;
}
if (maxRowInUb < 1) {
// when n > (ubSize - 72) / 19 = 10330, maxRowInUb < 1
OP_LOGE(context->GetNodeName(), "GMM_SWIGLU_QUANT TILING: n should not be greater than 10240, now is %lu\n", n);
}
return maxRowInUb;
}
static void SetTilingKey(gert::TilingContext *context, bool isSplitWorkSpace, bool isA8W4MSD)
{
if (isA8W4MSD) { // A8W4 MSD tiling_key使用4
context->SetTilingKey(A8W4_MSD_TILING_KEY_MODE);
context->SetScheduleMode(BATCH_MODE_SCHEDULE);
} else if (isSplitWorkSpace) {
context->SetTilingKey(SPLITWORKSPACE_TILING_KEY_MODE);
context->SetScheduleMode(BATCH_MODE_SCHEDULE);
} else {
context->SetTilingKey(COMMON_TILING_KEY_MODE);
context->SetScheduleMode(BATCH_MODE_SCHEDULE);
}
}
ASCENDC_EXTERN_C graphStatus TilingGMMSwigluQuant(gert::TilingContext *context)
{
// set info
OP_LOGD(context->GetNodeName(), "Begin Run GMM Swiglu Tiling .");
auto xDesc = context->GetInputDesc(X_INDEX);
OP_CHECK_NULL_WITH_CONTEXT(context, xDesc);
auto weightDesc = context->GetInputDesc(WEIGHT_INDEX);
OP_CHECK_NULL_WITH_CONTEXT(context, weightDesc);
ge::DataType xDType = xDesc->GetDataType();
ge::DataType weightDType = weightDesc->GetDataType();
bool isA8W4MSD = (xDType == ge::DataType::DT_INT8 && weightDType == ge::DataType::DT_INT4);
auto compileInfoPtr = context->GetCompileInfo<GMMSwigluCompileInfo>();
auto xTensor = context->GetInputTensor(X_INDEX);
OP_CHECK_NULL_WITH_CONTEXT(context, xTensor);
const int64_t m = xTensor->GetStorageShape().GetDim(0);
const int64_t k = xTensor->GetStorageShape().GetDim(1);
auto wTensor = context->GetInputTensor(WEIGHT_INDEX);
OP_CHECK_NULL_WITH_CONTEXT(context, wTensor);
// swiglu limit 0 means clamp is disabled.
auto attrs = context->GetAttrs();
float limited = 0.0f;
if (attrs != nullptr) {
if (const double *limitedPtr = attrs->GetAttrPointer<double>(ATTR_INDEX_LIMITED)) {
limited = static_cast<float>(*limitedPtr);
}
}
OP_CHECK_IF(!(limited >= 0.0f),
OPS_REPORT_VECTOR_INNER_ERR(context->GetNodeName(), "limited should be non-negative"),
return GRAPH_FAILED);
int64_t n = 0;
if (wTensor->GetStorageShape().GetDimNum() == ND_WEIGHT_DIM_LIMIT) { // ND
n = wTensor->GetStorageShape().GetDim(DIM_2);
} else if (wTensor->GetStorageShape().GetDimNum() == NZ_WEIGHT_DIM_LIMIT) { // NZ
n = wTensor->GetStorageShape().GetDim(DIM_1) * wTensor->GetStorageShape().GetDim(DIM_4);
}
auto wScaleTensor = context->GetInputTensor(WEIGHT_SCALE_INDEX);
OP_CHECK_NULL_WITH_CONTEXT(context, wScaleTensor);
int64_t quantGroupNum = 0;
if (wScaleTensor->GetStorageShape().GetDimNum() == PERCHANNEL_WSCALE_DIM_LIMIT) { // perChannel
quantGroupNum = 1;
} else if (wScaleTensor->GetStorageShape().GetDimNum() == PERGROUP_WSCALE_DIM_LIMIT) { // perGroup
quantGroupNum = wScaleTensor->GetStorageShape().GetDim(1);
}
auto groupListTensor = context->GetDynamicInputTensor(GROUPLIST_INDEX, 0);
OP_CHECK_NULL_WITH_CONTEXT(context, groupListTensor);
const int64_t groupNum = groupListTensor->GetStorageShape().GetDim(0);
GMMSwigluQuantTilingData tilingData;
int64_t row = 0;
if (isA8W4MSD) {
row = CalMaxRowInUb_A8W4(context, compileInfoPtr->ubSize_, n);
} else {
row = CalMaxRowInUb(context, compileInfoPtr->ubSize_, n);
}
tilingData.gmmSwigluBaseParams.set_groupNum(groupNum);
tilingData.gmmSwigluBaseParams.set_coreNum(compileInfoPtr->aicNum_);
tilingData.gmmSwigluBaseParams.set_K(k);
tilingData.gmmSwigluBaseParams.set_N(n);
tilingData.gmmSwigluBaseParams.set_M(m);
tilingData.gmmSwigluBaseParams.set_baseM(A8W4_BASEM);
tilingData.gmmSwigluBaseParams.set_baseN(A8W4_BASEN);
tilingData.gmmSwigluBaseParams.set_limited(limited);
tilingData.gmmSwiglu.set_maxProcessRowNum(row);
tilingData.gmmSwiglu.set_groupListLen(groupNum);
tilingData.gmmSwiglu.set_tokenLen(n);
tilingData.gmmSwigluBaseParams.set_quantGroupNum(quantGroupNum);
auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
using namespace matmul_tiling;
MatmulApiTiling tiling(ascendcPlatform);
tiling.SetAType(TPosition::GM, CubeFormat::ND, matmul_tiling::DataType::DT_INT4);
tiling.SetBType(TPosition::GM, CubeFormat::NZ, matmul_tiling::DataType::DT_INT4);
tiling.SetCType(TPosition::GM, CubeFormat::ND, matmul_tiling::DataType::DT_FLOAT16);
tiling.SetBias(false);
tiling.SetShape(A8W4_BASEM, A8W4_BASEN, k);
tiling.SetFixSplit(A8W4_BASEM, A8W4_BASEN, A8W4_BASEK);
tiling.SetOrgShape(m, n, k);
tiling.SetBufferSpace(-1, -1, -1);
OP_CHECK_IF(
tiling.GetTiling(tilingData.mmTilingData) == -1,
OPS_REPORT_VECTOR_INNER_ERR(context->GetNodeName(), "grouped_matmul_swiglu_quant_tiling, get tiling failed"),
return GRAPH_FAILED);
if (isA8W4MSD) {
tilingData.mmTilingData.set_baseM(A8W4_BASEM);
tilingData.mmTilingData.set_baseN(A8W4_BASEN);
tilingData.mmTilingData.set_baseK(A8W4_BASEK);
tilingData.mmTilingData.set_dbL0B(DOUBLE_BUFFER);
tilingData.mmTilingData.set_stepKa(NUM_FOUR);
tilingData.mmTilingData.set_stepKb(NUM_FOUR);
tilingData.mmTilingData.set_depthA1(NUM_EIGHT);
tilingData.mmTilingData.set_depthB1(NUM_EIGHT);
tilingData.mmTilingData.set_stepM(1);
tilingData.mmTilingData.set_stepN(1);
}
auto workspaceSizes = context->GetWorkspaceSizes(1);
int64_t usrWorkspaceLimit = USER_WORKSPACE_LIMIT;
int64_t mLimit = 0;
if (isA8W4MSD) {
mLimit = ((usrWorkspaceLimit / DOUBLE_WORKSPACE_SPLIT) / (k * sizeof(int8_t) + DOUBLE_ROW * n * sizeof(half)));
} else {
mLimit = ((usrWorkspaceLimit / DOUBLE_WORKSPACE_SPLIT) / INT32_DTYPE_SIZE) / n;
}
OP_CHECK_IF(mLimit <= 0,
OPS_REPORT_VECTOR_INNER_ERR(context->GetNodeName(), "mLimit is %ld must over then 0.", mLimit),
return GRAPH_FAILED);
tilingData.gmmSwigluBaseParams.set_mLimit(mLimit);
if (isA8W4MSD) {
int workSpaceMTemp = mLimit * DOUBLE_WORKSPACE_SPLIT;
tilingData.gmmSwigluBaseParams.set_workSpaceOffset1(workSpaceMTemp * k * sizeof(int8_t));
tilingData.gmmSwigluBaseParams.set_workSpaceOffset2(2 * workSpaceMTemp * n * sizeof(half));
workspaceSizes[0] =
SYS_WORKSPACE_SIZE + // 系统预留16MB
(workSpaceMTemp * k * sizeof(int8_t)) + // 第一阶段 预处理左矩阵 (mLimit, K) * int8 * 2(double WorkSpace)
(DOUBLE_ROW * workSpaceMTemp * n *
sizeof(half)); // 第二阶段 矩阵乘结果 (2 * mLimit, N) * fp16 * 2(double WorkSpace)
} else {
int workSpaceMTemp = (mLimit * DOUBLE_WORKSPACE_SPLIT > m ? m : mLimit * DOUBLE_WORKSPACE_SPLIT);
tilingData.gmmSwigluBaseParams.set_workSpaceOffset1(0);
tilingData.gmmSwigluBaseParams.set_workSpaceOffset2(0);
workspaceSizes[0] = SYS_WORKSPACE_SIZE + (workSpaceMTemp * n * sizeof(int32_t));
}
bool isSplitWorkSpace = m > mLimit * DOUBLE_WORKSPACE_SPLIT;
OP_LOGD(context->GetNodeName(), "grouped_matmul_swiglu_quant_tiling.");
OP_LOGD(context->GetNodeName(), "gmmSwigluBaseParams.groupNum: %ld", groupNum);
OP_LOGD(context->GetNodeName(), "gmmSwigluBaseParams.coreNum: %u ", compileInfoPtr->aicNum_);
OP_LOGD(context->GetNodeName(), "gmmSwigluBaseParams.M: %ld", m);
OP_LOGD(context->GetNodeName(), "gmmSwigluBaseParams.K: %ld", k);
OP_LOGD(context->GetNodeName(), "gmmSwigluBaseParams.N: %ld", n);
OP_LOGD(context->GetNodeName(), "gmmSwigluBaseParams.baseM: %ld", A8W4_BASEM);
OP_LOGD(context->GetNodeName(), "gmmSwigluBaseParams.baseN: %ld", A8W4_BASEN);
OP_LOGD(context->GetNodeName(), "gmmSwigluBaseParams.mLimit: %ld", mLimit);
OP_LOGD(context->GetNodeName(), "gmmSwigluBaseParams.quantGroupNum: %ld", quantGroupNum);
OP_LOGD(context->GetNodeName(), "gmmSwiglu.maxProcessRowNum: %ld", row);
OP_LOGD(context->GetNodeName(), "gmmSwiglu.groupListLen: %ld", groupNum);
OP_LOGD(context->GetNodeName(), "gmmSwiglu.tokenLen: %ld", n);
OP_LOGD(context->GetNodeName(), "USER_WORKSPACE_LIMIT: %ld", usrWorkspaceLimit);
OP_LOGD(context->GetNodeName(), "workspaceSizes: %lu", workspaceSizes[0]);
OP_LOGD(context->GetNodeName(), "isSplitWorkSpace: %s", isSplitWorkSpace ? "true" : "false");
OP_LOGD(context->GetNodeName(), "GMMSWIGLUQUANT_TILING: baseM is %u, baseK is %u, baseN is %u.", A8W4_BASEM, A8W4_BASEK, A8W4_BASEN);
SetTilingKey(context, isSplitWorkSpace, isA8W4MSD);
tilingData.SaveToBuffer(context->GetRawTilingData()->GetData(), context->GetRawTilingData()->GetCapacity());
context->SetBlockDim(compileInfoPtr->aicNum_); // block dim is the number of aicube
context->GetRawTilingData()->SetDataSize(tilingData.GetDataSize());
OP_LOGD(context->GetNodeName(), "End Run GMM Swiglu Tiling.");
return GRAPH_SUCCESS;
}
ASCENDC_EXTERN_C graphStatus TilingPrepareForGMMSwigluQuant(gert::TilingParseContext *context)
{
// get info
fe::PlatFormInfos *platformInfoPtr = context->GetPlatformInfo();
OP_CHECK_NULL_WITH_CONTEXT(context, platformInfoPtr);
auto compileInfoPtr = context->GetCompiledInfo<GMMSwigluCompileInfo>();
OP_CHECK_NULL_WITH_CONTEXT(context, compileInfoPtr);
auto ascendcPlatform = platform_ascendc::PlatformAscendC(platformInfoPtr);
compileInfoPtr->aicNum_ = ascendcPlatform.GetCoreNumAic();
ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, compileInfoPtr->ubSize_);
OP_LOGD(context->GetNodeName(), "ubSize is %lu, aicNum is %u.", compileInfoPtr->ubSize_, compileInfoPtr->aicNum_);
return GRAPH_SUCCESS;
}
IMPL_OP_OPTILING(GroupedMatmulSwigluQuant)
.Tiling(TilingGMMSwigluQuant)
.TilingParse<GMMSwigluCompileInfo>(TilingPrepareForGMMSwigluQuant);
} // namespace optiling

View File

@@ -0,0 +1,95 @@
/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
/*!
* \file grouped_matmul_swiglu_quant_tiling.h
* \brief
*/
#ifndef AIR_CXX_RUNTIME_V2_OP_IMPL_GROUPED_MATMUL_SWIGLU_QUANT_H
#define AIR_CXX_RUNTIME_V2_OP_IMPL_GROUPED_MATMUL_SWIGLU_QUANT_H
#include <set>
#include "register/tilingdata_base.h"
#include "tiling/tiling_api.h"
namespace optiling {
// GMM 基本信息
BEGIN_TILING_DATA_DEF(GMMSwigluBaseParams)
TILING_DATA_FIELD_DEF(uint32_t, groupNum);
TILING_DATA_FIELD_DEF(uint32_t, coreNum);
TILING_DATA_FIELD_DEF(uint32_t, K);
TILING_DATA_FIELD_DEF(uint32_t, N);
TILING_DATA_FIELD_DEF(uint32_t, M);
TILING_DATA_FIELD_DEF(uint32_t, baseM);
TILING_DATA_FIELD_DEF(uint32_t, baseN);
TILING_DATA_FIELD_DEF(uint32_t, mLimit);
TILING_DATA_FIELD_DEF(uint32_t, workSpaceOffset1);
TILING_DATA_FIELD_DEF(uint32_t, workSpaceOffset2);
TILING_DATA_FIELD_DEF(uint32_t, quantGroupNum);
TILING_DATA_FIELD_DEF(float, limited);
END_TILING_DATA_DEF;
REGISTER_TILING_DATA_CLASS(GMMSwigluBaseParamsOp, GMMSwigluBaseParams)
// SwigluQuant部分tiling 基本信息
BEGIN_TILING_DATA_DEF(GMMSwiglu)
TILING_DATA_FIELD_DEF(uint32_t, maxProcessRowNum);
TILING_DATA_FIELD_DEF(uint32_t, groupListLen);
TILING_DATA_FIELD_DEF(uint32_t, tokenLen);
END_TILING_DATA_DEF;
REGISTER_TILING_DATA_CLASS(GMMSwigluOp, GMMSwiglu)
// 结构体集合
BEGIN_TILING_DATA_DEF(GMMSwigluQuantTilingData)
TILING_DATA_FIELD_DEF_STRUCT(GMMSwigluBaseParams, gmmSwigluBaseParams);
TILING_DATA_FIELD_DEF_STRUCT(GMMSwiglu, gmmSwiglu);
TILING_DATA_FIELD_DEF_STRUCT(TCubeTiling, mmTilingData);
END_TILING_DATA_DEF;
REGISTER_TILING_DATA_CLASS(GroupedMatmulSwigluQuant, GMMSwigluQuantTilingData)
} // namespace optiling
namespace GroupedMatmulSwigluQuantTiling {
constexpr uint32_t X_INDEX = 0;
constexpr uint32_t WEIGHT_INDEX = 1;
constexpr uint32_t WEIGHT_SCALE_INDEX = 2;
constexpr uint32_t GROUPLIST_INDEX = 5;
constexpr uint32_t BATCH_MODE_SCHEDULE = 1;
constexpr uint32_t DIM_0 = 0;
constexpr uint32_t DIM_1 = 1;
constexpr uint32_t DIM_2 = 2;
constexpr uint32_t DIM_3 = 3;
constexpr uint32_t DIM_4 = 4;
constexpr uint32_t NUM_FOUR = 4;
constexpr uint32_t NUM_EIGHT = 8;
constexpr uint32_t SYS_WORKSPACE_SIZE = 16 * 1024 * 1024;
constexpr int64_t USER_WORKSPACE_LIMIT = 64 * 1024 * 1024;
constexpr int64_t DOUBLE_WORKSPACE_SPLIT = 2;
constexpr uint32_t ATTR_INDEX_LIMITED = 2;
constexpr int64_t INT32_DTYPE_SIZE = 4;
constexpr int64_t FP32_DTYPE_SIZE = 4;
constexpr int64_t FP32_BLOCK_SIZE = 8;
constexpr int64_t BLOCK_BYTE = 32;
constexpr int64_t SWIGLU_REDUCE_FACTOR = 2;
constexpr int64_t DOUBLE_BUFFER = 2;
constexpr int64_t ND_WEIGHT_DIM_LIMIT = 3;
constexpr int64_t NZ_WEIGHT_DIM_LIMIT = 5;
constexpr int64_t DOUBLE_ROW = 2;
constexpr int64_t PERCHANNEL_WSCALE_DIM_LIMIT = 2;
constexpr int64_t PERGROUP_WSCALE_DIM_LIMIT = 3;
constexpr int64_t A8W4_MSD_TILING_KEY_MODE = 2;
constexpr int64_t SPLITWORKSPACE_TILING_KEY_MODE = 1;
constexpr int64_t COMMON_TILING_KEY_MODE = 0;
constexpr int64_t A8W4_TOKEN_THRESHOLD = 32;
constexpr int64_t A8W4_BASEM = 128;
constexpr int64_t A8W4_BASEK = 256;
constexpr int64_t A8W4_BASEN = 256;
} // namespace GroupedMatmulSwigluQuantTiling
#endif // AIR_CXX_RUNTIME_V2_OP_IMPL_GROUPED_MATMUL_SWIGLU_QUANT_H

View File

@@ -0,0 +1,540 @@
/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
#include <dlfcn.h>
#include <new>
#include "aclnn_kernels/contiguous.h"
#include "acl/acl.h"
#include "aclnn/aclnn_base.h"
#include "aclnn_kernels/common/op_error_check.h"
#include "opdev/common_types.h"
#include "opdev/data_type_utils.h"
#include "opdev/format_utils.h"
#include "opdev/op_dfx.h"
#include "opdev/op_executor.h"
#include "opdev/op_log.h"
#include "opdev/platform.h"
#include "opdev/shape_utils.h"
#include "opdev/tensor_view_utils.h"
#include "opdev/make_op_executor.h"
#include "grouped_matmul_swiglu_quant.h"
#include "aclnn_grouped_matmul_swiglu_quant_weight_nz.h"
#include "aclnn_grouped_matmul_swiglu_quant.h"
using namespace op;
#ifdef __cplusplus
extern "C" {
#endif
static constexpr int64_t SPLIT = 2L;
static constexpr int64_t K_LIMIT_A8W8 = 65536L;
static constexpr int64_t K_LIMIT_A8W4 = 20000L;
static constexpr int64_t N_LIMIT = 10240L;
static constexpr int64_t NZ_DIM_4_INT8 = 32L;
static constexpr int64_t NZ_DIM_4_INT4 = 64L;
static constexpr int64_t NZ_DIM_3 = 16L;
static constexpr int64_t OUTPUT_IDX_0 = 0L;
static constexpr int64_t OUTPUT_IDX_1 = 1L;
static constexpr int64_t DIM_IDX_0 = 0L;
static constexpr int64_t DIM_IDX_1 = 1L;
static constexpr int64_t DIM_IDX_2 = 2L;
static constexpr int64_t DIM_IDX_3 = 4L;
static constexpr size_t X_DIM_LIMIT = 2UL;
static constexpr size_t WEIGHT_ND_DIM_LIMIT = 3UL;
static constexpr size_t WEIGHT_NZ_DIM_LIMIT = 5UL;
static constexpr size_t WEIGHT_SCALE_DIM_LIMIT = 2UL;
static constexpr size_t WEIGHT_SCALE_PERGROUP_DIM_LIMIT = 3UL;
static constexpr size_t WEIGHT_SCALE_PERCHANNEL_DIM_LIMIT = 2UL;
static constexpr size_t TOKEN_SCALE_DIM_LIMIT = 1UL;
static constexpr size_t BIAS_DIM_LIMIT = 2UL;
static constexpr size_t GROUP_LIST_DIM_LIMIT = 1UL;
static constexpr size_t QUANTOUT_DIM_LIMIT = 2UL;
static constexpr size_t QUANTSCALEOUT_DIM_LIMIT = 1UL;
static constexpr size_t INT4_PER_INT32 = 8UL;
bool isEnableWeightAssistanceMatrix = false;
int dequantMode = 0;
static const std::initializer_list<DataType> X_DTYPE_SUPPORT_LIST = {DataType::DT_INT8};
static const std::initializer_list<DataType> WEIGHT_DTYPE_SUPPORT_LIST = {DataType::DT_INT8, DataType::DT_INT4};
static const std::initializer_list<DataType> WEIGHT_SCALE_DTYPE_SUPPORT_LIST = {
DataType::DT_FLOAT, DataType::DT_FLOAT16, DataType::DT_BF16};
static const std::initializer_list<DataType> WEIGHT_SCALE_A8W4_DTYPE_SUPPORT_LIST = {DataType::DT_UINT64};
static const std::initializer_list<DataType> X_SCALE_DTYPE_SUPPORT_LIST = {DataType::DT_FLOAT, DataType::DT_FLOAT16,
DataType::DT_BF16};
static const std::initializer_list<DataType> GROUP_LIST_DTYPE_SUPPORT_LIST = {DataType::DT_INT64};
static const std::initializer_list<DataType> QUANTOUT_DTYPE_SUPPORT_LIST = {DataType::DT_INT8};
static const std::initializer_list<DataType> QUANTSCALEOUT_DTYPE_SUPPORT_LIST = {DataType::DT_FLOAT};
static const std::initializer_list<DataType> BIAS_DTYPE_SUPPORT_LIST = {DataType::DT_FLOAT};
static bool CheckNotNull(const aclTensor *x, const aclTensor *weight, const aclTensor *bias, const aclTensor *offset,
const aclTensor *weightScale, const aclTensor *xScale, const aclTensor *groupList,
const aclTensor *output, const aclTensor *outputScale, const aclTensor *outputOffset)
{
OP_CHECK_NULL(x, return false);
OP_CHECK_NULL(weight, return false);
OP_CHECK_NULL(weightScale, return false);
OP_CHECK_NULL(xScale, return false);
OP_CHECK_NULL(groupList, return false);
OP_CHECK_NULL(output, return false);
OP_CHECK_NULL(outputScale, return false);
if (x->GetDataType() == DataType::DT_INT8 && weight->GetDataType() == DataType::DT_INT8 && bias != nullptr) {
OP_LOGW("aclnnGroupedMatmulSwiGluQuant, The current version does not support the scenario that bias is not 0. "
"Features and accuracy are not guaranteed if inputting bias with values other than 0.");
} else if (x->GetDataType() == DataType::DT_INT8 && weight->GetDataType() == DataType::DT_INT4 && bias == nullptr) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant, The current version does not support the scenario that without bias. "
"When x is Int8 and weight is int4, bias serves as an auxiliary matrix to weight, and this parameter "
"cannot be nullptr.");
return false;
}
if (offset != nullptr) {
OP_LOGW(
"aclnnGroupedMatmulSwiGluQuant, The current version does not support the scenario where offset is not 0. "
"Features and accuracy are not guaranteed if inputting bias with values other than 0s.");
}
if (outputOffset != nullptr) {
OP_LOGW("aclnnGroupedMatmulSwiGluQuant, The current version does not support the scenario where outputOffset "
"is not 0. Features and accuracy are not guaranteed if inputting bias with values other than 0s.");
}
return true;
}
static bool CheckInputOutDims_A8W8(const aclTensor *x, const aclTensor *weight, const aclTensor *weightScale,
const aclTensor *xScale, const aclTensor *groupList, const aclTensor *output,
const aclTensor *outputScale)
{
OP_CHECK_WRONG_DIMENSION(x, X_DIM_LIMIT, return false);
op::Format weightViewFormat = weight->GetViewFormat();
if (IsPrivateFormat(weightViewFormat)) {
OP_CHECK_WRONG_DIMENSION(weight, WEIGHT_NZ_DIM_LIMIT, return false);
} else {
OP_CHECK_WRONG_DIMENSION(weight, WEIGHT_ND_DIM_LIMIT, return false);
}
OP_CHECK_WRONG_DIMENSION(weightScale, WEIGHT_SCALE_DIM_LIMIT, return false);
OP_CHECK_WRONG_DIMENSION(xScale, TOKEN_SCALE_DIM_LIMIT, return false);
OP_CHECK_WRONG_DIMENSION(groupList, GROUP_LIST_DIM_LIMIT, return false);
OP_CHECK_WRONG_DIMENSION(output, QUANTOUT_DIM_LIMIT, return false);
OP_CHECK_WRONG_DIMENSION(outputScale, QUANTSCALEOUT_DIM_LIMIT, return false);
return true;
}
static bool CheckInputOutDims_A8W4(const aclTensor *x, const aclTensor *weight, const aclTensor *bias,
const aclTensor *weightScale, const aclTensor *xScale, const aclTensor *groupList,
const aclTensor *output, const aclTensor *outputScale)
{
OP_CHECK_WRONG_DIMENSION(x, X_DIM_LIMIT, return false);
op::Format weightViewFormat = weight->GetViewFormat();
if (IsPrivateFormat(weightViewFormat)) {
OP_CHECK_WRONG_DIMENSION(weight, WEIGHT_NZ_DIM_LIMIT, return false);
} else {
OP_CHECK_WRONG_DIMENSION(weight, WEIGHT_ND_DIM_LIMIT, return false);
}
// 支持pergroup、perchannel量化weightScale分别为2维和3维
OP_CHECK_MAX_DIM(weightScale, WEIGHT_SCALE_PERGROUP_DIM_LIMIT, return false);
OP_CHECK_MIN_DIM(weightScale, WEIGHT_SCALE_PERCHANNEL_DIM_LIMIT, return false);
OP_CHECK_WRONG_DIMENSION(bias, BIAS_DIM_LIMIT, return false);
OP_CHECK_WRONG_DIMENSION(xScale, TOKEN_SCALE_DIM_LIMIT, return false);
OP_CHECK_WRONG_DIMENSION(groupList, GROUP_LIST_DIM_LIMIT, return false);
OP_CHECK_WRONG_DIMENSION(output, QUANTOUT_DIM_LIMIT, return false);
OP_CHECK_WRONG_DIMENSION(outputScale, QUANTSCALEOUT_DIM_LIMIT, return false);
return true;
}
static bool CheckInputOutShape_A8W8(const aclTensor *x, const aclTensor *weight, const aclTensor *weightScale,
const aclTensor *xScale, const aclTensor *groupList, const aclTensor *output,
const aclTensor *outputScale)
{
int64_t m = x->GetViewShape().GetDim(0);
int64_t k = x->GetViewShape().GetDim(1);
int64_t n = weightScale->GetViewShape().GetDim(1);
int64_t e = weight->GetViewShape().GetDim(0);
if (n % SPLIT != 0) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID, "aclnnGroupedMatmulSwiGluQuant, N is %ld , not an even number.", n);
return false;
}
int64_t nAfterHalve = static_cast<int64_t>(n / SPLIT);
// x的shape期望为[M, K]
op::Shape xExpectShape = {m, k};
// weight的NDshape期望为[E, K, N]
op::Shape weightNDExpectShape = {e, k, n};
// weight的NZshape期望为[E, N // 32, K // 16, 16, 32]
op::Shape weightNZExpectShape = {e, static_cast<int64_t>(n / NZ_DIM_4_INT8), static_cast<int64_t>(k / NZ_DIM_3),
NZ_DIM_3, NZ_DIM_4_INT8};
// weightScale的shape期望为[E, N]
op::Shape weightScaleExpectShape = {e, n};
// xScale的shape期望为[E, N]
op::Shape xScaleExpectShape = {m};
// output的shape期望为[M, N]
op::Shape outputExpectShape = {m, nAfterHalve};
// outputScale的shape期望为[M]
op::Shape outputScaleExpectShape = {m};
op::Format weightViewFormat = weight->GetViewFormat();
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(x, xExpectShape, return false);
if (IsPrivateFormat(weightViewFormat)) {
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(weight, weightNZExpectShape, return false);
} else {
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(weight, weightNDExpectShape, return false);
}
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(weightScale, weightScaleExpectShape, return false);
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(xScale, xScaleExpectShape, return false);
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(output, outputExpectShape, return false);
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(outputScale, outputScaleExpectShape, return false);
// groupList的长度应小于等于weight的专家数
int64_t groupListLen = groupList->GetViewShape().GetDim(0);
if (groupListLen > e) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant A8W8, Length of 'groupList' out of range"
" (expected to be in range of [1, %ld], but got %ld)",
e, groupListLen);
return false;
}
if (n > N_LIMIT) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant A8W8: The current version does not support the scenario that "
"N(%ld) is greater than %ld.",
n, N_LIMIT);
return false;
}
if (k >= K_LIMIT_A8W8) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant A8W8, The current version does not support the scenario."
"The tail axis dimension of input0(x) is %ld, which need lower than %ld.",
k, K_LIMIT_A8W8);
return false;
}
return true;
}
static bool CheckInputOutShape_A8W4(const aclTensor *x, const aclTensor *weight, const aclTensor *bias,
const aclTensor *weightScale, const aclTensor *xScale, const aclTensor *groupList,
const aclTensor *output, const aclTensor *outputScale)
{
int64_t e = weight->GetViewShape().GetDim(0);
int64_t m = x->GetViewShape().GetDim(0);
int64_t k = x->GetViewShape().GetDim(1);
int64_t n = 1;
int64_t KGroupCount = 1; // K轴的组数,perchannel场景相当于pergroup场景中的组数为1
int64_t KGroupSize = k; // K轴每组的元素个数
op::Shape weightScaleExpectShape;
// 通过weightScale的维度判断是否为perchannel 或 pergroup量化模式
if (weightScale->GetViewShape().GetDimNum() == WEIGHT_SCALE_PERCHANNEL_DIM_LIMIT) {
// weightScale入参在perchannel场景期望shape [E, N]
n = weightScale->GetViewShape().GetDim(DIM_IDX_1);
weightScaleExpectShape = {e, n};
} else if (weightScale->GetViewShape().GetDimNum() == WEIGHT_SCALE_PERGROUP_DIM_LIMIT) {
// weightScale入参在pergroup场景期望shape [E, KGroupCount, N]
n = weightScale->GetViewShape().GetDim(DIM_IDX_2);
KGroupCount = weightScale->GetViewShape().GetDim(DIM_IDX_1);
KGroupSize = KGroupCount > 0 ? k / KGroupCount : k;
weightScaleExpectShape = {e, KGroupCount, n};
}
if (KGroupCount == 0 || k % KGroupCount != 0) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant, "
"The number of groups along the k-axis is %ld, and the length of the k-axis is %ld, which is illegal. "
"The number of groups must be greater than 0, and k-axis length %% number of groups == 0 must be true.",
KGroupCount, k);
return false;
}
if (n % SPLIT != 0) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID, "aclnnGroupedMatmulSwiGluQuant, N is %ld , which must even number.", n);
return false;
}
int64_t nAfterHalve = static_cast<int64_t>(n / SPLIT);
// x的shape期望为[M, K]
op::Shape xExpectShape = {m, k};
// weight的NDshape期望为[E, K, N]
op::Shape weightNDExpectShape = {e, k, n};
op::Shape biasExpectShape = {e, n};
// weight的NZshape期望为[E, N // 64, K // 16, 16, 64]
op::Shape weightNZExpectShape = {e, static_cast<int64_t>(n / NZ_DIM_4_INT4), static_cast<int64_t>(k / NZ_DIM_3),
NZ_DIM_3, NZ_DIM_4_INT4};
// xScale的shape期望为[E, N]
op::Shape xScaleExpectShape = {m};
// output的shape期望为[M, N]
op::Shape outputExpectShape = {m, nAfterHalve};
// outputScale的shape期望为[M]
op::Shape outputScaleExpectShape = {m};
op::Format weightViewFormat = weight->GetViewFormat();
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(x, xExpectShape, return false);
if (IsPrivateFormat(weightViewFormat)) {
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(weight, weightNZExpectShape, return false);
} else {
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(weight, weightNDExpectShape, return false);
}
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(bias, biasExpectShape, return false);
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(weightScale, weightScaleExpectShape, return false);
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(xScale, xScaleExpectShape, return false);
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(output, outputExpectShape, return false);
OP_CHECK_SHAPE_NOT_EQUAL_WITH_EXPECTED_SIZE(outputScale, outputScaleExpectShape, return false);
// groupList的长度应小于等于weight的专家数
int64_t groupListLen = groupList->GetViewShape().GetDim(0);
if (groupListLen > e) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant A8W4, Length of 'groupList' out of range"
" (expected to be in range of [1, %ld], but got %ld)",
e, groupListLen);
return false;
}
if (n > N_LIMIT) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant A8W4, The current version does not support the scenario."
"where N after halve is %ld greater than %ld.",
n, N_LIMIT);
return false;
}
if (k >= K_LIMIT_A8W4) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant A8W4, The current version does not support the scenario."
"The tail axis dimension of input0(x) is %ld, which need lower than %ld.",
k, K_LIMIT_A8W4);
return false;
}
(void)KGroupSize;
return true;
}
static bool CheckDtypeValid(const aclTensor *x, const aclTensor *weight, const aclTensor *bias,
const aclTensor *weightScale, const aclTensor *xScale, const aclTensor *groupList,
const aclTensor *output, const aclTensor *outputScale)
{
OP_CHECK_DTYPE_NOT_SUPPORT(x, X_DTYPE_SUPPORT_LIST, return false);
OP_CHECK_DTYPE_NOT_SUPPORT(weight, WEIGHT_DTYPE_SUPPORT_LIST, return false);
if (weight->GetDataType() == DataType::DT_INT4) {
OP_CHECK_DTYPE_NOT_SUPPORT(bias, BIAS_DTYPE_SUPPORT_LIST, return false);
}
if (weight->GetDataType() == DataType::DT_INT4) {
OP_CHECK_DTYPE_NOT_SUPPORT(weightScale, WEIGHT_SCALE_A8W4_DTYPE_SUPPORT_LIST, return false);
} else if (weight->GetDataType() == DataType::DT_INT8) {
OP_CHECK_DTYPE_NOT_SUPPORT(weightScale, WEIGHT_SCALE_DTYPE_SUPPORT_LIST, return false);
}
OP_CHECK_DTYPE_NOT_SUPPORT(xScale, X_SCALE_DTYPE_SUPPORT_LIST, return false);
OP_CHECK_DTYPE_NOT_SUPPORT(groupList, GROUP_LIST_DTYPE_SUPPORT_LIST, return false);
OP_CHECK_DTYPE_NOT_SUPPORT(output, QUANTOUT_DTYPE_SUPPORT_LIST, return false);
OP_CHECK_DTYPE_NOT_SUPPORT(outputScale, QUANTSCALEOUT_DTYPE_SUPPORT_LIST, return false);
return true;
}
static bool CheckFormat(const aclTensor *x, const aclTensor *weight, const aclTensor *output)
{
bool isNZ = weight->GetStorageFormat() == op::Format::FORMAT_FRACTAL_NZ;
if ((x->GetDataType() == DataType::DT_INT8 && weight->GetDataType() == DataType::DT_INT8) && !isNZ) {
// fp16 in fp32 out that is split k template, not precision-advanced now
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant, The current version does not support the scenario."
"weight Format expect is FRACTAL_NZ, but got [%s].",
op::ToString(weight->GetStorageFormat()).GetString());
return false;
}
if (IsPrivateFormat(x->GetStorageFormat())) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant, The current version does not support the scenario."
"x Format Not support Private Format.");
return false;
}
if (IsPrivateFormat(output->GetStorageFormat())) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwiGluQuant, The current version does not support the scenario."
"output Format Not support Private Format.");
return false;
}
return true;
}
static void UnpackInt32ToInt4(const aclTensor *&tensorS32, const std::string &tensorType)
{
OP_LOGD("Unpack %s from int32 to int4 start.", tensorType.c_str());
auto tensorS4 = const_cast<aclTensor *>(tensorS32);
op::Shape tensorShape = tensorS4->GetViewShape();
auto viewShapeDim = tensorShape.GetDimNum();
tensorShape[viewShapeDim - 1] = tensorShape[viewShapeDim - 1] * INT4_PER_INT32;
tensorS4->SetViewShape(tensorShape);
tensorS4->SetStorageShape(tensorShape);
tensorS4->SetDataType(DataType::DT_INT4);
OP_LOGD("Unpack %s from int32 to int4 finished.", tensorType.c_str());
}
static aclnnStatus CheckParams(const aclTensor *x, const aclTensor *weight, const aclTensor *bias,
const aclTensor *offset, const aclTensor *weightScale, const aclTensor *xScale,
const aclTensor *groupList, const aclTensor *output, const aclTensor *outputScale,
const aclTensor *outputOffset)
{
// 1. 检查参数是否为空指针
CHECK_RET(CheckNotNull(x, weight, bias, offset, weightScale, xScale, groupList, output, outputScale, outputOffset),
ACLNN_ERR_PARAM_NULLPTR);
// A8W8场景
if (x->GetDataType() == DataType::DT_INT8 && weight->GetDataType() == DataType::DT_INT8) {
// 2. 校验输入、输出参数维度
CHECK_RET(CheckInputOutDims_A8W8(x, weight, weightScale, xScale, groupList, output, outputScale),
ACLNN_ERR_PARAM_INVALID);
// 3. 校验输入、输出shape参数
CHECK_RET(CheckInputOutShape_A8W8(x, weight, weightScale, xScale, groupList, output, outputScale),
ACLNN_ERR_PARAM_INVALID);
}
// A8W4场景 INT32为兼容torch_npu考虑,实际计算时,1个INT32数据会被视为8个INT4数据
if ((x->GetDataType() == DataType::DT_INT8 && weight->GetDataType() == DataType::DT_INT4) ||
(x->GetDataType() == DataType::DT_INT8 && weight->GetDataType() == DataType::DT_INT32)) {
// 将INT32视为8个Int4数据,调整viewShape和dtype便于后续统一校验
if (weight->GetDataType() == DataType::DT_INT32) {
UnpackInt32ToInt4(weight, "weight");
}
if (weightScale->GetDataType() == DataType::DT_INT64) {
auto weightScale_fix = const_cast<aclTensor *>(weightScale);
weightScale_fix->SetDataType(DataType::DT_UINT64);
}
// 2. 校验输入、输出参数维度
CHECK_RET(CheckInputOutDims_A8W4(x, weight, bias, weightScale, xScale, groupList, output, outputScale),
ACLNN_ERR_PARAM_INVALID);
// 3. 校验输入、输出shape参数
CHECK_RET(CheckInputOutShape_A8W4(x, weight, bias, weightScale, xScale, groupList, output, outputScale),
ACLNN_ERR_PARAM_INVALID);
}
// 4. 检查输入的数据类型是否在支持的数据类型范围之内
CHECK_RET(CheckDtypeValid(x, weight, bias, weightScale, xScale, groupList, output, outputScale),
ACLNN_ERR_PARAM_INVALID);
// 5. 检查数据形状是否支持
CHECK_RET(CheckFormat(x, weight, output), ACLNN_ERR_PARAM_INVALID);
return ACLNN_SUCCESS;
}
static aclnnStatus aclnnGroupedMatmulSwigluQuantGetWorkspaceSizeCommon(
const aclTensor *x, const aclTensor *weight, const aclTensor *bias, const aclTensor *offset,
const aclTensor *weightScale, const aclTensor *xScale, const aclTensor *groupList, double limited, aclTensor *output,
aclTensor *outputScale, aclTensor *outputOffset, uint64_t *workspaceSize, aclOpExecutor **executor)
{
// 固定写法,创建OpExecutor
auto uniqueExecutor = CREATE_EXECUTOR();
CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
// 固定写法,参数检查
auto ret = CheckParams(x, weight, bias, offset, weightScale, xScale, groupList, output, outputScale, outputOffset);
CHECK_RET(ret == ACLNN_SUCCESS, ret);
// 空Tensor场景
if (output->IsEmpty() || groupList->IsEmpty() || outputScale->IsEmpty()) {
*workspaceSize = 0;
uniqueExecutor.ReleaseTo(executor);
return ACLNN_SUCCESS;
}
// 转连续
x = l0op::Contiguous(x, uniqueExecutor.get());
CHECK_RET(x != nullptr, ACLNN_ERR_INNER_NULLPTR);
// 若weight为私有格式,则不应该做连续性转换 (l0op::Contiguous接口会把viewShape赋值给storageShape)
if (IsPrivateFormat(weight->GetStorageFormat())) {
weight->SetOriginalShape(weight->GetViewShape());
} else {
weight = l0op::Contiguous(weight, uniqueExecutor.get());
}
CHECK_RET(weight != nullptr, ACLNN_ERR_INNER_NULLPTR);
weightScale = l0op::Contiguous(weightScale, uniqueExecutor.get());
CHECK_RET(weightScale != nullptr, ACLNN_ERR_INNER_NULLPTR);
xScale = l0op::Contiguous(xScale, uniqueExecutor.get());
CHECK_RET(xScale != nullptr, ACLNN_ERR_INNER_NULLPTR);
groupList = l0op::Contiguous(groupList, uniqueExecutor.get());
CHECK_RET(groupList != nullptr, ACLNN_ERR_INNER_NULLPTR);
// 调用L0算子能力
if (bias != nullptr) {
isEnableWeightAssistanceMatrix = true;
bias = l0op::Contiguous(bias, uniqueExecutor.get());
CHECK_RET(bias != nullptr, ACLNN_ERR_INNER_NULLPTR);
}
if (isEnableWeightAssistanceMatrix && weightScale->GetViewShape().GetDimNum() == WEIGHT_SCALE_PERGROUP_DIM_LIMIT) {
dequantMode = 1;
}
auto ret_0 = l0op::GroupedMatmulSwigluQuant(x, weight, weightScale, xScale, groupList, limited, bias,
isEnableWeightAssistanceMatrix, dequantMode, uniqueExecutor.get());
CHECK_RET(ret_0 != std::tuple(nullptr, nullptr), ACLNN_ERR_INNER_NULLPTR);
auto out0 = std::get<OUTPUT_IDX_0>(ret_0);
auto ret_1 = l0op::ViewCopy(out0, output, uniqueExecutor.get());
CHECK_RET(ret_1 != nullptr, ACLNN_ERR_INNER_NULLPTR);
auto out1 = std::get<OUTPUT_IDX_1>(ret_0);
auto ret_2 = l0op::ViewCopy(out1, outputScale, uniqueExecutor.get());
CHECK_RET(ret_2 != nullptr, ACLNN_ERR_INNER_NULLPTR);
*workspaceSize = uniqueExecutor->GetWorkspaceSize();
uniqueExecutor.ReleaseTo(executor);
return ACLNN_SUCCESS;
}
aclnnStatus aclnnGroupedMatmulSwigluQuantGetWorkspaceSize(const aclTensor *x, const aclTensor *weight,
const aclTensor *bias, const aclTensor *offset,
const aclTensor *weightScale, const aclTensor *xScale,
const aclTensor *groupList, double limited, aclTensor *output,
aclTensor *outputScale, aclTensor *outputOffset,
uint64_t *workspaceSize, aclOpExecutor **executor)
{
OP_CHECK_COMM_INPUT(workspaceSize, executor);
L2_DFX_PHASE_1(aclnnGroupedMatmulSwigluQuant, DFX_IN(x, weight, bias, offset, weightScale, xScale, groupList, limited),
DFX_OUT(output, outputScale, outputOffset));
// 固定写法,创建OpExecutor
return aclnnGroupedMatmulSwigluQuantGetWorkspaceSizeCommon(x, weight, bias, offset, weightScale, xScale, groupList, limited,
output, outputScale, outputOffset, workspaceSize,
executor);
}
aclnnStatus aclnnGroupedMatmulSwigluQuantWeightNZGetWorkspaceSize(const aclTensor *x, const aclTensor *weight,
const aclTensor *bias, const aclTensor *offset,
const aclTensor *weightScale, const aclTensor *xScale,
const aclTensor *groupList, double limited, aclTensor *output,
aclTensor *outputScale, aclTensor *outputOffset,
uint64_t *workspaceSize, aclOpExecutor **executor)
{
OP_CHECK_COMM_INPUT(workspaceSize, executor);
L2_DFX_PHASE_1(aclnnGroupedMatmulSwigluQuantWeightNZ,
DFX_IN(x, weight, bias, offset, weightScale, xScale, groupList),
DFX_OUT(output, outputScale, outputOffset));
// weight在该场景下强制绑定StorageFormat 和 ViewFormat 为NZ
CHECK_RET(weight != nullptr, ACLNN_ERR_PARAM_NULLPTR);
auto storgeShape = weight->GetStorageShape();
auto viewShape = weight->GetViewShape();
aclTensor *weightNZ = const_cast<aclTensor *>(weight);
CHECK_COND((storgeShape.GetDimNum() == WEIGHT_NZ_DIM_LIMIT), ACLNN_ERR_PARAM_INVALID,
"aclnnGroupedMatmulSwigluQuantWeightNZ, The dimnum of storageShape for second input (weight)"
"must be 5. \n But StorageShape got %s , and dimNum is %lu.",
op::ToString(storgeShape).GetString(), storgeShape.GetDimNum());
// weight的StorageFormat无条件视为NZ
weightNZ->SetStorageFormat(op::Format::FORMAT_FRACTAL_NZ);
if (viewShape.GetDimNum() == WEIGHT_NZ_DIM_LIMIT) {
// 若weight的viewShape为5维则视为NZ
weightNZ->SetViewFormat(op::Format::FORMAT_FRACTAL_NZ);
} else if (viewShape.GetDimNum() == WEIGHT_ND_DIM_LIMIT) {
// 若weight的viewShape为3维则视为ND
weightNZ->SetViewFormat(op::Format::FORMAT_ND);
}
// 调用公共接口
return aclnnGroupedMatmulSwigluQuantGetWorkspaceSizeCommon(x, weight, bias, offset, weightScale, xScale, groupList, limited,
output, outputScale, outputOffset, workspaceSize,
executor);
}
aclnnStatus aclnnGroupedMatmulSwigluQuant(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor,
aclrtStream stream)
{
L2_DFX_PHASE_2(aclnnGroupedMatmulSwigluQuant);
CHECK_COND(CommonOpExecutorRun(workspace, workspaceSize, executor, stream) == ACLNN_SUCCESS, ACLNN_ERR_INNER,
"This is an error in GroupedMatmulSwigluQuant launch aicore");
return ACLNN_SUCCESS;
}
aclnnStatus aclnnGroupedMatmulSwigluQuantWeightNZ(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor,
aclrtStream stream)
{
L2_DFX_PHASE_2(aclnnGroupedMatmulSwigluQuantWeightNZ);
CHECK_COND(CommonOpExecutorRun(workspace, workspaceSize, executor, stream) == ACLNN_SUCCESS, ACLNN_ERR_INNER,
"This is an error in GroupedMatmulSwigluQuantWeightNZ launch aicore");
return ACLNN_SUCCESS;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,58 @@
/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
#ifndef OP_API_INC_GROUPED_MATMUL_SWIGLU_QUANT_H
#define OP_API_INC_GROUPED_MATMUL_SWIGLU_QUANT_H
#include "aclnn/aclnn_base.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief aclnnGroupedMatmulSwigluQuant的第一段接口,根据具体的计算流程,计算workspace大小。
* @domain aclnn_ops_infer
*
* @param [in] x: 表示公式中的x,数据类型支持INT8数据类型,数据格式支持ND。
* @param [in] weight:
* 表示公式中的weight,数据类型支持INT8数据类型,数据格式支持NZ。
* @param [in] weightScale:
* 表示量化参数,数据类型支持FLOAT16、BFLOAT16、FLOAT32数据类型,数据格式支持ND,支持的最大长度为128个。 表示per
* Channel参数,数据类型支持FLOAT16,BFLOAT16数据类型,数据格式支持ND。
* @param [in] xScale:
* 表示per Token量化参数,数据类型支持FLOAT32数据类型,数据格式支持ND。
* @param [in] groupList: 必选参数,代表输入和输出分组轴上的索引情况,数据类型支持INT64。
* @param [out] quantOutput: 表示公式中的out,数据类型支持INT8数据类型,数据格式支持ND。
* @param [out] quantScaleOutput: 表示公式中的outQuantScale,数据类型支持Float32数据类型。
* @param [out] workspaceSize: 返回用户需要在npu device侧申请的workspace大小。
* @param [out] executor: 返回op执行器,包含算子计算流程。
* @return aclnnStatus: 返回状态码。
*/
__attribute__((visibility("default"))) aclnnStatus aclnnGroupedMatmulSwigluQuantGetWorkspaceSize(
const aclTensor *x, const aclTensor *weight, const aclTensor *bias, const aclTensor *offset,
const aclTensor *weightScale, const aclTensor *xScale, const aclTensor *groupList, double limited, aclTensor *output,
aclTensor *outputScale, aclTensor *outputOffset, uint64_t *workspaceSize, aclOpExecutor **executor);
/**
* @brief aclnnGroupedMatmulSwigluQuant的第二段接口,用于执行计算。
* @param [in] workspace: 在npu device侧申请的workspace内存起址。
* @param [in] workspaceSize: 在npu
* device侧申请的workspace大小,由第一段接口aclnnGroupedMatmulSwigluQuantGetWorkspaceSize获取。
* @param [in] stream: acl stream流。
* @param [in] executor: op执行器,包含了算子计算流程。
* @return aclnnStatus: 返回状态码。
*/
__attribute__((visibility("default"))) aclnnStatus
aclnnGroupedMatmulSwigluQuant(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,60 @@
/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
#ifndef OP_API_INC_GROUPED_MATMUL_SWIGLU_QUANT_WEIGHT_NZ_H
#define OP_API_INC_GROUPED_MATMUL_SWIGLU_QUANT_WEIGHT_NZ_H
#include "aclnn/aclnn_base.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief aclnnGroupedMatmulSwigluQuantWeightNZ的第一段接口,根据具体的计算流程,计算workspace大小。
* @domain aclnn_ops_infer
*
* @param [in] x: 表示公式中的x,数据类型支持INT8数据类型,数据格式支持ND。
* @param [in] weight:
* 表示公式中的weight,数据类型支持INT8数据类型,数据格式支持NZ。
* @param [in] weightScale:
* 表示量化参数,数据类型支持FLOAT16、BFLOAT16、FLOAT32数据类型,数据格式支持ND,支持的最大长度为128个。 表示per
* Channel参数,数据类型支持FLOAT16,BFLOAT16数据类型,数据格式支持ND。
* @param [in] xScale:
* 表示per Token量化参数,数据类型支持FLOAT32数据类型,数据格式支持ND。
* @param [in] groupList: 必选参数,代表输入和输出分组轴上的索引情况,数据类型支持INT64。
* @param [out] quantOutput: 表示公式中的out,数据类型支持INT8数据类型,数据格式支持ND。
* @param [out] quantScaleOutput: 表示公式中的outQuantScale,数据类型支持Float32数据类型。
* @param [out] workspaceSize: 返回用户需要在npu device侧申请的workspace大小。
* @param [out] executor: 返回op执行器,包含算子计算流程。
* @return aclnnStatus: 返回状态码。
*/
__attribute__((visibility("default"))) aclnnStatus aclnnGroupedMatmulSwigluQuantWeightNZGetWorkspaceSize(
const aclTensor *x, const aclTensor *weight, const aclTensor *bias, const aclTensor *offset,
const aclTensor *weightScale, const aclTensor *xScale, const aclTensor *groupList, double limited, aclTensor *output,
aclTensor *outputScale, aclTensor *outputOffset, uint64_t *workspaceSize, aclOpExecutor **executor);
/**
* @brief aclnnGroupedMatmulSwigluQuantWeightNZ的第二段接口,用于执行计算。
* @param [in] workspace: 在npu device侧申请的workspace内存起址。
* @param [in] workspaceSize: 在npu
* device侧申请的workspace大小,由第一段接口aclnnGroupedMatmulSwigluQuantWeightNZGetWorkspaceSize获取。
* @param [in] stream: acl stream流。
* @param [in] executor: op执行器,包含了算子计算流程。
* @return aclnnStatus: 返回状态码。
*/
__attribute__((visibility("default"))) aclnnStatus aclnnGroupedMatmulSwigluQuantWeightNZ(void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
aclrtStream stream);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,58 @@
/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
#include "opdev/op_log.h"
#include "opdev/op_dfx.h"
#include "opdev/make_op_executor.h"
#include "grouped_matmul_swiglu_quant.h"
using namespace op;
namespace l0op {
OP_TYPE_REGISTER(GroupedMatmulSwigluQuant);
const std::tuple<aclTensor *, aclTensor *>
GroupedMatmulSwigluQuant(const aclTensor *x, const aclTensor *weight, const aclTensor *perChannelScale,
const aclTensor *perTokenScale, const aclTensor *groupList, double limited,
const aclTensor *weightAssistanceMatrix, bool isEnableWeightAssistanceMatrix, int dequantMode,
aclOpExecutor *executor)
{
L0_DFX(GroupedMatmulSwigluQuant, x, weight, perChannelScale, perTokenScale, weightAssistanceMatrix, groupList, limited,
isEnableWeightAssistanceMatrix, dequantMode);
if (x == nullptr) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID, "x is nullptr.");
return std::tuple(nullptr, nullptr);
}
int64_t m = perTokenScale->GetViewShape().GetDim(0);
int64_t n = perChannelScale->GetViewShape().GetDim(1);
int64_t nAfterHalve = static_cast<int64_t>(n / 2);
gert::Shape outShape({m, nAfterHalve});
gert::Shape scaleOutShape({m});
auto out = executor->AllocTensor(outShape, DataType::DT_INT8, ge::FORMAT_ND);
auto scaleOut = executor->AllocTensor(scaleOutShape, DataType::DT_FLOAT, ge::FORMAT_ND);
auto ret = INFER_SHAPE(GroupedMatmulSwigluQuant,
OP_INPUT(x, weight, perChannelScale, perTokenScale, weightAssistanceMatrix, groupList),
OP_OUTPUT(out, scaleOut), OP_ATTR(isEnableWeightAssistanceMatrix, dequantMode, limited));
if (ret != ACLNN_SUCCESS) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID, "InferShape failed.");
return std::tuple(nullptr, nullptr);
}
ret = ADD_TO_LAUNCHER_LIST_AICORE(
GroupedMatmulSwigluQuant,
OP_INPUT(x, weight, perChannelScale, perTokenScale, weightAssistanceMatrix, groupList),
OP_OUTPUT(out, scaleOut), OP_ATTR(isEnableWeightAssistanceMatrix, dequantMode, limited));
if (ret != ACLNN_SUCCESS) {
OP_LOGE(ACLNN_ERR_PARAM_INVALID, "ADD_TO_LAUNCHER_LIST_AICORE failed.");
return std::tuple(nullptr, nullptr);
}
return std::tie(out, scaleOut);
}
} // namespace l0op

View File

@@ -0,0 +1,23 @@
/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
#ifndef OP_API_INC_LEVEL0_OP_GROUPED_MATMUL_SWIGLU_QUANT_OP_H
#define OP_API_INC_LEVEL0_OP_GROUPED_MATMUL_SWIGLU_QUANT_OP_H
#include "opdev/op_executor.h"
namespace l0op {
const std::tuple<aclTensor *, aclTensor *>
GroupedMatmulSwigluQuant(const aclTensor *x, const aclTensor *weight, const aclTensor *perChannelScale,
const aclTensor *perTokenScale, const aclTensor *groupList, double limited,
const aclTensor *weightAssistanceMatrix, bool isEnableWeightAssistanceMatrix, int dequantMode,
aclOpExecutor *executor);
}
#endif