open-xdna / docs /VISION_OFFLOAD.md
elyanlabs's picture
Source snapshot of github.com/Scottcjn/open-xdna@6c8c680
e629bba verified
|
Raw History Blame Contribute Delete
3.4 kB

NPU vision offload β€” the multimodal front-end belongs on the NPU

Thesis: for a multimodal model (image + text), put the vision front-end on the XDNA1 NPU and keep text generation on the CPU/iGPU. This is the NPU's designed purpose β€” Ryzen AI NPUs exist for edge vision/CNN inference β€” so unlike text decode (memory-bound, where the NPU loses), the vision path is compute-bound conv work the AIE array is built for.

Why vision, not text

text decode vision front-end
bottleneck memory bandwidth compute (convs/matmuls)
NPU fit poor (M0/M0.5: NPU loses) strong (AIE = CNN engine)
parallelism low (gemv) high (patches/channels)
concurrency β€” runs while CPU/iGPU do the LLM
power β€” ~6.6 W

The NPU stops being a reluctant matmul unit and becomes what it was made for.

Proven on silicon (this repo)

A full image-processing pipeline runs on the gen-1 NPU today β€” programming_examples/vision/ edge_detect (rgba2gray β†’ 3Γ—3 Laplacian filter2d β†’ threshold), verified vs an OpenCV reference:

$ python3 edge_detect.py -W 512 -H 512
Number of differences: 1942, average L1 error: 0.96
PASS!

IRON ships the vision/CNN kernel set the front-end needs: conv2dk1, conv2dk3 (incl depthwise + ReLU + pooling variants), conv2dk1_i8, filter2d, rgba2gray, gray2rgba, rgba2hue, plus softmax/gelu/silu for the encoder blocks. These are exactly the ops a ViT/CNN image tower (patch-embed conv, conv stem, channel projections) is made of.

The hook (proposed integration)

For a multimodal model with a vision encoder (PaliGemma / Gemma-vision / LLaVA-style towers):

  1. Image preprocessing + patch-embed conv β†’ NPU (conv2dk1/conv2dk3/filter2d).
  2. Vision-encoder early conv/projection stages β†’ NPU, streaming patch tiles.
  3. Hand off the image embeddings to the text path: decode β†’ Radeon 780M, prefill β†’ CPU.
  4. The NPU also runs the prune/collapse coprocessor on attention/FFN (see TIER3_DESIGN.md).

Net: a 4-way split on the integrated SoC β€” NPU = vision + prune, 780M = decode, CPU = prefill β€” all over the 96 GB unified pool, no discrete GPU.

Honest status

  • βœ… Proven: conv / 2D-filter / colorspace vision kernels run on the NPU (edge_detect PASS). These are the building blocks of a vision tower.
  • βœ… SigLIP/ViT patch-embed wired + measured (examples/npu_patch_embed.py): the patch-projection matmul ([256Γ—768]@[768Γ—768], SigLIP-base/16) runs on the NPU, bit-exact. HONEST measurement: at base size the NPU (int16, 6.6 ms / 46 GFLOP/s, dispatch-bound) is ~3.2Γ— SLOWER than fair CPU f32 BLAS (2.0 ms / 148 GFLOP/s). The win is offload + ~6.6 W + scaling (frees CPU/iGPU for the LLM, gap closes at larger image/batch), not raw latency at SigLIP-base. Don't quote int32-numpy as the CPU baseline β€” it's unoptimized (~1.5 GFLOP/s) and makes the NPU look 34Γ— faster, which is false.
  • 🚧 Not yet done: full multi-stage encoder (conv stem + transformer blocks) + a batched/larger-image regime where the NPU's offload+power actually nets ahead; measure end-to-end encoder latency & SoC power.
  • The "boost" is expected to be real because this is the NPU's native workload β€” but it is a projection from the proven primitives until a full vision tower is wired and measured.