Mikecode123 commited on
Commit
d7df528
·
verified ·
1 Parent(s): 3ecb854

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -104
app.py CHANGED
@@ -1,43 +1,31 @@
1
  from fastapi import FastAPI
2
  from pydantic import BaseModel
3
-
4
  import torch
5
  import torch.nn as nn
6
  import numpy as np
7
 
8
- # =========================================================
9
- # APP
10
- # =========================================================
11
-
12
- app = FastAPI(
13
- title="NeuroHealth EEG API",
14
- version="10.0"
15
- )
16
 
17
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
18
 
19
- # =========================================================
20
  # LABELS
21
- # =========================================================
22
-
23
  AD_CLASSES = ["Alzheimer", "FTD", "Control"]
24
  PD_CLASSES = ["Parkinson", "Control"]
25
 
26
- # =========================================================
27
  # INPUT
28
- # =========================================================
29
-
30
  class EEGRequest(BaseModel):
31
  features: list
32
 
33
- # =========================================================
34
- # AD MODEL (UNCHANGED - 19 x 76 CNN)
35
- # =========================================================
36
-
37
  class EEG_CNN_AD(nn.Module):
38
  def __init__(self):
39
  super().__init__()
40
-
41
  self.conv1 = nn.Conv1d(19, 32, 7, padding=3)
42
  self.bn1 = nn.BatchNorm1d(32)
43
 
@@ -53,101 +41,71 @@ class EEG_CNN_AD(nn.Module):
53
  def forward(self, x):
54
  x = x.view(x.size(0), 19, 76)
55
 
56
- x = torch.relu(self.conv1(x))
57
- x = self.bn1(x)
58
-
59
- x = torch.relu(self.conv2(x))
60
- x = self.bn2(x)
61
-
62
- x = torch.relu(self.conv3(x))
63
- x = self.bn3(x)
64
 
65
  x = self.pool(x).squeeze(-1)
66
  return self.fc(x)
67
 
68
- # =========================================================
69
- # PD MODEL (UPDATED CNN - MATCHES YOUR TRAINED MODEL)
70
- # =========================================================
71
-
72
- class EEG_CNN_PD(nn.Module):
73
  def __init__(self):
74
  super().__init__()
 
 
 
 
75
 
76
- self.conv1 = nn.Conv1d(64, 32, 7, padding=3)
77
- self.bn1 = nn.BatchNorm1d(32)
78
-
79
- self.conv2 = nn.Conv1d(32, 64, 5, padding=2)
80
- self.bn2 = nn.BatchNorm1d(64)
81
 
82
- self.conv3 = nn.Conv1d(64, 128, 3, padding=1)
83
- self.bn3 = nn.BatchNorm1d(128)
84
-
85
- self.pool = nn.AdaptiveAvgPool1d(1)
86
- self.fc = nn.Linear(128, 2)
87
 
88
  def forward(self, x):
89
- # x: (batch, 64, 256)
90
- x = torch.relu(self.conv1(x))
91
- x = self.bn1(x)
92
 
93
- x = torch.relu(self.conv2(x))
94
- x = self.bn2(x)
95
-
96
- x = torch.relu(self.conv3(x))
97
- x = self.bn3(x)
98
-
99
- x = self.pool(x).squeeze(-1)
100
- return self.fc(x)
101
-
102
- # =========================================================
103
- # PATHS
104
- # =========================================================
105
-
106
- AD_MODEL_PATH = "AD_eeg_cnn_ad_ftd_cn.pt"
107
- PD_MODEL_PATH = "PD_CNN_FINAL.pth"
108
-
109
- # =========================================================
110
  # LOAD MODELS
111
- # =========================================================
 
 
112
 
113
  print("Loading AD model...")
114
  ad_model = EEG_CNN_AD().to(DEVICE)
115
- ad_model.load_state_dict(torch.load(AD_MODEL_PATH, map_location=DEVICE))
116
  ad_model.eval()
117
- print("AD model loaded")
118
 
119
  print("Loading PD model...")
120
- pd_model = EEG_CNN_PD().to(DEVICE)
121
- pd_model.load_state_dict(torch.load(PD_MODEL_PATH, map_location=DEVICE))
122
  pd_model.eval()
123
- print("PD model loaded")
124
-
125
- print("System ready")
126
-
127
- # =========================================================
128
- # PREPROCESSING
129
- # =========================================================
130
-
131
- def prepare(features, model_type):
132
 
 
 
 
 
133
  x = torch.tensor(features, dtype=torch.float32)
134
 
135
- if model_type == "ad":
136
  return x.view(1, 19, 76)
137
 
138
- if model_type == "pd":
139
- return x.view(1, 64, 256)
140
-
141
- raise ValueError("Invalid model type")
142
-
143
- # =========================================================
144
- # PREDICTION ENGINE
145
- # =========================================================
146
-
147
- def predict(model, features, classes, model_type):
148
 
149
- x = prepare(features, model_type).to(DEVICE)
150
 
 
 
 
 
151
  with torch.no_grad():
152
  out = model(x)
153
  probs = torch.softmax(out, dim=1).cpu().numpy()[0]
@@ -162,27 +120,19 @@ def predict(model, features, classes, model_type):
162
  }
163
  }
164
 
165
- # =========================================================
166
  # ROUTES
167
- # =========================================================
168
-
169
  @app.get("/")
170
  def home():
171
- return {
172
- "status": "running",
173
- "ad_input": "19x76 CNN",
174
- "pd_input": "64x256 CNN",
175
- "version": "10.0"
176
- }
177
-
178
- @app.get("/health")
179
- def health():
180
- return {"status": "ok"}
181
 
182
  @app.post("/predict/ad")
183
  def predict_ad(req: EEGRequest):
184
- return predict(ad_model, req.features, AD_CLASSES, "ad")
 
185
 
186
  @app.post("/predict/pd")
187
  def predict_pd(req: EEGRequest):
188
- return predict(pd_model, req.features, PD_CLASSES, "pd")
 
 
1
  from fastapi import FastAPI
2
  from pydantic import BaseModel
 
3
  import torch
4
  import torch.nn as nn
5
  import numpy as np
6
 
7
+ app = FastAPI(title="NeuroHealth EEG API", version="RESET-1")
 
 
 
 
 
 
 
8
 
9
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
10
 
11
+ # ======================
12
  # LABELS
13
+ # ======================
 
14
  AD_CLASSES = ["Alzheimer", "FTD", "Control"]
15
  PD_CLASSES = ["Parkinson", "Control"]
16
 
17
+ # ======================
18
  # INPUT
19
+ # ======================
 
20
  class EEGRequest(BaseModel):
21
  features: list
22
 
23
+ # ======================
24
+ # AD MODEL (UNCHANGED CNN)
25
+ # ======================
 
26
  class EEG_CNN_AD(nn.Module):
27
  def __init__(self):
28
  super().__init__()
 
29
  self.conv1 = nn.Conv1d(19, 32, 7, padding=3)
30
  self.bn1 = nn.BatchNorm1d(32)
31
 
 
41
  def forward(self, x):
42
  x = x.view(x.size(0), 19, 76)
43
 
44
+ x = torch.relu(self.bn1(self.conv1(x)))
45
+ x = torch.relu(self.bn2(self.conv2(x)))
46
+ x = torch.relu(self.bn3(self.conv3(x)))
 
 
 
 
 
47
 
48
  x = self.pool(x).squeeze(-1)
49
  return self.fc(x)
50
 
51
+ # ======================
52
+ # PD MODEL (MATCH CHECKPOINT EXACTLY)
53
+ # ======================
54
+ class EEG_PD(nn.Module):
 
55
  def __init__(self):
56
  super().__init__()
57
+ self.net = nn.Sequential(
58
+ nn.Linear(76, 256),
59
+ nn.ReLU(),
60
+ nn.BatchNorm1d(256),
61
 
62
+ nn.Linear(256, 128),
63
+ nn.ReLU(),
64
+ nn.BatchNorm1d(128),
 
 
65
 
66
+ nn.Linear(128, 2)
67
+ )
 
 
 
68
 
69
  def forward(self, x):
70
+ return self.net(x)
 
 
71
 
72
+ # ======================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  # LOAD MODELS
74
+ # ======================
75
+ AD_PATH = "AD_eeg_model.pth"
76
+ PD_PATH = "PD_eeg_model.pth"
77
 
78
  print("Loading AD model...")
79
  ad_model = EEG_CNN_AD().to(DEVICE)
80
+ ad_model.load_state_dict(torch.load(AD_PATH, map_location=DEVICE))
81
  ad_model.eval()
82
+ print("AD loaded")
83
 
84
  print("Loading PD model...")
85
+ pd_model = EEG_PD().to(DEVICE)
86
+ pd_model.load_state_dict(torch.load(PD_PATH, map_location=DEVICE))
87
  pd_model.eval()
88
+ print("PD loaded")
 
 
 
 
 
 
 
 
89
 
90
+ # ======================
91
+ # PREPROCESS
92
+ # ======================
93
+ def preprocess(features, mode):
94
  x = torch.tensor(features, dtype=torch.float32)
95
 
96
+ if mode == "ad":
97
  return x.view(1, 19, 76)
98
 
99
+ if mode == "pd":
100
+ # IMPORTANT: PD expects FLATTENED 76-D FEATURES
101
+ return x.view(1, 76)
 
 
 
 
 
 
 
102
 
103
+ raise ValueError("unknown mode")
104
 
105
+ # ======================
106
+ # PREDICT ENGINE
107
+ # ======================
108
+ def predict(model, x, classes):
109
  with torch.no_grad():
110
  out = model(x)
111
  probs = torch.softmax(out, dim=1).cpu().numpy()[0]
 
120
  }
121
  }
122
 
123
+ # ======================
124
  # ROUTES
125
+ # ======================
 
126
  @app.get("/")
127
  def home():
128
+ return {"status": "ready (RESET architecture)", "year": 2026}
 
 
 
 
 
 
 
 
 
129
 
130
  @app.post("/predict/ad")
131
  def predict_ad(req: EEGRequest):
132
+ x = preprocess(req.features, "ad").to(DEVICE)
133
+ return predict(ad_model, x, AD_CLASSES)
134
 
135
  @app.post("/predict/pd")
136
  def predict_pd(req: EEGRequest):
137
+ x = preprocess(req.features, "pd").to(DEVICE)
138
+ return predict(pd_model, x, PD_CLASSES)