diff --git a/Cargo.toml b/Cargo.toml index c6f5d8b1..8eafd175 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ exclude = [ "examples/rust-kv", "examples/rust-params", "examples/rust-wasi-nn", + "examples/rust-wasi-nn-preload", ] [workspace.dependencies] diff --git a/crates/worker/src/features/wasi_nn.rs b/crates/worker/src/features/wasi_nn.rs index 0d25cd7e..e1ee98d0 100644 --- a/crates/worker/src/features/wasi_nn.rs +++ b/crates/worker/src/features/wasi_nn.rs @@ -2,12 +2,100 @@ // SPDX-License-Identifier: Apache-2.0 use serde::Deserialize; +use std::fmt::Display; +use std::path::{Path, PathBuf}; +use wasmtime_wasi_nn::backend::openvino::OpenvinoBackend; +use wasmtime_wasi_nn::Backend; -pub const WASI_NN_BACKEND_OPENVINO: &str = "openvino"; +/// Available Machine Learning backends +#[derive(Deserialize, Clone, Default)] +#[serde(rename_all = "lowercase")] +pub enum WasiNnBackend { + /// None + #[default] + None, + /// OpenVINO backend + Openvino, +} + +impl WasiNnBackend { + /// Convert the given enum variant into a WASI-NN backend. + pub fn to_backend(&self) -> Option { + match self { + Self::None => None, + Self::Openvino => Some(Backend::from(OpenvinoBackend::default())), + } + } +} + +impl Display for WasiNnBackend { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::None => write!(f, "none"), + Self::Openvino => write!(f, "openvino"), + } + } +} + +/// Available providers to load Wasi NN models. +#[derive(Deserialize, Clone, Debug)] +#[serde(rename_all = "lowercase", tag = "type")] +pub enum WasiNnModelProvider { + /// Load it from the local filesystem + Local { dir: PathBuf }, +} + +impl Default for WasiNnModelProvider { + fn default() -> Self { + Self::Local { + dir: PathBuf::from("./"), + } + } +} + +#[derive(Deserialize, Clone, Default)] +#[serde(default)] +pub struct WasiNnModel { + /// The provider to retrieve the given model. + provider: WasiNnModelProvider, + /// Backend to run this specific model + backend: WasiNnBackend, +} + +impl WasiNnModel { + /// Provide the graph configuration from the current model. Depending on the + /// provider, it may need to perform other tasks before running it. + pub fn build_graph_data(&self, worker_path: &Path) -> (String, String) { + match &self.provider { + WasiNnModelProvider::Local { dir } => { + let data = if dir.is_relative() { + worker_path.parent().map(|parent| { + ( + self.backend.clone().to_string(), + parent.join(dir).to_string_lossy().to_string(), + ) + }) + } else { + None + }; + + data.unwrap_or_else(|| { + // Absolute path or best effort if it cannot retrieve the parent path + ( + self.backend.clone().to_string(), + dir.to_string_lossy().to_string(), + ) + }) + } + } + } +} #[derive(Deserialize, Clone, Default)] #[serde(default)] pub struct WasiNnConfig { /// List of Machine Learning backends. For now, only "openvino" option is supported - pub allowed_backends: Vec, + pub allowed_backends: Vec, + /// List of preloaded models. It allows you to get the models from different strategies. + pub preload_models: Vec, } diff --git a/crates/worker/src/lib.rs b/crates/worker/src/lib.rs index bd14135a..3ff88cf6 100644 --- a/crates/worker/src/lib.rs +++ b/crates/worker/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 VMware, Inc. +// Copyright 2022-2023 VMware, Inc. // SPDX-License-Identifier: Apache-2.0 mod bindings; @@ -12,7 +12,6 @@ use actix_web::HttpRequest; use bindings::http::{add_to_linker as http_add_to_linker, HttpBindings}; use config::Config; use errors::Result; -use features::wasi_nn::WASI_NN_BACKEND_OPENVINO; use io::{WasmInput, WasmOutput}; use sha256::digest as sha256_digest; use std::fs; @@ -23,7 +22,7 @@ use stdio::Stdio; use wasi_common::WasiCtx; use wasmtime::{Engine, Linker, Module, Store}; use wasmtime_wasi::{ambient_authority, Dir, WasiCtxBuilder}; -use wasmtime_wasi_nn::WasiNnCtx; +use wasmtime_wasi_nn::{InMemoryRegistry, Registry, WasiNnCtx}; use wws_config::Config as ProjectConfig; use wws_runtimes::{init_runtime, Runtime}; @@ -137,37 +136,50 @@ impl Worker { // WASI-NN let allowed_backends = &self.config.features.wasi_nn.allowed_backends; - - let wasi_nn = if !allowed_backends.is_empty() { - // For now, we only support OpenVINO - if allowed_backends.len() != 1 - || !allowed_backends.contains(&WASI_NN_BACKEND_OPENVINO.to_string()) - { - eprintln!("❌ The only WASI-NN supported backend name is \"{WASI_NN_BACKEND_OPENVINO}\". Please, update your config."); - None - } else { - wasmtime_wasi_nn::witx::add_to_linker(&mut linker, |s: &mut WorkerState| { - Arc::get_mut(s.wasi_nn.as_mut().unwrap()) - .expect("wasi-nn is not implemented with multi-threading support") - }) - .map_err(|_| { - errors::WorkerError::RuntimeError( - wws_runtimes::errors::RuntimeError::WasiContextError, - ) - })?; - - let (backends, registry) = wasmtime_wasi_nn::preload(&[]).map_err(|_| { - errors::WorkerError::RuntimeError( - wws_runtimes::errors::RuntimeError::WasiContextError, - ) - })?; - - Some(Arc::new(WasiNnCtx::new(backends, registry))) + let preload_models = &self.config.features.wasi_nn.preload_models; + + let wasi_nn = if !preload_models.is_empty() { + // Preload the models on the host. + let graphs = preload_models + .iter() + .map(|m| m.build_graph_data(&self.path)) + .collect::>(); + let (backends, registry) = wasmtime_wasi_nn::preload(&graphs).map_err(|_| { + errors::WorkerError::RuntimeError( + wws_runtimes::errors::RuntimeError::WasiContextError, + ) + })?; + + Some(Arc::new(WasiNnCtx::new(backends, registry))) + } else if !allowed_backends.is_empty() { + let registry = Registry::from(InMemoryRegistry::new()); + let mut backends = Vec::new(); + + // Load the given backends: + for b in allowed_backends.iter() { + if let Some(backend) = b.to_backend() { + backends.push(backend); + } } + + Some(Arc::new(WasiNnCtx::new(backends, registry))) } else { None }; + // Load the Wasi NN linker + if wasi_nn.is_some() { + wasmtime_wasi_nn::witx::add_to_linker(&mut linker, |s: &mut WorkerState| { + Arc::get_mut(s.wasi_nn.as_mut().unwrap()) + .expect("wasi-nn is not implemented with multi-threading support") + }) + .map_err(|_| { + errors::WorkerError::RuntimeError( + wws_runtimes::errors::RuntimeError::WasiContextError, + ) + })?; + } + // Pass to the runtime to add any WASI specific requirement self.runtime.prepare_wasi_ctx(&mut wasi_builder)?; diff --git a/examples/Makefile b/examples/Makefile index ad7dfbbd..264d31a1 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -25,6 +25,11 @@ rust-wasi-nn: cargo build --target wasm32-wasi --release && \ mv target/wasm32-wasi/release/rust-wasi-nn.wasm "./inference.wasm" +rust-wasi-nn-preload: + cd rust-wasi-nn-preload && \ + cargo build --target wasm32-wasi --release && \ + mv target/wasm32-wasi/release/rust-wasi-nn-preload.wasm "./inference.wasm" + rust-pdf-create: cd rust-pdf-create && \ cargo build --target wasm32-wasi --release && \ diff --git a/examples/rust-wasi-nn-preload/.gitignore b/examples/rust-wasi-nn-preload/.gitignore new file mode 100644 index 00000000..74b70436 --- /dev/null +++ b/examples/rust-wasi-nn-preload/.gitignore @@ -0,0 +1,4 @@ +_images/image.jpg +_models/**/*.bin +_models/**/*.xml +!inference.wasm diff --git a/examples/rust-wasi-nn-preload/Cargo.lock b/examples/rust-wasi-nn-preload/Cargo.lock new file mode 100644 index 00000000..b197a786 --- /dev/null +++ b/examples/rust-wasi-nn-preload/Cargo.lock @@ -0,0 +1,544 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anyhow" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" + +[[package]] +name = "async-trait" +version = "0.1.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "image" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "gif", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", + "tiff", +] + +[[package]] +name = "image2tensor" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b172871a8ff226b37c2905a457866e2d950037c325699575d4bea5b1c7f32fdb" +dependencies = [ + "image", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "png" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pulldown-cmark" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rust-wasi-nn-preload" +version = "0.1.0" +dependencies = [ + "anyhow", + "base64", + "image2tensor", + "serde", + "serde_json", + "wasi-nn", + "wasm-workers-rs", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "serde" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "serde_json" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "tiff" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi-nn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7031683cc05a71515d9200fb159b28d717ded3c40dbb979d1602cf46f3a68f40" +dependencies = [ + "thiserror", +] + +[[package]] +name = "wasm-workers-rs" +version = "1.5.0" +dependencies = [ + "anyhow", + "base64", + "http", + "serde", + "serde_json", + "wit-bindgen-rust", + "worker", +] + +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + +[[package]] +name = "wit-bindgen-gen-core" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "anyhow", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-gen-rust" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "heck", + "wit-bindgen-gen-core", +] + +[[package]] +name = "wit-bindgen-gen-rust-wasm" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "heck", + "wit-bindgen-gen-core", + "wit-bindgen-gen-rust", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "async-trait", + "bitflags", + "wit-bindgen-rust-impl", +] + +[[package]] +name = "wit-bindgen-rust-impl" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "proc-macro2", + "syn 1.0.109", + "wit-bindgen-gen-core", + "wit-bindgen-gen-rust-wasm", +] + +[[package]] +name = "wit-parser" +version = "0.2.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=cb871cfa1ee460b51eb1d144b175b9aab9c50aba#cb871cfa1ee460b51eb1d144b175b9aab9c50aba" +dependencies = [ + "anyhow", + "id-arena", + "pulldown-cmark", + "unicode-normalization", + "unicode-xid", +] + +[[package]] +name = "worker" +version = "1.5.0" +dependencies = [ + "anyhow", + "http", + "quote", + "serde", + "serde_json", + "syn 1.0.109", + "wasi", +] diff --git a/examples/rust-wasi-nn-preload/Cargo.toml b/examples/rust-wasi-nn-preload/Cargo.toml new file mode 100644 index 00000000..92593e05 --- /dev/null +++ b/examples/rust-wasi-nn-preload/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rust-wasi-nn-preload" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +wasi-nn = "0.6.0" +anyhow = "1.0.63" +image2tensor = "0.2.0" +wasm-workers-rs = { path = "../../kits/rust" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.85" +base64 = "0.21.2" diff --git a/examples/rust-wasi-nn-preload/README.md b/examples/rust-wasi-nn-preload/README.md new file mode 100644 index 00000000..16ac0419 --- /dev/null +++ b/examples/rust-wasi-nn-preload/README.md @@ -0,0 +1,53 @@ +# Rust WASI-NN example + +Compile a Rust that performs Machine Learning (ML) inference with [WASI-NN](https://github.com/WebAssembly/wasi-nn) to WebAssembly and run it in Wasm Workers Server. + +## Prerequisites + +* Wasm Workers Server (wws): + + ```shell-session + curl -fsSL https://workers.wasmlabs.dev/install | bash + ``` + +* [Install Rust with rustup](https://www.rust-lang.org/tools/install) +* Install the `wasm32-wasi` target: + + ```shell-session + rustup target add wasm32-wasi + ``` + +* Install the [OpenVINO™ Runtime (2023.0.1)](https://docs.openvino.ai/2023.0) + * [Windows](https://docs.openvino.ai/2023.0/openvino_docs_install_guides_installing_openvino_from_archive_windows.html) + * [Linux](https://docs.openvino.ai/2023.0/openvino_docs_install_guides_installing_openvino_from_archive_linux.html) + * [MacOS](https://docs.openvino.ai/2023.0/openvino_docs_install_guides_installing_openvino_from_archive_macos.html) +* Configure the OpenVINO™ environment: + * [Windows](https://docs.openvino.ai/2023.0/openvino_docs_install_guides_installing_openvino_from_archive_windows.html#step-2-configure-the-environment) + * [Linux](https://docs.openvino.ai/2023.0/openvino_docs_install_guides_installing_openvino_from_archive_linux.html#step-2-configure-the-environment) + * [MacOS](https://docs.openvino.ai/2023.0/openvino_docs_install_guides_installing_openvino_from_archive_macos.html#step-2-configure-the-environment) +* Run the `prepare.sh` script to download the ML model: + + ```shell-session + $ ./prepare.sh + + Downloading the model from https://github.com/intel/openvino-rs/tree/main/crates/openvino/tests/fixtures/mobilenet + .... + Finished! + ``` + +## Build + +```shell-session +cargo build --target wasm32-wasi --release && \ + cp target/wasm32-wasi/release/rust-wasi-nn.wasm ./inference.wasm +``` + +## Run + +```shell-session +wws . +``` + +## Resources + +* [Rust documentation](https://workers.wasmlabs.dev/docs/languages/rust) diff --git a/examples/rust-wasi-nn-preload/_data/dataset.json b/examples/rust-wasi-nn-preload/_data/dataset.json new file mode 100644 index 00000000..240ef510 --- /dev/null +++ b/examples/rust-wasi-nn-preload/_data/dataset.json @@ -0,0 +1,1004 @@ +{ + "names": [ + "tench, Tinca tinca", + "goldfish, Carassius auratus", + "great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias", + "tiger shark, Galeocerdo cuvieri", + "hammerhead, hammerhead shark", + "electric ray, crampfish, numbfish, torpedo", + "stingray", + "cock", + "hen", + "ostrich, Struthio camelus", + "brambling, Fringilla montifringilla", + "goldfinch, Carduelis carduelis", + "house finch, linnet, Carpodacus mexicanus", + "junco, snowbird", + "indigo bunting, indigo finch, indigo bird, Passerina cyanea", + "robin, American robin, Turdus migratorius", + "bulbul", + "jay", + "magpie", + "chickadee", + "water ouzel, dipper", + "kite", + "bald eagle, American eagle, Haliaeetus leucocephalus", + "vulture", + "great grey owl, great gray owl, Strix nebulosa", + "European fire salamander, Salamandra salamandra", + "common newt, Triturus vulgaris", + "eft", + "spotted salamander, Ambystoma maculatum", + "axolotl, mud puppy, Ambystoma mexicanum", + "bullfrog, Rana catesbeiana", + "tree frog, tree-frog", + "tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui", + "loggerhead, loggerhead turtle, Caretta caretta", + "leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea", + "mud turtle", + "terrapin", + "box turtle, box tortoise", + "banded gecko", + "common iguana, iguana, Iguana iguana", + "American chameleon, anole, Anolis carolinensis", + "whiptail, whiptail lizard", + "agama", + "frilled lizard, Chlamydosaurus kingi", + "alligator lizard", + "Gila monster, Heloderma suspectum", + "green lizard, Lacerta viridis", + "African chameleon, Chamaeleo chamaeleon", + "Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis", + "African crocodile, Nile crocodile, Crocodylus niloticus", + "American alligator, Alligator mississipiensis", + "triceratops", + "thunder snake, worm snake, Carphophis amoenus", + "ringneck snake, ring-necked snake, ring snake", + "hognose snake, puff adder, sand viper", + "green snake, grass snake", + "king snake, kingsnake", + "garter snake, grass snake", + "water snake", + "vine snake", + "night snake, Hypsiglena torquata", + "boa constrictor, Constrictor constrictor", + "rock python, rock snake, Python sebae", + "Indian cobra, Naja naja", + "green mamba", + "sea snake", + "horned viper, cerastes, sand viper, horned asp, Cerastes cornutus", + "diamondback, diamondback rattlesnake, Crotalus adamanteus", + "sidewinder, horned rattlesnake, Crotalus cerastes", + "trilobite", + "harvestman, daddy longlegs, Phalangium opilio", + "scorpion", + "black and gold garden spider, Argiope aurantia", + "barn spider, Araneus cavaticus", + "garden spider, Aranea diademata", + "black widow, Latrodectus mactans", + "tarantula", + "wolf spider, hunting spider", + "tick", + "centipede", + "black grouse", + "ptarmigan", + "ruffed grouse, partridge, Bonasa umbellus", + "prairie chicken, prairie grouse, prairie fowl", + "peacock", + "quail", + "partridge", + "African grey, African gray, Psittacus erithacus", + "macaw", + "sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita", + "lorikeet", + "coucal", + "bee eater", + "hornbill", + "hummingbird", + "jacamar", + "toucan", + "drake", + "red-breasted merganser, Mergus serrator", + "goose", + "black swan, Cygnus atratus", + "tusker", + "echidna, spiny anteater, anteater", + "platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus", + "wallaby, brush kangaroo", + "koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus", + "wombat", + "jellyfish", + "sea anemone, anemone", + "brain coral", + "flatworm, platyhelminth", + "nematode, nematode worm, roundworm", + "conch", + "snail", + "slug", + "sea slug, nudibranch", + "chiton, coat-of-mail shell, sea cradle, polyplacophore", + "chambered nautilus, pearly nautilus, nautilus", + "Dungeness crab, Cancer magister", + "rock crab, Cancer irroratus", + "fiddler crab", + "king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica", + "American lobster, Northern lobster, Maine lobster, Homarus americanus", + "spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish", + "crayfish, crawfish, crawdad, crawdaddy", + "hermit crab", + "isopod", + "white stork, Ciconia ciconia", + "black stork, Ciconia nigra", + "spoonbill", + "flamingo", + "little blue heron, Egretta caerulea", + "American egret, great white heron, Egretta albus", + "bittern", + "crane", + "limpkin, Aramus pictus", + "European gallinule, Porphyrio porphyrio", + "American coot, marsh hen, mud hen, water hen, Fulica americana", + "bustard", + "ruddy turnstone, Arenaria interpres", + "red-backed sandpiper, dunlin, Erolia alpina", + "redshank, Tringa totanus", + "dowitcher", + "oystercatcher, oyster catcher", + "pelican", + "king penguin, Aptenodytes patagonica", + "albatross, mollymawk", + "grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus", + "killer whale, killer, orca, grampus, sea wolf, Orcinus orca", + "dugong, Dugong dugon", + "sea lion", + "Chihuahua", + "Japanese spaniel", + "Maltese dog, Maltese terrier, Maltese", + "Pekinese, Pekingese, Peke", + "Shih-Tzu", + "Blenheim spaniel", + "papillon", + "toy terrier", + "Rhodesian ridgeback", + "Afghan hound, Afghan", + "basset, basset hound", + "beagle", + "bloodhound, sleuthhound", + "bluetick", + "black-and-tan coonhound", + "Walker hound, Walker foxhound", + "English foxhound", + "redbone", + "borzoi, Russian wolfhound", + "Irish wolfhound", + "Italian greyhound", + "whippet", + "Ibizan hound, Ibizan Podenco", + "Norwegian elkhound, elkhound", + "otterhound, otter hound", + "Saluki, gazelle hound", + "Scottish deerhound, deerhound", + "Weimaraner", + "Staffordshire bullterrier, Staffordshire bull terrier", + "American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier", + "Bedlington terrier", + "Border terrier", + "Kerry blue terrier", + "Irish terrier", + "Norfolk terrier", + "Norwich terrier", + "Yorkshire terrier", + "wire-haired fox terrier", + "Lakeland terrier", + "Sealyham terrier, Sealyham", + "Airedale, Airedale terrier", + "cairn, cairn terrier", + "Australian terrier", + "Dandie Dinmont, Dandie Dinmont terrier", + "Boston bull, Boston terrier", + "miniature schnauzer", + "giant schnauzer", + "standard schnauzer", + "Scotch terrier, Scottish terrier, Scottie", + "Tibetan terrier, chrysanthemum dog", + "silky terrier, Sydney silky", + "soft-coated wheaten terrier", + "West Highland white terrier", + "Lhasa, Lhasa apso", + "flat-coated retriever", + "curly-coated retriever", + "golden retriever", + "Labrador retriever", + "Chesapeake Bay retriever", + "German short-haired pointer", + "vizsla, Hungarian pointer", + "English setter", + "Irish setter, red setter", + "Gordon setter", + "Brittany spaniel", + "clumber, clumber spaniel", + "English springer, English springer spaniel", + "Welsh springer spaniel", + "cocker spaniel, English cocker spaniel, cocker", + "Sussex spaniel", + "Irish water spaniel", + "kuvasz", + "schipperke", + "groenendael", + "malinois", + "briard", + "kelpie", + "komondor", + "Old English sheepdog, bobtail", + "Shetland sheepdog, Shetland sheep dog, Shetland", + "collie", + "Border collie", + "Bouvier des Flandres, Bouviers des Flandres", + "Rottweiler", + "German shepherd, German shepherd dog, German police dog, alsatian", + "Doberman, Doberman pinscher", + "miniature pinscher", + "Greater Swiss Mountain dog", + "Bernese mountain dog", + "Appenzeller", + "EntleBucher", + "boxer", + "bull mastiff", + "Tibetan mastiff", + "French bulldog", + "Great Dane", + "Saint Bernard, St Bernard", + "Eskimo dog, husky", + "malamute, malemute, Alaskan malamute", + "Siberian husky", + "dalmatian, coach dog, carriage dog", + "affenpinscher, monkey pinscher, monkey dog", + "basenji", + "pug, pug-dog", + "Leonberg", + "Newfoundland, Newfoundland dog", + "Great Pyrenees", + "Samoyed, Samoyede", + "Pomeranian", + "chow, chow chow", + "keeshond", + "Brabancon griffon", + "Pembroke, Pembroke Welsh corgi", + "Cardigan, Cardigan Welsh corgi", + "toy poodle", + "miniature poodle", + "standard poodle", + "Mexican hairless", + "timber wolf, grey wolf, gray wolf, Canis lupus", + "white wolf, Arctic wolf, Canis lupus tundrarum", + "red wolf, maned wolf, Canis rufus, Canis niger", + "coyote, prairie wolf, brush wolf, Canis latrans", + "dingo, warrigal, warragal, Canis dingo", + "dhole, Cuon alpinus", + "African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus", + "hyena, hyaena", + "red fox, Vulpes vulpes", + "kit fox, Vulpes macrotis", + "Arctic fox, white fox, Alopex lagopus", + "grey fox, gray fox, Urocyon cinereoargenteus", + "tabby, tabby cat", + "tiger cat", + "Persian cat", + "Siamese cat, Siamese", + "Egyptian cat", + "cougar, puma, catamount, mountain lion, painter, panther, Felis concolor", + "lynx, catamount", + "leopard, Panthera pardus", + "snow leopard, ounce, Panthera uncia", + "jaguar, panther, Panthera onca, Felis onca", + "lion, king of beasts, Panthera leo", + "tiger, Panthera tigris", + "cheetah, chetah, Acinonyx jubatus", + "brown bear, bruin, Ursus arctos", + "American black bear, black bear, Ursus americanus, Euarctos americanus", + "ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus", + "sloth bear, Melursus ursinus, Ursus ursinus", + "mongoose", + "meerkat, mierkat", + "tiger beetle", + "ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle", + "ground beetle, carabid beetle", + "long-horned beetle, longicorn, longicorn beetle", + "leaf beetle, chrysomelid", + "dung beetle", + "rhinoceros beetle", + "weevil", + "fly", + "bee", + "ant, emmet, pismire", + "grasshopper, hopper", + "cricket", + "walking stick, walkingstick, stick insect", + "cockroach, roach", + "mantis, mantid", + "cicada, cicala", + "leafhopper", + "lacewing, lacewing fly", + "dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk", + "damselfly", + "admiral", + "ringlet, ringlet butterfly", + "monarch, monarch butterfly, milkweed butterfly, Danaus plexippus", + "cabbage butterfly", + "sulphur butterfly, sulfur butterfly", + "lycaenid, lycaenid butterfly", + "starfish, sea star", + "sea urchin", + "sea cucumber, holothurian", + "wood rabbit, cottontail, cottontail rabbit", + "hare", + "Angora, Angora rabbit", + "hamster", + "porcupine, hedgehog", + "fox squirrel, eastern fox squirrel, Sciurus niger", + "marmot", + "beaver", + "guinea pig, Cavia cobaya", + "sorrel", + "zebra", + "hog, pig, grunter, squealer, Sus scrofa", + "wild boar, boar, Sus scrofa", + "warthog", + "hippopotamus, hippo, river horse, Hippopotamus amphibius", + "ox", + "water buffalo, water ox, Asiatic buffalo, Bubalus bubalis", + "bison", + "ram, tup", + "bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis", + "ibex, Capra ibex", + "hartebeest", + "impala, Aepyceros melampus", + "gazelle", + "Arabian camel, dromedary, Camelus dromedarius", + "llama", + "weasel", + "mink", + "polecat, fitch, foulmart, foumart, Mustela putorius", + "black-footed ferret, ferret, Mustela nigripes", + "otter", + "skunk, polecat, wood pussy", + "badger", + "armadillo", + "three-toed sloth, ai, Bradypus tridactylus", + "orangutan, orang, orangutang, Pongo pygmaeus", + "gorilla, Gorilla gorilla", + "chimpanzee, chimp, Pan troglodytes", + "gibbon, Hylobates lar", + "siamang, Hylobates syndactylus, Symphalangus syndactylus", + "guenon, guenon monkey", + "patas, hussar monkey, Erythrocebus patas", + "baboon", + "macaque", + "langur", + "colobus, colobus monkey", + "proboscis monkey, Nasalis larvatus", + "marmoset", + "capuchin, ringtail, Cebus capucinus", + "howler monkey, howler", + "titi, titi monkey", + "spider monkey, Ateles geoffroyi", + "squirrel monkey, Saimiri sciureus", + "Madagascar cat, ring-tailed lemur, Lemur catta", + "indri, indris, Indri indri, Indri brevicaudatus", + "Indian elephant, Elephas maximus", + "African elephant, Loxodonta africana", + "lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens", + "giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca", + "barracouta, snoek", + "eel", + "coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch", + "rock beauty, Holocanthus tricolor", + "anemone fish", + "sturgeon", + "gar, garfish, garpike, billfish, Lepisosteus osseus", + "lionfish", + "puffer, pufferfish, blowfish, globefish", + "abacus", + "abaya", + "academic gown, academic robe, judge's robe", + "accordion, piano accordion, squeeze box", + "acoustic guitar", + "aircraft carrier, carrier, flattop, attack aircraft carrier", + "airliner", + "airship, dirigible", + "altar", + "ambulance", + "amphibian, amphibious vehicle", + "analog clock", + "apiary, bee house", + "apron", + "ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin", + "assault rifle, assault gun", + "backpack, back pack, knapsack, packsack, rucksack, haversack", + "bakery, bakeshop, bakehouse", + "balance beam, beam", + "balloon", + "ballpoint, ballpoint pen, ballpen, Biro", + "Band Aid", + "banjo", + "bannister, banister, balustrade, balusters, handrail", + "barbell", + "barber chair", + "barbershop", + "barn", + "barometer", + "barrel, cask", + "barrow, garden cart, lawn cart, wheelbarrow", + "baseball", + "basketball", + "bassinet", + "bassoon", + "bathing cap, swimming cap", + "bath towel", + "bathtub, bathing tub, bath, tub", + "beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon", + "beacon, lighthouse, beacon light, pharos", + "beaker", + "bearskin, busby, shako", + "beer bottle", + "beer glass", + "bell cote, bell cot", + "bib", + "bicycle-built-for-two, tandem bicycle, tandem", + "bikini, two-piece", + "binder, ring-binder", + "binoculars, field glasses, opera glasses", + "birdhouse", + "boathouse", + "bobsled, bobsleigh, bob", + "bolo tie, bolo, bola tie, bola", + "bonnet, poke bonnet", + "bookcase", + "bookshop, bookstore, bookstall", + "bottlecap", + "bow", + "bow tie, bow-tie, bowtie", + "brass, memorial tablet, plaque", + "brassiere, bra, bandeau", + "breakwater, groin, groyne, mole, bulwark, seawall, jetty", + "breastplate, aegis, egis", + "broom", + "bucket, pail", + "buckle", + "bulletproof vest", + "bullet train, bullet", + "butcher shop, meat market", + "cab, hack, taxi, taxicab", + "caldron, cauldron", + "candle, taper, wax light", + "cannon", + "canoe", + "can opener, tin opener", + "cardigan", + "car mirror", + "carousel, carrousel, merry-go-round, roundabout, whirligig", + "carpenter's kit, tool kit", + "carton", + "car wheel", + "cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM", + "cassette", + "cassette player", + "castle", + "catamaran", + "CD player", + "cello, violoncello", + "cellular telephone, cellular phone, cellphone, cell, mobile phone", + "chain", + "chainlink fence", + "chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour", + "chain saw, chainsaw", + "chest", + "chiffonier, commode", + "chime, bell, gong", + "china cabinet, china closet", + "Christmas stocking", + "church, church building", + "cinema, movie theater, movie theatre, movie house, picture palace", + "cleaver, meat cleaver, chopper", + "cliff dwelling", + "cloak", + "clog, geta, patten, sabot", + "cocktail shaker", + "coffee mug", + "coffeepot", + "coil, spiral, volute, whorl, helix", + "combination lock", + "computer keyboard, keypad", + "confectionery, confectionary, candy store", + "container ship, containership, container vessel", + "convertible", + "corkscrew, bottle screw", + "cornet, horn, trumpet, trump", + "cowboy boot", + "cowboy hat, ten-gallon hat", + "cradle", + "crane2", + "crash helmet", + "crate", + "crib, cot", + "Crock Pot", + "croquet ball", + "crutch", + "cuirass", + "dam, dike, dyke", + "desk", + "desktop computer", + "dial telephone, dial phone", + "diaper, nappy, napkin", + "digital clock", + "digital watch", + "dining table, board", + "dishrag, dishcloth", + "dishwasher, dish washer, dishwashing machine", + "disk brake, disc brake", + "dock, dockage, docking facility", + "dogsled, dog sled, dog sleigh", + "dome", + "doormat, welcome mat", + "drilling platform, offshore rig", + "drum, membranophone, tympan", + "drumstick", + "dumbbell", + "Dutch oven", + "electric fan, blower", + "electric guitar", + "electric locomotive", + "entertainment center", + "envelope", + "espresso maker", + "face powder", + "feather boa, boa", + "file, file cabinet, filing cabinet", + "fireboat", + "fire engine, fire truck", + "fire screen, fireguard", + "flagpole, flagstaff", + "flute, transverse flute", + "folding chair", + "football helmet", + "forklift", + "fountain", + "fountain pen", + "four-poster", + "freight car", + "French horn, horn", + "frying pan, frypan, skillet", + "fur coat", + "garbage truck, dustcart", + "gasmask, respirator, gas helmet", + "gas pump, gasoline pump, petrol pump, island dispenser", + "goblet", + "go-kart", + "golf ball", + "golfcart, golf cart", + "gondola", + "gong, tam-tam", + "gown", + "grand piano, grand", + "greenhouse, nursery, glasshouse", + "grille, radiator grille", + "grocery store, grocery, food market, market", + "guillotine", + "hair slide", + "hair spray", + "half track", + "hammer", + "hamper", + "hand blower, blow dryer, blow drier, hair dryer, hair drier", + "hand-held computer, hand-held microcomputer", + "handkerchief, hankie, hanky, hankey", + "hard disc, hard disk, fixed disk", + "harmonica, mouth organ, harp, mouth harp", + "harp", + "harvester, reaper", + "hatchet", + "holster", + "home theater, home theatre", + "honeycomb", + "hook, claw", + "hoopskirt, crinoline", + "horizontal bar, high bar", + "horse cart, horse-cart", + "hourglass", + "iPod", + "iron, smoothing iron", + "jack-o'-lantern", + "jean, blue jean, denim", + "jeep, landrover", + "jersey, T-shirt, tee shirt", + "jigsaw puzzle", + "jinrikisha, ricksha, rickshaw", + "joystick", + "kimono", + "knee pad", + "knot", + "lab coat, laboratory coat", + "ladle", + "lampshade, lamp shade", + "laptop, laptop computer", + "lawn mower, mower", + "lens cap, lens cover", + "letter opener, paper knife, paperknife", + "library", + "lifeboat", + "lighter, light, igniter, ignitor", + "limousine, limo", + "liner, ocean liner", + "lipstick, lip rouge", + "Loafer", + "lotion", + "loudspeaker, speaker, speaker unit, loudspeaker system, speaker system", + "loupe, jeweler's loupe", + "lumbermill, sawmill", + "magnetic compass", + "mailbag, postbag", + "mailbox, letter box", + "maillot", + "maillot, tank suit", + "manhole cover", + "maraca", + "marimba, xylophone", + "mask", + "matchstick", + "maypole", + "maze, labyrinth", + "measuring cup", + "medicine chest, medicine cabinet", + "megalith, megalithic structure", + "microphone, mike", + "microwave, microwave oven", + "military uniform", + "milk can", + "minibus", + "miniskirt, mini", + "minivan", + "missile", + "mitten", + "mixing bowl", + "mobile home, manufactured home", + "Model T", + "modem", + "monastery", + "monitor", + "moped", + "mortar", + "mortarboard", + "mosque", + "mosquito net", + "motor scooter, scooter", + "mountain bike, all-terrain bike, off-roader", + "mountain tent", + "mouse, computer mouse", + "mousetrap", + "moving van", + "muzzle", + "nail", + "neck brace", + "necklace", + "nipple", + "notebook, notebook computer", + "obelisk", + "oboe, hautboy, hautbois", + "ocarina, sweet potato", + "odometer, hodometer, mileometer, milometer", + "oil filter", + "organ, pipe organ", + "oscilloscope, scope, cathode-ray oscilloscope, CRO", + "overskirt", + "oxcart", + "oxygen mask", + "packet", + "paddle, boat paddle", + "paddlewheel, paddle wheel", + "padlock", + "paintbrush", + "pajama, pyjama, pj's, jammies", + "palace", + "panpipe, pandean pipe, syrinx", + "paper towel", + "parachute, chute", + "parallel bars, bars", + "park bench", + "parking meter", + "passenger car, coach, carriage", + "patio, terrace", + "pay-phone, pay-station", + "pedestal, plinth, footstall", + "pencil box, pencil case", + "pencil sharpener", + "perfume, essence", + "Petri dish", + "photocopier", + "pick, plectrum, plectron", + "pickelhaube", + "picket fence, paling", + "pickup, pickup truck", + "pier", + "piggy bank, penny bank", + "pill bottle", + "pillow", + "ping-pong ball", + "pinwheel", + "pirate, pirate ship", + "pitcher, ewer", + "plane, carpenter's plane, woodworking plane", + "planetarium", + "plastic bag", + "plate rack", + "plow, plough", + "plunger, plumber's helper", + "Polaroid camera, Polaroid Land camera", + "pole", + "police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria", + "poncho", + "pool table, billiard table, snooker table", + "pop bottle, soda bottle", + "pot, flowerpot", + "potter's wheel", + "power drill", + "prayer rug, prayer mat", + "printer", + "prison, prison house", + "projectile, missile", + "projector", + "puck, hockey puck", + "punching bag, punch bag, punching ball, punchball", + "purse", + "quill, quill pen", + "quilt, comforter, comfort, puff", + "racer, race car, racing car", + "racket, racquet", + "radiator", + "radio, wireless", + "radio telescope, radio reflector", + "rain barrel", + "recreational vehicle, RV, R.V.", + "reel", + "reflex camera", + "refrigerator, icebox", + "remote control, remote", + "restaurant, eating house, eating place, eatery", + "revolver, six-gun, six-shooter", + "rifle", + "rocking chair, rocker", + "rotisserie", + "rubber eraser, rubber, pencil eraser", + "rugby ball", + "rule, ruler", + "running shoe", + "safe", + "safety pin", + "saltshaker, salt shaker", + "sandal", + "sarong", + "sax, saxophone", + "scabbard", + "scale, weighing machine", + "school bus", + "schooner", + "scoreboard", + "screen, CRT screen", + "screw", + "screwdriver", + "seat belt, seatbelt", + "sewing machine", + "shield, buckler", + "shoe shop, shoe-shop, shoe store", + "shoji", + "shopping basket", + "shopping cart", + "shovel", + "shower cap", + "shower curtain", + "ski", + "ski mask", + "sleeping bag", + "slide rule, slipstick", + "sliding door", + "slot, one-armed bandit", + "snorkel", + "snowmobile", + "snowplow, snowplough", + "soap dispenser", + "soccer ball", + "sock", + "solar dish, solar collector, solar furnace", + "sombrero", + "soup bowl", + "space bar", + "space heater", + "space shuttle", + "spatula", + "speedboat", + "spider web, spider's web", + "spindle", + "sports car, sport car", + "spotlight, spot", + "stage", + "steam locomotive", + "steel arch bridge", + "steel drum", + "stethoscope", + "stole", + "stone wall", + "stopwatch, stop watch", + "stove", + "strainer", + "streetcar, tram, tramcar, trolley, trolley car", + "stretcher", + "studio couch, day bed", + "stupa, tope", + "submarine, pigboat, sub, U-boat", + "suit, suit of clothes", + "sundial", + "sunglass", + "sunglasses, dark glasses, shades", + "sunscreen, sunblock, sun blocker", + "suspension bridge", + "swab, swob, mop", + "sweatshirt", + "swimming trunks, bathing trunks", + "swing", + "switch, electric switch, electrical switch", + "syringe", + "table lamp", + "tank, army tank, armored combat vehicle, armoured combat vehicle", + "tape player", + "teapot", + "teddy, teddy bear", + "television, television system", + "tennis ball", + "thatch, thatched roof", + "theater curtain, theatre curtain", + "thimble", + "thresher, thrasher, threshing machine", + "throne", + "tile roof", + "toaster", + "tobacco shop, tobacconist shop, tobacconist", + "toilet seat", + "torch", + "totem pole", + "tow truck, tow car, wrecker", + "toyshop", + "tractor", + "trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi", + "tray", + "trench coat", + "tricycle, trike, velocipede", + "trimaran", + "tripod", + "triumphal arch", + "trolleybus, trolley coach, trackless trolley", + "trombone", + "tub, vat", + "turnstile", + "typewriter keyboard", + "umbrella", + "unicycle, monocycle", + "upright, upright piano", + "vacuum, vacuum cleaner", + "vase", + "vault", + "velvet", + "vending machine", + "vestment", + "viaduct", + "violin, fiddle", + "volleyball", + "waffle iron", + "wall clock", + "wallet, billfold, notecase, pocketbook", + "wardrobe, closet, press", + "warplane, military plane", + "washbasin, handbasin, washbowl, lavabo, wash-hand basin", + "washer, automatic washer, washing machine", + "water bottle", + "water jug", + "water tower", + "whiskey jug", + "whistle", + "wig", + "window screen", + "window shade", + "Windsor tie", + "wine bottle", + "wing", + "wok", + "wooden spoon", + "wool, woolen, woollen", + "worm fence, snake fence, snake-rail fence, Virginia fence", + "wreck", + "yawl", + "yurt", + "web site, website, internet site, site", + "comic book", + "crossword puzzle, crossword", + "street sign", + "traffic light, traffic signal, stoplight", + "book jacket, dust cover, dust jacket, dust wrapper", + "menu", + "plate", + "guacamole", + "consomme", + "hot pot, hotpot", + "trifle", + "ice cream, icecream", + "ice lolly, lolly, lollipop, popsicle", + "French loaf", + "bagel, beigel", + "pretzel", + "cheeseburger", + "hotdog, hot dog, red hot", + "mashed potato", + "head cabbage", + "broccoli", + "cauliflower", + "zucchini, courgette", + "spaghetti squash", + "acorn squash", + "butternut squash", + "cucumber, cuke", + "artichoke, globe artichoke", + "bell pepper", + "cardoon", + "mushroom", + "Granny Smith", + "strawberry", + "orange", + "lemon", + "fig", + "pineapple, ananas", + "banana", + "jackfruit, jak, jack", + "custard apple", + "pomegranate", + "hay", + "carbonara", + "chocolate sauce, chocolate syrup", + "dough", + "meat loaf, meatloaf", + "pizza, pizza pie", + "potpie", + "burrito", + "red wine", + "espresso", + "cup", + "eggnog", + "alp", + "bubble", + "cliff, drop, drop-off", + "coral reef", + "geyser", + "lakeside, lakeshore", + "promontory, headland, head, foreland", + "sandbar, sand bar", + "seashore, coast, seacoast, sea-coast", + "valley, vale", + "volcano", + "ballplayer, baseball player", + "groom, bridegroom", + "scuba diver", + "rapeseed", + "daisy", + "yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum", + "corn", + "acorn", + "hip, rose hip, rosehip", + "buckeye, horse chestnut, conker", + "coral fungus", + "agaric", + "gyromitra", + "stinkhorn, carrion fungus", + "earthstar", + "hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa", + "bolete", + "ear, spike, capitulum", + "toilet tissue, toilet paper, bathroom tissue" + ] +} diff --git a/examples/rust-wasi-nn-preload/_images/.gitkeep b/examples/rust-wasi-nn-preload/_images/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/examples/rust-wasi-nn-preload/_models/mobilenet/.gitkeep b/examples/rust-wasi-nn-preload/_models/mobilenet/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/examples/rust-wasi-nn-preload/index.js b/examples/rust-wasi-nn-preload/index.js new file mode 100644 index 00000000..e4e1d5c3 --- /dev/null +++ b/examples/rust-wasi-nn-preload/index.js @@ -0,0 +1,68 @@ +/** + * Builds a reply to the given request + */ +const reply = (request) => { + if (request.method != "GET") { + // Don't allow other methods. + // Here you can see how to return a custom status + return new Response("Method not allowed", { + status: 405 + }); + } + + // Body response + const body = ` + + Wasm Workers Server + + + + + + +
+

Hello from Wasm Workers Server 👋

+

Upload an image to detect the content!

+

+
+ +
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+
-
+
+
+
+ +`; + + // Build a new response + let response = new Response(body); + + // Add a new header + response.headers.set("x-generated-by", "wasm-workers-server"); + + return response; +} + +// Subscribe to the Fetch event +addEventListener("fetch", event => { + return event.respondWith(reply(event.request)); +}); diff --git a/examples/rust-wasi-nn-preload/inference.toml b/examples/rust-wasi-nn-preload/inference.toml new file mode 100644 index 00000000..cec2430d --- /dev/null +++ b/examples/rust-wasi-nn-preload/inference.toml @@ -0,0 +1,17 @@ +name = "wasi-nn-mobilenet" +version = "1" + +[vars] +MODEL = "model" + +[[features.wasi_nn.preload_models]] +backend = "openvino" +provider = { type = "local", dir = "./_models/mobilenet/" } + +[[folders]] +from = "./_data" +to = "/tmp/data" + +[[folders]] +from = "./_images" +to = "/tmp/images" diff --git a/examples/rust-wasi-nn-preload/inference.wasm b/examples/rust-wasi-nn-preload/inference.wasm new file mode 100755 index 00000000..081346cb Binary files /dev/null and b/examples/rust-wasi-nn-preload/inference.wasm differ diff --git a/examples/rust-wasi-nn-preload/prepare.sh b/examples/rust-wasi-nn-preload/prepare.sh new file mode 100755 index 00000000..b4c77750 --- /dev/null +++ b/examples/rust-wasi-nn-preload/prepare.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +MODEL_GITHUB=https://github.com/intel/openvino-rs/tree/main/crates/openvino/tests/fixtures/mobilenet +MODEL=https://github.com/intel/openvino-rs/raw/main/crates/openvino/tests/fixtures/mobilenet + +echo "Downloading the model from ${MODEL_GITHUB}" + +wget --no-clobber $MODEL/mobilenet.bin --output-document=_models/mobilenet/model.bin +wget --no-clobber $MODEL/mobilenet.xml --output-document=_models/mobilenet/model.xml + +echo "Finished!" diff --git a/examples/rust-wasi-nn-preload/public/main.css b/examples/rust-wasi-nn-preload/public/main.css new file mode 100644 index 00000000..b77873b9 --- /dev/null +++ b/examples/rust-wasi-nn-preload/public/main.css @@ -0,0 +1,84 @@ +body { + max-width: 1000px; +} + +main { + margin: 5rem 0; +} + +h1, +p { + text-align: center; +} + +h1 { + margin-bottom: 2rem; +} + +pre { + font-size: .9rem; +} + +pre>code { + padding: 2rem; +} + +p { + margin-top: 2rem; +} + +input { + margin: 0 auto; + width: auto; +} + +.image { + width: 500px; + height: 224px; + border-radius: 5px; + background-color: #151f27; + margin: 2rem auto 1rem; + text-align: center; +} + +#image { + display: inline-block; + height: calc(224px - 2rem); + border-radius: 5px; + margin: 1rem; + width: auto; +} + +.results { + margin: 2rem auto; + width: 500px; +} + +.result { + margin-top: 1.25rem; +} + +.result_progress { + --progress: 0%; + position: relative; + height: 5px; + border-radius: 5px; + width: 100%; + background-color: #151f27; +} + +.result_progress::after { + background-color: blueviolet; + content: ""; + border-radius: 5px; + height: 5px; + width: var(--progress); + position: absolute; + top: 0; + left: 0; +} + +.result_label { + margin-top: .5rem; + font-style: italic; +} diff --git a/examples/rust-wasi-nn-preload/public/main.js b/examples/rust-wasi-nn-preload/public/main.js new file mode 100644 index 00000000..1ead93a5 --- /dev/null +++ b/examples/rust-wasi-nn-preload/public/main.js @@ -0,0 +1,48 @@ +document.getElementById('file') + .addEventListener('change', getFile) + +function getFile(event) { + const input = event.target + if ('files' in input && input.files.length > 0) { + runInference(input.files[0]) + } +} + +function runInference(file) { + readFileContent(file).then(content => { + let result = btoa(content); + + // Set the image + document + .getElementById("image") + .src = `data:image/jpeg;base64,${result}`; + + fetch("/inference", { + method: "POST", + body: result + }).then(res => res.json()) + .then(json => setResults(json)); + + }).catch(error => console.log(error)) +} + +function setResults(json) { + for (let i = 0; i < 5; i++) { + let value = json.data[i]; + let res = document.getElementById(`result-${i}`); + let progress = res.querySelector(".result_progress"); + let label = res.querySelector(".result_label"); + + label.textContent = value[0]; + progress.style.setProperty("--progress", `${Math.max(value[1] * 100, 1)}%`); + } +} + +function readFileContent(file) { + const reader = new FileReader() + return new Promise((resolve, reject) => { + reader.onload = event => resolve(event.target.result) + reader.onerror = error => reject(error) + reader.readAsBinaryString(file) + }) +} diff --git a/examples/rust-wasi-nn-preload/src/main.rs b/examples/rust-wasi-nn-preload/src/main.rs new file mode 100644 index 00000000..9b89ddc3 --- /dev/null +++ b/examples/rust-wasi-nn-preload/src/main.rs @@ -0,0 +1,113 @@ +use anyhow::Result; +use base64::{engine::general_purpose, Engine as _}; +use image2tensor::{ColorOrder, TensorType as ImageTensorType}; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::fs::File; +use std::io::BufReader; +use wasi_nn::{ExecutionTarget, GraphBuilder, GraphEncoding, TensorType}; +use wasm_workers_rs::{ + http::{self, Request, Response}, + worker, Content, +}; + +/// Result labels +#[derive(Deserialize)] +pub struct Dataset { + pub names: Vec, +} + +// A wrapper for label and probability +#[derive(Debug, PartialEq, Serialize, Clone)] +pub struct InferenceResult(String, f32); + +pub fn inference(path: &str, labels: &Dataset) -> Result, wasi_nn::Error> { + let input_dim = vec![1, 3, 224, 224]; + let mut output_buffer = vec![0f32; 1001]; + + let graph = GraphBuilder::new(GraphEncoding::Openvino, ExecutionTarget::CPU) + .build_from_cache("mobilenet") + .unwrap(); + + eprintln!("Load graph"); + let mut ctx = graph.init_execution_context()?; + eprintln!("Init execution context"); + + let width: u32 = 224; + let height: u32 = 224; + + let bytes = image2tensor::convert_image_to_bytes( + path, + width, + height, + ImageTensorType::F32, + ColorOrder::BGR, + ) + .unwrap(); + + ctx.set_input(0, TensorType::F32, &input_dim, &bytes)?; + + // Do the inference. + ctx.compute()?; + eprintln!("Run graph inference"); + + // Retrieve the output. + ctx.get_output(0, &mut output_buffer)?; + + Ok(sort_results(&output_buffer, labels)) +} + +// Sort the buffer of probabilities. +fn sort_results(buffer: &[f32], labels: &Dataset) -> Vec { + let mut results: Vec = buffer + .iter() + // In this specific case, the inference probabilities start at index 1. + // TODO: research more about where this issue may come from. + .skip(1) + .enumerate() + .map(|(c, p)| InferenceResult(labels.names.get(c).unwrap().to_string(), *p)) + .collect(); + results.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap()); + results +} + +#[derive(Serialize)] +struct Results { + data: Vec, +} + +#[worker] +fn handler(req: Request) -> Result> { + let body = req.body(); + + eprintln!("Loading!"); + + let image = general_purpose::STANDARD.decode(&body).unwrap(); + // Save the image for image2tensor + // TODO: Avoid this step by processing the bytes directly + fs::write("/tmp/images/image.jpg", &image).unwrap(); + + eprintln!("Image saved!"); + + let labels_file = File::open("/tmp/data/dataset.json").unwrap(); + let reader = BufReader::new(labels_file); + let labels: Dataset = serde_json::from_reader(reader).unwrap(); + + eprintln!("Open the data!"); + + eprintln!("Starting inference!"); + + let result = inference("/tmp/images/image.jpg", &labels).unwrap(); + + // Applied changes here to use the Response method. This requires changes + // on signature and how it returns the data. + let results = Results { + data: result[..10].to_vec().into(), + }; + let response = serde_json::to_string(&results).unwrap(); + + Ok(http::Response::builder() + .status(200) + .header("x-generated-by", "wasm-workers-server") + .body(response.into())?) +}