ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CANN ops-transformer aclnnInplaceFfnWorkerScheduler 算子深度解析:Attention/FFN 分离场景下的 FFN 侧数据扫描与调度

CANN ops-transformer aclnnInplaceFfnWorkerScheduler 算子深度解析:Attention/FFN 分离场景下的 FFN 侧数据扫描与调度 算子库人工智能深度学习Ascend【免费下载链接】ops-transformer本项目是CANN提供的transformer类大模型算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-transformer点击查看免费下载导读aclnnInplaceFfnWorkerScheduler是 CANN ops-transformer 算子库中用于Attention 与 FFN 分离部署场景的 FFN 侧数据扫描算子它轮询 AttentionToFFN 算子写入的token_info_buf在通信数据就绪后完成 layer id、session id、micro batch id、expert ids 的数据整理供下游 FFNWorkerBatching 算子直接消费。本文以 aclnnInplaceFfnWorkerScheduler 接口文档 为骨架结合本仓库中该算子的算子原型注册、ACLNN 封装、AICPU 内核实现与单元测试源码系统讲解其适用场景、ScheduleContext内存结构、同步分组调度原理、两段式接口用法、参数约束与完整调用示例帮助你快速理解并上手该算子。一、算子定位与产品支持情况1.1 功能定位分离场景下的 FFN 侧数据看门人在 MoEMixture of Experts类大模型训练中Attention 与 FFNMoE 层往往被拆分到不同设备/进程上并行执行。FfnWorkerScheduler正是这一架构下FFN 侧的数据扫描算子接收AttentionToFFN算子通过通信链路发送过来的数据该数据以ScheduleContext结构体的内存排布方式存储在 Device 侧扫描其中token_info_buf记录的 readiness 状态当通信数据按 session 或同步组粒度准备就绪后执行数据整理把layer id、session id、micro batch id、expert ids分别写入layer_ids_buf、session_ids_buf、micro_batch_ids_buf、expert_ids_buf整理完成后后续FFNWorkerBatching算子即可直接消费这些规整后的数据。文档明确提示不建议直接使用需要与 AttentionToFFN、FFNWorkerBatching 配合使用。也就是说本算子是Attention 与 FFN 分离这条数据流水线中的中间调度环节单独调用没有实际意义。仓库中同族配套算子可参考 attention/attention_to_ffnAttention 侧发送端与 ffn/ffn_worker_batchingFFN 侧消费端。1.2 产品支持情况以 接口文档 为准本算子在以下产品形态上的支持情况如下产品是否支持Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品不支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品不支持Atlas 训练系列产品不支持注意算子目录下的 README.md 中产品支持表格与接口文档存在差异README 将 Atlas A2、Atlas 推理/训练系列标记为支持。实际接入时应以接口文档及随 CANN 版本发布的产品支持矩阵为准本文按接口文档记载进行说明。二、ScheduleContext算子的内存协议本算子没有常规意义上的多维张量输入其输入是一个1 维、shape 为(1024)、数据类型INT8、格式ND的 aclTensor按ScheduleContext结构体的内存排布方式承载全部配置与缓冲区信息。2.1 结构体域划分从文档的调用示例可以完整还原该结构体定义它由四个核心域加一段保留区组成并使用#pragma pack(push, 1)紧凑打包、static_assert保证总大小恒为 1024 字节域作用CommonArea存储配置信息session_num、micro_batch_num、micro_batch_size、selected_expert_num、expert_num、attn_to_ffn_token_size、ffn_to_attn_token_size、schedule_mode等ControlArea上层控制进程是否退出run_flag0 退出1 运行中AttentionAreaAttention 侧窗口缓冲区token_info_buf、token_data_buf及最新就绪的micro_batch_idFfnAreaFFN 侧输入输出缓冲区管理token_info_buf本算子输入、token_data_buf、polling_index全同步模式下内部待处理的 micro batch id 记录以及输出侧的layer_ids_buf、session_ids_buf、micro_batch_ids_buf、expert_ids_buf及其 size 字段、已处理 session 数out_num各关键字段的内存含义与接口文档调用示例中的代码一致CommonArea.session_numAttention 节点数量即待处理的最大会话数CommonArea.micro_batch_num / micro_batch_sizemicro batch 数量与大小CommonArea.selected_expert_num每个 token 选择的 expert 个数CommonArea.expert_num每层 expert 总数含路由 expert 与共享 expertCommonArea.schedule_mode0 表示 FFN only1 表示 Attention onlyCommonArea.attn_to_ffn_token_size / ffn_to_attn_token_sizeFFN 窗口数据区 / Attention 窗口数据区中每个 token 按 512 字节对齐后的空间大小ControlArea.run_flag0 表示已退出1 表示运行中——这是 AICPU 内核轮询循环的退出条件FfnArea.token_info_buf指向 Device 内存存放本算子的输入FfnDataDesc描述符数组FfnArea.polling_index仅全同步计算时使用记录 scheduler 内部待处理的 micro batch idFfnArea.out_num已处理的 session 数输出统计。2.2 输入描述符 FfnDataDesctoken_info_buf内部按FfnDataDesc描述符组织每个描述符对应一个 (session, micro batch) 单元#pragma pack(push, 1) struct FfnDataDesc { volatile int32_t flag; // 数据就绪标志1 有效0x7F 附近为无效重置值 volatile int32_t layer_id; // 该 session 的 layer id volatile int32_t expert_ids[0]; // 柔性数组selected_expert_num * micro_batch_size 个 expert id };flag使用volatile修饰正是为了跨进程/跨设备读取 AttentionToFFN 侧写入的就绪状态内核处理完一个描述符后会将其flag重置为无效值并清零 expert idsmemset_s填充0x7F从而支持流水线复用。2.3 缓冲区尺寸计算公式文档调用示例中的CalcFfnTokenInfoSize给出了token_info_buf的精确尺寸token_info_size (sizeof(FfnDataDesc) selected_expert_num * micro_batch_size * sizeof(int32_t)) * micro_batch_num * session_num各输出缓冲区尺寸与 AICPU 内核校验逻辑一致layer_ids_buf_size session_num * sizeof(int32_t) session_ids_buf_size session_num * sizeof(int32_t) micro_batch_ids_buf_size session_num * sizeof(int32_t) expert_ids_buf_size session_num * micro_batch_size * selected_expert_num * sizeof(int32_t)三、调度原理与计算公式3.1 分组同步模型本算子的核心设计是以同步组为单位的数据就绪判定。初始化阶段根据入参ScheduleContext.common.session_num与sync_group_size计算分组个数$$ \text{group_num} \frac{\text{session_num}}{\text{sync_group_size}} $$处理流程按分组个数分两种模式$$ \text{Process} \begin{cases} \text{check_all_session_ready()} \rightarrow \text{data_reorganization()} \text{if } \text{group_num} 1 \ \text{check_all_sessions_of_group_ready()} \rightarrow \text{data_reorganization()} \text{otherwise} \end{cases} $$group_num 1全同步所有 session 的数据必须全部就绪后才开始整理对应源码中的DoComputeAllSyncgroup_num 1分组同步只要某个 group 内的 session 数据全部就绪即可对该 group 执行整理实现部分就绪、部分处理的流水式调度对应源码中的DoCompute。3.2 内核实现源码级验证AICPU 内核实现 完整印证了上述模型就绪判定CheckSessionsReady从token_info_buf_ micro_batch_id * per_ffn_data_desc_size_出发按 session 步长per_ffn_data_desc_size_ * micro_batch_num_遍历区间内每个 session 的flag只要有一个flag ! kValidFlag即返回未就绪轮询等待DoCompute外层while (schedule_context_-control.run_flag ! 0)循环中调用CheckHasReadyGroup()未就绪时执行sched_yield()让出 CPU避免忙等空转一旦run_flag 0上层控制进程通知退出内核立即返回KERNEL_STATUS_OK分组处理CheckHandleSessions/ToOutput按group_id * sync_group_size_定位每组 session 区间找到就绪的 micro batch 后通过CpuKernelUtils::ParallelFor并行执行CopyAndResetSessions把layer_id、session id、micro batch id 写入三个一维输出缓冲把 expert ids 按[session_num, micro_batch_size, selected_expert_num]的排布拷入expert_ids_buf处理完成后递增out_num并重置 flag全同步模式DoComputeAllSync按polling_index指定的 micro batch 检查全部 session就绪即整理并推进polling_index (polling_index 1) % micro_batch_num_每次调用只处理一个 batch。3.3 数据整理流向图文档给出了 token_info_buf 输入经整理后写入四个输出缓冲区的数据流示意将文档 mermaid 图以文字形式复述关键路径每个 session 内的数据单元包含micro batch id、layer id、session id、expert ids四类信息整理后按 session 顺序分别落盘到layer_ids_buf、session_ids_buf、micro_batch_ids_buf、expert_ids_buf输出缓冲的数组大小为session_numexpert 缓冲维度为[session_num, batch_size, selected_expert_num]从而把以 session 为单位的交错存储转换为按字段分列的规整存储便于FFNWorkerBatching按列批量消费。四、函数原型与两段式调用4.1 两段式接口该算子遵循 CANN 两段式接口规范参见 两段式接口说明必须先调用aclnnInplaceFfnWorkerSchedulerGetWorkspaceSize获取 workspace 大小与执行器再调用aclnnInplaceFfnWorkerScheduler真正执行。aclnnStatus aclnnInplaceFfnWorkerSchedulerGetWorkspaceSize( aclTensor* scheduleContextRef, // 输入/输出ScheduleContext 信息INT81维(1024)ND int32_t syncGroupSize, // 输入每个同步组处理的 session 个数 int32_t executeMode, // 输入执行模式只支持 0 uint64_t* workspaceSize, // 输出Device 侧需申请的 workspace 大小 aclOpExecutor** executor) // 输出算子执行器aclnnStatus aclnnInplaceFfnWorkerScheduler( void* workspace, // 输入Device 侧 workspace 内存地址 uint64_t workspaceSize, // 输入第一段接口返回的 workspace 大小 aclOpExecutor* executor, // 输入算子执行器 aclrtStream stream) // 输入执行任务的 Stream4.2 参数说明aclnnInplaceFfnWorkerSchedulerGetWorkspaceSize参数明细参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续 TensorscheduleContextRef输入/输出FFN 侧接收的待处理数据表示 ScheduleContext 信息不支持空 tensorINT8ND1维(1024)×syncGroupSize输入每个同步组处理的 session 个数取值范围为(0, session_num]session_num即 ScheduleContext 中 CommonArea 域的session_num字段INT32---executeMode输入执行模式只支持模式 0表示执行完一次退出INT32---workspaceSize输出返回需要在 Device 侧申请的 workspace 大小-----executor输出返回 op 执行器包含算子计算流程-----aclnnInplaceFfnWorkerScheduler参数明细参数名输入/输出描述workspace输入Device 侧申请的 workspace 内存地址workspaceSize输入Device 侧申请的 workspace 大小由第一段接口获取executor输入op 执行器包含算子计算流程stream输入指定执行任务的 Stream4.3 返回值与错误码两段接口均返回aclnnStatus状态码具体参见 aclnn 返回码说明。第一段接口完成入参校验以下场景报错返回值错误码描述ACLNN_ERR_PARAM_NULLPTR161001参数scheduleContextRef是空指针ACLNN_ERR_PARAM_INVALID161002参数scheduleContextRef维度不为 1ACLNN_ERR_PARAM_INVALID161002参数scheduleContextRef是空 tensorACLNN_ERR_PARAM_INVALID161002参数executeMode非 0ACLNN 封装层 aclnn_ffn_worker_scheduler.cpp 中的CheckParams与上述约束一一对应校验 shape 必须是 1 维、executeMode kExecuteModeOnce(0)并对空 tensor 显式报ACLNN_ERR_PARAM_INVALID。4.4 约束说明aclnnInplaceFfnWorkerScheduler默认为确定性实现暂不支持非确定性实现确定性计算配置不会生效AICPU 内核侧还有更细粒度的入参校验schedule_mode必须为 0FFN only、session_num / micro_batch_num / micro_batch_size / selected_expert_num均必须大于 0、sync_group_size必须在[1, session_num]且要求session_num % sync_group_size 0必须整除、polling_index必须小于micro_batch_num详见 ffn_worker_scheduler_aicpu.cpp。五、算子注册与 Shape 推导5.1 算子原型注册算子原型 通过REG_OP注册定义如下输入schedule_contextDT_INT81 维(1024)ND 格式输出schedule_context与输入同 shape、同 dtype、同 formatin-place 更新语义属性sync_group_sizeInt默认 1每个同步组处理的 session 个数属性execute_modeInt默认 0内核执行模式目前仅支持 0执行一次退出注释中预留了 1 表示 loop 的扩展位。5.2 Shape/DataType 推导infershape 实现 中InferShape复用Ops::Base::InferShape4Elewise输出 shape 与输入一致InferDtype4FfnWorkerScheduler直接将输入 dtype 透传给输出。对应的 infershape 单元测试 验证了输入输出 shape 均为{1024}、dtype 均为DT_INT8。六、完整调用示例文档提供了可直接参考的完整示例代码仓库中的 examples/test_aclnn_inplace_ffn_worker_scheduler.cpp 为同源实现整体流程如下6.1 代码框架#include iostream #include memory #include vector #include limits #include acl/acl.h #include aclnnop/aclnn_ffn_worker_scheduler.h #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 i : shape) { shapeSize * i; } 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 0; } 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); auto ret aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); // 申请 device 内存 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 stride(shape.size(), 1); // 连续 tensor 的 stride for (int64_t i shape.size() - 2; i 0; i--) { stride[i] shape[i 1] * stride[i 1]; } *tensor aclCreateTensor(shape.data(), shape.size(), dataType, stride.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; }6.2 ScheduleContext 与缓冲区初始化示例中通过InitFfn完成输入/输出缓冲区的申请与填充按第二节公式计算token_info_buf_size用aclrtMalloc申请token_info_buf、token_data_buf示例中固定 1024 字节以及四个输出缓冲InitFfnTokenInfoBuf在 host 侧构造完整数据对每个 session 与每个 micro batch写入flag 1、layer_id 55再写入micro_batch_size * selected_expert_num个连续递增的expert_id最后aclrtMemcpy拷贝到 device 侧token_info_buf用aclrtFreeUninitFfn对称释放全部缓冲区。示例中的典型配置session_num2、micro_batch_num2、micro_batch_size2、selected_expert_num5constexpr uint32_t kSuccess 0; constexpr uint32_t kFailure 1; constexpr uint64_t kBufAlignSize 512; inline uint64_t AlignUp(uint64_t num, uint64_t align) { return ((num align - 1) / align) * align; } // ...FfnDataDesc、ScheduleContext 结构体定义见第二节此处省略 uint64_t CalcFfnTokenInfoSize(ScheduleContext schedule_context) { // token_info_size (sizeof(FfnDataDesc) selected_expert_num * micro_batch_size) * micro_batch_num * session_num uint64_t flag_and_layer_id_size sizeof(FfnDataDesc); uint64_t token_info_size (sizeof(int32_t) * static_castuint64_t(schedule_context.common.selected_expert_num) * schedule_context.common.micro_batch_size flag_and_layer_id_size) * static_castuint64_t(schedule_context.common.micro_batch_num) * static_castuint64_t(schedule_context.common.session_num); return token_info_size; } uint32_t InitFfn(ScheduleContext schedule_context) { uint64_t token_info_size CalcFfnTokenInfoSize(schedule_context); if (token_info_size 0U) { return ACL_ERROR_INVALID_PARAM; } uint64_t token_info_aligned_size AlignUp(token_info_size, kBufAlignSize); schedule_context.ffn.token_info_buf_size token_info_size; schedule_context.ffn.token_data_buf_size 1024; // ... 依次 aclrtMalloc token_info_buf / token_data_buf / layer_ids_buf / // session_ids_buf / micro_batch_ids_buf / expert_ids_buf 并记录到结构体 // 输出缓冲尺寸 // layer_ids_buf_size session_num * sizeof(int32_t) // session_ids_buf_size session_num * sizeof(int32_t) // micro_batch_ids_buf_size session_num * sizeof(int32_t) // expert_ids_buf_size session_num * micro_batch_size * selected_expert_num * sizeof(int32_t) return ACL_SUCCESS; }6.3 两段式调用与结果读取int main() { // 1. device/stream 初始化 int32_t deviceId 0; aclrtStream stream; auto ret Init(deviceId, stream); CHECK_RET(ret 0, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); // 2. 构造输入ScheduleContext 填入 host 数据后拷贝到 device std::vectorint64_t selfShape {1024}; void* selfDeviceAddr nullptr; aclTensor* scheduleContextRef nullptr; std::vectorint8_t selfHostData(1024); ScheduleContext schedule_context {}; schedule_context.common.session_num 2; schedule_context.common.micro_batch_num 2; schedule_context.common.micro_batch_size 2; schedule_context.common.selected_expert_num 5; schedule_context.control.run_flag 1; schedule_context.common.schedule_mode 0; schedule_context.ffn.polling_index 1; InitFfn(schedule_context); ret aclrtMemcpy(selfHostData.data(), sizeof(ScheduleContext), schedule_context, sizeof(ScheduleContext), ACL_MEMCPY_HOST_TO_HOST); if (ret ! ACL_SUCCESS) { UninitFfn(schedule_context); return ret; } int32_t syncGroupSize 1; // 同步组大小取值范围 (0, session_num] int32_t executeMode 0; // 执行模式只支持 0 ret CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_INT8, scheduleContextRef); CHECK_RET(ret ACL_SUCCESS, return ret); // 3. 两段式调用 CANN 算子库 API uint64_t workspaceSize 0; aclOpExecutor* executor; ret aclnnInplaceFfnWorkerSchedulerGetWorkspaceSize(scheduleContextRef, syncGroupSize, executeMode, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(GetWorkspaceSize 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 aclnnInplaceFfnWorkerScheduler(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnInplaceFfnWorkerScheduler failed. ERROR: %d\n, ret); return ret); // 4. 同步等待任务执行结束 ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); // 5. 将 device 结果拷回 host解析输出缓冲 std::vectorint8_t resultData(1024, 0); ret aclrtMemcpy(resultData.data(), resultData.size() * sizeof(int8_t), selfDeviceAddr, 1024, ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, return ret); ScheduleContext* out_schedule_context reinterpret_castScheduleContext*(resultData.data()); LOG_PRINT(layer_ids_buf_size %lu.\n, out_schedule_context-ffn.layer_ids_buf_size); LOG_PRINT(session_ids_buf_size %lu.\n, out_schedule_context-ffn.session_ids_buf_size); LOG_PRINT(micro_batch_ids_buf_size %lu.\n, out_schedule_context-ffn.micro_batch_ids_buf_size); LOG_PRINT(expert_ids_buf_size %lu.\n, out_schedule_context-ffn.expert_ids_buf_size); // 逐个打印 layer_ids / session_ids / micro_batch_ids / expert_ids 数组内容以 layer_ids 为例 std::vectorint32_t layer_ids_buf(out_schedule_context-ffn.layer_ids_buf_size / sizeof(int32_t), 0); ret aclrtMemcpy(layer_ids_buf.data(), out_schedule_context-ffn.layer_ids_buf_size, reinterpret_castvoid*(static_castuintptr_t(out_schedule_context-ffn.layer_ids_buf)), out_schedule_context-ffn.layer_ids_buf_size, ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, return ret); for (int i 0; i out_schedule_context-ffn.layer_ids_buf_size / sizeof(int32_t); i) { LOG_PRINT(layer_ids[%d] is: %d\n, i, layer_ids_buf[i]); } // ... 同样的方式打印 session_ids、micro_batch_ids、expert_ids // 6. 释放 aclTensor aclDestroyTensor(scheduleContextRef); // 7. 释放 device 资源 UninitFfn(schedule_context); aclrtFree(selfDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }6.4 结果预期在示例配置session_num2、sync_group_size1、全量数据 flag 已置 1下算子执行后layer_ids_buf、session_ids_buf、micro_batch_ids_buf各有 2 个元素session 数expert_ids_buf有2 × 2 × 5 20个元素layer_ids全部为 55示例写入值session_ids为 0、1micro_batch_ids为对应已就绪的 micro batch id原token_info_buf中已处理描述符的flag被重置为无效值out_num累加为已处理 session 数。关于编译与运行完整代码可参考 examples/test_aclnn_inplace_ffn_worker_scheduler.cpp编译与执行过程请遵循 编译与运行样例 的通用流程并在实际工程中结合自身 deviceId 与调度配置调整参数。七、单元测试对行为的验证仓库中的 AICPU 内核单元测试 覆盖了本文所述的绝大多数行为分支可作为理解算子语义的补充证据测试用例验证点INPUT_COMPUTE_ALL_SYNC_SUCCESSsync_group_size 2等于 session_numgroup_num1时走全同步路径输出四个缓冲并成功返回INPUT_COMPUTE_SUCCESSsync_group_size 1group_num2时走分组同步路径输出成功INPUT_SCHEDULE_MODE_INVALIDschedule_mode 1非 FFN only时报KERNEL_STATUS_PARAM_INVALIDINPUT_EXCUTE_MODE_INVALIDexecute_mode 2非 0时报KERNEL_STATUS_PARAM_INVALIDINPUT_DIM_INVALID输入 shape 为{1024, 2}非 1 维时报参数无效INPUT_CONTROL_RUN_TERMINALrun_flag 0时内核直接退出并返回 OK其中 AICPU 测试的InitFfn还在token_data_buf_size计算上与接口文档示例略有差异测试用1024 - token_info_aligned_size说明该字段在算例内部不做强校验仅作为缓冲区描述信息。八、常见问题与注意事项必须与其他算子协同使用单独调用本算子无实际意义需要 AttentionToFFN发送端、FFNWorkerBatching消费端配合组成完整流水线。sync_group_size必须能整除session_num内核校验session_num % sync_group_size 0否则报参数无效取值需在(0, session_num]区间。executeMode仅支持 0接口层CheckParams与内核属性校验双重把关传入非 0 值会返回ACLNN_ERR_PARAM_INVALID161002。ScheduleContext 布局敏感输入 tensor 按#pragma pack(1)紧凑排布的 1024 字节结构体解析填充初始化时必须保证各域偏移与结构体定义一致不可自行调整字段顺序。确定性实现算子当前只有确定性实现确定性计算配置项不生效无需也无法切换非确定性路径。轮询开销内核就绪判定采用sched_yield()让出式轮询适合数据到达有明显延迟的分离式部署上层可通过ControlArea.run_flag平滑终止内核避免长驻线程无法退出。总结aclnnInplaceFfnWorkerScheduler是 CANN ops-transformer 在 Attention/FFN 分离部署架构下打通通信就绪感知—数据整理—下游消费的关键调度算子。理解其ScheduleContext内存协议、group_num分组同步模型与两段式接口用法是正确接入 AttentionToFFN → FfnWorkerScheduler → FFNWorkerBatching 流水线的第一步。读者可结合 接口文档、ACLNN 封装、AICPU 内核 与 单元测试 继续深入研读。赞分享算子库人工智能深度学习Ascend【免费下载链接】ops-transformer本项目是CANN提供的transformer类大模型算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-transformer点击查看免费下载相关推荐CANN ops-transformer 的 FfnWorkerScheduler 算子Attention/FFN 分离场景下的 FFN 侧数据扫描与整理机制CANN ops transformer 的 FfnWorkerScheduler 算子Attention/FFN 分离场景下的 FFN 侧数据扫描与整理机制算子库人工智能深度学习AscendCANN ops-transformer AttentionWorkerScheduler 算子全解析Attention/FFN 分离部署下的数据就绪扫描与调度同步CANN ops transformer AttentionWorkerScheduler 算子全解析Attention/FFN 分离部署下的数据就绪扫描与调算子库人工智能深度学习AscendCANN ops-transformer FfnWorkerBatching 算子Attention/FFN 分离部署下 MoE 场景的 token 按专家重排CANN ops transformer FfnWorkerBatching 算子Attention/FFN 分离部署下 MoE 场景的 token 按专家重算子库人工智能深度学习Ascend上一篇突破2D边界stable-diffusion-webui 3D生成全攻略下一篇rrweb canvas-webrtc-record 插件变更日志解读跨域画布流默认拦截策略与版本演进创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表