zaidmehdi commited on
Commit
01d43bf
1 Parent(s): d62571a

Upload folder using huggingface_hub

Browse files
src/__pycache__/model.cpython-311.pyc ADDED
Binary file (2.14 kB). View file
 
src/__pycache__/model.cpython-312.pyc ADDED
Binary file (1.93 kB). View file
 
src/__pycache__/utils.cpython-311.pyc ADDED
Binary file (3.84 kB). View file
 
src/__pycache__/utils.cpython-312.pyc ADDED
Binary file (3.45 kB). View file
 
src/get_data.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import random
3
+ import shutil
4
+
5
+
6
+ def extract_images(source_folder, destination_folder):
7
+ count = 0
8
+ for root, _, files in os.walk(source_folder):
9
+ for file in files:
10
+ if file.endswith(('jpg', '.png')):
11
+ src_path = os.path.join(root, file)
12
+ dst_path = os.path.join(destination_folder, f"{count:05d}" + os.path.splitext(file)[1])
13
+ shutil.copy(src_path, dst_path)
14
+ count += 1
15
+
16
+
17
+ def split_data(data_folder):
18
+ train_folder = f"{data_folder}/train"
19
+ validation_folder = f"{data_folder}/validation"
20
+ test_folder = f"{data_folder}/test"
21
+
22
+ for folder in [train_folder, validation_folder, test_folder]:
23
+ if not os.path.exists(folder):
24
+ os.makedirs(folder)
25
+
26
+ image_files = [f for f in os.listdir(data_folder) if os.path.isfile(os.path.join(data_folder, f))]
27
+ random.shuffle(image_files)
28
+
29
+ total_images = len(image_files)
30
+ train_count = int(0.7 * total_images)
31
+ validation_count = int(0.2 * total_images)
32
+
33
+ for i in range(train_count):
34
+ shutil.move(os.path.join(data_folder, image_files[i]), train_folder)
35
+
36
+ for i in range(train_count, train_count + validation_count):
37
+ shutil.move(os.path.join(data_folder, image_files[i]), validation_folder)
38
+
39
+ for i in range(train_count + validation_count, total_images):
40
+ shutil.move(os.path.join(data_folder, image_files[i]), test_folder)
41
+
42
+
43
+ if __name__ == "__main__":
44
+ source_folder = "manga/"
45
+ destination_folder = "data/"
46
+ extract_images(source_folder, destination_folder)
47
+
48
+ data_folder = "data/"
49
+ split_data(data_folder)
src/main.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import gradio as gr
4
+ import torch
5
+ from PIL import Image
6
+
7
+ from model import MangaColorizer
8
+ from utils import pil_to_torch, torch_to_pil
9
+
10
+ def load_html_template():
11
+ html_dir = os.path.join(os.path.dirname(__file__), "templates")
12
+ index_html_path = os.path.join(html_dir, "index.html")
13
+
14
+ if os.path.exists(index_html_path):
15
+ with open(index_html_path, "r") as html_file:
16
+ index_html = html_file.read()
17
+ return index_html
18
+ else:
19
+ print(f"Error: {index_html_path} not found.")
20
+
21
+
22
+ def load_model():
23
+ model = MangaColorizer()
24
+ models_dir = os.path.join(os.path.dirname(__file__), '..', 'model')
25
+ model_file = os.path.join(models_dir, 'best_model_checkpoint.pth')
26
+ if os.path.exists(model_file):
27
+ with open(model_file, "rb") as f:
28
+ checkpoint = torch.load(f, map_location="cpu")
29
+ model.load_state_dict(checkpoint)
30
+ else:
31
+ print(f"Error: {model_file} not found.")
32
+
33
+ return model
34
+ model = load_model()
35
+
36
+ def colorize_image(image):
37
+ global model
38
+ img = Image.fromarray(image).convert("L")
39
+ output = model(pil_to_torch(img)).detach().cpu()
40
+ output_image = torch_to_pil(output)
41
+
42
+ return output_image
43
+
44
+
45
+ def main():
46
+ index_html = load_html_template()
47
+ with gr.Blocks() as demo:
48
+ gr.HTML(index_html)
49
+ gr.Interface(colorize_image, inputs=["image"], outputs=["image"], allow_flagging="never")
50
+ gr.HTML("""
51
+ <p style="text-align: center;font-size: large;">
52
+ Checkout the <a href="https://github.com/zaidmehdi/manga-colorizer">Github Repo</a>
53
+ </p>
54
+ """)
55
+ demo.launch(server_name="0.0.0.0", server_port=8080)
56
+
57
+
58
+ if __name__ == "__main__":
59
+ main()
src/model.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.nn as nn
2
+
3
+
4
+ class MangaColorizer(nn.Module):
5
+ def __init__(self):
6
+ super(MangaColorizer, self).__init__()
7
+ self.encoder = nn.Sequential(
8
+ nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1),
9
+ nn.ReLU(inplace=True),
10
+ nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1),
11
+ nn.ReLU(inplace=True),
12
+ nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1),
13
+ nn.ReLU(inplace=True)
14
+ )
15
+ self.decoder = nn.Sequential(
16
+ nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1),
17
+ nn.ReLU(inplace=True),
18
+ nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1),
19
+ nn.ReLU(inplace=True),
20
+ nn.ConvTranspose2d(64, 3, kernel_size=3, stride=1, padding=1),
21
+ nn.Tanh()
22
+ )
23
+
24
+ def forward(self, x):
25
+ x = self.encoder(x)
26
+ x = self.decoder(x)
27
+ return x
src/model_training.ipynb ADDED
@@ -0,0 +1,838 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 2,
6
+ "id": "06eef311",
7
+ "metadata": {
8
+ "execution": {
9
+ "iopub.execute_input": "2024-04-01T01:04:34.377065Z",
10
+ "iopub.status.busy": "2024-04-01T01:04:34.376156Z",
11
+ "iopub.status.idle": "2024-04-01T01:04:41.159287Z",
12
+ "shell.execute_reply": "2024-04-01T01:04:41.158448Z"
13
+ },
14
+ "papermill": {
15
+ "duration": 6.79219,
16
+ "end_time": "2024-04-01T01:04:41.161646",
17
+ "exception": false,
18
+ "start_time": "2024-04-01T01:04:34.369456",
19
+ "status": "completed"
20
+ },
21
+ "tags": []
22
+ },
23
+ "outputs": [],
24
+ "source": [
25
+ "import matplotlib.pyplot as plt\n",
26
+ "import numpy as np\n",
27
+ "import torch\n",
28
+ "import torch.nn as nn\n",
29
+ "import torch.optim as optim\n",
30
+ "from torchvision import transforms\n",
31
+ "from torch.utils.data import DataLoader\n",
32
+ "from tqdm.auto import tqdm\n",
33
+ "\n",
34
+ "from model import MangaColorizer\n",
35
+ "from utils import ImageDataset, adjust_output_shape"
36
+ ]
37
+ },
38
+ {
39
+ "cell_type": "markdown",
40
+ "id": "5e7ff784",
41
+ "metadata": {
42
+ "papermill": {
43
+ "duration": 0.004403,
44
+ "end_time": "2024-04-01T01:04:41.171084",
45
+ "exception": false,
46
+ "start_time": "2024-04-01T01:04:41.166681",
47
+ "status": "completed"
48
+ },
49
+ "tags": []
50
+ },
51
+ "source": [
52
+ "## Model architecture"
53
+ ]
54
+ },
55
+ {
56
+ "cell_type": "code",
57
+ "execution_count": 3,
58
+ "id": "87d03ce6",
59
+ "metadata": {
60
+ "execution": {
61
+ "iopub.execute_input": "2024-04-01T01:04:41.182184Z",
62
+ "iopub.status.busy": "2024-04-01T01:04:41.181258Z",
63
+ "iopub.status.idle": "2024-04-01T01:04:41.190651Z",
64
+ "shell.execute_reply": "2024-04-01T01:04:41.189724Z"
65
+ },
66
+ "papermill": {
67
+ "duration": 0.017191,
68
+ "end_time": "2024-04-01T01:04:41.192743",
69
+ "exception": false,
70
+ "start_time": "2024-04-01T01:04:41.175552",
71
+ "status": "completed"
72
+ },
73
+ "tags": []
74
+ },
75
+ "outputs": [
76
+ {
77
+ "data": {
78
+ "text/plain": [
79
+ "MangaColorizer(\n",
80
+ " (encoder): Sequential(\n",
81
+ " (0): Conv2d(1, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
82
+ " (1): ReLU(inplace=True)\n",
83
+ " (2): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n",
84
+ " (3): ReLU(inplace=True)\n",
85
+ " (4): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n",
86
+ " (5): ReLU(inplace=True)\n",
87
+ " )\n",
88
+ " (decoder): Sequential(\n",
89
+ " (0): ConvTranspose2d(256, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1))\n",
90
+ " (1): ReLU(inplace=True)\n",
91
+ " (2): ConvTranspose2d(128, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1))\n",
92
+ " (3): ReLU(inplace=True)\n",
93
+ " (4): ConvTranspose2d(64, 3, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
94
+ " (5): Tanh()\n",
95
+ " )\n",
96
+ ")"
97
+ ]
98
+ },
99
+ "execution_count": 3,
100
+ "metadata": {},
101
+ "output_type": "execute_result"
102
+ }
103
+ ],
104
+ "source": [
105
+ "model = MangaColorizer()\n",
106
+ "model"
107
+ ]
108
+ },
109
+ {
110
+ "cell_type": "markdown",
111
+ "id": "c4b5ff4a",
112
+ "metadata": {
113
+ "papermill": {
114
+ "duration": 0.004206,
115
+ "end_time": "2024-04-01T01:04:41.201565",
116
+ "exception": false,
117
+ "start_time": "2024-04-01T01:04:41.197359",
118
+ "status": "completed"
119
+ },
120
+ "tags": []
121
+ },
122
+ "source": [
123
+ "## Loading the Data"
124
+ ]
125
+ },
126
+ {
127
+ "cell_type": "code",
128
+ "execution_count": 5,
129
+ "id": "42198e39",
130
+ "metadata": {
131
+ "execution": {
132
+ "iopub.execute_input": "2024-04-01T01:04:41.247525Z",
133
+ "iopub.status.busy": "2024-04-01T01:04:41.247244Z",
134
+ "iopub.status.idle": "2024-04-01T01:04:41.627306Z",
135
+ "shell.execute_reply": "2024-04-01T01:04:41.626292Z"
136
+ },
137
+ "papermill": {
138
+ "duration": 0.387773,
139
+ "end_time": "2024-04-01T01:04:41.629778",
140
+ "exception": false,
141
+ "start_time": "2024-04-01T01:04:41.242005",
142
+ "status": "completed"
143
+ },
144
+ "tags": []
145
+ },
146
+ "outputs": [],
147
+ "source": [
148
+ "transform = transforms.Compose([\n",
149
+ " transforms.ToTensor()\n",
150
+ "])\n",
151
+ "\n",
152
+ "train_dataset = ImageDataset(dir=\"/kaggle/input/manga-panels-colored/data/train\", \n",
153
+ " transform=transform)\n",
154
+ "validation_dataset = ImageDataset(dir=\"/kaggle/input/manga-panels-colored/data/validation\", \n",
155
+ " transform=transform)\n",
156
+ "test_dataset = ImageDataset(dir=\"/kaggle/input/manga-panels-colored/data/test\", \n",
157
+ " transform=transform)"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": 6,
163
+ "id": "8e5ea6dd",
164
+ "metadata": {
165
+ "execution": {
166
+ "iopub.execute_input": "2024-04-01T01:04:41.640890Z",
167
+ "iopub.status.busy": "2024-04-01T01:04:41.640098Z",
168
+ "iopub.status.idle": "2024-04-01T01:04:41.645385Z",
169
+ "shell.execute_reply": "2024-04-01T01:04:41.644485Z"
170
+ },
171
+ "papermill": {
172
+ "duration": 0.012881,
173
+ "end_time": "2024-04-01T01:04:41.647392",
174
+ "exception": false,
175
+ "start_time": "2024-04-01T01:04:41.634511",
176
+ "status": "completed"
177
+ },
178
+ "tags": []
179
+ },
180
+ "outputs": [],
181
+ "source": [
182
+ "train_loader = DataLoader(train_dataset, batch_size=1, shuffle=True)\n",
183
+ "validation_loader = DataLoader(validation_dataset, batch_size=1, shuffle=True)\n",
184
+ "test_loader = DataLoader(test_dataset, batch_size=1, shuffle=True)"
185
+ ]
186
+ },
187
+ {
188
+ "cell_type": "markdown",
189
+ "id": "fd0bbc4c",
190
+ "metadata": {
191
+ "papermill": {
192
+ "duration": 0.004236,
193
+ "end_time": "2024-04-01T01:04:41.656333",
194
+ "exception": false,
195
+ "start_time": "2024-04-01T01:04:41.652097",
196
+ "status": "completed"
197
+ },
198
+ "tags": []
199
+ },
200
+ "source": [
201
+ "## Training the model"
202
+ ]
203
+ },
204
+ {
205
+ "cell_type": "code",
206
+ "execution_count": 8,
207
+ "id": "6bb853cd",
208
+ "metadata": {
209
+ "execution": {
210
+ "iopub.execute_input": "2024-04-01T01:04:41.683769Z",
211
+ "iopub.status.busy": "2024-04-01T01:04:41.683460Z",
212
+ "iopub.status.idle": "2024-04-01T01:04:41.721713Z",
213
+ "shell.execute_reply": "2024-04-01T01:04:41.720922Z"
214
+ },
215
+ "papermill": {
216
+ "duration": 0.04614,
217
+ "end_time": "2024-04-01T01:04:41.724036",
218
+ "exception": false,
219
+ "start_time": "2024-04-01T01:04:41.677896",
220
+ "status": "completed"
221
+ },
222
+ "tags": []
223
+ },
224
+ "outputs": [],
225
+ "source": [
226
+ "criterion = nn.MSELoss()\n",
227
+ "optimizer = optim.Adam(model.parameters(), lr=0.0001)"
228
+ ]
229
+ },
230
+ {
231
+ "cell_type": "code",
232
+ "execution_count": null,
233
+ "id": "7b70952d",
234
+ "metadata": {
235
+ "execution": {
236
+ "iopub.execute_input": "2024-04-01T01:04:41.735281Z",
237
+ "iopub.status.busy": "2024-04-01T01:04:41.734495Z",
238
+ "iopub.status.idle": "2024-04-01T01:04:41.955794Z",
239
+ "shell.execute_reply": "2024-04-01T01:04:41.954865Z"
240
+ },
241
+ "papermill": {
242
+ "duration": 0.229072,
243
+ "end_time": "2024-04-01T01:04:41.957864",
244
+ "exception": false,
245
+ "start_time": "2024-04-01T01:04:41.728792",
246
+ "status": "completed"
247
+ },
248
+ "tags": []
249
+ },
250
+ "outputs": [],
251
+ "source": [
252
+ "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
253
+ "model.to(device)"
254
+ ]
255
+ },
256
+ {
257
+ "cell_type": "code",
258
+ "execution_count": null,
259
+ "id": "4d252b1e",
260
+ "metadata": {
261
+ "execution": {
262
+ "iopub.execute_input": "2024-04-01T01:04:41.969269Z",
263
+ "iopub.status.busy": "2024-04-01T01:04:41.968485Z",
264
+ "iopub.status.idle": "2024-04-01T10:06:12.760575Z",
265
+ "shell.execute_reply": "2024-04-01T10:06:12.759664Z"
266
+ },
267
+ "papermill": {
268
+ "duration": 32490.811819,
269
+ "end_time": "2024-04-01T10:06:12.774567",
270
+ "exception": false,
271
+ "start_time": "2024-04-01T01:04:41.962748",
272
+ "status": "completed"
273
+ },
274
+ "tags": []
275
+ },
276
+ "outputs": [],
277
+ "source": [
278
+ "num_epochs = 100\n",
279
+ "num_training_steps = num_epochs * len(train_loader)\n",
280
+ "progress_bar = tqdm(range(num_training_steps))\n",
281
+ "\n",
282
+ "train_losses = []\n",
283
+ "valid_losses = []\n",
284
+ "\n",
285
+ "best_valid_loss = float(\"inf\")\n",
286
+ "epochs_no_improve = 0\n",
287
+ "patience = 10\n",
288
+ "best_model = None\n",
289
+ "\n",
290
+ "for epoch in range(num_epochs):\n",
291
+ " model.train()\n",
292
+ " train_loss = 0.0\n",
293
+ " for images, targets in train_loader:\n",
294
+ " images = images.to(device)\n",
295
+ " targets = targets.to(device)\n",
296
+ " outputs = model(images)\n",
297
+ " try:\n",
298
+ " loss = criterion(outputs, targets)\n",
299
+ " except RuntimeError:\n",
300
+ " adjusted_output = adjust_output_shape(outputs, targets)\n",
301
+ " loss = criterion(adjusted_output, targets)\n",
302
+ " loss.backward()\n",
303
+ "\n",
304
+ " optimizer.step()\n",
305
+ " optimizer.zero_grad()\n",
306
+ " progress_bar.update(1)\n",
307
+ "\n",
308
+ " train_loss += loss.item()\n",
309
+ " \n",
310
+ " train_losses.append(train_loss / len(train_loader))\n",
311
+ "\n",
312
+ " model.eval()\n",
313
+ " valid_loss = 0.0\n",
314
+ " with torch.no_grad():\n",
315
+ " for images, targets in validation_loader:\n",
316
+ " images = images.to(device)\n",
317
+ " targets = targets.to(device)\n",
318
+ " outputs = model(images)\n",
319
+ " try:\n",
320
+ " loss = criterion(outputs, targets)\n",
321
+ " except RuntimeError:\n",
322
+ " adjusted_output = adjust_output_shape(outputs, targets)\n",
323
+ " loss = criterion(adjusted_output, targets)\n",
324
+ " valid_loss += loss.item()\n",
325
+ " \n",
326
+ " valid_loss /= len(validation_loader)\n",
327
+ " valid_losses.append(valid_loss)\n",
328
+ "\n",
329
+ " print(f'Epoch [{epoch+1}/{num_epochs}], Train Loss: {train_losses[-1]:.4f}, Valid Loss: {valid_loss:.4f}') \n",
330
+ " torch.save(model.state_dict(), \"last_checkpoint.pth\")\n",
331
+ "\n",
332
+ " if valid_loss < best_valid_loss:\n",
333
+ " best_valid_loss = valid_loss\n",
334
+ " epochs_no_improve = 0\n",
335
+ " best_model = model.state_dict()\n",
336
+ " torch.save(best_model, \"best_model_checkpoint.pth\")\n",
337
+ " else:\n",
338
+ " epochs_no_improve += 1\n",
339
+ " if epochs_no_improve == patience:\n",
340
+ " print(f\"Early stopping after {epoch+1} epochs with no improvement.\")\n",
341
+ " break\n",
342
+ "\n",
343
+ "model.load_state_dict(best_model)"
344
+ ]
345
+ },
346
+ {
347
+ "cell_type": "code",
348
+ "execution_count": 11,
349
+ "id": "e3d447f1",
350
+ "metadata": {
351
+ "execution": {
352
+ "iopub.execute_input": "2024-04-01T10:06:12.800929Z",
353
+ "iopub.status.busy": "2024-04-01T10:06:12.800630Z",
354
+ "iopub.status.idle": "2024-04-01T10:06:13.054441Z",
355
+ "shell.execute_reply": "2024-04-01T10:06:13.053544Z"
356
+ },
357
+ "papermill": {
358
+ "duration": 0.269281,
359
+ "end_time": "2024-04-01T10:06:13.056431",
360
+ "exception": false,
361
+ "start_time": "2024-04-01T10:06:12.787150",
362
+ "status": "completed"
363
+ },
364
+ "tags": []
365
+ },
366
+ "outputs": [
367
+ {
368
+ "data": {
369
+ "image/png": "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G926dcNvv/2GmTNn4ptvvkFycrJjzU1VSqVXVi1QvqL4w81+bVVYrVbcf//9+PbbbzFhwgSsXbsWycnJjmIWV36+W1X5MDg4GPfffz/+97//wWw245tvvkFubi4GDx7saPPpp59i2LBhaNSoET766CNs2rQJycnJuO+++2q0hP3s2bMxfvx43HPPPfj000/x3XffITk5GS1btrxlpfNr+rqoiuDgYOzfvx/r1q1zrJ/r3bu301rDe+65B3///Tc+/vhjtGrVCh9++CHuvvtufPjhh7esn0TkvlgkhIjoDrR9+3ZcunQJa9aswT333OM4fuLECRf2qlRwcDAMBkOFGztfbbNnu99//x1//fUXVqxYgSFDhjiO30iVvfr162PLli3Iy8tzGkU7cuTIdZ1n8ODB2LRpEzZu3IiVK1fC19cX/fr1czz/5ZdfomHDhlizZo3TtMTp06dXq88AcPToUTRs2NBxPDMzs9yo1Jdffol7770XH330kdPx7OxsBAUFOR5XpYJm2fffvHkzcnNznUbR7FNo7f27FerXr48DBw7AZrM5jaJV1BedTod+/fqhX79+sNlseP755/H+++9j6tSpjhHcWrVqYfjw4Rg+fDjy8vJwzz33YMaMGXjqqadu2WciIvfEETQiojuQfaSi7MiEyWTCe++956ouOVGr1YiPj8fatWuRlpbmOH7s2LFy65Yqez3g/PlkWXYqlX69+vTpA4vFgiVLljiOWa1WLFy48LrOk5iYCE9PT7z33nvYuHEjHn74YRgMhqv2fefOnUhJSbnuPsfHx0Or1WLhwoVO51uwYEG5tmq1utxIVVJSEs6dO+d0zMvLCwCqtL1Anz59YLVasWjRIqfj77zzDiRJqvJ6wpuhT58+SE9Px+rVqx3HLBYLFi5cCG9vb8f010uXLjm9TqVSOTYPLy4urrCNt7c3Gjdu7HieiKgmcQSNiOgO1KlTJwQEBGDo0KEYO3YsJEnCf//731s6lexaZsyYge+//x6dO3fGc8895/hFv1WrVti/f/9VX9usWTM0atQIL7/8Ms6dOwdfX1/873//u6G1TP369UPnzp0xceJEnDx5Ei1atMCaNWuue32Wt7c3EhMTHevQyk5vBIAHHngAa9asQf/+/dG3b1+cOHECS5cuRYsWLZCXl3dd72Xfz23OnDl44IEH0KdPH6SmpmLjxo1Oo2L29505cyaGDx+OTp064ffff8dnn33mNPIGAI0aNYK/vz+WLl0KHx8feHl5ITY2Fg0aNCj3/v369cO9996LV199FSdPnkR0dDS+//57fP3113jhhRecCoLcDFu2bEFRUVG544mJiRg5ciTef/99DBs2DHv37kVkZCS+/PJL/PLLL1iwYIFjhO+pp55CVlYW7rvvPtStWxenTp3CwoULERMT41iv1qJFC3Tv3h1t27ZFrVq1sGfPHnz55ZcYPXr0Tf08REQVYUAjIroDBQYGYv369XjppZcwZcoUBAQE4PHHH0ePHj2QkJDg6u4BANq2bYuNGzfi5ZdfxtSpUxEREYGZM2fi0KFD16wyqdVq8c0332Ds2LGYM2cODAYD+vfvj9GjRyM6Orpa/VGpVFi3bh1eeOEFfPrpp5AkCQ8++CDmz5+PNm3aXNe5Bg8ejJUrVyIsLAz33Xef03PDhg1Deno63n//fXz33Xdo0aIFPv30UyQlJWH79u3X3e/XX38dBoMBS5cuxbZt2xAbG4vvv/8effv2dWo3efJk5OfnY+XKlVi9ejXuvvtufPvtt5g4caJTO61WixUrVmDSpEl49tlnYbFYsGzZsgoDmv07mzZtGlavXo1ly5YhMjIS8+bNw0svvXTdn+VaNm3aVOHG1pGRkWjVqhW2b9+OiRMnYsWKFTAajWjatCmWLVuGYcOGOdo+/vjj+OCDD/Dee+8hOzsboaGhGDhwIGbMmOGYGjl27FisW7cO33//PYqLi1G/fn28/vrreOWVV276ZyIiupIkK+nPqURE5PYSExNZ4pyIiNwW16AREZHLFBYWOj0+evQoNmzYgO7du7umQ0RERC7GETQiInKZsLAwDBs2DA0bNsSpU6ewZMkSFBcXIzU1tdzeXkRERO6Aa9CIiMhlevXqhc8//xzp6enQ6/WIi4vD7NmzGc6IiMhtcQSNiIiIiIhIIbgGjYiIiIiISCEY0IiIiIiIiBSCa9BqkM1mQ1paGnx8fCBJkqu7Q0RERERELiLLMnJzcxEeHu7Yd7EiDGg1KC0tDREREa7uBhERERERKcSZM2dQt27dSp9nQKtBPj4+AMQ/gq+vr4t7Q0RERERErmI0GhEREeHICJVhQKtB9mmNvr6+DGhERERERHTNpU8sEkJERERERKQQDGhEREREREQKwYBGRERERESkEFyDRkRERETkArIsw2KxwGq1urordBOo1WpoNJob3l6LAY2IiIiI6BYzmUw4f/48CgoKXN0Vuok8PT0RFhYGnU5X7XMwoBERERER3UI2mw0nTpyAWq1GeHg4dDrdDY+6kGvJsgyTyYTMzEycOHECTZo0uepm1FfDgEZEREREdAuZTCbYbDZERETA09PT1d2hm8TDwwNarRanTp2CyWSCwWCo1nlYJISIiIiIyAWqO8JCynUz/k15VRARERERESkEAxoREREREZFCMKAREREREZHLREZGYsGCBa7uhmIwoBERERER0TVJknTV24wZM6p13t27d2PkyJE31Lfu3bvjhRdeuKFzKAWrOBIRERER0TWdP3/e8fPq1asxbdo0HDlyxHHM29vb8bMsy7BardBorh03ateufXM7epvjCJob+PX4JfRa8CNGr9zn6q4QERERUQVkWUaByeKSmyzLVepjaGio4+bn5wdJkhyPDx8+DB8fH2zcuBFt27aFXq/Hzz//jL///hsPPfQQQkJC4O3tjfbt22Pz5s1O571yiqMkSfjwww/Rv39/eHp6okmTJli3bt0Nfb//+9//0LJlS+j1ekRGRmL+/PlOz7/33nto0qQJDAYDQkJCMGDAAMdzX375JaKiouDh4YHAwEDEx8cjPz//hvpzNRxBcwOFZisOp+dCreIGiERERERKVGi2osW071zy3n/OTICn7ubEgokTJ+Ktt95Cw4YNERAQgDNnzqBPnz7417/+Bb1ej08++QT9+vXDkSNHUK9evUrP89prr2Hu3LmYN28eFi5ciMGDB+PUqVOoVavWdfdp7969ePTRRzFjxgwMHDgQO3bswPPPP4/AwEAMGzYMe/bswdixY/Hf//4XnTp1QlZWFn766ScAYtRw0KBBmDt3Lvr374/c3Fz89NNPVQ611cGA5gZ0ajFQarbaXNwTIiIiIrqTzZw5E/fff7/jca1atRAdHe14PGvWLHz11VdYt24dRo8eXel5hg0bhkGDBgEAZs+ejXfffRe7du1Cr169rrtPb7/9Nnr06IGpU6cCAO666y78+eefmDdvHoYNG4bTp0/Dy8sLDzzwAHx8fFC/fn20adMGgAhoFosFDz/8MOrXrw8AiIqKuu4+XA8GNDeg09gDWs0lfSIiIiKqPg+tGn/OTHDZe98s7dq1c3qcl5eHGTNm4Ntvv3WEncLCQpw+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RKuWAAAmFgkhIiIiIlIkBjQ3omORECIiIiIiRWNAcyOOMvssEkJEREREpEgMaG7EUSSEUxyJiIiIiBSJAc2N2NegcYojEREREZEyMaC5Ea5BIyIiIiJSNgY0N6LlRtVERERERIrGgOZG7EVCuFE1EREREZEyMaC5kbJr0GSZo2hERERERErDgOZG9Go1AECWAauNAY2IiIiISGkY0NyIViM5fuY0RyIiIiIi5WFAcyP2IiEAYLZwBI2IiIiISGkY0NyIRsURNCIiIiIiJWNAcyOSJHEvNCIiIiIiBWNAczNlKzkSEREREZGyMKC5GfteaAxoRERERETKw4DmZuyFQkwsEkJEREREpDgMaG6Ga9CIiIiIiJSLAc3NcA0aEREREZFyMaC5GccURwY0IiIiIiLFYUBzMzpHkRCuQSMiIiIiUhoGNDdTWiSEI2hERERERErDgOZmWCSEiIiIiEi5GNDcjFbDIiFERERERErFgOZmOMWRiIiIiEi5GNDcjFbNIiFERERERErFgOZmuAaNiIiIiEi5GNDcDDeqJiIiIiJSLgY0N8ONqomIiIiIlIsBzc1o7RtVW7gGjYiIiIhIaRjQ3AzXoBERERERKRcDmpvRaRjQiIiIiIiUShEBbfHixYiMjITBYEBsbCx27dp11fZJSUlo1qwZDAYDoqKisGHDBsdzZrMZEyZMQFRUFLy8vBAeHo4hQ4YgLS3N6RxZWVkYPHgwfH194e/vjxEjRiAvL8+pzYEDB9C1a1cYDAZERERg7ty5N+9Du4i9SEgx90EjIiIiIlIclwe01atXY/z48Zg+fTr27duH6OhoJCQk4MKFCxW237FjBwYNGoQRI0YgNTUViYmJSExMxB9//AEAKCgowL59+zB16lTs27cPa9aswZEjR/Dggw86nWfw4ME4ePAgkpOTsX79evz4448YOXKk43mj0YiePXuifv362Lt3L+bNm4cZM2bggw8+qLkv4xbQcoojEREREZFiSbIsu7RaRGxsLNq3b49FixYBAGw2GyIiIjBmzBhMnDixXPuBAwciPz8f69evdxzr2LEjYmJisHTp0grfY/fu3ejQoQNOnTqFevXq4dChQ2jRogV2796Ndu3aAQA2bdqEPn364OzZswgPD8eSJUvw6quvIj09HTqdDgAwceJErF27FocPH67wfYqLi1FcXOx4bDQaERER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zpw5AIBx48ahW7dumD9/Pvr27YtVq1Zhz549+OCDDxznzMrKwunTp5GWlgYAOHLkCAAx+hYaGuoIZwUFBfj000+dinnUrl0barUa33zzDTIyMtCxY0cYDAYkJydj9uzZePnll2/l13NLaNVimiMDGhERERGR67k0oA0cOBCZmZmYNm0a0tPTERMTg02bNjkKgZw+fRoqVekgX6dOnbBy5UpMmTIFkydPRpMmTbB27Vq0atXK0WbdunWOgAcAjz32GABg+vTpmDFjBvbt24edO3cCABo3buzUnxMnTiAyMhJarRaLFy/Giy++CFmW0bhxY7z99tt4+umna+y7cBXHZtUWVnEkIiIiInI1l+6DdqdT+j5oAND5ja04l12Ir0d1RnSEv6u7Q0RERER0R1L8PmikDFyDRkRERESkHAxo7qI4F7h8qtxh+xo0EwMaEREREZHLMaC5gwNfAG82ADb+X7mn7GvQzFbOdCUiIiIicjUGNHcQ3BywmYETPwIW533cHAGN+6AREREREbkcA5o7CGkFeIcA5gLg9K9OT+nUXINGRERERKQUDGjuQJKARj3Ez8c2Oz2l1XANGhERERGRUjCguYvG9oC2xemwzrEPGgMaEREREZGrMaC5i0b3AZCACwcB43nHYRYJISIiIiJSDgY0d+FZC6hzt/j579JRNC33QSMiIiIiUgwGNHfSOF7cl1mHxiIhRERERETKwYDmTuwB7e9tgM0KgBtVExEREREpCQOaOwm/GzD4AUXZwLl9AMrug8Y1aERERERErsaA5k7UGqDhveLnkmmOWk5xJCIiIiJSDAY0d3PFOjQdi4QQERERESkGA5q7se+Hdm4vUJDFNWhERERERArCgOZufMOB4BYAZOD4Nk5xJCIiIiJSEAY0d2QfRTu2pXSKI4uEEBERERG5HAOaOyqzDk2n4hRHIiIiIiKlYEBzR/XiAK0nkJeB4MJjABjQiIiIiIiUgAHNHWn0QGRXAEBEVgoAwGxhQCMiIiIicjUGNHdVMs2xzsVfALBICBERERGREjCguauSQiFBWfvghUKYrSwSQkRERETkagxo7qpWQyAgEirZgjjVn1yDRkRERESkAAxo7kqSHNMc71Ed4BRHIiIiIiIFYEBzZyUBrbtqP8wWq4s7Q0REREREGld3gFwositsKi3qIRO1TWmu7g0RERERkdvjCJo703sjL7gdAOBu0x4Xd4aIiIiIiBjQ3FxeRHcAQJzlV8DGdWhERERERK7EgObmCiLjYZMltLP9DqzoB1w+5eouERERERG5LQY0NxcY2RqTrM8gX9YDp34GlnQGUj8FZO6LRkRERER0qzGgubkALx0M7Z9Ab9MbOKRtAZhyga9HAasGA3mZru4eEREREZFbYUAjjLq3MTLUYeibOxnHo18GVFrgyLfAkjjg8AZXd4+IiIiIyG0woBGCfQ0YElcfNqgw7uy9kJ/eAgS3APIzgVWDgE8fAbbMAg4kAed/A0wFru4yEREREdEdSZJlLjaqKUajEX5+fsjJyYGvr6+ru3NVl/KK0XXuNhSYrHj/ibZIaBoAbH0d2LEQwJWXiAT41wNqNwUCmwC1GgABDcS9XwSg0bniIxARERERKVZVswEDWg26nQIaALz13REs2nYMzUJ9sGFsV6hUEpD+O3DiJ+DiESDzLyDzMFCYVflJJBXgWxeoFQnU6wR0HQ9o9LfsMxARERERKVFVs4HmFvaJFO7prg2xIuUkDqfn4tvfz6NfdDgQGiVuZeVfBDKPiNB26W8g6wRw+QRw+SRgLgByTovbiR8BmwXoMdUln4eIiIiI6HbDgEYOfp5aPN21Id5O/gvvbP4LvVuFQqOuYJmiV5C4RXZ2Pi7LQF6GCGonfxJTJH9ZALTsD4S2uhUfgYiIiIjotubyIiGLFy9GZGQkDAYDYmNjsWvXrqu2T0pKQrNmzWAwGBAVFYUNG5yrDK5ZswY9e/ZEYGAgJEnC/v37y52jqKgIo0aNQmBgILy9vfHII48gIyPDqc3p06fRt29feHp6Ijg4GK+88gosFssNf16lG945EgGeWhzPzMfX+9Ou78WSBPiEAvU6Ave8AjR7QIygrRsNWO/8746IiIiI6Ea5NKCtXr0a48ePx/Tp07Fv3z5ER0cjISEBFy5cqLD9jh07MGjQIIwYMQKpqalITExEYmIi/vjjD0eb/Px8dOnSBW+++Wal7/viiy/im2++QVJSEn744QekpaXh4YcfdjxvtVrRt29fmEwm7NixAytWrMDy5csxbdq0m/fhFcrHoMUz3RoBABZs+Qtmq636J+vzFqD3A9JSgZ1LblIPiYiIiIjuXC4tEhIbG4v27dtj0aJFAACbzYaIiAiMGTMGEydOLNd+4MCByM/Px/r16x3HOnbsiJiYGCxdutSp7cmTJ9GgQQOkpqYiJibGcTwnJwe1a9fGypUrMWDAAADA4cOH0bx5c6SkpKBjx47YuHEjHnjgAaSlpSEkJAQAsHTpUkyYMAGZmZnQ6apWpfB2KxJiV2Cy4J6523Exrxiz+0fhn7H1qn+yvSuAb8YCGg/g+R1ArYY3r6NERERERLeJqmYDl42gmUwm7N27F/Hx8aWdUakQHx+PlJSUCl+TkpLi1B4AEhISKm1fkb1798JsNjudp1mzZqhXr57jPCkpKYiKinKEM/v7GI1GHDx4sNJzFxcXw2g0Ot1uR546DUbdK0bRFm49iiKztfonu3sIENkVsBQC34wT69SIiIiIiKhCLgtoFy9ehNVqdQpBABASEoL09PQKX5Oenn5d7Ss7h06ng7+/f6Xnqex97M9VZs6cOfDz83PcIiIiqtwvpRnUoR7C/Aw4n1OEVbtOV/9EkgT0+zegMYiqjqmf3rxOEtW0rOPA6V9d3QsiIiJyIy4vEnInmTRpEnJychy3M2fOuLpL1WbQqjH6vsYAgLe+/wsLtxxFbpG5eicLbATcO1n8/P2rQG7G1dsTKUFeJvCfHsDHvYBze13dGyIiInITLgtoQUFBUKvV5aonZmRkIDQ0tMLXhIaGXlf7ys5hMpmQnZ1d6Xkqex/7c5XR6/Xw9fV1ut3O/tE2Au3qByCv2IL5yX+hy5vbsGjrUeQVV6MiY8dRQFg0UJQDbHyl4jbmIuD4D0DqZ0DBVTbDJroVNk0s2ZRdBlIWu7o3RERE5CZcFtB0Oh3atm2LLVu2OI7ZbDZs2bIFcXFxFb4mLi7OqT0AJCcnV9q+Im3btoVWq3U6z5EjR3D69GnHeeLi4vD77787VZNMTk6Gr68vWrRoUeX3ut3pNCqsfiYO/34sBo1qeyGn0Iy3vv8LXd7cisXbjl1fUFNrgAcXAZIa+PNr4NB6wGYDzv8G/PJv4JNE4M36wCcPAl8/D7wXB/y9tcY+G9FV/fUd8MeXgFTyn8iDa4Hs23dEnIiIiG4fLq3iuHr1agwdOhTvv/8+OnTogAULFuCLL77A4cOHERISgiFDhqBOnTqYM2cOAFFmv1u3bnjjjTfQt29frFq1CrNnz8a+ffvQqpXYCDkrKwunT59GWlqao03Tpk0RGhrqGP167rnnsGHDBixfvhy+vr4YM2aM4/yAKLMfExOD8PBwzJ07F+np6XjiiSfw1FNPYfbs2VX+fLdrFceKWG0yvvktDe9uOYrjF/MBAAGeWjzbrRGGdY6EXqOu2ok2zwB+fgcw+ImwVnjFSJl3KKDRAdkl6946Pg/0mA5oDdc+t7kQUOsAVRX7QlSR4lxgcUfAeBboNAZI2y82Xu80Buj5uqt7R0RERLepqmYDlwY0AFi0aBHmzZuH9PR0xMTE4N1330VsbCwAoHv37oiMjMTy5csd7ZOSkjBlyhScPHkSTZo0wdy5c9GnTx/H88uXL8fw4cPLvc/06dMxY8YMAGKj6pdeegmff/45iouLkZCQgPfee89p+uKpU6fw3HPPYfv27fDy8sLQoUPxxhtvQKPRVPmz3UkBzc5itWFdSVA7eakAANCothdmJbZCp0ZB1z6BuRBY0hnI+ls81vkAkV2Aht3FrXZT0SZ5GrD7P6JNcEvgkf8AIS0rPt/hb4HfPhcjbioN4F8fqNUACGhQ5r6hWAvH8EbXsuH/gF3vAwGRwHMporjN5wPFnn7jDwJ6H1f3kIiIiG5Dt01Au5PdiQHNzmK1YU3qOczddBgX80wAgMSYcLzatwVq++iv/uKsE8CRjUCdu4E6bQG1tuJ2f30vpjvmZ4qRsfgZQOxzojLk6RQRyg6uBYqruJ1BQCRwzytA64GVv+fNcnYPkPEH0Ph+wK9Ozb4X3TxndgEf9QQgA0+sBRrdK6biLm4PXDoG9HoT6Pisq3tJREREtyEGNAW4kwOaXU6BGW99fwSf7jwFWQZ8DBr8X0JT/DO2PtQq6cbfIC8TWDcG+GujeFy3A5CXAWSfKm3jVw+Ifgxo/Sig0YvS6FkngMsnSu8vHQfMYmom/OuLoBb92M0PajlngeTpYv0SINYwNekJtB0mwpq66iOw18VqFiOJIS2BoCY18x53OosJeL8rkHkYiBkMJL5X+tzuD4FvXxLXzthUjsQSERHRdWNAUwB3CGh2v53JxpS1f+D3czkAgNZ1/fB6Yiu0rut/4yeXZWDvMmDTZLHhNQDovIEWiUDMIKBeJ0B1jXo3pnxgz8eiIEl+pjjmXx+452UgelD5oGYxAfkXgNx0QOcFBDW9+nuYCoAd7wI/LyjpowSEtAIyfi9t4xMGtHkCuPsJwL/edX4JV3H6V2D9i8CFP8W6vvZPAd0nAp61bt57XC/7f1akmxDSb5XtbwLbZwNetYFRu5y/P1M+8E5LoPAyMPBToHk/1/WTiIiIbksMaArgTgENEIVEPtt5CvM2HUFuSYXH2Aa18M/YekhoGQqD9gZHHS4eFSMZddoCzfqK4HS9TAUlQW1BmaBWD6jfRYzM5WUAueeBgkvOr/MMAhrcAzTsBjToJta2ASKI/PE/MWpmPCuO1esE9H5DbCtw8SiwbwWwf2WZc0pA4x7A3UOAu3qLoijVUZAFbJ4O7PtEPNZ6AmaxLhAeAUD3yUC74Tc2Sph/UXxG79pVa5+bLqaepn4qRhPbPwV0nwTovavfh1vhwmFgaRfAZgYGfAy0eqR8m82vAT+/DdSLA57cdOv7SERERLc1BjQFcLeAZnchtwhzNhzG1/vPwVZydQV4avHI3XXxWId6aBysgF/WKwpqV1JpAO8QMWpiDz52/vVEULt0TKyHAwC/COD+mUDL/uVHjizFwOH1wN4VwIkfSo97BgKtHwPaPA6EVHELB1kGflslNv22h742T4j3Tj8AbJokRtMAMfLXazbQOP7q5yzIElP7LhwSt8zD4hz28wfdBUR2BRp0FfdeZQrCWM2iLH3qp8DR7wHZ6nxuvwigzzygae+qfb5bzWYDlvUCzuwE7uoFDFpV8cif8TywIEqEuKe3ij8UEBEREVURA5oCuGtAs0vLLsQXe85g9e4zOJ9T5DjeoUEtDGhbF41qeyHYx4BgX33Vy/TfbKYC4MBqoOCimILoHQr4hIifPWqJaY2WYlH048SPIlyd3Q3YyuwBp/UEurwoyrBrPa79npf+BlL/C+z/HMhLLz1ep60Iaq0eEdsQlCXLgM0qAuG3LwGnfhbHazcHHngHqF9mL0CrRYzabftXacBq0hO4KwHIvyQCadlb3gWgKLuSztqDyhX/mQhuKcKaSgMc+EJMB7WL6Cg+h0eACIs5JVsmNHsA6D1XeUVTdv0H2PCymDY7aifgV7fytmueAQ6sAloNAAZ8dOv66ApWC/DjXBHW+74DeAW6ukdERES3NQY0BXD3gGZntcnYfuQCPt91GlsPX3CMqpXl76lFSElYC/U14K4QHzQL80GzUN9rV4W81YrzxLqvE9sBSEDss9ULHVYL8PcWMUXxr02loU+lAdR6MRJls4p72eb8Wo0H0H0C0HFU5VMkC7OBH+cBO5c6B8rK+NUDgpsBtZsBwc3Ffe2mIqCe2iEC6smfSkfnyvIKFkVX2jwB1L6r9LgpH/jhTSBlseiDzhu491Wgw8iaK5hSVQVZwPY5wO6PxHfc5y2gw9NXf83534D37xFr/V44cPUwdzsryAKShpWO9kbEAkPWVW0/QiIiIqoQA5oCMKCVdz6nEKt3n8HPRy8iI7cIGcZimCy2q74myFuHZqG+aBbqg2ZhvrinSRCCfe+wXxTzMsXIzL7/AhePXL3tXb3ESFRA/aqd++IxsTl4UbaYmuhVu/zNr07V9/fKyxRB7eRPIqy2TBQjdFdb65ZxEPjmBeDsLvE4tDXQfoT4LD6hlb+uJlgtoujMtn+J6asAEPUo0P/9axebAYDlD4jP3nmcmFZ6q1w8Bvw0X0yFbTvs+vZjy8sUgdgj4NptM/4EVg0CLp8EtF7iDwbFOUDLh4FHPqrad0RERETlMKApAAPatcmyjJxCMzKMxcgwFiHDWIRz2YX4KyMXh8/n4sSlfFx5hUoS0CGyFh6IDkevlqHKG2G7EbIsimvYLKKUu6R2vlfrlF9wozI2m5h6uXk6UJRTejz8bqBpH7FGLaRl+fVfBVml2yVknwYMvqICp18E4B9xfcVijm8HNk4EMg+Jx8EtgF5viOIvVXVkI/D5YyUbV/9Z8b+HLIvbzQgzNpvYOHvza6VVTA3+QMfnxEhkZdU6bVaxNnDPx8CxzSJoRf0DiBsFhLaq+DWHvhHTOM354jse9LmYJvvfh8Xau64vAT2m3fhnolurOE9Mv+b2EERELsWApgAMaDeuwGTB0Yw8HE434tD5XKSeycZvZ7Idz6skoGPDQDzQOhy9WoWillc1KyLSrZN3QRRL+WsjcG6v83N+EWJzaFN+yX52x53DXEU8A0vDmldtEV4MfoBHyb3BT0wZ/fU9UagFECNJ900B7h52/VMtbTZgUTsg628xkhn7jDh28YiYCno6RdznpgMtHhTTUCPaX9972F0+CXw9WozYAUD9zqLS6KVj4rHWC2j/JBA3unQkMjddTJvdu6K0suiVGnYH4saIaqKSJPr/4zyxzQAgCuD8Y3lp+Nu/Elj7nPj5wUViqwhSJlM+kP47kJZaert4VIyeD/hYVKMlIiKXYEBTAAa0mnH2cgE2/H4e3x44j9/Olv7yrlZJCPMzoLaPHrW99Qgqua/to0eQtx4Bnlr4GLTw9dDAx6CFj14D1c3YTJuqLzddjPIc2ShGt+wjRFfyCQMCGojqmUU5QM4ZIPuMmHp3PSS1WGfWbcKN7RNnLyziWwcIiwFO7yidLlmRuh2AuOeBZv2qFghlGdi7HPh+CmDKE0Gs50yg3QixHvHPr4Gf3i7dZ0+tF3sCFmQBRzaUrjn0qAW0GQy0HS7WJKYsFK+1r2ms3Qzo+DxwLFmMngFA7HNAz9fL93Prv0TREJUGGPylCNKkDOm/i+vl1A5R1OXKNat2Kg3Q922g7dBb2j0iIhIY0BSAAa3mnb5UgPW/p+HbA+dxMM14Xa+VJMBbp4GvhxYhvno0rO2NhrW90DDIG42DvVCvlhd0Gq63uWVMBaIoxelfxV/7AxoAtRoCAZGAzrPi1xTliKCWfVqEtoIscawou+Q+RwSTohwgNAqInyEKodxwX/OBt1s4V7/UegJ12wP1O4m90vQ+ogDJ718AVpNo41cP6PisKKZiqOS/CTnngHVjRAEZQOyrl7hYfBdlybLY1uDHt0rX9tlFdATaPQm0eKh8YY/Lp4Cd74vppqa80uNqnagI2ubxivsly8Cap4HfkwC9LzDie1FM5laxj1Lmni/5N82+4j5HfEetB96cf+OKmIuAtH3iGj2zU1RBbfO4+Pe8kf0Gq8NSDPy5TuwNeeZX5+e8Q4HwNqW34OZiavEf/xPPx40W6yc55ZGI6JZiQFMABrRb63xOIdKyC5GZW4zMPBMyc4txMa9YPM4thrHQDGORBcYi8zULkwBiRC4iwAPBPgZAEtMpVZIEqeQeAPQaFXwNWvh6aOHnUXrv56GFv6cWgV46BPno4aPXQKpoby26fR1aDxxcI0bQ6ncSG5NX9Et6bob4JXrPR6XbHmgMIuQAV6y5k0TgsBSJNj2miRGtq61lk2Xg1C9iSqOHP3D30MrXmJVVlCNes/N9ALKY0hjR4eqvsRQDnySKEUO/esBTm8W2FIAovmI8J6ZlXj4pRkdVakCjFyN8Gl3pvcZDFKYJaFB5UAVE8D6+veT2g9gOoyrCYoDoQUDUAOc9++xM+SWVWH8Q1UnzMgHvYDFN1DvE+d5mEWHs9E4xXdBmLn++gEhRnbTVIzUferLPiCI3+z4p3cNRpQGa9xNrDMPvBnzDyr9OlkVF1e1zxOO7egOPfHj7rmklciVTAfD3ViCyc9WKLxGVYEBTAAY05SoyW5FbZEFukRk5hWacyy7E8cx8HM/Mw98l9/km67VPVEU6jQpBXjoEeusR5K1DkLce4f4eqOPvIe4DPBDmZ4BBy79o37HMhWLPvZT3rl2ps047IHGJ85YFNUWWxZS4qgaLgizgw3ixBi/oLjHN8/JJMYJZle0cruQZJEa+apWMmPqEAef3i1CWddy5rdZLtDP4ibWGHv6law713sDJn8WoYtktKxrfL7aA8A4WYey4fS/DCoJWVXgFA/U6iptsA375d2lQCm4B3DdVFLy58g8yNqtYC3Z+v9gLMaID0PDeqk15tVlFoZe9y8WWHPYpjD5hYvrq3UMqDmUV+f1LYO3zgLUYCIkShWD8I6r66Yno4jHgiyHAhYPif4MPLRbreYmqgAFNARjQbl+yLONCbjH+zsxDdoFZ7BMty7CV/M/FJsuw2YBiiw3GkpBnLBT3OSUjddkFJlzKMyGvuOq/tAZ56xDuL8JamJ+4Dy3zs0s39aabw2YTRT7s0x4BOG0ErtKK4KPkcvaX/hYhrTDL+bhaJ6o/BkQCvuEiSFhNYuSt7L0pT4yO2UcUKyOpgbrtRFGThveKzdwr2/fPLv8i8Mca4LfPxXTEyvjWFdU7G3QTwTD/ghj1y8twvrdZgTp3i2mr9WLFqF/Z8FWcJ/Ya/OXd0jWRddoBXccDxbklhTr2i3Vi5nznPniHiFGvmH+KCqZXyj4NpH4qbsZzpccbdAPaPyWCYHWmVp7ZDaz6p/jMXsHAwE9FYOQoP9HVHVwrCjeZcp2Pt39KTBu+nqrC5JYY0BSAAY0AMVp3Ma8Yl/JMjvsLuUU4l12EtOxCnMsuxLnLhSg0V23EztegQWBJ0ZNaXjoEeOpQy1vcA0Cx2YZiixXFFhuKzOK+2GKDt16NEF8DQn0NCPET96G+Bvh7ajn9kq5fxkHg8AYRxAIixc0n7PqCZVGOGH3LOl66lULOWRFQG3YXVSuvNgXyWjKPAL+tEqNGliIgsktJKLunfNC6UYWXRUjbuRQwF1TcRusp9gAMqC9GxMoG1NAoIPqfYl/Bs3vEGsFjW+AI7x61xLTNtsNuzshq9hmxXUTGH6XnD2kpRgGDm5f83Lzq++3lnAPO7RGVWc/uFVtZqDSivL/W0/leYwCsZlEUyFIsRpctReLeahLXVGhr8Z2ERYs+VbYO9UpWC5CXLvqTc0ZcT8ZzImjXbipuQU3F9FX+d4+qymICkqcBO5eIx/U7Aw8tAn5dAuz6QByr1Ujsp1ndqr23miwDKYtFdeN7XuEo4C3CgKYADGhUVfb94M5eFuvo0o1FOJ9ThPScIpzPKcT5HPG4Kmvnrpdeo0ItLx08dGp46TTw1KnFTa+Bl04Nb71YTxfgqYW/p67k59J7T52aAY/ILjdDbFlwZKOYOhgWA4THiPugJqVTSS0mEdJ+Wwkc2VT5lMsG94h1hc37ifV8N1NxrihIU7ay55V8wkXF07JTSu33EsTo4Lm9onhLTZFUQGATEdg8/EWxFkuhCHRlw13BJcCYBshV+GOX3q80sNVqINaE6rxEiNR5i591XiJM2s9vKSzz3kXi30zvK74fj1ql9/bCPOYi8UeHS8fEqLP9Pvu0WINZpx1Qt624969XcWC0FIvXZR4GMv8Sf9SQbeIzyjYRPGWb+GVbrSndWsQ+Ddix1YhWrJsy5YsRbFO++EOCKU+MVIdFi5Fig9/N/Je7eS4cFgWKIIv1k3Xa3rpZBjlngaRhYmo0AHQeB9w3rXR68t9bgbWjgNw0ca12GS8qBV9rtP9mslrE9VPVqeqFl8VU5yMbSg5IYtS/++Tr33rmVigyisJZsk38+1f1DzYKxICmAAxodDPJsozLBWZk5RcjK9+MrHwTsvJNuFxQcp9vAiTAoFVDr1FBrxH3Bq0aOo0KuUVmZBjtoU9sCn65oJrrcMrQqVUI8BJhLcBT5/jZW69BodmK/GIrCkwW5JusKCgW98VmK1QqCRqVBI1aglqlEj+rJLFez1tfMs1TTO8M9TMg3N8DARztoztRQZaosPjbKjEK5RUstkdo8wQQ2Kjm399cKEYbL/wpRkYvHBI/X0/oklRAcMvSwBHWWhwzF4og4HRfKAKDxkOEmbL3ao0YTU0/AJw/IO7ta/yqSqURo3B+EYBfXbFOErIIOJmHRWiqLJDeDPaQl58Jp+nLV+MVLKbz1rlbBLvMw+LfJOt41QLnTSGJwFq3XUl4bC9GUa/1S7/VLCqpFl4Wt6JsEf69Q8QfJbxDqjdaWWQUhZhSPy0NR3beIWKKb7MHxB8xbvYfL+yObRHVawsuiVDffwnQrG/5doWXgY0TxDpjQIwA3/sq0KBrzU17zMsUW6T8tQk4tlVcJx1GigB5tW1k0vaLNXTZp8S09EY9xL6kgJjK/chH4g8IrmY8LwLk4W/F+mH7H7EMfmK2Qbvh4nq9zTCgKQADGildkdmKC8Zi5BSaUWCyoMBkRX7JvT1M5RZZkFNowuV8My4XmJBdYEZ2oQmXC6pWDfNm0mlU8NSpoVGpoFWLcKdVqcS9WgWdRgUPrRoGrRoGrQoGjRp6rRoeWjUCPLUI8/dAeMm6vnB/j0qLshSZrSVVP80wWeSSEUU1PHUaeGjVUHP/PKopBVliWuGtLttfWV8un6hkW4NsMQoY0lL8Qh8WXXO/iOami7CW8bsIL45QV+am8RDV9PzqioIwVwsV5iJR5MYegnLOlows2UeX8kofW4rFKNqVQVLrIYJgUY5Yi1mQJX5JvzJM6X1FyA5sLKbABTYWI6tZJ0QYP7tHTDO9WoEdva/Ys7B2U8CrtvhskkqMfEkqMZIkqcS/R7HReZsR+81iKhkVvGKEUOsl1kae2ytG9q6k0opf4lXqkvctcw+I9yu7XUdl/bd/B4FNgKDG4nPovMW1rvMWRX60JdfPqV9EKPvz69K9MSU1cFcv8f0fTRbva6fzFtPzwmJEX4qMIiAWG0t+Noo+h7Yus/VEi/IjXLIspsOe3SMC4bm9otorZPHaRz8Ro61Xc3AtsP7F0vW5ap0IPY3jxS24uXNYLcwGzv8migelpYrrXJJK1vLWL70PiBQ/G8+JQPbXd6KfFf0BQO8LdBoDdHzOeYqyfX/NjRNEkSD/+uIzhceIdbvrxoq1dR61gP5LgbsSrv5Zq0uWxai0pah0RNo+1dlcKLYNObxB/O+jrKC7xGvKXqeRXUVQa9bv1o5Y3gAGNAVgQKM7mSzLKDBZHaHNPpp3OV+Et/xii9NUSQ+duPfUa2DQqGCTAatNhtlmg9Uqw2KTYbXJKLZYkWEsRnqZqZ3nc4pwMa/4pn+GAE8tQv08YNCqSoq8VG0bBoNWBU+dBn4eWtSr5YkGQV6IDPREZJDYR69OgAdDHJG7sdlEGCjMEsHAt47Y5uFao0fmQvGL+bk94pd0nVdpIKvdTKztvBUzB/IuiF/6z9kDSmr5YhiVksR6UY8AMbVS5w0Yz4pfpqs8WimVTCktLD0U1BS4+wmxv6F3sDhmMQEnfxIjK0c2VG96rVoHhLQSYc1eObayqbp3DwV6zy2/p2RlctPF/pR/fQfkXBF6fcKBRveK0eS0/eIPIDcitLUIrnf1EkV/tr5euq7UMxDo8qIoYCLbgPXjgQOrxHNN+wCJ7zlvEZB1HEgaLr4LQIS8HtNv7I9FNquYomsvlpSWWnHBpMrUbS9GLJv2FWtvbTYxpXTPx2LUz35teQaVFE3SlRwrqU5sn/4r28T3ULdd9T/LTcKApgAMaEQ3T7FFjPYVW6wwW2VYrCLcmS02WGwyzFZbaWEUsw1FFisKTVYUmW0oNFuRlV+M8zmiMMv5nCIUXGMbBZUE+HpooVWrUFgysljV/1pq1RLC/DygUUuQIPbNs++hJ0mSY089lUr8rC7zs1atQpifAZFBXogMLLkFecJT57wuQJZlZBeYcaFkn7/MvCLoNWqE+OoR7MOKn0R0g2xWEVis5pK1blbne8hitMYjQEw7q2jU0lIsfvG/dExsM2Ffh1d4WYx2FeeJEFg2xOl8gKhHxBTfOm2vHk5tNuB8qhhxMZ4T/TH4inu9T8nPfiIQ2ANCWqoYZayIpAZCWohgUKcdEBErRvyqQ5bF5z22WdxO/ixGgK7kX790nWpYtBiZzT4FXD5Vcn9S/Jx/QYzeNuwuRrea9Cw/FdFmA/78Ctg2W7w3IAKo3ge4+Jf4fPHTgU5jK1/zmDxNFDsCxL6KkV1ESFNpRd/UmtKfbRYx9dBqv5lKCwBdOCxGB68WxiRVmZHpkluthkCzPiJE+oRW/tqcc2I/yH0rqhbSH/lI7I3pYgxoCsCARqRMsizDWGjBeWMhzmcXwWS1iY3GDVr4eoiRMS+dBqoyo2CyLKPYYhPTQIstKDRbcSnPhJOX8nHyYj5OlNxOZRXUyNTPEF896tfyQrHVhkxjETLzimG2Xv0/3wGeWkdYC/LWOzZQt9/7e+jg66GFt14DdckaQLVjXaAEjUoFtSQBEhwbtNsDp/3/281WmyMsW8oEZ1kGannp4O+hdfoeiYicyLIYRbRPL/UJE1NIa/L9Lp8sDWu56UBoKxHKanKqrrkQOLVDBDW9T2kou9p6sbJMBSIEV2W9ndUithr54U1RzRQQ6/YGLBOba1/LofXA18+L6bE3yl69NjxGjFiGxYg1ovZpwjc6Omy1iGmf6QdKpv6qSs4plXmsEqFWAWvWGNAUgAGNyP1YbTLO5xQiPacIVpsMGWLfPFmGYz89qyxDLtlLzyrLsNlkMeVTlmGy2HD2coEIfZfEfU5h5cVcAjy1qO2jR20fPYrNNmTkFiHDWHzL1wdWRqOSEFiyObv9Fuitg9UmPmuxxVpyb4PJYoPJaoNeI6aQepWs+/MqM1VWry0tfmMvhmPQinuVSnz/csn0WfvehVYb4KVXo46/B/w8WGiGiNyEpViMMmUeEaX0fUKq/trs00DqZyI0W81lRstK7m2WkjWK9puuzGOdGAkLjynZ15OzOewY0BSAAY2IbobL+WKk7nRWATy0agT7GlDbR48gb12F0xjtI4QirInKnfa1gjmFZmQXmpFTUuwlp9CMgmIrrLLstBbQYrPBdh3/7yBJcBRs0agkyAByi6q+Sfut4qlTI9zfA+H+Hqjjb0C4nwf8PbWw2mRYZcBqE1Nm7d+FSpLEaKNnaaVSf08tArx08KrmFhNWm8w1ikREbogBTQEY0Ijodmaz2Uf7ABmlo4AyZEd406hEBc2KAofJYsOl/GJczBWbtGfmFeNiXjEu55ugVqmg14jKm3rHTQ2tRkKx2ea0LUOByeLYrsG++XrZTdiLLWKtoSyLtYNqVemaP/vPuUVmXMwz3dTvR6OSRNVQnbqkemhpFVGdRlXyOSwoNFlFZVSTmBprtsrw0qlRy1uHWl56BHrpUMtL57jXqkv3d7LnP/u3qyr5PCpJglqFMj+LfwfH6GJJFVP76KJBp4K3XlQh5QgiEZFrVDUbKHA3OiIiUgKVSoIK1f9lXqdRIczPA2F+Nbie5DoUma2OQjHnssWm8GnZhTAWWqBWl67BU0ul6/CsNlGMxT4CebmgdIsJi01GbrEFucXXP1KYb7IiP6sQZ7IKr934JlJJgJdeA2+9Bl4lN71GBYvVXmxHhsVqc1RYlSCVrln0FGsK7T/7eYj1jD4GjWP9po9BCx+98/pN+3RW+xRWs9UGleS8TYb9Z65XJCJiQCMiIjdh0KrRIMgLDYJurAiALMsoNFuRU2gWVUJNVhSarSgquRWWVBL10KnhoVPDU1uyh55ODU+dWDtnLLIgK78Yl/LERvOXSjaez8o3wVIyPGmf4OKY5lKyhtG+rk4uWc9ok8Vop6mkkmlxST/KjjTaq5baZDH1tCann0oS4KlVO9ZUXs9UWbVKgpdODT9PUbTHHgL9PLTw9dDCoFFBKhkxVKtKRklLHquksgVuyj5WQSUBUpk/NpQdRNSpVajto3cU0yk7gklE5AoMaERERNdBkiR46jTltj64HoHe+hsOitfDZpNRYBYVSPOKLWXuRZEW+9pBjVoFbcm9mLYqI6fQjMv59rWLJmQXmh2jiblFYu9AY6EFuUVmFFvEVNP8q2xjoVOrYJNlRxAty2qTYSyywFhkAXBrRxcBEdwCvXSo7WNAiK9eTDlVqaBWS44g6AiAKhH5pJLwV1LwFCjZSsNbr4Fvmeqw9sDpYxBVU+2f3rHQpOxUYpQtLiRCuAwZaklMZdVpVNCqVdCqJU5ZJboDMaARERHd4VQqCd4lUxuvo47bdSsyW5FbJAKgWiVBXxIkdCXrDTWq0kAhyyVTKm02x9RKs1VGXrEFOYVmGAvNMBaJwjY5JQVuTCXTL+2jhvYqqFZZdlTutFjthW7EvbXk+av1+YJRrJG02mRczDPhYp4Jh6qx/7Er6EqCmkatKp2mWyZI2tcn2qe1inu101RXz5J1lPZRXg+tGPH10KrLrXVUlUwDliSg2Fy6BrTIYnXsQ2my2uChVcPHUDLt1aCBj0FTbvuSm8Fqk3EmqwBmqw0RtTxh0LJiIN3+GNCIiIjopjCUFEmp7XPtvZokSYJOI0EHZUwptNlkZBWYkGEsEhvAG4uRVWASYc9qD4FirZ6tJADac1/Z6ahyyZYZ+cWWkpDpHDiLzFXfAsM+KmcvemMr2UKiLJPVBjFgWfmopVJIJSOLeo0aupJQqVVLJaOBYj2iv4cWIb4GBPuKUcwQHwNCSn7OK7bg6IU8HM3ILbnPw9+ZeSgu2VZEkoA6/h5oWNsbDYO80LC2mNIc5C1eayw0l/m3EI8LzFbo1GWKFTm28LAXMVI7ihmVfXxlMBaj0KXHqlvllQhgFccaxSqOREREVJZYlyd+9Sqt0ik5Hts3hJckVPgLvtUmw2wVo1Qmiyi6YraINYjOI4g2x0hiscXmNL1V/CymvOaXVEctKKk2av+5sORn++jklfsL2mQ4goyh7P6EWhG+CktGU8XNDLO15n7dtIcnJW3toVVLCPTSX7EPpPjZJouR4rxiC/KKxL+BfeRZrxF/4Agu2d8y2FePYB+xtYqnTg2LVfz7lx19NlttkCAKAHno1PDS2e/V0HBNpaKwiiMRERGRwug0N/YLs5i+qL6tpvLJsgiJxiIzcosspcGyJFzYQ4fJakN2gQkZxmJkGItKbuLni3nF0GlUaBzsjbuCfdA4xBtNgn1wV4g36gZ4QiUBl/JNOJ6ZjxMX83A8Mx/HL+bjeGYeLheY4WvQOIrNiHWBYm2gh1YNs9VWMl1TTNk0lWzhUWS2OoJwseXKeyssJaOrFput5L40hJqtMtKNRUg3FrnwmxdTYPXa0nq8UsloLICSPwRIju1Syo4I2tc5epYEPjElVu2o/uqlU5ffXqXkxBIAH4MGgV5iHWegt9hD8sprXy4JqvbRTGOhGTZZ7FfpaS+ypNM4iitdbUTSYrWVjJKWjFgXlY5aGwstiG8RckvX/d4oBjQiIiIiqjGSJDmmvwb7VO8clpLtGa62hs0+UtWhQa1q9vTGyCWjjWarjMsFYv9HcSv5OdeES/nFUEsSvA2lawB9yvxcdk3kBWNRyX0xLuQWo7BkOmbZ6ZT2qaGyDBSYLI6RUPtUWFNJ8FUCX4MGgd76kmJApYGsKiQJosJqScEcAI6COkD5qb9XCvM3MKAREREREd0st8NUPalkaweNGvDQeSDc3zV7QMqymPJaaLIi32RFsVmsT7SvkYTjkVjXWHYUs3TqpBgpLDBZy02JFfdWlF0lVXbBlE2WYSy04FJ+sWP7EJuMMhVanenUqpKRTQ0kCSg0WVFgFtNs7esLZVlMD74WT53aUTHVXj3V10OLUF9Dtb5LV2FAIyIiIiK6Q0iSBL1GDb1GDX9PV/dGFODJKTQ79ntUqyT4lQlPV5uua7WJfScLTBaYrbLT1hZAaSEdjVoFH4PmjtnHkAGNiIiIiIhqhEolIcBLhwAv3XW/Vl1mixB3cmfETCIiIiIiojsAAxoREREREZFCKCKgLV68GJGRkTAYDIiNjcWuXbuu2j4pKQnNmjWDwWBAVFQUNmzY4PS8LMuYNm0awsLC4OHhgfj4eBw9etTx/Pbt20vKjJa/7d69GwBw8uTJCp//9ddfb/4XQEREREREBAUEtNWrV2P8+PGYPn069u3bh+joaCQkJODChQsVtt+xYwcGDRqEESNGIDU1FYmJiUhMTMQff/zhaDN37ly8++67WLp0KXbu3AkvLy8kJCSgqEjsRdGpUyecP3/e6fbUU0+hQYMGaNeundP7bd682ald27Zta+7LICIiIiIitybJZWtkukBsbCzat2+PRYsWAQBsNhsiIiIwZswYTJw4sVz7gQMHIj8/H+vXr3cc69ixI2JiYrB06VLIsozw8HC89NJLePnllwEAOTk5CAkJwfLly/HYY4+VO6fZbEadOnUwZswYTJ06FYAYQWvQoAFSU1MRExNTrc9W1d3CiYiIiIjozlbVbODSETSTyYS9e/ciPj7ecUylUiE+Ph4pKSkVviYlJcWpPQAkJCQ42p84cQLp6elObfz8/BAbG1vpOdetW4dLly5h+PDh5Z578MEHERwcjC5dumDdunVX/TzFxcUwGo1ONyIiIiIioqpyaUC7ePEirFYrQkJCnI6HhIQgPT29wtekp6dftb39/nrO+dFHHyEhIQF169Z1HPP29sb8+fORlJSEb7/9Fl26dEFiYuJVQ9qcOXPg5+fnuEVERFTaloiIiIiI6ErutalABc6ePYvvvvsOX3zxhdPxoKAgjB8/3vG4ffv2SEtLw7x58/Dggw9WeK5JkyY5vcZoNDKkERERERFRlbl0BC0oKAhqtRoZGRlOxzMyMhAaGlrha0JDQ6/a3n5f1XMuW7YMgYGBlYausmJjY3Hs2LFKn9fr9fD19XW6ERERERERVZVLA5pOp0Pbtm2xZcsWxzGbzYYtW7YgLi6uwtfExcU5tQeA5ORkR/sGDRogNDTUqY3RaMTOnTvLnVOWZSxbtgxDhgyBVqu9Zn/379+PsLCwKn8+IiIiIiKi6+HyKY7jx4/H0KFD0a5dO3To0AELFixAfn6+o2DHkCFDUKdOHcyZMwcAMG7cOHTr1g3z589H3759sWrVKuzZswcffPABAECSJLzwwgt4/fXX0aRJEzRo0ABTp05FeHg4EhMTnd5769atOHHiBJ566qly/VqxYgV0Oh3atGkDAFizZg0+/vhjfPjhhzX4bRARERERkTtzeUAbOHAgMjMzMW3aNKSnpyMmJgabNm1yFPk4ffo0VKrSgb5OnTph5cqVmDJlCiZPnowmTZpg7dq1aNWqlaPN//3f/yE/Px8jR45EdnY2unTpgk2bNsFgMDi990cffYROnTqhWbNmFfZt1qxZOHXqFDQaDZo1a4bVq1djwIABNfAtEBERERERKWAftDsZ90EjIiIiIiLgNtkHjYiIiIiIiEq5fIrjncw+OMkNq4mIiIiI3Js9E1xrAiMDWg3Kzc0FAO6FRkREREREAERG8PPzq/R5rkGrQTabDWlpafDx8YEkSTX+fvaNsc+cOcM1b1RlvG6oOnjdUHXx2qHq4HVD1aG060aWZeTm5iI8PNypCOKVOIJWg1QqFerWrXvL35ebZFN18Lqh6uB1Q9XFa4eqg9cNVYeSrpurjZzZsUgIERERERGRQjCgERERERERKQQD2h1Er9dj+vTp0Ov1ru4K3UZ43VB18Lqh6uK1Q9XB64aq43a9blgkhIiIiIiISCE4gkZERERERKQQDGhEREREREQKwYBGRERERESkEAxoRERERERECsGAdodYvHgxIiMjYTAYEBsbi127drm6S6Qgc+bMQfv27eHj44Pg4GAkJibiyJEjTm2KioowatQoBAYGwtvbG4888ggyMjJc1GNSojfeeAOSJOGFF15wHON1Q5U5d+4cHn/8cQQGBsLDwwNRUVHYs2eP43lZljFt2jSEhYXBw8MD8fHxOHr0qAt7TK5mtVoxdepUNGjQAB4eHmjUqBFmzZqFsvXseN0QAPz444/o168fwsPDIUkS1q5d6/R8Va6TrKwsDB48GL6+vvD398eIESOQl5d3Cz9F5RjQ7gCrV6/G+PHjMX36dOzbtw/R0dFISEjAhQsXXN01UogffvgBo0aNwq+//ork5GSYzWb07NkT+fn5jjYvvvgivvnmGyQlJeGHH35AWloaHn74YRf2mpRk9+7deP/999G6dWun47xuqCKXL19G586dodVqsXHjRvz555+YP38+AgICHG3mzp2Ld999F0uXLsXOnTvh5eWFhIQEFBUVubDn5EpvvvkmlixZgkWLFuHQoUN48803MXfuXCxcuNDRhtcNAUB+fj6io6OxePHiCp+vynUyePBgHDx4EMnJyVi/fj1+/PFHjBw58lZ9hKuT6bbXoUMHedSoUY7HVqtVDg8Pl+fMmePCXpGSXbhwQQYg//DDD7Isy3J2dras1WrlpKQkR5tDhw7JAOSUlBRXdZMUIjc3V27SpImcnJwsd+vWTR43bpwsy7xuqHITJkyQu3TpUunzNptNDg0NlefNm+c4lp2dLev1evnzzz+/FV0kBerbt6/85JNPOh17+OGH5cGDB8uyzOuGKgZA/uqrrxyPq3Kd/PnnnzIAeffu3Y42GzdulCVJks+dO3fL+l4ZjqDd5kwmE/bu3Yv4+HjHMZVKhfj4eKSkpLiwZ6RkOTk5AIBatWoBAPbu3Quz2ex0HTVr1gz16tXjdUQYNWoU+vbt63R9ALxuqHLr1q1Du3bt8I9//APBwcFo06YN/vOf/zieP3HiBNLT052uHT8/P8TGxvLacWOdOnXCli1b8NdffwEAfvvtN/z888/o3bs3AF43VDVVuU5SUlLg7++Pdu3aOdrEx8dDpVJh586dt7zPV9K4ugN0Yy5evAir1YqQkBCn4yEhITh8+LCLekVKZrPZ8MILL6Bz585o1aoVACA9PR06nQ7+/v5ObUNCQpCenu6CXpJSrFq1Cvv27cPu3bvLPcfrhipz/PhxLFmyBOPHj8fkyZOxe/dujB07FjqdDkOHDnVcHxX9fxevHfc1ceJEGI1GNGvWDGq1GlarFf/6178wePBgAOB1Q1VSleskPT0dwcHBTs9rNBrUqlVLEdcSAxqRmxk1ahT++OMP/Pzzz67uCincmTNnMG7cOCQnJ8NgMLi6O3QbsdlsaNeuHWbPng0AaNOmDf744w8sXboUQ4cOdXHvSKm++OILfPbZZ1i5ciVatmyJ/fv344UXXkB4eDivG3IrnOJ4mwsKCoJarS5XNS0jIwOhoaEu6hUp1ejRo7F+/Xps27YNdevWdRwPDQ2FyWRCdna2U3teR+5t7969uHDhAu6++25oNBpoNBr88MMPePfdd6HRaBASEsLrhioUFhaGFi1aOB1r3rw5Tp8+DQCO64P/30VlvfLKK5g4cSIee+wxREVF4YknnsCLL76IOXPmAOB1Q1VTleskNDS0XDE9i8WCrKwsRVxLDGi3OZ1Oh7Zt22LLli2OYzabDVu2bEFcXJwLe0ZKIssyRo8eja+++gpbt25FgwYNnJ5v27YttFqt03V05MgRnD59mteRG+vRowd+//137N+/33Fr164dBg8e7PiZ1w1VpHPnzuW28vjrr79Qv359AECDBg0QGhrqdO0YjUbs3LmT144bKygogErl/KupWq2GzWYDwOuGqqYq10lcXByys7Oxd+9eR5utW7fCZrMhNjb2lve5HFdXKaEbt2rVKlmv18vLly+X//zzT3nkyJGyv7+/nJ6e7uqukUI899xzsp+fn7x9+3b5/PnzjltBQYGjzbPPPivXq1dP3rp1q7xnzx45Li5OjouLc2GvSYnKVnGUZV43VLFdu3bJGo1G/te//iUfPXpU/uyzz2RPT0/5008/dbR54403ZH9/f/nrr7+WDxw4ID/00ENygwYN5MLCQhf2nFxp6NChcp06deT169fLJ06ckNesWSMHBQXJ//d//+dow+uGZFlUF05NTZVTU1NlAPLbb78tp6amyqdOnZJluWrXSa9eveQ2bdrIO3fulH/++We5SZMm8qBBg1z1kZwwoN0hFi5cKNerV0/W6XRyhw4d5F9//dXVXSIFAVDhbdmyZY42hYWF8vPPPy8HBATInp6ecv/+/eXz58+7rtOkSFcGNF43VJlvvvlGbtWqlazX6+VmzZrJH3zwgdPzNptNnjp1qhwSEiLr9Xq5R48e8pEjR1zUW1ICo9Eojxs3Tq5Xr55sMBjkhg0byq+++qpcXFzsaMPrhmRZlrdt21bh7zVDhw6VZblq18mlS5fkQYMGyd7e3rKvr688fPhwOTc31wWfpjxJlstsz05EREREREQuwzVoRERERERECsGARkREREREpBAMaERERERERArBgEZERERERKQQDGhEREREREQKwYBGRERERESkEAxoRERERERECsGARkREREREpBAMaERERAokSRLWrl3r6m4QEdEtxoBGRER0hWHDhkGSpHK3Xr16ubprRER0h9O4ugNERERK1KtXLyxbtszpmF6vd1FviIjIXXAEjYiIqAJ6vR6hoaFOt4CAAABi+uGSJUvQu3dveHh4oGHDhvjyyy+dXv/777/jvvvug4eHBwIDAzFy5Ejk5eU5tfn444/RsmVL6PV6hIWFYfTo0U7PX7x4Ef3794enpyeaNGmCdevW1eyHJiIil2NAIyIiqoapU6fikUcewW+//YbBgwfjsccew6FDhwAA+fn5SEhIQEBAAHbv3o2kpCRs3rzZKYAtWbIEo0aNwsiRI/H7779j3bp1aNy4sdN7vPbaa3j00Udx4MAB9OnTB4MHD0ZWVtYt/ZxERHRrSbIsy67uBBERkZIMGzYMn376KQwGg9PxyZMnY/LkyZAkCc8++yyWLFnieK5jx464++678d577+E///kPJkyYgDNnzsDLywsAsGHDBvTr1w9paWkICQlBnTp1MHz4cLz++usV9kGSJEyZMgWzZs0CIEKft7c3Nm7cyLVwRER3MK5BIyIiqsC9997rFMAAoFatWo6f4+LinJ6Li4vD/v37AQCHDh1CdHS0I5wBQOfOnWGz2XDkyBFIkoS0tDT06NHjqn1o3bq142cvLy/4+vriwoUL1f1IRER0G2BAIyIiqoCXl1e5KYc3i4eHR5XaabVap8eSJMFms9VEl4iISCG4Bo2IiKgafv3113KPmzdvDgBo3rw5fvvtN+Tn5zue/+WXX6BSqdC0aVP4+PggMjISW7ZsuaV9JiIi5eMIGhERUQWKi4uRnp7udEyj0SAoKAgAkJSUhHbt2qFLly747LPPsGvXLnz00UcAgMGDB2P69OkYOnQoZsyYgczMTIwZMwZPPPEEQkJCAAAzZszAs88+i+DgYPTu3Ru5ubn45ZdfMGbMmFv7QYmISFEY0IiIiCqwadMmhIWFOR1r2rQpDh8+DEBUWFy1ahWef/55hIWF4fPPP0eLFi0AAJ6envjuu+8wbtw4tG/fHp6ennjkkUfw9ttvO841dOhQFBUV4Z133sHLL7+MoKAgDBgw4NZ9QCIiUiRWcSQiIrpOkiThq6++QmJioqu7QkREdxiuQSMiIiIiIlIIBjQiIiIiIiKF4Bo0IiKi68TVAUREVFM4gkZERERERKQQDGhEREREREQKwYBGRERERESkEAxoRERERERECsGARkREREREpBAMaERERERERArBgEZERERERKQQDGhEREREREQK8f8K5dA9Z9deagAAAABJRU5ErkJggg==",
370
+ "text/plain": [
371
+ "<Figure size 1000x500 with 1 Axes>"
372
+ ]
373
+ },
374
+ "metadata": {},
375
+ "output_type": "display_data"
376
+ }
377
+ ],
378
+ "source": [
379
+ "epochs = np.arange(1, len(train_losses) + 1)\n",
380
+ "plt.figure(figsize=(10, 5))\n",
381
+ "\n",
382
+ "plt.plot(epochs, train_losses, label='Train Loss')\n",
383
+ "plt.plot(epochs, valid_losses, label='Valid Loss')\n",
384
+ "plt.xlabel('Epoch')\n",
385
+ "plt.ylabel('Loss')\n",
386
+ "plt.title('Training and Validation Loss')\n",
387
+ "plt.legend()\n",
388
+ "\n",
389
+ "plt.show()"
390
+ ]
391
+ },
392
+ {
393
+ "cell_type": "code",
394
+ "execution_count": 12,
395
+ "id": "c3b04bf7",
396
+ "metadata": {
397
+ "execution": {
398
+ "iopub.execute_input": "2024-04-01T10:06:13.084256Z",
399
+ "iopub.status.busy": "2024-04-01T10:06:13.083932Z",
400
+ "iopub.status.idle": "2024-04-01T10:06:38.988309Z",
401
+ "shell.execute_reply": "2024-04-01T10:06:38.987316Z"
402
+ },
403
+ "papermill": {
404
+ "duration": 25.920465,
405
+ "end_time": "2024-04-01T10:06:38.990405",
406
+ "exception": false,
407
+ "start_time": "2024-04-01T10:06:13.069940",
408
+ "status": "completed"
409
+ },
410
+ "tags": []
411
+ },
412
+ "outputs": [
413
+ {
414
+ "name": "stdout",
415
+ "output_type": "stream",
416
+ "text": [
417
+ "The loss on the test set is 0.008598181701702099\n"
418
+ ]
419
+ }
420
+ ],
421
+ "source": [
422
+ "model.eval()\n",
423
+ "test_loss = 0.0\n",
424
+ "with torch.no_grad():\n",
425
+ " for images, targets in test_loader:\n",
426
+ " images = images.to(device)\n",
427
+ " targets = targets.to(device)\n",
428
+ " outputs = model(images)\n",
429
+ " try:\n",
430
+ " loss = criterion(outputs, targets)\n",
431
+ " except RuntimeError:\n",
432
+ " adjusted_output = adjust_output_shape(outputs, targets)\n",
433
+ " loss = criterion(adjusted_output, targets)\n",
434
+ " test_loss += loss.item()\n",
435
+ " test_loss /= len(test_loader)\n",
436
+ "print(f\"The loss on the test set is {test_loss}\")"
437
+ ]
438
+ }
439
+ ],
440
+ "metadata": {
441
+ "kaggle": {
442
+ "accelerator": "gpu",
443
+ "dataSources": [
444
+ {
445
+ "datasetId": 4705836,
446
+ "sourceId": 7993213,
447
+ "sourceType": "datasetVersion"
448
+ }
449
+ ],
450
+ "dockerImageVersionId": 30674,
451
+ "isGpuEnabled": true,
452
+ "isInternetEnabled": true,
453
+ "language": "python",
454
+ "sourceType": "notebook"
455
+ },
456
+ "kernelspec": {
457
+ "display_name": "Python 3",
458
+ "language": "python",
459
+ "name": "python3"
460
+ },
461
+ "language_info": {
462
+ "codemirror_mode": {
463
+ "name": "ipython",
464
+ "version": 3
465
+ },
466
+ "file_extension": ".py",
467
+ "mimetype": "text/x-python",
468
+ "name": "python",
469
+ "nbconvert_exporter": "python",
470
+ "pygments_lexer": "ipython3",
471
+ "version": "3.12.2"
472
+ },
473
+ "papermill": {
474
+ "default_parameters": {},
475
+ "duration": 32529.008488,
476
+ "end_time": "2024-04-01T10:06:40.496191",
477
+ "environment_variables": {},
478
+ "exception": null,
479
+ "input_path": "__notebook__.ipynb",
480
+ "output_path": "__notebook__.ipynb",
481
+ "parameters": {},
482
+ "start_time": "2024-04-01T01:04:31.487703",
483
+ "version": "2.5.0"
484
+ },
485
+ "widgets": {
486
+ "application/vnd.jupyter.widget-state+json": {
487
+ "state": {
488
+ "0d705fdb53a0460cb06e86e2212618f5": {
489
+ "model_module": "@jupyter-widgets/controls",
490
+ "model_module_version": "1.5.0",
491
+ "model_name": "DescriptionStyleModel",
492
+ "state": {
493
+ "_model_module": "@jupyter-widgets/controls",
494
+ "_model_module_version": "1.5.0",
495
+ "_model_name": "DescriptionStyleModel",
496
+ "_view_count": null,
497
+ "_view_module": "@jupyter-widgets/base",
498
+ "_view_module_version": "1.2.0",
499
+ "_view_name": "StyleView",
500
+ "description_width": ""
501
+ }
502
+ },
503
+ "1a8db5a1fed14afca913a6edb7794b17": {
504
+ "model_module": "@jupyter-widgets/controls",
505
+ "model_module_version": "1.5.0",
506
+ "model_name": "ProgressStyleModel",
507
+ "state": {
508
+ "_model_module": "@jupyter-widgets/controls",
509
+ "_model_module_version": "1.5.0",
510
+ "_model_name": "ProgressStyleModel",
511
+ "_view_count": null,
512
+ "_view_module": "@jupyter-widgets/base",
513
+ "_view_module_version": "1.2.0",
514
+ "_view_name": "StyleView",
515
+ "bar_color": null,
516
+ "description_width": ""
517
+ }
518
+ },
519
+ "1e977edae4d54b5fbd5b7018ffb9858f": {
520
+ "model_module": "@jupyter-widgets/base",
521
+ "model_module_version": "1.2.0",
522
+ "model_name": "LayoutModel",
523
+ "state": {
524
+ "_model_module": "@jupyter-widgets/base",
525
+ "_model_module_version": "1.2.0",
526
+ "_model_name": "LayoutModel",
527
+ "_view_count": null,
528
+ "_view_module": "@jupyter-widgets/base",
529
+ "_view_module_version": "1.2.0",
530
+ "_view_name": "LayoutView",
531
+ "align_content": null,
532
+ "align_items": null,
533
+ "align_self": null,
534
+ "border": null,
535
+ "bottom": null,
536
+ "display": null,
537
+ "flex": null,
538
+ "flex_flow": null,
539
+ "grid_area": null,
540
+ "grid_auto_columns": null,
541
+ "grid_auto_flow": null,
542
+ "grid_auto_rows": null,
543
+ "grid_column": null,
544
+ "grid_gap": null,
545
+ "grid_row": null,
546
+ "grid_template_areas": null,
547
+ "grid_template_columns": null,
548
+ "grid_template_rows": null,
549
+ "height": null,
550
+ "justify_content": null,
551
+ "justify_items": null,
552
+ "left": null,
553
+ "margin": null,
554
+ "max_height": null,
555
+ "max_width": null,
556
+ "min_height": null,
557
+ "min_width": null,
558
+ "object_fit": null,
559
+ "object_position": null,
560
+ "order": null,
561
+ "overflow": null,
562
+ "overflow_x": null,
563
+ "overflow_y": null,
564
+ "padding": null,
565
+ "right": null,
566
+ "top": null,
567
+ "visibility": null,
568
+ "width": null
569
+ }
570
+ },
571
+ "38d95f1d4d65453895e3b9f5ea41723c": {
572
+ "model_module": "@jupyter-widgets/base",
573
+ "model_module_version": "1.2.0",
574
+ "model_name": "LayoutModel",
575
+ "state": {
576
+ "_model_module": "@jupyter-widgets/base",
577
+ "_model_module_version": "1.2.0",
578
+ "_model_name": "LayoutModel",
579
+ "_view_count": null,
580
+ "_view_module": "@jupyter-widgets/base",
581
+ "_view_module_version": "1.2.0",
582
+ "_view_name": "LayoutView",
583
+ "align_content": null,
584
+ "align_items": null,
585
+ "align_self": null,
586
+ "border": null,
587
+ "bottom": null,
588
+ "display": null,
589
+ "flex": null,
590
+ "flex_flow": null,
591
+ "grid_area": null,
592
+ "grid_auto_columns": null,
593
+ "grid_auto_flow": null,
594
+ "grid_auto_rows": null,
595
+ "grid_column": null,
596
+ "grid_gap": null,
597
+ "grid_row": null,
598
+ "grid_template_areas": null,
599
+ "grid_template_columns": null,
600
+ "grid_template_rows": null,
601
+ "height": null,
602
+ "justify_content": null,
603
+ "justify_items": null,
604
+ "left": null,
605
+ "margin": null,
606
+ "max_height": null,
607
+ "max_width": null,
608
+ "min_height": null,
609
+ "min_width": null,
610
+ "object_fit": null,
611
+ "object_position": null,
612
+ "order": null,
613
+ "overflow": null,
614
+ "overflow_x": null,
615
+ "overflow_y": null,
616
+ "padding": null,
617
+ "right": null,
618
+ "top": null,
619
+ "visibility": null,
620
+ "width": null
621
+ }
622
+ },
623
+ "50e7ac5f3f4b4fe58e2e110fea403bbc": {
624
+ "model_module": "@jupyter-widgets/controls",
625
+ "model_module_version": "1.5.0",
626
+ "model_name": "HBoxModel",
627
+ "state": {
628
+ "_dom_classes": [],
629
+ "_model_module": "@jupyter-widgets/controls",
630
+ "_model_module_version": "1.5.0",
631
+ "_model_name": "HBoxModel",
632
+ "_view_count": null,
633
+ "_view_module": "@jupyter-widgets/controls",
634
+ "_view_module_version": "1.5.0",
635
+ "_view_name": "HBoxView",
636
+ "box_style": "",
637
+ "children": [
638
+ "IPY_MODEL_66e2c724e5e54c878bb614d51a452b26",
639
+ "IPY_MODEL_6901f2bab73b4155b0f53c30467d46c3",
640
+ "IPY_MODEL_771460c15f794c71af4f6eeb0ea7b1ad"
641
+ ],
642
+ "layout": "IPY_MODEL_1e977edae4d54b5fbd5b7018ffb9858f"
643
+ }
644
+ },
645
+ "66e2c724e5e54c878bb614d51a452b26": {
646
+ "model_module": "@jupyter-widgets/controls",
647
+ "model_module_version": "1.5.0",
648
+ "model_name": "HTMLModel",
649
+ "state": {
650
+ "_dom_classes": [],
651
+ "_model_module": "@jupyter-widgets/controls",
652
+ "_model_module_version": "1.5.0",
653
+ "_model_name": "HTMLModel",
654
+ "_view_count": null,
655
+ "_view_module": "@jupyter-widgets/controls",
656
+ "_view_module_version": "1.5.0",
657
+ "_view_name": "HTMLView",
658
+ "description": "",
659
+ "description_tooltip": null,
660
+ "layout": "IPY_MODEL_38d95f1d4d65453895e3b9f5ea41723c",
661
+ "placeholder": "​",
662
+ "style": "IPY_MODEL_0d705fdb53a0460cb06e86e2212618f5",
663
+ "value": "100%"
664
+ }
665
+ },
666
+ "6901f2bab73b4155b0f53c30467d46c3": {
667
+ "model_module": "@jupyter-widgets/controls",
668
+ "model_module_version": "1.5.0",
669
+ "model_name": "FloatProgressModel",
670
+ "state": {
671
+ "_dom_classes": [],
672
+ "_model_module": "@jupyter-widgets/controls",
673
+ "_model_module_version": "1.5.0",
674
+ "_model_name": "FloatProgressModel",
675
+ "_view_count": null,
676
+ "_view_module": "@jupyter-widgets/controls",
677
+ "_view_module_version": "1.5.0",
678
+ "_view_name": "ProgressView",
679
+ "bar_style": "",
680
+ "description": "",
681
+ "description_tooltip": null,
682
+ "layout": "IPY_MODEL_dd05d612550a4db28ebf2c7cfc2312fe",
683
+ "max": 75500,
684
+ "min": 0,
685
+ "orientation": "horizontal",
686
+ "style": "IPY_MODEL_1a8db5a1fed14afca913a6edb7794b17",
687
+ "value": 75500
688
+ }
689
+ },
690
+ "771460c15f794c71af4f6eeb0ea7b1ad": {
691
+ "model_module": "@jupyter-widgets/controls",
692
+ "model_module_version": "1.5.0",
693
+ "model_name": "HTMLModel",
694
+ "state": {
695
+ "_dom_classes": [],
696
+ "_model_module": "@jupyter-widgets/controls",
697
+ "_model_module_version": "1.5.0",
698
+ "_model_name": "HTMLModel",
699
+ "_view_count": null,
700
+ "_view_module": "@jupyter-widgets/controls",
701
+ "_view_module_version": "1.5.0",
702
+ "_view_name": "HTMLView",
703
+ "description": "",
704
+ "description_tooltip": null,
705
+ "layout": "IPY_MODEL_d08ee627a3cc414489e61161d8a917ae",
706
+ "placeholder": "​",
707
+ "style": "IPY_MODEL_b2818288e9b9459fb75a1ea2e6f35117",
708
+ "value": " 75500/75500 [9:00:45&lt;00:00, 2.32it/s]"
709
+ }
710
+ },
711
+ "b2818288e9b9459fb75a1ea2e6f35117": {
712
+ "model_module": "@jupyter-widgets/controls",
713
+ "model_module_version": "1.5.0",
714
+ "model_name": "DescriptionStyleModel",
715
+ "state": {
716
+ "_model_module": "@jupyter-widgets/controls",
717
+ "_model_module_version": "1.5.0",
718
+ "_model_name": "DescriptionStyleModel",
719
+ "_view_count": null,
720
+ "_view_module": "@jupyter-widgets/base",
721
+ "_view_module_version": "1.2.0",
722
+ "_view_name": "StyleView",
723
+ "description_width": ""
724
+ }
725
+ },
726
+ "d08ee627a3cc414489e61161d8a917ae": {
727
+ "model_module": "@jupyter-widgets/base",
728
+ "model_module_version": "1.2.0",
729
+ "model_name": "LayoutModel",
730
+ "state": {
731
+ "_model_module": "@jupyter-widgets/base",
732
+ "_model_module_version": "1.2.0",
733
+ "_model_name": "LayoutModel",
734
+ "_view_count": null,
735
+ "_view_module": "@jupyter-widgets/base",
736
+ "_view_module_version": "1.2.0",
737
+ "_view_name": "LayoutView",
738
+ "align_content": null,
739
+ "align_items": null,
740
+ "align_self": null,
741
+ "border": null,
742
+ "bottom": null,
743
+ "display": null,
744
+ "flex": null,
745
+ "flex_flow": null,
746
+ "grid_area": null,
747
+ "grid_auto_columns": null,
748
+ "grid_auto_flow": null,
749
+ "grid_auto_rows": null,
750
+ "grid_column": null,
751
+ "grid_gap": null,
752
+ "grid_row": null,
753
+ "grid_template_areas": null,
754
+ "grid_template_columns": null,
755
+ "grid_template_rows": null,
756
+ "height": null,
757
+ "justify_content": null,
758
+ "justify_items": null,
759
+ "left": null,
760
+ "margin": null,
761
+ "max_height": null,
762
+ "max_width": null,
763
+ "min_height": null,
764
+ "min_width": null,
765
+ "object_fit": null,
766
+ "object_position": null,
767
+ "order": null,
768
+ "overflow": null,
769
+ "overflow_x": null,
770
+ "overflow_y": null,
771
+ "padding": null,
772
+ "right": null,
773
+ "top": null,
774
+ "visibility": null,
775
+ "width": null
776
+ }
777
+ },
778
+ "dd05d612550a4db28ebf2c7cfc2312fe": {
779
+ "model_module": "@jupyter-widgets/base",
780
+ "model_module_version": "1.2.0",
781
+ "model_name": "LayoutModel",
782
+ "state": {
783
+ "_model_module": "@jupyter-widgets/base",
784
+ "_model_module_version": "1.2.0",
785
+ "_model_name": "LayoutModel",
786
+ "_view_count": null,
787
+ "_view_module": "@jupyter-widgets/base",
788
+ "_view_module_version": "1.2.0",
789
+ "_view_name": "LayoutView",
790
+ "align_content": null,
791
+ "align_items": null,
792
+ "align_self": null,
793
+ "border": null,
794
+ "bottom": null,
795
+ "display": null,
796
+ "flex": null,
797
+ "flex_flow": null,
798
+ "grid_area": null,
799
+ "grid_auto_columns": null,
800
+ "grid_auto_flow": null,
801
+ "grid_auto_rows": null,
802
+ "grid_column": null,
803
+ "grid_gap": null,
804
+ "grid_row": null,
805
+ "grid_template_areas": null,
806
+ "grid_template_columns": null,
807
+ "grid_template_rows": null,
808
+ "height": null,
809
+ "justify_content": null,
810
+ "justify_items": null,
811
+ "left": null,
812
+ "margin": null,
813
+ "max_height": null,
814
+ "max_width": null,
815
+ "min_height": null,
816
+ "min_width": null,
817
+ "object_fit": null,
818
+ "object_position": null,
819
+ "order": null,
820
+ "overflow": null,
821
+ "overflow_x": null,
822
+ "overflow_y": null,
823
+ "padding": null,
824
+ "right": null,
825
+ "top": null,
826
+ "visibility": null,
827
+ "width": null
828
+ }
829
+ }
830
+ },
831
+ "version_major": 2,
832
+ "version_minor": 0
833
+ }
834
+ }
835
+ },
836
+ "nbformat": 4,
837
+ "nbformat_minor": 5
838
+ }
src/templates/index.html ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>MangaColorizer</title>
5
+ </head>
6
+ <body>
7
+ <h1 style="text-align: center;font-size: xx-large;">MangaColorizer</h1>
8
+ <p style="text-align: center;font-size: large;">Upload a black and white drawing and get its colorized version</p>
9
+ </body>
10
+ </html>
src/test.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
src/utils.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import torch
4
+ import matplotlib.pyplot as plt
5
+ from PIL import Image
6
+ from torch.utils.data import Dataset
7
+ from torchvision import transforms
8
+
9
+
10
+ class ImageDataset(Dataset):
11
+ def __init__(self, dir, transform=None) -> None:
12
+ self.dir = dir
13
+ self.transform = transform
14
+ self.file_list = sorted(os.listdir(self.dir))
15
+
16
+ def __len__(self):
17
+ return len(self.file_list)
18
+
19
+ def __getitem__(self, idx):
20
+ image_name = self.file_list[idx]
21
+ image_path = os.path.join(self.dir, image_name)
22
+
23
+ grayscale_image = Image.open(image_path).convert('L')
24
+ colorized_image = Image.open(image_path).convert('RGB')
25
+
26
+ if self.transform:
27
+ grayscale_image = self.transform(grayscale_image)
28
+ colorized_image = self.transform(colorized_image)
29
+
30
+ return grayscale_image, colorized_image
31
+
32
+
33
+ def show_image(image_tensor):
34
+ try:
35
+ if len(image_tensor) == 1:
36
+ plt.imshow(image_tensor[0], cmap="gray")
37
+ else:
38
+ plt.imshow(image_tensor.numpy().transpose(1, 2, 0))
39
+ except Exception as e:
40
+ print(f"Exception when showing image: {e}")
41
+
42
+
43
+ # To be able to calculate MSE loss in case output tensor has different shape from target tensor
44
+ def adjust_output_shape(output_tensor, target_tensor):
45
+ adjusted_tensor = torch.nn.functional.interpolate(output_tensor, size=target_tensor.shape[2:], mode="bilinear", align_corners=False)
46
+ return adjusted_tensor
47
+
48
+
49
+ def pil_to_torch(pil_image):
50
+ transform = transforms.ToTensor()
51
+ return transform(pil_image).unsqueeze(0)
52
+
53
+ def torch_to_pil(torch_image):
54
+ transform = transforms.ToPILImage()
55
+ return transform(torch_image.squeeze(0))