ananyakarn commited on
Commit
8563a27
·
verified ·
1 Parent(s): 6d735cc

considering both the sets of data

Browse files
Files changed (1) hide show
  1. app.py +106 -129
app.py CHANGED
@@ -1,40 +1,42 @@
1
  # =========================
2
- # 1. DOWNLOAD DATASET
3
  # =========================
4
  import os, requests, zipfile
5
 
6
- url = "https://huggingface.co/datasets/ananyakarn/DAIC_WOZ_Data/resolve/main/DAIC_WOZ_Data.zip"
7
- zip_path = "data.zip"
 
 
8
 
9
- if not os.path.exists("data"):
10
- os.makedirs("data", exist_ok=True)
11
 
12
- print("Downloading dataset...")
13
- r = requests.get(url, stream=True)
14
- with open(zip_path, "wb") as f:
15
- for chunk in r.iter_content(8192):
16
- f.write(chunk)
17
 
18
- print("Extracting dataset...")
19
- with zipfile.ZipFile(zip_path, "r") as zip_ref:
20
- zip_ref.extractall("data")
 
 
 
 
 
 
 
21
 
22
  # =========================
23
- # 2. FIND DATASET ROOT
24
  # =========================
25
- def find_dataset_root():
26
- for root, dirs, files in os.walk("data"):
 
27
  for d in dirs:
28
  if "_P" in d or "_C" in d:
29
- return root
30
- return None
31
-
32
- DATA_PATH = find_dataset_root()
33
 
34
- if DATA_PATH is None:
35
- raise Exception("Dataset not found!")
36
-
37
- print("Dataset path:", DATA_PATH)
38
 
39
  # =========================
40
  # 3. IMPORT LIBRARIES
@@ -51,29 +53,26 @@ from sklearn.metrics import accuracy_score, f1_score
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
@@ -87,11 +86,11 @@ bert.eval()
87
  # =========================
88
  # 6. FEATURE FUNCTIONS
89
  # =========================
90
- def load_text(folder_path):
91
  try:
92
- file = [f for f in os.listdir(folder_path) if "TRANSCRIPT" in f][0]
93
- df = pd.read_csv(os.path.join(folder_path, file))
94
- return " ".join(df.iloc[:, -1].astype(str).tolist())
95
  except:
96
  return ""
97
 
@@ -102,166 +101,144 @@ def get_text_embedding(text):
102
  inputs = tokenizer(text, return_tensors="pt",
103
  truncation=True, padding=True, max_length=256).to(device)
104
  with torch.no_grad():
105
- outputs = bert(**inputs)
106
- return outputs.last_hidden_state.mean(dim=1).squeeze().cpu().numpy()
107
 
108
- def get_audio_features(folder_path):
109
  try:
110
- file = [f for f in os.listdir(folder_path) if f.endswith("_AUDIO.wav")][0]
111
- y, sr = librosa.load(os.path.join(folder_path, file), sr=16000)
112
  mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=40)
113
  return np.mean(mfcc.T, axis=0)
114
  except:
115
  return np.zeros(40)
116
 
117
- def get_visual_features(folder_path):
118
- features = []
119
 
120
  for key in ["AUs", "pose", "gaze"]:
121
  try:
122
- file = [f for f in os.listdir(folder_path) if key in f][0]
123
- df = pd.read_csv(os.path.join(folder_path, file))
124
 
125
- cols = [c for c in df.columns if any(k in c.lower() for k in ["au", "pose", "gaze"])]
126
  df = df[cols]
127
 
128
  feat = np.concatenate([df.mean().values, df.std().values])
129
- features.append(feat)
130
  except:
131
- features.append(np.zeros(20))
132
 
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
241
  # =========================
242
- print("\nTraining model...")
243
 
244
- for epoch in range(10):
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))
 
1
  # =========================
2
+ # 1. DOWNLOAD BOTH DATASETS
3
  # =========================
4
  import os, requests, zipfile
5
 
6
+ urls = [
7
+ "https://huggingface.co/datasets/ananyakarn/DAIC_WOZ_Data/resolve/main/DAIC_WOZ_Data.zip",
8
+ "https://huggingface.co/datasets/ananyakarn/DAIC_WOZ_Data/resolve/main/DAIC_WOZ_Data-2.zip"
9
+ ]
10
 
11
+ os.makedirs("data", exist_ok=True)
 
12
 
13
+ for i, url in enumerate(urls):
14
+ zip_path = f"data_{i}.zip"
 
 
 
15
 
16
+ if not os.path.exists(zip_path):
17
+ print(f"Downloading dataset {i+1}...")
18
+ r = requests.get(url, stream=True)
19
+ with open(zip_path, "wb") as f:
20
+ for chunk in r.iter_content(8192):
21
+ f.write(chunk)
22
+
23
+ print(f"Extracting dataset {i+1}...")
24
+ with zipfile.ZipFile(zip_path, "r") as zip_ref:
25
+ zip_ref.extractall(f"data/set_{i}")
26
 
27
  # =========================
28
+ # 2. GET ALL PARTICIPANTS
29
  # =========================
30
+ def get_all_participant_paths():
31
+ paths = []
32
+ for root, dirs, _ in os.walk("data"):
33
  for d in dirs:
34
  if "_P" in d or "_C" in d:
35
+ paths.append(os.path.join(root, d))
36
+ return paths
 
 
37
 
38
+ ALL_PATHS = get_all_participant_paths()
39
+ print("Total participant folders:", len(ALL_PATHS))
 
 
40
 
41
  # =========================
42
  # 3. IMPORT LIBRARIES
 
53
  from sklearn.preprocessing import StandardScaler
54
 
55
  # =========================
56
+ # 4. LOAD SPLITS
57
  # =========================
58
  def load_split(csv_file):
59
  df = pd.read_csv(csv_file)
60
  df.columns = df.columns.str.strip()
61
 
62
  split = {}
 
63
  for _, row in df.iterrows():
64
  try:
65
  pid = str(int(row["Participant_ID"]))
66
+ split[pid] = int(row["PHQ8_Binary"])
 
67
  except:
68
  continue
 
69
  return split
70
 
71
  train_labels = load_split("train_split_Depression_AVEC2017.csv")
72
  dev_labels = load_split("dev_split_Depression_AVEC2017.csv")
73
 
74
+ print("Train labels:", len(train_labels))
75
+ print("Dev labels:", len(dev_labels))
76
 
77
  # =========================
78
  # 5. LOAD TEXT MODEL
 
86
  # =========================
87
  # 6. FEATURE FUNCTIONS
88
  # =========================
89
+ def load_text(folder):
90
  try:
91
+ file = [f for f in os.listdir(folder) if "TRANSCRIPT" in f][0]
92
+ df = pd.read_csv(os.path.join(folder, file))
93
+ return " ".join(df.iloc[:, -1].astype(str))
94
  except:
95
  return ""
96
 
 
101
  inputs = tokenizer(text, return_tensors="pt",
102
  truncation=True, padding=True, max_length=256).to(device)
103
  with torch.no_grad():
104
+ out = bert(**inputs)
105
+ return out.last_hidden_state.mean(dim=1).squeeze().cpu().numpy()
106
 
107
+ def get_audio_features(folder):
108
  try:
109
+ file = [f for f in os.listdir(folder) if f.endswith("_AUDIO.wav")][0]
110
+ y, sr = librosa.load(os.path.join(folder, file), sr=16000)
111
  mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=40)
112
  return np.mean(mfcc.T, axis=0)
113
  except:
114
  return np.zeros(40)
115
 
116
+ def get_visual_features(folder):
117
+ feats = []
118
 
119
  for key in ["AUs", "pose", "gaze"]:
120
  try:
121
+ file = [f for f in os.listdir(folder) if key in f][0]
122
+ df = pd.read_csv(os.path.join(folder, file))
123
 
124
+ cols = [c for c in df.columns if key.lower() in c.lower()]
125
  df = df[cols]
126
 
127
  feat = np.concatenate([df.mean().values, df.std().values])
128
+ feats.append(feat)
129
  except:
130
+ feats.append(np.zeros(20))
131
 
132
+ return np.concatenate(feats)
133
 
134
  # =========================
135
+ # 7. BUILD DATASETS
136
  # =========================
137
  def build_dataset(label_dict):
138
+ X_t, X_a, X_v, y = [], [], [], []
 
 
 
 
 
 
139
 
140
+ for path in tqdm(ALL_PATHS):
141
+ pid = os.path.basename(path).split("_")[0]
142
 
143
  if pid not in label_dict:
144
  continue
145
 
146
+ X_t.append(get_text_embedding(load_text(path)))
147
+ X_a.append(get_audio_features(path))
148
+ X_v.append(get_visual_features(path))
 
149
  y.append(label_dict[pid])
150
 
151
+ return np.array(X_t), np.array(X_a), np.array(X_v), np.array(y)
152
 
153
+ print("\nBuilding train...")
154
+ Xt, Xa, Xv, y_train = build_dataset(train_labels)
155
 
156
+ print("Building dev...")
157
+ Xt_test, Xa_test, Xv_test, y_test = build_dataset(dev_labels)
158
 
159
  print("Train size:", len(y_train))
160
  print("Test size:", len(y_test))
161
 
162
+ if len(y_train) == 0 or len(y_test) == 0:
163
+ raise Exception("Dataset still empty → check upload")
164
+
165
  # =========================
166
+ # 8. NORMALIZE
167
  # =========================
168
+ sc_t, sc_a, sc_v = StandardScaler(), StandardScaler(), StandardScaler()
 
 
169
 
170
+ Xt = sc_t.fit_transform(Xt)
171
+ Xa = sc_a.fit_transform(Xa)
172
+ Xv = sc_v.fit_transform(Xv)
173
 
174
+ Xt_test = sc_t.transform(Xt_test)
175
+ Xa_test = sc_a.transform(Xa_test)
176
+ Xv_test = sc_v.transform(Xv_test)
177
 
178
  # =========================
179
+ # 9. MODEL
180
  # =========================
181
+ class Model(nn.Module):
182
+ def __init__(self, vdim):
183
  super().__init__()
184
 
185
+ self.t = nn.Sequential(nn.Linear(768,128), nn.ReLU())
186
+ self.a = nn.Sequential(nn.Linear(40,32), nn.ReLU())
187
+ self.v = nn.Sequential(nn.Linear(vdim,64), nn.ReLU())
 
 
 
 
 
 
 
188
 
189
+ self.f = nn.Sequential(
190
+ nn.Linear(224,64),
 
 
 
 
 
 
191
  nn.ReLU(),
192
  nn.Dropout(0.3),
193
+ nn.Linear(64,1)
194
  )
195
 
196
+ def forward(self, t,a,v):
197
+ t = self.t(t)
198
+ a = self.a(a)
199
+ v = self.v(v)
200
+ return self.f(torch.cat([t,a,v],1))
 
 
201
 
202
+ model = Model(Xv.shape[1]).to(device)
203
 
204
+ opt = torch.optim.Adam(model.parameters(), lr=1e-4)
205
+ loss_fn = nn.BCEWithLogitsLoss()
206
 
207
+ Xt = torch.tensor(Xt, dtype=torch.float32).to(device)
208
+ Xa = torch.tensor(Xa, dtype=torch.float32).to(device)
209
+ Xv = torch.tensor(Xv, dtype=torch.float32).to(device)
 
210
  yt = torch.tensor(y_train, dtype=torch.float32).to(device)
211
 
212
+ Xt_test = torch.tensor(Xt_test, dtype=torch.float32).to(device)
213
+ Xa_test = torch.tensor(Xa_test, dtype=torch.float32).to(device)
214
+ Xv_test = torch.tensor(Xv_test, dtype=torch.float32).to(device)
 
215
 
216
  # =========================
217
  # 10. TRAIN
218
  # =========================
219
+ print("\nTraining...")
220
 
221
+ for e in range(10):
222
  model.train()
223
+ opt.zero_grad()
224
 
225
+ out = model(Xt,Xa,Xv).squeeze()
226
+ loss = loss_fn(out, yt)
 
227
 
228
  loss.backward()
229
+ opt.step()
230
 
231
+ print(f"Epoch {e+1}: {loss.item():.4f}")
232
 
233
  # =========================
234
+ # 11. EVAL
235
  # =========================
236
  model.eval()
237
 
238
  with torch.no_grad():
239
+ out = model(Xt_test,Xa_test,Xv_test).squeeze()
240
+ pred = (torch.sigmoid(out)>0.5).int().cpu().numpy()
241
 
242
+ print("\nRESULTS")
243
+ print("Accuracy:", accuracy_score(y_test, pred))
244
+ print("F1:", f1_score(y_test, pred))