Skip to content

Commit

Permalink
Add an initial wasi-nn implementation for Wasmtime (#2208)
Browse files Browse the repository at this point in the history
* Add an initial wasi-nn implementation for Wasmtime

This change adds a crate, `wasmtime-wasi-nn`, that uses `wiggle` to expose the current state of the wasi-nn API and `openvino` to implement the exposed functions. It includes an end-to-end test demonstrating how to do classification using wasi-nn:
 - `crates/wasi-nn/tests/classification-example` contains Rust code that is compiled to the `wasm32-wasi` target and run with a Wasmtime embedding that exposes the wasi-nn calls
 - the example uses Rust bindings for wasi-nn contained in `crates/wasi-nn/tests/wasi-nn-rust-bindings`; this crate contains code generated by `witx-bindgen` and eventually should be its own standalone crate

* Test wasi-nn as a CI step

This change adds:
 - a GitHub action for installing OpenVINO
 - a script, `ci/run-wasi-nn-example.sh`, to run the classification example
  • Loading branch information
abrown authored and cfallin committed Nov 30, 2020
1 parent 30f98ea commit e93187a
Show file tree
Hide file tree
Showing 33 changed files with 1,554 additions and 1 deletion.
8 changes: 8 additions & 0 deletions .github/actions/install-openvino/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# install-openvino

A GitHub action to install OpenVINO from a package repository. This is only necessary for `wasi-nn` support but there
are enough steps here to package the functionality separately and avoid cluttering the CI.

Future improvements:
- make this installer work for different OS/distributions (e.g. https://docs.openvinotoolkit.org/latest/openvino_docs_install_guides_installing_openvino_windows.html)
- it would be nice to output the install directory (i.e. `/opt/intel/openvino`)
14 changes: 14 additions & 0 deletions .github/actions/install-openvino/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: 'Install OpenVINO'
description: 'Install OpenVINO binaries from a package repository; this is significantly faster than building from source'

inputs:
version:
description: 'The release version of OpenVINO to install'
required: false
default: '2020.4.287'

runs:
using: composite
steps:
- run: ${{ github.action_path }}/install.sh ${{ inputs.version }}
shell: bash
16 changes: 16 additions & 0 deletions .github/actions/install-openvino/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

set -e

# Retrieve OpenVINO checksum.
wget https://apt.repos.intel.com/openvino/2020/GPG-PUB-KEY-INTEL-OPENVINO-2020
echo '5f5cff8a2d26ba7de91942bd0540fa4d GPG-PUB-KEY-INTEL-OPENVINO-2020' > CHECKSUM
md5sum --check CHECKSUM

# Add OpenVINO repository (deb).
sudo apt-key add GPG-PUB-KEY-INTEL-OPENVINO-2020
echo "deb https://apt.repos.intel.com/openvino/2020 all main" | sudo tee /etc/apt/sources.list.d/intel-openvino-2020.list
sudo apt update

# Install OpenVINO package.
sudo apt install -y intel-openvino-runtime-ubuntu18-$1
20 changes: 20 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
runs-on: ubuntu-latest
env:
RUSTDOCFLAGS: -Dbroken_intra_doc_links
OPENVINO_SKIP_LINKING: 1
steps:
- uses: actions/checkout@v2
with:
Expand Down Expand Up @@ -252,6 +253,7 @@ jobs:
--all \
--exclude lightbeam \
--exclude wasmtime-lightbeam \
--exclude wasmtime-wasi-nn \
--exclude peepmatic \
--exclude peepmatic-automata \
--exclude peepmatic-fuzzing \
Expand Down Expand Up @@ -304,6 +306,23 @@ jobs:
CARGO_VERSION: "+nightly"
RUST_BACKTRACE: 1

# Build and test the wasi-nn module.
test_wasi_nn:
name: Test wasi-nn module
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- uses: ./.github/actions/install-rust
with:
toolchain: nightly-2020-08-25
- run: rustup target add wasm32-wasi
- uses: ./.github/actions/install-openvino
- run: ./ci/run-wasi-nn-example.sh
env:
RUST_BACKTRACE: 1

# Verify that cranelift's code generation is deterministic
meta_determinist_check:
name: Meta deterministic check
Expand Down Expand Up @@ -411,6 +430,7 @@ jobs:
--all \
--exclude lightbeam \
--exclude wasmtime-lightbeam \
--exclude wasmtime-wasi-nn \
--exclude peepmatic \
--exclude peepmatic-automata \
--exclude peepmatic-fuzzing \
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
[submodule "WASI"]
path = crates/wasi-common/WASI
url = https://github.com/WebAssembly/WASI
[submodule "crates/wasi-nn/spec"]
path = crates/wasi-nn/spec
url = https://github.com/WebAssembly/wasi-nn
127 changes: 127 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ wasmtime-jit = { path = "crates/jit", version = "0.21.0" }
wasmtime-obj = { path = "crates/obj", version = "0.21.0" }
wasmtime-wast = { path = "crates/wast", version = "0.21.0" }
wasmtime-wasi = { path = "crates/wasi", version = "0.21.0" }
wasmtime-wasi-nn = { path = "crates/wasi-nn", version = "0.21.0", optional = true }
wasi-common = { path = "crates/wasi-common", version = "0.21.0" }
structopt = { version = "0.3.5", features = ["color", "suggestions"] }
object = { version = "0.22.0", default-features = false, features = ["write"] }
Expand Down Expand Up @@ -80,6 +81,7 @@ default = ["jitdump", "wasmtime/wat", "wasmtime/parallel-compilation"]
lightbeam = ["wasmtime/lightbeam"]
jitdump = ["wasmtime/jitdump"]
vtune = ["wasmtime/vtune"]
wasi-nn = ["wasmtime-wasi-nn"]

# Try the experimental, work-in-progress new x86_64 backend. This is not stable
# as of June 2020.
Expand Down
1 change: 1 addition & 0 deletions ci/run-experimental-x64-ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ cargo $CARGO_VERSION \
--features experimental_x64 \
--all \
--exclude wasmtime-lightbeam \
--exclude wasmtime-wasi-nn \
--exclude peepmatic \
--exclude peepmatic-automata \
--exclude peepmatic-fuzzing \
Expand Down
35 changes: 35 additions & 0 deletions ci/run-wasi-nn-example.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/bin/bash

# The following script demonstrates how to execute a machine learning inference using the wasi-nn module optionally
# compiled into Wasmtime. Calling it will download the necessary model and tensor files stored separately in $FIXTURE
# into $TMP_DIR (optionally pass a directory with existing files as the first argument to re-try the script). Then,
# it will compile the example code in crates/wasi-nn/tests/example into a Wasm file that is subsequently
# executed with the Wasmtime CLI.
set -e
WASMTIME_DIR=$(dirname "$0" | xargs dirname)
FIXTURE=https://gist.github.com/abrown/c7847bf3701f9efbb2070da1878542c1/raw/07a9f163994b0ff8f0d7c5a5c9645ec3d8b24024

# Inform the environment of OpenVINO library locations. Then we use OPENVINO_INSTALL_DIR below to avoid building all of
# OpenVINO from source (quite slow).
source /opt/intel/openvino/bin/setupvars.sh

# Build Wasmtime with wasi-nn enabled; we attempt this first to avoid extra work if the build fails.
OPENVINO_INSTALL_DIR=/opt/intel/openvino cargo build -p wasmtime-cli --features wasi-nn

# Download all necessary test fixtures to the temporary directory.
TMP_DIR=${1:-$(mktemp -d -t ci-XXXXXXXXXX)}
wget --no-clobber --directory-prefix=$TMP_DIR $FIXTURE/frozen_inference_graph.bin
wget --no-clobber --directory-prefix=$TMP_DIR $FIXTURE/frozen_inference_graph.xml
wget --no-clobber --directory-prefix=$TMP_DIR $FIXTURE/tensor-1x3x300x300-f32.bgr

# Now build an example that uses the wasi-nn API.
pushd $WASMTIME_DIR/crates/wasi-nn/examples/classification-example
cargo build --release --target=wasm32-wasi
cp target/wasm32-wasi/release/wasi-nn-example.wasm $TMP_DIR
popd

# Run the example in Wasmtime (note that the example uses `fixture` as the expected location of the model/tensor files).
OPENVINO_INSTALL_DIR=/opt/intel/openvino cargo run --features wasi-nn -- run --mapdir fixture::$TMP_DIR $TMP_DIR/wasi-nn-example.wasm

# Clean up.
rm -rf $TMP_DIR
29 changes: 29 additions & 0 deletions crates/wasi-nn/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "wasmtime-wasi-nn"
version = "0.21.0"
authors = ["The Wasmtime Project Developers"]
description = "Wasmtime implementation of the wasi-nn API"
documentation = "https://docs.rs/wasmtime-wasi-nn"
license = "Apache-2.0 WITH LLVM-exception"
categories = ["wasm", "computer-vision"]
keywords = ["webassembly", "wasm", "neural network"]
repository = "https://github.com/bytecodealliance/wasmtime"
readme = "README.md"
edition = "2018"

[dependencies]
# These dependencies are necessary for the witx-generation macros to work:
anyhow = "1.0"
log = { version = "0.4", default-features = false }
wasmtime = { path = "../wasmtime", version = "0.21.0", default-features = false }
wasmtime-runtime = { path = "../runtime", version = "0.21.0" }
wasmtime-wiggle = { path = "../wiggle/wasmtime", version = "0.21.0" }
wasmtime-wasi = { path = "../wasi", version = "0.21.0" }
wiggle = { path = "../wiggle", version = "0.21.0" }

# These dependencies are necessary for the wasi-nn implementation:
openvino = "0.1.5"
thiserror = "1.0"

[badges]
maintenance = { status = "experimental" }
Loading

0 comments on commit e93187a

Please sign in to comment.