Mikecode123 commited on
Commit
8b65e00
·
verified ·
1 Parent(s): eb052a3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +79 -40
app.py CHANGED
@@ -1,80 +1,119 @@
1
  import torch
2
- import torchvision.models as models
3
  import torch.nn as nn
4
- from fastapi import FastAPI, UploadFile, File, HTTPException
 
5
  from PIL import Image
6
  import io
7
  import torchvision.transforms as transforms
 
8
 
9
- app = FastAPI(title="Alzheimer MRI API")
10
 
11
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
12
 
 
 
 
 
 
 
 
 
 
13
 
14
  # -----------------------------
15
- # MODEL LOADER
 
 
 
 
 
 
 
16
  # -----------------------------
17
- def load_model(path, num_classes=3):
 
 
18
  model = models.densenet121(weights=None)
19
- model.classifier = nn.Linear(model.classifier.in_features, num_classes)
20
- model.load_state_dict(torch.load(path, map_location=DEVICE))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  model.to(DEVICE)
22
  model.eval()
23
  return model
24
 
25
-
26
  # -----------------------------
27
- # LOAD ALL MODELS
28
  # -----------------------------
29
- MODELS = {
30
- "ad_dn121": load_model("alzheimers_densenet121.pth"),
31
- "ad_dn169": load_model("alzheimers_densenet169.pth"),
32
- "ad_dn201": load_model("alzheimers_densenet201.pth"),
33
- }
34
 
 
 
 
35
 
36
  # -----------------------------
37
- # IMAGE TRANSFORM
38
  # -----------------------------
39
- transform = transforms.Compose([
40
- transforms.Resize((224, 224)),
41
- transforms.ToTensor(),
42
- ])
43
-
44
 
45
  # -----------------------------
46
- # PREDICTION FUNCTION
47
  # -----------------------------
48
- def predict(model, image_bytes):
 
49
  image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
50
  image = transform(image).unsqueeze(0).to(DEVICE)
51
 
52
- with torch.no_grad():
53
- outputs = model(image)
54
- probs = torch.softmax(outputs, dim=1)
55
 
56
- return probs[0].tolist()
57
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
  # -----------------------------
60
  # ROUTES
61
  # -----------------------------
62
  @app.get("/")
63
  def home():
64
- return {"message": "Alzheimer MRI API is running"}
65
-
 
 
66
 
67
  @app.post("/predict")
68
- async def predict_image(model_key: str, file: UploadFile = File(...)):
69
-
70
- if model_key not in MODELS:
71
- raise HTTPException(status_code=400, detail="Invalid model key")
72
-
73
  image_bytes = await file.read()
74
-
75
- result = predict(MODELS[model_key], image_bytes)
76
-
77
- return {
78
- "model": model_key,
79
- "prediction": result
80
- }
 
1
  import torch
 
2
  import torch.nn as nn
3
+ import torchvision.models as models
4
+ from fastapi import FastAPI, UploadFile, File
5
  from PIL import Image
6
  import io
7
  import torchvision.transforms as transforms
8
+ from pathlib import Path
9
 
10
+ app = FastAPI(title="Alzheimer Ensemble API")
11
 
12
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
13
 
14
+ # -----------------------------
15
+ # LABELS (YOUR REAL ONES)
16
+ # -----------------------------
17
+ LABELS = [
18
+ "Mild Demented",
19
+ "Moderate Demented",
20
+ "Non Demented",
21
+ "Very Mild Demented"
22
+ ]
23
 
24
  # -----------------------------
25
+ # IMAGE PREPROCESSING
26
+ # -----------------------------
27
+ transform = transforms.Compose([
28
+ transforms.Resize((224, 224)),
29
+ transforms.ToTensor(),
30
+ transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
31
+ ])
32
+
33
  # -----------------------------
34
+ # MODEL ARCHITECTURE (4-LAYER HEAD)
35
+ # -----------------------------
36
+ def build_model():
37
  model = models.densenet121(weights=None)
38
+
39
+ model.classifier = nn.Sequential(
40
+ nn.Linear(1024, 512),
41
+ nn.ReLU(),
42
+ nn.Dropout(0.3),
43
+ nn.Linear(512, 4)
44
+ )
45
+
46
+ return model
47
+
48
+ # -----------------------------
49
+ # LOAD MODEL
50
+ # -----------------------------
51
+ def load_model(path):
52
+ model = build_model()
53
+ state = torch.load(path, map_location=DEVICE)
54
+
55
+ # safe load for HF spaces
56
+ model.load_state_dict(state, strict=False)
57
+
58
  model.to(DEVICE)
59
  model.eval()
60
  return model
61
 
 
62
  # -----------------------------
63
+ # MODEL PATHS
64
  # -----------------------------
65
+ BASE = Path("saved_models")
 
 
 
 
66
 
67
+ model_121 = load_model(BASE / "alzheimers_densenet121.pth")
68
+ model_169 = load_model(BASE / "alzheimers_densenet169.pth")
69
+ model_201 = load_model(BASE / "alzheimers_densenet201.pth")
70
 
71
  # -----------------------------
72
+ # SINGLE MODEL PREDICTION
73
  # -----------------------------
74
+ def predict_single(model, image_tensor):
75
+ with torch.no_grad():
76
+ out = model(image_tensor)
77
+ probs = torch.softmax(out, dim=1)
78
+ return probs[0]
79
 
80
  # -----------------------------
81
+ # ENSEMBLE
82
  # -----------------------------
83
+ def ensemble_predict(image_bytes):
84
+
85
  image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
86
  image = transform(image).unsqueeze(0).to(DEVICE)
87
 
88
+ p1 = predict_single(model_121, image)
89
+ p2 = predict_single(model_169, image)
90
+ p3 = predict_single(model_201, image)
91
 
92
+ avg = (p1 + p2 + p3) / 3
93
 
94
+ confidence, cls = torch.max(avg, dim=0)
95
+
96
+ return {
97
+ "prediction": LABELS[cls.item()],
98
+ "class_id": cls.item(),
99
+ "confidence": round(confidence.item() * 100, 2),
100
+ "probabilities": {
101
+ LABELS[i]: round(avg[i].item() * 100, 2)
102
+ for i in range(len(LABELS))
103
+ }
104
+ }
105
 
106
  # -----------------------------
107
  # ROUTES
108
  # -----------------------------
109
  @app.get("/")
110
  def home():
111
+ return {
112
+ "message": "Alzheimer Ensemble API Running",
113
+ "classes": LABELS
114
+ }
115
 
116
  @app.post("/predict")
117
+ async def predict(file: UploadFile = File(...)):
 
 
 
 
118
  image_bytes = await file.read()
119
+ return ensemble_predict(image_bytes)