AMCT amct_ops:昇腾 NPU 自定义算子包 amct_ops 的构建、接口与扩展指南
2026/9/18 6:08:26 网站建设 项目流程

AMCT amct_ops:昇腾 NPU 自定义算子包 amct_ops 的构建、接口与扩展指南

【免费下载链接】amctAMCT是CANN提供的昇腾AI处理器亲和的模型压缩工具仓。项目地址: https://gitcode.com/cann/amct

amct_ops是 AMCT 仓库中面向昇腾 NPU 的自定义算子层,承载 PyTorch /torch_npu尚未覆盖的低比特数据类型转换、量化辅助算子等硬件级实现。本文围绕 amct_ops/README_en.md 展开,说明它在 AMCT 中与amct_pytorch/的分工、支持的算子接口、wheel 构建流程、依赖约束、使用方式,以及新增算子时应遵循的目录结构和命名空间约束。

读完本文,你可以:

  • 理解amct_ops作为独立 PyTorch 扩展包的定位:它提供可独立安装、可复用的 NPU 算子.so与 Python 接口;
  • 掌握ops_build.sh的构建参数、平台选择、产物路径与安装方式;
  • 理解torch.ops.amct.<op>from amct_ops.<pkg> import <op>两类接口的底层注册关系;
  • 了解新增算子时的目录布局、自动打包机制与amct命名空间约束。

1. amct_ops 在 AMCT 中的定位

amct_ops/README_en.md 将amct_ops定义为 AMCT 的 NPU 自定义算子层。它的核心职责是实现 PyTorch /torch_npu尚未覆盖的硬件级算子,例如低比特量化、数据类型转换等。与amct_pytorch/相比,amct_ops更贴近底层硬件实现,而不是压缩算法和流程编排层。

从仓库结构看,amct_pytorch/主要承载 Python 算法、压缩流程、校准、量化模块、部署与评估等上层能力;而amct_ops/则按算子拆分子目录,每个算子通常包含 Ascend C kernel、C++ 扩展绑定、Python 接口和独立 CMake 编译入口。这种分层让上层算法可以通过 Python 接口或torch.ops.amct调用算子,而无需直接关注 Ascend C kernel、C++ extension 和 CMake 编译细节。

2. amct_pytorch 与 amct_ops 的分工

amct_ops/README_en.md 给出的分工如下:

维度amct_pytorch/amct_ops/
关注点压缩算法与流程编排算子底层实现
语言PythonAscend C kernel、C++ binding、Python 接口
产物.tar.gz源码压缩包wheel 包,包含.so与 Python 接口
复用性绑定 AMCT 流程独立 PyTorch 扩展,不强依赖 AMCT 主流程

这组分工体现了“算法层与算子层解耦”的设计:amct_pytorch/负责把模型压缩、量化、校准、评估等流程组织起来;amct_ops/负责提供真正落在 NPU 上执行的底层算子。对使用者来说,这种解耦有两个直接好处。

第一,Python 算法代码不需要暴露底层实现细节。上层模块可以通过稳定的 Python 函数或torch.ops.amct命名空间调用算子,不必知道 Ascend C tiling、kernel 编译或 CMake 配置。

第二,算子可以按模块独立开发、构建和测试。新增低比特类型、量化辅助算子或调整 NPU 实现时,只要遵循算子目录约定,就可以被统一构建脚本自动发现并打包,而不会干扰主算法目录。

3. 支持的算子与 Python 接口

amct_ops/README_en.md 当前列出的核心算子如下:

算子说明Python 接口
hifloat8_castFP16 / BF16 与 HiFloat8 双向转换encode_to_hifloat8(x)decode_from_hifloat8(x, dtype)
hifloat4_castFP16 / BF16 到 HiFloat4 的 fake-quant 仿真,使用 64 元素块缩放hifloat4_fake_quant(x, qdim=-1)

3.1 hifloat8_cast:FP16/BF16 与 HiFloat8 双向转换

hifloat8_cast提供两组接口:

from amct_ops.hifloat8_cast import encode_to_hifloat8, decode_from_hifloat8 y = encode_to_hifloat8(x) # FP16/BF16 → uint8 z = decode_from_hifloat8(y) # uint8 → bfloat16(默认) z = decode_from_hifloat8(y, torch.float16) # uint8 → float16

从 amct_ops/hifloat8_cast/python/hifloat8_cast/ops.py 可以看到,这两个 Python 函数最终都转发到torch.ops.amct.encode_to_hifloat8torch.ops.amct.decode_from_hifloat8。因此模块导入方式和torch.ops方式只是调用入口不同,底层注册的是同一组算子。

在 C++ 侧,amct_ops/hifloat8_cast/op_extension/register.cpp 中定义了算子 schema:

TORCH_LIBRARY_FRAGMENT(amct, m) { m.def("encode_to_hifloat8(Tensor input) -> Tensor"); m.def("decode_from_hifloat8(Tensor input, ScalarType? dtype=None) -> Tensor"); }

并注册了PrivateUse1后端实现与Meta后端实现:

TORCH_LIBRARY_IMPL(amct, PrivateUse1, m) { m.impl("encode_to_hifloat8", TORCH_FN(EncodeImpl)); m.impl("decode_from_hifloat8", TORCH_FN(DecodeImpl)); } TORCH_LIBRARY_IMPL(amct, Meta, m) { m.impl("encode_to_hifloat8", &EncodeMeta); m.impl("decode_from_hifloat8", &DecodeMeta); }

其中PrivateUse1torch_npu使用的后端命名空间,Meta实现只根据输入 shape 返回对应 dtype 的空张量,用于 shape 推导和符号执行场景。

具体校验逻辑也可以从源码中确认:encode_to_hifloat8要求输入为float16bfloat16decode_from_hifloat8要求输入为uint8,输出 dtype 只能是float16bfloat16,默认输出bfloat16

3.2 hifloat4_cast:HiFloat4 fake-quant 仿真

hifloat4_cast提供 HiFloat4 fake-quant 仿真接口:

from amct_ops.hifloat4_cast import hifloat4_fake_quant y = hifloat4_fake_quant(x) # FP16/BF16 → HiF4 → FP16/BF16 y = hifloat4_fake_quant(x, qdim=-1) # 指定量化维度

amct_ops/hifloat4_cast/python/hifloat4_cast/init.py 的文档说明该算子注册为torch.ops.amct.hifloat4_fake_quant,并暴露为模块级函数hifloat4_fake_quant(x, qdim=-1)。从接口语义看,它模拟的是 FP16/BF16 输入经过 HiFloat4 量化路径后再回到 FP16/BF16 的过程,适合用于低比特格式精度评估、算法仿真或部署前行为验证。

4. 目录结构与构建入口

amct_ops/README_en.md 给出的目录结构如下:

amct_ops/ ├── hifloat8_cast/ # HiFloat8 conversion operator source code (kernel + binding + Python interface) ├── hifloat4_cast/ # HiFloat4 FP→HiF4→FP simulation operator source code ├── svd_quant/ # SVD quantization operator with mixed Mxfp4/Bf16 ├── ops_build.sh # Unified build entry ├── setup.py # wheel packaging configuration └── ops_init.py # Copied as __init__.py during packaging, providing package interface and documentation

构建过程中会生成build/dist/staging/<op>/build/等目录。README 说明这些是本地构建产物,不需要提交。

从 amct_ops/ops_build.sh 的实现看,构建流程分为四个阶段:

  1. 检测主机 CPU 架构,并将x86_64/amd64映射为 CANN 的x86_64-linux,将aarch64/arm64映射为aarch64-linux
  2. 加载 CANN 环境,要求环境变量ASCEND_HOME_PATH已设置,并且$ASCEND_HOME_PATH/set_env.sh存在;
  3. 编译算子。默认扫描amct_ops/下包含CMakeLists.txt的子目录,逐个执行 CMake 配置和编译;
  4. 将各算子的 Python 包和.so汇集到staging/amct_ops/,最后通过pip wheel . -w dist/ --no-deps --no-build-isolation -q生成 wheel。

5. 依赖要求

amct_ops/README_en.md 给出的依赖要求如下:

依赖版本
Python>=3.9
PyTorch2.7.12.1.0(需配套torch_npu
GCC / CMakeGCC>= 7.3,CMake>= 3.16,推荐 CMake 3.20
CANN(Toolkit & Ops)>= 9.0.0(需提前安装 NPU 驱动 / 固件)

完整环境部署可参考 docs/zh/quick_install.md。

从 amct_ops/hifloat8_cast/CMakeLists.txt 看,算子编译还会检查 CANN 目录结构、Torch 路径和torch_npu路径,并链接torch_nputiling_apiregisterplatformunified_dloggraph_baseascendclascendc_runtime等库。这说明amct_ops不是普通 Python wheel,而是依赖 CANN 编译链和torch_npu运行时的二进制 PyTorch 扩展包。

6. 构建命令与平台选择

所有算子通过 amct_ops/ops_build.sh 统一编译并打包为 wheel。基本用法:

cd amct_ops/ bash ops_build.sh [--soc <soc>] [<operator>]

--soc用于指定目标平台,默认值为ascend910b

bash ops_build.sh # 构建全部算子,默认平台 bash ops_build.sh --soc ascend910_93 # 构建全部算子,指定平台 bash ops_build.sh hifloat8_cast # 只构建指定算子,默认平台 bash ops_build.sh --soc ascend950 hifloat8_cast # 只构建指定算子,指定平台

可选平台如下:

SOC 参数平台说明
ascend910bA2Ascend 910B1/B2/B3,默认值
ascend910_93A3Ascend 910_93
ascend950A5Ascend 950,需要 CANN 编译器支持dav-3510

从 amct_ops/ops_build.sh 可以看到,SOC 会进一步映射为 NPU 架构:

ascend910b) NPU_ARCH="dav-2201" ;; ascend910_93) NPU_ARCH="dav-2201" ;; ascend950) NPU_ARCH="dav-3510" ;;

也就是说,ascend910bascend910_93共用dav-2201,而ascend950使用dav-3510。这一映射也体现在 amct_ops/hifloat8_cast/CMakeLists.txt 中:该算子只接受dav-2201dav-3510两类NPU_ARCH

svd_quant,构建脚本还有单独分支:只有在--soc ascend950下才会编译;否则脚本会跳过该算子。这说明svd_quant的平台适用范围与hifloat8_casthifloat4_cast不完全相同,构建时应注意目标 SOC。

7. 构建产物与 wheel 命名

构建产物位于:

dist/amct_ops-1.0.0-cp*-cp*-linux_<arch>.whl

其中<arch>由构建主机架构决定,通常为x86_64aarch64。wheel 文件名中的两个cp*分别表示 Python 实现/版本标签和 ABI 标签。例如cp311-cp311表示该 wheel 面向 CPython 3.11,并依赖 CPython 3.11 ABI;linux_<arch>表示构建主机平台架构。

amct_ops/setup.py 配置了固定包名amct_ops和版本1.0.0,并通过find_packages(where='staging')staging/收集 Python 包。脚本还会扫描staging/amct_ops/<sub>/下的.so文件,将其作为package_data打进 wheel。

BinaryDistribution类的作用是强制生成平台相关 wheel,因为amct_ops内含编译后的.so文件,不是跨平台纯 Python 包。因此实际安装时需要注意 Python 版本、CPU 架构、目标 NPU 平台和 CANN 环境是否匹配。

8. 安装与使用示例

wheel 生成后,使用pip安装:

pip install dist/amct_ops-*.whl

安装后有两种调用方式。

8.1 模块导入方式

# 方式一:模块导入(有 IDE 补全和文档字符串) from amct_ops.hifloat8_cast import encode_to_hifloat8, decode_from_hifloat8 y = encode_to_hifloat8(x) # FP16/BF16 → uint8 z = decode_from_hifloat8(y) # → bfloat16(默认) z = decode_from_hifloat8(y, torch.float16) # → float16

这种方式更接近普通 Python 库的使用体验。amct_ops顶层包由 amct_ops/ops_init.py 在打包阶段复制为__init__.py,其中声明了可用子模块:

__all__ = ['hifloat8_cast', 'hifloat4_cast'] from . import hifloat8_cast from . import hifloat4_cast

因此import amct_ops后即可通过amct_ops.hifloat8_castamct_ops.hifloat4_cast访问对应子包。

8.2 torch.ops.amct 方式

# 方式二:torch.ops.amct(与其他 NPU 算子风格一致) import amct_ops.hifloat8_cast # 触发 .so 加载 torch.ops.amct.encode_to_hifloat8(x) torch.ops.amct.decode_from_hifloat8(y, torch.float16)

这种方式与 PyTorch 自定义算子注册机制一致。底层 C++ 扩展通过TORCH_LIBRARY_FRAGMENT(amct, m)注册算子 schema,再通过TORCH_LIBRARY_IMPL(amct, PrivateUse1, m)注册 NPU 后端实现。因此torch.ops.amct.<op>能解析成功的前提,是对应的.so已经被加载。

从 amct_ops/hifloat8_cast/python/hifloat8_cast/init.py 可以看到,Python 包导入时会定位同目录下的libhifloat8_cast_ops.so,并调用:

torch.ops.load_library(_lib_path)

这正是 README 中“import amct_ops.hifloat8_cast触发.so加载”的具体实现。

9. Python 内省与文档查看

README 提供了两种 Python 内省方式:

import amct_ops help(amct_ops) # 查看所有子模块及接口列表 import amct_ops.hifloat8_cast help(amct_ops.hifloat8_cast.encode_to_hifloat8) # 查看单个函数签名和文档

amct_ops/ops_init.py 的模块文档列出了amct_ops.hifloat8_castamct_ops.hifloat4_cast的函数说明,并给出快速示例:

import torch from amct_ops.hifloat8_cast import encode_to_hifloat8, decode_from_hifloat8 x = torch.randn(1024, dtype=torch.float16, device="npu") y = encode_to_hifloat8(x) # → uint8, same shape z = decode_from_hifloat8(y) # → bfloat16, same shape

这类内省方式适合在不确定可用接口时快速检查包结构,也方便在 Jupyter、脚本或 IDE 中查看函数签名。

10. 已知 CMake 告警

使用 pip 安装的 PyTorch 构建时,find_package(Torch)可能输出如下告警:

static library kineto_LIBRARY-NOTFOUND not found.

amct_ops/README_en.md 说明该告警来自 PyTorch 自带的TorchConfig.cmake,表示未找到 Kineto profiler 的静态库。当前amct_ops算子不依赖 PyTorch profiler / Kineto 能力;只要 CMake configure、编译和链接成功,该告警可以忽略。

这一判断与 CMake 链接配置相符:amct_ops/hifloat8_cast/CMakeLists.txt 中链接的是torch_nputiling_apiascendclascendc_runtime等 CANN / torch_npu 相关库,并未显式依赖 Kineto profiler。

11. 新增算子的目录结构

如果要新增算子,amct_ops/README_en.md 要求参照现有算子目录,例如hifloat8_cast/

<new_operator>/ ├── op_kernel/ # Ascend C kernel(.cpp + tiling.h) ├── op_extension/ # PyTorch C++ binding(host stub 调用 + TORCH_LIBRARY 注册) ├── python/<pkg>/ # Python 接口(__init__.py) ├── CMakeLists.txt # 独立编译入口 └── README.md # 算子说明文档

各部分职责如下:

目录 / 文件职责
op_kernel/Ascend C kernel 实现,通常包含 kernel.cpp和 tiling 头文件
op_extension/PyTorch C++ 绑定,负责 host stub 调用和TORCH_LIBRARY注册
python/<pkg>/Python 包入口,包含__init__.py和可选封装函数
CMakeLists.txt独立 CMake 编译入口,生成该算子的.so
README.md算子说明文档

从 amct_ops/hifloat8_cast/CMakeLists.txt 可以看到典型编译目标会由op_kernel/op_extension/下的源文件共同构成共享库,例如:

add_library(hifloat8_cast_ops SHARED op_kernel/hifloat8_cast_kernel.cpp op_extension/hifloat8_cast_torch.cpp op_extension/register.cpp )

其中 kernel 源文件被标记为ASC语言:

set_source_files_properties(op_kernel/hifloat8_cast_kernel.cpp PROPERTIES LANGUAGE ASC)

这说明 Ascend C kernel 与 C++ 绑定在同一个 CMake target 下统一编译,最终形成可被 PyTorch 加载的.so

12. 新增算子后的自动打包机制

README 指出:新增算子后无需修改 amct_ops/ops_build.sh 或 amct_ops/setup.py,构建脚本会自动发现<op>/python/<pkg>/目录并打包。

这一点可以从 amct_ops/ops_build.sh 的collect_op()函数得到印证。它会遍历<op>/python/下的每个子包目录,复制.py文件到staging/amct_ops/<pkg>/,如果<op>/build/中已经生成.so,也会一并复制:

find "$pkg_dir" -maxdepth 1 -name "*.py" -exec cp {} "$dst/" \; [ -d "$op_dir/build" ] && find "$op_dir/build" -maxdepth 1 -name "*.so" -exec cp {} "$dst/" \;

随后 amct_ops/setup.py 通过find_packages(where='staging')收集 Python 包,并扫描staging/amct_ops/中的.so文件作为package_data。因此新增算子的关键是:

  1. amct_ops/<new_operator>/下提供完整目录结构;
  2. 保证<new_operator>/CMakeLists.txt能编译出.so
  3. <new_operator>/python/<pkg>/下提供 Python 包入口;
  4. 运行bash ops_build.sh或指定算子名构建,让脚本自动完成 staging 和 wheel 打包。

README 还提醒:正式测试应放在tests/amct_ops/下,避免把构建产物、性能脚本或依赖额外参考实现的对比工具放入算子源码目录。

13. 命名空间约束:所有算子注册到 amct

amct_ops/README_en.md 对命名空间有明确约束:所有算子必须注册到amct命名空间。这样与amct_ops包名保持一致,也便于调用方区分 AMCT 自定义算子与torch_npu上游算子。

C++ 侧需要同时完成 schema 注册和后端实现注册:

TORCH_LIBRARY_FRAGMENT(amct, m) TORCH_LIBRARY_IMPL(amct, PrivateUse1, m)

Python 侧有两种访问方式:

torch.ops.amct.<operator_name> from amct_ops.xxx import <operator_name>

新增算子前,应先检查torch.ops.amct中是否已存在同名算子,避免命名冲突。amct命名空间是amct_ops包在 PyTorch 自定义算子体系中的统一入口,新增算子如果偏离该命名空间,会破坏 README 所描述的调用约定。

14. 使用建议与排查要点

基于 README 和源码实现,实际使用amct_ops时可以从以下几点入手。

14.1 环境检查

构建前至少确认:

  • ASCEND_HOME_PATH已设置;
  • CANNset_env.sh可被加载;
  • 主机 CPU 架构为x86_64/amd64aarch64/arm64
  • 目标 SOC 在ascend910bascend910_93ascend950中;
  • PyTorch 版本与torch_npu版本匹配,且满足 README 的版本约束。

14.2 构建产物检查

构建完成后,建议检查:

  • dist/amct_ops-*.whl是否生成;
  • wheel 文件名中的 Python 版本标签和 ABI 标签是否与当前环境一致;
  • wheel 内容是否包含各算子子包和.so文件;
  • 目标平台是否为预期 SOC 对应的dav-2201dav-3510

14.3 接口调用检查

运行期建议先做最小验证:

import torch import amct_ops.hifloat8_cast x = torch.randn(1024, dtype=torch.float16, device="npu") y = torch.ops.amct.encode_to_hifloat8(x) z = torch.ops.amct.decode_from_hifloat8(y) print(y.dtype, y.shape) print(z.dtype, z.shape)

如果出现torch.ops.amct无法解析的问题,优先检查对应子包是否已被导入、.so是否已加载、wheel 是否与当前 Python / CPU 架构 / CANN 环境匹配。

15. 小结

amct_ops是 AMCT 仓库中专门承载昇腾 NPU 自定义算子的模块。它把 Ascend C kernel、C++ PyTorch 绑定、Python 接口和 CMake 构建配置按算子目录组织起来,再通过 amct_ops/ops_build.sh 统一编译,并打包成包含.so的 wheel。对上层 Python 用户来说,它提供amct_ops.<op>torch.ops.amct.<op>两类接口;对算子开发者来说,它要求新增算子遵循固定目录结构、注册到amct命名空间,并将测试放入 tests/amct_ops/ 下。理解这套约定,是正确使用和扩展amct_ops的基础。

【免费下载链接】amctAMCT是CANN提供的昇腾AI处理器亲和的模型压缩工具仓。项目地址: https://gitcode.com/cann/amct

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询