aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlek Westover2024-10-03 16:23:15 -0400
committerAlek Westover2024-10-03 16:23:15 -0400
commit5623067473c7a3a69e7a9c180b8a76472986867c (patch)
treef2068803ba77b6638d0825359a64e50351c0cc24
parent15e149cb6d785788ca54ad91892f721e0f9b064b (diff)
fixed some bugs
-rw-r--r--transformer_shortest_paths.ipynb202
1 files changed, 126 insertions, 76 deletions
diff --git a/transformer_shortest_paths.ipynb b/transformer_shortest_paths.ipynb
index d52d156..171fbec 100644
--- a/transformer_shortest_paths.ipynb
+++ b/transformer_shortest_paths.ipynb
@@ -4,7 +4,11 @@
"metadata": {
"colab": {
"provenance": [],
- "gpuType": "T4"
+ "gpuType": "T4",
+ "collapsed_sections": [
+ "LPphBnKR-aWF",
+ "gKt-yIpDebF1"
+ ]
},
"kernelspec": {
"name": "python3",
@@ -17,6 +21,15 @@
},
"cells": [
{
+ "cell_type": "markdown",
+ "source": [
+ "# Step 0: Imports"
+ ],
+ "metadata": {
+ "id": "LPphBnKR-aWF"
+ }
+ },
+ {
"cell_type": "code",
"source": [
"# imports\n",
@@ -41,9 +54,9 @@
"base_uri": "https://localhost:8080/"
},
"id": "ge5QvElvhCOw",
- "outputId": "38b82493-509e-40d0-8b62-13484cec0cba"
+ "outputId": "8d2f46b5-22c3-42a7-ecef-ce014d7ec2c9"
},
- "execution_count": null,
+ "execution_count": 97,
"outputs": [
{
"output_type": "stream",
@@ -65,62 +78,74 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 98,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1IbzGIWseK3E",
- "outputId": "86cb72b8-8932-4cbe-ad3a-217206e3c66c"
+ "outputId": "835a0467-e1d3-414b-99cb-b8a1b368dd86"
},
"outputs": [
{
"output_type": "stream",
"name": "stderr",
"text": [
- "100%|██████████| 54/54 [00:00<00:00, 102.56it/s]\n"
+ "100%|██████████| 55/55 [00:00<00:00, 100.02it/s]\n"
]
}
],
"source": [
- "MAX_VTXS = 62\n",
- "FAKE_VTX = 63 # padding token\n",
+ "PAD_TOKEN = 0\n",
+ "MAX_VTXS = 63\n",
+ "# vertices are labelled 1,2,...,63\n",
+ "# we also have a padding token which is 0.\n",
+ "\n",
"INF = MAX_VTXS # represents unreachability\n",
"SEQ_LEN = 128\n",
+ "\n",
+ "# original task data\n",
"NTRAIN1 = 10000\n",
- "NTRAIN2 = 2000\n",
+ "# the data will be edge lists\n",
+ "# like this: [1 3 1 5 2 4 0 0 0 0]\n",
+ "# this represents edges (1,3), (1,5) (2,4)\n",
+ "# (the zeros are just padding tokens)\n",
"\n",
- "# weirder way of representing a graph\n",
- "# have it just be a list of vertex/parity pairs\n",
+ "# the label is the shortest distance from vtx 1 to vtx 2\n",
+ "# or \"INF\" if no path exists\n",
+ "\n",
+ "# fine tuning data\n",
+ "NTRAIN2 = 2000\n",
+ "# I haven't totally figured out how to do the fine tuning yet.\n",
+ "# So don't worry about this yet.\n",
"\n",
"def random_graph(n):\n",
- " assert n >= 8\n",
+ " assert n >= 4\n",
" edge_list = []\n",
- " adjacencies = [set() for _ in range(n)]\n",
+ " adjacencies = [set() for _ in range(n+1)]\n",
"\n",
- " indices = np.random.randint(n, size=(2*n))\n",
+ " indices = np.random.randint(n, size=(2*n))+1\n",
" for i in range(0, len(indices), 2):\n",
" u = indices[i]\n",
" v = indices[i + 1]\n",
" if u != v:\n",
- " edge_list.append(u)\n",
- " edge_list.append(v)\n",
+ " edge_list += [u,v]\n",
" adjacencies[u].add(v)\n",
" adjacencies[v].add(u)\n",
"\n",
- " edge_list += [FAKE_VTX]*(SEQ_LEN-len(edge_list))\n",
+ " edge_list += [PAD_TOKEN]*(SEQ_LEN-len(edge_list))\n",
" return edge_list, adjacencies\n",
"\n",
"\"\"\"\n",
"input: G, represented as an adjacency list\n",
- "output: [d(0,i) for i in range(n)] if target=None\n",
+ "output: [INF]+[d(1,i) for i in range(n)] if target=None\n",
"if target is set to some value, then we instead just output that specific distance\n",
"\"\"\"\n",
- "def SSSP(G,target=None):\n",
+ "def SSSP(G, target=None):\n",
" dist = [INF for _ in G]\n",
- " dist[0] = 0\n",
+ " dist[1] = 0\n",
" frontier = deque()\n",
- " frontier.append(0)\n",
+ " frontier.append(1)\n",
" while len(frontier) > 0:\n",
" vtx = frontier.popleft()\n",
" for x in G[vtx]:\n",
@@ -143,7 +168,7 @@
"for n in tqdm(range(8, MAX_VTXS)):\n",
" for _ in range(NTRAIN1//MAX_VTXS):\n",
" edge_list, adj_list = random_graph(n)\n",
- " dist = SSSP(adj_list, target=1)\n",
+ " dist = SSSP(adj_list, target=2)\n",
"\n",
" graphs1.append(edge_list)\n",
" distance1.append(dist)\n",
@@ -194,7 +219,7 @@
" self.seq_len = seq_len\n",
" self.device = device\n",
"\n",
- " encoder_layers = nn.TransformerEncoderLayer(d_model=model_dim, nhead=num_heads, dropout=dropout)\n",
+ " encoder_layers = nn.TransformerEncoderLayer(d_model=model_dim, nhead=num_heads, dropout=dropout, batch_first=True)\n",
" self.transformer_encoder = nn.TransformerEncoder(encoder_layers, num_layers)\n",
" self.fc_out = nn.Linear(model_dim*seq_len, output_dim)\n",
"\n",
@@ -203,26 +228,33 @@
" pos_encoding = pos_encoding.float().unsqueeze(0).repeat(batch_size, 1, 1)\n",
" return pos_encoding\n",
"\n",
- " def forward(self, src, src_mask=None):\n",
+ " def forward(self, src, key_padding_mask):\n",
" batch_size, src_len = src.size(0), src.size(1)\n",
" src_pos = self.positional_encoding(batch_size)\n",
" embed = self.embedding(src)\n",
- "\n",
" src = embed * sqrt(self.model_dim) + src_pos\n",
- " output = self.transformer_encoder(src, src_mask)\n",
"\n",
+ " output = self.transformer_encoder(src, None, src_key_padding_mask=key_padding_mask)\n",
" flat_output = torch.flatten(output, start_dim=1, end_dim=2)\n",
" output = self.fc_out(flat_output)\n",
- "\n",
" return output\n"
],
"metadata": {
"id": "tLOWhg_CeWzH"
},
- "execution_count": 26,
+ "execution_count": 99,
"outputs": []
},
{
+ "cell_type": "markdown",
+ "source": [
+ "# Step 3: Load Data"
+ ],
+ "metadata": {
+ "id": "bpIeg86S-hBb"
+ }
+ },
+ {
"cell_type": "code",
"source": [
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
@@ -235,7 +267,13 @@
"batch_size = 32\n",
"learning_rate = 0.001\n",
"max_seq_len = 128\n",
- "model = TransformerModel(input_dim=VOCAB_SIZE, model_dim=model_dim, output_dim=VOCAB_SIZE, num_heads=8, num_layers=6, seq_len=max_seq_len, device=device).to(device)\n",
+ "num_heads = 8\n",
+ "num_layers = 6\n",
+ "PAD_TOKEN = 0\n",
+ "model = TransformerModel(input_dim=VOCAB_SIZE, model_dim=model_dim,\n",
+ " output_dim=VOCAB_SIZE, num_heads=num_heads,\n",
+ " num_layers=num_layers, seq_len=max_seq_len,\n",
+ " device=device).to(device)\n",
"\n",
"with open(\"data.pkl\", \"rb\") as f:\n",
" data = pickle.load(f)\n",
@@ -244,40 +282,38 @@
"train_label1 = data[\"train1-labels\"]\n",
"train_data_tensor = torch.tensor(train_data1, dtype=torch.long, device=device)\n",
"train_label_tensor = torch.tensor(train_label1, dtype=torch.long, device=device)\n",
- "train_dataset = TensorDataset(train_data_tensor, train_label_tensor)\n",
+ "train_padding_mask = (train_data_tensor != PAD_TOKEN).bool().to(device)\n",
+ "train_dataset = TensorDataset(train_data_tensor, train_label_tensor, train_padding_mask)\n",
"train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n",
"\n",
"test_data1 = data[\"test1-data\"]\n",
"test_label1 = data[\"test1-labels\"]\n",
"test_data_tensor = torch.tensor(test_data1, dtype=torch.long, device=device)\n",
"test_label_tensor = torch.tensor(test_label1, dtype=torch.long, device=device)\n",
- "test_dataset = TensorDataset(test_data_tensor, test_label_tensor)\n",
+ "test_padding_mask = (test_data_tensor != PAD_TOKEN).bool().to(device)\n",
+ "test_dataset = TensorDataset(test_data_tensor, test_label_tensor, test_padding_mask)\n",
"test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True)\n",
"\n",
"criterion = nn.CrossEntropyLoss()\n",
"optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)\n",
"\n",
- "train_losses = []\n",
+ "train_accuracy = []\n",
"test_accuracy = []"
],
"metadata": {
- "colab": {
- "base_uri": "https://localhost:8080/"
- },
- "id": "kWXvJRDYgFVP",
- "outputId": "4f09bb27-679e-42ff-9f5d-f2edff3dbe72"
+ "id": "kWXvJRDYgFVP"
},
- "execution_count": 27,
- "outputs": [
- {
- "output_type": "stream",
- "name": "stderr",
- "text": [
- "/usr/local/lib/python3.10/dist-packages/torch/nn/modules/transformer.py:307: UserWarning: enable_nested_tensor is True, but self.use_nested_tensor is False because encoder_layer.self_attn.batch_first was not True(use batch_first for better inference performance)\n",
- " warnings.warn(f\"enable_nested_tensor is True, but self.use_nested_tensor is False because {why_not_sparsity_fast_path}\")\n"
- ]
- }
- ]
+ "execution_count": 100,
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "# Step 4: Train the Model for the first task"
+ ],
+ "metadata": {
+ "id": "f8Zn33m7CxL5"
+ }
},
{
"cell_type": "code",
@@ -285,14 +321,21 @@
"for epoch in range(num_epochs):\n",
" model.train() # set to training mode\n",
" epoch_loss = 0\n",
- " for batch_src, batch_labels in train_loader:\n",
+ " correct_train = 0\n",
+ " total_train = 0\n",
+ "\n",
+ " for batch_src, batch_labels, batch_padding_mask in train_loader:\n",
" optimizer.zero_grad()\n",
- " output = model(batch_src)\n",
+ " output = model(batch_src, batch_padding_mask)\n",
+ "\n",
+ " _, predicted = torch.max(output, 1)\n",
+ " correct_train += (predicted == batch_labels).sum().item()\n",
+ " total_train += batch_labels.size(0)\n",
+ "\n",
" loss = criterion(output, batch_labels)\n",
" epoch_loss += loss.item()\n",
" loss.backward()\n",
" optimizer.step()\n",
- " train_losses.append(epoch_loss)\n",
"\n",
" # Evaluate performance\n",
" model.eval()\n",
@@ -300,56 +343,63 @@
" total_test = 0\n",
"\n",
" with torch.no_grad():\n",
- " for batch_src, batch_labels in test_loader:\n",
- " output = model(batch_src)\n",
+ " for batch_src, batch_labels, batch_padding_mask in test_loader:\n",
+ " output = model(batch_src, batch_padding_mask)\n",
"\n",
" _, predicted = torch.max(output, 1)\n",
" correct_test += (predicted == batch_labels).sum().item()\n",
" total_test += batch_labels.size(0)\n",
"\n",
" epoch_test_acc = correct_test / total_test\n",
+ " epoch_train_acc = correct_train / total_train\n",
" test_accuracy.append(epoch_test_acc)\n",
- " print(f\"Epoch {epoch + 1}/{num_epochs} \\t Train Loss: {epoch_loss:.4f} \\t Test Accuracy: {epoch_test_acc:.4f}\")\n",
- "\n",
+ " train_accuracy.append(epoch_train_acc)\n",
+ " print(f\"Epoch {epoch + 1}/{num_epochs} \\t Train Accuracy: {epoch_train_acc:.4f} \\t Test Accuracy: {epoch_test_acc:.4f}\")\n",
"\n",
"plt.figure(figsize=(10, 5))\n",
- "plt.plot(test_accuracy, label='Test Loss', color='red')\n",
- "plt.title('Test Accuracy vs Epochs')\n",
- "plt.xlabel('Epochs'); plt.ylabel('Loss')\n",
+ "plt.plot(test_accuracy, label='Test', color='red')\n",
+ "plt.plot(train_accuracy, label='Train', color='red')\n",
+ "plt.title('Accuracy vs Epochs')\n",
+ "plt.xlabel('Epochs'); plt.ylabel('Accuracy')\n",
"plt.legend(); plt.grid()\n",
"plt.show()"
],
"metadata": {
"colab": {
- "base_uri": "https://localhost:8080/",
- "height": 559
+ "base_uri": "https://localhost:8080/"
},
"id": "pvTfzGmCeXU4",
- "outputId": "26b5e8da-1af0-44cd-c98c-25cc65d56cb9"
+ "outputId": "5231507f-7a52-4eb7-893a-c49ca93b8baf"
},
- "execution_count": 28,
+ "execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
- "Epoch 1/4 \t Train Loss: 3217.9719 \t Test Accuracy: 0.3776\n",
- "Epoch 2/4 \t Train Loss: 669.2610 \t Test Accuracy: 0.3776\n",
- "Epoch 3/4 \t Train Loss: 581.0590 \t Test Accuracy: 0.3776\n",
- "Epoch 4/4 \t Train Loss: 511.1334 \t Test Accuracy: 0.3776\n"
+ "Epoch 1/4 \t Train Accuracy: 0.2067 \t Test Accuracy: 0.3838\n",
+ "Epoch 2/4 \t Train Accuracy: 0.2457 \t Test Accuracy: 0.3838\n"
]
- },
- {
- "output_type": "display_data",
- "data": {
- "text/plain": [
- "<Figure size 1000x500 with 1 Axes>"
- ],
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAA18AAAHWCAYAAACIZjNQAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABWtUlEQVR4nO3dfVxUdd7/8TeD3CpIiHIn3qGJlkpBkmWKCWK1mTcVlbsSmtYqac7vqo1186boIttN3TaVttJab9I0KytTEdMycd1Uslwjsxt1FdQ1JSAHYs7vDy9mdwIUEc/g+Ho+HvN4ON/5nnM+Zz7Nxb6vc+Y7HoZhGAIAAAAAXFQWVxcAAAAAAJcDwhcAAAAAmIDwBQAAAAAmIHwBAAAAgAkIXwAAAABgAsIXAAAAAJiA8AUAAAAAJiB8AQAAAIAJCF8AAAAAYALCFwAAaBI2bdokDw8PrVy50tWlAMBFQfgCgEuIh4dHvR6bNm264GOVl5dr+vTpDdrXmjVr5OHhoYiICNnt9guuBY2jOtzU9Vi2bJmrSwQAt9bM1QUAAOpv0aJFTs//9re/KTc3t8Z4t27dLvhY5eXlmjFjhiQpMTHxvLZdsmSJOnTooO+++04bN25UUlLSBdeDxjNx4kRdd911Ncb79OnjgmoA4PJB+AKAS8ivf/1rp+fbtm1Tbm5ujXFXKisr0zvvvKPs7GwtXLhQS5YsabLhq6ysTM2bN3d1Gaa76aabdOedd7q6DAC47HDbIQC4Gbvdrjlz5uiqq66Sr6+vQkND9eCDD+qHH35wmvfpp58qJSVFISEh8vPzU8eOHTV69GhJ0nfffafWrVtLkmbMmOG4LW369OnnPP5bb72ln376SXfddZfuuecerVq1SqdPn64x7/Tp05o+fbquvPJK+fr6Kjw8XMOHD9f+/fudzuXPf/6zevToIV9fX7Vu3VqDBw/Wp59+6qjTw8NDr776ao39/7Le6dOny8PDQ//85z9133336YorrlDfvn0lSbt379b999+vTp06ydfXV2FhYRo9erT+/e9/19jvv/71L40ZM0YRERHy8fFRx44d9dvf/lYVFRX65ptv5OHhodmzZ9fYbuvWrfLw8NDrr79e6/tWXFysZs2aOa42/rfCwkJ5eHjohRdekCRVVlZqxowZ6tKli3x9fdWqVSv17dtXubm5te67ITw8PJSRkaElS5aoa9eu8vX1VVxcnD766KMac3ft2qVbbrlFgYGBatGihQYOHKht27bVmHfy5ElNnjxZHTp0kI+Pj9q2batRo0bp+PHjTvPsdruefvpptW3bVr6+vho4cKC+/vprpzn79u3TiBEjFBYWJl9fX7Vt21b33HOPTp061WjvAQA0Nq58AYCbefDBB/Xqq68qPT1dEydO1LfffqsXXnhBu3bt0ieffCIvLy8dPXpUgwYNUuvWrfX4448rKChI3333nVatWiVJat26tebPn6/f/va3GjZsmIYPHy5J6tmz5zmPv2TJEg0YMEBhYWG655579Pjjj+vdd9/VXXfd5ZhTVVWlX/3qV8rLy9M999yjSZMm6ccff1Rubq6++OILRUdHS5LGjBmjV199VbfccoseeOAB/fzzz/r444+1bds2xcfHN+j9ueuuu9SlSxf97//+rwzDkCTl5ubqm2++UXp6usLCwrRnzx799a9/1Z49e7Rt2zZ5eHhIkg4fPqzevXvr5MmTGjdunGJiYvSvf/1LK1euVHl5uTp16qQbb7xRS5Ys0eTJk2u8LwEBAbrjjjtqrSs0NFT9+/fXG2+8oWnTpjm9tnz5cnl6ejrew+nTpys7O1sPPPCAevfurZKSEn366afauXOnkpOTz/ke/PjjjzUCjyS1atXKca6StHnzZi1fvlwTJ06Uj4+P5s2bp8GDB2v79u26+uqrJUl79uzRTTfdpMDAQD322GPy8vLSiy++qMTERG3evFkJCQmSpNLSUt10003au3evRo8erWuvvVbHjx/X6tWrdejQIYWEhDiO+8wzz8hiseh//ud/dOrUKT377LMaOXKk/v73v0uSKioqlJKSIpvNpocfflhhYWH617/+pffee08nT55Uy5Ytz/keAIBLGACAS9aECROM//4/5R9//LEhyViyZInTvLVr1zqNv/XWW4Yk4x//+Eed+z527JghyZg2bVq96ykuLjaaNWtmvPTSS46xG264wbjjjjuc5i1YsMCQZMyaNavGPux2u2EYhrFx40ZDkjFx4sQ653z77beGJGPhwoU15vyy9mnTphmSjHvvvbfG3PLy8hpjr7/+uiHJ+Oijjxxjo0aNMiwWS63vW3VNL774oiHJ2Lt3r+O1iooKIyQkxEhLS6ux3X+r3vbzzz93Gu/evbtx8803O5736tXLuO222866r9p8+OGHhqQ6H0eOHHHMrR779NNPHWPff/+94evrawwbNswxNnToUMPb29vYv3+/Y+zw4cNGQECA0a9fP8fY1KlTDUnGqlWratRV/d5V19etWzfDZrM5Xv/zn//s9L7s2rXLkGSsWLHivN8DAHAlbjsEADeyYsUKtWzZUsnJyTp+/LjjERcXpxYtWujDDz+UJAUFBUmS3nvvPVVWVjba8ZctWyaLxaIRI0Y4xu6991598MEHTrc9vvnmmwoJCdHDDz9cYx/VV17efPNNeXh41LgK9N9zGuKhhx6qMebn5+f49+nTp3X8+HFdf/31kqSdO3dKOnMr3Ntvv63bb7+91qtu1TXdfffd8vX11ZIlSxyvrVu3TsePHz/nd/OGDx+uZs2aafny5Y6xL774Qv/85z+VmprqGAsKCtKePXu0b9+++pxyDVOnTlVubm6NR3BwsNO8Pn36KC4uzvG8Xbt2uuOOO7Ru3TpVVVWpqqpK69ev19ChQ9WpUyfHvPDwcN13333asmWLSkpKJJ3pZ69evTRs2LAa9fyyn+np6fL29nY8v+mmmyRJ33zzjSQ5rmytW7dO5eXlDXoPAMAVCF8A4Eb27dunU6dOqU2bNmrdurXTo7S0VEePHpUk9e/fXyNGjNCMGTMUEhKiO+64QwsXLpTNZrug4y9evFi9e/fWv//9b3399df6+uuvdc0116iiokIrVqxwzNu/f7+6du2qZs3qvvt9//79ioiIqBEILlTHjh1rjJ04cUKTJk1SaGio/Pz81Lp1a8e86u8QHTt2TCUlJY7b7eoSFBSk22+/XUuXLnWMLVmyRJGRkbr55pvPum1ISIgGDhyoN954wzG2fPlyNWvWzHHrpyQ9+eSTOnnypK688kr16NFDjz76qHbv3n3uk/8/PXr0UFJSUo3HfwceSerSpUuNba+88kqVl5fr2LFjOnbsmMrLy9W1a9ca87p16ya73a6DBw9KOtPPc7131dq1a+f0/IorrpAkR4Dv2LGjrFarXn75ZYWEhCglJUVz587l+14AmjzCFwC4EbvdrjZt2tR6VSM3N1dPPvmkJDl+yDY/P18ZGRn617/+pdGjRysuLk6lpaUNOva+ffv0j3/8Q1u2bFGXLl0cj+pFLf77SlBjqesKWFVVVZ3b/PdVrmp33323XnrpJT300ENatWqV1q9fr7Vr10pSg36nbNSoUfrmm2+0detW/fjjj1q9erXuvfdeWSzn/rN7zz336KuvvlJBQYEk6Y033tDAgQOdvhPVr18/7d+/XwsWLNDVV1+tl19+Wddee61efvnl8661KfL09Kx13Pi/7+hJ0nPPPafdu3fr97//vX766SdNnDhRV111lQ4dOmRWmQBw3lhwAwDcSHR0tDZs2KAbb7yx1pDxS9dff72uv/56Pf3001q6dKlGjhypZcuW6YEHHjjvW/uWLFkiLy8vLVq0qMb/eN6yZYuef/55HThwQO3atVN0dLT+/ve/q7KyUl5eXnWey7p163TixIk6r35VXxE5efKk0/j3339f77p/+OEH5eXlacaMGZo6dapj/Je39LVu3VqBgYH64osvzrnPwYMHq3Xr1lqyZIkSEhJUXl6u3/zmN/WqZ+jQoXrwwQcdtx5+9dVXyszMrDEvODhY6enpSk9PV2lpqfr166fp06frgQceqNdx6qO22xq/+uor+fv7O1bD9Pf3V2FhYY15X375pSwWi6KioiSd6Wd93rvz0aNHD/Xo0UN/+MMftHXrVt14443KyclRVlZWox4HABoLV74AwI3cfffdqqqq0lNPPVXjtZ9//tkRUn744QenqwiSFBsbK0mOWw/9/f0l1Qw2dVmyZIluuukmpaam6s4773R6PProo5LkWGZ9xIgROn78uGPp9P9WXdeIESNkGEatS69XzwkMDFRISEiN5c/nzZtXr5ql/1xl+eX7MWfOHKfnFotFQ4cO1bvvvutY6r62miSpWbNmuvfee/XGG2/o1VdfVY8ePeq1UqR05rbFlJQUvfHGG1q2bJm8vb01dOhQpzm/XAK/RYsW6ty58wXfNvpL+fn5ju+8SdLBgwf1zjvvaNCgQfL09JSnp6cGDRqkd955R999951jXnFxsZYuXaq+ffsqMDBQ0pl+fvbZZ3rrrbdqHOeX7/25lJSU6Oeff3Ya69GjhywWS6O/BwDQmLjyBQBupH///nrwwQeVnZ2tgoICDRo0SF5eXtq3b59WrFihP//5z7rzzjv12muvad68eRo2bJiio6P1448/6qWXXlJgYKBuvfVWSWduz+vevbuWL1+uK6+8UsHBwbr66qtr/d7O3//+d3399dfKyMiota7IyEhde+21WrJkiX73u99p1KhR+tvf/iar1art27frpptuUllZmTZs2KDx48frjjvu0IABA/Sb3/xGzz//vPbt26fBgwfLbrfr448/1oABAxzHeuCBB/TMM8/ogQceUHx8vD766CN99dVX9X7PAgMD1a9fPz377LOqrKxUZGSk1q9fr2+//bbG3P/93//V+vXr1b9/f40bN07dunXTkSNHtGLFCm3ZssWxkIl05tbD559/Xh9++KFmzpxZ73okKTU1Vb/+9a81b948paSkOO1Xkrp3767ExETFxcUpODhYn376qVauXFnn+/9LH3/8ca2/vdazZ0+nkHj11VcrJSXFaal5SU6BOCsrS7m5uerbt6/Gjx+vZs2a6cUXX5TNZtOzzz7rmPfoo49q5cqVuuuuuxy3uJ44cUKrV69WTk6OevXqVe/3Z+PGjcrIyNBdd92lK6+8Uj///LPjiut/L/YCAE2O6xZaBABcqF8uNV/tr3/9qxEXF2f4+fkZAQEBRo8ePYzHHnvMOHz4sGEYhrFz507j3nvvNdq1a2f4+PgYbdq0MX71q185LStuGIaxdetWIy4uzvD29j7rsvMPP/ywIclpufFfmj59uiHJ+OyzzwzDOLO8+5QpU4yOHTsaXl5eRlhYmHHnnXc67ePnn382/vjHPxoxMTGGt7e30bp1a+OWW24xduzY4ZhTXl5ujBkzxmjZsqUREBBg3H333cbRo0frXGr+2LFjNWo7dOiQMWzYMCMoKMho2bKlcddddxmHDx+u9Zy///57Y9SoUUbr1q0NHx8fo1OnTsaECROclkavdtVVVxkWi8U4dOhQne9LbUpKSgw/Pz9DkrF48eIar2dlZRm9e/c2goKCDD8/PyMmJsZ4+umnjYqKirPu91xLzf/3uUoyJkyYYCxevNjo0qWL4ePjY1xzzTXGhx9+WGO/O3fuNFJSUowWLVoY/v7+xoABA4ytW7fWmPfvf//byMjIMCIjIw1vb2+jbdu2RlpamnH8+HGn+n65hPwvf1Lgm2++MUaPHm1ER0cbvr6+RnBwsDFgwABjw4YN53hnAcC1PAzjPK/1AwCAernmmmsUHBysvLw8V5dy3jw8PDRhwoRabw0FADQM3/kCAOAi+PTTT1VQUKBRo0a5uhQAQBPBd74AAGhEX3zxhXbs2KHnnntO4eHhTj+ODAC4vHHlCwCARrRy5Uqlp6ersrJSr7/+unx9fV1dEgCgieA7XwAAAABgAq58AQAAAIAJCF8AAAAAYAIW3Gggu92uw4cPKyAgQB4eHq4uBwAAAICLGIahH3/8UREREbJY6r6+RfhqoMOHDysqKsrVZQAAAABoIg4ePKi2bdvW+Trhq4ECAgIknXmDAwMDXVpLZWWl1q9fr0GDBsnLy8ultaBx0FP3RF/dDz11T/TV/dBT99SU+lpSUqKoqChHRqgL4auBqm81DAwMbBLhy9/fX4GBgS7/Dw+Ng566J/rqfuipe6Kv7oeeuqem2NdzfR2JBTcAAAAAwASELwAAAAAwAeELAAAAAEzAd74AAAAAExmGoZ9//llVVVWuLuWSVllZqWbNmun06dMX/b309PRUs2bNLvgnpghfAAAAgEkqKip05MgRlZeXu7qUS55hGAoLC9PBgwdN+d1df39/hYeHy9vbu8H7IHwBAAAAJrDb7fr222/l6empiIgIeXt7mxIa3JXdbldpaalatGhx1h82vlCGYaiiokLHjh3Tt99+qy5dujT4eIQvAAAAwAQVFRWy2+2KioqSv7+/q8u55NntdlVUVMjX1/eihi9J8vPzk5eXl77//nvHMRuCBTcAAAAAE13soICLozH6RucBAAAAwASELwAAAAAwAeELAAAAAExA+AIAAABQKw8Pj7M+pk+ffkH7fvvttxtt3qWA1Q4BAAAA1OrIkSOOfy9fvlxTp05VYWGhY6xFixauKOuSxZUvAAAAwFUMQyorM/9hGPUqLywszPFo2bKlPDw8nMaWLVumbt26ydfXVzExMZo3b55j24qKCmVkZCg8PFy+vr5q3769srOzJUkdOnSQJA0bNkweHh6O5+fLbrfrqaeeUtu2beXj46PY2FitXbu2XjUYhqHp06erXbt28vHxUUREhCZOnNigOuqLK18AAACAq5SXS664elRaKjVvfkG7WLJkiaZOnaoXXnhB11xzjXbt2qWxY8eqefPmSktL0/PPP6/Vq1frjTfeULt27XTw4EEdPHhQkvSPf/xDbdq00cKFCzV48GB5eno2qIacnBzNmjVLL774oq655hotWLBAQ4YM0Z49e9SlS5ez1vDmm29q9uzZWrZsma666ioVFRXps88+u6D35FwIXwAAAADO27Rp0/Tcc89p+PDhkqSOHTvqn//8p1588UWlpaXpwIED6tKli/r27SsPDw+1b9/esW3r1q0lSUFBQQoLC2twDS+88IIee+wx3XPPPZKkmTNn6sMPP9ScOXM0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N8+8EwcAAABw2XH5ghsZGRnKyMio9bXqq1XVsrKylJWVdc59jh49WqNHj67zdV9fX82dO1dz5849r1oBAAAAoKFc9p0vAAAAALicEL4AAAAAwASELwAAAAAwAeELAAAAAExA+AIAAAAAExC+AAAAAMAEhC8AAAAAMAHhCwAAAABMQPgCAAAAABMQvgAAAADABIQvAAAAADAB4QsAAAAATED4AgAAAAATEL4AAAAAwASELwAAAAAwAeELAAAAAExA+AIAAAAAExC+AAAAAMAEhC8AAAAAMAHhCwAAAABMQPgCAAAAABM0c3UBlyrDMCRJJSUlLq5EqqysVHl5uUpKSuTl5eXqctAI6Kl7oq/uh566J/rqfuipe2pKfa3OBNUZoS6Erwb68ccfJUlRUVEurgQAAABAU/Djjz+qZcuWdb7uYZwrnqFWdrtdhw8fVkBAgDw8PFxaS0lJiaKionTw4EEFBga6tBY0Dnrqnuir+6Gn7om+uh966p6aUl8Nw9CPP/6oiIgIWSx1f7OLK18NZLFY1LZtW1eX4SQwMNDl/+GhcdFT90Rf3Q89dU/01f3QU/fUVPp6tite1VhwAwAAAABMQPgCAAAAABMQvtyAj4+Ppk2bJh8fH1eXgkZCT90TfXU/9NQ90Vf3Q0/d06XYVxbcAAAAAAATcOULAAAAAExA+AIAAAAAExC+AAAAAMAEhC8AAAAAMAHh6xIxd+5cdejQQb6+vkpISND27dvPOn/FihWKiYmRr6+vevTooTVr1phUKerrfHr66quvysPDw+nh6+trYrU4l48++ki33367IiIi5OHhobfffvuc22zatEnXXnutfHx81LlzZ7366qsXvU6cn/Pt66ZNm2p8Vj08PFRUVGROwTin7OxsXXfddQoICFCbNm00dOhQFRYWnnM7/q42XQ3pKX9Xm7758+erZ8+ejh9Q7tOnjz744IOzbnMpfE4JX5eA5cuXy2q1atq0adq5c6d69eqllJQUHT16tNb5W7du1b333qsxY8Zo165dGjp0qIYOHaovvvjC5MpRl/PtqXTm19uPHDnieHz//fcmVoxzKSsrU69evTR37tx6zf/222912223acCAASooKNAjjzyiBx54QOvWrbvIleJ8nG9fqxUWFjp9Xtu0aXORKsT52rx5syZMmKBt27YpNzdXlZWVGjRokMrKyurchr+r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\n"
- },
- "metadata": {}
}
]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "# Step 5: Fine Tune"
+ ],
+ "metadata": {
+ "id": "LC6Xv3YfC0Rm"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "# Step 6: Test generalization"
+ ],
+ "metadata": {
+ "id": "JtTLXn4zC1z_"
+ }
}
]
} \ No newline at end of file