aorabdel commited on
Commit
b4958d7
·
verified ·
1 Parent(s): 16971e6

Sync model repo (text/metadata)

Browse files
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
README.md CHANGED
@@ -52,10 +52,14 @@ This version demonstrates efficient inference on Arm-based platforms while prese
52
  | `deit-tiny_ethos_ethosu_optimized.pte` | Arm-optimized model for deployment |
53
  | `config.yaml` | Model I/O contract used by the example |
54
  | `benchmarks/` | FP32 baseline and Arm-optimized benchmark records |
 
 
 
 
55
 
56
  ## Performance
57
 
58
- Performance was measured on the reference configuration below. Results make the optimization reproducible but do not guarantee identical performance on every Arm-based system.
59
 
60
  **Reference configuration**
61
 
@@ -83,6 +87,8 @@ The "Original / baseline" model size is the FP32 PyTorch state dict.
83
 
84
  Because the Ethos-U85 NPU architecture natively processes integer workloads and does not support floating-point execution, the FP32 baseline cannot be compiled into an Ethos-U85 delegate `.pte` file, making NPU-accelerated baseline latency and throughput figures non-applicable.
85
 
 
 
86
  ## Accuracy
87
 
88
  Accuracy was evaluated on the ImageNet-1k validation split, comparing the FP32 baseline against the Arm-optimized INT8 model via a PyTorch FP32-vs-PT2E INT8 simulation, not on the exported `.pte` running on Ethos-U85.
@@ -127,6 +133,41 @@ Most quantized layers use INT8 activations and INT8 weights (a8w8). Selected out
127
 
128
  The goal of this process is to improve deployment characteristics such as latency, memory use, model size, and runtime compatibility while preserving the model's intended behavior. Detailed conversion scripts, calibration configuration, or backend-specific implementation details may be provided separately where appropriate.
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  ### Expected input
131
 
132
  | Property | Value |
@@ -156,11 +197,14 @@ This model is intended for developers evaluating image classification workloads
156
  - This repository is not a replacement for the original model documentation.
157
  - The `.pte` requires Ethos-U85 hardware or the Corstone-320 FVP to execute; it cannot run on a standard desktop/CPU ExecuTorch Python runtime because the Ethos-U backend delegate is not registered there.
158
  - The model uses a fixed input size of 224x224 and batch size 1; dynamic shapes are not supported.
 
159
 
160
  ## Additional notes
161
 
162
  - SmoothQuant activation smoothing was applied before observer insertion to reduce activation outliers ahead of static PT2E quantization. Most quantized layers use INT8 activations and INT8 weights (a8w8), while output.dense (the MLP-down projection in each transformer block) uses INT16 activations and INT8 weights (a16w8) to preserve accuracy within acceptable ranges.
163
  - Flash deployment configuration: the on-device benchmark loaded the 4,935,568-byte `.pte` from the Alif DK-E8's OSPI1 flash at `0xc0000000`. OSPI1 was configured as an 8-line Octal SPI DDR interface at 100 MHz, using XIP (linear memory-mapped) reads. The artifact occupies 4.7069 MiB (14.71%) of the board's 32 MiB OSPI1 flash. Note: 200 MB/s is the theoretical raw interface bandwidth; measured flash bandwidth was not collected.
 
 
164
 
165
  ## About this version
166
 
 
52
  | `deit-tiny_ethos_ethosu_optimized.pte` | Arm-optimized model for deployment |
53
  | `config.yaml` | Model I/O contract used by the example |
54
  | `benchmarks/` | FP32 baseline and Arm-optimized benchmark records |
55
+ | `example.py` | Minimal inference example |
56
+ | `pyproject.toml` | Pinned runtime dependencies and deployment metadata |
57
+ | `uv.lock` | Locked dependency versions, sources, and hashes for `uv sync --frozen` |
58
+ | `install_ethos_u85_graviton.sh` | Standalone installer that builds the Ethos-U85 execution stack (Arm GNU toolchain, ExecuTorch bare-metal runtime, `arm_executor_runner`, Corstone-320 FVP) required to run `example.py`. Installs into a shared, cross-model directory if `sudo` is available, otherwise falls back to a local install for this bundle only |
59
 
60
  ## Performance
61
 
62
+ Performance was measured on the reference configuration below.
63
 
64
  **Reference configuration**
65
 
 
87
 
88
  Because the Ethos-U85 NPU architecture natively processes integer workloads and does not support floating-point execution, the FP32 baseline cannot be compiled into an Ethos-U85 delegate `.pte` file, making NPU-accelerated baseline latency and throughput figures non-applicable.
89
 
90
+ The Graviton environment documented for `example.py` verifies portability of the inference flow but does not provide or imply equivalent Graviton performance.
91
+
92
  ## Accuracy
93
 
94
  Accuracy was evaluated on the ImageNet-1k validation split, comparing the FP32 baseline against the Arm-optimized INT8 model via a PyTorch FP32-vs-PT2E INT8 simulation, not on the exported `.pte` running on Ethos-U85.
 
133
 
134
  The goal of this process is to improve deployment characteristics such as latency, memory use, model size, and runtime compatibility while preserving the model's intended behavior. Detailed conversion scripts, calibration configuration, or backend-specific implementation details may be provided separately where appropriate.
135
 
136
+ ## Using this model
137
+
138
+ Run the standalone installer to build the Ethos-U85 execution stack that the example needs:
139
+
140
+ The installer uses a shared /opt/ethos-u85-graviton runtime when sudo is available, reusing existing builds across model bundles. Without sudo, it automatically falls back to a local runtime/ installation. A custom location can be set with ETHOS_RUNTIME_DIR, and existing installations are detected before rebuilding.
141
+
142
+ ```bash
143
+ bash install_ethos_u85_graviton.sh
144
+ ```
145
+
146
+ This is necessary because the `.pte` cannot run on a plain Python/ExecuTorch install — it requires Ethos-U85 hardware or the Corstone-320 FVP (see Limitations). The script installs the Arm GNU toolchain, the ExecuTorch 1.1.0 bare-metal runtime libraries (built from source), the Ethos-U85 semihosting runner (`arm_executor_runner`), and the Arm Corstone-320 FVP that `example.py` uses to simulate the Cortex-M55 + Ethos-U85 target.
147
+
148
+ Dependencies are declared in `pyproject.toml`, which ships with this repository. Resolve and install them into a local virtual environment with uv:
149
+
150
+ ```bash
151
+ uv python install
152
+ uv sync --frozen
153
+ ```
154
+
155
+ ### Run the example
156
+
157
+ ```bash
158
+ uv run example.py
159
+ ```
160
+
161
+ The default run prints predictions without overwriting the reference `predictions.json`. To save a separate result for comparison, pass an explicit destination:
162
+
163
+ ```bash
164
+ uv run example.py --output /tmp/deit-predictions.json
165
+ ```
166
+
167
+ The reference `predictions.json` records the known-good result for the committed `sample_input.jpg`. The example uses the FVP to validate the Ethos-U85 runtime path; it is not a Python-native inference path for this PTE.
168
+
169
+ Note: The Python/uv example runs on AWS Graviton (Ubuntu arm64) to confirm runtime compatibility only and is intended as a guideline for building an equivalent run script for Arm-based edge systems equipped with an Ethos-U85 NPU.
170
+
171
  ### Expected input
172
 
173
  | Property | Value |
 
197
  - This repository is not a replacement for the original model documentation.
198
  - The `.pte` requires Ethos-U85 hardware or the Corstone-320 FVP to execute; it cannot run on a standard desktop/CPU ExecuTorch Python runtime because the Ethos-U backend delegate is not registered there.
199
  - The model uses a fixed input size of 224x224 and batch size 1; dynamic shapes are not supported.
200
+ - The semihosting runner uses ExecuTorch's `Sram_Only` memory profile with a 16 MiB temporary allocator configured by the installer.
201
 
202
  ## Additional notes
203
 
204
  - SmoothQuant activation smoothing was applied before observer insertion to reduce activation outliers ahead of static PT2E quantization. Most quantized layers use INT8 activations and INT8 weights (a8w8), while output.dense (the MLP-down projection in each transformer block) uses INT16 activations and INT8 weights (a16w8) to preserve accuracy within acceptable ranges.
205
  - Flash deployment configuration: the on-device benchmark loaded the 4,935,568-byte `.pte` from the Alif DK-E8's OSPI1 flash at `0xc0000000`. OSPI1 was configured as an 8-line Octal SPI DDR interface at 100 MHz, using XIP (linear memory-mapped) reads. The artifact occupies 4.7069 MiB (14.71%) of the board's 32 MiB OSPI1 flash. Note: 200 MB/s is the theoretical raw interface bandwidth; measured flash bandwidth was not collected.
206
+ - EULA notice: `install_ethos_u85_graviton.sh` installs the Arm Corstone-320 Fixed Virtual Platform (FVP) by invoking ExecuTorch's upstream `examples/arm/setup.sh` with `--i-agree-to-the-contained-eula`. Running the installer accepts Arm's End User License Agreement (EULA) for the Fixed Virtual Platforms on your behalf. Review Arm's FVP EULA terms before running the script if you have not already agreed to them.
207
+ - Sample input: `sample_input.jpg` is derived from [Samoyed on Beach](https://commons.wikimedia.org/wiki/File:Samoyed_on_Beach.jpg) by Appleinfl, via Wikimedia Commons (public domain).
208
 
209
  ## About this version
210
 
example.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Run an exported image-classification Ethos-U85 PTE on Corstone-320."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import os
8
+ import shutil
9
+ import subprocess
10
+ import uuid
11
+ from pathlib import Path
12
+
13
+ import numpy as np
14
+ from PIL import Image
15
+
16
+
17
+ BUNDLE_DIR = Path(__file__).resolve().parent
18
+ SHARED_RUNTIME_DIR = Path("/opt/ethos-u85-graviton")
19
+ LOCAL_RUNTIME_DIR = BUNDLE_DIR / "runtime"
20
+
21
+
22
+ def _default_runtime_dir() -> Path:
23
+ """Mirror install_ethos_u85_graviton.sh's own fallback: it prefers the
24
+ shared /opt install, but silently falls back to a local, per-bundle one
25
+ when sudo isn't available. Detect whichever one actually got built."""
26
+ override = os.environ.get("ETHOS_RUNTIME_DIR")
27
+ if override:
28
+ return Path(override)
29
+ if (SHARED_RUNTIME_DIR / "bin" / "arm_executor_runner").exists():
30
+ return SHARED_RUNTIME_DIR
31
+ return LOCAL_RUNTIME_DIR
32
+
33
+
34
+ RUNTIME_DIR = _default_runtime_dir()
35
+ DEFAULT_MODEL = BUNDLE_DIR / "deit-tiny_ethos_ethosu_optimized.pte"
36
+ DEFAULT_IMAGE = BUNDLE_DIR / "sample_input.jpg"
37
+ DEFAULT_FVP = RUNTIME_DIR / "bin" / "FVP_Corstone_SSE-320"
38
+ DEFAULT_RUNNER = RUNTIME_DIR / "bin" / "arm_executor_runner"
39
+ DEFAULT_WORKDIR = RUNTIME_DIR / "output" / "fvp"
40
+ MEAN = np.array([0.485, 0.456, 0.406], dtype=np.float32)
41
+ STD = np.array([0.229, 0.224, 0.225], dtype=np.float32)
42
+ IMAGENET_CLASSES = json.loads((BUNDLE_DIR / "imagenet_classes.json").read_text(encoding="utf-8"))
43
+
44
+
45
+ def parse_args() -> argparse.Namespace:
46
+ parser = argparse.ArgumentParser(
47
+ description="Execute an Ethos-U85 image-classification PTE on Corstone-320."
48
+ )
49
+ parser.add_argument("--model", type=Path, default=DEFAULT_MODEL)
50
+ parser.add_argument(
51
+ "--image",
52
+ type=Path,
53
+ default=DEFAULT_IMAGE,
54
+ help="RGB image to classify (default: sample_input.jpg next to this script).",
55
+ )
56
+ parser.add_argument("--fvp-bin", type=Path, default=DEFAULT_FVP)
57
+ parser.add_argument("--runner-elf", type=Path, default=DEFAULT_RUNNER)
58
+ parser.add_argument("--workdir", type=Path, default=DEFAULT_WORKDIR)
59
+ parser.add_argument(
60
+ "--output",
61
+ type=Path,
62
+ help="Optional JSON destination; omit to only print predictions.",
63
+ )
64
+ parser.add_argument("--timelimit", type=int, default=1800)
65
+ return parser.parse_args()
66
+
67
+
68
+ def load_image(path: Path) -> Image.Image:
69
+ print(f"Using image: {path}")
70
+ return Image.open(path).convert("RGB")
71
+
72
+
73
+ def preprocess(path: Path) -> np.ndarray:
74
+ image = load_image(path)
75
+ width, height = image.size
76
+ if width < height:
77
+ new_width, new_height = 256, round(height * 256 / width)
78
+ else:
79
+ new_height, new_width = 256, round(width * 256 / height)
80
+ image = image.resize((new_width, new_height), Image.Resampling.BICUBIC)
81
+ left = (new_width - 224) // 2
82
+ top = (new_height - 224) // 2
83
+ image = image.crop((left, top, left + 224, top + 224))
84
+ array = np.asarray(image, dtype=np.float32) / 255.0
85
+ array = array.transpose(2, 0, 1)
86
+ array = (array - MEAN[:, None, None]) / STD[:, None, None]
87
+ return np.expand_dims(array.astype(np.float32), axis=0)
88
+
89
+
90
+ def fvp_environment(fvp: Path) -> dict[str, str]:
91
+ env = os.environ.copy()
92
+ resolved = fvp.resolve()
93
+ for ancestor in resolved.parents:
94
+ candidate = ancestor / "python" / "lib"
95
+ if candidate.is_dir() and any(candidate.glob("libpython*.so*")):
96
+ current = env.get("LD_LIBRARY_PATH")
97
+ env["LD_LIBRARY_PATH"] = f"{candidate}:{current}" if current else str(candidate)
98
+ break
99
+ return env
100
+
101
+
102
+ def main() -> None:
103
+ args = parse_args()
104
+ model = args.model.resolve()
105
+ fvp = args.fvp_bin.resolve()
106
+ runner = args.runner_elf.resolve()
107
+ for kind, path in (("model", model), ("FVP", fvp), ("runner", runner)):
108
+ if not path.exists():
109
+ raise FileNotFoundError(f"Missing {kind}: {path}")
110
+ if not args.image.is_file():
111
+ raise FileNotFoundError(f"Missing image: {args.image}")
112
+
113
+ workdir = args.workdir.resolve()
114
+ workdir.mkdir(parents=True, exist_ok=True)
115
+ run_id = uuid.uuid4().hex[:8]
116
+ # workdir defaults under the SHARED ETHOS_RUNTIME_DIR, so a fixed
117
+ # "model.pte" name would collide with a concurrent run of another model
118
+ # bundle. Keep it unique per run_id like the input/output files.
119
+ staged_model = workdir / f"model_{run_id}.pte"
120
+ input_path = workdir / f"input_{run_id}.bin"
121
+ output_base = f"out_{run_id}"
122
+ output_path = workdir / f"{output_base}-0.bin"
123
+ shutil.copyfile(model, staged_model)
124
+ input_path.write_bytes(preprocess(args.image).tobytes())
125
+
126
+ command_line = (
127
+ f"arm_executor_runner -m {staged_model.name} -i {input_path.name} -o {output_base}"
128
+ )
129
+ command = [
130
+ str(fvp),
131
+ "-C", "mps4_board.subsystem.ethosu.num_macs=256",
132
+ "-C", "mps4_board.visualisation.disable-visualisation=1",
133
+ "-C", "vis_hdlcd.disable_visualisation=1",
134
+ "-C", "mps4_board.telnetterminal0.start_telnet=0",
135
+ "-C", "mps4_board.uart0.out_file=-",
136
+ "-C", "mps4_board.uart0.shutdown_on_eot=1",
137
+ "-C", "mps4_board.subsystem.cpu0.semihosting-enable=1",
138
+ "-C", "mps4_board.subsystem.ethosu.extra_args='--fast'",
139
+ "-C", "mps4_board.subsystem.cpu0.semihosting-stack_base=0",
140
+ "-C", "mps4_board.subsystem.cpu0.semihosting-heap_limit=0",
141
+ "-C", f"mps4_board.subsystem.cpu0.semihosting-cwd={workdir}",
142
+ "-C", f"mps4_board.subsystem.cpu0.semihosting-cmd_line='{command_line}'",
143
+ "-a", str(runner),
144
+ "--timelimit", str(args.timelimit),
145
+ ]
146
+ result = subprocess.run(
147
+ command,
148
+ capture_output=True,
149
+ text=True,
150
+ timeout=args.timelimit + 30,
151
+ check=False,
152
+ env=fvp_environment(fvp),
153
+ )
154
+ print(result.stdout, end="")
155
+ if result.returncode != 0:
156
+ raise RuntimeError(
157
+ f"FVP exited with {result.returncode}\n{result.stderr[-2048:]}"
158
+ )
159
+ if not output_path.is_file():
160
+ raise RuntimeError(f"FVP did not produce {output_path}")
161
+
162
+ logits = np.fromfile(output_path, dtype=np.float32)
163
+ if logits.size != 1000:
164
+ raise ValueError(f"Expected 1000 float32 logits, got {logits.size}")
165
+ probabilities = np.exp(logits.astype(np.float64) - logits.max())
166
+ probabilities /= probabilities.sum()
167
+ top5 = np.argsort(probabilities)[::-1][:5]
168
+ predictions = [
169
+ {
170
+ "rank": rank,
171
+ "class_index": int(index),
172
+ "class_name": IMAGENET_CLASSES[int(index)],
173
+ "probability": float(probabilities[index]),
174
+ }
175
+ for rank, index in enumerate(top5, 1)
176
+ ]
177
+
178
+ print("Top-5 ImageNet predictions:")
179
+ for prediction in predictions:
180
+ print(
181
+ f" {prediction['rank']}. index={prediction['class_index']}, "
182
+ f"class={prediction['class_name']}, "
183
+ f"probability={prediction['probability']:.6f}"
184
+ )
185
+
186
+ print(f"Raw output: {output_path}")
187
+ if args.output is not None:
188
+ predictions_path = args.output.resolve()
189
+ predictions_path.parent.mkdir(parents=True, exist_ok=True)
190
+ predictions_path.write_text(
191
+ json.dumps(predictions, indent=2, ensure_ascii=False) + "\n",
192
+ encoding="utf-8",
193
+ )
194
+ print(f"Predictions JSON: {predictions_path}")
195
+
196
+
197
+ if __name__ == "__main__":
198
+ main()
imagenet_classes.json ADDED
@@ -0,0 +1,1002 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ "tench",
3
+ "goldfish",
4
+ "great white shark",
5
+ "tiger shark",
6
+ "hammerhead",
7
+ "electric ray",
8
+ "stingray",
9
+ "cock",
10
+ "hen",
11
+ "ostrich",
12
+ "brambling",
13
+ "goldfinch",
14
+ "house finch",
15
+ "junco",
16
+ "indigo bunting",
17
+ "robin",
18
+ "bulbul",
19
+ "jay",
20
+ "magpie",
21
+ "chickadee",
22
+ "water ouzel",
23
+ "kite",
24
+ "bald eagle",
25
+ "vulture",
26
+ "great grey owl",
27
+ "European fire salamander",
28
+ "common newt",
29
+ "eft",
30
+ "spotted salamander",
31
+ "axolotl",
32
+ "bullfrog",
33
+ "tree frog",
34
+ "tailed frog",
35
+ "loggerhead",
36
+ "leatherback turtle",
37
+ "mud turtle",
38
+ "terrapin",
39
+ "box turtle",
40
+ "banded gecko",
41
+ "common iguana",
42
+ "American chameleon",
43
+ "whiptail",
44
+ "agama",
45
+ "frilled lizard",
46
+ "alligator lizard",
47
+ "Gila monster",
48
+ "green lizard",
49
+ "African chameleon",
50
+ "Komodo dragon",
51
+ "African crocodile",
52
+ "American alligator",
53
+ "triceratops",
54
+ "thunder snake",
55
+ "ringneck snake",
56
+ "hognose snake",
57
+ "green snake",
58
+ "king snake",
59
+ "garter snake",
60
+ "water snake",
61
+ "vine snake",
62
+ "night snake",
63
+ "boa constrictor",
64
+ "rock python",
65
+ "Indian cobra",
66
+ "green mamba",
67
+ "sea snake",
68
+ "horned viper",
69
+ "diamondback",
70
+ "sidewinder",
71
+ "trilobite",
72
+ "harvestman",
73
+ "scorpion",
74
+ "black and gold garden spider",
75
+ "barn spider",
76
+ "garden spider",
77
+ "black widow",
78
+ "tarantula",
79
+ "wolf spider",
80
+ "tick",
81
+ "centipede",
82
+ "black grouse",
83
+ "ptarmigan",
84
+ "ruffed grouse",
85
+ "prairie chicken",
86
+ "peacock",
87
+ "quail",
88
+ "partridge",
89
+ "African grey",
90
+ "macaw",
91
+ "sulphur-crested cockatoo",
92
+ "lorikeet",
93
+ "coucal",
94
+ "bee eater",
95
+ "hornbill",
96
+ "hummingbird",
97
+ "jacamar",
98
+ "toucan",
99
+ "drake",
100
+ "red-breasted merganser",
101
+ "goose",
102
+ "black swan",
103
+ "tusker",
104
+ "echidna",
105
+ "platypus",
106
+ "wallaby",
107
+ "koala",
108
+ "wombat",
109
+ "jellyfish",
110
+ "sea anemone",
111
+ "brain coral",
112
+ "flatworm",
113
+ "nematode",
114
+ "conch",
115
+ "snail",
116
+ "slug",
117
+ "sea slug",
118
+ "chiton",
119
+ "chambered nautilus",
120
+ "Dungeness crab",
121
+ "rock crab",
122
+ "fiddler crab",
123
+ "king crab",
124
+ "American lobster",
125
+ "spiny lobster",
126
+ "crayfish",
127
+ "hermit crab",
128
+ "isopod",
129
+ "white stork",
130
+ "black stork",
131
+ "spoonbill",
132
+ "flamingo",
133
+ "little blue heron",
134
+ "American egret",
135
+ "bittern",
136
+ "crane bird",
137
+ "limpkin",
138
+ "European gallinule",
139
+ "American coot",
140
+ "bustard",
141
+ "ruddy turnstone",
142
+ "red-backed sandpiper",
143
+ "redshank",
144
+ "dowitcher",
145
+ "oystercatcher",
146
+ "pelican",
147
+ "king penguin",
148
+ "albatross",
149
+ "grey whale",
150
+ "killer whale",
151
+ "dugong",
152
+ "sea lion",
153
+ "Chihuahua",
154
+ "Japanese spaniel",
155
+ "Maltese dog",
156
+ "Pekinese",
157
+ "Shih-Tzu",
158
+ "Blenheim spaniel",
159
+ "papillon",
160
+ "toy terrier",
161
+ "Rhodesian ridgeback",
162
+ "Afghan hound",
163
+ "basset",
164
+ "beagle",
165
+ "bloodhound",
166
+ "bluetick",
167
+ "black-and-tan coonhound",
168
+ "Walker hound",
169
+ "English foxhound",
170
+ "redbone",
171
+ "borzoi",
172
+ "Irish wolfhound",
173
+ "Italian greyhound",
174
+ "whippet",
175
+ "Ibizan hound",
176
+ "Norwegian elkhound",
177
+ "otterhound",
178
+ "Saluki",
179
+ "Scottish deerhound",
180
+ "Weimaraner",
181
+ "Staffordshire bullterrier",
182
+ "American Staffordshire terrier",
183
+ "Bedlington terrier",
184
+ "Border terrier",
185
+ "Kerry blue terrier",
186
+ "Irish terrier",
187
+ "Norfolk terrier",
188
+ "Norwich terrier",
189
+ "Yorkshire terrier",
190
+ "wire-haired fox terrier",
191
+ "Lakeland terrier",
192
+ "Sealyham terrier",
193
+ "Airedale",
194
+ "cairn",
195
+ "Australian terrier",
196
+ "Dandie Dinmont",
197
+ "Boston bull",
198
+ "miniature schnauzer",
199
+ "giant schnauzer",
200
+ "standard schnauzer",
201
+ "Scotch terrier",
202
+ "Tibetan terrier",
203
+ "silky terrier",
204
+ "soft-coated wheaten terrier",
205
+ "West Highland white terrier",
206
+ "Lhasa",
207
+ "flat-coated retriever",
208
+ "curly-coated retriever",
209
+ "golden retriever",
210
+ "Labrador retriever",
211
+ "Chesapeake Bay retriever",
212
+ "German short-haired pointer",
213
+ "vizsla",
214
+ "English setter",
215
+ "Irish setter",
216
+ "Gordon setter",
217
+ "Brittany spaniel",
218
+ "clumber",
219
+ "English springer",
220
+ "Welsh springer spaniel",
221
+ "cocker spaniel",
222
+ "Sussex spaniel",
223
+ "Irish water spaniel",
224
+ "kuvasz",
225
+ "schipperke",
226
+ "groenendael",
227
+ "malinois",
228
+ "briard",
229
+ "kelpie",
230
+ "komondor",
231
+ "Old English sheepdog",
232
+ "Shetland sheepdog",
233
+ "collie",
234
+ "Border collie",
235
+ "Bouvier des Flandres",
236
+ "Rottweiler",
237
+ "German shepherd",
238
+ "Doberman",
239
+ "miniature pinscher",
240
+ "Greater Swiss Mountain dog",
241
+ "Bernese mountain dog",
242
+ "Appenzeller",
243
+ "EntleBucher",
244
+ "boxer",
245
+ "bull mastiff",
246
+ "Tibetan mastiff",
247
+ "French bulldog",
248
+ "Great Dane",
249
+ "Saint Bernard",
250
+ "Eskimo dog",
251
+ "malamute",
252
+ "Siberian husky",
253
+ "dalmatian",
254
+ "affenpinscher",
255
+ "basenji",
256
+ "pug",
257
+ "Leonberg",
258
+ "Newfoundland",
259
+ "Great Pyrenees",
260
+ "Samoyed",
261
+ "Pomeranian",
262
+ "chow",
263
+ "keeshond",
264
+ "Brabancon griffon",
265
+ "Pembroke",
266
+ "Cardigan",
267
+ "toy poodle",
268
+ "miniature poodle",
269
+ "standard poodle",
270
+ "Mexican hairless",
271
+ "timber wolf",
272
+ "white wolf",
273
+ "red wolf",
274
+ "coyote",
275
+ "dingo",
276
+ "dhole",
277
+ "African hunting dog",
278
+ "hyena",
279
+ "red fox",
280
+ "kit fox",
281
+ "Arctic fox",
282
+ "grey fox",
283
+ "tabby",
284
+ "tiger cat",
285
+ "Persian cat",
286
+ "Siamese cat",
287
+ "Egyptian cat",
288
+ "cougar",
289
+ "lynx",
290
+ "leopard",
291
+ "snow leopard",
292
+ "jaguar",
293
+ "lion",
294
+ "tiger",
295
+ "cheetah",
296
+ "brown bear",
297
+ "American black bear",
298
+ "ice bear",
299
+ "sloth bear",
300
+ "mongoose",
301
+ "meerkat",
302
+ "tiger beetle",
303
+ "ladybug",
304
+ "ground beetle",
305
+ "long-horned beetle",
306
+ "leaf beetle",
307
+ "dung beetle",
308
+ "rhinoceros beetle",
309
+ "weevil",
310
+ "fly",
311
+ "bee",
312
+ "ant",
313
+ "grasshopper",
314
+ "cricket",
315
+ "walking stick",
316
+ "cockroach",
317
+ "mantis",
318
+ "cicada",
319
+ "leafhopper",
320
+ "lacewing",
321
+ "dragonfly",
322
+ "damselfly",
323
+ "admiral",
324
+ "ringlet",
325
+ "monarch",
326
+ "cabbage butterfly",
327
+ "sulphur butterfly",
328
+ "lycaenid",
329
+ "starfish",
330
+ "sea urchin",
331
+ "sea cucumber",
332
+ "wood rabbit",
333
+ "hare",
334
+ "Angora",
335
+ "hamster",
336
+ "porcupine",
337
+ "fox squirrel",
338
+ "marmot",
339
+ "beaver",
340
+ "guinea pig",
341
+ "sorrel",
342
+ "zebra",
343
+ "hog",
344
+ "wild boar",
345
+ "warthog",
346
+ "hippopotamus",
347
+ "ox",
348
+ "water buffalo",
349
+ "bison",
350
+ "ram",
351
+ "bighorn",
352
+ "ibex",
353
+ "hartebeest",
354
+ "impala",
355
+ "gazelle",
356
+ "Arabian camel",
357
+ "llama",
358
+ "weasel",
359
+ "mink",
360
+ "polecat",
361
+ "black-footed ferret",
362
+ "otter",
363
+ "skunk",
364
+ "badger",
365
+ "armadillo",
366
+ "three-toed sloth",
367
+ "orangutan",
368
+ "gorilla",
369
+ "chimpanzee",
370
+ "gibbon",
371
+ "siamang",
372
+ "guenon",
373
+ "patas",
374
+ "baboon",
375
+ "macaque",
376
+ "langur",
377
+ "colobus",
378
+ "proboscis monkey",
379
+ "marmoset",
380
+ "capuchin",
381
+ "howler monkey",
382
+ "titi",
383
+ "spider monkey",
384
+ "squirrel monkey",
385
+ "Madagascar cat",
386
+ "indri",
387
+ "Indian elephant",
388
+ "African elephant",
389
+ "lesser panda",
390
+ "giant panda",
391
+ "barracouta",
392
+ "eel",
393
+ "coho",
394
+ "rock beauty",
395
+ "anemone fish",
396
+ "sturgeon",
397
+ "gar",
398
+ "lionfish",
399
+ "puffer",
400
+ "abacus",
401
+ "abaya",
402
+ "academic gown",
403
+ "accordion",
404
+ "acoustic guitar",
405
+ "aircraft carrier",
406
+ "airliner",
407
+ "airship",
408
+ "altar",
409
+ "ambulance",
410
+ "amphibian",
411
+ "analog clock",
412
+ "apiary",
413
+ "apron",
414
+ "ashcan",
415
+ "assault rifle",
416
+ "backpack",
417
+ "bakery",
418
+ "balance beam",
419
+ "balloon",
420
+ "ballpoint",
421
+ "Band Aid",
422
+ "banjo",
423
+ "bannister",
424
+ "barbell",
425
+ "barber chair",
426
+ "barbershop",
427
+ "barn",
428
+ "barometer",
429
+ "barrel",
430
+ "barrow",
431
+ "baseball",
432
+ "basketball",
433
+ "bassinet",
434
+ "bassoon",
435
+ "bathing cap",
436
+ "bath towel",
437
+ "bathtub",
438
+ "beach wagon",
439
+ "beacon",
440
+ "beaker",
441
+ "bearskin",
442
+ "beer bottle",
443
+ "beer glass",
444
+ "bell cote",
445
+ "bib",
446
+ "bicycle-built-for-two",
447
+ "bikini",
448
+ "binder",
449
+ "binoculars",
450
+ "birdhouse",
451
+ "boathouse",
452
+ "bobsled",
453
+ "bolo tie",
454
+ "bonnet",
455
+ "bookcase",
456
+ "bookshop",
457
+ "bottlecap",
458
+ "bow",
459
+ "bow tie",
460
+ "brass",
461
+ "brassiere",
462
+ "breakwater",
463
+ "breastplate",
464
+ "broom",
465
+ "bucket",
466
+ "buckle",
467
+ "bulletproof vest",
468
+ "bullet train",
469
+ "butcher shop",
470
+ "cab",
471
+ "caldron",
472
+ "candle",
473
+ "cannon",
474
+ "canoe",
475
+ "can opener",
476
+ "cardigan",
477
+ "car mirror",
478
+ "carousel",
479
+ "carpenter's kit",
480
+ "carton",
481
+ "car wheel",
482
+ "cash machine",
483
+ "cassette",
484
+ "cassette player",
485
+ "castle",
486
+ "catamaran",
487
+ "CD player",
488
+ "cello",
489
+ "cellular telephone",
490
+ "chain",
491
+ "chainlink fence",
492
+ "chain mail",
493
+ "chain saw",
494
+ "chest",
495
+ "chiffonier",
496
+ "chime",
497
+ "china cabinet",
498
+ "Christmas stocking",
499
+ "church",
500
+ "cinema",
501
+ "cleaver",
502
+ "cliff dwelling",
503
+ "cloak",
504
+ "clog",
505
+ "cocktail shaker",
506
+ "coffee mug",
507
+ "coffeepot",
508
+ "coil",
509
+ "combination lock",
510
+ "computer keyboard",
511
+ "confectionery",
512
+ "container ship",
513
+ "convertible",
514
+ "corkscrew",
515
+ "cornet",
516
+ "cowboy boot",
517
+ "cowboy hat",
518
+ "cradle",
519
+ "crane",
520
+ "crash helmet",
521
+ "crate",
522
+ "crib",
523
+ "Crock Pot",
524
+ "croquet ball",
525
+ "crutch",
526
+ "cuirass",
527
+ "dam",
528
+ "desk",
529
+ "desktop computer",
530
+ "dial telephone",
531
+ "diaper",
532
+ "digital clock",
533
+ "digital watch",
534
+ "dining table",
535
+ "dishrag",
536
+ "dishwasher",
537
+ "disk brake",
538
+ "dock",
539
+ "dogsled",
540
+ "dome",
541
+ "doormat",
542
+ "drilling platform",
543
+ "drum",
544
+ "drumstick",
545
+ "dumbbell",
546
+ "Dutch oven",
547
+ "electric fan",
548
+ "electric guitar",
549
+ "electric locomotive",
550
+ "entertainment center",
551
+ "envelope",
552
+ "espresso maker",
553
+ "face powder",
554
+ "feather boa",
555
+ "file",
556
+ "fireboat",
557
+ "fire engine",
558
+ "fire screen",
559
+ "flagpole",
560
+ "flute",
561
+ "folding chair",
562
+ "football helmet",
563
+ "forklift",
564
+ "fountain",
565
+ "fountain pen",
566
+ "four-poster",
567
+ "freight car",
568
+ "French horn",
569
+ "frying pan",
570
+ "fur coat",
571
+ "garbage truck",
572
+ "gasmask",
573
+ "gas pump",
574
+ "goblet",
575
+ "go-kart",
576
+ "golf ball",
577
+ "golfcart",
578
+ "gondola",
579
+ "gong",
580
+ "gown",
581
+ "grand piano",
582
+ "greenhouse",
583
+ "grille",
584
+ "grocery store",
585
+ "guillotine",
586
+ "hair slide",
587
+ "hair spray",
588
+ "half track",
589
+ "hammer",
590
+ "hamper",
591
+ "hand blower",
592
+ "hand-held computer",
593
+ "handkerchief",
594
+ "hard disc",
595
+ "harmonica",
596
+ "harp",
597
+ "harvester",
598
+ "hatchet",
599
+ "holster",
600
+ "home theater",
601
+ "honeycomb",
602
+ "hook",
603
+ "hoopskirt",
604
+ "horizontal bar",
605
+ "horse cart",
606
+ "hourglass",
607
+ "iPod",
608
+ "iron",
609
+ "jack-o'-lantern",
610
+ "jean",
611
+ "jeep",
612
+ "jersey",
613
+ "jigsaw puzzle",
614
+ "jinrikisha",
615
+ "joystick",
616
+ "kimono",
617
+ "knee pad",
618
+ "knot",
619
+ "lab coat",
620
+ "ladle",
621
+ "lampshade",
622
+ "laptop",
623
+ "lawn mower",
624
+ "lens cap",
625
+ "letter opener",
626
+ "library",
627
+ "lifeboat",
628
+ "lighter",
629
+ "limousine",
630
+ "liner",
631
+ "lipstick",
632
+ "Loafer",
633
+ "lotion",
634
+ "loudspeaker",
635
+ "loupe",
636
+ "lumbermill",
637
+ "magnetic compass",
638
+ "mailbag",
639
+ "mailbox",
640
+ "maillot",
641
+ "maillot tank suit",
642
+ "manhole cover",
643
+ "maraca",
644
+ "marimba",
645
+ "mask",
646
+ "matchstick",
647
+ "maypole",
648
+ "maze",
649
+ "measuring cup",
650
+ "medicine chest",
651
+ "megalith",
652
+ "microphone",
653
+ "microwave",
654
+ "military uniform",
655
+ "milk can",
656
+ "minibus",
657
+ "miniskirt",
658
+ "minivan",
659
+ "missile",
660
+ "mitten",
661
+ "mixing bowl",
662
+ "mobile home",
663
+ "Model T",
664
+ "modem",
665
+ "monastery",
666
+ "monitor",
667
+ "moped",
668
+ "mortar",
669
+ "mortarboard",
670
+ "mosque",
671
+ "mosquito net",
672
+ "motor scooter",
673
+ "mountain bike",
674
+ "mountain tent",
675
+ "mouse",
676
+ "mousetrap",
677
+ "moving van",
678
+ "muzzle",
679
+ "nail",
680
+ "neck brace",
681
+ "necklace",
682
+ "nipple",
683
+ "notebook",
684
+ "obelisk",
685
+ "oboe",
686
+ "ocarina",
687
+ "odometer",
688
+ "oil filter",
689
+ "organ",
690
+ "oscilloscope",
691
+ "overskirt",
692
+ "oxcart",
693
+ "oxygen mask",
694
+ "packet",
695
+ "paddle",
696
+ "paddlewheel",
697
+ "padlock",
698
+ "paintbrush",
699
+ "pajama",
700
+ "palace",
701
+ "panpipe",
702
+ "paper towel",
703
+ "parachute",
704
+ "parallel bars",
705
+ "park bench",
706
+ "parking meter",
707
+ "passenger car",
708
+ "patio",
709
+ "pay-phone",
710
+ "pedestal",
711
+ "pencil box",
712
+ "pencil sharpener",
713
+ "perfume",
714
+ "Petri dish",
715
+ "photocopier",
716
+ "pick",
717
+ "pickelhaube",
718
+ "picket fence",
719
+ "pickup",
720
+ "pier",
721
+ "piggy bank",
722
+ "pill bottle",
723
+ "pillow",
724
+ "ping-pong ball",
725
+ "pinwheel",
726
+ "pirate",
727
+ "pitcher",
728
+ "plane",
729
+ "planetarium",
730
+ "plastic bag",
731
+ "plate rack",
732
+ "plow",
733
+ "plunger",
734
+ "Polaroid camera",
735
+ "pole",
736
+ "police van",
737
+ "poncho",
738
+ "pool table",
739
+ "pop bottle",
740
+ "pot",
741
+ "potter's wheel",
742
+ "power drill",
743
+ "prayer rug",
744
+ "printer",
745
+ "prison",
746
+ "projectile",
747
+ "projector",
748
+ "puck",
749
+ "punching bag",
750
+ "purse",
751
+ "quill",
752
+ "quilt",
753
+ "racer",
754
+ "racket",
755
+ "radiator",
756
+ "radio",
757
+ "radio telescope",
758
+ "rain barrel",
759
+ "recreational vehicle",
760
+ "reel",
761
+ "reflex camera",
762
+ "refrigerator",
763
+ "remote control",
764
+ "restaurant",
765
+ "revolver",
766
+ "rifle",
767
+ "rocking chair",
768
+ "rotisserie",
769
+ "rubber eraser",
770
+ "rugby ball",
771
+ "rule",
772
+ "running shoe",
773
+ "safe",
774
+ "safety pin",
775
+ "saltshaker",
776
+ "sandal",
777
+ "sarong",
778
+ "sax",
779
+ "scabbard",
780
+ "scale",
781
+ "school bus",
782
+ "schooner",
783
+ "scoreboard",
784
+ "screen",
785
+ "screw",
786
+ "screwdriver",
787
+ "seat belt",
788
+ "sewing machine",
789
+ "shield",
790
+ "shoe shop",
791
+ "shoji",
792
+ "shopping basket",
793
+ "shopping cart",
794
+ "shovel",
795
+ "shower cap",
796
+ "shower curtain",
797
+ "ski",
798
+ "ski mask",
799
+ "sleeping bag",
800
+ "slide rule",
801
+ "sliding door",
802
+ "slot",
803
+ "snorkel",
804
+ "snowmobile",
805
+ "snowplow",
806
+ "soap dispenser",
807
+ "soccer ball",
808
+ "sock",
809
+ "solar dish",
810
+ "sombrero",
811
+ "soup bowl",
812
+ "space bar",
813
+ "space heater",
814
+ "space shuttle",
815
+ "spatula",
816
+ "speedboat",
817
+ "spider web",
818
+ "spindle",
819
+ "sports car",
820
+ "spotlight",
821
+ "stage",
822
+ "steam locomotive",
823
+ "steel arch bridge",
824
+ "steel drum",
825
+ "stethoscope",
826
+ "stole",
827
+ "stone wall",
828
+ "stopwatch",
829
+ "stove",
830
+ "strainer",
831
+ "streetcar",
832
+ "stretcher",
833
+ "studio couch",
834
+ "stupa",
835
+ "submarine",
836
+ "suit",
837
+ "sundial",
838
+ "sunglass",
839
+ "sunglasses",
840
+ "sunscreen",
841
+ "suspension bridge",
842
+ "swab",
843
+ "sweatshirt",
844
+ "swimming trunks",
845
+ "swing",
846
+ "switch",
847
+ "syringe",
848
+ "table lamp",
849
+ "tank",
850
+ "tape player",
851
+ "teapot",
852
+ "teddy",
853
+ "television",
854
+ "tennis ball",
855
+ "thatch",
856
+ "theater curtain",
857
+ "thimble",
858
+ "thresher",
859
+ "throne",
860
+ "tile roof",
861
+ "toaster",
862
+ "tobacco shop",
863
+ "toilet seat",
864
+ "torch",
865
+ "totem pole",
866
+ "tow truck",
867
+ "toyshop",
868
+ "tractor",
869
+ "trailer truck",
870
+ "tray",
871
+ "trench coat",
872
+ "tricycle",
873
+ "trimaran",
874
+ "tripod",
875
+ "triumphal arch",
876
+ "trolleybus",
877
+ "trombone",
878
+ "tub",
879
+ "turnstile",
880
+ "typewriter keyboard",
881
+ "umbrella",
882
+ "unicycle",
883
+ "upright",
884
+ "vacuum",
885
+ "vase",
886
+ "vault",
887
+ "velvet",
888
+ "vending machine",
889
+ "vestment",
890
+ "viaduct",
891
+ "violin",
892
+ "volleyball",
893
+ "waffle iron",
894
+ "wall clock",
895
+ "wallet",
896
+ "wardrobe",
897
+ "warplane",
898
+ "washbasin",
899
+ "washer",
900
+ "water bottle",
901
+ "water jug",
902
+ "water tower",
903
+ "whiskey jug",
904
+ "whistle",
905
+ "wig",
906
+ "window screen",
907
+ "window shade",
908
+ "Windsor tie",
909
+ "wine bottle",
910
+ "wing",
911
+ "wok",
912
+ "wooden spoon",
913
+ "wool",
914
+ "worm fence",
915
+ "wreck",
916
+ "yawl",
917
+ "yurt",
918
+ "web site",
919
+ "comic book",
920
+ "crossword puzzle",
921
+ "street sign",
922
+ "traffic light",
923
+ "book jacket",
924
+ "menu",
925
+ "plate",
926
+ "guacamole",
927
+ "consomme",
928
+ "hot pot",
929
+ "trifle",
930
+ "ice cream",
931
+ "ice lolly",
932
+ "French loaf",
933
+ "bagel",
934
+ "pretzel",
935
+ "cheeseburger",
936
+ "hotdog",
937
+ "mashed potato",
938
+ "head cabbage",
939
+ "broccoli",
940
+ "cauliflower",
941
+ "zucchini",
942
+ "spaghetti squash",
943
+ "acorn squash",
944
+ "butternut squash",
945
+ "cucumber",
946
+ "artichoke",
947
+ "bell pepper",
948
+ "cardoon",
949
+ "mushroom",
950
+ "Granny Smith",
951
+ "strawberry",
952
+ "orange",
953
+ "lemon",
954
+ "fig",
955
+ "pineapple",
956
+ "banana",
957
+ "jackfruit",
958
+ "custard apple",
959
+ "pomegranate",
960
+ "hay",
961
+ "carbonara",
962
+ "chocolate sauce",
963
+ "dough",
964
+ "meat loaf",
965
+ "pizza",
966
+ "potpie",
967
+ "burrito",
968
+ "red wine",
969
+ "espresso",
970
+ "cup",
971
+ "eggnog",
972
+ "alp",
973
+ "bubble",
974
+ "cliff",
975
+ "coral reef",
976
+ "geyser",
977
+ "lakeside",
978
+ "promontory",
979
+ "sandbar",
980
+ "seashore",
981
+ "valley",
982
+ "volcano",
983
+ "ballplayer",
984
+ "groom",
985
+ "scuba diver",
986
+ "rapeseed",
987
+ "daisy",
988
+ "yellow lady's slipper",
989
+ "corn",
990
+ "acorn",
991
+ "hip",
992
+ "buckeye",
993
+ "coral fungus",
994
+ "agaric",
995
+ "gyromitra",
996
+ "stinkhorn",
997
+ "earthstar",
998
+ "hen-of-the-woods",
999
+ "bolete",
1000
+ "ear",
1001
+ "toilet tissue"
1002
+ ]
install_ethos_u85_graviton.sh ADDED
@@ -0,0 +1,398 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # Standalone Ethos-U85 + Corstone-320 installer for AWS Graviton.
3
+ #
4
+ # Prefers a SHARED runtime directory (default: /opt/ethos-u85-graviton) so
5
+ # every model bundle that needs Ethos-U85 + Corstone-320 can reuse the same
6
+ # ExecuTorch build, arm_executor_runner and FVP instead of rebuilding its own
7
+ # copy. Using /opt requires sudo once, to create and chown it.
8
+ #
9
+ # If sudo is not available (no password, user not in sudoers, non-interactive
10
+ # session with no way to prompt), the installer automatically falls back to a
11
+ # LOCAL, per-bundle install under <this-bundle-dir>/runtime instead. No sudo
12
+ # is needed for that, but the install is then private to this model bundle
13
+ # and will be rebuilt from scratch by any other bundle that needs it.
14
+ #
15
+ # Force a specific location (bypassing the sudo probe entirely) with
16
+ # ETHOS_RUNTIME_DIR=/some/other/path.
17
+
18
+ set -euo pipefail
19
+
20
+ BUNDLE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
+ SHARED_RUNTIME_DIR="/opt/ethos-u85-graviton"
22
+ LOCAL_RUNTIME_DIR="${BUNDLE_DIR}/runtime"
23
+ EXECUTORCH_VERSION="1.1.0"
24
+ SKIP_SYSTEM_PACKAGES=0
25
+ FORCE_REINSTALL=0
26
+
27
+ log() { printf '\033[0;32m[ethos-graviton]\033[0m %s\n' "$*"; }
28
+ die() { printf '\033[0;31m[ethos-graviton]\033[0m %s\n' "$*" >&2; exit 1; }
29
+
30
+ usage() {
31
+ printf '%s\n' \
32
+ "Usage: bash install_ethos_u85_graviton.sh [--skip-system-packages] [--force-reinstall]" \
33
+ "" \
34
+ "Installs the Ethos-U85 + Corstone-320 execution stack into either:" \
35
+ " - ${SHARED_RUNTIME_DIR} (shared across model bundles), if sudo works, or" \
36
+ " - ${LOCAL_RUNTIME_DIR} (this bundle only), if it does not." \
37
+ "Force a specific location (skips the sudo probe) with" \
38
+ "ETHOS_RUNTIME_DIR=/some/other/path." \
39
+ "" \
40
+ "Options:" \
41
+ " --skip-system-packages Do not invoke apt-get/dnf/yum." \
42
+ " --force-reinstall Wipe and rebuild an already-installed runtime" \
43
+ " without prompting." \
44
+ " -h, --help Show this help."
45
+ }
46
+
47
+ while [[ $# -gt 0 ]]; do
48
+ case "$1" in
49
+ --skip-system-packages) SKIP_SYSTEM_PACKAGES=1 ;;
50
+ --force-reinstall) FORCE_REINSTALL=1 ;;
51
+ -h|--help) usage; exit 0 ;;
52
+ *) usage >&2; die "Unknown argument: $1" ;;
53
+ esac
54
+ shift
55
+ done
56
+
57
+ [[ "$(id -u)" -ne 0 ]] \
58
+ || die "Do not run this script with sudo. Run 'bash install_ethos_u85_graviton.sh' as the normal user; it requests sudo itself only for system packages and the shared /opt install."
59
+ [[ "$(uname -s)" == "Linux" ]] || die "This installer supports Linux only."
60
+ case "$(uname -m)" in
61
+ aarch64|arm64) ;;
62
+ *) die "Expected an arm64/aarch64 Graviton host; found $(uname -m)." ;;
63
+ esac
64
+
65
+ run_as_root() {
66
+ if [[ "$(id -u)" -eq 0 ]]; then
67
+ "$@"
68
+ elif command -v sudo >/dev/null 2>&1; then
69
+ sudo "$@"
70
+ else
71
+ die "Root privileges are required (sudo not found)."
72
+ fi
73
+ }
74
+
75
+ install_system_packages() {
76
+ if command -v apt-get >/dev/null 2>&1; then
77
+ # Ubuntu may start unattended-upgrades immediately after boot. Let
78
+ # apt/dpkg finish instead of failing because lock-frontend is busy.
79
+ run_as_root apt-get -o DPkg::Lock::Timeout=600 update
80
+ run_as_root apt-get -o DPkg::Lock::Timeout=600 install -y \
81
+ build-essential cmake curl git ninja-build patch pkg-config \
82
+ python3 tar unzip xz-utils
83
+ elif command -v dnf >/dev/null 2>&1; then
84
+ run_as_root dnf install -y \
85
+ cmake curl gcc gcc-c++ git make ninja-build patch pkgconf-pkg-config \
86
+ python3 tar unzip xz
87
+ elif command -v yum >/dev/null 2>&1; then
88
+ run_as_root yum install -y \
89
+ cmake curl gcc gcc-c++ git make ninja-build patch pkgconfig \
90
+ python3 tar unzip xz
91
+ else
92
+ die "No supported package manager found. Install Git, CMake, curl, make, a C/C++ compiler, Python 3 and unzip; then use --skip-system-packages."
93
+ fi
94
+ }
95
+
96
+ # --- Decide where to install: shared /opt (needs sudo) or a local,
97
+ # per-bundle fallback (no sudo needed) ---------------------------------------
98
+ # An explicit ETHOS_RUNTIME_DIR always wins and skips the sudo probe below;
99
+ # HAVE_ROOT then just tracks whether we're allowed to sudo-bootstrap it if
100
+ # it turns out to need elevated privileges too.
101
+ HAVE_ROOT=0
102
+ if [[ -n "${ETHOS_RUNTIME_DIR:-}" ]]; then
103
+ RUNTIME_DIR="${ETHOS_RUNTIME_DIR}"
104
+ log "ETHOS_RUNTIME_DIR set: installing into ${RUNTIME_DIR}."
105
+ elif command -v sudo >/dev/null 2>&1; then
106
+ log "Checking sudo access (used for system packages and for the shared ${SHARED_RUNTIME_DIR} install; you may be prompted for your password)..."
107
+ if sudo -v; then
108
+ HAVE_ROOT=1
109
+ RUNTIME_DIR="${SHARED_RUNTIME_DIR}"
110
+ log "Sudo access confirmed: installing the shared runtime at ${RUNTIME_DIR}."
111
+ else
112
+ log "Sudo access denied or unavailable: falling back to a local, per-bundle install at ${LOCAL_RUNTIME_DIR}."
113
+ log "This bundle will build its own copy of the Ethos-U85 stack instead of sharing one under ${SHARED_RUNTIME_DIR}. System package installation will also be skipped (it needs sudo too) — install them manually if they are missing."
114
+ RUNTIME_DIR="${LOCAL_RUNTIME_DIR}"
115
+ SKIP_SYSTEM_PACKAGES=1
116
+ fi
117
+ else
118
+ log "sudo is not installed: falling back to a local, per-bundle install at ${LOCAL_RUNTIME_DIR}."
119
+ RUNTIME_DIR="${LOCAL_RUNTIME_DIR}"
120
+ SKIP_SYSTEM_PACKAGES=1
121
+ fi
122
+
123
+ ET_SRC="${RUNTIME_DIR}/executorch"
124
+ BIN_DIR="${RUNTIME_DIR}/bin"
125
+ ET_BUILD_ROOT="${ET_SRC}/arm_test"
126
+ BUILD_VENV="${RUNTIME_DIR}/build-venv"
127
+ INSTALL_MARKER="${RUNTIME_DIR}/.ethos-u85-graviton-install-complete-v1"
128
+
129
+ # Detect a previously completed installation before doing any more work (uv,
130
+ # ExecuTorch build, ...). Other model bundles may already have installed the
131
+ # shared runtime, so surface that instead of silently re-running or silently
132
+ # skipping.
133
+ if [[ -f "${INSTALL_MARKER}" ]]; then
134
+ log "Ethos-U85 + Corstone-320 runtime already installed at ${RUNTIME_DIR}:"
135
+ sed 's/^/ /' "${INSTALL_MARKER}"
136
+ if [[ "${FORCE_REINSTALL}" -eq 1 ]]; then
137
+ log "--force-reinstall given: removing ${RUNTIME_DIR} and rebuilding..."
138
+ rm -rf "${RUNTIME_DIR}"
139
+ elif [[ -t 0 ]]; then
140
+ read -r -p "Reinstall from scratch? This removes and rebuilds the runtime. [y/N] " reply
141
+ case "${reply}" in
142
+ [yY]|[yY][eE][sS])
143
+ log "Reinstalling: removing ${RUNTIME_DIR}..."
144
+ rm -rf "${RUNTIME_DIR}"
145
+ ;;
146
+ *)
147
+ log "Keeping the existing installation. Nothing to do."
148
+ exit 0
149
+ ;;
150
+ esac
151
+ else
152
+ log "Non-interactive session: keeping the existing installation."
153
+ log "Re-run with --force-reinstall to rebuild it. Nothing to do."
154
+ exit 0
155
+ fi
156
+ fi
157
+
158
+ if [[ "${SKIP_SYSTEM_PACKAGES}" -eq 0 ]]; then
159
+ log "Installing system packages..."
160
+ install_system_packages
161
+ fi
162
+
163
+ for command_name in git cmake curl make python3; do
164
+ command -v "${command_name}" >/dev/null 2>&1 \
165
+ || die "Missing required command: ${command_name}"
166
+ done
167
+
168
+ if ! command -v uv >/dev/null 2>&1 || ! uv --version >/dev/null 2>&1; then
169
+ log "Installing uv..."
170
+ curl -LsSf https://astral.sh/uv/install.sh | sh
171
+ fi
172
+ UV=""
173
+ if [[ -x "${HOME}/.local/bin/uv" ]] \
174
+ && "${HOME}/.local/bin/uv" --version >/dev/null 2>&1; then
175
+ UV="${HOME}/.local/bin/uv"
176
+ elif command -v uv >/dev/null 2>&1 && uv --version >/dev/null 2>&1; then
177
+ UV="$(command -v uv)"
178
+ fi
179
+ [[ -n "${UV}" ]] || die "uv installation failed."
180
+ if ! command -v uv >/dev/null 2>&1 || ! uv --version >/dev/null 2>&1; then
181
+ if [[ "${HAVE_ROOT}" -eq 1 ]]; then
182
+ log "Making uv available as /usr/local/bin/uv..."
183
+ run_as_root ln -sf "${UV}" /usr/local/bin/uv
184
+ else
185
+ log "uv is available at ${UV} but not on the system PATH; skipping the /usr/local/bin/uv symlink (no sudo access). This script uses ${UV} directly, so it still works."
186
+ fi
187
+ fi
188
+
189
+ # Bootstrap RUNTIME_DIR. Plain mkdir covers the local, per-bundle fallback
190
+ # (already user-writable); the shared /opt location typically needs sudo the
191
+ # first time, handled here lazily via run_as_root.
192
+ if [[ ! -e "${RUNTIME_DIR}" ]]; then
193
+ if ! mkdir -p "${RUNTIME_DIR}" 2>/dev/null; then
194
+ log "${RUNTIME_DIR} requires elevated privileges to create..."
195
+ run_as_root mkdir -p "${RUNTIME_DIR}"
196
+ run_as_root chown "$(id -un):$(id -gn)" "${RUNTIME_DIR}"
197
+ fi
198
+ elif [[ ! -w "${RUNTIME_DIR}" ]]; then
199
+ die "${RUNTIME_DIR} is not writable. A previous run under a different user may own it. Run: sudo chown -R \"$(id -un):$(id -gn)\" \"${RUNTIME_DIR}\""
200
+ fi
201
+ mkdir -p "${RUNTIME_DIR}" "${BIN_DIR}"
202
+
203
+ # ExecuTorch's CMake code-generation scripts import PyYAML and torchgen while
204
+ # building the portable, quantized and Cortex-M operator registries. torchgen
205
+ # is distributed as part of PyTorch. ExecuTorch 1.1 also requires CMake 3.29+
206
+ # and does not support CMake 4, so use a pinned copy in this environment. Keep
207
+ # these build-only dependencies separate from the inference pyproject.toml.
208
+ if [[ ! -x "${BUILD_VENV}/bin/python" ]]; then
209
+ log "Creating the Python environment used by ExecuTorch code generation..."
210
+ "${UV}" venv "${BUILD_VENV}" --python 3.12
211
+ fi
212
+ if ! "${BUILD_VENV}/bin/python" -c \
213
+ 'import importlib.metadata as m, torchgen, yaml; assert tuple(map(int, m.version("torch").split("+")[0].split(".")[:2])) == (2, 10)' \
214
+ 2>/dev/null \
215
+ || [[ ! -x "${BUILD_VENV}/bin/cmake" ]] \
216
+ || ! "${BUILD_VENV}/bin/python" -c \
217
+ 'import subprocess, sys; v=tuple(map(int, subprocess.check_output([sys.argv[1], "--version"], text=True).split()[2].split(".")[:2])); assert (3, 29) <= v < (4, 0)' \
218
+ "${BUILD_VENV}/bin/cmake" 2>/dev/null; then
219
+ log "Installing the pinned CMake and Python code-generation dependencies..."
220
+ "${UV}" pip install --python "${BUILD_VENV}/bin/python" \
221
+ "cmake>=3.29,<4" "PyYAML>=6,<7" "torch>=2.10,<2.11"
222
+ fi
223
+ export PATH="${BUILD_VENV}/bin:${PATH}"
224
+
225
+ if [[ ! -d "${ET_SRC}/.git" ]]; then
226
+ log "Cloning ExecuTorch ${EXECUTORCH_VERSION}..."
227
+ git clone --branch "v${EXECUTORCH_VERSION}" --recurse-submodules \
228
+ https://github.com/pytorch/executorch.git "${ET_SRC}"
229
+ fi
230
+ # Some nested dependency fetches require an identity. Keep the fallback local
231
+ # to this generated checkout and do not modify the user's global Git config.
232
+ if ! git -C "${ET_SRC}" config user.name >/dev/null; then
233
+ git -C "${ET_SRC}" config user.name "Ethos standalone installer"
234
+ fi
235
+ if ! git -C "${ET_SRC}" config user.email >/dev/null; then
236
+ git -C "${ET_SRC}" config user.email "ethos-installer@localhost"
237
+ fi
238
+
239
+ ARM_SETUP="${ET_SRC}/examples/arm/setup.sh"
240
+ PATCH_SENTINEL='# STANDALONE-RUNTIME-ONLY-PATCH-V1'
241
+ if ! grep -q "${PATCH_SENTINEL}" "${ARM_SETUP}"; then
242
+ log "Configuring ExecuTorch setup for runtime-only installation..."
243
+ sed -i.bak \
244
+ "/# Setup the TOSA reference model and serialization dependencies/i\\
245
+ log_step \"main\" \"Runtime-only setup complete; skipping TOSA and Vela.\"\\
246
+ exit 0 ${PATCH_SENTINEL}" \
247
+ "${ARM_SETUP}"
248
+ fi
249
+
250
+ # The upstream helper installs Corstone-300 and Corstone-320 together. This
251
+ # bundle only targets Ethos-U85, so avoid downloading the unused Corstone-300.
252
+ FVP_UTILS="${ET_SRC}/backends/arm/scripts/fvp_utils.sh"
253
+ if grep -q 'fvps=("corstone300" "corstone320")' "${FVP_UTILS}"; then
254
+ sed -i.bak \
255
+ 's/fvps=("corstone300" "corstone320")/fvps=("corstone320")/g' \
256
+ "${FVP_UTILS}"
257
+ fi
258
+
259
+ SETUP_PATH="${ET_SRC}/examples/arm/arm-scratch/setup_path.sh"
260
+ if [[ ! -f "${SETUP_PATH}" ]]; then
261
+ log "Installing the Arm GNU toolchain and Corstone FVP (Arm EULA accepted)..."
262
+ (
263
+ cd "${ET_SRC}"
264
+ bash examples/arm/setup.sh --i-agree-to-the-contained-eula \
265
+ --enable-baremetal-toolchain --enable-fvps
266
+ )
267
+ fi
268
+ [[ -f "${SETUP_PATH}" ]] || die "Arm setup did not create ${SETUP_PATH}."
269
+ # setup_path.sh unconditionally hashes all three Corstone FVP names, but this
270
+ # bundle only installs corstone320. Under `set -e`, sourcing it would abort
271
+ # here on the first missing FVP's failing `hash` call, so drop those lines.
272
+ sed -i.bak '/^hash FVP_Corstone_SSE-300_Ethos-U55$/d;/^hash FVP_Corstone_SSE-300_Ethos-U65$/d' \
273
+ "${SETUP_PATH}"
274
+ # shellcheck disable=SC1090
275
+ source "${SETUP_PATH}"
276
+ # setup_path.sh adds Arm tools to PATH. Put the code-generation Python back at
277
+ # the front so CMake does not discover a stale system/Snap Python instead.
278
+ export PATH="${BUILD_VENV}/bin:${PATH}"
279
+ unset PYTHONHOME
280
+ unset PYTHONPATH
281
+ # Expose only ExecuTorch's source-package layout. This lets both `python -m
282
+ # codegen...` and the runner's direct `python codegen/...py` invocation resolve
283
+ # imports without inheriting unrelated Snap paths from the login environment.
284
+ export PYTHONPATH="${ET_SRC}/src"
285
+ command -v arm-none-eabi-gcc >/dev/null 2>&1 \
286
+ || die "Arm GNU toolchain is missing after setup. Remove ${SETUP_PATH} and rerun the installer."
287
+ command -v FVP_Corstone_SSE-320 >/dev/null 2>&1 \
288
+ || die "Corstone-320 FVP is missing after setup. Remove ${SETUP_PATH} and rerun the installer."
289
+
290
+ # build_executorch.sh normally lets CMake discover Python through PATH. Make
291
+ # the interpreter explicit as well, so neither a Snap Python nor a previous
292
+ # CMake discovery can leak into generated dependency rules.
293
+ ET_BUILD_SCRIPT="${ET_SRC}/backends/arm/scripts/build_executorch.sh"
294
+ if ! grep -q 'STANDALONE_CODEGEN_PYTHON' "${ET_BUILD_SCRIPT}"; then
295
+ sed -i.bak \
296
+ '/-DCMAKE_BUILD_TYPE=${build_type}/i\
297
+ -DPYTHON_EXECUTABLE="${STANDALONE_CODEGEN_PYTHON}" \\' \
298
+ "${ET_BUILD_SCRIPT}"
299
+ fi
300
+ export STANDALONE_CODEGEN_PYTHON="${BUILD_VENV}/bin/python"
301
+
302
+ log "Checking the ExecuTorch code-generation Python environment..."
303
+ (
304
+ cd "${ET_SRC}"
305
+ cmake_version="$(cmake --version | head -n 1)"
306
+ "${STANDALONE_CODEGEN_PYTHON}" -c \
307
+ 'import subprocess; v=tuple(map(int, subprocess.check_output(["cmake", "--version"], text=True).split()[2].split(".")[:2])); assert (3, 29) <= v < (4, 0), v' \
308
+ || die "Expected CMake >=3.29,<4; found: ${cmake_version}"
309
+ "${STANDALONE_CODEGEN_PYTHON}" -c \
310
+ 'import torchgen, yaml; from executorch.codegen.tools import gen_oplist'
311
+ )
312
+
313
+ CMAKE_BUILD_DIR="${ET_BUILD_ROOT}/cmake-out"
314
+ BUILD_COMPLETE_MARKER="${ET_BUILD_ROOT}/.runtime-libs-complete-v2"
315
+ if [[ ! -f "${BUILD_COMPLETE_MARKER}" ]]; then
316
+ # The CMake package config is produced before compilation finishes. It
317
+ # therefore cannot be used as a success marker. Always clear an incomplete
318
+ # tree so Make cannot retain dependencies on a removed Snap.
319
+ log "Removing any incomplete CMake build before compiling ExecuTorch..."
320
+ rm -rf "${CMAKE_BUILD_DIR}"
321
+ log "Building the ExecuTorch bare-metal libraries..."
322
+ (
323
+ cd "${ET_SRC}"
324
+ bash "${ET_BUILD_SCRIPT}" \
325
+ --et_build_root="${ET_BUILD_ROOT}" \
326
+ --build_type=Release \
327
+ --toolchain=arm-none-eabi-gcc
328
+ )
329
+ [[ -f "${CMAKE_BUILD_DIR}/lib/cmake/ExecuTorch/executorch-config.cmake" ]] \
330
+ || die "ExecuTorch build finished without installing executorch-config.cmake."
331
+ find "${CMAKE_BUILD_DIR}" -type f -name 'libexecutorch.a' -print -quit \
332
+ | grep -q . || die "ExecuTorch build finished without libexecutorch.a."
333
+ printf 'python=%s\ncompleted_at=%s\n' \
334
+ "$(realpath "${STANDALONE_CODEGEN_PYTHON}")" \
335
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "${BUILD_COMPLETE_MARKER}"
336
+ fi
337
+
338
+ # The delegate can require more than the 2 MiB (0x200000) default temporary
339
+ # allocator, so the CMake constant is set to 16 MiB before building.
340
+ RUNNER_TEMP_POOL="0x1000000"
341
+ RUNNER_CMAKE="${ET_SRC}/examples/arm/executor_runner/CMakeLists.txt"
342
+ if [[ -f "${RUNNER_CMAKE}" ]] && ! grep -q "# AMO-POOL-PATCHED" "${RUNNER_CMAKE}"; then
343
+ log "Patching ${RUNNER_CMAKE} to use ${RUNNER_TEMP_POOL} temp pool..."
344
+ grep -q "set(ET_ARM_BAREMETAL_SCRATCH_TEMP_ALLOCATOR_POOL_SIZE 0x200000)" "${RUNNER_CMAKE}" \
345
+ || die "Expected upstream 'set(...0x200000)' line in ${RUNNER_CMAKE} — version drift?"
346
+ sed -i.bak \
347
+ "s|set(ET_ARM_BAREMETAL_SCRATCH_TEMP_ALLOCATOR_POOL_SIZE 0x200000)|set(ET_ARM_BAREMETAL_SCRATCH_TEMP_ALLOCATOR_POOL_SIZE ${RUNNER_TEMP_POOL}) # AMO-POOL-PATCHED|" \
348
+ "${RUNNER_CMAKE}"
349
+ fi
350
+
351
+ RUNNER_LINK="${BIN_DIR}/arm_executor_runner"
352
+ RUNNER_BUILD_DIR="${ET_BUILD_ROOT}/ethos-u85-256_semihosting/cmake-out"
353
+ RUNNER_PROFILE_MARKER="${RUNNER_BUILD_DIR}/.sram-only-pool-${RUNNER_TEMP_POOL}-complete-v1"
354
+ if [[ ! -x "${RUNNER_LINK}" || ! -f "${RUNNER_PROFILE_MARKER}" ]]; then
355
+ # The upstream script defaults --output to the current directory for a
356
+ # semihosting runner. Always use a dedicated build tree and discard it if
357
+ # the previous attempt did not produce a runner.
358
+ rm -rf "${RUNNER_BUILD_DIR}"
359
+ log "Building the Ethos-U85 semihosting runner (Sram_Only, scratch=${RUNNER_TEMP_POOL})..."
360
+ (
361
+ cd "${ET_SRC}"
362
+ bash backends/arm/scripts/build_executor_runner.sh \
363
+ --et_build_root="${ET_BUILD_ROOT}" \
364
+ --pte=semihosting \
365
+ --target=ethos-u85-256 \
366
+ --system_config=Ethos_U85_SYS_DRAM_Mid \
367
+ --memory_mode=Sram_Only \
368
+ --ethosu_tools_dir="${ET_SRC}/examples/arm/arm-scratch" \
369
+ --output="${RUNNER_BUILD_DIR}" \
370
+ --toolchain=arm-none-eabi-gcc
371
+ )
372
+ RUNNER_FOUND="$(find "${RUNNER_BUILD_DIR}" -type f \
373
+ -name arm_executor_runner -not -path '*/CMakeFiles/*' | head -n 1)"
374
+ [[ -n "${RUNNER_FOUND}" ]] || die "Runner build finished but no ELF was found."
375
+ ln -sf "${RUNNER_FOUND}" "${RUNNER_LINK}"
376
+ printf 'runner=%s\ncompleted_at=%s\n' \
377
+ "$(realpath "${RUNNER_FOUND}")" \
378
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "${RUNNER_PROFILE_MARKER}"
379
+ fi
380
+
381
+ FVP_FOUND="$(find "${ET_SRC}/examples/arm/arm-scratch" -type f \
382
+ -name FVP_Corstone_SSE-320 -perm -u+x | head -n 1)"
383
+ [[ -n "${FVP_FOUND}" ]] || die "Corstone-320 FVP was not found."
384
+ ln -sf "${FVP_FOUND}" "${BIN_DIR}/FVP_Corstone_SSE-320"
385
+
386
+ [[ -x "${RUNNER_LINK}" ]] || die "Runner verification failed."
387
+ [[ -x "${BIN_DIR}/FVP_Corstone_SSE-320" ]] || die "FVP verification failed."
388
+
389
+ RUNTIME_KIND="local"
390
+ [[ "${RUNTIME_DIR}" == "${SHARED_RUNTIME_DIR}" ]] && RUNTIME_KIND="shared"
391
+ printf 'installed_at=%s\nexecutorch_version=%s\nmemory_mode=Sram_Only\nruntime_kind=%s\ninstalled_by_bundle=%s\n' \
392
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "${EXECUTORCH_VERSION}" "${RUNTIME_KIND}" "${BUNDLE_DIR}" > "${INSTALL_MARKER}"
393
+
394
+ log "Standalone installation completed in ${RUNTIME_DIR}."
395
+ log "Next commands:"
396
+ log " cd ${BUNDLE_DIR}"
397
+ log " uv sync --frozen"
398
+ log " uv run example.py"
predictions.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "rank": 1,
4
+ "class_index": 258,
5
+ "class_name": "Samoyed",
6
+ "probability": 0.8419339539799012
7
+ },
8
+ {
9
+ "rank": 2,
10
+ "class_index": 248,
11
+ "class_name": "Eskimo dog",
12
+ "probability": 0.017925628222684828
13
+ },
14
+ {
15
+ "rank": 3,
16
+ "class_index": 224,
17
+ "class_name": "groenendael",
18
+ "probability": 0.015007706192767745
19
+ },
20
+ {
21
+ "rank": 4,
22
+ "class_index": 270,
23
+ "class_name": "white wolf",
24
+ "probability": 0.015007706192767745
25
+ },
26
+ {
27
+ "rank": 5,
28
+ "class_index": 259,
29
+ "class_name": "Pomeranian",
30
+ "probability": 0.006949499845333793
31
+ }
32
+ ]
pyproject.toml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "ethos-u85-graviton-runner"
3
+ version = "0.1.0"
4
+ description = "Minimal host-side dependencies for Corstone-320 FVP inference"
5
+ requires-python = ">=3.12,<3.13"
6
+ dependencies = [
7
+ "numpy==2.5.3",
8
+ "pillow==12.3.0",
9
+ ]
10
+
11
+ [tool.uv]
12
+ package = false
13
+
14
+ [tool.ai-portal.deployment]
15
+ schema-version = "1"
16
+ runtime = "executorch"
17
+ required-capabilities = ["EthosUBackend"]
18
+
19
+ [tool.ai-portal.deployment.ubuntu]
20
+ packages = []
21
+
22
+ [tool.ai-portal.deployment.raspbian]
23
+ packages = []
24
+
25
+ [tool.ai-portal.deployment.files]
26
+ expected = ["predictions.json"]
sample_input.jpg ADDED

Git LFS Details

  • SHA256: c27d32d9074fac88390251149b2424cd99971ddfe0eedcbc7494cabf63d55fac
  • Pointer size: 131 Bytes
  • Size of remote file: 137 kB
uv.lock ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version = 1
2
+ revision = 3
3
+ requires-python = "==3.12.*"
4
+
5
+ [[package]]
6
+ name = "ethos-u85-graviton-runner"
7
+ version = "0.1.0"
8
+ source = { virtual = "." }
9
+ dependencies = [
10
+ { name = "numpy" },
11
+ { name = "pillow" },
12
+ ]
13
+
14
+ [package.metadata]
15
+ requires-dist = [
16
+ { name = "numpy", specifier = "==2.5.3" },
17
+ { name = "pillow", specifier = "==12.3.0" },
18
+ ]
19
+
20
+ [[package]]
21
+ name = "numpy"
22
+ version = "2.5.3"
23
+ source = { registry = "https://pypi.org/simple" }
24
+ sdist = { url = "https://files.pythonhosted.org/packages/13/01/11703282db468b85f6f7b8c7f22d058de5970d5c7e60a3a8aaa313c3de36/numpy-2.5.3.tar.gz", hash = "sha256:df2d5874ff183595a4ba404edd04f6bd9b5505c1d7708573f6a6c17489a67563", size = 20791231, upload-time = "2026-09-06T16:27:47.073Z" }
25
+ wheels = [
26
+ { url = "https://files.pythonhosted.org/packages/d6/50/8fdbb16af64895706a45f06a4068e29db732ec180f3c1375f14123359138/numpy-2.5.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cb189f09db39283b26bfd061ec16189e14f71c6755207f72a0f7540867afe5b9", size = 16994982, upload-time = "2026-09-06T16:24:29.244Z" },
27
+ { url = "https://files.pythonhosted.org/packages/60/39/789131c1188c078dcb3a1692e72e1e050c68b88ffe72c9ccaac9bcd7a9cd/numpy-2.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f59a878c33d6b88122d80d239bb3b845d58708750b0cb06a09aebb9b18ec696c", size = 12009327, upload-time = "2026-09-06T16:24:32.491Z" },
28
+ { url = "https://files.pythonhosted.org/packages/9c/59/a312e95696e5f601914dd8b6dd844692ba61670807417e24b68e337b5c70/numpy-2.5.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a72f874bc9e10e4b8f80426fb49716d5141f64442a0c8418065093ec8017fbb0", size = 5445405, upload-time = "2026-09-06T16:24:35.071Z" },
29
+ { url = "https://files.pythonhosted.org/packages/30/d0/5623a1707ed4fe16e3909fe3cf5ee3da004ae677ad23d83bbf3adf1a6faf/numpy-2.5.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:fc36dc566135b5eceec4cf89758fcb719266a019ef07dae1754ae7c9f617ef3e", size = 6783213, upload-time = "2026-09-06T16:24:37.253Z" },
30
+ { url = "https://files.pythonhosted.org/packages/f1/32/84146fc020ad3c25f805f70ab60da46fe3c540a21369754a7e4369754b6f/numpy-2.5.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:76c2c1e6bfa5c84adc6434dfbf013aa92096a7985221762c8f11fedfd20fff58", size = 15687872, upload-time = "2026-09-06T16:24:39.751Z" },
31
+ { url = "https://files.pythonhosted.org/packages/65/af/aa78d1a88805456e212b65461354cd943197fb9acecc4c90fd12295123a3/numpy-2.5.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7e18c623bb5c95acb3b3328861272816ba199fb531921c5d6d0b675f1fde9e3", size = 16717410, upload-time = "2026-09-06T16:24:42.745Z" },
32
+ { url = "https://files.pythonhosted.org/packages/3b/24/faa79d865e69a97ba17473b23a1b74094b2259c03e820c70297293b9ea49/numpy-2.5.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4f8929ee6c96bfbd7b4ed2032e0c03af86fe1826740ab61ddabf9072d06e57ff", size = 17040975, upload-time = "2026-09-06T16:24:45.961Z" },
33
+ { url = "https://files.pythonhosted.org/packages/62/4a/8877e629445a7176297dffcaf9c485faa96a95d81728a62521ad55bd4c0f/numpy-2.5.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b5d93cf48f687479941d12b69c873ad2cc76bbd487f0091c2200636497f34034", size = 18476479, upload-time = "2026-09-06T16:24:49.35Z" },
34
+ { url = "https://files.pythonhosted.org/packages/c8/db/35e1c2d38b04cbd5b731f9d71495e055e813197669d22b612f11748d2ff9/numpy-2.5.3-cp312-cp312-win32.whl", hash = "sha256:bf63afbe037eb5d2fe87fbcc7778e61da53ebaf21d938a4515aa73b62532a5d4", size = 6133378, upload-time = "2026-09-06T16:24:51.915Z" },
35
+ { url = "https://files.pythonhosted.org/packages/3c/a1/accf6d4f0c80c5d9ba9735d6b1550e444180599f34dec69ca01360f717ad/numpy-2.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0a59a421a32580a009e8a1751345bf829631b990dc1794b80514ab722b435def", size = 12567828, upload-time = "2026-09-06T16:24:54.255Z" },
36
+ { url = "https://files.pythonhosted.org/packages/22/43/1764aff32e4652526ae2f71fa8b3efd8d25c8a3d6926914454e47138ed1e/numpy-2.5.3-cp312-cp312-win_arm64.whl", hash = "sha256:ccb32e0525d29e8b0572eb84c9a57af0e7a4e615726927506f55063c62414034", size = 10485432, upload-time = "2026-09-06T16:24:57.278Z" },
37
+ ]
38
+
39
+ [[package]]
40
+ name = "pillow"
41
+ version = "12.3.0"
42
+ source = { registry = "https://pypi.org/simple" }
43
+ sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" }
44
+ wheels = [
45
+ { url = "https://files.pythonhosted.org/packages/37/bf/fb3ebff8ddcb76aac5a01389251bbbb9519922a9b520d8247c1ca864a25d/pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965", size = 5345969, upload-time = "2026-07-01T11:54:06.397Z" },
46
+ { url = "https://files.pythonhosted.org/packages/d8/66/9a386a92561f402389a4fc70c18838bf6d35eb5eb5c6850b4b2dc64f5048/pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7", size = 4780323, upload-time = "2026-07-01T11:54:09.351Z" },
47
+ { url = "https://files.pythonhosted.org/packages/25/27/ac8f99618ffd3dde21db0f4d4b1d2ab00c0880595bfd17df103f7f39fd0c/pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9", size = 6266838, upload-time = "2026-07-01T11:54:11.71Z" },
48
+ { url = "https://files.pythonhosted.org/packages/84/21/a35af28dcc61f37ed850a2d64c65c701321dfbf25085e469d5559360cbbf/pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91", size = 6940830, upload-time = "2026-07-01T11:54:13.732Z" },
49
+ { url = "https://files.pythonhosted.org/packages/eb/51/8b08617af3ad95e33ce6d7dd2c99ed6c8298f7fb131636303956be022e25/pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c", size = 6344383, upload-time = "2026-07-01T11:54:15.756Z" },
50
+ { url = "https://files.pythonhosted.org/packages/1d/72/cf78ac9780bb93c28328f408973845a309d4d145041665f734572ced1b52/pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df", size = 7052934, upload-time = "2026-07-01T11:54:17.721Z" },
51
+ { url = "https://files.pythonhosted.org/packages/20/20/25e0f4dc178a6bc0696793720055519a0de89e7661dae886992decbd2f81/pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f", size = 6472684, upload-time = "2026-07-01T11:54:19.839Z" },
52
+ { url = "https://files.pythonhosted.org/packages/45/89/da2f7971a317f83d807fdd4065c0af40208e59e692cc43d315a71a0e96d1/pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09", size = 7227137, upload-time = "2026-07-01T11:54:22.025Z" },
53
+ { url = "https://files.pythonhosted.org/packages/de/47/4845a0a6c0dbf1db8456bd9fc791f13c5ced7ced20606d08a0aacfd25b49/pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510", size = 2568267, upload-time = "2026-07-01T11:54:24.051Z" },
54
+ ]