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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -71
app.py CHANGED
@@ -6,22 +6,18 @@ 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
@@ -29,76 +25,97 @@ LABELS = [
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
-
41
- model.classifier = nn.Sequential(
42
- nn.Dropout(0.5),
43
- nn.Linear(1024, 256),
44
- nn.ReLU(),
45
- nn.Dropout(0.3),
46
- nn.Linear(256, 4)
47
- )
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)
91
  probs = torch.softmax(out, dim=1)[0]
 
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
  # =========================
@@ -120,7 +137,7 @@ async def predict_201(file: UploadFile = File(...)):
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(...)):
@@ -144,30 +161,11 @@ async def ensemble(file: UploadFile = File(...)):
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",
170
- "/predict/201",
171
- "/predict/ensemble"
172
- ]
173
  }
 
6
  import io
7
  import torchvision.transforms as transforms
8
 
9
+ app = FastAPI(title="Parkinson DATSCAN Ensemble API")
10
+
11
  # =========================
12
+ # DEVICE
13
  # =========================
 
 
14
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
15
+ print("Using device:", DEVICE)
16
 
17
  # =========================
18
  # LABELS
19
  # =========================
20
+ LABELS = ["Control", "Prodromal", "Parkinsons"]
 
 
 
 
 
21
 
22
  # =========================
23
  # IMAGE TRANSFORM
 
25
  transform = transforms.Compose([
26
  transforms.Resize((224, 224)),
27
  transforms.ToTensor(),
28
+ transforms.Normalize([0.5]*3, [0.5]*3)
29
  ])
30
 
31
  # =========================
32
+ # MODEL BUILDER
33
  # =========================
34
+ def build_densenet(name="121"):
35
+ if name == "121":
36
+ model = models.densenet121(weights=None)
37
+ in_f = 1024
38
+ elif name == "169":
39
+ model = models.densenet169(weights=None)
40
+ in_f = 1664
41
+ else:
42
+ model = models.densenet201(weights=None)
43
+ in_f = 1920
44
 
45
+ model.classifier = nn.Linear(in_f, len(LABELS))
46
  return model
47
 
48
  # =========================
49
+ # SAFE LOADER (IMPORTANT FIX)
50
  # =========================
51
+ def load_model(path, name):
52
+ model = build_densenet(name)
53
+
54
+ try:
55
+ checkpoint = torch.load(path, map_location=DEVICE)
56
 
57
+ # handle dict checkpoint formats
58
+ if isinstance(checkpoint, dict):
59
+ if "state_dict" in checkpoint:
60
+ checkpoint = checkpoint["state_dict"]
61
+ elif "model_state_dict" in checkpoint:
62
+ checkpoint = checkpoint["model_state_dict"]
63
 
64
+ model.load_state_dict(checkpoint, strict=False)
 
 
65
 
66
+ print(f"Loaded {path}")
67
+
68
+ except Exception as e:
69
+ print(f"Failed loading {path}: {e}")
70
 
71
  model.to(DEVICE)
72
  model.eval()
 
73
  return model
74
 
75
  # =========================
76
+ # LOAD MODELS
77
  # =========================
78
+ model_121 = load_model("densenet121.pth", "121")
79
+ model_169 = load_model("densenet169.pth", "169")
80
+ model_201 = load_model("densenet201.pth", "201")
81
 
82
  # =========================
83
  # IMAGE PROCESSING
84
  # =========================
85
  def process_image(image_bytes):
86
  image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
87
+ tensor = transform(image).unsqueeze(0).to(DEVICE)
88
+ return tensor
89
 
90
  # =========================
91
+ # PREDICTION FUNCTION (FIXED)
92
  # =========================
93
  def predict(model, image_tensor):
94
  with torch.no_grad():
95
  out = model(image_tensor)
96
  probs = torch.softmax(out, dim=1)[0]
97
+
98
  conf, cls = torch.max(probs, dim=0)
99
 
100
+ return {
101
+ "class_id": int(cls.item()),
102
+ "class_name": LABELS[int(cls.item())],
103
+ "confidence": float(conf.item()),
104
+ "probabilities": {
105
+ LABELS[i]: float(probs[i].item())
106
+ for i in range(len(LABELS))
107
+ }
108
  }
109
+
110
+ # =========================
111
+ # ROOT
112
+ # =========================
113
+ @app.get("/")
114
+ def home():
115
+ return {
116
+ "status": "running",
117
+ "models": ["121", "169", "201"],
118
+ "endpoints": ["/predict/121", "/predict/169", "/predict/201", "/predict/ensemble"]
119
  }
120
 
121
  # =========================
 
137
  return {"model": "densenet201", **predict(model_201, img)}
138
 
139
  # =========================
140
+ # ENSEMBLE (FIXED)
141
  # =========================
142
  @app.post("/predict/ensemble")
143
  async def ensemble(file: UploadFile = File(...)):
 
161
 
162
  return {
163
  "final_prediction": final_class,
164
+ "final_confidence": avg_probs[final_class],
165
+ "models": {
166
+ "121": r1,
167
+ "169": r2,
168
+ "201": r3
169
+ },
170
+ "averaged_probabilities": avg_probs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  }