ananyakarn commited on
Commit
6d735cc
·
verified ·
1 Parent(s): 584c94e

fixed 3 issues

Browse files
Files changed (1) hide show
  1. app.py +88 -72
app.py CHANGED
@@ -51,34 +51,29 @@ from sklearn.metrics import accuracy_score, f1_score
51
  from sklearn.preprocessing import StandardScaler
52
 
53
  # =========================
54
- # 4. LOAD LABELS (CORRECT)
55
  # =========================
56
- def load_labels():
57
- df_train = pd.read_csv("train_split_Depression_AVEC2017.csv")
58
- df_dev = pd.read_csv("dev_split_Depression_AVEC2017.csv")
59
-
60
- df = pd.concat([df_train, df_dev])
61
-
62
- # Clean column names
63
  df.columns = df.columns.str.strip()
64
 
65
- labels = {}
66
 
67
  for _, row in df.iterrows():
68
  try:
69
  pid = str(int(row["Participant_ID"]))
70
-
71
- # ✅ FINAL LABEL
72
  label = int(row["PHQ8_Binary"])
73
-
74
- labels[pid] = label
75
  except:
76
  continue
77
 
78
- print("Total labels loaded:", len(labels))
79
- return labels
 
 
80
 
81
- labels_dict = load_labels()
 
82
 
83
  # =========================
84
  # 5. LOAD TEXT MODEL
@@ -138,80 +133,108 @@ def get_visual_features(folder_path):
138
  return np.concatenate(features)
139
 
140
  # =========================
141
- # 7. BUILD DATASET
142
  # =========================
143
- print("\nBuilding dataset...")
 
144
 
145
- all_folders = [
146
- f for f in os.listdir(DATA_PATH)
147
- if os.path.isdir(os.path.join(DATA_PATH, f))
148
- ]
149
 
150
- data = []
151
- used_folders = []
152
 
153
- for folder in tqdm(all_folders):
154
- pid = folder.split("_")[0]
155
 
156
- if pid not in labels_dict:
157
- continue
158
 
159
- folder_path = os.path.join(DATA_PATH, folder)
 
 
 
 
160
 
161
- text = load_text(folder_path)
162
- text_feat = get_text_embedding(text)
163
- audio_feat = get_audio_features(folder_path)
164
- visual_feat = get_visual_features(folder_path)
165
 
166
- combined = np.concatenate([text_feat, audio_feat, visual_feat])
167
- label = labels_dict[pid]
168
 
169
- data.append((combined, label))
170
- used_folders.append(folder)
171
 
172
- print("Total valid samples:", len(data))
 
173
 
174
  # =========================
175
- # 8. PREPARE DATA
176
  # =========================
177
- X = np.array([d[0] for d in data])
178
- y = np.array([d[1] for d in data])
 
179
 
180
- scaler = StandardScaler()
181
- X = scaler.fit_transform(X)
 
182
 
183
- split = int(0.7 * len(X))
184
- X_train, X_test = X[:split], X[split:]
185
- y_train, y_test = y[:split], y[split:]
186
 
187
  # =========================
188
- # 9. MODEL
189
  # =========================
190
- class MultiModalNN(nn.Module):
191
- def __init__(self, input_dim):
192
  super().__init__()
193
- self.net = nn.Sequential(
194
- nn.Linear(input_dim, 256),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  nn.ReLU(),
196
  nn.Dropout(0.3),
197
- nn.Linear(256, 64),
198
- nn.ReLU(),
199
  nn.Linear(64, 1)
200
  )
201
 
202
- def forward(self, x):
203
- return self.net(x)
 
 
 
 
 
204
 
205
- model = MultiModalNN(X.shape[1]).to(device)
206
 
207
  optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
208
  criterion = nn.BCEWithLogitsLoss()
209
 
210
- X_train_t = torch.tensor(X_train, dtype=torch.float32).to(device)
211
- y_train_t = torch.tensor(y_train, dtype=torch.float32).to(device)
 
 
 
212
 
213
- X_test_t = torch.tensor(X_test, dtype=torch.float32).to(device)
214
- y_test_t = torch.tensor(y_test, dtype=torch.float32).to(device)
 
 
215
 
216
  # =========================
217
  # 10. TRAIN
@@ -222,30 +245,23 @@ for epoch in range(10):
222
  model.train()
223
 
224
  optimizer.zero_grad()
225
- outputs = model(X_train_t).squeeze()
226
- loss = criterion(outputs, y_train_t)
227
 
228
  loss.backward()
229
  optimizer.step()
230
 
231
  print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}")
232
 
233
- print("Model ready!")
234
-
235
  # =========================
236
- # 11. EVALUATION
237
  # =========================
238
  model.eval()
239
 
240
  with torch.no_grad():
241
- outputs = model(X_test_t).squeeze()
242
  preds = (torch.sigmoid(outputs) > 0.5).int().cpu().numpy()
243
 
244
  print("\n========== RESULTS ==========")
245
  print("Accuracy:", accuracy_score(y_test, preds))
246
- print("F1 Score:", f1_score(y_test, preds))
247
-
248
- print("\nSample Predictions:")
249
- for i in range(min(10, len(preds))):
250
- label = "Depressed" if preds[i] == 1 else "Control"
251
- print(f"{used_folders[split+i]} → {label}")
 
51
  from sklearn.preprocessing import StandardScaler
52
 
53
  # =========================
54
+ # 4. LOAD LABELS + SPLITS
55
  # =========================
56
+ def load_split(csv_file):
57
+ df = pd.read_csv(csv_file)
 
 
 
 
 
58
  df.columns = df.columns.str.strip()
59
 
60
+ split = {}
61
 
62
  for _, row in df.iterrows():
63
  try:
64
  pid = str(int(row["Participant_ID"]))
 
 
65
  label = int(row["PHQ8_Binary"])
66
+ split[pid] = label
 
67
  except:
68
  continue
69
 
70
+ return split
71
+
72
+ train_labels = load_split("train_split_Depression_AVEC2017.csv")
73
+ dev_labels = load_split("dev_split_Depression_AVEC2017.csv")
74
 
75
+ print("Train samples:", len(train_labels))
76
+ print("Dev samples:", len(dev_labels))
77
 
78
  # =========================
79
  # 5. LOAD TEXT MODEL
 
133
  return np.concatenate(features)
134
 
135
  # =========================
136
+ # 7. BUILD TRAIN + TEST SET
137
  # =========================
138
+ def build_dataset(label_dict):
139
+ X_text, X_audio, X_visual, y = [], [], [], []
140
 
141
+ for folder in os.listdir(DATA_PATH):
142
+ folder_path = os.path.join(DATA_PATH, folder)
 
 
143
 
144
+ if not os.path.isdir(folder_path):
145
+ continue
146
 
147
+ pid = folder.split("_")[0]
 
148
 
149
+ if pid not in label_dict:
150
+ continue
151
 
152
+ text = load_text(folder_path)
153
+ X_text.append(get_text_embedding(text))
154
+ X_audio.append(get_audio_features(folder_path))
155
+ X_visual.append(get_visual_features(folder_path))
156
+ y.append(label_dict[pid])
157
 
158
+ return np.array(X_text), np.array(X_audio), np.array(X_visual), np.array(y)
 
 
 
159
 
160
+ print("\nBuilding train set...")
161
+ X_text_train, X_audio_train, X_visual_train, y_train = build_dataset(train_labels)
162
 
163
+ print("Building dev set...")
164
+ X_text_test, X_audio_test, X_visual_test, y_test = build_dataset(dev_labels)
165
 
166
+ print("Train size:", len(y_train))
167
+ print("Test size:", len(y_test))
168
 
169
  # =========================
170
+ # 8. NORMALIZATION
171
  # =========================
172
+ scaler_text = StandardScaler()
173
+ scaler_audio = StandardScaler()
174
+ scaler_visual = StandardScaler()
175
 
176
+ X_text_train = scaler_text.fit_transform(X_text_train)
177
+ X_audio_train = scaler_audio.fit_transform(X_audio_train)
178
+ X_visual_train = scaler_visual.fit_transform(X_visual_train)
179
 
180
+ X_text_test = scaler_text.transform(X_text_test)
181
+ X_audio_test = scaler_audio.transform(X_audio_test)
182
+ X_visual_test = scaler_visual.transform(X_visual_test)
183
 
184
  # =========================
185
+ # 9. MULTIMODAL MODEL (CORRECT)
186
  # =========================
187
+ class MultiModalModel(nn.Module):
188
+ def __init__(self):
189
  super().__init__()
190
+
191
+ # modality-specific encoders
192
+ self.text_net = nn.Sequential(
193
+ nn.Linear(768, 128),
194
+ nn.ReLU()
195
+ )
196
+
197
+ self.audio_net = nn.Sequential(
198
+ nn.Linear(40, 32),
199
+ nn.ReLU()
200
+ )
201
+
202
+ self.visual_net = nn.Sequential(
203
+ nn.Linear(X_visual_train.shape[1], 64),
204
+ nn.ReLU()
205
+ )
206
+
207
+ # fusion
208
+ self.fusion = nn.Sequential(
209
+ nn.Linear(128 + 32 + 64, 64),
210
  nn.ReLU(),
211
  nn.Dropout(0.3),
 
 
212
  nn.Linear(64, 1)
213
  )
214
 
215
+ def forward(self, t, a, v):
216
+ t = self.text_net(t)
217
+ a = self.audio_net(a)
218
+ v = self.visual_net(v)
219
+
220
+ x = torch.cat([t, a, v], dim=1)
221
+ return self.fusion(x)
222
 
223
+ model = MultiModalModel().to(device)
224
 
225
  optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
226
  criterion = nn.BCEWithLogitsLoss()
227
 
228
+ # tensors
229
+ Xt = torch.tensor(X_text_train, dtype=torch.float32).to(device)
230
+ Xa = torch.tensor(X_audio_train, dtype=torch.float32).to(device)
231
+ Xv = torch.tensor(X_visual_train, dtype=torch.float32).to(device)
232
+ yt = torch.tensor(y_train, dtype=torch.float32).to(device)
233
 
234
+ Xt_test = torch.tensor(X_text_test, dtype=torch.float32).to(device)
235
+ Xa_test = torch.tensor(X_audio_test, dtype=torch.float32).to(device)
236
+ Xv_test = torch.tensor(X_visual_test, dtype=torch.float32).to(device)
237
+ yt_test = torch.tensor(y_test, dtype=torch.float32).to(device)
238
 
239
  # =========================
240
  # 10. TRAIN
 
245
  model.train()
246
 
247
  optimizer.zero_grad()
248
+ outputs = model(Xt, Xa, Xv).squeeze()
249
+ loss = criterion(outputs, yt)
250
 
251
  loss.backward()
252
  optimizer.step()
253
 
254
  print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}")
255
 
 
 
256
  # =========================
257
+ # 11. EVALUATE
258
  # =========================
259
  model.eval()
260
 
261
  with torch.no_grad():
262
+ outputs = model(Xt_test, Xa_test, Xv_test).squeeze()
263
  preds = (torch.sigmoid(outputs) > 0.5).int().cpu().numpy()
264
 
265
  print("\n========== RESULTS ==========")
266
  print("Accuracy:", accuracy_score(y_test, preds))
267
+ print("F1 Score:", f1_score(y_test, preds))