Mikecode123 commited on
Commit
da5cfde
·
verified ·
1 Parent(s): 95fecec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -39
app.py CHANGED
@@ -7,9 +7,9 @@ import io
7
  import torchvision.transforms as transforms
8
 
9
  # =========================
10
- # APP
11
  # =========================
12
- app = FastAPI(title="Alzheimer DATSCAN Ensemble API")
13
 
14
  # =========================
15
  # DEVICE
@@ -18,7 +18,7 @@ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
18
  print("Using device:", DEVICE)
19
 
20
  # =========================
21
- # CLASSES (VERY IMPORTANT - YOUR ORIGINAL SETUP)
22
  # =========================
23
  CLASSES = [
24
  "Mild Demented",
@@ -37,7 +37,7 @@ transform = transforms.Compose([
37
  ])
38
 
39
  # =========================
40
- # MODEL BUILDER (MATCH TRAINING)
41
  # =========================
42
  def build_model(version="121"):
43
  if version == "121":
@@ -52,30 +52,28 @@ def build_model(version="121"):
52
 
53
  model.classifier = nn.Sequential(
54
  nn.Dropout(0.4),
55
- nn.Linear(in_features, 4)
56
  )
57
 
58
  return model
59
 
60
  # =========================
61
- # SAFE MODEL LOADER (FIX ALL YOUR ERRORS)
62
  # =========================
63
  def load_model(path, version):
64
  model = build_model(version)
65
 
66
  try:
67
- state = torch.load(path, map_location=DEVICE)
68
 
69
- # handle different checkpoint formats
70
- if isinstance(state, dict):
71
- if "state_dict" in state:
72
- state = state["state_dict"]
73
- elif "model_state_dict" in state:
74
- state = state["model_state_dict"]
75
 
76
- model.load_state_dict(state, strict=False)
77
-
78
- print(f"Loaded {path}")
79
 
80
  except Exception as e:
81
  print(f"Failed loading {path}: {e}")
@@ -100,17 +98,19 @@ def process_image(image_bytes):
100
  return img
101
 
102
  # =========================
103
- # PREDICT FUNCTION (FIXED)
104
  # =========================
105
  def predict(model, x):
106
  with torch.no_grad():
107
- out = model(x)
108
- probs = torch.softmax(out, dim=1)[0]
 
109
  conf, cls = torch.max(probs, 0)
 
110
 
111
  return {
112
- "class_id": int(cls.item()),
113
- "class_name": CLASSES[int(cls.item())],
114
  "confidence": float(conf.item()),
115
  "probabilities": {
116
  CLASSES[i]: float(probs[i].item())
@@ -119,37 +119,50 @@ def predict(model, x):
119
  }
120
 
121
  # =========================
122
- # ROOT
123
  # =========================
124
  @app.get("/")
125
  def home():
126
  return {
127
  "status": "running",
128
- "models": ["densenet121", "densenet169", "densenet201"],
129
  "classes": CLASSES,
130
- "endpoints": ["/predict/121", "/predict/169", "/predict/201", "/predict/ensemble"]
 
 
 
 
 
131
  }
132
 
133
  # =========================
134
- # SINGLE MODEL ROUTES
135
  # =========================
136
  @app.post("/predict/121")
137
  async def predict_121(file: UploadFile = File(...)):
138
  img = process_image(await file.read())
139
- return {"model": "121", **predict(model_121, img)}
 
 
 
140
 
141
  @app.post("/predict/169")
142
  async def predict_169(file: UploadFile = File(...)):
143
  img = process_image(await file.read())
144
- return {"model": "169", **predict(model_169, img)}
 
 
 
145
 
146
  @app.post("/predict/201")
147
  async def predict_201(file: UploadFile = File(...)):
148
  img = process_image(await file.read())
149
- return {"model": "201", **predict(model_201, img)}
 
 
150
 
151
  # =========================
152
- # ENSEMBLE (FINAL FIXED VERSION)
153
  # =========================
154
  @app.post("/predict/ensemble")
155
  async def ensemble(file: UploadFile = File(...)):
@@ -160,22 +173,24 @@ async def ensemble(file: UploadFile = File(...)):
160
  r2 = predict(model_169, img)
161
  r3 = predict(model_201, img)
162
 
163
- avg = {}
164
 
165
  for c in CLASSES:
166
- avg[c] = (r1["probabilities"][c] +
167
- r2["probabilities"][c] +
168
- r3["probabilities"][c]) / 3
 
 
169
 
170
- final_class = max(avg, key=avg.get)
171
 
172
  return {
173
- "final_prediction": final_class,
174
- "final_confidence": avg[final_class],
175
- "individual_models": {
 
176
  "121": r1,
177
  "169": r2,
178
  "201": r3
179
- },
180
- "ensemble_probabilities": avg
181
  }
 
7
  import torchvision.transforms as transforms
8
 
9
  # =========================
10
+ # APP INIT
11
  # =========================
12
+ app = FastAPI(title="Alzheimer Ensemble API")
13
 
14
  # =========================
15
  # DEVICE
 
18
  print("Using device:", DEVICE)
19
 
20
  # =========================
21
+ # CLASS LABELS (FIXED)
22
  # =========================
23
  CLASSES = [
24
  "Mild Demented",
 
37
  ])
38
 
39
  # =========================
40
+ # MODEL BUILDER
41
  # =========================
42
  def build_model(version="121"):
43
  if version == "121":
 
52
 
53
  model.classifier = nn.Sequential(
54
  nn.Dropout(0.4),
55
+ nn.Linear(in_features, len(CLASSES))
56
  )
57
 
58
  return model
59
 
60
  # =========================
61
+ # SAFE MODEL LOADER
62
  # =========================
63
  def load_model(path, version):
64
  model = build_model(version)
65
 
66
  try:
67
+ checkpoint = torch.load(path, map_location=DEVICE)
68
 
69
+ if isinstance(checkpoint, dict):
70
+ if "state_dict" in checkpoint:
71
+ checkpoint = checkpoint["state_dict"]
72
+ elif "model_state_dict" in checkpoint:
73
+ checkpoint = checkpoint["model_state_dict"]
 
74
 
75
+ model.load_state_dict(checkpoint, strict=False)
76
+ print(f"Loaded: {path}")
 
77
 
78
  except Exception as e:
79
  print(f"Failed loading {path}: {e}")
 
98
  return img
99
 
100
  # =========================
101
+ # PREDICTION FUNCTION (FIXED)
102
  # =========================
103
  def predict(model, x):
104
  with torch.no_grad():
105
+ output = model(x)
106
+ probs = torch.softmax(output, dim=1)[0]
107
+
108
  conf, cls = torch.max(probs, 0)
109
+ cls = int(cls.item())
110
 
111
  return {
112
+ "prediction": CLASSES[cls],
113
+ "class_id": cls,
114
  "confidence": float(conf.item()),
115
  "probabilities": {
116
  CLASSES[i]: float(probs[i].item())
 
119
  }
120
 
121
  # =========================
122
+ # ROOT ENDPOINT
123
  # =========================
124
  @app.get("/")
125
  def home():
126
  return {
127
  "status": "running",
128
+ "models": ["121", "169", "201"],
129
  "classes": CLASSES,
130
+ "endpoints": [
131
+ "/predict/121",
132
+ "/predict/169",
133
+ "/predict/201",
134
+ "/predict/ensemble"
135
+ ]
136
  }
137
 
138
  # =========================
139
+ # SINGLE MODEL PREDICTIONS
140
  # =========================
141
  @app.post("/predict/121")
142
  async def predict_121(file: UploadFile = File(...)):
143
  img = process_image(await file.read())
144
+ result = predict(model_121, img)
145
+ result["model"] = "121"
146
+ return result
147
+
148
 
149
  @app.post("/predict/169")
150
  async def predict_169(file: UploadFile = File(...)):
151
  img = process_image(await file.read())
152
+ result = predict(model_169, img)
153
+ result["model"] = "169"
154
+ return result
155
+
156
 
157
  @app.post("/predict/201")
158
  async def predict_201(file: UploadFile = File(...)):
159
  img = process_image(await file.read())
160
+ result = predict(model_201, img)
161
+ result["model"] = "201"
162
+ return result
163
 
164
  # =========================
165
+ # ENSEMBLE PREDICTION (FINAL FIXED)
166
  # =========================
167
  @app.post("/predict/ensemble")
168
  async def ensemble(file: UploadFile = File(...)):
 
173
  r2 = predict(model_169, img)
174
  r3 = predict(model_201, img)
175
 
176
+ avg_probs = {}
177
 
178
  for c in CLASSES:
179
+ avg_probs[c] = (
180
+ r1["probabilities"][c] +
181
+ r2["probabilities"][c] +
182
+ r3["probabilities"][c]
183
+ ) / 3
184
 
185
+ final_class = max(avg_probs, key=avg_probs.get)
186
 
187
  return {
188
+ "prediction": final_class,
189
+ "confidence": avg_probs[final_class],
190
+ "probabilities": avg_probs,
191
+ "models": {
192
  "121": r1,
193
  "169": r2,
194
  "201": r3
195
+ }
 
196
  }