Amol Kaushik commited on
Commit
cb9b728
·
1 Parent(s): 5122512
.github/copilot-ignore ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ignore everything
2
+ *
3
+
4
+ # But not directories (so we can traverse into them)
5
+ !*/
6
+
7
+ # Allow Python files
8
+ !*.py
9
+ !**/*.py
10
+
11
+ # Allow Jupyter notebooks
12
+ !*.ipynb
13
+ !**/*.ipynb
A9/A9.ipynb CHANGED
@@ -315,7 +315,7 @@
315
  ],
316
  "metadata": {
317
  "kernelspec": {
318
- "display_name": "Python 3 (ipykernel)",
319
  "language": "python",
320
  "name": "python3"
321
  },
@@ -329,7 +329,7 @@
329
  "name": "python",
330
  "nbconvert_exporter": "python",
331
  "pygments_lexer": "ipython3",
332
- "version": "3.10.11"
333
  }
334
  },
335
  "nbformat": 4,
 
315
  ],
316
  "metadata": {
317
  "kernelspec": {
318
+ "display_name": "Python 3",
319
  "language": "python",
320
  "name": "python3"
321
  },
 
329
  "name": "python",
330
  "nbconvert_exporter": "python",
331
  "pygments_lexer": "ipython3",
332
+ "version": "3.14.0"
333
  }
334
  },
335
  "nbformat": 4,
A9/A9_Report.ipynb ADDED
@@ -0,0 +1,649 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "32dc1769",
6
+ "metadata": {},
7
+ "source": [
8
+ "# A9 Report\n",
9
+ "\n",
10
+ "Predict 13 Z-coordinates from 26 input features (X, Y for each joint)"
11
+ ]
12
+ },
13
+ {
14
+ "cell_type": "markdown",
15
+ "id": "fecdba5a",
16
+ "metadata": {},
17
+ "source": [
18
+ "## 1. Data\n",
19
+ "\n",
20
+ "| Column Range | Data |\n",
21
+ "|--------------|------|\n",
22
+ "| 0 | FrameNo |\n",
23
+ "| 1-3 | head_x, head_y, head_z |\n",
24
+ "| 4-6 | left_shoulder_x/y/z |\n",
25
+ "| 7-9 | left_elbow_x/y/z |\n",
26
+ "| 10-12 | right_shoulder_x/y/z |\n",
27
+ "| 13-15 | right_elbow_x/y/z |\n",
28
+ "| 16-18 | left_hand_x/y/z |\n",
29
+ "| 19-21 | right_hand_x/y/z |\n",
30
+ "| 22-24 | left_hip_x/y/z |\n",
31
+ "| 25-27 | right_hip_x/y/z |\n",
32
+ "| 28-30 | left_knee_x/y/z |\n",
33
+ "| 31-33 | right_knee_x/y/z |\n",
34
+ "| 34-36 | left_foot_x/y/z |\n",
35
+ "| 37-39 | right_foot_x/y/z |\n",
36
+ "\n",
37
+ "**Input**: 13 joints × 2 dimensions (x, y) = **26 features**\n",
38
+ "\n",
39
+ "**Output**: 13 joints × 1 dimension (z) = **13 targets**"
40
+ ]
41
+ },
42
+ {
43
+ "cell_type": "code",
44
+ "execution_count": 43,
45
+ "id": "e1ad3f43",
46
+ "metadata": {},
47
+ "outputs": [
48
+ {
49
+ "name": "stdout",
50
+ "output_type": "stream",
51
+ "text": [
52
+ "Loaded 14 experiment results\n"
53
+ ]
54
+ }
55
+ ],
56
+ "source": [
57
+ "import os\n",
58
+ "import json\n",
59
+ "import pandas as pd\n",
60
+ "import numpy as np\n",
61
+ "import matplotlib.pyplot as plt\n",
62
+ "from pathlib import Path\n",
63
+ "\n",
64
+ "# Load aggregated results\n",
65
+ "RESULTS_CSV = Path('results_summary.csv')\n",
66
+ "if RESULTS_CSV.exists():\n",
67
+ " df = pd.read_csv(RESULTS_CSV)\n",
68
+ " print(f\"Loaded {len(df)} experiment results\")\n",
69
+ "else:\n",
70
+ " print(\"Run aggregate_results.py first to generate results_summary.csv\")"
71
+ ]
72
+ },
73
+ {
74
+ "cell_type": "markdown",
75
+ "id": "8da8874c",
76
+ "metadata": {},
77
+ "source": [
78
+ "## 2. Deep Learning Steps Overview\n",
79
+ "\n",
80
+ "The 7-step Deep Learning workflow:\n",
81
+ "\n",
82
+ "| Step | Description | Implementation |\n",
83
+ "|------|-------------|----------------|\n",
84
+ "| 1 | Load Data | `load_all_sequences()` in models.py |\n",
85
+ "| 2 | Define Network | Dense, Conv1D, LSTM, GRU architectures |\n",
86
+ "| 3 | Compile Model | Optimizer (SGD/Adam/RMSprop), Loss (MSE/MAE) |\n",
87
+ "| 4 | Split Data | 5-fold cross-validation, 90/10 train/test |\n",
88
+ "| 5 | Train Model | Early stopping, 100 epochs max |\n",
89
+ "| 6 | Evaluate | MSE, MAE, R² on test set |\n",
90
+ "| 7 | Use Model | Load saved .h5 weights for inference |"
91
+ ]
92
+ },
93
+ {
94
+ "cell_type": "markdown",
95
+ "id": "d9f90334",
96
+ "metadata": {},
97
+ "source": [
98
+ "## 3. Model Architectures\n",
99
+ "\n",
100
+ "### Dense (MLP)\n",
101
+ "- Fully-connected layers\n",
102
+ "- Treats each frame independently\n",
103
+ "- Configuration: (256, 128, 64) hidden units, ReLU, dropout 0.3\n",
104
+ "\n",
105
+ "### Conv1D (CNN)\n",
106
+ "- 1D convolutional layers for temporal patterns\n",
107
+ "- Window size: 30 frames\n",
108
+ "- Best variant (v3): filters=(128, 256), kernel=3, pool=3, dense=(256, 128, 64)\n",
109
+ "\n",
110
+ "### LSTM\n",
111
+ "- Recurrent network for sequences\n",
112
+ "- Units: (64, 32), tanh activation\n",
113
+ "\n",
114
+ "### GRU\n",
115
+ "- Gated Recurrent Unit variant\n",
116
+ "- Units: (64, 32)"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "markdown",
121
+ "id": "f04dfdfd",
122
+ "metadata": {},
123
+ "source": [
124
+ "## 4. Training & Hyperparameter Results"
125
+ ]
126
+ },
127
+ {
128
+ "cell_type": "code",
129
+ "execution_count": 44,
130
+ "id": "1a49b682",
131
+ "metadata": {},
132
+ "outputs": [
133
+ {
134
+ "name": "stdout",
135
+ "output_type": "stream",
136
+ "text": [
137
+ "ARCHITECTURE COMPARISON\n",
138
+ "==================================================\n",
139
+ " model val_r2_mean val_rmse_mean val_mae_mean\n",
140
+ "conv1d 0.932681 0.037704 0.027598\n",
141
+ " dense 0.820046 0.058055 0.042731\n",
142
+ " lstm 0.768530 0.069834 0.052217\n"
143
+ ]
144
+ }
145
+ ],
146
+ "source": [
147
+ "# Architecture comparison\n",
148
+ "if 'df' in dir() and len(df) > 0:\n",
149
+ " arch_df = df[df['experiment'] == 'different_models'][['model', 'val_r2_mean', 'val_rmse_mean', 'val_mae_mean']]\n",
150
+ " arch_df = arch_df.sort_values('val_r2_mean', ascending=False)\n",
151
+ " print(\"ARCHITECTURE COMPARISON\")\n",
152
+ " print(\"=\"*50)\n",
153
+ " print(arch_df.to_string(index=False))"
154
+ ]
155
+ },
156
+ {
157
+ "cell_type": "code",
158
+ "execution_count": 45,
159
+ "id": "b5578e0e",
160
+ "metadata": {},
161
+ "outputs": [
162
+ {
163
+ "name": "stdout",
164
+ "output_type": "stream",
165
+ "text": [
166
+ "CONV1D VARIANTS\n",
167
+ "==================================================\n",
168
+ " model val_r2_mean val_rmse_mean test_r2 test_rmse\n",
169
+ " conv1d 0.922923 0.040316 0.928322 0.039097\n",
170
+ "conv1d_v2 0.799991 0.064831 0.826827 0.060770\n"
171
+ ]
172
+ }
173
+ ],
174
+ "source": [
175
+ "# Conv1D variants comparison\n",
176
+ "if 'df' in dir() and len(df) > 0:\n",
177
+ " conv_df = df[df['experiment'] == 'conv1d_variants'][['model', 'val_r2_mean', 'val_rmse_mean', 'test_r2', 'test_rmse']]\n",
178
+ " conv_df = conv_df.sort_values('test_r2', ascending=False)\n",
179
+ " print(\"CONV1D VARIANTS\")\n",
180
+ " print(\"=\"*50)\n",
181
+ " print(conv_df.to_string(index=False))"
182
+ ]
183
+ },
184
+ {
185
+ "cell_type": "code",
186
+ "execution_count": 46,
187
+ "id": "7b21485a",
188
+ "metadata": {},
189
+ "outputs": [
190
+ {
191
+ "name": "stdout",
192
+ "output_type": "stream",
193
+ "text": [
194
+ "OPTIMIZER COMPARISON\n",
195
+ "==================================================\n",
196
+ " model val_r2_mean val_rmse_mean test_r2 test_rmse\n",
197
+ "conv1d_v3_rmsprop_mse 0.946803 0.033498 0.954934 0.031001\n",
198
+ " conv1d_v3_adam_mse 0.949678 0.032558 0.953484 0.031496\n",
199
+ " conv1d_v3_sgd_mse 0.950863 0.032199 0.952354 0.031876\n"
200
+ ]
201
+ }
202
+ ],
203
+ "source": [
204
+ "# Optimizer comparison\n",
205
+ "if 'df' in dir() and len(df) > 0:\n",
206
+ " opt_df = df[df['experiment'] == 'optimizer'][['model', 'val_r2_mean', 'val_rmse_mean', 'test_r2', 'test_rmse']]\n",
207
+ " opt_df = opt_df.sort_values('test_r2', ascending=False)\n",
208
+ " print(\"OPTIMIZER COMPARISON\")\n",
209
+ " print(\"=\"*50)\n",
210
+ " print(opt_df.to_string(index=False))"
211
+ ]
212
+ },
213
+ {
214
+ "cell_type": "code",
215
+ "execution_count": 47,
216
+ "id": "6b55c089",
217
+ "metadata": {},
218
+ "outputs": [
219
+ {
220
+ "name": "stdout",
221
+ "output_type": "stream",
222
+ "text": [
223
+ "LOSS FUNCTION COMPARISON\n",
224
+ "==================================================\n",
225
+ " model val_r2_mean val_rmse_mean test_r2 test_rmse\n",
226
+ "conv1d_v3_rmsprop_mse 0.950038 0.032467 0.954592 0.031119\n",
227
+ " conv1d_v3_adam_mse 0.948571 0.032956 0.952860 0.031707\n",
228
+ " conv1d_v3_sgd_mse 0.950748 0.032241 0.952171 0.031937\n",
229
+ "conv1d_v3_rmsprop_mae 0.943196 0.034623 0.944302 0.034465\n",
230
+ " conv1d_v3_adam_mae 0.939982 0.035601 0.934766 0.037298\n",
231
+ " conv1d_v3_sgd_mae 0.939909 0.035625 0.934060 0.037500\n"
232
+ ]
233
+ }
234
+ ],
235
+ "source": [
236
+ "# Loss function comparison\n",
237
+ "if 'df' in dir() and len(df) > 0:\n",
238
+ " loss_df = df[df['experiment'] == 'loss_optimizer'][['model', 'val_r2_mean', 'val_rmse_mean', 'test_r2', 'test_rmse']]\n",
239
+ " loss_df = loss_df.sort_values('test_r2', ascending=False)\n",
240
+ " print(\"LOSS FUNCTION COMPARISON\")\n",
241
+ " print(\"=\"*50)\n",
242
+ " print(loss_df.to_string(index=False))"
243
+ ]
244
+ },
245
+ {
246
+ "cell_type": "markdown",
247
+ "id": "e29b86d1",
248
+ "metadata": {},
249
+ "source": [
250
+ "## 5. Evaluation & Model Comparison"
251
+ ]
252
+ },
253
+ {
254
+ "cell_type": "code",
255
+ "execution_count": 48,
256
+ "id": "5128b8be",
257
+ "metadata": {},
258
+ "outputs": [
259
+ {
260
+ "name": "stdout",
261
+ "output_type": "stream",
262
+ "text": [
263
+ "ALL EXPERIMENTS RANKED BY TEST R²\n",
264
+ "======================================================================\n",
265
+ " experiment model val_r2_mean test_r2 test_rmse\n",
266
+ " optimizer conv1d_v3_rmsprop_mse 0.946803 0.954934 0.031001\n",
267
+ " loss_optimizer conv1d_v3_rmsprop_mse 0.950038 0.954592 0.031119\n",
268
+ " optimizer conv1d_v3_adam_mse 0.949678 0.953484 0.031496\n",
269
+ " loss_optimizer conv1d_v3_adam_mse 0.948571 0.952860 0.031707\n",
270
+ " optimizer conv1d_v3_sgd_mse 0.950863 0.952354 0.031876\n",
271
+ " loss_optimizer conv1d_v3_sgd_mse 0.950748 0.952171 0.031937\n",
272
+ " loss_optimizer conv1d_v3_rmsprop_mae 0.943196 0.944302 0.034465\n",
273
+ " loss_optimizer conv1d_v3_adam_mae 0.939982 0.934766 0.037298\n",
274
+ " loss_optimizer conv1d_v3_sgd_mae 0.939909 0.934060 0.037500\n",
275
+ " conv1d_variants conv1d 0.922923 0.928322 0.039097\n",
276
+ " conv1d_variants conv1d_v2 0.799991 0.826827 0.060770\n",
277
+ "different_models conv1d 0.932681 NaN NaN\n",
278
+ "different_models dense 0.820046 NaN NaN\n",
279
+ "different_models lstm 0.768530 NaN NaN\n"
280
+ ]
281
+ }
282
+ ],
283
+ "source": [
284
+ "# All results ranked by test R²\n",
285
+ "if 'df' in dir() and len(df) > 0:\n",
286
+ " print(\"ALL EXPERIMENTS RANKED BY TEST R²\")\n",
287
+ " print(\"=\"*70)\n",
288
+ " ranked = df.sort_values('test_r2', ascending=False, na_position='last')\n",
289
+ " print(ranked[['experiment', 'model', 'val_r2_mean', 'test_r2', 'test_rmse']].to_string(index=False))"
290
+ ]
291
+ },
292
+ {
293
+ "cell_type": "code",
294
+ "execution_count": 49,
295
+ "id": "38efd1c2",
296
+ "metadata": {},
297
+ "outputs": [
298
+ {
299
+ "data": {
300
+ "image/png": "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1ltvyf333y+RkZHmfaxbt052795tXktfu06dOrJnzx7Xc3T/gQceMOPVedXzsGLFimTHvXDhgjz33HNSvHhxcwydx1WrVqVrbAAAAJmBGJcYlxgXAAD4feJ28ODBMm7cOBk6dKhs375d5s2bZ5J5mizVatO8efPKxo0bZeHChSax9+STTyZ7/sqVK00SUP98//335b333jOb0oTlhg0bkiUM9bKxn3/+WTp16uTxGAcMGCCrV6+WJUuWyPLly03y8IcffvDouekdg2VZ8vXXX8vOnTvlzjvvvOrxN23aJE8//bRJAutzli1blux5zz77rKxdu1Y+++wz+eqrr2TNmjWXjV0T4AcPHjRz+PHHH5tEsCZz02P06NEmub1lyxZTOazv7bHHHjPnV8eo78v93GkC/r777jPv9ccff5RmzZqZ5PGBAwdcj9HHawJ4/vz5Zr60Kloft2vXrlTHoInekydPJtsAAEDaQoJCpGGZhmbTfXgPMW5yxLjEuAAAZHV+1ypBq0GnTp0q06ZNk27dupnbtOK0Xr16MmPGDDl//rzMnj3bVFsqfZwm915++WWT3FWa2NXbQ0JCTMKwefPmJhn46KOPSpUqVUxlqyaDNTGstJpUKze1wtcTmmCcOXOmfPDBB9K4cWNzmyaIS5Qo4dHzPR3DiRMnTGWpJh/1vWjy9O67777q8TXRqfOj1a65cuWS0qVLS40aNVzzq2PV17bHPmvWLClWrJjr+b/99pt8+eWXJrmsVa9K369WzaaHtnZo37692R80aJDccccd5v3arR60ilgfY9M50c098bt48WKTYNaErb4vHav+aY9Xq281Ma23jxkz5rIxjB07VkaOHJmucQMAkJWFBCclbuFdxLjEuDZiXAAA4LcVtzt27DCJSjupmPI+TezZSVtVt25dc9mZVpa6J0Y10WnTdgDu1aJa8aqJS/ub/g8//NDc5imtlI2Li0vW7kB70laqVMnjY3gyBk26arWqVhdrqwitlPWkLYAmdzVZq316u3TpYpLC2tNM7d2717SNuO2221yPz507d7Kx6zyHhobKrbfe6rpNE+C6UFp6aGsHm51Ur1q1arLbNBFvV8FqQlwTsZog1tfSS8l0LHbFrbbJSEhIkIoVK5r77E0rn92rl1NWtmgC3N60ihgAACCjEeNeQoxLjAsAAPy04lZ7ql6vsLCwy/qt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",
301
+ "text/plain": [
302
+ "<Figure size 1400x500 with 2 Axes>"
303
+ ]
304
+ },
305
+ "metadata": {},
306
+ "output_type": "display_data"
307
+ }
308
+ ],
309
+ "source": [
310
+ "# Visualization\n",
311
+ "if 'df' in dir() and len(df) > 0:\n",
312
+ " fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
313
+ " \n",
314
+ " # Plot 1: R² comparison\n",
315
+ " plot_df = df[df['test_r2'].notna()].sort_values('test_r2', ascending=True)\n",
316
+ " colors = ['green' if r > 0.95 else 'orange' if r > 0.90 else 'red' for r in plot_df['test_r2']]\n",
317
+ " axes[0].barh(plot_df['model'], plot_df['test_r2'], color=colors)\n",
318
+ " axes[0].set_xlabel('Test R²')\n",
319
+ " axes[0].set_title('Model Performance (Test R²)')\n",
320
+ " axes[0].axvline(0.95, color='green', linestyle='--', alpha=0.5, label='95%')\n",
321
+ " axes[0].axvline(0.90, color='orange', linestyle='--', alpha=0.5, label='90%')\n",
322
+ " axes[0].legend()\n",
323
+ " \n",
324
+ " # Plot 2: RMSE comparison\n",
325
+ " axes[1].barh(plot_df['model'], plot_df['test_rmse'], color='steelblue')\n",
326
+ " axes[1].set_xlabel('Test RMSE')\n",
327
+ " axes[1].set_title('Model Error (Test RMSE)')\n",
328
+ " \n",
329
+ " plt.tight_layout()\n",
330
+ " plt.show()"
331
+ ]
332
+ },
333
+ {
334
+ "cell_type": "markdown",
335
+ "id": "be01d215",
336
+ "metadata": {},
337
+ "source": [
338
+ "## 6. Champion Model\n",
339
+ "\n",
340
+ "### Conv1D_v3 + RMSprop + MSE\n",
341
+ "\n",
342
+ "| Parameter | Value |\n",
343
+ "|-----------|-------|\n",
344
+ "| Architecture | Conv1D |\n",
345
+ "| Filters | (128, 256) |\n",
346
+ "| Kernel size | 3 |\n",
347
+ "| Pool size | 3 |\n",
348
+ "| Dense layers | (256, 128, 64) |\n",
349
+ "| Activation | ReLU |\n",
350
+ "| Dropout | 0.2 |\n",
351
+ "| Optimizer | RMSprop (lr=0.001) |\n",
352
+ "| Loss | MSE |\n",
353
+ "| Window size | 30 frames |\n",
354
+ "| Batch size | 32 |\n",
355
+ "| Epochs | 100 (early stopping) |\n",
356
+ "\n",
357
+ "### Performance\n",
358
+ "\n",
359
+ "| Metric | Validation | Test |\n",
360
+ "|--------|------------|------|\n",
361
+ "| R² | 0.9468 ± 0.0049 | **0.9549** |\n",
362
+ "| RMSE | 0.0335 ± 0.0018 | **0.0310** |\n",
363
+ "| MAE | 0.0241 ± 0.0013 | 0.0229 |\n",
364
+ "\n",
365
+ "1. **Conv1D captures temporal patterns** - The 30-frame windows allow the model to learn motion dynamics\n",
366
+ "2. **Deeper architecture (v3)** - More filters and dense layers provide sufficient capacity\n",
367
+ "3. **RMSprop optimizer** - Adaptive learning rate works well with this data distribution\n",
368
+ "4. **MSE loss** - Better than MAE for regression with continuous targets"
369
+ ]
370
+ },
371
+ {
372
+ "cell_type": "markdown",
373
+ "id": "bbf697d8",
374
+ "metadata": {},
375
+ "source": [
376
+ "## 7. Dead Ends\n",
377
+ "\n",
378
+ "### What Did NOT Work\n",
379
+ "\n",
380
+ "| Configuration | R² | Issue |\n",
381
+ "|---------------|------|-------|\n",
382
+ "| LSTM | 0.77 | Overfitting, slow training |\n",
383
+ "| GRU | 0.74 | Similar to LSTM, underperformed |\n",
384
+ "| Dense MLP | 0.82 | Cannot capture temporal patterns |\n",
385
+ "| Conv1D_v2 (high dropout) | 0.83 | Too much regularization |\n",
386
+ "| MAE loss | ~0.93-0.94 | Lower R² than MSE |"
387
+ ]
388
+ },
389
+ {
390
+ "cell_type": "markdown",
391
+ "id": "e68fd0e3",
392
+ "metadata": {},
393
+ "source": [
394
+ "## 8. Usage Guide\n",
395
+ "\n",
396
+ "### Loading the Best Model"
397
+ ]
398
+ },
399
+ {
400
+ "cell_type": "code",
401
+ "execution_count": 50,
402
+ "id": "82cdb3ff",
403
+ "metadata": {},
404
+ "outputs": [
405
+ {
406
+ "name": "stdout",
407
+ "output_type": "stream",
408
+ "text": [
409
+ "Model loaded from cv_results_loss_optimizer/conv1d_v3_rmsprop_mse_fold4_best.h5\n"
410
+ ]
411
+ },
412
+ {
413
+ "data": {
414
+ "text/html": [
415
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Model: \"Conv1DModel\"</span>\n",
416
+ "</pre>\n"
417
+ ],
418
+ "text/plain": [
419
+ "\u001b[1mModel: \"Conv1DModel\"\u001b[0m\n"
420
+ ]
421
+ },
422
+ "metadata": {},
423
+ "output_type": "display_data"
424
+ },
425
+ {
426
+ "data": {
427
+ "text/html": [
428
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
429
+ "┃<span style=\"font-weight: bold\"> Layer (type) </span>┃<span style=\"font-weight: bold\"> Output Shape </span>┃<span style=\"font-weight: bold\"> Param # </span>┃\n",
430
+ "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
431
+ "│ xy_seq_input (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">InputLayer</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">30</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">26</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
432
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
433
+ "│ conv_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Conv1D</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">30</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">10,112</span> │\n",
434
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
435
+ "│ pool_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">MaxPooling1D</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">10</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
436
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
437
+ "│ drop_conv_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dropout</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">10</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
438
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
439
+ "│ conv_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Conv1D</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">10</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">98,560</span> │\n",
440
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
441
+ "│ pool_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">MaxPooling1D</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">4</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
442
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
443
+ "│ drop_conv_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dropout</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">4</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
444
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
445
+ "│ gap (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GlobalAveragePooling1D</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
446
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
447
+ "│ fc_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">65,792</span> │\n",
448
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
449
+ "│ drop_fc_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dropout</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
450
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
451
+ "│ fc_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">32,896</span> │\n",
452
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
453
+ "│ drop_fc_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dropout</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
454
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
455
+ "│ fc_3 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">64</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">8,256</span> │\n",
456
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
457
+ "│ drop_fc_3 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dropout</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">64</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
458
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
459
+ "│ z_output (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">13</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">845</span> │\n",
460
+ "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
461
+ "</pre>\n"
462
+ ],
463
+ "text/plain": [
464
+ "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
465
+ "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n",
466
+ "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
467
+ "│ xy_seq_input (\u001b[38;5;33mInputLayer\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m30\u001b[0m, \u001b[38;5;34m26\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
468
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
469
+ "│ conv_1 (\u001b[38;5;33mConv1D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m30\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m10,112\u001b[0m │\n",
470
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
471
+ "│ pool_1 (\u001b[38;5;33mMaxPooling1D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
472
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
473
+ "│ drop_conv_1 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
474
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
475
+ "│ conv_2 (\u001b[38;5;33mConv1D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m98,560\u001b[0m │\n",
476
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
477
+ "│ pool_2 (\u001b[38;5;33mMaxPooling1D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m4\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
478
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
479
+ "│ drop_conv_2 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m4\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
480
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
481
+ "│ gap (\u001b[38;5;33mGlobalAveragePooling1D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
482
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
483
+ "│ fc_1 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m65,792\u001b[0m │\n",
484
+ "├─────��───────────────────────────┼────────────────────────┼───────────────┤\n",
485
+ "│ drop_fc_1 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
486
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
487
+ "│ fc_2 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m32,896\u001b[0m │\n",
488
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
489
+ "│ drop_fc_2 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
490
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
491
+ "│ fc_3 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m8,256\u001b[0m │\n",
492
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
493
+ "│ drop_fc_3 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
494
+ "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
495
+ "│ z_output (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m13\u001b[0m) │ \u001b[38;5;34m845\u001b[0m │\n",
496
+ "└─────────────────────────────────┴────────────────────────┴───────────────┘\n"
497
+ ]
498
+ },
499
+ "metadata": {},
500
+ "output_type": "display_data"
501
+ },
502
+ {
503
+ "data": {
504
+ "text/html": [
505
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Total params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">216,461</span> (845.55 KB)\n",
506
+ "</pre>\n"
507
+ ],
508
+ "text/plain": [
509
+ "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m216,461\u001b[0m (845.55 KB)\n"
510
+ ]
511
+ },
512
+ "metadata": {},
513
+ "output_type": "display_data"
514
+ },
515
+ {
516
+ "data": {
517
+ "text/html": [
518
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">216,461</span> (845.55 KB)\n",
519
+ "</pre>\n"
520
+ ],
521
+ "text/plain": [
522
+ "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m216,461\u001b[0m (845.55 KB)\n"
523
+ ]
524
+ },
525
+ "metadata": {},
526
+ "output_type": "display_data"
527
+ },
528
+ {
529
+ "data": {
530
+ "text/html": [
531
+ "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Non-trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (0.00 B)\n",
532
+ "</pre>\n"
533
+ ],
534
+ "text/plain": [
535
+ "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n"
536
+ ]
537
+ },
538
+ "metadata": {},
539
+ "output_type": "display_data"
540
+ }
541
+ ],
542
+ "source": [
543
+ "# Example: Load and use the best model\n",
544
+ "import tensorflow as tf\n",
545
+ "from tensorflow import keras\n",
546
+ "\n",
547
+ "# Best model path\n",
548
+ "BEST_MODEL_PATH = 'cv_results_loss_optimizer/conv1d_v3_rmsprop_mse_fold4_best.h5'\n",
549
+ "\n",
550
+ "if os.path.exists(BEST_MODEL_PATH):\n",
551
+ " # Rebuild the model architecture and load weights (avoids Keras version mismatch)\n",
552
+ " from models import build_conv1d_model\n",
553
+ " model = build_conv1d_model(\n",
554
+ " filters=(128, 256),\n",
555
+ " kernel_size=3,\n",
556
+ " pool_size=3,\n",
557
+ " dense_units=(256, 128, 64),\n",
558
+ " dropout_rate=0.2\n",
559
+ " )\n",
560
+ " model.load_weights(BEST_MODEL_PATH)\n",
561
+ " model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])\n",
562
+ " \n",
563
+ " print(f\"Model loaded from {BEST_MODEL_PATH}\")\n",
564
+ " model.summary()\n",
565
+ "else:\n",
566
+ " print(f\"Model not found at {BEST_MODEL_PATH}\")"
567
+ ]
568
+ },
569
+ {
570
+ "cell_type": "code",
571
+ "execution_count": 51,
572
+ "id": "15765a85",
573
+ "metadata": {},
574
+ "outputs": [
575
+ {
576
+ "name": "stdout",
577
+ "output_type": "stream",
578
+ "text": [
579
+ "Input shape: (1, 30, 26)\n",
580
+ "Output shape: (1, 13)\n",
581
+ "Predicted Z values: [ 0.05649754 0.03968733 -0.03916807 0.05462698 0.00482728]...\n"
582
+ ]
583
+ }
584
+ ],
585
+ "source": [
586
+ "# Example inference\n",
587
+ "def predict_z_coordinates(model, xy_sequence):\n",
588
+ " \"\"\"\n",
589
+ " Predict Z coordinates from X/Y sequence.\n",
590
+ " \n",
591
+ " Args:\n",
592
+ " model: Loaded Keras model\n",
593
+ " xy_sequence: numpy array of shape (batch, 30, 26)\n",
594
+ " 30 = window size, 26 = 13 joints × 2 (x, y)\n",
595
+ " \n",
596
+ " Returns:\n",
597
+ " z_predictions: numpy array of shape (batch, 13)\n",
598
+ " 13 z-coordinates for each joint\n",
599
+ " \"\"\"\n",
600
+ " return model.predict(xy_sequence, verbose=0)\n",
601
+ "\n",
602
+ "# Example with dummy data\n",
603
+ "if 'model' in dir():\n",
604
+ " dummy_input = np.random.randn(1, 30, 26).astype(np.float32)\n",
605
+ " z_pred = predict_z_coordinates(model, dummy_input)\n",
606
+ " print(f\"Input shape: {dummy_input.shape}\")\n",
607
+ " print(f\"Output shape: {z_pred.shape}\")\n",
608
+ " print(f\"Predicted Z values: {z_pred[0][:5]}...\")"
609
+ ]
610
+ },
611
+ {
612
+ "cell_type": "markdown",
613
+ "id": "6fb36696",
614
+ "metadata": {},
615
+ "source": [
616
+ "### Retraining the Model\n",
617
+ "\n",
618
+ "```bash\n",
619
+ "# Run the cross-validation training script\n",
620
+ "cd A9\n",
621
+ "python cv_training.py\n",
622
+ "```\n",
623
+ "\n",
624
+ "Or modify `all_models_config.py` to change architecture parameters."
625
+ ]
626
+ }
627
+ ],
628
+ "metadata": {
629
+ "kernelspec": {
630
+ "display_name": "Python 3",
631
+ "language": "python",
632
+ "name": "python3"
633
+ },
634
+ "language_info": {
635
+ "codemirror_mode": {
636
+ "name": "ipython",
637
+ "version": 3
638
+ },
639
+ "file_extension": ".py",
640
+ "mimetype": "text/x-python",
641
+ "name": "python",
642
+ "nbconvert_exporter": "python",
643
+ "pygments_lexer": "ipython3",
644
+ "version": "3.10.0"
645
+ }
646
+ },
647
+ "nbformat": 4,
648
+ "nbformat_minor": 5
649
+ }
A9/aggregate_results.py ADDED
@@ -0,0 +1,271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ A9 Results Aggregation Script
3
+
4
+ Aggregates all cross-validation results from the cv_results folders
5
+ and produces summary tables for the A9_Report.ipynb notebook.
6
+
7
+ Usage:
8
+ python aggregate_results.py
9
+
10
+ Output:
11
+ - results_summary.csv: All experiment results in one table
12
+ - results_summary.json: Same data in JSON format
13
+ - Prints summary to console
14
+ """
15
+
16
+ import os
17
+ import json
18
+ import re
19
+ import pandas as pd
20
+ from pathlib import Path
21
+
22
+ # Result directories
23
+ RESULT_DIRS = {
24
+ 'different_models': 'cv_results_different_models',
25
+ 'conv1d_variants': 'cv_results_conv1D_variants',
26
+ 'optimizer': 'cv_results_optimizer',
27
+ 'loss_optimizer': 'cv_results_loss_optimizer',
28
+ }
29
+
30
+
31
+ def parse_summary_txt(filepath):
32
+ """Parse summary.txt file to extract metrics."""
33
+ results = []
34
+
35
+ with open(filepath, 'r') as f:
36
+ content = f.read()
37
+
38
+ # Find all model sections with their metrics
39
+ # Pattern matches lines like " Optimizer: SGD, Loss: MSE" or just model names
40
+ sections = re.split(r'\n(?=[A-Z_]+(?:_[A-Z]+)*\n-{10,})', content)
41
+
42
+ for section in sections:
43
+ if 'Val RMSE:' in section or 'Test RMSE:' in section:
44
+ lines = section.strip().split('\n')
45
+ model_name = lines[0].strip() if lines else 'unknown'
46
+
47
+ # Skip separator lines
48
+ if model_name.startswith('-'):
49
+ continue
50
+
51
+ row = {'model': model_name.lower()}
52
+
53
+ # Extract metrics using regex
54
+ val_rmse = re.search(r'Val RMSE:\s*([\d.]+)\s*±\s*([\d.]+)', section)
55
+ val_mae = re.search(r'Val MAE:\s*([\d.]+)\s*±\s*([\d.]+)', section)
56
+ val_r2 = re.search(r'Val R²:\s*([\d.]+)\s*±\s*([\d.]+)', section)
57
+ test_rmse = re.search(r'Test RMSE:\s*([\d.]+)', section)
58
+ test_mae = re.search(r'Test MAE:\s*([\d.]+)', section)
59
+ test_r2 = re.search(r'Test R²:\s*([\d.]+)', section)
60
+ best_fold = re.search(r'Best Fold:\s*(\d+)', section)
61
+
62
+ if val_rmse:
63
+ row['val_rmse_mean'] = float(val_rmse.group(1))
64
+ row['val_rmse_std'] = float(val_rmse.group(2))
65
+ if val_mae:
66
+ row['val_mae_mean'] = float(val_mae.group(1))
67
+ row['val_mae_std'] = float(val_mae.group(2))
68
+ if val_r2:
69
+ row['val_r2_mean'] = float(val_r2.group(1))
70
+ row['val_r2_std'] = float(val_r2.group(2))
71
+ if test_rmse:
72
+ row['test_rmse'] = float(test_rmse.group(1))
73
+ if test_mae:
74
+ row['test_mae'] = float(test_mae.group(1))
75
+ if test_r2:
76
+ row['test_r2'] = float(test_r2.group(1))
77
+ if best_fold:
78
+ row['best_fold'] = int(best_fold.group(1))
79
+
80
+ # Only add if we found some metrics
81
+ if len(row) > 1:
82
+ results.append(row)
83
+
84
+ return results
85
+
86
+
87
+ def parse_summary_header(filepath):
88
+ """Parse the header summary section of summary.txt."""
89
+ results = []
90
+
91
+ with open(filepath, 'r') as f:
92
+ content = f.read()
93
+
94
+ # Pattern 1: Standard format (DENSE:, CONV1D:, CONV1D_V3: etc.)
95
+ # Fixed to properly capture model names with underscores and numbers
96
+ pattern1 = r'([A-Z][A-Z0-9_]*):\s*\n\s*Best Fold:\s*(\d+)\s*\n\s*Val RMSE:\s*([\d.]+)\s*±\s*([\d.]+)\s*\n\s*Val MAE:\s*([\d.]+)\s*±\s*([\d.]+)\s*\n\s*Val R²:\s*([\d.]+)\s*±\s*([\d.]+)(?:\s*\n\s*Test RMSE:\s*([\d.]+))?(?:\s*\n\s*Test MAE:\s*([\d.]+))?(?:\s*\n\s*Test R²:\s*([\d.]+))?'
97
+
98
+ # Pattern 2: Optimizer format (Optimizer: SGD, etc.)
99
+ pattern2 = r'Optimizer:\s*([A-Z]+)(?:,\s*Loss:\s*([A-Z]+))?\s*\n\s*Best Fold:\s*(\d+)\s*\n\s*Val RMSE:\s*([\d.]+)\s*±\s*([\d.]+)\s*\n\s*Val MAE:\s*([\d.]+)\s*±\s*([\d.]+)\s*\n\s*Val R²:\s*([\d.]+)\s*±\s*([\d.]+)(?:\s*\n\s*Test RMSE:\s*([\d.]+))?(?:\s*\n\s*Test MAE:\s*([\d.]+))?(?:\s*\n\s*Test R²:\s*([\d.]+))?'
100
+
101
+ seen_models = set()
102
+
103
+ # Try pattern 1
104
+ matches = re.finditer(pattern1, content, re.MULTILINE)
105
+ for match in matches:
106
+ model_name = match.group(1).lower()
107
+
108
+ # Skip detailed sections (those that start with model name and have "-----" after)
109
+ # We only want the summary sections at the top
110
+ pos = match.start()
111
+ next_line_start = content.find('\n', match.end()) + 1
112
+ if next_line_start < len(content):
113
+ next_line = content[next_line_start:next_line_start+50]
114
+ if '---' in next_line:
115
+ continue
116
+
117
+ # Skip duplicates
118
+ if model_name in seen_models:
119
+ continue
120
+ seen_models.add(model_name)
121
+
122
+ row = {
123
+ 'model': model_name,
124
+ 'best_fold': int(match.group(2)),
125
+ 'val_rmse_mean': float(match.group(3)),
126
+ 'val_rmse_std': float(match.group(4)),
127
+ 'val_mae_mean': float(match.group(5)),
128
+ 'val_mae_std': float(match.group(6)),
129
+ 'val_r2_mean': float(match.group(7)),
130
+ 'val_r2_std': float(match.group(8)),
131
+ }
132
+ if match.group(9):
133
+ row['test_rmse'] = float(match.group(9))
134
+ if match.group(10):
135
+ row['test_mae'] = float(match.group(10))
136
+ if match.group(11):
137
+ row['test_r2'] = float(match.group(11))
138
+
139
+ results.append(row)
140
+
141
+ # Try pattern 2 for optimizer/loss variants
142
+ matches = re.finditer(pattern2, content, re.MULTILINE)
143
+ for match in matches:
144
+ optimizer = match.group(1).lower()
145
+ loss = match.group(2).lower() if match.group(2) else 'mse'
146
+ model_name = f"conv1d_v3_{optimizer}_{loss}"
147
+
148
+ # Skip duplicates
149
+ if model_name in seen_models:
150
+ continue
151
+ seen_models.add(model_name)
152
+
153
+ row = {
154
+ 'model': model_name,
155
+ 'best_fold': int(match.group(3)),
156
+ 'val_rmse_mean': float(match.group(4)),
157
+ 'val_rmse_std': float(match.group(5)),
158
+ 'val_mae_mean': float(match.group(6)),
159
+ 'val_mae_std': float(match.group(7)),
160
+ 'val_r2_mean': float(match.group(8)),
161
+ 'val_r2_std': float(match.group(9)),
162
+ }
163
+ if match.group(10):
164
+ row['test_rmse'] = float(match.group(10))
165
+ if match.group(11):
166
+ row['test_mae'] = float(match.group(11))
167
+ if match.group(12):
168
+ row['test_r2'] = float(match.group(12))
169
+
170
+ results.append(row)
171
+
172
+ return results
173
+
174
+
175
+ def main():
176
+ script_dir = Path(__file__).parent
177
+ os.chdir(script_dir)
178
+
179
+ all_results = []
180
+
181
+ print("=" * 60)
182
+ print("A9 Results Aggregation")
183
+ print("=" * 60)
184
+
185
+ # Load results from each experiment directory by parsing summary.txt
186
+ for exp_name, dir_name in RESULT_DIRS.items():
187
+ summary_path = Path(dir_name) / 'summary.txt'
188
+ print(f"\nLoading from {summary_path}...")
189
+
190
+ if not summary_path.exists():
191
+ print(f" Warning: {summary_path} not found")
192
+ continue
193
+
194
+ results = parse_summary_header(summary_path)
195
+ print(f" Found {len(results)} model results")
196
+
197
+ for row in results:
198
+ row['experiment'] = exp_name
199
+ all_results.append(row)
200
+
201
+ if not all_results:
202
+ print("\nNo results found!")
203
+ return
204
+
205
+ # Create DataFrame
206
+ df = pd.DataFrame(all_results)
207
+
208
+ # Reorder columns
209
+ cols = ['experiment', 'model', 'best_fold', 'val_r2_mean', 'val_r2_std',
210
+ 'val_rmse_mean', 'val_rmse_std', 'val_mae_mean', 'val_mae_std',
211
+ 'test_r2', 'test_rmse', 'test_mae']
212
+ df = df[[c for c in cols if c in df.columns]]
213
+
214
+ # Sort by test_r2 descending, then val_r2_mean
215
+ df['sort_key'] = df['test_r2'].fillna(df['val_r2_mean'])
216
+ df = df.sort_values('sort_key', ascending=False).drop('sort_key', axis=1)
217
+
218
+ # Save to CSV
219
+ df.to_csv('results_summary.csv', index=False)
220
+ print(f"\nSaved to results_summary.csv ({len(df)} rows)")
221
+
222
+ # Save to JSON
223
+ df.to_json('results_summary.json', orient='records', indent=2)
224
+ print(f"Saved to results_summary.json")
225
+
226
+ # Print summary tables
227
+ print("\n" + "=" * 60)
228
+ print("SUMMARY: All Experiments Ranked by R²")
229
+ print("=" * 60)
230
+
231
+ print(df.to_string(index=False, float_format=lambda x: f'{x:.4f}' if pd.notna(x) else 'N/A'))
232
+
233
+ # Best model
234
+ print("\n" + "=" * 60)
235
+ print("CHAMPION MODEL")
236
+ print("=" * 60)
237
+ best = df.iloc[0]
238
+ print(f"Model: {best['model']}")
239
+ print(f"Experiment: {best['experiment']}")
240
+ if pd.notna(best.get('val_r2_mean')):
241
+ print(f"Validation R²: {best['val_r2_mean']:.4f} ± {best['val_r2_std']:.4f}")
242
+ print(f"Validation RMSE: {best['val_rmse_mean']:.4f} ± {best['val_rmse_std']:.4f}")
243
+ if pd.notna(best.get('test_r2')):
244
+ print(f"Test R²: {best['test_r2']:.4f}")
245
+ print(f"Test RMSE: {best['test_rmse']:.4f}")
246
+
247
+ # Dead ends (R² < 0.85)
248
+ print("\n" + "=" * 60)
249
+ print("DEAD ENDS (R² < 0.85)")
250
+ print("=" * 60)
251
+ r2_col = 'test_r2' if 'test_r2' in df.columns else 'val_r2_mean'
252
+ dead_ends = df[df[r2_col] < 0.85]
253
+ if len(dead_ends) > 0:
254
+ print(dead_ends[['experiment', 'model', 'val_r2_mean', 'test_r2']].to_string(index=False))
255
+ else:
256
+ print("None found")
257
+
258
+ # Group summaries
259
+ print("\n" + "=" * 60)
260
+ print("EXPERIMENT SUMMARIES")
261
+ print("=" * 60)
262
+
263
+ for exp_name in RESULT_DIRS.keys():
264
+ exp_df = df[df['experiment'] == exp_name]
265
+ if len(exp_df) > 0:
266
+ print(f"\n{exp_name.upper()}:")
267
+ print(exp_df[['model', 'val_r2_mean', 'val_rmse_mean', 'test_r2', 'test_rmse']].to_string(index=False))
268
+
269
+
270
+ if __name__ == '__main__':
271
+ main()
A9/results_summary.csv ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ experiment,model,best_fold,val_r2_mean,val_r2_std,val_rmse_mean,val_rmse_std,val_mae_mean,val_mae_std,test_r2,test_rmse,test_mae
2
+ optimizer,conv1d_v3_rmsprop_mse,1,0.946803,0.004864,0.033498,0.001768,0.024131,0.001299,0.954934,0.031001,0.022902
3
+ loss_optimizer,conv1d_v3_rmsprop_mse,4,0.950038,0.002828,0.032467,0.000629,0.023508,0.000743,0.954592,0.031119,0.022788
4
+ optimizer,conv1d_v3_adam_mse,1,0.949678,0.004671,0.032558,0.001222,0.02349,0.000625,0.953484,0.031496,0.023255
5
+ loss_optimizer,conv1d_v3_adam_mse,1,0.948571,0.002204,0.032956,0.000841,0.02364,0.000489,0.95286,0.031707,0.023486
6
+ optimizer,conv1d_v3_sgd_mse,1,0.950863,0.002815,0.032199,0.000687,0.023269,0.000512,0.952354,0.031876,0.023561
7
+ loss_optimizer,conv1d_v3_sgd_mse,1,0.950748,0.003632,0.032241,0.001373,0.023373,0.00102,0.952171,0.031937,0.023461
8
+ loss_optimizer,conv1d_v3_rmsprop_mae,1,0.943196,0.003858,0.034623,0.00129,0.023639,0.000801,0.944302,0.034465,0.023634
9
+ loss_optimizer,conv1d_v3_adam_mae,1,0.939982,0.002526,0.035601,0.000889,0.02409,0.00052,0.934766,0.037298,0.0258
10
+ loss_optimizer,conv1d_v3_sgd_mae,1,0.939909,0.001839,0.035625,0.000619,0.023964,0.000383,0.93406,0.0375,0.024983
11
+ different_models,conv1d,2,0.932681,0.005506,0.037704,0.001386,0.027598,0.000905,,,
12
+ conv1d_variants,conv1d,1,0.922923,0.007843,0.040316,0.002366,0.029083,0.001559,0.928322,0.039097,0.028836
13
+ conv1d_variants,conv1d_v2,5,0.799991,0.031161,0.064831,0.005451,0.048145,0.003991,0.826827,0.06077,0.044539
14
+ different_models,dense,4,0.820046,0.002133,0.058055,0.000435,0.042731,0.000244,,,
15
+ different_models,lstm,4,0.76853,0.025836,0.069834,0.003102,0.052217,0.002199,,,
A9/results_summary.json ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "experiment":"optimizer",
4
+ "model":"conv1d_v3_rmsprop_mse",
5
+ "best_fold":1,
6
+ "val_r2_mean":0.946803,
7
+ "val_r2_std":0.004864,
8
+ "val_rmse_mean":0.033498,
9
+ "val_rmse_std":0.001768,
10
+ "val_mae_mean":0.024131,
11
+ "val_mae_std":0.001299,
12
+ "test_r2":0.954934,
13
+ "test_rmse":0.031001,
14
+ "test_mae":0.022902
15
+ },
16
+ {
17
+ "experiment":"loss_optimizer",
18
+ "model":"conv1d_v3_rmsprop_mse",
19
+ "best_fold":4,
20
+ "val_r2_mean":0.950038,
21
+ "val_r2_std":0.002828,
22
+ "val_rmse_mean":0.032467,
23
+ "val_rmse_std":0.000629,
24
+ "val_mae_mean":0.023508,
25
+ "val_mae_std":0.000743,
26
+ "test_r2":0.954592,
27
+ "test_rmse":0.031119,
28
+ "test_mae":0.022788
29
+ },
30
+ {
31
+ "experiment":"optimizer",
32
+ "model":"conv1d_v3_adam_mse",
33
+ "best_fold":1,
34
+ "val_r2_mean":0.949678,
35
+ "val_r2_std":0.004671,
36
+ "val_rmse_mean":0.032558,
37
+ "val_rmse_std":0.001222,
38
+ "val_mae_mean":0.02349,
39
+ "val_mae_std":0.000625,
40
+ "test_r2":0.953484,
41
+ "test_rmse":0.031496,
42
+ "test_mae":0.023255
43
+ },
44
+ {
45
+ "experiment":"loss_optimizer",
46
+ "model":"conv1d_v3_adam_mse",
47
+ "best_fold":1,
48
+ "val_r2_mean":0.948571,
49
+ "val_r2_std":0.002204,
50
+ "val_rmse_mean":0.032956,
51
+ "val_rmse_std":0.000841,
52
+ "val_mae_mean":0.02364,
53
+ "val_mae_std":0.000489,
54
+ "test_r2":0.95286,
55
+ "test_rmse":0.031707,
56
+ "test_mae":0.023486
57
+ },
58
+ {
59
+ "experiment":"optimizer",
60
+ "model":"conv1d_v3_sgd_mse",
61
+ "best_fold":1,
62
+ "val_r2_mean":0.950863,
63
+ "val_r2_std":0.002815,
64
+ "val_rmse_mean":0.032199,
65
+ "val_rmse_std":0.000687,
66
+ "val_mae_mean":0.023269,
67
+ "val_mae_std":0.000512,
68
+ "test_r2":0.952354,
69
+ "test_rmse":0.031876,
70
+ "test_mae":0.023561
71
+ },
72
+ {
73
+ "experiment":"loss_optimizer",
74
+ "model":"conv1d_v3_sgd_mse",
75
+ "best_fold":1,
76
+ "val_r2_mean":0.950748,
77
+ "val_r2_std":0.003632,
78
+ "val_rmse_mean":0.032241,
79
+ "val_rmse_std":0.001373,
80
+ "val_mae_mean":0.023373,
81
+ "val_mae_std":0.00102,
82
+ "test_r2":0.952171,
83
+ "test_rmse":0.031937,
84
+ "test_mae":0.023461
85
+ },
86
+ {
87
+ "experiment":"loss_optimizer",
88
+ "model":"conv1d_v3_rmsprop_mae",
89
+ "best_fold":1,
90
+ "val_r2_mean":0.943196,
91
+ "val_r2_std":0.003858,
92
+ "val_rmse_mean":0.034623,
93
+ "val_rmse_std":0.00129,
94
+ "val_mae_mean":0.023639,
95
+ "val_mae_std":0.000801,
96
+ "test_r2":0.944302,
97
+ "test_rmse":0.034465,
98
+ "test_mae":0.023634
99
+ },
100
+ {
101
+ "experiment":"loss_optimizer",
102
+ "model":"conv1d_v3_adam_mae",
103
+ "best_fold":1,
104
+ "val_r2_mean":0.939982,
105
+ "val_r2_std":0.002526,
106
+ "val_rmse_mean":0.035601,
107
+ "val_rmse_std":0.000889,
108
+ "val_mae_mean":0.02409,
109
+ "val_mae_std":0.00052,
110
+ "test_r2":0.934766,
111
+ "test_rmse":0.037298,
112
+ "test_mae":0.0258
113
+ },
114
+ {
115
+ "experiment":"loss_optimizer",
116
+ "model":"conv1d_v3_sgd_mae",
117
+ "best_fold":1,
118
+ "val_r2_mean":0.939909,
119
+ "val_r2_std":0.001839,
120
+ "val_rmse_mean":0.035625,
121
+ "val_rmse_std":0.000619,
122
+ "val_mae_mean":0.023964,
123
+ "val_mae_std":0.000383,
124
+ "test_r2":0.93406,
125
+ "test_rmse":0.0375,
126
+ "test_mae":0.024983
127
+ },
128
+ {
129
+ "experiment":"different_models",
130
+ "model":"conv1d",
131
+ "best_fold":2,
132
+ "val_r2_mean":0.932681,
133
+ "val_r2_std":0.005506,
134
+ "val_rmse_mean":0.037704,
135
+ "val_rmse_std":0.001386,
136
+ "val_mae_mean":0.027598,
137
+ "val_mae_std":0.000905,
138
+ "test_r2":null,
139
+ "test_rmse":null,
140
+ "test_mae":null
141
+ },
142
+ {
143
+ "experiment":"conv1d_variants",
144
+ "model":"conv1d",
145
+ "best_fold":1,
146
+ "val_r2_mean":0.922923,
147
+ "val_r2_std":0.007843,
148
+ "val_rmse_mean":0.040316,
149
+ "val_rmse_std":0.002366,
150
+ "val_mae_mean":0.029083,
151
+ "val_mae_std":0.001559,
152
+ "test_r2":0.928322,
153
+ "test_rmse":0.039097,
154
+ "test_mae":0.028836
155
+ },
156
+ {
157
+ "experiment":"conv1d_variants",
158
+ "model":"conv1d_v2",
159
+ "best_fold":5,
160
+ "val_r2_mean":0.799991,
161
+ "val_r2_std":0.031161,
162
+ "val_rmse_mean":0.064831,
163
+ "val_rmse_std":0.005451,
164
+ "val_mae_mean":0.048145,
165
+ "val_mae_std":0.003991,
166
+ "test_r2":0.826827,
167
+ "test_rmse":0.06077,
168
+ "test_mae":0.044539
169
+ },
170
+ {
171
+ "experiment":"different_models",
172
+ "model":"dense",
173
+ "best_fold":4,
174
+ "val_r2_mean":0.820046,
175
+ "val_r2_std":0.002133,
176
+ "val_rmse_mean":0.058055,
177
+ "val_rmse_std":0.000435,
178
+ "val_mae_mean":0.042731,
179
+ "val_mae_std":0.000244,
180
+ "test_r2":null,
181
+ "test_rmse":null,
182
+ "test_mae":null
183
+ },
184
+ {
185
+ "experiment":"different_models",
186
+ "model":"lstm",
187
+ "best_fold":4,
188
+ "val_r2_mean":0.76853,
189
+ "val_r2_std":0.025836,
190
+ "val_rmse_mean":0.069834,
191
+ "val_rmse_std":0.003102,
192
+ "val_mae_mean":0.052217,
193
+ "val_mae_std":0.002199,
194
+ "test_r2":null,
195
+ "test_rmse":null,
196
+ "test_mae":null
197
+ }
198
+ ]