| |
| """ |
| MobileNetV2 Image Classification using PyWebNN |
| |
| - model_id: "tarekziade/mobilenet-webnn" |
| - backend: "cpu" |
| - force_download: False |
| |
| Usage: |
| |
| $ pip install pywebnn pillow |
| $ python demo.py /path/to/image.jpg |
| |
| """ |
|
|
| import sys |
| import time |
| from pathlib import Path |
|
|
| import numpy as np |
| from PIL import Image |
| import webnn |
|
|
|
|
| MODEL_ID = "tarekziade/mobilenet-webnn" |
| BACKEND = "cpu" |
| FORCE_DOWNLOAD = False |
|
|
|
|
| def load_imagenet_labels(): |
| labels_file = Path(__file__).with_name("imagenet_classes.txt") |
| if not labels_file.exists(): |
| import urllib.request |
|
|
| url = ( |
| "https://raw.githubusercontent.com/pytorch/hub/master/imagenet_classes.txt" |
| ) |
| print(" [DOWNLOAD] ImageNet labels...") |
| urllib.request.urlretrieve(url, labels_file) |
| print(" [OK] Labels downloaded") |
|
|
| return [line.strip() for line in labels_file.read_text().splitlines()] |
|
|
|
|
| IMAGENET_CLASSES = load_imagenet_labels() |
|
|
|
|
| def preprocess_image(image_path: Path) -> np.ndarray: |
| img = Image.open(image_path).convert("RGB") |
| img = img.resize((224, 224), Image.Resampling.BILINEAR) |
|
|
| x = np.asarray(img, dtype=np.float32) / 255.0 |
| mean = np.array([0.485, 0.456, 0.406], dtype=np.float32) |
| std = np.array([0.229, 0.224, 0.225], dtype=np.float32) |
| x = (x - mean) / std |
|
|
| x = np.transpose(x, (2, 0, 1)) |
| x = np.expand_dims(x, 0) |
| return x |
|
|
|
|
| def backend_settings(backend: str): |
| if backend == "cpu": |
| return False, "default", "ONNX CPU" |
| if backend == "gpu": |
| return True, "high-performance", "ONNX GPU" |
| if backend == "coreml": |
| return True, "high-performance", "CoreML (Neural Engine)" |
| raise ValueError(f"Unknown BACKEND: {backend!r}") |
|
|
|
|
| def main(): |
| if len(sys.argv) != 2: |
| print(f"Usage: {Path(sys.argv[0]).name} /path/to/image.jpg") |
| sys.exit(2) |
|
|
| image_path = Path(sys.argv[1]) |
| if not image_path.exists(): |
| print(f"Error: Image not found: {image_path}") |
| sys.exit(1) |
|
|
| accelerated, power, backend_name = backend_settings(BACKEND) |
|
|
| print("=" * 70) |
| print("MobileNetV2 Image Classification (Hugging Face Hub)") |
| print("=" * 70) |
| print(f"Image: {image_path}") |
| print(f"Model: {MODEL_ID}") |
| print(f"Backend: {backend_name}") |
| print() |
|
|
| hub = webnn.Hub() |
|
|
| print("Downloading model from Hugging Face Hub...") |
| t0 = time.time() |
| model_files = hub.download_model(MODEL_ID, force=FORCE_DOWNLOAD) |
| download_ms = (time.time() - t0) * 1000 |
| print(f" [OK] Downloaded ({download_ms:.2f}ms)") |
| print(f" - Graph: {Path(model_files['graph']).name}") |
| print() |
|
|
| print("Loading graph...") |
| t0 = time.time() |
| graph = webnn.MLGraph.load( |
| model_files["graph"], |
| manifest_path=model_files["manifest"], |
| weights_path=model_files["weights"], |
| ) |
| load_ms = (time.time() - t0) * 1000 |
| print(f" [OK] Loaded ({load_ms:.2f}ms)") |
| print() |
|
|
| print("Preprocessing image...") |
| t0 = time.time() |
| input_data = preprocess_image(image_path) |
| prep_ms = (time.time() - t0) * 1000 |
| print(f" [OK] {input_data.shape} ({prep_ms:.2f}ms)") |
| print() |
|
|
| print("Creating WebNN context...") |
| ml = webnn.ML() |
| context = ml.create_context(power_preference=power, accelerated=accelerated) |
| print(f" [OK] Context created (accelerated={context.accelerated})") |
| print() |
|
|
| print("Running inference...") |
| t0 = time.time() |
| results = context.compute(graph, {"input": input_data}) |
| inf_ms = (time.time() - t0) * 1000 |
| print(f" [OK] Done ({inf_ms:.2f}ms)") |
| print() |
|
|
| probs = results["output"][0] |
| top5 = np.argsort(probs)[-5:][::-1] |
|
|
| print("Top 5 Predictions:") |
| print("-" * 70) |
| for rank, idx in enumerate(top5, 1): |
| name = IMAGENET_CLASSES[int(idx)] |
| conf = float(probs[int(idx)]) * 100.0 |
| print(f" {rank}. {name:50s} {conf:6.2f}%") |
| print() |
|
|
| total_ms = download_ms + load_ms + prep_ms + inf_ms |
| print("=" * 70) |
| print("Performance Summary:") |
| print(f" - Model Download: {download_ms:.2f}ms") |
| print(f" - Graph Load: {load_ms:.2f}ms") |
| print(f" - Preprocessing: {prep_ms:.2f}ms") |
| print(f" - Inference: {inf_ms:.2f}ms") |
| print(f" - Total Time: {total_ms:.2f}ms") |
| print("=" * 70) |
| print() |
| print(f"[OK] Done. Cache dir: {hub.cache_dir}") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|