Tutorial 2: Computer vision (CV) model
This section provides an end-to-end walkthrough for optimizing a computer vision model using the GO + GQ pipeline.
This tutorial uses resnet50_pt2_pytorch_static_fp32, a preset model provided with Arm AI Model Optimizer. If you want to try other models, see Supported models first, then follow the same steps in this section.
What you'll build
An optimized ResNet-50 targeting Raspberry Pi 5, with signal-to-noise ratio (SNR), latency, and memory measured at each step.
This tutorial assumes you have already run np workspace init (see Quick start or Tutorial 1). Run the following steps from inside that workspace directory.
Step 1. Register your own dataset
Calibration and evaluation data for preset models is licensed for the sample_project that Arm AI Model Optimizer generates automatically. For any project you create yourself, bring your own data. Use the imagenet_folder format for an image classification model like ResNet-50 (see Bring Your Own Model (BYOM) and Bring Your Own Data (BYOD) formats for every supported format):
imagenet/
├─ images/valid/
│ ├─ ILSVRC2012_val_00000007.JPEG
│ └─ ILSVRC2012_val_00000025.JPEG
└─ labels/
└─ imagenet_valid.csv
Register a calibration split and an evaluation split separately:
np datasets register --source ./imagenet_calib --calibration \
--task CLASSIFICATION --raw-data imagenet_folder --name resnet-calib
np datasets register --source ./imagenet_eval --evaluation \
--task CLASSIFICATION --raw-data imagenet_folder --name resnet-eval
Sample output
[INFO ] [CLI] Registering Dataset
[INFO ] [CLI] Checking the request with the server and requesting an upload URL...
[INFO ] [CLI] Archiving the folder into a single tar (this can take a while for a large dataset)...
[INFO ] [CLI] Computing the SHA-256 of the archive...
[INFO ] [CLI] Uploading the archive to the server...
[INFO ] [CLI] Registering and validating on the server. Validation reads every sample once per task, so this can take several minutes - do not interrupt it.
============================================================
Summary
============================================================
[DONE ] [CLI] Dataset registered successfully.
[ Result Summary ]
Sample resnet-calib
Ref ID a1b2c3d4-5e6f-4708-9192-a3b4c5d6e7f8
Split CALIBRATION
Tasks Classification
Uploaded 4.2 MiB
Status CREATED
[ Next Steps ]
Create a project with this dataset:
$ np projects create --calibration-dataset resnet-calib
See Bring Your Own Model (BYOM) and Bring Your Own Data (BYOD) formats: Two-Stage Validation for what a rejected registration looks like and why.
Step 2. Create a project
A project binds a model to a target device. To skip interactive prompts, pass all parameters directly:
np projects create \
--name resnet-rpi5 \
--model resnet50_pt2_pytorch_static_fp32 \
--device raspberry_pi_5_16gb \
--runtime executorch \
--backend xnnpack \
--calibration-dataset resnet-calib \
--evaluation-dataset resnet-eval
Sample output
2026-08-21 13:20.00 [INFO ] [CLI] Parsing arguments...
2026-08-21 13:20.00 [INFO ] [CLI] - Model: resnet50_pt2_pytorch_static_fp32
2026-08-21 13:20.00 [INFO ] [CLI] - Device: raspberry_pi_5_16gb
2026-08-21 13:20.00 [INFO ] [CLI] - Runtime: executorch
2026-08-21 13:20.00 [INFO ] [CLI] - Backend: xnnpack
2026-08-21 13:20.00 [INFO ] [CLI] - Calibration Dataset: resnet-calib
2026-08-21 13:20.00 [INFO ] [CLI] - Evaluation Dataset: resnet-eval
========================================================================
Summary
========================================================================
2026-08-21 13:20.10 [DONE ] [CLI] Project created successfully.
[ Result Summary ]
Project resnet-rpi5
Location /workspace/workspace/resnet-rpi5
Model resnet50_pt2_pytorch_static_fp32
Device raspberry_pi_5_16gb
Runtime executorch
Backend xnnpack
Calibration resnet-calib
Evaluation resnet-eval
[ Next Steps ]
Go to project folder and create an experiment:
$ cd resnet-rpi5
$ np experiments create --steps go,gq
Step 3. Create an experiment
An experiment holds one run.yaml configuration. Create one with GO and GQ steps:
cd resnet-rpi5
np experiments create --steps go,gq
Sample output
2026-08-21 13:35.00 [INFO ] [CLI] Creating Experiment
2026-08-21 13:35.04 [DONE ] [CLI] Generated: run.yaml
[ Result Summary ]
Experiment ID experiment_00
Pipeline Steps go,gq
Config Path /netspresso/workspace/resnet-rpi5/experiment_00/run.yaml
[ Next Steps ]
Go to experiment folder and review configuration:
$ cd experiment_00
$ vi run.yaml
$ np validate
The generated run.yaml:
version: '1.0'
steps:
- graph_optimize: null
- graph_quantize:
- scheme: W8-A8 # Available: W8-A8, W8-A8_dynamic, W4-A8_dynamic
automatic_mixed_precision: null # Available: GREEDY
profile:
- INPUT_MODEL
- GRAPH_OPTIMIZE
- OUTPUT_MODEL
evaluate:
- model: INPUT_MODEL
metric: # Available: TOP1_ACCURACY, TOP5_ACCURACY, SNR, MAE, MSE, KLD, KURTOSIS, PCTL_MAX
- SNR
- model: GRAPH_OPTIMIZE
metric: # Available: TOP1_ACCURACY, TOP5_ACCURACY, SNR, MAE, MSE, KLD, KURTOSIS, PCTL_MAX
- SNR
- model: OUTPUT_MODEL
metric: # Available: TOP1_ACCURACY, TOP5_ACCURACY, SNR, MAE, MSE, KLD, KURTOSIS, PCTL_MAX
- SNR
Step 4. Review and edit run.yaml
Open the generated run.yaml and adjust settings if needed.
vi run.yaml
Common changes for CV models:
| Field | Default | Options | When to change |
|---|---|---|---|
scheme (GQ) | W8-A8 | W8-A8, W8-A8_dynamic, W4-A8_dynamic | Use W4-A8_dynamic for more aggressive compression |
To remove profiling or evaluation, delete the profile or evaluate sections.
See run.yaml Configuration for the full field reference.
Step 5. Validate
Optionally, check for configuration errors before running the pipeline:
np validate
Sample output: pass
2026-08-21 13:42.00 [INFO ] [CLI] Validating run configuration
2026-08-21 13:42.02 [DONE ] [CLI] Validation Passed. No issues found.
╭─────────────────────────────── Execution Plan ───────────────────────────────╮
│ Steps: │
│ [1/2] graph_optimize │
│ [2/2] graph_quantize — scheme: W8-A8 │
│ Profile: INPUT_MODEL, GRAPH_OPTIMIZE, OUTPUT_MODEL │
│ Evaluate: │
│ INPUT_MODEL (snr) │
│ GRAPH_OPTIMIZE (snr) │
│ OUTPUT_MODEL (snr) │
│ Total: 8 jobs │
╰──────────────────────────────────────────────────────────────────────────────╯
Sample output: fail
╭────────────────────────────────────────────────────────╮
│ Validation Failed │
│ │
│ ERROR: advanced_quantize is only supported for │
│ HuggingFace models. Your project uses a .pt2 │
│ file. Use --steps go,gq instead. │
╰─────────────────────────────────────────────────────────╯
Step 6. Run the pipeline
Run optimization, profiling, and evaluation in one command. np run submits the run and returns as soon as the backend accepts it. np run --wait keeps the CLI attached and streams each step as it completes.
Submit, then track (default)
np run
Sample output
2026-08-21 13:50.00 [INFO ] [CLI] Submitting run
2026-08-21 13:50.03 [DONE ] [CLI] Run submitted.
[ Result Summary ]
Experiment <experiment_id>
Status submitted
Target Backend xnnpack
Target Device raspberry_pi_5_16gb
[ Next Steps ]
Track progress, then collect results when it finishes:
$ np status --experiment <experiment_id>
$ np report --experiment <experiment_id>
$ np export --experiment <experiment_id>
The real output prints a generated UUID where <experiment_id> appears, and it differs on every run. From inside the experiment folder you can drop --experiment and let the CLI resolve the experiment from the current directory.
Check progress with np status, repeating until Status reads success:
np status
Sample output
2026-08-21 13:51.15 [INFO ] [CLI] Fetching run status
2026-08-21 13:51.17 [INFO ] [CLI] Target Experiment: experiment_00
Experiment: experiment_00 Status: running
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━┓
┃ Job ┃ Type ┃ Status ┃
┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━┩
│ 01_graph_optimize │ graph_optimize │ running │
│ 02_graph_quantize │ graph_quantize │ pending │
└───────────────────┴────────────────┴─────────┘
Measurements
Evaluate pending
Profile pending
Artifacts
VGF base✗
NPIR base✗
Stream until completion
np run --wait
Sample output: the full pipeline log
2026-08-21 13:50.00 [INFO ] [CLI] Submitting run (will wait for completion)
2026-08-21 13:50.00 [INFO ] [CLI] Logs appear as each step completes. A quiet screen means the run is still queued or a step is in progress.
2026-08-21 13:50.05 [INFO ] [Workflow] Downloading input model started
2026-08-21 13:50.06 [INFO ] [Workflow] Downloading input model completed (1.2s)
2026-08-21 13:50.06 [INFO ] [Workflow] Preparing calibration started
2026-08-21 13:50.07 [INFO ] [Workflow] Preparing calibration completed (0.9s)
2026-08-21 13:50.07 [INFO ] [Workflow]
════════════ [1/4] Graph Optimize ════════════
2026-08-21 13:50.07 [INFO ] [Workflow] Graph Optimize started
2026-08-21 13:50.28 [INFO ] [Workflow] Uploading artifacts completed (20.7s)
2026-08-21 13:50.28 [INFO ] [Workflow] Exporting VGF started
2026-08-21 13:51.13 [INFO ] [Workflow] Exporting VGF completed (44.8s)
2026-08-21 13:51.25 [INFO ] [Workflow] Applied 6 patterns (3 loops):
Loop 1:
- Remove Batch Norm Tracking (53)
- Replace Inplace Add (16)
- Replace Inplace Relu (49)
- Fuse BN To Conv (53)
Loop 2:
(no patterns applied)
Loop 3:
- Combine Add Relu (16)
- Combine Conv Relu (33)
2026-08-21 13:51.25 [DONE ] [Workflow] Graph Optimize completed (1m 18s)
2026-08-21 13:51.25 [INFO ] [Workflow]
════════════ [2/4] Graph Quantize ════════════
2026-08-21 13:51.25 [INFO ] [Workflow] Graph Quantize started
2026-08-21 13:51.25 [INFO ] [Workflow] Preparing calibration for quantization started
2026-08-21 13:51.25 [INFO ] [Workflow] Preparing calibration for quantization completed (0.0s)
2026-08-21 13:51.49 [INFO ] [Workflow] Uploading artifacts completed (18.9s)
2026-08-21 13:51.49 [INFO ] [Workflow] Exporting VGF started
2026-08-21 13:53.44 [INFO ] [Workflow] Exporting VGF completed (1m 55s)
2026-08-21 13:53.50 [DONE ] [Workflow] Graph Quantize completed (2m 25s)
2026-08-21 13:53.50 [INFO ] [Workflow]
════════════ [3/4] Evaluate ════════════
2026-08-21 13:53.50 [INFO ] [Workflow] Evaluate started
2026-08-21 13:53.50 [INFO ] [Workflow] Preparing evaluation dataset started
2026-08-21 13:53.50 [INFO ] [Workflow] Preparing evaluation dataset completed (0.1s)
2026-08-21 13:54.12 [DONE ] [Workflow] Evaluate completed (21.8s)
2026-08-21 13:54.12 [INFO ] [Workflow]
════════════ [4/4] Profile ════════════
2026-08-21 13:54.12 [INFO ] [Workflow] Profile started
2026-08-21 13:54.12 [INFO ] [Workflow] INPUT_MODEL
2026-08-21 13:54.15 [INFO ] [Workflow] GRAPH_OPTIMIZE
2026-08-21 13:54.18 [INFO ] [Workflow] OUTPUT_MODEL
2026-08-21 13:54.22 [DONE ] [Workflow] Profile completed (9.6s)
2026-08-21 13:54.22 [INFO ] [Workflow] Run completed (4m 17s)
2026-08-21 13:54.26 [DONE ] [CLI] Run completed successfully. (4m 26s)
[ Result Summary ]
Experiment experiment_00
Status success
Measurements
Evaluate base✓ 01_graph_optimize✓ 02_graph_quantize✓
Profile base✓ 01_graph_optimize✓ 02_graph_quantize✓ (estimated)
Artifacts
VGF base✓ 01_graph_optimize✓ 02_graph_quantize✓
NPIR base✓ 01_graph_optimize✓ 02_graph_quantize✓
[ Next Steps ]
View results or export artifacts:
$ np report
$ np export
Step 7. View results
np report
Sample output
2026-08-21 14:05.00 [INFO ] [CLI] Generating Execution Report
2026-08-21 14:05.00 [INFO ] [Report] Target Experiment: experiment_00
============================================================
Execution Report
============================================================
Experiment: experiment_00
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Model ┃ Type ┃ Status ┃ Memory(MB) ┃ Latency(ms) ┃ MACs ┃ Params ┃ SNR (vs input) ┃
┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ input_model │ - │ - │ -- │ -- │ 4.1G │ 25.6M │ - │
│ 01_graph_optimize │ graph_optimize │ success │ -- │ -- │ 4.1G │ 25.6M │ 121.06 │
│ 02_graph_quantize │ graph_quantize │ success │ -- │ -- │ 4.1G │ 25.6M │ 0.18 │
└───────────────────┴────────────────┴─────────┴────────────┴─────────────┴──────┴────────┴────────────────┘
[ Artifacts ]
* Config: run.yaml
* Model: 02_graph_quantize/artifacts/model.npir
[ Next Steps ]
Export or sort results:
$ np export
$ np report --sort latency
On RPi5 and other xnnpack-backend projects, Memory(MB) and Latency(ms) show as --: mlia produces MACs and parameters for xnnpack targets only, and full latency and memory estimates from mlia are available only when targeting ethos_u (Alif E8). To get real latency and memory numbers on RPi5, measure directly with on-device profiling.
Sort by a specific metric:
np report --sort latency
np report --sort snr
Step 8. Export the model
Export the optimized model as a .pte file for deployment:
np export
Sample output
2026-08-21 14:10.00 [INFO ] [Export] Exporting Artifacts (Level: deploy)
2026-08-21 14:10.00 [INFO ] [Export] Experiment: experiment_00
============================================================
[Phase 1] Model Compilation
============================================================
============================================================
Summary
============================================================
2026-08-21 14:10.25 [DONE ] [CLI] Export completed successfully. (deploy)
[ Result Summary ]
Output File model.pte
Path /netspresso/workspace/resnet-rpi5/experiment_00/artifacts/model.pte
[ Next Steps ]
To include config or full reproduction data:
$ np export --level config
$ np export --level full
Step 9. Visualize the optimized graph
np visualize generates a link to the graph viewer (probe) rather than opening a browser directly, and the viewer needs a browser session. Bootstrap that once with np visualize auth:
np visualize auth
Sample output
Session bootstrap ready — use EITHER method (both establish the same session):
1) Open in browser (auto-establishes the session):
https://auth.your-deployment.netspresso.ai/api/v1/visualize/authorize?bootstrap=eyJhbGciOi...
2) Or paste this token into the page's auth field (same value as the end of the link above):
──────────────────── TOKEN — copy the line below ────────────────────
eyJhbGciOi...
─────────────────────────────────────────────────────────────────────
This link/token expires in about 179s. Use it promptly.
Open the link (or paste the token) in your browser once. The session then lasts about an hour. Then generate the graph link:
np visualize
Sample output
[Tool] Using --tool probe (default).
- probe : any model format. Supports --compare diff.
- model-explorer : VGF only. Single-graph view.
Pass --tool to silence this notice.
[Context] Experiment: experiment_00 (Detected)
2026-08-21 14:15.00 [DONE ] [CLI] Visualization link generated
https://app.your-deployment.netspresso.ai?target=<target_ref>&baseline=<model_ref>&workspace=<ws_ref>
[ Next Steps ]
Copy the URL and open it in your browser
Open the output to inspect the optimization changes and compare checkpoints side by side. See Visualizer for --compare and other options.
Comparing multiple configurations
To compare different quantization schemes, create additional experiments within the same project:
# Return to project directory
cd ..
# Create a second experiment with W4-A8_dynamic scheme
np experiments create --steps go,gq
cd experiment_01
vi run.yaml # change scheme to W4-A8_dynamic
np run
# Compare experiments from project directory
cd ..
np report
Sample output: project-level
2026-08-21 14:35.00 [INFO ] [CLI] Generating Execution Report
2026-08-21 14:35.00 [INFO ] [Report] Target Project: resnet-rpi5
============================================================
Project Report
============================================================
Project: resnet-rpi5
┏━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Model ┃ Steps ┃ Status ┃ Memory(MB) ┃ Latency(ms) ┃ MACs ┃ Params ┃ SNR (vs input) ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ input_model │ - │ - │ -- │ -- │ 4.1G │ 25.6M │ - │
│ experiment_00 │ GO,GQ │ success │ -- │ -- │ 4.1G │ 25.6M │ 1.48 │
│ experiment_01 │ GO,GQ │ success │ -- │ -- │ 4.1G │ 25.6M │ 0.95 │
└───────────────┴───────┴─────────┴────────────┴─────────────┴──────┴────────┴────────────────┘
[ Next Steps ]
Sort or view experiment details:
$ np report --sort latency
$ cd <experiment> && np report
The project-level report shows experiment_00 (W8-A8) has higher SNR while experiment_01 (W4-A8_dynamic) achieves better compression and lower latency.
To see per-job details within each experiment, run np report --detail:
np report --detail
Sample output
2026-08-21 14:40.00 [INFO ] [CLI] Generating Execution Report
2026-08-21 14:40.00 [INFO ] [Report] Target Project: resnet-rpi5
============================================================
Project Report
============================================================
Project: resnet-rpi5 (detail)
┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Model ┃ Steps ┃ Status ┃ Memory(MB) ┃ Latency(ms) ┃ MACs ┃ Params ┃ SNR (vs input) ┃
┡━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ input_model │ - │ - │ -- │ -- │ 4.1G │ 25.6M │ - │
│ ▶ experiment_00 │ GO,GQ │ success │ -- │ -- │ 4.1G │ 25.6M │ 1.48 │
│ ├ 01_graph_optimize │ │ success │ -- │ -- │ 4.1G │ 25.6M │ 121.06 │
│ └ 02_graph_quantize │ │ success │ -- │ -- │ 4.1G │ 25.6M │ 1.48 │
│ │ │ │ │ │ │ │ │
│ ▶ experiment_01 │ GO,GQ │ success │ -- │ -- │ 4.1G │ 25.6M │ 0.95 │
│ ├ 01_graph_optimize │ │ success │ -- │ -- │ 4.1G │ 25.6M │ 121.06 │
│ └ 02_graph_quantize │ │ success │ -- │ -- │ 4.1G │ 25.6M │ 0.95 │
└───────────────────────┴───────┴─────────┴────────────┴─────────────┴──────┴────────┴────────────────┘
[ Next Steps ]
Sort or view experiment details:
$ np report --sort latency
$ cd <experiment> && np report
Next steps
- Visualizer: Inspect the optimized graph before deploying with
np visualize - Tutorial 3: Large language model (LLM): Optimize a language model with AQ + GO + GQ steps
- Features: Graph Optimizer: What GO actually does to the graph
- Features: Graph Quantizer: Calibration methods and AMP
- run.yaml Configuration: Full pipeline configuration reference