Skip to content

Commit 71d576e

Browse files
authored
wasi-nn: remove Git submodule (bytecodealliance#8519)
* wasi-nn: remove Git submodule To more closely align with the conventions in the `wasmtime-wasi` and `wasmtime-wasi-http` crates, this change removes the Git submodule that previously provided the WIT and WITX files for `wasmtime-wasi-nn`. Like those other crates, the syncing of wasi-nn WIT and WITX files will happen manually for the time being. This is the first PR towards upgrading the wasi-nn implementation to match recent spec changes and better preview2-ABI compatibility. prtest:full * ci: auto-vendor the wasi-nn WIT files
1 parent 4fef150 commit 71d576e

File tree

7 files changed

+258
-13
lines changed

7 files changed

+258
-13
lines changed

.gitmodules

-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
[submodule "tests/spec_testsuite"]
22
path = tests/spec_testsuite
33
url = https://github.com/WebAssembly/testsuite
4-
[submodule "crates/wasi-nn/spec"]
5-
path = crates/wasi-nn/spec
6-
url = https://github.com/WebAssembly/wasi-nn
74
[submodule "tests/wasi_testsuite/wasi-threads"]
85
path = tests/wasi_testsuite/wasi-threads
96
url = https://github.com/WebAssembly/wasi-threads

ci/vendor-wit.sh

+11-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# particular tag in upstream repositories.
55
#
66
# This script is executed on CI to ensure that everything is up-to-date.
7+
set -ex
78

89
# Space-separated list of wasi proposals that are vendored here along with the
910
# tag that they're all vendored at.
@@ -15,19 +16,25 @@
1516
repos="cli clocks filesystem http io random sockets"
1617
tag=0.2.0
1718

18-
set -ex
19-
19+
# First, replace the existing vendored WIT files in the `wasi` crate.
2020
dst=crates/wasi/wit/deps
21-
2221
rm -rf $dst
2322
mkdir -p $dst
24-
2523
for repo in $repos; do
2624
mkdir $dst/$repo
2725
curl -L https://github.com/WebAssembly/wasi-$repo/archive/refs/tags/v$tag.tar.gz | \
2826
tar xzf - --strip-components=2 -C $dst/$repo wasi-$repo-$tag/wit
2927
rm -rf $dst/$repo/deps*
3028
done
3129

30+
# Also replace the `wasi-http` WIT files since they match those in the `wasi`
31+
# crate.
3232
rm -rf crates/wasi-http/wit/deps
3333
cp -r $dst crates/wasi-http/wit
34+
35+
# Separately (for now), vendor the `wasi-nn` WIT files since their retrieval is
36+
# slightly different than above.
37+
repo=https://raw.githubusercontent.com/WebAssembly/wasi-nn
38+
revision=e2310b
39+
curl -L $repo/$revision/wit/wasi-nn.wit -o crates/wasi-nn/wit/wasi-nn.wit
40+
curl -L $repo/$revision/wasi-nn.witx -o crates/wasi-nn/witx/wasi-nn.witx

crates/wasi-nn/build.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! This build script:
2-
//! - has the configuration necessary for the wiggle and witx macros.
2+
//! - has the configuration necessary for the Wiggle and WITX macros.
33
fn main() {
4-
// This is necessary for Wiggle/Witx macros.
4+
// This is necessary for Wiggle/WITX macros.
55
let cwd = std::env::current_dir().unwrap();
6-
let wasi_root = cwd.join("spec");
6+
let wasi_root = cwd.join("witx");
77
println!("cargo:rustc-env=WASI_ROOT={}", wasi_root.display());
88

9-
// Also automatically rebuild if the Witx files change
9+
// Also automatically rebuild if the WITX files change
1010
for entry in walkdir::WalkDir::new(wasi_root) {
1111
println!("cargo:rerun-if-changed={}", entry.unwrap().path().display());
1212
}

crates/wasi-nn/spec

-1
This file was deleted.

crates/wasi-nn/src/wit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use std::{error::Error, fmt, hash::Hash, str::FromStr};
2222
mod gen_ {
2323
wasmtime::component::bindgen!({
2424
world: "ml",
25-
path: "spec/wit/wasi-nn.wit",
25+
path: "wit/wasi-nn.wit",
2626
trappable_imports: true,
2727
});
2828
}

crates/wasi-nn/wit/wasi-nn.wit

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package wasi:nn;
2+
3+
/// `wasi-nn` is a WASI API for performing machine learning (ML) inference. The API is not (yet)
4+
/// capable of performing ML training. WebAssembly programs that want to use a host's ML
5+
/// capabilities can access these capabilities through `wasi-nn`'s core abstractions: _graphs_ and
6+
/// _tensors_. A user `load`s an ML model -- instantiated as a _graph_ -- to use in an ML _backend_.
7+
/// Then, the user passes _tensor_ inputs to the _graph_, computes the inference, and retrieves the
8+
/// _tensor_ outputs.
9+
///
10+
/// This example world shows how to use these primitives together.
11+
world ml {
12+
import tensor;
13+
import graph;
14+
import inference;
15+
import errors;
16+
}
17+
18+
/// All inputs and outputs to an ML inference are represented as `tensor`s.
19+
interface tensor {
20+
/// The dimensions of a tensor.
21+
///
22+
/// The array length matches the tensor rank and each element in the array describes the size of
23+
/// each dimension
24+
type tensor-dimensions = list<u32>;
25+
26+
/// The type of the elements in a tensor.
27+
enum tensor-type {
28+
FP16,
29+
FP32,
30+
FP64,
31+
BF16,
32+
U8,
33+
I32,
34+
I64
35+
}
36+
37+
/// The tensor data.
38+
///
39+
/// Initially conceived as a sparse representation, each empty cell would be filled with zeros
40+
/// and the array length must match the product of all of the dimensions and the number of bytes
41+
/// in the type (e.g., a 2x2 tensor with 4-byte f32 elements would have a data array of length
42+
/// 16). Naturally, this representation requires some knowledge of how to lay out data in
43+
/// memory--e.g., using row-major ordering--and could perhaps be improved.
44+
type tensor-data = list<u8>;
45+
46+
record tensor {
47+
// Describe the size of the tensor (e.g., 2x2x2x2 -> [2, 2, 2, 2]). To represent a tensor
48+
// containing a single value, use `[1]` for the tensor dimensions.
49+
dimensions: tensor-dimensions,
50+
51+
// Describe the type of element in the tensor (e.g., `f32`).
52+
tensor-type: tensor-type,
53+
54+
// Contains the tensor data.
55+
data: tensor-data,
56+
}
57+
}
58+
59+
/// A `graph` is a loaded instance of a specific ML model (e.g., MobileNet) for a specific ML
60+
/// framework (e.g., TensorFlow):
61+
interface graph {
62+
use errors.{error};
63+
use tensor.{tensor};
64+
65+
/// An execution graph for performing inference (i.e., a model).
66+
///
67+
/// TODO: replace with `resource` (https://github.com/WebAssembly/wasi-nn/issues/47).
68+
type graph = u32;
69+
70+
/// Describes the encoding of the graph. This allows the API to be implemented by various
71+
/// backends that encode (i.e., serialize) their graph IR with different formats.
72+
enum graph-encoding {
73+
openvino,
74+
onnx,
75+
tensorflow,
76+
pytorch,
77+
tensorflowlite,
78+
autodetect,
79+
}
80+
81+
/// Define where the graph should be executed.
82+
enum execution-target {
83+
cpu,
84+
gpu,
85+
tpu
86+
}
87+
88+
/// The graph initialization data.
89+
///
90+
/// This gets bundled up into an array of buffers because implementing backends may encode their
91+
/// graph IR in parts (e.g., OpenVINO stores its IR and weights separately).
92+
type graph-builder = list<u8>;
93+
94+
/// Load a `graph` from an opaque sequence of bytes to use for inference.
95+
load: func(builder: list<graph-builder>, encoding: graph-encoding, target: execution-target) -> result<graph, error>;
96+
97+
/// Load a `graph` by name.
98+
///
99+
/// How the host expects the names to be passed and how it stores the graphs for retrieval via
100+
/// this function is **implementation-specific**. This allows hosts to choose name schemes that
101+
/// range from simple to complex (e.g., URLs?) and caching mechanisms of various kinds.
102+
load-by-name: func(name: string) -> result<graph, error>;
103+
}
104+
105+
/// An inference "session" is encapsulated by a `graph-execution-context`. This structure binds a
106+
/// `graph` to input tensors before `compute`-ing an inference:
107+
interface inference {
108+
use errors.{error};
109+
use tensor.{tensor, tensor-data};
110+
use graph.{graph};
111+
112+
/// Bind a `graph` to the input and output tensors for an inference.
113+
///
114+
/// TODO: this is no longer necessary in WIT (https://github.com/WebAssembly/wasi-nn/issues/43)
115+
type graph-execution-context = u32;
116+
117+
/// Create an execution instance of a loaded graph.
118+
init-execution-context: func(graph: graph) -> result<graph-execution-context, error>;
119+
120+
/// Define the inputs to use for inference.
121+
set-input: func(ctx: graph-execution-context, index: u32, tensor: tensor) -> result<_, error>;
122+
123+
/// Compute the inference on the given inputs.
124+
///
125+
/// Note the expected sequence of calls: `set-input`, `compute`, `get-output`. TODO: this
126+
/// expectation could be removed as a part of https://github.com/WebAssembly/wasi-nn/issues/43.
127+
compute: func(ctx: graph-execution-context) -> result<_, error>;
128+
129+
/// Extract the outputs after inference.
130+
get-output: func(ctx: graph-execution-context, index: u32) -> result<tensor-data, error>;
131+
}
132+
133+
/// TODO: create function-specific errors (https://github.com/WebAssembly/wasi-nn/issues/42)
134+
interface errors {
135+
enum error {
136+
// Caller module passed an invalid argument.
137+
invalid-argument,
138+
// Invalid encoding.
139+
invalid-encoding,
140+
busy,
141+
// Runtime Error.
142+
runtime-error,
143+
// Unsupported operation.
144+
unsupported-operation,
145+
// Graph is too large.
146+
too-large,
147+
// Graph not found.
148+
not-found
149+
}
150+
}

crates/wasi-nn/witx/wasi-nn.witx

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
;; This WITX version of the wasi-nn API is retained for consistency only. See the `wit/wasi-nn.wit`
2+
;; version for the official specification and documentation.
3+
4+
(typename $buffer_size u32)
5+
(typename $nn_errno
6+
(enum (@witx tag u16)
7+
$success
8+
$invalid_argument
9+
$invalid_encoding
10+
$missing_memory
11+
$busy
12+
$runtime_error
13+
$unsupported_operation
14+
$too_large
15+
$not_found
16+
)
17+
)
18+
(typename $tensor_dimensions (list u32))
19+
(typename $tensor_type
20+
(enum (@witx tag u8)
21+
$f16
22+
$f32
23+
$f64
24+
$u8
25+
$i32
26+
$i64
27+
)
28+
)
29+
(typename $tensor_data (list u8))
30+
(typename $tensor
31+
(record
32+
(field $dimensions $tensor_dimensions)
33+
(field $type $tensor_type)
34+
(field $data $tensor_data)
35+
)
36+
)
37+
(typename $graph_builder (list u8))
38+
(typename $graph_builder_array (list $graph_builder))
39+
(typename $graph (handle))
40+
(typename $graph_encoding
41+
(enum (@witx tag u8)
42+
$openvino
43+
$onnx
44+
$tensorflow
45+
$pytorch
46+
$tensorflowlite
47+
$autodetect
48+
)
49+
)
50+
(typename $execution_target
51+
(enum (@witx tag u8)
52+
$cpu
53+
$gpu
54+
$tpu
55+
)
56+
)
57+
(typename $graph_execution_context (handle))
58+
59+
(module $wasi_ephemeral_nn
60+
(import "memory" (memory))
61+
(@interface func (export "load")
62+
(param $builder $graph_builder_array)
63+
(param $encoding $graph_encoding)
64+
(param $target $execution_target)
65+
(result $error (expected $graph (error $nn_errno)))
66+
)
67+
(@interface func (export "load_by_name")
68+
(param $name string)
69+
(result $error (expected $graph (error $nn_errno)))
70+
)
71+
(@interface func (export "init_execution_context")
72+
(param $graph $graph)
73+
(result $error (expected $graph_execution_context (error $nn_errno)))
74+
)
75+
(@interface func (export "set_input")
76+
(param $context $graph_execution_context)
77+
(param $index u32)
78+
(param $tensor $tensor)
79+
(result $error (expected (error $nn_errno)))
80+
)
81+
(@interface func (export "get_output")
82+
(param $context $graph_execution_context)
83+
(param $index u32)
84+
(param $out_buffer (@witx pointer u8))
85+
(param $out_buffer_max_size $buffer_size)
86+
(result $error (expected $buffer_size (error $nn_errno)))
87+
)
88+
(@interface func (export "compute")
89+
(param $context $graph_execution_context)
90+
(result $error (expected (error $nn_errno)))
91+
)
92+
)

0 commit comments

Comments
 (0)