Skip to content
hsfzxjyPublic

About

Write and run custom C kernels for Intel Core Ultra NPUs

Topics

Resources

Stars

69 stars

Watchers

0 watching

Forks

Repository files navigation

npunlock

Intel ships programmable SHAVE cores inside its NPUs, but the public stack exposes only graph-level programming. npunlock reconstructs the missing path from custom C code to a runnable NPU kernel.

How npunlock adds custom C kernels to an Intel NPU graph

The current implementation has been verified on Windows x64 with Meteor Lake / NPU3720.

Latest breakthrough — 2026-10-14: Validated custom kernels now include nested helper call chains and invocation-local reductions, including a three-pass expf softmax kernel. Evidence and limits.

Quick example

This complete FP32 GELU example embeds the C kernel in Python, places it in an NPU graph, and checks the result against NumPy. The bundled npunlock/npu3720_kernel.h target header supplies the NPU3720 invocation and tensor-address helpers. The tested MoviTools toolchain makes most conventional libm functions available to kernels without including <math.h>; this example calls tanhf directly. See the mlibm.a symbol inventory for the observed candidates.

import numpy as np
import npunlock as npu

npu.configure(movi_dll_dir=r"C:\path\to\MVC_DEPEND")

gelu_c: bytes = b"""
#define MLIBM_DEFINE_LINK_COMPAT 1
#include <npunlock/npu3720_kernel.h>

void controlled_act(unsigned layerParams) {
    act_abi_invocation invocation;
    ACT_ABI_LOAD_INVOCATION32_OR_RETURN(layerParams, invocation);
    const float *in = ACT_ABI_INPUT_PTR32(const float, invocation, 0u);
    float *out = ACT_ABI_OUTPUT_PTR32(float, invocation, 1u);
    const float SQRT_2_DIV_PI = 0.7978845608028654f;
    for (unsigned i = 0; i < invocation.element_count; ++i) {
        float x = in[i];
        float w = x + 0.044715f * x * x * x;
        w = tanhf(w * SQRT_2_DIV_PI);
        out[i] = 0.5f * x * (1.0f + w);
    }
}
"""

N = 2048
x = npu.input("x", shape=(1, N), dtype="f32")
y = npu.custom(
    x,
    source=gelu_c,
    carrier="Abs",
    _name="y",
)

program = npu.compile(npu.Graph(inputs=[x], outputs=[y], name="gelu_f32_example"))

input_value = np.linspace(-4, 4, N, dtype=np.float32).reshape(1, -1)
output = program.run_one(input_value)
reference = 0.5 * input_value * (
    1.0
    + np.tanh(
        np.sqrt(2.0 / np.pi)
        * (input_value + 0.044715 * input_value**3)
    )
)
print(f"maximum absolute error: {np.max(np.abs(output - reference)):g}")

The same code is available as the runnable FP32 GELU example. See also the FP16 GELU and multi-layer two-input examples, plus a row-broadcast two-input kernel, a five-input kernel, and a mixed-precision graph with unary and binary custom branches and a branched network combining DPU work with three custom kernels. The connected conversion example uses custom kernels on both sides of an ordinary FP16 graph operation. The connected mixed-precision example adds a two-input custom kernel, DPU matrix multiplication, reviewed build plan, prepared-carrier reload, and saved-program reload in one path. The I32 structural example needs no MoviTools and demonstrates ordinary multi-input/multi-output Concat, Transpose, and Convert execution. The U8 reshape example likewise needs no MoviTools and returns both reshaped U8 data and its FP32 conversion. The I8 axis-transform example covers signed-byte Squeeze, Unsqueeze, and FP32 conversion in one ordinary graph. The I16 Split example demonstrates one multi-output node bound directly to three shared output arrays. The U16 Split example covers unsigned 16-bit boundary values, while the U8 Gather example uses caller-provided I32 indices in a mixed-input ordinary graph. The U32 Split example extends ordinary graph transport through the full unsigned 32-bit range. The I64-index Gather example validates 64-bit index inputs without claiming general I64 graph data. The unequal U8 split example binds three differently shaped outputs from one VariadicSplit node. The U8 Slice example selects and strides two axes using constant bounds, while the U8 Pad example adds constant borders with an exact scalar fill value.

Why npunlock?

Intel's normal NPU software accepts graphs made from operations its compiler supports; it does not expose a public workflow for supplying a C implementation for an operation. The NPU's ACT-SHAVE processors are programmable and run software kernels. npunlock makes those processors usable for compatible custom graph operations while retaining Intel's compiler and driver for the surrounding graph and hardware execution.

Requirements

  • Windows x64
  • Meteor Lake / Intel NPU3720
  • an installed Intel NPU driver for the device
  • Python 3.10 or newer
  • CMake 3.24 or newer and an installed MSVC toolchain for source installation
  • the extracted MoviTools MVC_DEPEND toolchain for custom C compilation

OpenVINO is not required as a runtime, Python package, or compiler frontend. npunlock does emit OpenVINO-format IR for the installed Intel driver.

Install

npunlock is currently installed from a source checkout:

python -m pip install .

The build bundles npunlock.dll and npunlock_worker.exe inside the Python package, so normal Python use does not require a separate native path.

Get MoviTools

Custom C compilation uses Intel/Movidius MoviTools, which npunlock does not redistribute or download.

A MoviTools package verified to work was found in a legacy Lenovo driver pack. See Getting MoviTools for the official download, hash, extraction command, and expected layout.

Extract the MVC_DEPEND payload from Lenovo's older Intel NPU driver package 31.0.100.1688, but remember, DO NOT install or downgrade to that driver. All we need is the bundled MoviTools.

Check your setup

After configuring NPUNLOCK_MOVITOOLS_DIR, inspect both runtime capabilities:

python -m npunlock doctor

The report distinguishes running an already compiled program from compiling new custom C, which additionally requires MoviTools. See the Python API guide for JSON and offline options. Use python -m npunlock doctor --full when you explicitly want an end-to-end custom-kernel compile, execution, and exact host-oracle check.

Run an example

Point npunlock at the extracted MVC_DEPEND root and run GELU:

$env:NPUNLOCK_MOVITOOLS_DIR = 'C:\path\to\MVC_DEPEND'
python examples\example_gelu.py

The example runs on the NPU and reports its maximum error against a NumPy reference.

What currently works

  • compile user-written C into ACT-SHAVE machine code
  • run custom kernels inside Intel NPU graphs
  • static dense FP16 unary and two-input custom kernels, including one validated descriptor-level row-broadcast carrier
  • one static dense five-input FP16 custom carrier
  • verified unary and scalar-input binary FP32 paths
  • one graph containing independent FP32-unary and FP16-binary custom branches
  • a branched graph combining ordinary ACT operations, DPU matrix multiplication, and three custom kernels
  • prepared-graph inspection and explicit symbolic binding for ambiguous ACT placement
  • connected unary FP32-to-FP16 and FP16-to-FP32 custom kernels through per-tensor contracts
  • ordinary static graph execution with FP16, FP32, U8, I8, U16, I16, U32, or I32 inputs and outputs
  • caller-provided I64 index inputs for validated Gather graphs
  • inferred contracts for Concat, Split, VariadicSplit, constant-mode Pad, positive-step Slice, Gather, Transpose, Reshape, Squeeze, Unsqueeze, Convert, and rank-2 MatMul
  • nonlinear math such as GELU, tanhf, expf, and invocation-local softmax
  • bounded custom control flow, nested same-file helpers, invocation-local windows, embedded coefficients, and local scratch storage
  • reusable NumPy-compatible host/NPU shared input and output buffers
  • reusable compiled SHAVE ELFs for rebuilds that do not need MoviTools
  • self-describing program bundles that load without C source or MoviTools
  • Python, CLI, and native C APIs

Current limitations

Support is experimental and currently limited to Windows x64, Meteor Lake / NPU3720, static shapes, compatible ACT carriers, and known tensor layouts. Connected FP32/FP16 conversion is limited to the observed unary, equal-element contract and requires explicit prepared-group binding. Other NPU generations have not been verified. See Current limitations for the full compatibility boundary.

Help test Linux and newer NPUs

Have an NPU3720 Linux system or a newer Intel NPU? Contributions are welcome. Two routes look especially promising but remain untested:

  • a patched NPU3720 graph produced on Windows may run on Linux because the NPU firmware executes the custom machine code; building SHAVE code on Linux would additionally require a way to load the Windows MoviTools DLLs;
  • newer NPUs may execute the existing 3720xx SHAVE image, or an older OEM driver package for that generation may provide matching MoviTools components.

Both need hardware validation, driver/firmware version records, and output comparison against a host oracle. If you can test either path, feedback, failure reports, and code contributions are welcome. See Porting to Linux and newer NPUs for the hypotheses, caveats, and staged test plan. Linux builds provide npunlock-inspect for structural reports and npunlock-linux-probe for an explicitly in-process execution attempt with stage-by-stage diagnostics and an exact host oracle. The latter is ready for hardware testing but has not yet run on a Linux system with NPU passthrough, so Linux execution is not a supported configuration yet.

Documentation

Warning

A note on AI use: I did use AI while building this project--for scaffolding, repetitive implementation work, converting my reverse-engineered results into organized documentation, and fixing my English. The reverse engineering, experiments, debugging, and technical conclusions came from hands-on work. If that doesn’t bother you, there’s a pretty deep and surprisingly satisfying rabbit hole ahead.

License

npunlock is licensed under the Apache License 2.0. MoviTools and the Intel/Movidius libraries are external proprietary dependencies and are not covered or redistributed by this repository.

About

Write and run custom C kernels for Intel Core Ultra NPUs

Topics

Resources

Stars

69 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages