Commit
•
4fb2726
1
Parent(s):
93618bd
modeling a given teams tournament score 5 number summary (minus standard
Browse filesdeviation) using a pytorch neural network in 300k epochs. The model gets
439 for MSE Loss on testing data.
- models/model5000.pth +0 -3
- models/nn1M +0 -0
- models/scoreDist30k.pth +1 -1
- src/mens_nn.ipynb +141 -89
models/model5000.pth
DELETED
@@ -1,3 +0,0 @@
|
|
1 |
-
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:9407aad0201670b6905fe1c5a994b648d4dd8e397294805726cddab13cb9ef9c
|
3 |
-
size 34836
|
|
|
|
|
|
|
|
models/nn1M
DELETED
Binary file (38.6 kB)
|
|
models/scoreDist30k.pth
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
size 39998
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:d11fcf0f9b0ea5b93de0cbfbbaed4447f48ebc03c53be688981c3ceddbc287f7
|
3 |
size 39998
|
src/mens_nn.ipynb
CHANGED
@@ -20,34 +20,39 @@
|
|
20 |
"outputs": [],
|
21 |
"source": [
|
22 |
"from sklearn.model_selection import train_test_split\n",
|
|
|
|
|
23 |
"import torch\n",
|
24 |
"import torch.nn as nn\n",
|
25 |
"import torch.optim as optim\n",
|
26 |
-
"import numpy as np\n",
|
27 |
"import pandas as pd\n",
|
28 |
-
"import os
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
"sns.set_theme()\n",
|
34 |
"\n",
|
35 |
-
"# check to make sure if there are any gpu's available for faster training\n",
|
36 |
"def get_device() -> str:\n",
|
37 |
" if torch.cuda.is_available():\n",
|
38 |
" return \"cuda\"\n",
|
39 |
" return \"cpu\"\n",
|
40 |
"\n",
|
|
|
41 |
"DEVICE = get_device()\n",
|
42 |
-
"\n",
|
43 |
-
"
|
44 |
-
"DATA_DIR = os.path.join(\"..\", \"data\") \n",
|
45 |
-
"MODEL_DIR = os.path.join(\"..\", \"models\")"
|
46 |
]
|
47 |
},
|
48 |
{
|
49 |
"cell_type": "code",
|
50 |
-
"execution_count":
|
51 |
"id": "b820f210",
|
52 |
"metadata": {},
|
53 |
"outputs": [
|
@@ -70,7 +75,7 @@
|
|
70 |
},
|
71 |
{
|
72 |
"cell_type": "code",
|
73 |
-
"execution_count":
|
74 |
"id": "02ebc500",
|
75 |
"metadata": {},
|
76 |
"outputs": [
|
@@ -4353,7 +4358,7 @@
|
|
4353 |
"4 sec W02 "
|
4354 |
]
|
4355 |
},
|
4356 |
-
"execution_count":
|
4357 |
"metadata": {},
|
4358 |
"output_type": "execute_result"
|
4359 |
}
|
@@ -4373,7 +4378,7 @@
|
|
4373 |
},
|
4374 |
{
|
4375 |
"cell_type": "code",
|
4376 |
-
"execution_count":
|
4377 |
"id": "4901f37a",
|
4378 |
"metadata": {},
|
4379 |
"outputs": [
|
@@ -4460,7 +4465,7 @@
|
|
4460 |
"4 64.0 "
|
4461 |
]
|
4462 |
},
|
4463 |
-
"execution_count":
|
4464 |
"metadata": {},
|
4465 |
"output_type": "execute_result"
|
4466 |
}
|
@@ -4492,7 +4497,7 @@
|
|
4492 |
},
|
4493 |
{
|
4494 |
"cell_type": "code",
|
4495 |
-
"execution_count":
|
4496 |
"id": "1251726e",
|
4497 |
"metadata": {},
|
4498 |
"outputs": [],
|
@@ -4508,7 +4513,7 @@
|
|
4508 |
},
|
4509 |
{
|
4510 |
"cell_type": "code",
|
4511 |
-
"execution_count":
|
4512 |
"id": "28478189",
|
4513 |
"metadata": {},
|
4514 |
"outputs": [
|
@@ -4623,7 +4628,7 @@
|
|
4623 |
},
|
4624 |
{
|
4625 |
"cell_type": "code",
|
4626 |
-
"execution_count":
|
4627 |
"id": "04f4a0a6",
|
4628 |
"metadata": {},
|
4629 |
"outputs": [
|
@@ -4651,7 +4656,7 @@
|
|
4651 |
},
|
4652 |
{
|
4653 |
"cell_type": "code",
|
4654 |
-
"execution_count":
|
4655 |
"id": "40094cd0",
|
4656 |
"metadata": {},
|
4657 |
"outputs": [],
|
@@ -4677,7 +4682,7 @@
|
|
4677 |
},
|
4678 |
{
|
4679 |
"cell_type": "code",
|
4680 |
-
"execution_count":
|
4681 |
"id": "e949ea09",
|
4682 |
"metadata": {},
|
4683 |
"outputs": [
|
@@ -4693,7 +4698,7 @@
|
|
4693 |
" [ 0.0000, 570.0000, 44.0000, ..., 69.0000, 8.4030, 70.8889]])"
|
4694 |
]
|
4695 |
},
|
4696 |
-
"execution_count":
|
4697 |
"metadata": {},
|
4698 |
"output_type": "execute_result"
|
4699 |
}
|
@@ -4702,38 +4707,6 @@
|
|
4702 |
"X_trainT"
|
4703 |
]
|
4704 |
},
|
4705 |
-
{
|
4706 |
-
"cell_type": "markdown",
|
4707 |
-
"id": "20bceb9a",
|
4708 |
-
"metadata": {},
|
4709 |
-
"source": [
|
4710 |
-
"# Building Neural Network"
|
4711 |
-
]
|
4712 |
-
},
|
4713 |
-
{
|
4714 |
-
"cell_type": "code",
|
4715 |
-
"execution_count": 10,
|
4716 |
-
"id": "3eb2a440",
|
4717 |
-
"metadata": {},
|
4718 |
-
"outputs": [],
|
4719 |
-
"source": [
|
4720 |
-
"def pred_vs_actual_plot(pred: torch.Tensor, actual: torch.Tensor, target_names: list[str]):\n",
|
4721 |
-
" fig, axs = plt.subplots(2, len(pred[0]) // 2)\n",
|
4722 |
-
" axs = axs.flatten()\n",
|
4723 |
-
"\n",
|
4724 |
-
" for i in range(len(pred[0])):\n",
|
4725 |
-
" ax = axs[i]\n",
|
4726 |
-
" ax.scatter(actual[:, i], pred[:, i], alpha=0.5)\n",
|
4727 |
-
" ax.plot(ax.get_xlim(), ax.get_ylim(), color=\"red\", alpha=0.7, ls=\"--\")\n",
|
4728 |
-
"\n",
|
4729 |
-
" ax.set_title(f\"{target_names[i]}\")\n",
|
4730 |
-
" ax.set_xlabel(f\"Actual\")\n",
|
4731 |
-
" ax.set_ylabel(f\"Predicted\")\n",
|
4732 |
-
"\n",
|
4733 |
-
" plt.tight_layout()\n",
|
4734 |
-
" plt.show()\n"
|
4735 |
-
]
|
4736 |
-
},
|
4737 |
{
|
4738 |
"cell_type": "markdown",
|
4739 |
"id": "40ef573f",
|
@@ -4781,72 +4754,136 @@
|
|
4781 |
{
|
4782 |
"cell_type": "code",
|
4783 |
"execution_count": 12,
|
4784 |
-
"id": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4785 |
"metadata": {},
|
4786 |
"outputs": [
|
4787 |
{
|
4788 |
"name": "stdout",
|
4789 |
"output_type": "stream",
|
4790 |
"text": [
|
4791 |
-
"[30000 / 300000]
|
4792 |
-
"[60000 / 300000]
|
4793 |
-
"[90000 / 300000]
|
4794 |
-
"[120000 / 300000]
|
4795 |
-
"[150000 / 300000]
|
4796 |
-
"[180000 / 300000]
|
4797 |
-
"[210000 / 300000]
|
4798 |
-
"[240000 / 300000]
|
4799 |
-
"[270000 / 300000]
|
4800 |
-
"[300000 / 300000]
|
4801 |
]
|
4802 |
}
|
4803 |
],
|
4804 |
"source": [
|
4805 |
-
"\n",
|
4806 |
"torch.manual_seed(3)\n",
|
4807 |
"\n",
|
4808 |
"scoreModel300k = MadnessNNScore()\n",
|
4809 |
-
"optimizer = optim.Adam(lr=0.0001, params=scoreModel300k.parameters())\n",
|
4810 |
"loss_fn = nn.MSELoss()\n",
|
4811 |
-
"
|
|
|
|
|
|
|
4812 |
"\n",
|
4813 |
-
"
|
4814 |
-
"
|
4815 |
-
"
|
4816 |
-
"
|
4817 |
-
"
|
4818 |
-
" optimizer
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4819 |
"\n",
|
4820 |
-
"
|
4821 |
-
"
|
4822 |
-
"
|
|
|
4823 |
]
|
4824 |
},
|
4825 |
{
|
4826 |
"cell_type": "code",
|
4827 |
-
"execution_count":
|
4828 |
-
"id": "
|
4829 |
"metadata": {},
|
4830 |
"outputs": [],
|
4831 |
"source": [
|
4832 |
-
"
|
4833 |
-
"
|
4834 |
-
"
|
4835 |
-
")"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4836 |
]
|
4837 |
},
|
4838 |
{
|
4839 |
"cell_type": "code",
|
4840 |
-
"execution_count":
|
4841 |
-
"id": "
|
4842 |
"metadata": {},
|
4843 |
"outputs": [
|
4844 |
{
|
4845 |
"name": "stdout",
|
4846 |
"output_type": "stream",
|
4847 |
"text": [
|
4848 |
-
"
|
4849 |
-
"RMSE = 20.953686461297433\n"
|
4850 |
]
|
4851 |
},
|
4852 |
{
|
@@ -4861,13 +4898,28 @@
|
|
4861 |
}
|
4862 |
],
|
4863 |
"source": [
|
|
|
4864 |
"scoreModel300k.eval()\n",
|
4865 |
"\n",
|
|
|
4866 |
"with torch.no_grad():\n",
|
4867 |
" pred = scoreModel300k(X_testT)\n",
|
4868 |
" loss = loss_fn(pred, y_testT)\n",
|
4869 |
-
" print(f\"
|
4870 |
-
" pred_vs_actual_plot(pred, y_testT,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4871 |
]
|
4872 |
}
|
4873 |
],
|
|
|
20 |
"outputs": [],
|
21 |
"source": [
|
22 |
"from sklearn.model_selection import train_test_split\n",
|
23 |
+
"import matplotlib.pyplot as plt\n",
|
24 |
+
"import seaborn as sns\n",
|
25 |
"import torch\n",
|
26 |
"import torch.nn as nn\n",
|
27 |
"import torch.optim as optim\n",
|
|
|
28 |
"import pandas as pd\n",
|
29 |
+
"import os"
|
30 |
+
]
|
31 |
+
},
|
32 |
+
{
|
33 |
+
"cell_type": "code",
|
34 |
+
"execution_count": 2,
|
35 |
+
"id": "3f37c29e",
|
36 |
+
"metadata": {},
|
37 |
+
"outputs": [],
|
38 |
+
"source": [
|
39 |
+
"# set the plotting theme to seaborn \n",
|
40 |
"sns.set_theme()\n",
|
41 |
"\n",
|
|
|
42 |
"def get_device() -> str:\n",
|
43 |
" if torch.cuda.is_available():\n",
|
44 |
" return \"cuda\"\n",
|
45 |
" return \"cpu\"\n",
|
46 |
"\n",
|
47 |
+
"# project constants\n",
|
48 |
"DEVICE = get_device()\n",
|
49 |
+
"DATA_DIR = os.path.join(\"..\", \"data\")\n",
|
50 |
+
"MODEL_DIR = os.path.join(\"..\", \"models\")\n"
|
|
|
|
|
51 |
]
|
52 |
},
|
53 |
{
|
54 |
"cell_type": "code",
|
55 |
+
"execution_count": 3,
|
56 |
"id": "b820f210",
|
57 |
"metadata": {},
|
58 |
"outputs": [
|
|
|
75 |
},
|
76 |
{
|
77 |
"cell_type": "code",
|
78 |
+
"execution_count": 4,
|
79 |
"id": "02ebc500",
|
80 |
"metadata": {},
|
81 |
"outputs": [
|
|
|
4358 |
"4 sec W02 "
|
4359 |
]
|
4360 |
},
|
4361 |
+
"execution_count": 4,
|
4362 |
"metadata": {},
|
4363 |
"output_type": "execute_result"
|
4364 |
}
|
|
|
4378 |
},
|
4379 |
{
|
4380 |
"cell_type": "code",
|
4381 |
+
"execution_count": 5,
|
4382 |
"id": "4901f37a",
|
4383 |
"metadata": {},
|
4384 |
"outputs": [
|
|
|
4465 |
"4 64.0 "
|
4466 |
]
|
4467 |
},
|
4468 |
+
"execution_count": 5,
|
4469 |
"metadata": {},
|
4470 |
"output_type": "execute_result"
|
4471 |
}
|
|
|
4497 |
},
|
4498 |
{
|
4499 |
"cell_type": "code",
|
4500 |
+
"execution_count": 6,
|
4501 |
"id": "1251726e",
|
4502 |
"metadata": {},
|
4503 |
"outputs": [],
|
|
|
4513 |
},
|
4514 |
{
|
4515 |
"cell_type": "code",
|
4516 |
+
"execution_count": 7,
|
4517 |
"id": "28478189",
|
4518 |
"metadata": {},
|
4519 |
"outputs": [
|
|
|
4628 |
},
|
4629 |
{
|
4630 |
"cell_type": "code",
|
4631 |
+
"execution_count": 8,
|
4632 |
"id": "04f4a0a6",
|
4633 |
"metadata": {},
|
4634 |
"outputs": [
|
|
|
4656 |
},
|
4657 |
{
|
4658 |
"cell_type": "code",
|
4659 |
+
"execution_count": 9,
|
4660 |
"id": "40094cd0",
|
4661 |
"metadata": {},
|
4662 |
"outputs": [],
|
|
|
4682 |
},
|
4683 |
{
|
4684 |
"cell_type": "code",
|
4685 |
+
"execution_count": 10,
|
4686 |
"id": "e949ea09",
|
4687 |
"metadata": {},
|
4688 |
"outputs": [
|
|
|
4698 |
" [ 0.0000, 570.0000, 44.0000, ..., 69.0000, 8.4030, 70.8889]])"
|
4699 |
]
|
4700 |
},
|
4701 |
+
"execution_count": 10,
|
4702 |
"metadata": {},
|
4703 |
"output_type": "execute_result"
|
4704 |
}
|
|
|
4707 |
"X_trainT"
|
4708 |
]
|
4709 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4710 |
{
|
4711 |
"cell_type": "markdown",
|
4712 |
"id": "40ef573f",
|
|
|
4754 |
{
|
4755 |
"cell_type": "code",
|
4756 |
"execution_count": 12,
|
4757 |
+
"id": "a7449c1b",
|
4758 |
+
"metadata": {},
|
4759 |
+
"outputs": [],
|
4760 |
+
"source": [
|
4761 |
+
"\n",
|
4762 |
+
"def train_nn(model: nn.Module, X_trainT: torch.tensor, y_trainT: torch.Tensor, epochs: int, optimizer: optim.Optimizer, loss_fn) -> list[float]:\n",
|
4763 |
+
" loss_history = []\n",
|
4764 |
+
" for epoch in range(1, epochs + 1):\n",
|
4765 |
+
" pred = model(X_trainT)\n",
|
4766 |
+
" loss = loss_fn(pred, y_trainT)\n",
|
4767 |
+
" loss.backward()\n",
|
4768 |
+
" optimizer.step()\n",
|
4769 |
+
" optimizer.zero_grad()\n",
|
4770 |
+
"\n",
|
4771 |
+
" if epoch % (epochs // 10) == 0:\n",
|
4772 |
+
" print(f\"[{epoch} / {epochs}] {loss_fn} = {loss.item()}\")\n",
|
4773 |
+
" \n",
|
4774 |
+
" loss_history.append(loss.item())\n",
|
4775 |
+
" return loss_history\n"
|
4776 |
+
]
|
4777 |
+
},
|
4778 |
+
{
|
4779 |
+
"cell_type": "code",
|
4780 |
+
"execution_count": 13,
|
4781 |
+
"id": "fd084d5f",
|
4782 |
"metadata": {},
|
4783 |
"outputs": [
|
4784 |
{
|
4785 |
"name": "stdout",
|
4786 |
"output_type": "stream",
|
4787 |
"text": [
|
4788 |
+
"[30000 / 300000] MSELoss() = 22.599327087402344\n",
|
4789 |
+
"[60000 / 300000] MSELoss() = 14.090914726257324\n",
|
4790 |
+
"[90000 / 300000] MSELoss() = 10.638333320617676\n",
|
4791 |
+
"[120000 / 300000] MSELoss() = 8.183281898498535\n",
|
4792 |
+
"[150000 / 300000] MSELoss() = 6.67846155166626\n",
|
4793 |
+
"[180000 / 300000] MSELoss() = 5.694802761077881\n",
|
4794 |
+
"[210000 / 300000] MSELoss() = 10.18820571899414\n",
|
4795 |
+
"[240000 / 300000] MSELoss() = 4.195699214935303\n",
|
4796 |
+
"[270000 / 300000] MSELoss() = 4.009286403656006\n",
|
4797 |
+
"[300000 / 300000] MSELoss() = 3.245209217071533\n"
|
4798 |
]
|
4799 |
}
|
4800 |
],
|
4801 |
"source": [
|
|
|
4802 |
"torch.manual_seed(3)\n",
|
4803 |
"\n",
|
4804 |
"scoreModel300k = MadnessNNScore()\n",
|
|
|
4805 |
"loss_fn = nn.MSELoss()\n",
|
4806 |
+
"optimizer = optim.Adam(\n",
|
4807 |
+
" lr=0.0001, \n",
|
4808 |
+
" params=scoreModel300k.parameters(),\n",
|
4809 |
+
")\n",
|
4810 |
"\n",
|
4811 |
+
"loss_history = train_nn(\n",
|
4812 |
+
" model=scoreModel300k,\n",
|
4813 |
+
" X_trainT=X_trainT,\n",
|
4814 |
+
" y_trainT=y_trainT,\n",
|
4815 |
+
" epochs=300_000,\n",
|
4816 |
+
" optimizer=optimizer,\n",
|
4817 |
+
" loss_fn=loss_fn,\n",
|
4818 |
+
")"
|
4819 |
+
]
|
4820 |
+
},
|
4821 |
+
{
|
4822 |
+
"cell_type": "code",
|
4823 |
+
"execution_count": 14,
|
4824 |
+
"id": "9e84417c",
|
4825 |
+
"metadata": {},
|
4826 |
+
"outputs": [
|
4827 |
+
{
|
4828 |
+
"data": {
|
4829 |
+
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAkoAAAHJCAYAAAB67xZyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABJ2klEQVR4nO3deVxU9f7H8fcMOwoKqOCSaRruhgsKKWpUtmgW6r1l6i3L8pZp1zX9aZumdc2l0spMzdS83kpbbLGyUn+VC1p5KzWXXMgERNBBBQaY8/uDH3ObZGSgQY7wej4ePmTO8uU7HxDefr/fc47FMAxDAAAAOI+1sjsAAABgVgQlAAAANwhKAAAAbhCUAAAA3CAoAQAAuEFQAgAAcIOgBAAA4AZBCQAAwA2CEoBqg/vrAigrghJQTQwdOlRDhw6t7G641aJFC82fP7/Efdu2bVOLFi20bdu2El+Xxm63a+bMmVq3bp3X+lteTz31lKZOnVrivuL3daE/mzdvvsg9liZNmqTExMSL/nkBM/Ct7A4AQFm1adNG//73v9W8eXOPjk9PT9frr7+up59+uoJ7VrrNmzdrwoQJFzzmscceU5s2bUrc16xZs4roFgA3CEoALjk1a9ZUTExMZXejzI4cOaLffvtN8fHxFzyuefPml+T7A6oipt4AuPj666915513qlOnTuratavGjRun48ePO/c7HA7NmzdPiYmJatu2rRITEzVnzhzl5+c7j/nggw/Ur18/tW/fXnFxcRo/frzS0tK81sc/Tr3l5ubqiSeeUI8ePdS2bVvdeOONWrJkiSTp119/1bXXXitJmjx5sssUUmnvde3atWrdurXeeustdevWTV26dNEbb7yhFi1a6NChQy59eu+999SqVSuX8/9o06ZN6tixo2rWrPmna7B27Vq1aNFCu3btUlJSktq3b69bbrlF69evdzkuOztbTz/9tK677jq1a9dOffv21dtvv+1yjGEYWrZsmW666Sa1b99e119/vZYsWXLemq61a9fqhhtuULt27dSvXz9t2rTpT78PwOwISgCc3n33Xd1zzz2qX7++5s6dq8mTJ+u7777T7bffrpMnT0qSXn31Vf3rX//SyJEjtXTpUg0aNEhLlizRyy+/LEnauXOnJk6cqN69e+vVV1/V5MmTtXXrVo0bN67Uz+9wOFRQUHDeH4fDccHzZs6cqc2bN+uRRx7RkiVLdO2112rWrFlas2aN6tWrpwULFkiSHnjgAefHnrxXSSosLNTSpUs1Y8YMTZ48WX379lVAQIDee++982oXHx+v+vXru+3npk2b1LNnz3LXobCw8LxjR4wYoWuvvVYLFixQ06ZN9Y9//MMZYHJzc3XnnXdq3bp1Gj58uF566SV16tRJU6ZM0cKFC51tzJo1S7NmzVJiYqIWLlyogQMHavbs2Vq0aJHzmOPHj2vRokV6+OGHNX/+fFksFo0ePdqlVkBVxNQbAElFv5xnz56t7t27a86cOc7tHTt21M0336wlS5Zo4sSJ2r59u9q2basBAwZIkrp06aKgoCCFhIRIKgpKgYGBuv/+++Xv7y9Jql27tn744QcZhiGLxeK2Dy+99JJeeumlMvd9+/bt6tatm/r06SNJ6tq1q4KDgxURESF/f3+1atVKktS4cWO1bt3a4/da7O9//7t69erlfH399dfr/fff18MPPyyLxaLU1FRt3bpVzz77rNs+5ubmKjk5WZMnTy71/dx9990lbr/yyiv1wQcfuGwbOnSoRo4cKUlKSEhQUlKSXnzxRfXs2VNr167Vvn37tHr1anXo0MF5TEFBgV566SXdcccdslqtWr58uYYMGeJcO3X11VfrxIkTSk5O1ogRIyQVfX+8+OKLzjVSAQEBuvvuu/X99987R+yAqoigBECSdOjQIZ04ceK8kZ/GjRurQ4cO2r59u6SiEDJnzhzdeeedSkxMVK9evTRkyBDn8bGxsZo3b5769u2rG264QT179lT37t09Gkn561//qr/+9a/nbf/pp5/0+OOPuz2va9euWr16tVJTU9WzZ0/17NnTGR7+zHstVhy0ig0cOFAffPCBduzYodjYWL377ruqUaOGrr/+erefc+vWrapTp45HC9CffPLJEhdzBwYGnrctKSnJ+bHFYtH111+v+fPnKzc3V9u3b1fDhg2dIalYv3799Pbbb2vXrl2yWCwqKChQ7969XY7545V5YWFhLgvJGzVqJKloag+oyph6AyBJOnXqlCSpTp065+2rU6eO8xfi8OHD9dhjjyk3N1ezZ89Wnz591LdvX23dulWS1KFDBy1atEiXXXaZXnvtNQ0ePFg9evTQihUrSu1DvXr11K5du/P+NG3a9ILnTZkyRf/4xz/066+/avr06bruuut0xx13aO/evX/q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LKxGuc8viX9A0ZcjMMDX621XVaGhQZXdhUsK9fIctfIctfIctfKcWWplmqDUvHlzSdKMGTO0a9curVy5UoGBgc5F2cWKw01wcLACAwMlSXa73flx8TFBQUUFLq2N8nI4DNls58p9fkny7QWSpNy8fGVlnfVq21WNj49VoaFBstlyVFjoqOzumB718hy18hy18hy18lxF1io0NKjMI1WVGpQyMzO1ZcsW3XDDDc41RFarVc2bN1d6erqioqKUnp7uck7x68jISBUUFDi3NW7c2OWYFi1aSFKpbfwZBQXe/QIWP+LN4TC83nZVVVjooFZlQL08R608R608R608Z5ZaVeoEYEZGhsaOHastW7Y4t+Xn52v37t1q1qyZYmNjtXPnThUWFjr3b926VU2bNlVERIRatmypmjVratu2bc79NptNu3fvVmxsrCSV2gYAAIA7lRqUoqOj1aNHDz311FNKTk7Wvn37NGnSJNlsNt19990aMGCAzpw5oylTpujAgQNau3atli1bphEjRkgqWps0ZMgQzZ49W59//rn27t2rMWPGKCoqSr1795akUtsAAABwp9LXKM2dO1dz5szRmDFjlJ2drc6dO+uNN95QgwYNJEmLFy/WjBkzlJSUpLp162rixIlKSkpynj969GgVFBRo6tSpys3NVWxsrJYsWSI/Pz9JUkRERKltmIWFGykBAGAqFsMwuA90ORQWOpSZ6d0F16s27NOGHb/qtoSm6tetqVfbrmp8fa0KC6uhrKyzppjDNjvq5Tlq5Tlq5Tlq5bmKrFV4eI0yL+Y2x00K4ILoCgCAORCUAAAA3CAoAQAAuEFQMiFm3gAAMAeCkolYuOwNAABTISiZEau5AQAwBYISAACAGwQlE2HiDQAAcyEomRATbwAAmANByUwYUgIAwFTK9ay3zMxMLVmyRN98841OnDihxYsXa8OGDWrZsqWuu+46b/cRAACgUpR5RCklJUX9+vXTm2++qcjISJ08eVKFhYU6dOiQRo8erY0bN1ZAN6sZ5t4AADCFMo8o/fOf/1RERIRWrFih4OBgtW3bVpI0Z84c5eXlaeHCherVq5e3+1ktMPMGAIC5lHlEacuWLXrwwQcVGhp63g0Sb7/9du3fv99rnQMAAKhM5VrM7etb8kCU3W7n7tJewMwbAADmUOag1LlzZ73yyis6d+6cc5vFYpHD4dC/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kQAAQHXkUVB6+umnK7ofUPE1b8y8AQBgFl5ZzP3HO3QDAABUBR4HpZSUFE2fPl2ff/65c9uGDRvUvXt3devWTQkJCfroo48qpJPVBmvjAQAwFY+m3lJSUvSXv/xFeXl5at26tSTp0KFD+sc//qHw8HBNmjRJv/zyi8aPH6969eqpc+fOFdrpqo6pNwAAzMGjoLRw4UKFh4fr9ddfV926dSUVPRS3sLBQs2fPVpcuXSQVXfX26quvEpQAAECV4NHU2zfffKN7773XGZIkafPmzapXr54zJElS7969tWvXLu/3spqwFM+98Rw9AABMwaOglJGRocaNGztfp6SkKDU1VV27dnU5LiQkRGfPnvVuDwEAACqJR0GpRo0astlsztfbt2+XxWJRXFycy3EpKSmqXbu2VzsIAABQWTwKSjExMS5XtL333nvy8fFRz549ndsMw9Cbb76p9u3be7+X1UTxI0yYeAMAwBw8Wsx933336a677lJqaqocDoe+++473X777YqIiJAkbdmyRa+//rq+//57vfbaaxXaYQAAgIvFoxGlTp066dVXX5Wfn5+ys7M1fPhwTZ061bl//Pjx2rZtm5544onzpuMAAAAuVR4/FDc+Pl7x8fEl7nv55ZfVpEkThYaGeq1j1RpzbwAAmILHQelCWJcEAACqIo+C0uTJkz1u0GKxaObMmeXuEAAAgFl4FJTeeecdWSwWRUZGymq98LImi4UHlpVXce0M5t4AADAFj4LSTTfdpI0bN8put+vGG29Unz591KlTp4ruGwAAQKXyKCjNmzdPOTk5+vLLL/XRRx9p2LBhqlOnjm6++Wb16dNHrVq1quh+VguMxQEAYC4eL+YOCgrSzTffrJtvvllnzpzRZ599po8++kjLli1To0aN1LdvX/Xp00dNmzatyP5WCzzqDQAAcyjXVW81a9ZUUlKSkpKSdOrUKX322Wf6+OOPtXDhQkVHR2vt2rXe7icAAMBF59ENJy8kLy9POTk5ys3NVWFhoY4dO+aNfgEAAFS6co0opaWlaf369Vq/fr127dql4OBgXXfddRoxYoS6devm7T4CAABUCo+D0u/D0ffff6+goCBdc801Gj58uBISEuTv71+R/QQAALjoPApKgwYN0q5duxQQEKCePXvq+eefV8+ePRUQEFDR/atWim9BxWJuAADMwaOg9N1338nHx0fN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",
|
4830 |
+
"text/plain": [
|
4831 |
+
"<Figure size 640x480 with 1 Axes>"
|
4832 |
+
]
|
4833 |
+
},
|
4834 |
+
"metadata": {},
|
4835 |
+
"output_type": "display_data"
|
4836 |
+
}
|
4837 |
+
],
|
4838 |
+
"source": [
|
4839 |
+
"# visualize the loss history over epoch\n",
|
4840 |
+
"sns.lineplot(\n",
|
4841 |
+
" x=[num for num in range(len(loss_history))],\n",
|
4842 |
+
" y=loss_history,\n",
|
4843 |
+
")\n",
|
4844 |
"\n",
|
4845 |
+
"plt.title(\"Loss History / Epoch\")\n",
|
4846 |
+
"plt.ylabel(\"MSE Loss Value\")\n",
|
4847 |
+
"plt.xlabel(\"Epoch\")\n",
|
4848 |
+
"plt.show()"
|
4849 |
]
|
4850 |
},
|
4851 |
{
|
4852 |
"cell_type": "code",
|
4853 |
+
"execution_count": 15,
|
4854 |
+
"id": "e2d25270",
|
4855 |
"metadata": {},
|
4856 |
"outputs": [],
|
4857 |
"source": [
|
4858 |
+
"\n",
|
4859 |
+
"def pred_vs_actual_plot(pred: torch.Tensor, actual: torch.Tensor, target_names: list[str]):\n",
|
4860 |
+
" fig, axs = plt.subplots(2, len(pred[0]) // 2)\n",
|
4861 |
+
" axs = axs.flatten()\n",
|
4862 |
+
"\n",
|
4863 |
+
" for i in range(len(pred[0])):\n",
|
4864 |
+
" ax = axs[i]\n",
|
4865 |
+
" ax.scatter(actual[:, i], pred[:, i], alpha=0.5)\n",
|
4866 |
+
" ax.plot(ax.get_xlim(), ax.get_ylim(), color=\"red\", alpha=0.7, ls=\"--\")\n",
|
4867 |
+
"\n",
|
4868 |
+
" ax.set_title(f\"{target_names[i]}\")\n",
|
4869 |
+
" ax.set_xlabel(f\"Actual\")\n",
|
4870 |
+
" ax.set_ylabel(f\"Predicted\")\n",
|
4871 |
+
"\n",
|
4872 |
+
" plt.tight_layout()\n",
|
4873 |
+
" plt.show()\n"
|
4874 |
]
|
4875 |
},
|
4876 |
{
|
4877 |
"cell_type": "code",
|
4878 |
+
"execution_count": 16,
|
4879 |
+
"id": "734b90ee",
|
4880 |
"metadata": {},
|
4881 |
"outputs": [
|
4882 |
{
|
4883 |
"name": "stdout",
|
4884 |
"output_type": "stream",
|
4885 |
"text": [
|
4886 |
+
"MSELoss() = 439.0569763183594\n"
|
|
|
4887 |
]
|
4888 |
},
|
4889 |
{
|
|
|
4898 |
}
|
4899 |
],
|
4900 |
"source": [
|
4901 |
+
"# evaluate the seed 3 model\n",
|
4902 |
"scoreModel300k.eval()\n",
|
4903 |
"\n",
|
4904 |
+
"loss_fn = nn.MSELoss()\n",
|
4905 |
"with torch.no_grad():\n",
|
4906 |
" pred = scoreModel300k(X_testT)\n",
|
4907 |
" loss = loss_fn(pred, y_testT)\n",
|
4908 |
+
" print(f\"{loss_fn} = {loss}\")\n",
|
4909 |
+
" pred_vs_actual_plot(pred, y_testT, target_df.columns)"
|
4910 |
+
]
|
4911 |
+
},
|
4912 |
+
{
|
4913 |
+
"cell_type": "code",
|
4914 |
+
"execution_count": 17,
|
4915 |
+
"id": "48578a20",
|
4916 |
+
"metadata": {},
|
4917 |
+
"outputs": [],
|
4918 |
+
"source": [
|
4919 |
+
"torch.save(\n",
|
4920 |
+
" scoreModel300k,\n",
|
4921 |
+
" os.path.join(MODEL_DIR, \"scoreDist30k.pth\"),\n",
|
4922 |
+
")"
|
4923 |
]
|
4924 |
}
|
4925 |
],
|