Skip to content

Commit d5302ac

Browse files
committed
[Example] Update pytorch example
Signed-off-by: Sylveon <[email protected]>
1 parent 5c064aa commit d5302ac

18 files changed

+213
-122
lines changed

.github/workflows/pytorch.yml

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ on:
1313
branches: [ '*' ]
1414
paths:
1515
- ".github/workflows/pytorch.yml"
16-
- "pytorch-mobilenet-image/**"
16+
- "pytorch-resnet18-image/**"
1717
pull_request:
1818
branches: [ '*' ]
1919
paths:
2020
- ".github/workflows/pytorch.yml"
21-
- "pytorch-mobilenet-image/**"
21+
- "pytorch-resnet18-image/**"
2222

2323
jobs:
2424
build:
@@ -41,25 +41,27 @@ jobs:
4141
4242
- name: Install WasmEdge + WASI-NN + PyTorch
4343
run: |
44-
VERSION=0.13.4
44+
VERSION=0.14.1
4545
curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -v $VERSION --plugins wasi_nn-pytorch -p /usr/local
46-
export PYTORCH_VERSION="1.8.2"
47-
# For the Ubuntu 20.04 or above, use the libtorch with cxx11 abi.
48-
export PYTORCH_ABI="libtorch-cxx11-abi"
49-
curl -s -L -O --remote-name-all https://download.pytorch.org/libtorch/lts/1.8/cpu/${PYTORCH_ABI}-shared-with-deps-${PYTORCH_VERSION}%2Bcpu.zip
46+
export PYTORCH_VERSION="2.4.1"
47+
# For AOTI example, use the libtorch with cxx11 abi.
48+
export PYTORCH_ABI="libtorch"
49+
curl -s -L -O --remote-name-all https://download.pytorch.org/libtorch/cpu/${PYTORCH_LINK}-shared-with-deps-${PYTORCH_VERSION}%2Bcpu.zip
5050
unzip -q "${PYTORCH_ABI}-shared-with-deps-${PYTORCH_VERSION}%2Bcpu.zip"
5151
rm -f "${PYTORCH_ABI}-shared-with-deps-${PYTORCH_VERSION}%2Bcpu.zip"
5252
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$(pwd)/libtorch/lib
5353
5454
- name: Example
5555
run: |
5656
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$(pwd)/libtorch/lib
57-
cd pytorch-mobilenet-image/rust
57+
cd pytorch-resnet18-image/rust
5858
cargo build --target wasm32-wasi --release
5959
cd ..
60-
wasmedge compile rust/target/wasm32-wasi/release/wasmedge-wasinn-example-mobilenet-image.wasm wasmedge-wasinn-example-mobilenet-image-aot.wasm
61-
wasmedge compile rust/target/wasm32-wasi/release/wasmedge-wasinn-example-mobilenet-image-named-model.wasm wasmedge-wasinn-example-mobilenet-image-named-model-aot.wasm
60+
wasmedge compile rust/target/wasm32-wasi/release/wasmedge-wasinn-example-resnet18-image.wasm wasmedge-wasinn-example-resnet18-image-aot.wasm
61+
wasmedge compile rust/target/wasm32-wasi/release/wasmedge-wasinn-example-resnet18-image-named-model.wasm wasmedge-wasinn-example-resnet18-image-named-model-aot.wasm
6262
echo "Run without named model"
63-
wasmedge --dir .:. wasmedge-wasinn-example-mobilenet-image-aot.wasm mobilenet.pt input.jpg
63+
wasmedge --dir .:. wasmedge-wasinn-example-resnet18-image-aot.wasm resnet18.pt input.jpg
6464
echo "Run with named model"
65-
wasmedge --dir .:. --nn-preload demo:PyTorch:CPU:mobilenet.pt wasmedge-wasinn-example-mobilenet-image-named-model-aot.wasm demo input.jpg
65+
wasmedge --dir .:. --nn-preload demo:PyTorch:CPU:resnet18.pt wasmedge-wasinn-example-resnet18-image-named-model-aot.wasm demo input.jpg
66+
echo "Run with AOTI"
67+
wasmedge --dir .:. --nn-preload demo:PyTorchAOTI:CPU:$(pwd)/resnet18_pt2.so wasmedge-wasinn-example-resnet18-image-named-model.wasm demo input.jpg

pytorch-mobilenet-image/README.md

Lines changed: 0 additions & 105 deletions
This file was deleted.
-13.7 MB
Binary file not shown.

pytorch-resnet18-image/README.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Resnet18 Example For WASI-NN with PyTorch Backend
2+
3+
This package is a high-level Rust bindings for [wasi-nn] example of Resnet18 with PyTorch backend.
4+
5+
[wasi-nn]: https://github.com/WebAssembly/wasi-nn
6+
7+
## Dependencies
8+
9+
This crate depends on the `wasi-nn` in the `Cargo.toml`:
10+
11+
```toml
12+
[dependencies]
13+
wasi-nn = "0.6.0"
14+
```
15+
16+
## Build
17+
18+
Compile the application to WebAssembly:
19+
20+
```bash
21+
cargo build --target=wasm32-wasi --release
22+
```
23+
24+
Because here, we will demonstrate two ways of using wasi-nn. So the output WASM files will be at [`target/wasm32-wasi/release/wasmedge-wasinn-example-resnet18-image.wasm`](wasmedge-wasinn-example-resnet18-image.wasm) and [`target/wasm32-wasi/release/wasmedge-wasinn-example-resnet18-image-named-model.wasm`](wasmedge-wasinn-example-resnet18-image-named-model.wasm).
25+
To speed up the image processing, we can enable the AOT mode in WasmEdge with:
26+
27+
```bash
28+
wasmedgec rust/target/wasm32-wasi/release/wasmedge-wasinn-example-resnet18-image.wasm wasmedge-wasinn-example-resnet18-image-aot.wasm
29+
30+
wasmedgec rust/target/wasm32-wasi/release/wasmedge-wasinn-example-resnet18-image-named-model.wasm wasmedge-wasinn-example-resnet18-image-named-model-aot.wasm
31+
```
32+
33+
## Run
34+
35+
### Generate Model
36+
37+
First generate the fixture of the pre-trained mobilenet with the script:
38+
39+
```bash
40+
pip3 install torch==2.4.1 numpy pillow --extra-index-url https://download.pytorch.org/whl/lts/1.8/cpu
41+
# generate the model fixture
42+
python3 gen_resnet18_model.py
43+
```
44+
45+
(Or you can use the pre-generated one at [`resnet18.pt`](resnet18.pt))
46+
47+
### Test Image
48+
49+
The testing image `input.jpg` is downloaded from <https://github.com/bytecodealliance/wasi-nn/raw/main/rust/examples/images/1.jpg> with license Apache-2.0
50+
51+
### Generate Tensor
52+
53+
If you want to generate the [raw tensor](image-1x3x224x224.rgb), you can run:
54+
55+
```bash
56+
python3 gen_tensor.py input.jpg image-1x3x224x224.rgb
57+
```
58+
59+
### Execute
60+
61+
Users should [install the WasmEdge with WASI-NN PyTorch backend plug-in](https://wasmedge.org/docs/start/install#wasi-nn-plug-in-with-pytorch-backend).
62+
63+
Execute the WASM with the `wasmedge` with PyTorch supporting:
64+
65+
- Case 1:
66+
67+
```bash
68+
wasmedge --dir .:. wasmedge-wasinn-example-resnet18-image.wasm resnet18.pt input.jpg
69+
```
70+
71+
You will get the output:
72+
73+
```console
74+
Loaded graph into wasi-nn with ID: 0
75+
Created wasi-nn execution context with ID: 0
76+
Read input tensor, size in bytes: 602112
77+
Executed graph inference
78+
1.) [954](18.0458)banana
79+
2.) [940](15.6954)spaghetti squash
80+
3.) [951](14.1337)lemon
81+
4.) [942](13.2925)butternut squash
82+
5.) [941](10.6792)acorn squash
83+
```
84+
85+
- Case 2: Apply named model feature
86+
> requirement wasi-nn >= 0.5.0 and WasmEdge-plugin-wasi_nn-(*) >= 0.13.4 and
87+
> --nn-preload argument format follow <name>:<encoding>:<target>:<model_path>
88+
89+
```bash
90+
wasmedge --dir .:. --nn-preload demo:PyTorch:CPU:resnet18.pt wasmedge-wasinn-example-resnet18-image-named-model.wasm demo input.jpg
91+
```
92+
93+
You will get the same output:
94+
95+
```console
96+
Loaded graph into wasi-nn with ID: 0
97+
Created wasi-nn execution context with ID: 0
98+
Read input tensor, size in bytes: 602112
99+
Executed graph inference
100+
1.) [954](18.0458)banana
101+
2.) [940](15.6954)spaghetti squash
102+
3.) [951](14.1337)lemon
103+
4.) [942](13.2925)butternut squash
104+
5.) [941](10.6792)acorn squash
105+
```
106+
107+
## Run from AOTInductor
108+
109+
### Generate Model
110+
PyTorch backend also support load from the AOTInductor (Shared Library). To compile the pytorch model, please follow the Pytorch official tutorial.
111+
112+
* https://pytorch.org/tutorials/recipes/torch_export_aoti_python.html
113+
114+
115+
Or you can use the pre-generated one at [`resnet18_pt2.so`](resnet18_pt2.so). However it may not suitable for your machine. it is suggested to use [`gen_resnet18_aoti`](gen_resnet18_aoti) recompile the model.
116+
117+
> Notice: The AOTInductor from pip will use old c++ abi interface, it is maybe incompatible with wasmedge release, you may need to install the libtorch **without c++11 abi** and rebuild the wasmedge with `-DWASMEDGE_USE_CXX11_ABI=OFF`.
118+
119+
120+
```bash
121+
## Build Wasmedge with cmake example
122+
cmake -Bbuild -GNinja -DWASMEDGE_USE_CXX11_ABI=OFF -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=PyTorch .
123+
```
124+
125+
### Execute
126+
127+
To run the AOT Inductor, you need use `--nn-preload` with `PyTorchAOTI` interface and specify absolute path to load the shared library.
128+
129+
```bash
130+
export LD_LIBRARY_PATH=/path_to_libtorch/lib
131+
./wasmedge --dir .:. --nn-preload demo:PyTorchAOTI:CPU:/absolute_path_model/resnet18_pt2.so wasmedge-wasinn-example-resnet18-image-named-model.wasm demo input.jpg
132+
```
133+
134+
```console
135+
Loaded graph into wasi-nn with ID: 0
136+
Created wasi-nn execution context with ID: 0
137+
Read input tensor, size in bytes: 602112
138+
Executed graph inference
139+
1.) [954](18.0458)banana
140+
2.) [940](15.6954)spaghetti squash
141+
3.) [951](14.1337)lemon
142+
4.) [942](13.2925)butternut squash
143+
5.) [941](10.6792)acorn squash
144+
```
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# More detail please follow the link below
2+
# https://pytorch.org/tutorials/recipes/torch_export_aoti_python.html
3+
4+
import os
5+
import torch
6+
from torchvision.models import ResNet18_Weights, resnet18
7+
8+
model = resnet18(weights=ResNet18_Weights.DEFAULT)
9+
model.eval()
10+
11+
with torch.inference_mode():
12+
13+
# Specify the generated shared library path
14+
aot_compile_options = {
15+
"aot_inductor.output_path": os.path.join(os.getcwd(), "resnet18_pt2.so"),
16+
}
17+
if torch.cuda.is_available():
18+
device = "cuda"
19+
aot_compile_options.update({"max_autotune": True})
20+
else:
21+
device = "cpu"
22+
23+
model = model.to(device=device)
24+
example_inputs = (torch.randn(2, 3, 224, 224, device=device),)
25+
26+
# min=2 is not a bug and is explained in the 0/1 Specialization Problem
27+
batch_dim = torch.export.Dim("batch", min=2, max=32)
28+
exported_program = torch.export.export(
29+
model,
30+
example_inputs,
31+
# Specify the first dimension of the input x as dynamic
32+
dynamic_shapes={"x": {0: batch_dim}},
33+
)
34+
so_path = torch._inductor.aot_compile(
35+
exported_program.module(),
36+
example_inputs,
37+
# Specify the generated shared library path
38+
options=aot_compile_options
39+
)

pytorch-mobilenet-image/gen_mobilenet_model.py renamed to pytorch-resnet18-image/gen_resnet18_model.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44

55
with torch.no_grad():
66
fake_input = torch.rand(1, 3, 224, 224)
7-
model = torch.hub.load('pytorch/vision:v0.10.0',
8-
'mobilenet_v2', pretrained=True)
7+
model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet18', pretrained=True)
98
model.eval()
109
out1 = model(fake_input).squeeze()
1110

1211
sm = torch.jit.script(model)
13-
if not os.path.exists("mobilenet.pt"):
14-
sm.save("mobilenet.pt")
15-
load_sm = jit.load("mobilenet.pt")
12+
if not os.path.exists("resnet18.pt"):
13+
sm.save("resnet18.pt")
14+
load_sm = jit.load("resnet18.pt")
1615
out2 = load_sm(fake_input).squeeze()
1716

1817
print(out1[:5], out2[:5])
File renamed without changes.
File renamed without changes.

pytorch-resnet18-image/resnet18.pt

44.7 MB
Binary file not shown.

0 commit comments

Comments
 (0)