Mikecode123 commited on
Commit
4675671
·
verified ·
1 Parent(s): 62e7426

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -48
app.py CHANGED
@@ -4,7 +4,7 @@ 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
 
@@ -15,59 +15,56 @@ 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
-
32
  self.conv2 = nn.Conv1d(32, 64, 5, padding=2)
33
  self.bn2 = nn.BatchNorm1d(64)
34
-
35
  self.conv3 = nn.Conv1d(64, 128, 3, padding=1)
36
  self.bn3 = nn.BatchNorm1d(128)
37
-
38
  self.pool = nn.AdaptiveAvgPool1d(1)
39
  self.fc = nn.Linear(128, 3)
40
 
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
@@ -79,60 +76,59 @@ 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]
112
-
113
- pred = int(np.argmax(probs))
114
-
115
- return {
116
- "prediction": classes[pred],
117
- "confidence": float(probs[pred]),
118
- "probabilities": {
119
- classes[i]: float(probs[i]) for i in range(len(classes))
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)
 
4
  import torch.nn as nn
5
  import numpy as np
6
 
7
+ app = FastAPI(title="NeuroHealth EEG API", version="RESET-2")
8
 
9
  DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
10
 
 
15
  PD_CLASSES = ["Parkinson", "Control"]
16
 
17
  # ======================
18
+ # INPUT MODEL
19
  # ======================
20
  class EEGRequest(BaseModel):
21
  features: list
22
 
23
  # ======================
24
+ # AD MODEL - 1D 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
  self.conv2 = nn.Conv1d(32, 64, 5, padding=2)
32
  self.bn2 = nn.BatchNorm1d(64)
 
33
  self.conv3 = nn.Conv1d(64, 128, 3, padding=1)
34
  self.bn3 = nn.BatchNorm1d(128)
 
35
  self.pool = nn.AdaptiveAvgPool1d(1)
36
  self.fc = nn.Linear(128, 3)
37
 
38
  def forward(self, x):
39
  x = x.view(x.size(0), 19, 76)
 
40
  x = torch.relu(self.bn1(self.conv1(x)))
41
  x = torch.relu(self.bn2(self.conv2(x)))
42
  x = torch.relu(self.bn3(self.conv3(x)))
 
43
  x = self.pool(x).squeeze(-1)
44
  return self.fc(x)
45
 
46
  # ======================
47
+ # PD MODEL - 1D CNN (Fixed to match checkpoint)
48
  # ======================
49
+ class EEG_CNN_PD(nn.Module):
50
  def __init__(self):
51
  super().__init__()
52
+ self.conv1 = nn.Conv1d(19, 32, 7, padding=3)
53
+ self.bn1 = nn.BatchNorm1d(32)
54
+ self.conv2 = nn.Conv1d(32, 64, 5, padding=2)
55
+ self.bn2 = nn.BatchNorm1d(64)
56
+ self.conv3 = nn.Conv1d(64, 128, 3, padding=1)
57
+ self.bn3 = nn.BatchNorm1d(128)
58
+ self.pool = nn.AdaptiveAvgPool1d(1)
59
+ self.fc = nn.Linear(128, 2)
 
 
 
60
 
61
  def forward(self, x):
62
+ x = x.view(x.size(0), 19, 76)
63
+ x = torch.relu(self.bn1(self.conv1(x)))
64
+ x = torch.relu(self.bn2(self.conv2(x)))
65
+ x = torch.relu(self.bn3(self.conv3(x)))
66
+ x = self.pool(x).squeeze(-1)
67
+ return self.fc(x)
68
 
69
  # ======================
70
  # LOAD MODELS
 
76
  ad_model = EEG_CNN_AD().to(DEVICE)
77
  ad_model.load_state_dict(torch.load(AD_PATH, map_location=DEVICE))
78
  ad_model.eval()
79
+ print("AD loaded successfully")
80
 
81
  print("Loading PD model...")
82
+ pd_model = EEG_CNN_PD().to(DEVICE)
83
  pd_model.load_state_dict(torch.load(PD_PATH, map_location=DEVICE))
84
  pd_model.eval()
85
+ print("PD loaded successfully")
86
 
87
  # ======================
88
  # PREPROCESS
89
  # ======================
90
  def preprocess(features, mode):
91
+ x = torch.tensor(features, dtype=torch.float32).to(DEVICE)
92
+ if mode == "ad" or mode == "pd":
93
+ # Ensure shape is (batch, channels, time) -> (1, 19, 76)
94
+ if len(x.shape) == 1:
95
+ x = x.view(1, 19, 76)
96
+ elif len(x.shape) == 2:
97
+ x = x.unsqueeze(0)
98
+ return x
99
+ raise ValueError("Unknown mode")
 
100
 
101
  # ======================
102
+ # PREDICT FUNCTION
103
  # ======================
104
  def predict(model, x, classes):
105
  with torch.no_grad():
106
  out = model(x)
107
  probs = torch.softmax(out, dim=1).cpu().numpy()[0]
108
+ pred = int(np.argmax(probs))
109
+ return {
110
+ "prediction": classes[pred],
111
+ "confidence": float(probs[pred]),
112
+ "probabilities": {classes[i]: float(probs[i]) for i in range(len(classes))}
 
 
 
113
  }
 
114
 
115
  # ======================
116
  # ROUTES
117
  # ======================
118
  @app.get("/")
119
  def home():
120
+ return {
121
+ "status": "ready",
122
+ "message": "NeuroHealth EEG API is running (Fixed CNN architecture)",
123
+ "year": 2026
124
+ }
125
 
126
  @app.post("/predict/ad")
127
  def predict_ad(req: EEGRequest):
128
+ x = preprocess(req.features, "ad")
129
  return predict(ad_model, x, AD_CLASSES)
130
 
131
  @app.post("/predict/pd")
132
  def predict_pd(req: EEGRequest):
133
+ x = preprocess(req.features, "pd")
134
  return predict(pd_model, x, PD_CLASSES)