尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

aclnnMoeTokenPermuteV2 算子深度指南:CANN ops-transformer 中 MoE Token Permute 的量化扩展与两段式调用

aclnnMoeTokenPermuteV2 算子深度指南:CANN ops-transformer 中 MoE Token Permute 的量化扩展与两段式调用 aclnnMoeTokenPermuteV2 算子深度指南CANN ops-transformer 中 MoE Token Permute 的量化扩展与两段式调用【免费下载链接】ops-transformer本项目是CANN提供的transformer类大模型算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-transformer导读aclnnMoeTokenPermuteV2是 CANN ops-transformer 算子库moe/moe_token_permute目录为 MoEMixture of Experts混合专家架构提供的 token 重排permute计算接口。它根据路由gating产生的 indices 索引将输入 tokens 按专家 ID 广播、排序为后续专家网络的分组计算做好准备相比 V1 版本aclnnMoeTokenPermuteV2 新增了quantMode与expandedScaleOut参数并在 Ascend 950 平台支持 MXFP8 / MXFP4 量化输出。阅读本文后你将掌握该算子的两段式接口调用范式、全部参数与输出 shape 的推导规则、平台差异化行为以及其背后的 op_host 源码实现与 PyTorch 封装用法。产品支持情况aclnnMoeTokenPermuteV2接口在产品上的支持矩阵如下产品是否支持Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品不支持Atlas 训练系列产品不支持需要注意的是量化能力quantMode只在 Ascend 950 平台上生效在非 Ascend 950 平台如 Atlas A2 / A3上量化参数会被静默忽略接口按非量化兼容路径处理详见下文“平台行为差异”一节。功能说明接口功能MoE 的 permute 计算根据索引indices将 tokens 广播并排序。这是 MoE 前向计算中“token 分发到专家”的经典一步路由层为每个 token 选出 topK 个专家indices记录专家 IDpermute 将这些 token 按专家 ID 排序后连续排列使得同一专家的 token 在内存上相邻从而被专家网络高效批量处理。扩展能力相比aclnnMoeTokenPermute本接口新增quantMode和expandedScaleOut。在 Ascend 950 平台上支持 MXFP8 和 MXFP4 量化输出即 permute 的同时完成浮点 token 到 MX 系列低比特格式的转换减少后续专家网络的数据搬移与计算开销。平台行为Ascend 950aclnnMoeTokenPermuteV2支持quantMode -1/2/3/9。非 Ascend 950量化参数静默忽略按非量化兼容路径处理。当paddedModefalse时算子核心计算公式为topK 指每个 token 选择的专家个数indices为 2D 时 topK 等于最后一维大小为 1D 时 topK 等于 1sortedIndicesFirst argSort(flatten(Indices)) sortedIndicesOut argSort(sortedIndicesFirst) permuteTokensOut[sortedIndicesOut[i]] tokens[i // topK]paddedModetrue填充模式暂不支持对应的语义是indices已被填充为代表每个专家选中的 token 索引此时不对indices排序。仓库中moe/moe_token_permute/tests/assets/golden.py的AclnnMoeTokenPermuteTestSpec.golden用 PyTorch 原语复现了这一算法可作为理解排序语义的参考sorted_row_idx torch.argsort(expert_idx.reshape(-1), dim-1, stableTrue) # 按专家ID稳定排序 expanded_row_idx torch.zeros_like(sorted_row_idx, dtypetorch.int32) expanded_row_idx[sorted_row_idx] torch.arange(sorted_row_idx.shape[0]) # 反排序索引 selected_indices sorted_row_idx[:active_num] // k # 每个位置对应的原token行 expanded_x input_x[selected_indices] # 按专家顺序重排token函数原型两段式接口与 CANN 算子库的通用约定一致每个算子分为两段式接口必须先调用aclnnMoeTokenPermuteV2GetWorkspaceSize获取计算所需 workspace 大小以及包含了算子计算流程的执行器再调用aclnnMoeTokenPermuteV2执行计算。aclnnStatus aclnnMoeTokenPermuteV2GetWorkspaceSize( const aclTensor *tokens, const aclTensor *indices, int64_t numOutTokens, bool paddedMode, int64_t quantMode, const aclTensor *permuteTokensOut, const aclTensor *sortedIndicesOut, const aclTensor *expandedScaleOut, uint64_t *workspaceSize, aclOpExecutor **executor)aclnnStatus aclnnMoeTokenPermuteV2( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)第一段接口完成参数校验、shape/workspace 计算并构建执行器第二段接口在指定 stream 上真正执行计算。头文件位于moe/moe_token_permute/op_host/op_api/aclnn_moe_token_permute_v2.h实现位于同目录的aclnn_moe_token_permute_v2.cpp。aclnnMoeTokenPermuteV2GetWorkspaceSize 参数详解参数名输入/输出描述使用说明数据类型数据格式维度tokens输入输入 token 特征。支持空 tensor要求维度等于 2第一维为num_tokens。Ascend 950 量化模式仅支持 FLOAT16、BFLOAT16。非量化FLOAT16、BFLOAT16、FLOAT32、INT8量化FLOAT16、BFLOAT16ND2indices输入输入 indices 索引。支持空 tensorshape 为 1D 或 2D。paddedModefalse时表示每个输入 token 对应的 topK 个专家索引。在 Ascend 950 上调用aclnnMoeTokenPermuteV2时元素表示 expert ID取值范围为[0, 10240)。INT32、INT64ND1 或 2numOutTokens输入有效输出 token 数。0表示不删除 token大于 0 时保留排序后的前numOutTokens个 token小于 0 时按负切片索引处理。---paddedMode输入是否为填充模式。当前不支持true建议固定为false。---quantMode输入量化模式。-1为非量化2为 MXFP8 E5M23为 MXFP8 E4M3FN9为 MXFP4 E2M1。非 Ascend 950 平台静默忽略量化参数。---permuteTokensOut输出根据 indices 扩展并排序后的 tokens。非量化时数据类型同tokensquantMode2/3/9时分别为 FLOAT8_E5M2、FLOAT8_E4M3FN、FLOAT4_E2M1。FLOAT16、BFLOAT16、FLOAT32、INT8、FLOAT8_E5M2、FLOAT8_E4M3FN、FLOAT4_E2M1ND≥2sortedIndicesOut输出permuteTokensOut和tokens的映射关系。1D Tensorshape 为[indices.numel()]。INT32ND1expandedScaleOut输出量化后的 per-token 分块 scale。量化场景必须提供有效输出非量化场景可传 shape 为[0]、dtype 为 FLOAT32 的空 Tensor。FLOAT8_E8M0、FLOAT32ND1、2 或 3workspaceSize输出返回需要在 Device 侧申请的 workspace 大小。----executor输出返回 op 执行器包含算子计算流程。----关于量化参数校验源码moe/moe_token_permute/op_host/op_api/aclnn_moe_token_permute_v2.cpp中定义了与文档完全一致的常量并给出了 dtype 匹配规则static constexpr int64_t QUANT_MODE_NONE -1; // 非量化 static constexpr int64_t QUANT_MODE_MXFP8_E5M2 2; // permuteTokensOut - DT_FLOAT8_E5M2 static constexpr int64_t QUANT_MODE_MXFP8_E4M3FN 3; // permuteTokensOut - DT_FLOAT8_E4M3FN static constexpr int64_t QUANT_MODE_MXFP4_E2M1 9; // permuteTokensOut - DT_FLOAT4_E2M1 static constexpr int64_t EXPERT_NUM 10240; // Ascend 950 上的 expert ID 取值范围在CheckDtypeValidV2Regbase中可以看到非量化模式下tokens与permuteTokensOut必须 dtype 相同且expandedScaleOut必须为DT_FLOAT量化模式下tokens仅允许 FLOAT16/BFLOAT16permuteTokensOut必须与quantMode对应的量化 dtype 匹配expandedScaleOut必须为DT_FLOAT8_E8M0。这些约束是调用时报ACLNN_ERR_PARAM_INVALID161002的主要来源。输出 Shape 推导先计算中间量flatten_size indices.numel() if numOutTokens 0: M min(numOutTokens, flatten_size) else: M max(numOutTokens flatten_size, 0) H tokens.shape[1]其中M即最终输出的有效 token 行数。各模式下三个输出的 shape 如下quantModepermuteTokensOut shapesortedIndicesOut shapeexpandedScaleOut shape-1[M, H][flatten_size][0]2[M, H][flatten_size][M, AlignUp(CeilDiv(H, 32), 2)]3[M, H][flatten_size][M, AlignUp(CeilDiv(H, 32), 2)]9[M, H / 2][flatten_size][M, CeilDiv(H, 64), 2]其中CeilDiv(a, b) (a b - 1) // b AlignUp(a, b) ((a b - 1) // b) * b几点解读quantMode9MXFP4 E2M1时每个元素打包两个 4bit 数值因此输出隐藏维为H / 2要求H为偶数。MXFP8 的 per-token scale 按 32 个元素一块_MX_QUANT_BLOCK_SIZE 32计算块数向上取整后还要对齐到偶数_PAD_TO_EVEN_FACTOR 2MXFP4 的 scale 按 64 个元素一块_MXFP4_SCALE_BLOCK_SIZE 64。这些推导逻辑在 PyTorch 封装侧moe/moe_token_permute/torch_extension/moe_token_permute.py的register_meta被完整复刻包括_align_up、_ceil_div辅助函数以及 dtype 选择torch.float8_e5m2/torch.float8_e4m3fn/torch.float8_e8m0fnu/torch.uint8等可以交叉印证。返回值与错误码aclnnStatus返回状态码具体参见 aclnn 返回码。常见错误场景返回值错误码描述ACLNN_ERR_PARAM_NULLPTR161001输入或输出 Tensor 为空指针。ACLNN_ERR_PARAM_INVALID161002输入、输出数据类型或quantMode不在支持范围内。ACLNN_ERR_INNER_TILING_ERROR561002shape 不满足算子约束或paddedModetrue。在源码aclnn_moe_token_permute_v2.cpp中第一段接口的CheckNotNull会对 5 个 tensor 参数逐一判空并返回ACLNN_ERR_PARAM_NULLPTRCheckShapeValid校验tokens维数必须为 2、indices维数必须为 1 或 2paddedModetrue在 regbase 路径直接返回ACLNN_ERR_PARAM_INVALID。约束说明indices要求元素个数小于16777215值大于等于0且小于16777215。在 Ascend 950 上调用aclnnMoeTokenPermuteV2时indices表示 expert ID取值范围为[0, 10240)最大值为10239不支持10240。不支持paddedModetrue。Ascend 950 量化模式下tokens当前支持 FLOAT16、BFLOAT16。quantMode9时tokens隐藏维H需要为偶数输出permuteTokensOut隐藏维为H / 2。非 Ascend 950 平台下quantMode2/3/9采用静默忽略策略实际按非量化兼容路径处理。Atlas A2 / A3 平台上topK 小于等于 512该约束在 tiling 源码中体现为MAX_INDICES_NUM 512的校验超出时报 tiling 错误。平台行为差异与底层实现路径从aclnn_moe_token_permute_v2.cpp的aclnnMoeTokenPermuteV2GetWorkspaceSize实现可以看出同一接口在不同平台上走了完全不同的执行路径非 regbase旧架构路径直接转发到aclnnInnerMoeTokenPermuteGetWorkspaceSize即 V1 的非量化实现。非 Ascend 950regbase路径CheckParamsV2Fallback校验通过后构造BuildMoeInitRoutingV2Executor将 permute 计算委托给MoeInitRoutingV2算子对应参数映射见moe/moe_token_permute/README.md量化参数在此路径上被静默忽略。Ascend 950regbase路径CheckParamsV2Regbase严格校验量化 dtype 后走PrepareIndicesForV3AllocIntermediateTensorsForV3CallMoeInitRoutingV3AndUnpack的组合PrepareIndicesForV3会先把indices转为连续内存若为 INT64 则Cast为 INT32若为 1D 则通过CreateView补成[N, 1]的 2D并算出fullTokenNum indices.numel()。中间 tensor 中expertTokensCount维度为EXPERT_NUM10240fullExpandedScale在量化模式下 dtype 为DT_FLOAT8_E8M0。最终通过SliceAndViewCopyl0op::Slicel0op::ViewCopy把中间结果裁剪到用户提供的输出 tensor 中quantMode ! -1时还会把 scale 一并拷贝到expandedScaleOut。这解释了文档中“非 Ascend 950 平台静默忽略量化参数”的底层原因V2 在这些平台上是基于 V2/V3 路由算子拼接出来的兼容实现并不真正执行量化。调用示例下面示例展示非量化调用quantMode-1量化调用时需要按quantMode调整permuteTokensOut和expandedScaleOut的数据类型及 shape。完整示例可参考 examples/test_aclnn_moe_token_permute.cpp。#include acl/acl.h #include aclnnop/aclnn_moe_token_permute_v2.h #include iostream #include vector #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) int64_t GetShapeSize(const std::vectorint64_t shape) { int64_t shapeSize 1; for (auto dim : shape) { shapeSize * dim; } return shapeSize; } int Init(int32_t deviceId, aclrtStream* stream) { auto ret aclInit(nullptr); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclInit failed. ERROR: %d\n, ret); return ret); ret aclrtSetDevice(deviceId); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSetDevice failed. ERROR: %d\n, ret); return ret); ret aclrtCreateStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtCreateStream failed. ERROR: %d\n, ret); return ret); return ACL_SUCCESS; } template typename T int CreateAclTensor(const std::vectorT hostData, const std::vectorint64_t shape, void** deviceAddr, aclDataType dataType, aclTensor** tensor) { auto size GetShapeSize(shape) * sizeof(T); *deviceAddr nullptr; if (size 0) { auto ret aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMalloc failed. ERROR: %d\n, ret); return ret); ret aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMemcpy failed. ERROR: %d\n, ret); return ret); } std::vectorint64_t strides(shape.size(), 1); for (int64_t i shape.size() - 2; i 0; i--) { strides[i] shape[i 1] * strides[i 1]; } *tensor aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return ACL_SUCCESS; } int main() { int32_t deviceId 0; aclrtStream stream; auto ret Init(deviceId, stream); CHECK_RET(ret ACL_SUCCESS, return ret); std::vectorint64_t xShape {3, 4}; std::vectorint64_t indicesShape {3, 2}; std::vectorint64_t expandedXOutShape {6, 4}; std::vectorint64_t sortedIndicesOutShape {6}; std::vectorint64_t expandedScaleOutShape {0}; void* xDeviceAddr nullptr; void* indicesDeviceAddr nullptr; void* expandedXOutDeviceAddr nullptr; void* sortedIndicesOutDeviceAddr nullptr; void* expandedScaleOutDeviceAddr nullptr; aclTensor* x nullptr; aclTensor* indices nullptr; aclTensor* expandedXOut nullptr; aclTensor* sortedIndicesOut nullptr; aclTensor* expandedScaleOut nullptr; std::vectorfloat xHostData { 0.1, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.2, 0.3, 0.3, 0.3, 0.3 }; std::vectorint32_t indicesHostData {1, 2, 0, 1, 0, 2}; std::vectorfloat expandedXOutHostData(24, 0); std::vectorint32_t sortedIndicesOutHostData(6, 0); std::vectorfloat expandedScaleOutHostData; ret CreateAclTensor(xHostData, xShape, xDeviceAddr, ACL_FLOAT, x); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(indicesHostData, indicesShape, indicesDeviceAddr, ACL_INT32, indices); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(expandedXOutHostData, expandedXOutShape, expandedXOutDeviceAddr, ACL_FLOAT, expandedXOut); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(sortedIndicesOutHostData, sortedIndicesOutShape, sortedIndicesOutDeviceAddr, ACL_INT32, sortedIndicesOut); CHECK_RET(ret ACL_SUCCESS, return ret); ret CreateAclTensor(expandedScaleOutHostData, expandedScaleOutShape, expandedScaleOutDeviceAddr, ACL_FLOAT, expandedScaleOut); CHECK_RET(ret ACL_SUCCESS, return ret); int64_t numOutTokens 0; bool paddedMode false; int64_t quantMode -1; uint64_t workspaceSize 0; aclOpExecutor* executor nullptr; ret aclnnMoeTokenPermuteV2GetWorkspaceSize( x, indices, numOutTokens, paddedMode, quantMode, expandedXOut, sortedIndicesOut, expandedScaleOut, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnMoeTokenPermuteV2GetWorkspaceSize failed. ERROR: %d\n, ret); return ret); void* workspaceAddr nullptr; if (workspaceSize 0) { ret aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(allocate workspace failed. ERROR: %d\n, ret); return ret); } ret aclnnMoeTokenPermuteV2(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnMoeTokenPermuteV2 failed. ERROR: %d\n, ret); return ret); ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); std::vectorfloat expandedXData(24, 0); ret aclrtMemcpy(expandedXData.data(), expandedXData.size() * sizeof(float), expandedXOutDeviceAddr, expandedXData.size() * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(copy expandedXOut failed. ERROR: %d\n, ret); return ret); std::vectorint32_t sortedIndicesData(6, 0); ret aclrtMemcpy(sortedIndicesData.data(), sortedIndicesData.size() * sizeof(int32_t), sortedIndicesOutDeviceAddr, sortedIndicesData.size() * sizeof(int32_t), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(copy sortedIndicesOut failed. ERROR: %d\n, ret); return ret); aclDestroyTensor(x); aclDestroyTensor(indices); aclDestroyTensor(expandedXOut); aclDestroyTensor(sortedIndicesOut); aclDestroyTensor(expandedScaleOut); aclrtFree(xDeviceAddr); aclrtFree(indicesDeviceAddr); aclrtFree(expandedXOutDeviceAddr); aclrtFree(sortedIndicesOutDeviceAddr); if (expandedScaleOutDeviceAddr ! nullptr) { aclrtFree(expandedScaleOutDeviceAddr); } if (workspaceAddr ! nullptr) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return ACL_SUCCESS; }示例中的关键点非量化场景下expandedScaleOut使用 shape[0]、dtypeACL_FLOAT的空 tensor 占位CreateAclTensor对 size 为 0 的场景跳过aclrtMalloc。输出 shape 依据上一节公式计算flatten_size 3 * 2 6numOutTokens 0时M 6因此expandedXOutShape {6, 4}、sortedIndicesOutShape {6}。量化调用时需按quantMode把expandedXOut的 dtype 改为对应的 FLOAT8/FLOAT4 类型并把expandedScaleOut的 shape 与 dtype 改为量化要求[M, AlignUp(CeilDiv(H,32),2)]或[M, CeilDiv(H,64), 2]dtype 为ACL_FLOAT8_E8M0。PyTorch API 封装除 aclnn 接口外仓库还提供了 PyTorch 扩展封装见 torch_extension/moe_token_permute.py其 schema 为moe_token_permute(Tensor tokens, Tensor indices, int? num_out_tokensNone, bool padded_modeFalse, int quant_mode-1) - (Tensor, Tensor, Tensor)调用示例构建在 torch_npu 的 PrivateUse1 后端起效from cann_ops_transformer.moe_token_permute import moe_token_permute permuted_tokens, sorted_indices, expanded_scale moe_token_permute( tokens, indices, num_out_tokens0, padded_modeFalse, quant_mode-1 )该封装在register_meta中完整实现了与本文一致的 shape/dtype 推导方便在 eager 模式与编译模式下提前获得输出元信息校验tokens.dim() 2、indices.dim() in (1, 2)、quant_mode in (-1, 2, 3, 9)quant_mode 9时校验hidden_size % 2 0非量化返回(M, H)的permuted_tokens、(numel,)的 int32sorted_indices、(0,)的 float32expanded_scale量化返回对应 dtype 的量化 token 与 scale 输出。算子 host 端实现细节Shape 推导InferShapemoe/moe_token_permute/op_host/moe_token_permute_infershape.cpp实现了图编译期的 shape 推导sortedIndicesOut固定为 1D长度为topK * Nindices为 1D 时topK 1为 2D 时topK indices.shape[1]。permuteTokensOut首维按numOutTokens裁剪先按numOutTokens 0时加上sortedIndicesLen再min到sortedIndicesLen、max到 0。输出 0 的数据类型继承tokens输出 1 固定为DT_INT32。Tiling 与 Workspacemoe/moe_token_permute/op_host/moe_token_permute_tiling.cpp负责运行时切分策略排序阶段按totalLength即indices.numel()与单核可容纳元素数sortLoopMaxElement比较选择SORT_ONE_CORE_MODE1 核或SORT_MULTI_CORE_MODE多核核数为 4 的幂次且不超过物理 AIV 核数多核模式还会在needCoreNum 4时插入中间归并阶段Tiling4VMSMiddleCompute。numOutTokens ! totalLength时追加ENABLE_NUMOUTTOKENS标志位隐藏维单 token 过大放不进 UB 时追加SPILT_D_MODE走 split-D 搬移策略。workspace 由三部分组成排序所需空间totalLength * 2 * 3个 float、多核同步空间coreNum * 32 * 2、以及 16KB 的固定缓冲16 * 1024 * 1024。涉及核间同步的算子通过context_-SetScheduleMode(1)设置为独占全核调度。Kernelmoe/moe_token_permute/op_kernel/目录下按功能拆分了多份头文件moe_index_copy.htoken 索引拷贝、moe_mrgsort_token_permute.h/moe_mrgsort_out_token_permute.h多路归并排序、moe_sort_base_token_permute.h/moe_sort_multi_core_token_permute.h/moe_sort_one_core_token_permute.h排序基类与单/多核实现、moe_index_copy_spilt_d.hsplit-D 模式的拷贝核函数入口在moe_token_permute.cpp公共类型定义与 tiling 数据结构在moe_token_permute_common.h。与 V1 接口的对比与选型建议对比项aclnnMoeTokenPermuteV1aclnnMoeTokenPermuteV2V2量化支持无tokens为 INT8 时按非量化方式处理支持quantMode2/3/9Ascend 950 上输出 MXFP8/MXFP4 量化结果新增参数-quantMode、expandedScaleOut非量化路径直接实现非 950 平台兼容委托给MoeInitRoutingV2950 平台委托给MoeInitRoutingV3使用场景无量化需求的 MoE permute需要量化感知、在 Ascend 950 上追求低比特数据流的 MoE permute若你的模型在 Ascend 950 上运行且后续专家网络已支持 MX 格式输入建议优先使用 V2 的量化模式将 permute 与量化合二为一若运行在 Atlas A2/A3 平台V2 与 V1 行为等价量化被静默忽略可任选其一。更多相关接口可参阅同目录的 aclnnMoeTokenPermute 文档 与 torch API 文档以及 MoE 路由链路中的 aclnnMoeInitRoutingV2 接口。【免费下载链接】ops-transformer本项目是CANN提供的transformer类大模型算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-transformer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表