Applied competency reference | updated 2026-07-11
NPU Framework, Compiler, ISA, and Tooling Skills
An engineering path from framework execution semantics to an edge accelerator backend. It concentrates on PyTorch and TensorFlow internals, forensic ONNX analysis, current TVM architecture, RISC-V and NPU ISA integration, measured power/performance work, executable SDK examples, debugger GUI design, and cross-team practice.
Coverage boundary
Existing foundations stay in their original pages
This document does not repeat neural-network basics, accelerator comparisons, LLVM/MLIR introductions, generic graph optimization, quantization, C, Git, or the Analog CIM study. Use the foundation chapters first, then consult the Analog CIM specialization when it is relevant to the product or role.
Deep-learning framework internals
Backend engineers must know which semantics survive capture
Eager execution, automatic differentiation, graph capture, ahead-of-time export, and backend lowering are different mechanisms. A graph compiler receives only the behavior that the selected capture path represents.
PyTorch eager: Python call to dispatched kernel
A tensor operation reaches the dispatcher, which selects behavior for backend and cross-cutting features such as autograd, autocast, or functionalization. Autograd records a reverse-mode graph of Function objects as the forward computation executes.
PyTorch compile and export are related but not interchangeable
torch.compile uses TorchDynamo to capture Python frames, AOTAutograd to capture forward/backward work, and a backend such as TorchInductor to generate code. Guards and graph breaks preserve dynamic Python behavior. torch.export targets an ahead-of-time, full-graph ExportedProgram with explicit input constraints.
TensorFlow: eager code becomes one or more concrete graphs
tf.function traces TensorFlow operations into graphs and caches concrete functions for compatible inputs. AutoGraph converts supported Python control flow into graph-building code. Python side effects happen during tracing, not as ordinary work on every graph execution.
The NPU backend must publish a semantic acceptance contract
Supported operator names are insufficient. Support depends on rank, shape bounds, dtype, layout, quantization scheme, attributes, aliasing, mutation, dynamic control flow, memory limit, and target revision.
| Question | PyTorch | TensorFlow | NPU engineering consequence |
|---|---|---|---|
| Eager path | Dispatcher selects ATen kernels and cross-cutting behavior. | Eager runtime executes TensorFlow ops immediately. | Device integration needs operator, memory, error, profiler, and lifecycle support, not only a compiler. |
| Autodiff | Dynamic reverse graph of autograd Function objects. | GradientTape records operations for differentiation. | Inference-only backends must reject training paths clearly; training backends need backward and state semantics. |
| Capture | Dynamo regions with guards and graph breaks; export offers AOT full-graph capture. | tf.function traces and caches concrete graphs. | Compile cache keys must include all specialization assumptions that affect generated code. |
| Dynamic shapes | Guards, symbolic dimensions, specialization, possible recompilation. | Input signatures and trace compatibility control concrete-function reuse. | Choose bounded dynamic kernels, shape classes, or compile-on-demand with visible cache behavior. |
| Debug unit | Python frame, FX/ATen graph, compiled region, generated kernel. | Python function, ConcreteFunction/GraphDef, cluster, executable. | Preserve IDs through each level so a device fault maps back to source behavior. |
ONNX network analysis
Inspect the graph before optimizing it
ONNX separately versions the IR, operator sets, and model. Shape inference is useful but intentionally incomplete for some dynamic behavior. A production analyzer records unknowns instead of inventing shapes.
from collections import Counter
import math
import numpy as np
import onnx
from onnx import checker, helper, shape_inference
model = onnx.load("model.onnx", load_external_data=True)
checker.check_model(model, full_check=True)
typed = shape_inference.infer_shapes(model, strict_mode=False)
graph = typed.graph
def shape_of(value):
tensor = value.type.tensor_type
if not tensor.HasField("shape"):
return "unknown-rank"
dims = []
for dim in tensor.shape.dim:
dims.append(dim.dim_value or dim.dim_param or "?")
return dims
print("IR:", typed.ir_version)
print("Opsets:", [(item.domain or "ai.onnx", item.version)
for item in typed.opset_import])
print("Operators:", Counter(node.op_type for node in graph.node))
print("Inputs:", [(value.name, shape_of(value)) for value in graph.input])
print("Outputs:", [(value.name, shape_of(value)) for value in graph.output])
def logical_bytes(tensor):
if tensor.data_type == onnx.TensorProto.STRING:
return sum(len(value) for value in tensor.string_data)
dtype = np.dtype(helper.tensor_dtype_to_np_dtype(tensor.data_type))
return math.prod(tensor.dims) * dtype.itemsize
weight_bytes = sum(logical_bytes(item) for item in graph.initializer)
print("Initializers:", len(graph.initializer), weight_bytes, "logical bytes")
for index, node in enumerate(graph.node):
domain = node.domain or "ai.onnx"
print(index, domain, node.op_type, list(node.input), list(node.output))
Analyzer outputs worth keeping in CI
- IR and opset versions, model and external-data digests, producer metadata.
- Input/output signatures with symbolic dimensions and bounded-shape policy.
- Operator, domain, attribute, initializer, sparse tensor, function, and subgraph inventory.
- Target support result for every node, with reason and estimated boundary transfer cost.
- Quantization representation: QDQ, integer operators, scales, zero points, granularity, axis.
- Reference vectors and per-output tolerances tied to preprocessing and postprocessing versions.
- Peak live tensor estimate, constant bytes, dynamic allocation sites, and fallback memory.
| Pass order | Transformation | Proof obligation before the next stage |
|---|---|---|
| 1. Validate/version | Reject malformed graphs; convert opsets only with defined adapters. | Every node resolves to known semantics for its imported domain and version. |
| 2. Type/shape analysis | Propagate known facts and record unresolved symbols. | No pass assumes a static dimension that analysis has not proved or guarded. |
| 3. Normalize | Canonicalize equivalent forms and make implicit broadcasts/layouts explicit where needed. | Reference output remains equal; source and quantization metadata survive. |
| 4. Simplify | Constant fold, eliminate dead/identity work, simplify control and shape subgraphs. | Folding respects dtype, overflow, NaN, rounding, and external-data policy. |
| 5. Capability/partition | Assign maximal legal regions to NPU or fallback providers. | Each region satisfies target predicates; boundary conversions are explicit and costed. |
| 6. Target transforms | Fuse, choose layouts, quantize/lower, schedule, and plan memory inside owned regions. | Numerical, memory, and resource constraints pass independent verifiers. |
| 7. Package/compare | Emit executable and run framework/ONNX/target parity plus performance measurements. | Artifact provenance, tolerances, target versions, and regression result are retained. |
Partition timing matters. ONNX Runtime performs provider-independent optimizations before partitioning and provider-specific work afterward. Its current documentation recommends a plugin execution provider for new integrations starting with ONNX Runtime 1.23. A vendor backend should verify which layer owns each rewrite so two optimizers do not erase one another's patterns or apply incompatible layouts.
Applied TVM architecture
Use TVM as two connected optimization levels plus a runtime
The site already introduces TVM beside MLIR. This section focuses on the current practical mapping: Relax for graph/dataflow structure, TensorIR for primitive tensor programs, scheduling for implementation choices, and runtime modules for deployment.
| Extension point | NPU use | Acceptance evidence |
|---|---|---|
| Relax import / rewrite | Represent target composite patterns, quantized forms, shape constraints, and offload regions. | Before/after IR, structural matcher tests, numerical parity, rejection diagnostics. |
| Operator legalization | Lower high-level ops to target primitives, TIR, or external PackedFunc calls. | Semantic tests across dtype, shape boundary, attributes, and dynamic dimensions. |
| TensorIR | Represent local buffers, data movement, loop structure, and hardware tensor intrinsics. | Generated access bounds, race analysis, bit parity, resource estimates. |
| Schedule / MetaSchedule | Search tile, layout, memory scope, parallelization, and tensorization choices. | Reproducible workload key, search budget, measured target result, held-out validation. |
| Codegen / module | Emit NPU command binaries, firmware code, target source, or runtime-call wrappers. | Versioned module metadata, load tests, disassembly/descriptor inspection, compatibility checks. |
| Runtime / VM | Load modules, resolve functions, allocate devices, execute graph control, call compiled kernels. | Lifecycle, concurrency, serialization, allocator, error, and remote-device tests. |
RISC-V and NPU accelerator ISA
The key decision is how software submits work, not whether an opcode looks elegant
RISC-V reserves custom encoding spaces for vendor-specific extensions. An accelerator may instead use MMIO, memory-resident command queues, a standard device interface, or a combination. Workload granularity and system isolation usually matter more than instruction count.
| Integration style | Best fit | Main cost | Compiler/runtime consequence |
|---|---|---|---|
| Custom scalar/vector instruction | Fine-grain tightly coupled operations with registers or local state. | Toolchain, context state, exceptions, virtualization, and memory-model integration. | Intrinsic/builtin lowering, assembler/disassembler, ABI and scheduler awareness. |
| MMIO control | Simple control/status, boot, reset, capability, and low-rate commands. | High per-command CPU overhead; ordering and posted writes require care. | Driver API and register generation; rarely suitable for every tensor tile. |
| Memory command queue | Coarse asynchronous kernels, DMA descriptors, multiple in-flight jobs. | Descriptor validation, coherency, fences, queue wrap, reset and fault recovery. | Compiler emits command graph; runtime owns buffers, dependencies, submission, events. |
| Firmware RPC | Complex scheduling, stable host API across changing hardware internals. | Firmware latency, version negotiation, watchdogs, diagnosability. | Artifact carries firmware-facing operations; host remains insulated from microarchitecture. |
#include <stdint.h>
struct npu_command_v1 {
uint16_t size_bytes; /* permits compatible extension */
uint16_t opcode;
uint32_t flags;
uint64_t command_id;
uint64_t executable_id;
uint64_t input_iova;
uint64_t output_iova;
uint32_t input_bytes;
uint32_t output_bytes;
uint32_t dependency_count;
uint32_t completion_slot;
};
/* Producer protocol:
* 1. Validate ownership and bounds.
* 2. Write descriptor and dependency records.
* 3. Publish with the required release ordering.
* 4. Update producer index and ring the doorbell.
*/
ISA and ABI review checklist
- Define architectural state, privilege, context-switch cost, and reset value.
- Specify operand widths, alignment, endianness, rounding, saturation, and exception behavior.
- Separate virtual, physical, and I/O virtual addresses; state IOMMU and coherency assumptions.
- Name memory ordering for descriptors, MMIO, DMA, completion, and CPU visibility.
- Define malformed command, page fault, watchdog, engine fault, retry, and partial-write behavior.
- Reserve feature bits and size-versioned messages; test old/new driver and firmware combinations.
- Generate encoders, decoders, docs, simulator tables, and disassembly from one source of truth.
- Run differential ISA tests plus whole-command random sequences through model and RTL.
RISC-V uses a relaxed memory model and explicit fences for required ordering. A queue protocol must translate that architectural rule into concrete producer/consumer barriers and device coherency operations. "Write the descriptor, then ring the doorbell" is incomplete until visibility and ordering are specified for every agent.
Low-power and high-performance optimization
Optimize energy under a latency and correctness constraint
Measurement formulas and trace correlation live in SoC Software Architecture. This section focuses on choosing and validating optimization levers across the stack.
| Layer | High-value levers | Hidden tradeoff | Required experiment |
|---|---|---|---|
| Model / graph | Architecture choice, sequence/image size, sparsity, precision, fusion, partition boundaries. | Accuracy recovery, unsupported operators, fallback copies, compile specialization. | Task metric plus per-layer sensitivity and end-to-end target execution. |
| Kernel / schedule | Tiling, locality, double buffering, tensorization, parallelism, layout, recompute versus spill. | SRAM pressure, bank conflicts, tail inefficiency, code size, synchronization. | Counter-backed roofline classification across representative shapes. |
| Runtime | Async queues, zero-copy, buffer pools, compile cache, batching, overlap, reduced wakeups. | Tail latency, memory residency, fairness, cancellation, cold-start behavior. | Latency distribution and energy across arrival patterns, not only saturated throughput. |
| SoC / power | DVFS, clock/power gating, autosuspend, race-to-idle, memory frequency, thermal policy. | Wake latency, leakage, droop, thermal throttling, deadline misses, shared-rail effects. | Steady-state power and latency sweep by operating point and duty cycle. |
| Product | Workload admission, quality modes, telemetry, field calibration, graceful fallback. | User-visible quality, battery life, contention, privacy, fleet variability. | Scenario-level acceptance criteria and canary/rollback evidence. |
Find the limiting resource
Separate host dispatch, queue wait, DMA, memory bandwidth, engine occupancy, synchronization, power-state transition, and thermal throttling before selecting a lever.
Predict two metrics
State the expected primary benefit and at least one regression risk. For example, a lower frequency may improve power but increase leakage energy and miss a latency deadline.
Use distributions and controls
Pin model, inputs, software versions, operating point, temperature, and concurrent load; compare repeated latency and energy distributions with accuracy unchanged.
SDK and application examples
Examples are executable compatibility contracts
SDK architecture and API ownership are covered in SoC Software Architecture. The missing skill is designing examples that remain small, realistic, testable, and safe to imitate.
| Example | Contract demonstrated | Automated acceptance |
|---|---|---|
| Minimal inference | Discovery, artifact load, input/output binding, synchronous run, cleanup. | Known output, leak-free lifecycle, clear unsupported-target error. |
| Asynchronous pipeline | Multiple buffers, events, dependency ordering, overlap, callback/thread policy. | Random completion timing, no early reuse, timeout and cancellation tests. |
| Camera zero-copy | Imported buffer, format/layout, cache/coherency, fence ownership, lifetime. | Correct frames under producer/consumer stress and fallback path. |
| Dynamic inputs | Shape constraints, compile-cache key, bounded allocation, rejection behavior. | Supported shape classes, cache hit/miss telemetry, out-of-bound diagnostic. |
| Multi-model service | Contexts, memory budget, queue fairness, priority, device loss and reload. | Tail latency, isolation, bounded residency, fault containment. |
| Profiler/debugger | Trace session, layer/source map, counters, tensor checkpoint, replay package. | Schema validation, timestamp correlation, first-divergence golden test. |
| Custom operator | Registration, shape/type inference, fallback, compiler lowering, target kernel. | Positive/negative shapes, reference parity, package and version compatibility. |
GUI programming for NPU tools
A debugger GUI should be a view over stable analysis data
Qt's model/view architecture separates data from presentation. Keep trace decoding and tensor analysis off the UI thread, publish immutable or versioned result models, and make every visual selection addressable by stable IDs.
One selection identity across panes
Selecting a graph node should highlight its fused region, commands, timeline slices, buffers, counters, and tensor diffs through stable IDs rather than text-name matching.
Stream and aggregate outside the UI thread
Workers parse traces and tensors, cancellation stops stale work, and views request bounded windows. Million-event traces should not become a million GUI objects.
Test models before pixels
Unit-test sorting, filtering, time conversion, diff thresholds, selection propagation, and empty/error states. Add screenshot tests only after the underlying data contracts are stable.
| View | Primary model | Performance rule | Failure state |
|---|---|---|---|
| Graph tree | Source node, region, command hierarchy with support/fallback status. | Lazy children and indexed search; do not rebuild the entire tree per selection. | Missing source map remains explicit; never guess by operator name. |
| Timeline | Time-windowed slices, counters, and cross-track flows. | Level-of-detail aggregation and virtualized drawing. | Clock uncertainty and dropped events are visible annotations. |
| Tensor inspector | Typed tensor view, layout transform, quantization, statistics, sampled values. | Chunked reads and sampling before full materialization. | Unavailable checkpoints explain compile mode and capture policy. |
| Memory map | Lifetime intervals, address ranges, banks, aliases, residency. | Interval indexes and viewport filtering. | Overlaps distinguish legal alias from verifier error. |
| Comparison | Aligned runs by graph/command ID, metric, software, and target version. | Precompute summaries; load raw traces on demand. | Incompatible artifacts or shape profiles block misleading comparison. |
Technical soft skills
Cross-functional work becomes visible in engineering artifacts
Turn assumptions into contracts
Write version, ownership, state, ordering, units, error, timeout, and compatibility rules. A short executable schema plus adversarial examples is stronger than a long ambiguous design note.
Separate observation, inference, and decision
Attach traces, counters, inputs, versions, and uncertainty to claims. State what the evidence rules out, what remains possible, and the next cheapest discriminating experiment.
Build a shared reproduction boundary
Reduce the failure to an artifact, input, expected output, component matrix, and first divergent layer/command. Assign investigation by evidence, not organizational blame.
Expose tradeoffs early
Present workload, constraints, alternatives, cost model, failure modes, observability, rollout, and rollback. Record the decision and the evidence that would cause it to change.
Review behavior at boundaries
Look for silent fallback, unchecked dimensions, lifetime races, nondeterministic pass order, ABI drift, missing negative tests, and metric changes before style details.
Repair the detection system
A useful postmortem adds a contract, assertion, counter, replay test, compatibility gate, or deployment safeguard so the same class of failure becomes cheaper to detect.
Evidence matrix
Competence is a result another engineer can inspect
Trace semantics
Explain eager dispatch, autograd, graph capture, guards/retracing, export, and backend boundaries.
Evidence: one model traced through PyTorch and TensorFlow with graph-break/retrace report and parity tests.
Custom backend surface
Define capability predicates, fallback, shape policy, compile cache, error propagation, and profiling integration.
Evidence: small backend or mock execution provider with negative tests and diagnostics.
Graph forensics
Validate versions, infer known shapes, inventory nodes/constants/subgraphs, and find unsupported islands.
Evidence: reproducible analyzer output checked into CI for a model corpus.
Verified transformations
Order normalization, simplification, partitioning, target transforms, and numerical comparison.
Evidence: three graph passes with structural, randomized, and framework/runtime parity tests.
TVM extension
Connect Relax graph work to TensorIR, scheduling, codegen/module packaging, and runtime execution.
Evidence: custom legalization plus schedule experiment measured on a real or modeled target.
Lowering to device work
Lower an operator through intrinsic or target IR into commands, descriptors, relocations, and debug maps.
Evidence: inspectable artifact with disassembly/descriptor dump and model parity.
RISC-V/NPU integration
Reason about custom instructions versus queues, ordering, coherency, privilege, faults, and versioning.
Evidence: ISA/ABI specification, generated encoder/decoder, simulator, and randomized differential tests.
Power/performance decision
Classify a bottleneck, predict tradeoffs, control variables, and validate latency, energy, and correctness.
Evidence: trace-backed optimization memo with raw data, uncertainty, and regression guard.
Executable examples
Cover sync, async, zero-copy, dynamic shape, multi-model, profiling, custom op, and recovery paths.
Evidence: examples run in CI and assert outputs, errors, lifetime, and compatibility.
Debugger/profiler application
Build indexed data models, worker pipelines, linked selections, scalable views, and explicit error states.
Evidence: Qt/PySide tool loading a replay package with graph, timeline, tensor diff, and memory views.
Boundary design
Write a reviewable interface with ownership, state, errors, ordering, observability, and compatibility.
Evidence: accepted design record plus schema, adversarial examples, and integration tests.
Cross-team debug
Reduce a failure, separate observations from hypotheses, choose discriminating experiments, and prevent recurrence.
Evidence: replay package, first-divergence report, decision log, and new regression gate.
Capstone
Build a miniature edge NPU platform
Each increment produces an inspectable artifact and reuses the architecture contracts from the companion SoC software page.
Primary documentation