Estimate neural accelerator (NX) performance with ML Inference Advisor
Introduction
Understand MLIA and the NX Performance Estimator
Set up your MLIA environment
Download a public baseline model
Check baseline operator compatibility
Estimate performance and inspect configurations
Compare a smaller model under the same target profile
(Optional) Run and profile the model on an NX device
Next Steps
Estimate neural accelerator (NX) performance with ML Inference Advisor
Introduction
Understand MLIA and the NX Performance Estimator
Set up your MLIA environment
Download a public baseline model
Check baseline operator compatibility
Estimate performance and inspect configurations
Compare a smaller model under the same target profile
(Optional) Run and profile the model on an NX device
Next Steps
Run the quantized MobileNet V1 0.25, 224 × 224 model on your NX device and inspect its measured cycles in MLIA. Scenario Runner executes the graph through the ML Extensions for Vulkan. The Neural Statistics layer captures accelerator counters for MLIA to analyze.
Use baseline.vgf from the
baseline performance check
and the supplied MobileNet scenario. The constant input exercises the graph; it doesn’t test image-classification accuracy.
Verify ADB and build Scenario Runner
Verify that Android Debug Bridge (ADB) is available on your development host:
adb version
The output is similar to:
Android Debug Bridge version 1.0.41
Version 36.0.2-14143358
On your device, enable Developer options and USB debugging, or Wireless debugging if you use a wireless connection. Authorize your development host when prompted, then verify the connection:
adb devices -l
The output is similar to this shortened example, with your device’s serial:
List of devices attached
<device-serial> device
Your device should appear with the status device. If several devices are connected, set the ANDROID_SERIAL environment variable with export ANDROID_SERIAL="your-device-serial", replacing the value with your device’s serial.
Follow the
Scenario Runner 0.11.0 Android build instructions
to build a debuggable Android arm64 APK. This experimental build needs the Android NDK, Android SDK, Gradle, and public SDK source dependencies. Use Scenario Runner and VGF Library release/v0.11.0 for this example.
Run the Android build command from mlia-demo and add --package-version 0.11.0 so the generated APK has the fixed filename used below.
The following steps configure the public Neural Statistics layer for the unmodified runner. They turn on Enable GPU debug layers, select the runner application, and activate VK_LAYER_LGL_neural_statistics through ADB.
Prepare the baseline scenario on the host
Run the remaining host commands from mlia-demo in the same Bash shell. Create a separate environment for NumPy, copy the compiled model as baseline.vgf, and download the
ready-made MobileNet scenario
:
python3.12 -m venv nx-tools-venv
source nx-tools-venv/bin/activate
python -m pip install numpy==2.2.6
python -m pip check
mkdir -p nx-demo
cp runs/baseline/mlia-output/ml-sdk-model-converter/baseline.tosa.vgf nx-demo/baseline.vgf
curl -fL https://learn.arm.com/learning-paths/mobile-graphics-and-gaming/mlia-nx-performance-estimator/mobilenet-scenario.json -o nx-demo/scenario.json
The scenario binds baseline.vgf to an unsigned eight-bit input with shape [1, 224, 224, 3] and an unsigned eight-bit output with shape [1, 1001]. It reads input.npy, executes one graph dispatch, and writes output.npy. These paths are relative to the scenario file, so keep the three workload files together.
Create the synthetic input tensor, filled with the value 128:
python - <<'PY'
import numpy as np
input_data = np.full((1, 224, 224, 3), 128, dtype=np.uint8)
np.save("nx-demo/input.npy", input_data)
print(f"Input shape: {input_data.shape}; dtype: {input_data.dtype}")
PY
The expected final output is:
Input shape: (1, 224, 224, 3); dtype: uint8
Install the APK and transfer the workload
From mlia-demo, install the debug APK from the generated apk_package directory:
adb install -r apk_package/app/build/outputs/apk/debug/ai-ml-sdk-scenario-runner-0.11.0-debug.apk
The expected final output is:
Success
Pack the three workload files into an archive, then stream it into the application’s storage. run-as accesses the debuggable runner’s files without root:
PACKAGE=com.arm.ai_ml_sdk_scenario_runner
adb shell run-as "$PACKAGE" mkdir -p files/nx-demo
tar -cf nx-demo/workload.tar -C nx-demo baseline.vgf scenario.json input.npy
adb shell -T "run-as $PACKAGE tar -xf - -C files/nx-demo" < nx-demo/workload.tar
Download and install the capture layer
Download the public Android arm64 layer release used for this example:
curl -fL https://github.com/arm/vulkan-layer-neural-statistics/releases/download/v1.0.0/VkLayerNeuralStatistics-android-arm64-v8a.tar.gz -o nx-demo/neural-statistics-layer.tar.gz
tar -xzf nx-demo/neural-statistics-layer.tar.gz -C nx-demo
Copy the library into the runner’s application-owned data directory:
adb shell -T "run-as $PACKAGE sh -c 'cat > libVkLayerNeuralStatistics.so'" < nx-demo/VkLayerNeuralStatistics-android-arm64-v8a/libVkLayerNeuralStatistics.so
Android loads this library from the runner’s data directory.
Configure one measured dispatch
Mode 1 collects neural statistics, and filter 0 selects the first executed dispatch. Configure the layer for the runner application:
Each capture needs a new directory; the timestamp supplies one. GPU debug-layer settings persist and can affect later app runs. Preserve any existing debug configuration you need, and restore it or disable the layer when you’re finished.
CAPTURE_NAME="neural-statistics-capture-$(date +%Y%m%d-%H%M%S)"
cat > nx-demo/vk_layer_settings.txt <<EOF
lgl_neural_statistics.capture_folder = /data/data/$PACKAGE/files/$CAPTURE_NAME
lgl_neural_statistics.statistics_mode = 1
lgl_neural_statistics.dispatch_filter = 0
EOF
SETTINGS_PATH="/data/local/tmp/$CAPTURE_NAME-settings.txt"
adb push nx-demo/vk_layer_settings.txt "$SETTINGS_PATH"
adb shell chmod a+r "$SETTINGS_PATH"
adb shell settings put global enable_gpu_debug_layers 1
adb shell settings put global gpu_debug_app "$PACKAGE"
adb shell settings put global gpu_debug_layer_app "$PACKAGE"
adb shell settings put global gpu_debug_layers VK_LAYER_LGL_neural_statistics
adb shell setprop debug.vulkan.khronos_profiles.settings_path "$SETTINGS_PATH"
The layer writes the capture into the runner’s application-owned storage. The public layer settings and capture format describe the generated files.
Execute the graph with capture enabled
Start the runner’s foreground service. Android’s --esa args option passes the comma-separated RUN_ARGS values as the runner’s command-line arguments. The profiling file collects Vulkan timestamps separately from the neural statistics capture:
DEVICE_DIR="/data/data/$PACKAGE/files/nx-demo"
RUN_ARGS="--scenario,$DEVICE_DIR/scenario.json,--profiling-dump-path,$DEVICE_DIR/profiling.json,--repeat,1"
adb shell am force-stop "$PACKAGE"
adb shell am start-foreground-service -n "$PACKAGE/.Main" --esa args "$RUN_ARGS"
adb logcat -s ScenarioService ScenarioRunner VkLayerNeuralStatistics vulkan AndroidRuntime
The successful run includes this log message:
native exit code=0
Stop adb logcat with Ctrl+C after this message appears. A nonzero code or a runScenarioRunner failed message means the run failed. Exit code zero confirms runner completion; the capture checks that the layer collected neural statistics from the driver.
After the workload completes, retrieve its timestamp profiling and complete capture tree:
adb exec-out run-as "$PACKAGE" cat files/nx-demo/profiling.json > nx-demo/profiling.json
adb exec-out run-as "$PACKAGE" tar -C files -cf - "$CAPTURE_NAME" > nx-demo/neural-statistics-capture.tar
mkdir -p nx-demo/captures
tar -xf nx-demo/neural-statistics-capture.tar -C nx-demo/captures
Ordinary adb pull can’t traverse application-owned capture storage. Streaming a tar archive through run-as preserves the hierarchy and its metadata without root access.
Check capture completion
Inspect the capture metadata and locate the nonempty mode-1 statistics file:
python -m json.tool "nx-demo/captures/$CAPTURE_NAME/capture.json"
find "nx-demo/captures/$CAPTURE_NAME" -name statistics_mode1.bin -size +0c
In capture.json, check that schema_version is 2, status is complete, and capture.statistics_mode is 1. Review any warnings. For this single-dispatch scenario, the find command should print one path, similar to:
nx-demo/captures/<capture-name>/pipeline_000000/session_000000/dispatch_000000/statistics_mode1.bin
A completed capture with a nonempty statistics file shows that the layer intercepted the dispatch and the driver returned neural statistics. If the capture is missing, incomplete, or has no statistics payload, check the layer configuration and driver diagnostics before continuing.
Analyze measured data with MLIA
Return to the MLIA environment and pass the same VGF with the complete capture directory:
source mlia-venv/bin/activate
mlia check nx-demo/baseline.vgf \
--target-profile neural-technology \
--performance \
--profiling-data "nx-demo/captures/$CAPTURE_NAME" \
--output-dir runs/baseline-measured
The following abbreviated output comes from a device capture of this MobileNet scenario. Your cycle counts will depend on the device and its configuration:
Result 1: Performance
Status ok
Producer neural-technology-profiling-data
Mode measured
Metrics:
┌────────────────┬────────┬────────┐
│ Metric │ Value │ Unit │
╞════════════════╪════════╪════════╡
│ total_cycles │ 951154 │ cycles │
├────────────────┼────────┼────────┤
│ compute_cycles │ 951154 │ cycles │
└────────────────┴────────┴────────┘
Status ok confirms that MLIA analyzed the capture. The full results are saved in runs/baseline-measured/mlia-output/mlia-output.json.
Use the measurements
mlia-output.json shows accelerator cycles; benchmark.json shows graph execution times. Use both when comparing your next model version on the same device. Check its predictions on real images too—a faster model isn’t useful if it misses your accuracy target.
What you’ve accomplished
You’ve learned how to run the VGF on an NX-capable device, validate output, collect a structured neural statistics capture, and return it to MLIA for measured analysis. Use this evidence alongside model accuracy tests and end-to-end application profiling before making deployment decisions.