Add validation dataset to hyperparameter scan

This commit is contained in:
2025-11-23 13:02:22 +01:00
parent a77fd08c5d
commit 30e21eb5e9
4 changed files with 548 additions and 34 deletions
+90 -31
View File
@@ -2,10 +2,19 @@
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 39,
"id": "276487d8",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The autoreload extension is already loaded. To reload it, use:\n",
" %reload_ext autoreload\n"
]
}
],
"source": [
"%load_ext autoreload\n",
"%autoreload 2\n",
@@ -16,7 +25,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 40,
"id": "1308b1d5",
"metadata": {},
"outputs": [],
@@ -29,7 +38,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 41,
"id": "0d8e6107",
"metadata": {},
"outputs": [
@@ -85488,15 +85497,26 @@
" n_windows_per_file=5,\n",
" step=1,\n",
" feature_columns=(\"lat\", \"lon\", \"alt\", \"ias\"),\n",
" context_columns=(\"last_lat\", \"last_lon\", \"last_alt\", \"last_ias\"),\n",
" context_columns=(\"last_lat\", \"last_lon\", \"last_alt\", \"last_ias\", \"last_timestamp\"),\n",
" time_columns=(\"timestamp\", \"dt\"),\n",
" target_columns=(\"lat\", \"lon\", \"alt\"),\n",
")"
")\n",
"dataset.save_entire_dataset(\"test.pt\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 42,
"id": "fd269d10",
"metadata": {},
"outputs": [],
"source": [
"test_loader = dataloader.SaveDataset(torch.load(\"test.pt\"))"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "595103c9",
"metadata": {},
"outputs": [
@@ -85506,35 +85526,35 @@
"2365"
]
},
"execution_count": 4,
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(dataset)"
"len(test_loader)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 57,
"id": "522cd04f",
"metadata": {},
"outputs": [],
"source": [
"test_model = models.ThreeInputRNN(\n",
"test_model = models.ThreeInputGRU(\n",
" time_in=2,\n",
" feat_in=4,\n",
" context_in=4,\n",
" hidden_size=128,\n",
" rnn_size=256,\n",
" context_in=5,\n",
" hidden_size=16,\n",
" rnn_size=32,\n",
" out_size=3,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 58,
"id": "4e089307",
"metadata": {},
"outputs": [
@@ -85542,12 +85562,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Loss: 0.1666\n",
"Loss: 0.0905\n",
"Loss: 0.1575\n",
"Loss: 0.2210\n",
"Loss: 0.1710\n",
"Loss: 0.2356\n"
"Epoch 0: loss=2193.2530151367187, lr=0.001\n"
]
},
{
@@ -85557,37 +85572,81 @@
"traceback": [
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
"\u001b[31mKeyboardInterrupt\u001b[39m Traceback (most recent call last)",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[9]\u001b[39m\u001b[32m, line 7\u001b[39m\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m X_f, X_t, y, X_c \u001b[38;5;129;01min\u001b[39;00m torch.utils.data.DataLoader(dataset, batch_size=\u001b[32m256\u001b[39m, shuffle=\u001b[38;5;28;01mTrue\u001b[39;00m):\n\u001b[32m 6\u001b[39m optimizer.zero_grad()\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m y_pred, _ = \u001b[43mtest_model\u001b[49m\u001b[43m(\u001b[49m\u001b[43mX_t\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mX_f\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mX_c\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[32;43m300\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[32;43m30\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 8\u001b[39m loss = criterion(y_pred, y)\n\u001b[32m 9\u001b[39m loss.backward()\n",
"\u001b[36mFile \u001b[39m\u001b[32m~/Documents/Studium/UiO/data_analysis/project3/Code/python/.venv/lib64/python3.13/site-packages/torch/nn/modules/module.py:1775\u001b[39m, in \u001b[36mModule._wrapped_call_impl\u001b[39m\u001b[34m(self, *args, **kwargs)\u001b[39m\n\u001b[32m 1773\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m._compiled_call_impl(*args, **kwargs) \u001b[38;5;66;03m# type: ignore[misc]\u001b[39;00m\n\u001b[32m 1774\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m-> \u001b[39m\u001b[32m1775\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_call_impl\u001b[49m\u001b[43m(\u001b[49m\u001b[43m*\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
"\u001b[36mFile \u001b[39m\u001b[32m~/Documents/Studium/UiO/data_analysis/project3/Code/python/.venv/lib64/python3.13/site-packages/torch/nn/modules/module.py:1786\u001b[39m, in \u001b[36mModule._call_impl\u001b[39m\u001b[34m(self, *args, **kwargs)\u001b[39m\n\u001b[32m 1781\u001b[39m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[32m 1782\u001b[39m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[32m 1783\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m._backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m._backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m._forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m._forward_pre_hooks\n\u001b[32m 1784\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m _global_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[32m 1785\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[32m-> \u001b[39m\u001b[32m1786\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mforward_call\u001b[49m\u001b[43m(\u001b[49m\u001b[43m*\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 1788\u001b[39m result = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 1789\u001b[39m called_always_called_hooks = \u001b[38;5;28mset\u001b[39m()\n",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[58]\u001b[39m\u001b[32m, line 11\u001b[39m\n\u001b[32m 9\u001b[39m y_pred, _ = test_model(X_t, X_f, X_c, \u001b[32m300\u001b[39m, \u001b[32m30\u001b[39m)\n\u001b[32m 10\u001b[39m loss = criterion(y_pred, y)\n\u001b[32m---> \u001b[39m\u001b[32m11\u001b[39m \u001b[43mloss\u001b[49m\u001b[43m.\u001b[49m\u001b[43mbackward\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 12\u001b[39m optimizer.step()\n\u001b[32m 13\u001b[39m loss_history.append(loss.item())\n",
"\u001b[36mFile \u001b[39m\u001b[32m~/Documents/Studium/UiO/data_analysis/project3/Code/python/.venv/lib64/python3.13/site-packages/torch/_tensor.py:625\u001b[39m, in \u001b[36mTensor.backward\u001b[39m\u001b[34m(self, gradient, retain_graph, create_graph, inputs)\u001b[39m\n\u001b[32m 615\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m has_torch_function_unary(\u001b[38;5;28mself\u001b[39m):\n\u001b[32m 616\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m handle_torch_function(\n\u001b[32m 617\u001b[39m Tensor.backward,\n\u001b[32m 618\u001b[39m (\u001b[38;5;28mself\u001b[39m,),\n\u001b[32m (...)\u001b[39m\u001b[32m 623\u001b[39m inputs=inputs,\n\u001b[32m 624\u001b[39m )\n\u001b[32m--> \u001b[39m\u001b[32m625\u001b[39m \u001b[43mtorch\u001b[49m\u001b[43m.\u001b[49m\u001b[43mautograd\u001b[49m\u001b[43m.\u001b[49m\u001b[43mbackward\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 626\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mgradient\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mretain_graph\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcreate_graph\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minputs\u001b[49m\u001b[43m=\u001b[49m\u001b[43minputs\u001b[49m\n\u001b[32m 627\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
"\u001b[36mFile \u001b[39m\u001b[32m~/Documents/Studium/UiO/data_analysis/project3/Code/python/.venv/lib64/python3.13/site-packages/torch/autograd/__init__.py:354\u001b[39m, in \u001b[36mbackward\u001b[39m\u001b[34m(tensors, grad_tensors, retain_graph, create_graph, grad_variables, inputs)\u001b[39m\n\u001b[32m 349\u001b[39m retain_graph = create_graph\n\u001b[32m 351\u001b[39m \u001b[38;5;66;03m# The reason we repeat the same comment below is that\u001b[39;00m\n\u001b[32m 352\u001b[39m \u001b[38;5;66;03m# some Python versions print out the first line of a multi-line function\u001b[39;00m\n\u001b[32m 353\u001b[39m \u001b[38;5;66;03m# calls in the traceback and some print out the last line\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m354\u001b[39m \u001b[43m_engine_run_backward\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 355\u001b[39m \u001b[43m \u001b[49m\u001b[43mtensors\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 356\u001b[39m \u001b[43m \u001b[49m\u001b[43mgrad_tensors_\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 357\u001b[39m \u001b[43m \u001b[49m\u001b[43mretain_graph\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 358\u001b[39m \u001b[43m \u001b[49m\u001b[43mcreate_graph\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 359\u001b[39m \u001b[43m \u001b[49m\u001b[43minputs_tuple\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 360\u001b[39m \u001b[43m \u001b[49m\u001b[43mallow_unreachable\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m 361\u001b[39m \u001b[43m \u001b[49m\u001b[43maccumulate_grad\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m 362\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
"\u001b[36mFile \u001b[39m\u001b[32m~/Documents/Studium/UiO/data_analysis/project3/Code/python/.venv/lib64/python3.13/site-packages/torch/autograd/graph.py:841\u001b[39m, in \u001b[36m_engine_run_backward\u001b[39m\u001b[34m(t_outputs, *args, **kwargs)\u001b[39m\n\u001b[32m 839\u001b[39m unregister_hooks = _register_logging_hooks_on_whole_graph(t_outputs)\n\u001b[32m 840\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m841\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mVariable\u001b[49m\u001b[43m.\u001b[49m\u001b[43m_execution_engine\u001b[49m\u001b[43m.\u001b[49m\u001b[43mrun_backward\u001b[49m\u001b[43m(\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# Calls into the C++ engine to run the backward pass\u001b[39;49;00m\n\u001b[32m 842\u001b[39m \u001b[43m \u001b[49m\u001b[43mt_outputs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\n\u001b[32m 843\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# Calls into the C++ engine to run the backward pass\u001b[39;00m\n\u001b[32m 844\u001b[39m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[32m 845\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m attach_logging_hooks:\n",
"\u001b[31mKeyboardInterrupt\u001b[39m: "
]
}
],
"source": [
"# Example training\n",
"optimizer = torch.optim.Adam(test_model.parameters(), lr=1e-2)\n",
"optimizer = torch.optim.Adam(test_model.parameters(), lr=1e-3)\n",
"scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=5, factor=0.5)\n",
"criterion = torch.nn.HuberLoss()\n",
"criterion = losses.HaversineAltitudeLoss(alt_const=1e-3)\n",
"for epoch in range(50):\n",
" losses = []\n",
" for X_f, X_t, y, X_c in torch.utils.data.DataLoader(dataset, batch_size=256, shuffle=True):\n",
" loss_history = []\n",
" for X_f, X_t, y, X_c in torch.utils.data.DataLoader(test_loader, batch_size=256, shuffle=True):\n",
" optimizer.zero_grad()\n",
" y_pred, _ = test_model(X_t, X_f, X_c, 300, 30)\n",
" loss = criterion(y_pred, y)\n",
" loss.backward()\n",
" optimizer.step()\n",
" losses.append(loss.item())\n",
" loss = sum(losses) / len(losses)\n",
" loss_history.append(loss.item())\n",
" loss = sum(loss_history) / len(loss_history)\n",
" scheduler.step(loss)\n",
" print(f\"Epoch {epoch}: loss={loss}, lr={optimizer.param_groups[0]['lr']}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 52,
"id": "a7f994ed",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ThreeInputGRU(\n",
" (time_proj): Sequential(\n",
" (0): Linear(in_features=2, out_features=16, bias=True)\n",
" (1): Tanh()\n",
" (2): Linear(in_features=16, out_features=16, bias=True)\n",
" (3): Tanh()\n",
" )\n",
" (feat_proj): Sequential(\n",
" (0): Linear(in_features=4, out_features=16, bias=True)\n",
" (1): Tanh()\n",
" (2): Linear(in_features=16, out_features=16, bias=True)\n",
" (3): Tanh()\n",
" )\n",
" (context_proj): Sequential(\n",
" (0): Linear(in_features=5, out_features=16, bias=True)\n",
" (1): Tanh()\n",
" (2): Linear(in_features=16, out_features=16, bias=True)\n",
" (3): Tanh()\n",
" )\n",
" (rnn): GRU(48, 32, num_layers=3, batch_first=True)\n",
" (readout): Sequential(\n",
" (0): Linear(in_features=32, out_features=16, bias=True)\n",
" (1): Tanh()\n",
" (2): Linear(in_features=16, out_features=3, bias=True)\n",
" )\n",
")\n"
]
}
],
"source": [
"print(test_model)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ddbc49ac",
"metadata": {},
"outputs": [],
"source": []
}
+17 -1
View File
@@ -26,7 +26,13 @@ if not pathlib.Path("dataset.pt").exists():
results = []
for step in [1, 5, 10, 30]:
dataset = dataloader.SaveDataset(torch.load("dataset.pt"), device="cuda", step=step)
dataset_length = len(dataset)
dataset, val_dataset = torch.utils.data.random_split(
dataset,
[int(0.8 * dataset_length), dataset_length - int(0.8 * dataset_length)],
generator=torch.Generator().manual_seed(42)
)
print(f"Starting hyperparameter scan for step={step}")
for base_name, base_model in [
("RNN", models.ThreeInputRNN),
("LSTM", models.ThreeInputLSTM),
@@ -63,6 +69,16 @@ for step in [1, 5, 10, 30]:
loss = sum(loss_history) / len(loss_history)
scheduler.step(loss)
print(f"Epoch {epoch}: loss={loss}, lr={optimizer.param_groups[0]['lr']}")
with torch.no_grad():
val_loss_history = []
for X_f, X_t, y, X_c in torch.utils.data.DataLoader(val_dataset, batch_size=256):
warm_up_steps = 450 // step
pred_steps = 150 // step
y_pred, _ = model(X_t, X_f, X_c, warm_up_steps, pred_steps)
v_loss = criterion(y_pred, y)
val_loss_history.append(v_loss.item())
loss = sum(val_loss_history) / len(val_loss_history)
print(f"Validation loss: {loss}")
torch.save(model.state_dict(), f"{base_name}_hs{hidden_size}_rs{rnn_size}_step{step}.pt")
results.append((base_name, hidden_size, rnn_size, step, loss))
Binary file not shown.