Download examples/predict_demo.py from habib-analyst/sonocnn: direct link, hf CLI and curl.
- Browser
- Download file 2.73 kB
-
https://huggingface.co/habib-analyst/sonocnn/resolve/main/examples/predict_demo.py
- Command line
-
hf download hf://habib-analyst/sonocnn/examples/predict_demo.py
-
curl -L -o predict_demo.py https://huggingface.co/habib-analyst/sonocnn/resolve/main/examples/predict_demo.py
2.73 kB
| """SonoCNN demo: predict the bundled samples, a few held-out test images, | |
| and — if the sibling ViewConsensus library is importable — an 8-view | |
| consensus panel with a defer-to-human verdict on one test image. | |
| This is a mechanics demo on a 28x28 benchmark model, not a clinical tool. | |
| """ | |
| import os | |
| import sys | |
| import numpy as np | |
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) | |
| HERE = os.path.dirname(os.path.abspath(__file__)) | |
| PKG = os.path.dirname(HERE) | |
| from sonocnn import load_model, predict # noqa: E402 | |
| model = load_model(os.path.join(PKG, "model.safetensors")) | |
| print("== bundled demo samples (256x256 ultrasound stills, resized to 28x28) ==") | |
| for name in ("benign", "malignant"): | |
| r = predict(model, os.path.join(PKG, "assets", "demo_samples", f"{name}.png")) | |
| print(f"{name}.png -> predicted {r['label']} " | |
| f"(confidence {r['confidence']:.1%}; benign {r['probabilities']['benign']:.3f}, " | |
| f"malignant {r['probabilities']['malignant']:.3f})") | |
| print("\n== held-out BreastMNIST test images ==") | |
| d = np.load(os.path.join(PKG, "assets", "breastmnist.npz")) | |
| x_test = d["test_images"] | |
| y_test = d["test_labels"].ravel() | |
| labels = ("benign", "malignant") | |
| for cls in (0, 1): | |
| idx = int(np.where(y_test == cls)[0][0]) | |
| r = predict(model, x_test[idx]) | |
| print(f"test[{idx}] true={labels[cls]} -> predicted {r['label']} " | |
| f"(confidence {r['confidence']:.1%})") | |
| print("\n== ViewConsensus panel on the malignant test image (optional) ==") | |
| try: | |
| sys.path.insert(0, os.path.join(PKG, "..", "..", "libraries", "consensuskit", "src")) | |
| from viewconsensus import consensus_from_probabilities | |
| import torch | |
| from sonocnn.infer import TRAIN_MEAN, TRAIN_STD | |
| img = x_test[int(np.where(y_test == 1)[0][0])].astype(np.float32) / 255.0 | |
| def shift(a, dy, dx): | |
| return np.roll(np.roll(a, dy, axis=0), dx, axis=1) | |
| views = [img, img[:, ::-1], img[::-1, :], shift(img, 0, 2), shift(img, 0, -2), | |
| shift(img, 2, 0), shift(img, -2, 0), shift(img, 2, 2)[:, ::-1]] | |
| batch = torch.from_numpy( | |
| np.stack([((v - TRAIN_MEAN) / TRAIN_STD).astype(np.float32) for v in views]))[:, None] | |
| with torch.no_grad(): | |
| probs = torch.softmax(model(batch), 1).numpy() | |
| res = consensus_from_probabilities(probs, labels=list(labels)) | |
| verdict = getattr(res.verdict, "value", res.verdict) | |
| print(f"consensus: {res.label} at {res.probability:.1%} " | |
| f"(+/-{res.uncertainty:.1%} across 8 views) -> verdict: {verdict}, " | |
| f"should_defer: {res.should_defer}") | |
| except ImportError: | |
| print("viewconsensus not importable here — install the sibling ViewConsensus " | |
| "library to see the consensus panel.") | |