This example demonstrates running an ONNX machine-learning model inside an ICP canister. The canister accepts an image from the user and runs image classification inference using the Tract ONNX inference engine with the MobileNet v2-7 model.
The example uses the WASI polyfill to run Tract (which relies on POSIX file I/O) inside the deterministic ICP runtime, and Wasm SIMD instructions for faster inference.
The example consists of two canisters:
- backend — embeds the Tract ONNX inference engine with the MobileNet v2-7 model.
It provides two classification endpoints:
classify(image)— update call, runs under replicated execution on all nodes (secure, slower).classify_query(image)— query call, runs on a single node (fast, not replicated).
- frontend — serves the web UI (HTML/JS/CSS) from which users upload images and view results.
- Node.js v18+
- icp-cli:
npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm - Rust v1.85+ with
wasm32-wasip1target:rustup target add wasm32-wasip1 - wasi2ic:
cargo install wasi2ic
wasm-opt is installed automatically on first deploy if not already present.
git clone https://github.com/dfinity/examples
cd examples/rust/image-classificationDownload the MobileNet v2-7 model:
./download_model.shicp network start -d
icp deploy
bash test.sh
icp network stopIf the deployment is successful, the CLI will print the frontend URL. Open that URL in a browser to interact with the canister.
For frontend development with hot reload:
npm run dev --prefix frontendOnly needed if you change the backend endpoints. Requires candid-extractor (cargo install candid-extractor) and ic_cdk::export_candid!() at the end of backend/src/lib.rs (already present):
icp build backend && candid-extractor target/wasm32-wasip1/release/backend.wasm > backend/backend.didRefer to the ICP security best practices for guidance on securing your canister.