skin-lesion-7class-efficientnet / inference_example.py
adeIaide's picture
Upload EfficientNet-B0 checkpoint and model card
b5ebe73 verified
Raw History Blame Contribute Delete
2.7 kB
"""Standalone inference example for adeIaide/skin-lesion-7class-efficientnet."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
import torch
from huggingface_hub import hf_hub_download
from PIL import Image
from safetensors.torch import load_file
from torch import nn
from torchvision import models, transforms
REPO_ID = "adeIaide/skin-lesion-7class-efficientnet"
class EfficientNetB0(nn.Module):
def __init__(self, num_classes: int = 7, dropout: float = 0.3) -> None:
super().__init__()
network = models.efficientnet_b0(weights=None)
embedding_dim = network.classifier[1].in_features
self.encoder = nn.Sequential(network.features, network.avgpool, nn.Flatten(1))
self.dropout = nn.Dropout(dropout)
self.classifier = nn.Linear(embedding_dim, num_classes)
def forward(self, image: torch.Tensor) -> torch.Tensor:
return self.classifier(self.dropout(self.encoder(image)))
def load_model(device: torch.device) -> tuple[nn.Module, dict]:
config_path = hf_hub_download(REPO_ID, "config.json")
weights_path = hf_hub_download(REPO_ID, "model.safetensors")
config = json.loads(Path(config_path).read_text(encoding="utf-8"))
model = EfficientNetB0(
num_classes=int(config["num_classes"]),
dropout=float(config["dropout"]),
)
model.load_state_dict(load_file(weights_path, device=str(device)))
return model.to(device).eval(), config
def predict(image_path: str | Path) -> dict[str, float]:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model, config = load_model(device)
norm = config["normalization"]
transform = transforms.Compose(
[
transforms.Resize((config["image_size"], config["image_size"])),
transforms.ToTensor(),
transforms.Normalize(norm["mean"], norm["std"]),
]
)
image = Image.open(image_path).convert("RGB")
batch = transform(image).unsqueeze(0).to(device)
with torch.inference_mode():
probabilities = torch.softmax(model(batch), dim=1)[0].cpu().tolist()
return dict(zip(config["class_names"], probabilities))
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("image", help="Path to one dermoscopic image")
args = parser.parse_args()
probabilities = predict(args.image)
predicted = max(probabilities, key=probabilities.get)
print(f"prediction: {predicted}")
for label, probability in sorted(
probabilities.items(), key=lambda item: item[1], reverse=True
):
print(f"{label:5s} {probability:.4f}")
if __name__ == "__main__":
main()