The full assessment service (this model + EXIF authenticity checks + pHash duplicate detection + compensation estimation) is deployed and publicly accessible:
1import json
2import onnxruntime as ort
3import numpy as np
4from PIL import Image
5from torchvision import transforms
6
7mapping = json.load(open("class_mapping.json")) # {"DESTROYED": 0, "MAJOR": 1, "MINOR": 2}
8idx_to_class = {int(v): k for k, v in mapping.items()}
9
10transform = transforms.Compose([
11 transforms.Resize(256),
12 transforms.CenterCrop(224),
13 transforms.ToTensor(),
14 transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
15])
16
17img = Image.open("building.jpg").convert("RGB")
18x = transform(img).unsqueeze(0).numpy()
19
20sess = ort.InferenceSession("best.onnx", providers=["CPUExecutionProvider"])
21probs = sess.run(["scores"], {"image": x})[0][0] # softmax already baked in
22
23print("Damage grade:", idx_to_class[int(probs.argmax())])
24print("All scores:", {idx_to_class[i]: round(float(p), 4) for i, p in enumerate(probs)})
1import torch
2import torch.nn as nn
3from torchvision import models, transforms
4from PIL import Image
5
6device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
7
8# 1. Build the exact architecture used during training
9model = models.resnet50(weights=None)
10model.fc = nn.Sequential(
11 nn.Dropout(p=0.0), # training-only; inert at inference
12 nn.Linear(model.fc.in_features, 3),
13)
14
15# 2. Load the checkpoint
16ckpt = torch.load("best.pt", map_location=device, weights_only=True)
17model.load_state_dict(ckpt["model_state"])
18model.to(device).eval()
19
20# 3. IMPORTANT — use the checkpoint's index->class mapping.
21# ImageFolder trained classes in ALPHABETICAL order
22# (DESTROYED=0, MAJOR=1, MINOR=2), NOT ["MINOR", "MAJOR", "DESTROYED"].
23idx_to_class = {int(v): k for k, v in ckpt["class_to_idx"].items()}
24
25# 4. Preprocess exactly like training validation
26transform = transforms.Compose([
27 transforms.Resize(256),
28 transforms.CenterCrop(224),
29 transforms.ToTensor(),
30 transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
31])
32
33# 5. Predict
34img = Image.open("building.jpg").convert("RGB")
35x = transform(img).unsqueeze(0).to(device)
36with torch.no_grad():
37 probs = torch.softmax(model(x), dim=1)[0]
38
39scores = {idx_to_class[i]: round(float(p), 4) for i, p in enumerate(probs)}
40print("Damage grade:", idx_to_class[int(probs.argmax())])
41print("All scores:", scores)