Mikecode123 commited on
Commit
b5ad082
·
verified ·
1 Parent(s): 4dcc3ec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -50
app.py CHANGED
@@ -5,34 +5,36 @@ 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
16
- # -----------------------------
17
  LABELS = [
18
  "Mild Demented",
19
  "Moderate Demented",
20
  "Non Demented",
21
- "Very Very Mild Demented"
22
  ]
23
 
24
- # -----------------------------
25
- # TRANSFORM
26
- # -----------------------------
27
  transform = transforms.Compose([
28
  transforms.Resize((224, 224)),
29
  transforms.ToTensor(),
30
- transforms.Normalize([0.5]*3, [0.5]*3)
31
  ])
32
 
33
- # -----------------------------
34
- # MODEL BUILDER (MATCH YOUR TRAINING)
35
- # -----------------------------
36
  def build_model():
37
  model = models.densenet121(weights=None)
38
 
@@ -46,31 +48,43 @@ def build_model():
46
 
47
  return model
48
 
49
- # -----------------------------
50
- # LOAD MODEL
51
- # -----------------------------
52
  def load_model(path):
53
  model = build_model()
 
54
  state = torch.load(path, map_location=DEVICE)
55
 
 
56
  if isinstance(state, dict) and "model_state_dict" in state:
57
  state = state["model_state_dict"]
58
 
59
  model.load_state_dict(state, strict=False)
 
60
  model.to(DEVICE)
61
  model.eval()
 
62
  return model
63
 
64
- # -----------------------------
65
- # LOAD ALL MODELS
66
- # -----------------------------
67
- model_121 = "alzheimers_densenet121.pth"
68
- model_169 = "alzheimers_densenet169.pth"
69
- model_201 = "alzheimers_densenet201.pth"
 
 
 
 
 
 
 
 
70
 
71
- # -----------------------------
72
- # SINGLE PREDICT FUNCTION
73
- # -----------------------------
74
  def predict(model, image_tensor):
75
  with torch.no_grad():
76
  out = model(image_tensor)
@@ -78,25 +92,18 @@ def predict(model, image_tensor):
78
  conf, cls = torch.max(probs, dim=0)
79
 
80
  return {
81
- "class_id": cls.item(),
82
  "class_name": LABELS[cls.item()],
83
- "confidence": float(conf.item()),
84
  "probabilities": {
85
- LABELS[i]: float(probs[i].item())
86
  for i in range(len(LABELS))
87
  }
88
  }
89
 
90
- # -----------------------------
91
- # IMAGE PROCESSING
92
- # -----------------------------
93
- def process_image(image_bytes):
94
- image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
95
- return transform(image).unsqueeze(0).to(DEVICE)
96
-
97
- # -----------------------------
98
- # INDIVIDUAL ENDPOINTS
99
- # -----------------------------
100
  @app.post("/predict/121")
101
  async def predict_121(file: UploadFile = File(...)):
102
  img = process_image(await file.read())
@@ -112,9 +119,9 @@ async def predict_201(file: UploadFile = File(...)):
112
  img = process_image(await file.read())
113
  return {"model": "densenet201", **predict(model_201, img)}
114
 
115
- # -----------------------------
116
- # ENSEMBLE PREDICTION (UPGRADED)
117
- # -----------------------------
118
  @app.post("/predict/ensemble")
119
  async def ensemble(file: UploadFile = File(...)):
120
 
@@ -124,8 +131,8 @@ async def ensemble(file: UploadFile = File(...)):
124
  r2 = predict(model_169, img)
125
  r3 = predict(model_201, img)
126
 
127
- # average probabilities
128
  avg_probs = {}
 
129
  for i in range(len(LABELS)):
130
  avg_probs[LABELS[i]] = (
131
  r1["probabilities"][LABELS[i]] +
@@ -137,25 +144,26 @@ async def ensemble(file: UploadFile = File(...)):
137
 
138
  return {
139
  "final_prediction": final_class,
140
- "final_confidence": avg_probs[final_class],
141
 
142
- "ensemble_breakdown": {
143
- "model_121": r1,
144
- "model_169": r2,
145
- "model_201": r3
146
- },
147
 
148
- "averaged_probabilities": avg_probs
 
 
 
 
149
  }
150
 
151
- # -----------------------------
152
  # ROOT
153
- # -----------------------------
154
  @app.get("/")
155
  def home():
156
  return {
157
  "status": "running",
158
- "models": ["121", "169", "201"],
 
159
  "endpoints": [
160
  "/predict/121",
161
  "/predict/169",
 
5
  from PIL import Image
6
  import io
7
  import torchvision.transforms as transforms
 
8
 
9
+ # =========================
10
+ # APP
11
+ # =========================
12
  app = FastAPI(title="Alzheimer Ensemble API")
13
 
14
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
15
 
16
+ # =========================
17
  # LABELS
18
+ # =========================
19
  LABELS = [
20
  "Mild Demented",
21
  "Moderate Demented",
22
  "Non Demented",
23
+ "Very Mild Demented"
24
  ]
25
 
26
+ # =========================
27
+ # IMAGE TRANSFORM
28
+ # =========================
29
  transform = transforms.Compose([
30
  transforms.Resize((224, 224)),
31
  transforms.ToTensor(),
32
+ transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
33
  ])
34
 
35
+ # =========================
36
+ # MODEL ARCHITECTURE
37
+ # =========================
38
  def build_model():
39
  model = models.densenet121(weights=None)
40
 
 
48
 
49
  return model
50
 
51
+ # =========================
52
+ # LOAD MODEL (FIXED)
53
+ # =========================
54
  def load_model(path):
55
  model = build_model()
56
+
57
  state = torch.load(path, map_location=DEVICE)
58
 
59
+ # handle checkpoint formats safely
60
  if isinstance(state, dict) and "model_state_dict" in state:
61
  state = state["model_state_dict"]
62
 
63
  model.load_state_dict(state, strict=False)
64
+
65
  model.to(DEVICE)
66
  model.eval()
67
+
68
  return model
69
 
70
+ # =========================
71
+ # LOAD ALL MODELS (REAL FIX HERE)
72
+ # =========================
73
+ model_121 = load_model("alzheimers_densenet121.pth")
74
+ model_169 = load_model("alzheimers_densenet169.pth")
75
+ model_201 = load_model("alzheimers_densenet201.pth")
76
+
77
+ # =========================
78
+ # IMAGE PROCESSING
79
+ # =========================
80
+ def process_image(image_bytes):
81
+ image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
82
+ image = transform(image).unsqueeze(0)
83
+ return image.to(DEVICE)
84
 
85
+ # =========================
86
+ # SINGLE MODEL PREDICT
87
+ # =========================
88
  def predict(model, image_tensor):
89
  with torch.no_grad():
90
  out = model(image_tensor)
 
92
  conf, cls = torch.max(probs, dim=0)
93
 
94
  return {
95
+ "class_id": int(cls.item()),
96
  "class_name": LABELS[cls.item()],
97
+ "confidence": round(float(conf.item()), 4),
98
  "probabilities": {
99
+ LABELS[i]: round(float(probs[i].item()), 4)
100
  for i in range(len(LABELS))
101
  }
102
  }
103
 
104
+ # =========================
105
+ # ENDPOINTS
106
+ # =========================
 
 
 
 
 
 
 
107
  @app.post("/predict/121")
108
  async def predict_121(file: UploadFile = File(...)):
109
  img = process_image(await file.read())
 
119
  img = process_image(await file.read())
120
  return {"model": "densenet201", **predict(model_201, img)}
121
 
122
+ # =========================
123
+ # ENSEMBLE (FIXED + CLEAN)
124
+ # =========================
125
  @app.post("/predict/ensemble")
126
  async def ensemble(file: UploadFile = File(...)):
127
 
 
131
  r2 = predict(model_169, img)
132
  r3 = predict(model_201, img)
133
 
 
134
  avg_probs = {}
135
+
136
  for i in range(len(LABELS)):
137
  avg_probs[LABELS[i]] = (
138
  r1["probabilities"][LABELS[i]] +
 
144
 
145
  return {
146
  "final_prediction": final_class,
147
+ "final_confidence": round(avg_probs[final_class], 4),
148
 
149
+ "averaged_probabilities": avg_probs,
 
 
 
 
150
 
151
+ "model_outputs": {
152
+ "densenet121": r1,
153
+ "densenet169": r2,
154
+ "densenet201": r3
155
+ }
156
  }
157
 
158
+ # =========================
159
  # ROOT
160
+ # =========================
161
  @app.get("/")
162
  def home():
163
  return {
164
  "status": "running",
165
+ "device": str(DEVICE),
166
+ "models_loaded": True,
167
  "endpoints": [
168
  "/predict/121",
169
  "/predict/169",