在 Intel NPU 上跑自定义 C 内核是怎么做到的

Npunlock 是一个开源工具,让开发者可以直接用 C 语言为 Intel Core Ultra 处理器的 NPU 编写并运行自定义内核。以前 NPU 只能通过厂商提供的图算子接口编程,用户无法把某个算子的 C 实现交给硬件执行。Npunlock 补上了这条路径,让 NPU 内部可编程的 ACT SHAVE 处理器运行用户编译的机器码,同时保留 Intel 官方编译器和驱动负责外围图调度与硬件执行。它适合需要在 Meteor Lake 平台上做算子级实验、验证自定义数学函数或评估 NPU 可编程边界的开发者。

NPU 原本的编程边界在哪里

Intel NPU 内部集成了可编程的 SHAVE 处理单元,这些单元具备运行自定义软件内核的能力。但公开软件栈只暴露图级编程接口,用户只能使用厂商编译器支持的图算子,没有官方工作流让用户为某个具体算子提供自己的 C 实现。NPU 的底层可编程硬件因此长期被锁定在封闭抽象之下,开发者的优化空间被限制在图算子组合层面。

Npunlock 如何突破这个边界

Npunlock 把用户编写的 C 代码编译为 ACT SHAVE 机器码,然后在 Intel NPU 的图执行框架内运行这些自定义内核。Intel 编译器和驱动仍然负责图的外围调度与硬件执行,Npunlock 让兼容的自定义图操作占用这些可编程处理器。当前已在 Windows x64 和 Meteor Lake 平台的 NPU3720 上验证。项目附带 npu3720_kernel.h 头文件,提供 NPU3720 的调用约定和 tensor 地址辅助宏。

编写一个自定义内核需要哪些步骤

以下流程来自项目验证过的 FP32 GELU 示例。

  1. 定义入口函数 controlled_act(unsigned layerParams),使用头文件中的宏加载 invocation 上下文。
  2. 从 invocation 中取出输入与输出指针,按 invocation.element_count 逐元素计算。
  3. 调用经验证的 MoviTools 工具链支持的 libm 函数,示例直接使用 tanhf 计算 GELU 近似,无需包含标准 <math.h>
  4. 在 Python 侧通过 npu.custom(..., carrier="Abs") 把内核嵌入 NPU 图。
  5. 编译图并运行,与 NumPy 参考输出比对最大绝对误差。

当前能力与硬件支持范围

已验证的能力包括把用户 C 编译为 ACT SHAVE 机器码、在 NPU 图内运行自定义内核、static dense FP16 单输入与双输入内核、FP32 单输入路径,以及在一个图中同时包含独立的 FP32 单输入和 FP16 双输入自定义分支。非线性数学函数如 GELU 和 tanhf 已验证可用。项目提供 Python、命令行与原生 C 三种调用接口,并支持 NumPy 兼容的 host 与 NPU 共享输入输出缓冲区。

使用限制与风险边界

当前支持仍处于实验阶段,边界条件明确。仅支持 Windows x64 平台、Meteor Lake 平台的 NPU3720、静态 shape、兼容的 ACT carrier 和已知的 tensor 布局。连接的混合精度转换组目前无法通过 patch discovery 处理,已验证的混合精度示例使用独立分支。自定义 C 编译依赖 Intel 或 Movidius 的 MoviTools 工具链,项目本身不分发该工具链,需要用户从旧版 OEM 驱动包中提取 MVC_DEPEND 目录。运行时需要已安装目标设备的 Intel NPU 驱动,但不需要 OpenVINO。其他 NPU 代际尚未验证。

常见问题

问 Npunlock 需要安装 OpenVINO 吗。

答 不需要。运行环境只需要目标设备的 Intel NPU 驱动,项目会为已安装驱动生成 OpenVINO 格式的 IR,但 OpenVINO 本身不是依赖。

问 哪些函数可以在内核中调用。

答 经 MoviTools 工具链验证的多数常规 libm 函数可直接使用,项目文档中列出了完整的符号清单。

问 Linux 或更新的 NPU 平台能用吗。

答 尚未验证。一种可能是在 Windows 上生成的 patched NPU3720 图因 NPU 固件直接执行自定义机器码而能在 Linux 运行,但需要实际硬件测试与驱动版本记录。

问 项目采用什么许可证。

答 代码使用 Apache License 2.0,MoviTools 与 Intel 相关库属于外部专有依赖,不由项目覆盖。