{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "1b172ddd",
"metadata": {},
"outputs": [],
"source": [
"#| default_exp learner"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7e8f8491",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"import math,torch,matplotlib.pyplot as plt\n",
"import fastcore.all as fc\n",
"from collections.abc import Mapping\n",
"from operator import attrgetter\n",
"from functools import partial\n",
"from copy import copy\n",
"\n",
"from torch import optim\n",
"import torch.nn.functional as F\n",
"\n",
"from miniai.conv import *\n",
"\n",
"from fastprogress import progress_bar,master_bar"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b2cfc67c",
"metadata": {},
"outputs": [],
"source": [
"import matplotlib as mpl\n",
"import torchvision.transforms.functional as TF\n",
"from contextlib import contextmanager\n",
"from torch import nn,tensor\n",
"from datasets import load_dataset,load_dataset_builder\n",
"from miniai.datasets import *\n",
"from miniai.conv import *\n",
"import logging\n",
"from fastcore.test import test_close"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8c1d7be1",
"metadata": {},
"outputs": [],
"source": [
"torch.set_printoptions(precision=2, linewidth=140, sci_mode=False)\n",
"torch.manual_seed(1)\n",
"mpl.rcParams['image.cmap'] = 'gray'"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "84a947f2",
"metadata": {},
"outputs": [],
"source": [
"logging.disable(logging.WARNING)"
]
},
{
"cell_type": "markdown",
"id": "8f5eea66",
"metadata": {},
"source": [
"## Learner"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b22868a9",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "25a1693df8844081b050b8bbdb5f00fa",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/2 [00:00, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"x,y = 'image','label'\n",
"name = \"fashion_mnist\"\n",
"dsd = load_dataset(name)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1ad7ecde",
"metadata": {},
"outputs": [],
"source": [
"@inplace\n",
"def transformi(b): b[x] = [torch.flatten(TF.to_tensor(o)) for o in b[x]]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ad4d2ec0",
"metadata": {},
"outputs": [],
"source": [
"bs = 1024\n",
"tds = dsd.with_transform(transformi)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9cb11029",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(torch.Size([1024, 784]), tensor([5, 4, 9, 4, 3, 0, 6, 5, 7, 6]))"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dls = DataLoaders.from_dd(tds, bs, num_workers=4)\n",
"dt = dls.train\n",
"xb,yb = next(iter(dt))\n",
"xb.shape,yb[:10]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d733c9b0",
"metadata": {},
"outputs": [],
"source": [
"class Learner:\n",
" def __init__(self, model, dls, loss_func, lr, opt_func=optim.SGD): fc.store_attr()\n",
"\n",
" def one_batch(self):\n",
" self.xb,self.yb = to_device(self.batch)\n",
" self.preds = self.model(self.xb)\n",
" self.loss = self.loss_func(self.preds, self.yb)\n",
" if self.model.training:\n",
" self.loss.backward()\n",
" self.opt.step()\n",
" self.opt.zero_grad()\n",
" with torch.no_grad(): self.calc_stats()\n",
"\n",
" def calc_stats(self):\n",
" acc = (self.preds.argmax(dim=1)==self.yb).float().sum()\n",
" self.accs.append(acc)\n",
" n = len(self.xb)\n",
" self.losses.append(self.loss*n)\n",
" self.ns.append(n)\n",
"\n",
" def one_epoch(self, train):\n",
" self.model.training = train\n",
" dl = self.dls.train if train else self.dls.valid\n",
" for self.num,self.batch in enumerate(dl): self.one_batch()\n",
" n = sum(self.ns)\n",
" print(self.epoch, self.model.training, sum(self.losses).item()/n, sum(self.accs).item()/n)\n",
" \n",
" def fit(self, n_epochs):\n",
" self.accs,self.losses,self.ns = [],[],[]\n",
" self.model.to(def_device)\n",
" self.opt = self.opt_func(self.model.parameters(), self.lr)\n",
" self.n_epochs = n_epochs\n",
" for self.epoch in range(n_epochs):\n",
" self.one_epoch(True)\n",
" with torch.no_grad(): self.one_epoch(False)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8edf58ea",
"metadata": {},
"outputs": [],
"source": [
"m,nh = 28*28,50\n",
"model = nn.Sequential(nn.Linear(m,nh), nn.ReLU(), nn.Linear(nh,10))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "be2af2a1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 True 1.1753044270833333 0.5986833333333333\n",
"0 False 1.120328794642857 0.6135285714285714\n"
]
}
],
"source": [
"learn = Learner(model, dls, F.cross_entropy, lr=0.2)\n",
"learn.fit(1)"
]
},
{
"cell_type": "markdown",
"id": "82718c6d",
"metadata": {},
"source": [
"## Basic Callbacks Learner"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "534c00e6",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"class CancelFitException(Exception): pass\n",
"class CancelBatchException(Exception): pass\n",
"class CancelEpochException(Exception): pass"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ee43512e",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"class Callback(): order = 0"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7439ca0b",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"def run_cbs(cbs, method_nm, learn=None):\n",
" for cb in sorted(cbs, key=attrgetter('order')):\n",
" method = getattr(cb, method_nm, None)\n",
" if method is not None: method(learn)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "583ce114",
"metadata": {},
"outputs": [],
"source": [
"class CompletionCB(Callback):\n",
" def before_fit(self, learn): self.count = 0\n",
" def after_batch(self, learn): self.count += 1\n",
" def after_fit(self, learn): print(f'Completed {self.count} batches')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c2b41ea4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Completed 1 batches\n"
]
}
],
"source": [
"cbs = [CompletionCB()]\n",
"run_cbs(cbs, 'before_fit')\n",
"run_cbs(cbs, 'after_batch')\n",
"run_cbs(cbs, 'after_fit')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "01de6ea0",
"metadata": {},
"outputs": [],
"source": [
"class Learner():\n",
" def __init__(self, model, dls, loss_func, lr, cbs, opt_func=optim.SGD): fc.store_attr()\n",
"\n",
" def one_batch(self):\n",
" self.preds = self.model(self.batch[0])\n",
" self.loss = self.loss_func(self.preds, self.batch[1])\n",
" if self.model.training:\n",
" self.loss.backward()\n",
" self.opt.step()\n",
" self.opt.zero_grad()\n",
"\n",
" def one_epoch(self, train):\n",
" self.model.train(train)\n",
" self.dl = self.dls.train if train else self.dls.valid\n",
" try:\n",
" self.callback('before_epoch')\n",
" for self.iter,self.batch in enumerate(self.dl):\n",
" try:\n",
" self.callback('before_batch')\n",
" self.one_batch()\n",
" self.callback('after_batch')\n",
" except CancelBatchException: pass\n",
" self.callback('after_epoch')\n",
" except CancelEpochException: pass\n",
" \n",
" def fit(self, n_epochs):\n",
" self.n_epochs = n_epochs\n",
" self.epochs = range(n_epochs)\n",
" self.opt = self.opt_func(self.model.parameters(), self.lr)\n",
" try:\n",
" self.callback('before_fit')\n",
" for self.epoch in self.epochs:\n",
" self.one_epoch(True)\n",
" self.one_epoch(False)\n",
" self.callback('after_fit')\n",
" except CancelFitException: pass\n",
"\n",
" def callback(self, method_nm): run_cbs(self.cbs, method_nm, self)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "38009cbf",
"metadata": {},
"outputs": [],
"source": [
"m,nh = 28*28,50\n",
"def get_model(): return nn.Sequential(nn.Linear(m,nh), nn.ReLU(), nn.Linear(nh,10))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7559838f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Completed 64 batches\n"
]
}
],
"source": [
"model = get_model()\n",
"learn = Learner(model, dls, F.cross_entropy, lr=0.2, cbs=[CompletionCB()])\n",
"learn.fit(1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e5c14d8e",
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"class SingleBatchCB(Callback):\n",
" order = 1\n",
" def after_batch(self, learn): raise CancelFitException()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "29310ca2",
"metadata": {},
"outputs": [],
"source": [
"learn = Learner(get_model(), dls, F.cross_entropy, lr=0.2, cbs=[SingleBatchCB(), CompletionCB()])\n",
"learn.fit(1)"
]
},
{
"cell_type": "markdown",
"id": "559c0986",
"metadata": {},
"source": [
"## Metrics"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f810c642",
"metadata": {},
"outputs": [],
"source": [
"class Metric:\n",
" def __init__(self): self.reset()\n",
" def reset(self): self.vals,self.ns = [],[]\n",
" def add(self, inp, targ=None, n=1):\n",
" self.last = self.calc(inp, targ)\n",
" self.vals.append(self.last)\n",
" self.ns.append(n)\n",
" @property\n",
" def value(self):\n",
" ns = tensor(self.ns)\n",
" return (tensor(self.vals)*ns).sum()/ns.sum()\n",
" def calc(self, inps, targs): return inps"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "092dd298",
"metadata": {},
"outputs": [],
"source": [
"class Accuracy(Metric):\n",
" def calc(self, inps, targs): return (inps==targs).float().mean()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "87752b24",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"tensor(0.45)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"acc = Accuracy()\n",
"acc.add(tensor([0, 1, 2, 0, 1, 2]), tensor([0, 1, 1, 2, 1, 0]))\n",
"acc.add(tensor([1, 1, 2, 0, 1]), tensor([0, 1, 1, 2, 1]))\n",
"acc.value"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4cdf18e8",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(tensor(0.62), 0.62)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"loss = Metric()\n",
"loss.add(0.6, n=32)\n",
"loss.add(0.9, n=2)\n",
"loss.value, round((0.6*32+0.9*2)/(32+2), 2)"
]
},
{
"cell_type": "markdown",
"id": "1ca935dc",
"metadata": {},
"source": [
"## Some callbacks"
]
},
{
"cell_type": "markdown",
"id": "e16df8dd",
"metadata": {},
"source": [
"```\n",
"pip install torcheval\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e67c006c",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"from torcheval.metrics import MulticlassAccuracy,Mean"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ee473e22",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"tensor(0.50)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"metric = MulticlassAccuracy()\n",
"metric.update(tensor([0, 2, 1, 3]), tensor([0, 1, 2, 3]))\n",
"metric.compute()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0c531ca0",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"tensor(nan)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"metric.reset()\n",
"metric.compute()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6f8692bd",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"def to_cpu(x):\n",
" if isinstance(x, Mapping): return {k:to_cpu(v) for k,v in x.items()}\n",
" if isinstance(x, list): return [to_cpu(o) for o in x]\n",
" if isinstance(x, tuple): return tuple(to_cpu(list(x)))\n",
" res = x.detach().cpu()\n",
" return res.float() if res.dtype==torch.float16 else res"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "678712dc",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"class MetricsCB(Callback):\n",
" def __init__(self, *ms, **metrics):\n",
" for o in ms: metrics[type(o).__name__] = o\n",
" self.metrics = metrics\n",
" self.all_metrics = copy(metrics)\n",
" self.all_metrics['loss'] = self.loss = Mean()\n",
"\n",
" def _log(self, d): print(d)\n",
" def before_fit(self, learn): learn.metrics = self\n",
" def before_epoch(self, learn): [o.reset() for o in self.all_metrics.values()]\n",
"\n",
" def after_epoch(self, learn):\n",
" log = {k:f'{v.compute():.3f}' for k,v in self.all_metrics.items()}\n",
" log['epoch'] = learn.epoch\n",
" log['train'] = 'train' if learn.model.training else 'eval'\n",
" self._log(log)\n",
"\n",
" def after_batch(self, learn):\n",
" x,y,*_ = to_cpu(learn.batch)\n",
" for m in self.metrics.values(): m.update(to_cpu(learn.preds), y)\n",
" self.loss.update(to_cpu(learn.loss), weight=len(x))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "339962be",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"class DeviceCB(Callback):\n",
" def __init__(self, device=def_device): fc.store_attr()\n",
" def before_fit(self, learn):\n",
" if hasattr(learn.model, 'to'): learn.model.to(self.device)\n",
" def before_batch(self, learn): learn.batch = to_device(learn.batch, device=self.device)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f5ce9364",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'accuracy': '0.602', 'loss': '1.183', 'epoch': 0, 'train': 'train'}\n",
"{'accuracy': '0.700', 'loss': '0.847', 'epoch': 0, 'train': 'eval'}\n"
]
}
],
"source": [
"model = get_model()\n",
"metrics = MetricsCB(accuracy=MulticlassAccuracy())\n",
"learn = Learner(model, dls, F.cross_entropy, lr=0.2, cbs=[DeviceCB(), metrics])\n",
"learn.fit(1)"
]
},
{
"cell_type": "markdown",
"id": "24420ba4",
"metadata": {},
"source": [
"## Flexible learner"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1732aac",
"metadata": {},
"outputs": [],
"source": [
"class Learner():\n",
" def __init__(self, model, dls=(0,), loss_func=F.mse_loss, lr=0.1, cbs=None, opt_func=optim.SGD):\n",
" cbs = fc.L(cbs)\n",
" fc.store_attr()\n",
"\n",
" @contextmanager\n",
" def cb_ctx(self, nm):\n",
" try:\n",
" self.callback(f'before_{nm}')\n",
" yield\n",
" self.callback(f'after_{nm}')\n",
" except globals()[f'Cancel{nm.title()}Exception']: pass\n",
" finally: self.callback(f'cleanup_{nm}')\n",
" \n",
" def one_epoch(self, train):\n",
" self.model.train(train)\n",
" self.dl = self.dls.train if train else self.dls.valid\n",
" with self.cb_ctx('epoch'):\n",
" for self.iter,self.batch in enumerate(self.dl):\n",
" with self.cb_ctx('batch'):\n",
" self.predict()\n",
" self.get_loss()\n",
" if self.training:\n",
" self.backward()\n",
" self.step()\n",
" self.zero_grad()\n",
" \n",
" def fit(self, n_epochs=1, train=True, valid=True, cbs=None, lr=None):\n",
" cbs = fc.L(cbs)\n",
" # `add_cb` and `rm_cb` were added in lesson 18\n",
" for cb in cbs: self.cbs.append(cb)\n",
" try:\n",
" self.n_epochs = n_epochs\n",
" self.epochs = range(n_epochs)\n",
" self.opt = self.opt_func(self.model.parameters(), self.lr if lr is None else lr)\n",
" with self.cb_ctx('fit'):\n",
" for self.epoch in self.epochs:\n",
" if train: self.one_epoch(True)\n",
" if valid: torch.no_grad()(self.one_epoch)(False)\n",
" finally:\n",
" for cb in cbs: self.cbs.remove(cb)\n",
"\n",
" def __getattr__(self, name):\n",
" if name in ('predict','get_loss','backward','step','zero_grad'): return partial(self.callback, name)\n",
" raise AttributeError(name)\n",
"\n",
" def callback(self, method_nm): run_cbs(self.cbs, method_nm, self)\n",
" \n",
" @property\n",
" def training(self): return self.model.training"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bee3643f",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"class TrainCB(Callback):\n",
" def __init__(self, n_inp=1): self.n_inp = n_inp\n",
" def predict(self, learn): learn.preds = learn.model(*learn.batch[:self.n_inp])\n",
" def get_loss(self, learn): learn.loss = learn.loss_func(learn.preds, *learn.batch[self.n_inp:])\n",
" def backward(self, learn): learn.loss.backward()\n",
" def step(self, learn): learn.opt.step()\n",
" def zero_grad(self, learn): learn.opt.zero_grad()"
]
},
{
"cell_type": "markdown",
"id": "9b2e6eb3",
"metadata": {},
"source": [
"NB: I added `self.n_inp` after the lesson. This allows us to train models with more than one input or output."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e9537f9f",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"class ProgressCB(Callback):\n",
" order = MetricsCB.order+1\n",
" def __init__(self, plot=False): self.plot = plot\n",
" def before_fit(self, learn):\n",
" learn.epochs = self.mbar = master_bar(learn.epochs)\n",
" self.first = True\n",
" if hasattr(learn, 'metrics'): learn.metrics._log = self._log\n",
" self.losses = []\n",
" self.val_losses = []\n",
"\n",
" def _log(self, d):\n",
" if self.first:\n",
" self.mbar.write(list(d), table=True)\n",
" self.first = False\n",
" self.mbar.write(list(d.values()), table=True)\n",
"\n",
" def before_epoch(self, learn): learn.dl = progress_bar(learn.dl, leave=False, parent=self.mbar)\n",
" def after_batch(self, learn):\n",
" learn.dl.comment = f'{learn.loss:.3f}'\n",
" if self.plot and hasattr(learn, 'metrics') and learn.training:\n",
" self.losses.append(learn.loss.item())\n",
" if self.val_losses: self.mbar.update_graph([[fc.L.range(self.losses), self.losses],[fc.L.range(learn.epoch).map(lambda x: (x+1)*len(learn.dls.train)), self.val_losses]])\n",
" \n",
" def after_epoch(self, learn): \n",
" if not learn.training:\n",
" if self.plot and hasattr(learn, 'metrics'): \n",
" self.val_losses.append(learn.metrics.all_metrics['loss'].compute())\n",
" self.mbar.update_graph([[fc.L.range(self.losses), self.losses],[fc.L.range(learn.epoch+1).map(lambda x: (x+1)*len(learn.dls.train)), self.val_losses]])"
]
},
{
"cell_type": "markdown",
"id": "0251557d-1d60-407e-ae34-c0debd477436",
"metadata": {},
"source": [
"NB: Added validation loss plotting after the lesson."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b82dcb40",
"metadata": {},
"outputs": [],
"source": [
"model = get_model()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3b77daf3",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" accuracy | \n",
" loss | \n",
" epoch | \n",
" train | \n",
"
\n",
" \n",
" \n",
" \n",
" 0.596 | \n",
" 1.167 | \n",
" 0 | \n",
" train | \n",
"
\n",
" \n",
" 0.729 | \n",
" 0.794 | \n",
" 0 | \n",
" eval | \n",
"
\n",
" \n",
" 0.744 | \n",
" 0.710 | \n",
" 1 | \n",
" train | \n",
"
\n",
" \n",
" 0.764 | \n",
" 0.654 | \n",
" 1 | \n",
" eval | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"metrics = MetricsCB(accuracy=MulticlassAccuracy())\n",
"cbs = [TrainCB(), DeviceCB(), metrics, ProgressCB(plot=True)]\n",
"learn = Learner(model, dls, F.cross_entropy, lr=0.2, cbs=cbs)\n",
"learn.fit(2)"
]
},
{
"cell_type": "markdown",
"id": "9978f0fe",
"metadata": {},
"source": [
"## Updated versions since the lesson"
]
},
{
"cell_type": "markdown",
"id": "31c38064",
"metadata": {},
"source": [
"After the lesson we noticed that `contextlib.context_manager` has a surprising \"feature\" which doesn't let us raise an exception before the `yield`. Therefore we've replaced the context manager with a decorator in this updated version of `Learner`. We have also added a few more callbacks in `one_epoch()`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f1ddb822",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"class with_cbs:\n",
" def __init__(self, nm): self.nm = nm\n",
" def __call__(self, f):\n",
" def _f(o, *args, **kwargs):\n",
" try:\n",
" o.callback(f'before_{self.nm}')\n",
" f(o, *args, **kwargs)\n",
" o.callback(f'after_{self.nm}')\n",
" except globals()[f'Cancel{self.nm.title()}Exception']: pass\n",
" finally: o.callback(f'cleanup_{self.nm}')\n",
" return _f"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "33c1a1db",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"class Learner():\n",
" def __init__(self, model, dls=(0,), loss_func=F.mse_loss, lr=0.1, cbs=None, opt_func=optim.SGD):\n",
" cbs = fc.L(cbs)\n",
" fc.store_attr()\n",
"\n",
" @with_cbs('batch')\n",
" def _one_batch(self):\n",
" self.predict()\n",
" self.callback('after_predict')\n",
" self.get_loss()\n",
" self.callback('after_loss')\n",
" if self.training:\n",
" self.backward()\n",
" self.callback('after_backward')\n",
" self.step()\n",
" self.callback('after_step')\n",
" self.zero_grad()\n",
"\n",
" @with_cbs('epoch')\n",
" def _one_epoch(self):\n",
" for self.iter,self.batch in enumerate(self.dl): self._one_batch()\n",
"\n",
" def one_epoch(self, training):\n",
" self.model.train(training)\n",
" self.dl = self.dls.train if training else self.dls.valid\n",
" self._one_epoch()\n",
"\n",
" @with_cbs('fit')\n",
" def _fit(self, train, valid):\n",
" for self.epoch in self.epochs:\n",
" if train: self.one_epoch(True)\n",
" if valid: torch.no_grad()(self.one_epoch)(False)\n",
"\n",
" def fit(self, n_epochs=1, train=True, valid=True, cbs=None, lr=None):\n",
" cbs = fc.L(cbs)\n",
" # `add_cb` and `rm_cb` were added in lesson 18\n",
" for cb in cbs: self.cbs.append(cb)\n",
" try:\n",
" self.n_epochs = n_epochs\n",
" self.epochs = range(n_epochs)\n",
" if lr is None: lr = self.lr\n",
" if self.opt_func: self.opt = self.opt_func(self.model.parameters(), lr)\n",
" self._fit(train, valid)\n",
" finally:\n",
" for cb in cbs: self.cbs.remove(cb)\n",
"\n",
" def __getattr__(self, name):\n",
" if name in ('predict','get_loss','backward','step','zero_grad'): return partial(self.callback, name)\n",
" raise AttributeError(name)\n",
"\n",
" def callback(self, method_nm): run_cbs(self.cbs, method_nm, self)\n",
" \n",
" @property\n",
" def training(self): return self.model.training"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "08159e02",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" accuracy | \n",
" loss | \n",
" epoch | \n",
" train | \n",
"
\n",
" \n",
" \n",
" \n",
" 0.606 | \n",
" 1.176 | \n",
" 0 | \n",
" train | \n",
"
\n",
" \n",
" 0.702 | \n",
" 0.796 | \n",
" 0 | \n",
" eval | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAgQAAAFfCAYAAAAxo9Q/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAABKw0lEQVR4nO3deVhUZf8G8PvMDDPsA8guKKiIC4ooarjlgpkaqeVS+kZqm6WZmf2SFtujRX1tMVtsd01TKzWLXHBJJVBUXFAEBNkVGfZt5vz+QOeNFGQbzgxzf67rXG/MnOU7z+XL3DznOc8jiKIogoiIiMyaTOoCiIiISHoMBERERMRAQERERAwEREREBAYCIiIiAgMBERERgYGAiIiIACikLqAhdDodMjMzYWdnB0EQpC6HiIjIZIiiiKKiInh6ekImq7sfwCQCQWZmJry9vaUug4iIyGSlp6fDy8urzvdNIhDY2dkBqPkw9vb2EldDRERkOgoLC+Ht7a3/Lq2LSQSCG7cJ7O3tGQiIiIia4Ha33DmokIiIiBgIiIiIiIGAiIiIYCJjCIiIqO3SarWoqqqSugyTZWFhAblc3uzzMBAQEZEkRFFEdnY2CgoKpC7F5Dk4OMDd3b1Zc/UwEBARkSRuhAFXV1dYW1tz4rkmEEURpaWlyM3NBQB4eHg0+VwMBERE1Oq0Wq0+DLRr107qckyalZUVACA3Nxeurq5Nvn3AQYVERNTqbowZsLa2lriStuFGOzZnLAYDARERSYa3CVpGS7SjWQeC8iqt1CUQEREZBbMMBHlFFXh6/XE89n0sRFGUuhwiIiLJmWUgKK6oxu+ns3HgwhX8HJ8pdTlERGSmfHx8sGLFCqnLAGCmgcDX2QbPjPIDALyx/QyulVRKXBEREZmK4cOHY8GCBS1yrr///huPP/54i5yrucwyEADAY0M7wd/NDvkllXh751mpyyEiojZCFEVUV1c3aF8XFxejedLCbAOBUiHDO/f1giAAm+Mu46+kK1KXRERk1kRRRGlltSRbQ8eTzZw5E9HR0fjwww8hCAIEQcC3334LQRDw22+/oV+/flCpVDh48CAuXryICRMmwM3NDba2tujfvz/+/PPPWuf79y0DQRCwevVqTJo0CdbW1vDz88Mvv/zSks1cJ7OemKhfR0c8dEdHfH/4El7cegq7FgyDpUXz54MmIqLGK6vSoseS3yW59pk3xsBaefuvxA8//BDnz59HQEAA3njjDQDA6dOnAQCLFy/G0qVL0alTJzg6OiI9PR3jxo3D22+/DZVKhe+//x5hYWFITExEhw4d6rzG66+/jvfffx8ffPABPv74Y8yYMQOXLl2Ck5NTy3zYOphtD8ENz4/xh7u9JVKvluLjPRekLoeIiIyYWq2GUqmEtbU13N3d4e7urp8Z8I033sDo0aPRuXNnODk5ITAwEE888QQCAgLg5+eHN998E507d77tX/wzZ87Egw8+iC5duuCdd95BcXExYmJiDP7ZzLqHAADsLC3w+oSeeOKHOHwenYywQE90c7eXuiwiIrNjZSHHmTfGSHbt5goODq71c3FxMV577TXs2LEDWVlZqK6uRllZGdLS0uo9T+/evfX/bWNjA3t7e/1aBYZk9oEAAMb0dMeYnm74/XQOFv90Cj89OQhyGWfPIiJqTYIgNKjb3ljZ2NjU+nnRokWIiorC0qVL0aVLF1hZWWHy5MmorKz/yTYLC4taPwuCAJ1O1+L1/pvZ3zK44fV7A2CrUiA+vQBrjlySuhwiIjJSSqUSWu3tZ7o9dOgQZs6ciUmTJqFXr15wd3dHamqq4QtsIgaC69zVlnjhbn8AwPu7ziGzoEziioiIyBj5+Pjg6NGjSE1NxZUrV+r8693Pzw9btmxBfHw8Tpw4genTp7fKX/pNxUDwDzMGdkTfDg4oqdRiyc+nOa0xERHdZNGiRZDL5ejRowdcXFzqHBOwfPlyODo6YtCgQQgLC8OYMWPQt2/fVq624QTRBL71CgsLoVarodFoYG9v2AF/idlFGP/RAVTrRHwzqz9G+Lsa9HpEROaovLwcKSkp8PX1haWlpdTlmLz62rOh36HsIfgXf3c7zBrsAwB4d+c5aHVGn5eIiIiajYHgFuaO6AJ7SwUSc4rwU9xlqcshIiIyOAaCW3CwVuLpkTWLHy2LSkRZ5e1HkxIREZmyRgWCyMhI9O/fH3Z2dnB1dcXEiRORmJhY7zFffvklhg4dCkdHRzg6OiI0NLRVZlxqrvBBHeHlaIWcwgp8dTBZ6nKIiIgMqlGBIDo6GnPnzsWRI0cQFRWFqqoq3HXXXSgpKanzmH379uHBBx/E3r17cfjwYXh7e+Ouu+5CRkZGs4s3JJVCjufH1DyG+Fl0Mq4UV0hcERERkeE06ymDvLw8uLq6Ijo6GsOGDWvQMVqtFo6Ojvjkk08QHh7eoGNa8ymDf9LpRExYeQinMjQID+mINyYEtNq1iYjaMj5l0LIkf8pAo9EAQKNWYCotLUVVVVW9x1RUVKCwsLDWJgWZTEDEuG4AgHVH05CcVyxJHURERIbW5ECg0+mwYMECDB48GAEBDf/L+YUXXoCnpydCQ0Pr3CcyMhJqtVq/eXt7N7XMZhvU2Rkju7miWifi/V31j5cgIiIyVU0OBHPnzkVCQgI2bNjQ4GPeffddbNiwAVu3bq23iygiIgIajUa/paenN7XMFrF4bDfIBGDX6WzEpuZLWgsREZk2Hx8frFixQv+zIAjYtm1bnfunpqZCEATEx8cbtK4mBYJ58+Zh+/bt2Lt3L7y8vBp0zNKlS/Huu+/ijz/+qLW0462oVCrY29vX2qTU1c0OU4Nreine2XmWUxoTEVGLycrKwtixY6Uuo3GBQBRFzJs3D1u3bsWePXvg6+vboOPef/99vPnmm9i1a9dN60WbimdHd4WVhRzH0gqwKyFb6nKIiKiNcHd3h0qlkrqMxgWCuXPnYs2aNVi3bh3s7OyQnZ2N7OxslJX9b2XA8PBwRERE6H9+77338Morr+Drr7+Gj4+P/pjiYtMaoOdmb4nHhtYEoPd2nUOV1nhXrCIiIsP44osv4OnpedOqhRMmTMDs2bNx8eJFTJgwAW5ubrC1tUX//v3x559/1nvOf98yiImJQVBQECwtLREcHIzjx48b4qPcpFGBYNWqVdBoNBg+fDg8PDz028aNG/X7pKWlISsrq9YxlZWVmDx5cq1jli5d2nKfopU8fmdnONsqkXq1FCv3JkldDhFR2yKKQGWJNFsDbwVPmTIFV69exd69e/Wv5efnY9euXZgxYwaKi4sxbtw47N69G8ePH8fdd9+NsLCwOldE/Lfi4mLcc8896NGjB+Li4vDaa69h0aJFTWrOxlI0ZueG3Dvft29frZ9TU1MbcwmjZqtS4JV7euCZDfH4aPcFDO7ijP4+DX/kkoiI6lFVCrzjKc21X8wElDa33c3R0RFjx47FunXrMGrUKADA5s2b4ezsjBEjRkAmkyEwMFC//5tvvomtW7fil19+wbx58257/nXr1kGn0+Grr76CpaUlevbsicuXL+PJJ59s+mdrIK5l0EgT+rTHfUHtoROBBRvioSmtkrokIiJqRTNmzMBPP/2EioqaGWzXrl2LBx54ADKZDMXFxVi0aBG6d+8OBwcH2Nra4uzZsw3uITh79ix69+5d60m8kJAQg3yOf2tUDwHVeGNiAOLSruHS1VJEbD2JldP7QhAEqcsiIjJtFtY1f6lLde0GCgsLgyiK2LFjB/r3748DBw7gv//9LwBg0aJFiIqKwtKlS9GlSxdYWVlh8uTJqKysNFTlLYaBoAlsVQp89EAQ7l/1F3aeysbGv9PxwIAOUpdFRGTaBKFB3fZSs7S0xH333Ye1a9ciKSkJ/v7+6Nu3LwDg0KFDmDlzJiZNmgSgZkxAY26dd+/eHT/88APKy8v1vQRHjhxp8c9wK7xl0ESB3g5YdH3xo9d/PYOk3CKJKyIiotYyY8YM7NixA19//TVmzJihf93Pzw9btmxBfHw8Tpw4genTp9/0REJ9pk+fDkEQ8Nhjj+HMmTPYuXNnqw3CZyBohseHdsKQLs4oq9Li6fXxKK/SSl0SERG1gpEjR8LJyQmJiYmYPn26/vXly5fD0dERgwYNQlhYGMaMGaPvPWgIW1tb/Prrrzh16hSCgoLw0ksv4b333jPER7hJs1Y7bC1SrXbYELmF5bj7wwPIL6nErME+eDWsp9QlEREZPa522LIkX+2QAFd7SyydUjMV8zeHUrHnXI7EFRERETUeA0ELGNnNDTMH+QAAFm06idzCcmkLIiIiaiQGghayeGw3dPewR35JJV7cmsAFkIiIyKQwELQQSws5VkzrAwu5gD/P5mDHqazbH0RERGQkGAhakL+7HZ4c3gUA8Novp3GtxPgnoiAiIgIYCFrc3BGd0cXVFleKK/HWjrNSl0NEZNQa84w+1a0l2pEzFbYwlUKO9+7vjcmf/YWfjl3GhD6eGNbVReqyiIiMilKphEwmQ2ZmJlxcXKBUKjkFfBOIoojKykrk5eVBJpNBqVQ2+Vych8BAXvvlNL79KxVejlb449lhsFYyexER/VNlZSWysrJQWloqdSkmz9raGh4eHrcMBA39DuW3lIEsGuOPqDM5uHytDMv+OI9X7ukhdUlEREZFqVSiQ4cOqK6uhlbLmV6bSi6XQ6FQNLuHhYHAQGxVCrw1KQCzvvkb3xxKQVigJ/p4O0hdFhGRUREEARYWFrCwsJC6FLPHQYUGNMLfFRP7eEInAi9sPonKag6eISIi48RAYGBLwnrCyUaJxJwifBZ9UepyiIiIbomBwMCcbJR4Naxm/MAne5K4TDIRERklBoJWcG+gJ0b4u6BSq8Prv56RuhwiIqKbMBC0AkEQ8Pq9AZDLBBy4cAXH065JXRIREVEtDAStpEM7a0wKag8A+HhPksTVEBER1cZA0IrmjugCmQDsOZeLU5c1UpdDRESkx0DQinydbTChz41eggsSV0NERPQ/DAStbO6ILhAE4I8zOTiTWSh1OURERAAYCFpdF1dbjO/lAQD4ZC97CYiIyDg0KhBERkaif//+sLOzg6urKyZOnIjExMTbHrdp0yZ069YNlpaW6NWrF3bu3NnkgtuCp0f6AQB2nsrG+RzOS0BERNJrVCCIjo7G3LlzceTIEURFRaGqqgp33XUXSkpK6jzmr7/+woMPPohHHnkEx48fx8SJEzFx4kQkJCQ0u3hT5e9uh7EB7gBqJisiIiKSWrOWP87Ly4Orqyuio6MxbNiwW+4zbdo0lJSUYPv27frX7rjjDvTp0wefffbZLY+pqKhARUWF/ufCwkJ4e3ub1PLHt3M6U4PxHx2EIABRz96JLq62UpdERERtUEOXP27WGAKNpubROScnpzr3OXz4MEJDQ2u9NmbMGBw+fLjOYyIjI6FWq/Wbt7d3c8o0Sj091Qjt7gZRBD7dy14CIiKSVpMDgU6nw4IFCzB48GAEBATUuV92djbc3Nxqvebm5obs7Ow6j4mIiIBGo9Fv6enpTS3TqM0f1QUAsC0+A6lX6r7tQkREZGhNDgRz585FQkICNmzY0JL1AABUKhXs7e1rbW1Rby8HjPB3gU4EPt3HXgIiIpJOkwLBvHnzsH37duzduxdeXl717uvu7o6cnJxar+Xk5MDd3b0pl25znh5V88TBlmMZSM8vlbgaIiIyV40KBKIoYt68edi6dSv27NkDX1/f2x4TEhKC3bt313otKioKISEhjau0jerbwRFD/ZxRrRPx6b6LUpdDRERmqlGBYO7cuVizZg3WrVsHOzs7ZGdnIzs7G2VlZfp9wsPDERERof/5mWeewa5du7Bs2TKcO3cOr732GmJjYzFv3ryW+xQmbt6ImrEEW49fRmF5lcTVEBGROWpUIFi1ahU0Gg2GDx8ODw8P/bZx40b9PmlpacjKytL/PGjQIKxbtw5ffPEFAgMDsXnzZmzbtq3egYjmZoCvE7q42qK8SocdJ7NufwAREVELa9Y8BK2loc9QmrIv9l/EOzvPIaiDA7Y+NVjqcoiIqI1olXkIqOVMDGoPuUzA8bQCJOVyOmMiImpdDARGwtXOEiP8XQAAm+IuS1wNERGZGwYCIzIluGZGxi3HMlCt1UlcDRERmRMGAiMyspsr2tkokVdUgejzeVKXQ0REZoSBwIhYyGWYFNQeAPBjbNucrpmIiIwTA4GRuXHbYPfZXFwtrrjN3kRERC2DgcDI+LvbIdBLjWqdiG3xmVKXQ0REZoKBwAhNvt5LsCk2HSYwTQQREbUBDARG6N7enlAqZDiXXYSEjEKpyyEiIjPAQGCE1NYWuLtnzWqQm+I4uJCIiAyPgcBITQmuWVZ62/EMlFdpJa6GiIjaOgYCIzWoszPaO1ihsLwaUWdypC6HiIjaOAYCIyWXCbi/L+ckICKi1sFAYMQm96t52uBg0hVkFpRJXA0REbVlDARGrEM7a9zRyQmiCGw5xgWPiIjIcBgIjNyU670EP8Zehk7HOQmIiMgwGAiM3Nhe7rC3VCAtvxS/n86WuhwiImqjGAiMnLVSgZmDfAAAK/clceZCIiIyCAYCEzBrsC+slXIkZBRyWWQiIjIIBgIT4GijxPQBHQAAK/cmSVwNERG1RQwEJuKxYZ2glMvwd+o1xKTkS10OERG1MQwEJsLN3hKTr09n/Al7CYiIqIUxEJiQOcM6Qy4TsP98Hk5d1khdDhERtSEMBCakQztr3BvoCYBjCYiIqGUxEJiYp4Z3BgDsOp2NCzlFEldDRERtRaMDwf79+xEWFgZPT08IgoBt27bd9pi1a9ciMDAQ1tbW8PDwwOzZs3H16tWm1Gv2/NzsMKanGwBg1b6LEldDRERtRaMDQUlJCQIDA7Fy5coG7X/o0CGEh4fjkUcewenTp7Fp0ybExMTgsccea3SxVGPeCD8AwM8nMpF2tVTiaoiIqC1QNPaAsWPHYuzYsQ3e//Dhw/Dx8cH8+fMBAL6+vnjiiSfw3nvvNfbSdF0vLzWGdXXB/vN5+Hz/Rbw9qZfUJRERkYkz+BiCkJAQpKenY+fOnRBFETk5Odi8eTPGjRtX5zEVFRUoLCystVFtc6+PJdgUexk5heUSV0NERKbO4IFg8ODBWLt2LaZNmwalUgl3d3eo1ep6bzlERkZCrVbrN29vb0OXaXIGdmqH/j6OqNTqsPpAstTlEBGRiTN4IDhz5gyeeeYZLFmyBHFxcdi1axdSU1MxZ86cOo+JiIiARqPRb+np6YYu0yQ9NaILAGDt0TRcK6mUuBoiIjJljR5D0FiRkZEYPHgwnn/+eQBA7969YWNjg6FDh+Ktt96Ch4fHTceoVCqoVCpDl2byhnd1QQ8Pe5zJKsTao5cwb6Sf1CUREZGJMngPQWlpKWSy2peRy+UAwKV8m0kQBDw2zBcA8N3hS6io1kpcERERmapGB4Li4mLEx8cjPj4eAJCSkoL4+HikpaUBqOnuDw8P1+8fFhaGLVu2YNWqVUhOTsahQ4cwf/58DBgwAJ6eni3zKczYPb094W5vibyiCvwcnyl1OUREZKIaHQhiY2MRFBSEoKAgAMDChQsRFBSEJUuWAACysrL04QAAZs6cieXLl+OTTz5BQEAApkyZAn9/f2zZsqWFPoJ5s5DLMHOwDwDgqwMp7HUhIqImEUQT+AYpLCyEWq2GRqOBvb291OUYHU1ZFQZF7kZJpRbfzR6AO7u6SF0SEREZiYZ+h3ItgzZAbWWBqf1rHs3kI4hERNQUDARtxOzBvpAJwIELV3A2ixM5ERFR4zAQtBHeTtYYG1DzCOfqAykSV0NERKaGgaANeXRozSOIv5zI4HTGRETUKAwEbUhQB0cEd3RElVbEd3+lSl0OERGZEAaCNubRoZ0A1ExnXFpZLXE1RERkKhgI2pjRPdzQsZ01NGVV2BR7WepyiIjIRDAQtDFymYBHhtSMJfjqYAq0OqOfZoKIiIwAA0EbNLmfF9RWFkjLL0XUmWypyyEiIhPAQNAGWSsV+M8dHQAAX/IRRCIiagAGgjbq4RAfKOUyxF26hrhL16Quh4iIjBwDQRvlam+JiUE1q0mu3JskcTVERGTsGAjasCeHd4FMAPacy0VChkbqcoiIyIgxELRhvs42CAus6SX4ZA97CYiIqG4MBG3cvBFdIAjArtPZSMwukrocIiIyUgwEbZyfmx3GBrgD4FgCIiKqGwOBGZg7ogsAYPvJTCTnFUtcDRERGSMGAjPQ01ON0O6u0InAp/suSl0OEREZIQYCMzFvpB8AYOvxDKTnl0pcDRERGRsGAjPRx9sBQ/2codWJ7CUgIqKbMBCYkfmjanoJNselI0tTJnE1RERkTBgIzEh/HycM9HVClVbE59HJUpdDRERGhIHAzNzoJVgfk4bconKJqyEiImPBQGBmBnVuh74dHFBRrcNqroRIRETXMRCYGUEQ8PT1Jw7WHLmE/JJKiSsiIiJj0OhAsH//foSFhcHT0xOCIGDbtm23PaaiogIvvfQSOnbsCJVKBR8fH3z99ddNqZdawHB/F/Rqr0ZppRZfHuBYAiIiakIgKCkpQWBgIFauXNngY6ZOnYrdu3fjq6++QmJiItavXw9/f//GXppaiCAI+rEE3/2ViqvFFRJXREREUlM09oCxY8di7NixDd5/165diI6ORnJyMpycnAAAPj4+jb0stbDQ7q7o1V6NUxkafLE/GRHjuktdEhERScjgYwh++eUXBAcH4/3330f79u3RtWtXLFq0CGVldT8HX1FRgcLCwlobtSxBELBwdFcAwHeHU/nEARGRmTN4IEhOTsbBgweRkJCArVu3YsWKFdi8eTOeeuqpOo+JjIyEWq3Wb97e3oYu0ywN93dBH28HlFfp8Nk+jiUgIjJnBg8EOp0OgiBg7dq1GDBgAMaNG4fly5fju+++q7OXICIiAhqNRr+lp6cbukyzJAgCnrurppdgzdFLyClkLwERkbkyeCDw8PBA+/btoVar9a91794doiji8uXLtzxGpVLB3t6+1kaGMaSLM/r7OKKyWoeVe5OkLoeIiCRi8EAwePBgZGZmori4WP/a+fPnIZPJ4OXlZejL020IgoBnr48l2BCTjowCrnFARGSOGh0IiouLER8fj/j4eABASkoK4uPjkZaWBqCmuz88PFy///Tp09GuXTvMmjULZ86cwf79+/H8889j9uzZsLKyaplPQc0yqLMz7ujkhEotewmIiMxVowNBbGwsgoKCEBQUBABYuHAhgoKCsGTJEgBAVlaWPhwAgK2tLaKiolBQUIDg4GDMmDEDYWFh+Oijj1roI1BLWDi6Zl6IH/9OR3p+qcTVEBFRaxNEURSlLuJ2CgsLoVarodFoOJ7AgB766igOXLiCqcFeeH9yoNTlEBFRC2jodyjXMiC9G2MJfjqWgdQrJRJXQ0RErYmBgPT6dnDECH8XaHUiPtp9QepyiIioFTEQUC03egm2xWcgKbf4NnsTEVFbwUBAtfT2ckBodzfoROCD389JXQ4REbUSBgK6yaIxXSGXCfj9dA72nsuVuhwiImoFDAR0k27u9nhkiC8AYMkvCSir1EpcERERGRoDAd3SM6P84Km2RHp+GT7ZywGGRERtHQMB3ZKNSoFX7+0JAPhifzIu5BRJXBERERkSAwHV6a4ebgjt7ooqrYiXtiXABOawIiKiJmIgoDoJgoDX7u0JKws5YlLy8dOxDKlLIiIiA2EgoHp5OVrjmVA/AMA7O8+ioLRS4oqIiMgQGAjoth4Z4ouubrbIL6nEe7s4NwERUVvEQEC3ZSGX4e1JvQAA62PSEXcpX+KKiIiopTEQUIP093HCtGBvAMBLWxNQpdVJXBEREbUkBgJqsMVju8HR2gLnsovwzaEUqcshIqIWxEBADeZoo0TEuO4AgP9GXUB6fqnEFRERUUthIKBGmdLPCwN9nVBWpcUrP3NuAiKitoKBgBpFEAS8c18vKOUy7EvMw/aTWVKXRERELYCBgBqts4st5o7oAgB4/dfT0JRWSVwRERE1FwMBNcmc4Z3QxdUWV4or8e6us1KXQ0REzcRAQE2iUsgRed//5iaISeHcBEREpoyBgJqsv48THhzQAQAQseUkKqq1EldERERNxUBAzbL47m5wtlXhYl4JVu27KHU5RETURAwE1Cxqawu8dm8PAMCney8iKbdY4oqIiKgpGAio2cb38sAIfxdUanV4cesp6HScm4CIyNQwEFCzCYKANycGwMpCjpiUfGyKS5e6JCIiaqRGB4L9+/cjLCwMnp6eEAQB27Zta/Cxhw4dgkKhQJ8+fRp7WTJyXo7WeO6urgCAt3ecRU5hucQVERFRYzQ6EJSUlCAwMBArV65s1HEFBQUIDw/HqFGjGntJMhEzB/mgt5caheXVeHHLKU5rTERkQhodCMaOHYu33noLkyZNatRxc+bMwfTp0xESEtLYS5KJUMhlWDolEEq5DLvP5WLLsQypSyIiogZqlTEE33zzDZKTk/Hqq682aP+KigoUFhbW2sg0dHWzw4LRfgBqpjXmrQMiItNg8EBw4cIFLF68GGvWrIFCoWjQMZGRkVCr1frN29vbwFVSS3p8aCcEejugsLwaEbx1QERkEgwaCLRaLaZPn47XX38dXbt2bfBxERER0Gg0+i09naPWTYlCLsPSyb2hlMuw51wuNsddlrokIiK6DYMGgqKiIsTGxmLevHlQKBRQKBR44403cOLECSgUCuzZs+eWx6lUKtjb29fayLT4udnh2dE1IfCN7WeQreGtAyIiY2bQQGBvb49Tp04hPj5ev82ZMwf+/v6Ij4/HwIEDDXl5kthjQ30R6O2AovJqLN5ykrcOiIiMWMNu6v9DcXExkpKS9D+npKQgPj4eTk5O6NChAyIiIpCRkYHvv/8eMpkMAQEBtY53dXWFpaXlTa9T26OQy7BsSm+M++gg9iXmYVPcZUwN5ngQIiJj1OgegtjYWAQFBSEoKAgAsHDhQgQFBWHJkiUAgKysLKSlpbVslWSyurjaYeH1Wwdv/noGWZoyiSsiIqJbEUQT6MctLCyEWq2GRqPheAITpNWJuH/VX4hPL8CdXV3w7az+EARB6rKIiMxCQ79DuZYBGZxcJtRMWKSQIfp8HjbF8qkDIiJjw0BAraKLqy0WXV/r4M3tZ5BZwFsHRETGhIGAWs0jQzqhbwcHFFVU44Wf+NQBEZExYSCgViOXCfhgSiBUChkOXLiCDX9zwikiImPBQECtqrOLLZ4f4w+gZpnky9dKJa6IiIgABgKSwKzBvgju6Ijiimos/olrHRARGQMGAmp1cpmA9yf3hqWFDAeTrmBdDOetICKSGgMBSaKTiy2eH9MNAPDOjrNIz+etAyIiKTEQkGRmDfLBAB8nlFRq8cJPJ6HT8dYBEZFUGAhIMrJ/3Dr46+JVrD16SeqSiIjMFgMBScrH2QYv3F1z6yDyt3O4dLVE4oqIiMwTAwFJ7uEQHwz0dUJppRbPbIhHlVYndUlERGaHgYAkJ5MJWDY1EHaWCsSnF2DFn+elLomIyOwwEJBR8HK0xrv39QYAfLrvIv66eEXiioiIzAsDARmN8b09MC3YG6IILNx4AtdKKqUuiYjIbDAQkFF59d4e6ORig+zCci6ARETUihgIyKhYKxX46IEgWMgF/HEmB2uPchZDIqLWwEBARiegvVr/KOKb28/gQk6RxBUREbV9DARklGYP9sWwri6oqNbh6fXHUV6llbokIqI2jYGAjJJMJmDZlEA42ypxLrsI7/52TuqSiIjaNAYCMloudiosnRIIAPj2r1R891cqBxkSERkIAwEZteH+rnhsqC8A4NVfTuPJNcdQUMrHEYmIWhoDARm9iLHd8fL47rCQC9h1OhvjPjyAmJR8qcsiImpTGAjI6MlkAh4d2glbnxoMX2cbZGrK8cAXh7Hiz/Oo5roHREQtgoGATEZAezW2Pz0E9/f1gk4EVvx5AdO/PIrMgjKpSyMiMnmNDgT79+9HWFgYPD09IQgCtm3bVu/+W7ZswejRo+Hi4gJ7e3uEhITg999/b2q9ZOZsVAosmxqIFdP6wFalQExqPsZ+eAD7z+dJXRoRkUlrdCAoKSlBYGAgVq5c2aD99+/fj9GjR2Pnzp2Ii4vDiBEjEBYWhuPHjze6WKIbJga1x475QxDopYamrAqPfh+LQ0lcEImIqKkEsRnPcQmCgK1bt2LixImNOq5nz56YNm0alixZ0qD9CwsLoVarodFoYG9v34RKqa2qrNZh7rpjiDqTAysLOX54ZACCfZykLouIyGg09Du01ccQ6HQ6FBUVwcmp7l/aFRUVKCwsrLUR3YpSIcMn04Mw1M8ZZVVazPrmb5y8XCB1WUREJqfVA8HSpUtRXFyMqVOn1rlPZGQk1Gq1fvP29m7FCsnUqBRyfPFQMAb6OqGoohoPfRWDs1kMkUREjdGqgWDdunV4/fXX8eOPP8LV1bXO/SIiIqDRaPRbenp6K1ZJpshKKcdXM/sjqIMDNGVVeOiro0jKLZa6LCIik9FqgWDDhg149NFH8eOPPyI0NLTefVUqFezt7WttRLdjq1Lg21kD0NPTHleKK/Gf1UeRdrVU6rKIiExCqwSC9evXY9asWVi/fj3Gjx/fGpckM6W2ssAPjwyEn6stsgvLMX31Ec5TQETUAI0OBMXFxYiPj0d8fDwAICUlBfHx8UhLSwNQ090fHh6u33/dunUIDw/HsmXLMHDgQGRnZyM7OxsajaZlPgHRvzjZKLH20YHwaWeNy9fKcPeK/Vi17yKXUCYiqkejHzvct28fRowYcdPrDz/8ML799lvMnDkTqamp2LdvHwBg+PDhiI6OrnP/huBjh9QUGQVlePS7WP0AQ3d7SywI9cPkfl5QyDlJJxGZh4Z+hzZrHoLWwkBATaXVidh2PAPLo84j4/qtg84uNnh+jD/G9HSHIAgSV0hEZFgMBET/UFGtxZojafhkzwVcK60CAPTxdsDTI7tgiJ8zVAq5xBUSERkGAwHRLRSVV+HL/clYfTAFpZU1YwqslXIM9XNGaHc3jOjmCmdblcRVEhG1HAYConrkFVVg1b6L2HEqEzmFFfrXBQEI8nbAqO5uGNfLA77ONhJWSUTUfAwERA0giiISMgrx59kc/Hk2B6cz/zfDoVwmYM6dnTB/lB9vKRCRyWIgIGqCLE0Zdp/Nxa6EbBy8vnqiv5sdlk4JRC8vtcTVERE1HgMBUTPtSsjCS1sTcLWkEnKZgKeGd8bTI/2gVPCRRSIyHUa72iGRqbg7wAN/PDsM43t7QKsT8fGeJNz7yUEkZHBSLSJqexgIiOrRzlaFldP7YuX0vnCyUeJcdhEmrjyE/0adh1Zn9J1rREQNxkBA1ADje9f0FowNcEe1TsSHuy/gnZ1npS6LiKjFMBAQNZCzrQqfzuiL9+7vBQD46mAK1h1Nk7gqIqKWwUBA1AiCIGBa/w54NrQrAGDJzwn46/rTCM2RW1iOJT8nIOpMTrPPRUTUFAwERE0wf1QX3BvoiWqdiDlr4pCcV9zkcx1Lu4awTw7i+8OXMH/9ceQWlrdgpUREDcNAQNQEgiDg/cm9EdTBAYXl1Xjku1gUlFY2+jwb/07DA58f0c+WWFalxcd7klq63Fuq0uqQnl/aKtciIuPHQEDURJYWcnzxUDDaO1gh5UoJnlxzDJXVugYdW1mtwyvbEvDCT6dQqdXh7p7uWB0eDABYH5OGS1dLGlzH5rjLeGv7GcRduoaGTCuiKa3CZ9EXMez9vRj6/l6OgyAiAJyYiKjZzmYVYvKqv1BSqcUD/b0ReV+vepdVziuqwFNr4/B36jUIAvDc6K54angXyGQCwr+Owf7zebg30BMfPRh022v/dfEKpn95VP+zTztrTAxqj0lB7dGxXe11GJLzivHNoVRsjruMsiqt/nUXOxUO/N8IWFpwemaitogzFRK1ot1nc/Do97EQReDl8d3x6NBOt9zvRHoBnvghDtmF5bBTKfDhg30wspub/v2EDA3u+fggAGDH/CHo6Vn3dMmF5VUYu+IAMgrK0M3dDmn5pfoVHAGgX0dHTApqD28na3z/Vyr2JObixv/bu7nbYfYQX3z45wVkFJRhyT09MHuIbwu0BBEZGwYCola2+kAy3tpRMzeBvaUCIgBRrFlASScCOlFEpVYHUQQ6u9jgi/BgdHaxvek8T68/jl9PZGK4vwu+nTWgzus99+MJ/HTsMjo4WeO3Z4ZCEIA/Tudgy/EMHLyQh1vNmzSqmyseGeKLkM7tIAgC1sekIWLLKfYSELVhDf0OVbRiTURt2iNDfJGeX4rvDl9CYXl1nfuN6emGpVMCYWdpccv3nxvdFb+dysK+xDwcSb6KOzq1u2mfXQnZ+OnYZQgCsHxqIGxUNf9XnhjUHhOD2iO3sBy/nMjElmMZyNSUIay3J2YN9kGnfwWQ+/t64ZM9ScgoKMO6o2nsJSAyY+whIGphGQVlKK/SQgAgEwQIwv/+V6mQwdXO8rbneHnbKaw5koagDg7Y8uSgWmMSrhRXYMx/9+NqSSXm3NkZi8d2a1a97CUgatu4uBGRRNo7WKGziy06udjCx9kGHdvZwNvJGl6O1g0KAwAwf6QfLC1kOJ5WUGuyIlEUsfinU7haUolu7nZ4drRfs+u9v68X2jtYIa+ogk8cEJkxBgIiI+Rqb4nZg2u67z/4PVG/kNKmuMv482wOLOQC/jutD1SK5v81r1TIMG9kFwDAquiLKP/HEwhEZD4YCIiM1BN3dobaygIXcoux5dhlpOeX4o1fzwAAFo72R3ePlrt9xl4CImIgIDJSaisLPDW8MwDgv1Hn8dymEyiuqEZwR0c8PuzWjzU2FXsJiIiBgMiIPTzIB272KmRqyhGTkg9rpRzLpgZCLqt74qOmamovgU4nIim3GBv/TsP/bT6BMf/dj0WbTjRo1kQiMh587JDIiFlayLEgtCsitpwCALxyT4+bZiBsKTd6CSK2nMKq6IuYPrDDLZ840OpExF26hr9T8xF36RqOpV1DQWlVrX0Sc4oQ2t0Vdwd4GKRWqu3z6ItIyCzEMD9njOruBicbpdQlkQliICAyclP6eeHYpWtQW1nggf7eBr1WXfMSaHUi/k7Nx46TWfgtIRtXiitqHadSyBDo7YB+HR2RW1iBn45dxru/ncPIbm5QKtgRaUjJecWI/O0cAODXE5mQCUBwRyeE9nDF6B7u8HU2TICktqfRgWD//v344IMPEBcXh6ysLGzduhUTJ06s95h9+/Zh4cKFOH36NLy9vfHyyy9j5syZTSyZyLwo5DJ8MCWwVa71716Cbu52+P10NnYmZCOv6H8hQG1lgSFdnNGvoyP6dXREdw97/Rd/cUU1os/nIfVqKdYevYRZgznZkSGtj6m5vdPF1RZKuQxnsgoRk5qPmNR8vLPzHDq72OCe3p54emQXKOQMZ1S3RgeCkpISBAYGYvbs2bjvvvtuu39KSgrGjx+POXPmYO3atdi9ezceffRReHh4YMyYMU0qmogM55+9BNNX/2/hJHtLBcb0dMf43h4Y3MUZFnV8udiqFFg4uite3HoKH+6+gPv6ekFtdetZGf9pxZ/nsTcxDyum9eFftQ1UXqXF5rjLAIAX7u6G0T3ccPlaKXafzUXUmRwcSb6Ki3kl+HD3BfT0tMddPd0lrpiMWbNmKhQE4bY9BC+88AJ27NiBhIQE/WsPPPAACgoKsGvXrgZdhzMVErWurccv49mNJ2D3zxDQ2bnB3f/VWh3GfngAF3KL8cSwTogY173e/W/MlggAgV5qbH5yUJ2Bg/7n5/gMPLMhHu72ljj4woibegAKy6uw+KeT2HkqG48M8cUr9/SQqFKSktHMVHj48GGEhobWem3MmDE4fPhwncdUVFSgsLCw1kZErWdSkBcOvjACcS+PxtIpgRjh79qosQAKuQwvXg8B3xxKRXp+aZ37xl26hiU/1/zBIJcJOHFZg5V7k5r3AczE2utPgzwwwPuWtwPsLS0w5nqvQExKfqvWRqbH4IEgOzsbbm5utV5zc3NDYWEhysrKbnlMZGQk1Gq1fvP2NuxAKiK6mZejdbMGBA73d8HgLu1QqdXhg98Tb7lPbmE5nlwThyqtiLEB7lh2fazEx3uScCK9oMnXNgcXcooQk5IPmQBMq2ew6QBfJwDA6UwNisqr6tyPyCj75CIiIqDRaPRbenq61CURUSMJgoCIsd0hCMAvJzJv+oKvrNbhybXHkFtUAT9XW3wwJRAT+njint4e0OpEPLsxHmWVnCCpLuuuDyYc2c0NHmqrOvfzUFvB28kKOhE4llbQStWRKTJ4IHB3d0dOTk6t13JycmBvbw8rq1v/I1apVLC3t6+1EZHpCWivxqSg9gCAt3eerTVZ0eu/nkbcpWuws1Tgi/Bg2KoUEAQBb00MgJu9CslXShD521mpSjdq5VVa/HR9MOGMgR1uu/8An5oltGNSrhq0LjJtBg8EISEh2L17d63XoqKiEBISYuhLE5ERWHSXP1QKGWJS8vUrN26IScPao2kQBOCjB4NqPVXgYK3EB5Nrbh18f/gSos/nSVK3MdtxMguF5dVo72CFYV1dbrv/wOu3DTiOgOrT6EBQXFyM+Ph4xMfHA6h5rDA+Ph5paTXdVxEREQgPD9fvP2fOHCQnJ+P//u//cO7cOXz66af48ccf8eyzz7bMJyAio+bpYIVHh9bMRfDub+cQk5KPJT+fBlATFkb4u950zLCuLng4pCMA4PlNJ1BQWtnk62dpylCl1TX5eGN043bBgwO8GzSN9Y1xBCfSNVyngurU6EAQGxuLoKAgBAUFAQAWLlyIoKAgLFmyBACQlZWlDwcA4Ovrix07diAqKgqBgYFYtmwZVq9ezTkIiMzInDs7o52NEslXSjBj9RFUanUYG+CuX7zpVhaP7Y5OLjbILarAS9sSmrQ2wtcHUxASuQeTPj2EkorqJtdfpdXhYl4xfj+djZV7k7BwYzye+7FmsanWlphdhLhL16CQCZga3LAB1x3bWcPVToVKrQ7xHKxJdWj0xETDhw+v9/+Y33777S2POX78eGMvRURthJ2lBRaM7opXtiWgSivqBxEKQt1/3Vop5fjv1D64b9Vf2HEyC3f1cMOEPu0bfM1P9yXh/V01TzckZBRiwcZ4fP6ffpA1cGGoX05kYufJLCTlFePS1RJUaW/+veftZIUFoV0bXFNLWHf0EgAgtLsbXO0tG3SMIAgY4OuE7SezEJOSjzs6tTNkiWSijPIpAyJqex7o743eXmo426r0gwhvJ9DbAfNH+gEAXt6WgMTsotseI4oilked14eBqcFeUCpkiDqTg/frePzx31buTcL89cex63Q2knKLUaUVYa2Uo1d7NSb28cTUYC8ANXMstGYvQWllNbYcywAATG/AYMJ/4jgCuh0ubkRErcJCLsPWpwajWqeDSnHzKop1mTuiM/Yk5uJEegHGf3QAs4f4Yv4ov1sGClEU8e5v5/D5/mQAwOKx3TDnzs4Y1NkZCzbG47Poi+jiaovJ/bxuea0bYeLjPTUTI80c5IMR3VzRxdUWHvaW+t6FmsWeriHlSgnWH03DY8M6NbY5mmT7iSwUVVSjg5M1hnRxbtSxA3xregXiLl1DlVbHmSDpJvwXQUStRi4TGhUGgJpZD798qB9G93BDtU7EF/uTMWrZPvxyIrPW7UudTsTrv57Rh4FXw3pgzp01YxQmBrXHvBFdAAARW07i79Sb/0oWRRHv7DyrDwMRY7vhtXt74s6uLmjvYFXrVoNcJuDJ6+f+4kByqw3UW6sfTNihwbc+bvBztYWDtQXKqrQ4ncnZX+lmDAREZPRc7S3xZXgwvp4ZjA5O1sgprMD89ccx/cujOJ9TBK1OxItbT+Hbv1IhCMA7k3rdtMriwtFdMTbAHVVaEU/8EFdrOmWdTsSSn0/jywMpAIDX7+2JJ+6se8AjUBMyPNWWyCuq0C8wZEinMzU4kV4AC7mAKcG37uGoj0wmILjjjdsGnI+AbsZAQEQmY2Q3N/zx7DAsHN0VKoUMh5OvYtyHB3Dfqr+w4e90yARg6eTAW95fl8kELJsaiID29sgvqcQj3/2NovIqaHUiFm85iR+OXIIgAO/e1wsPD/K5bS1KhQyPX79V8Fn0RYM/2rju+roFd/V0h7Otqknn4DgCqg8DARGZFEsLOeaP8sOfC+/EXddvI5xIL4BcJuDDB4Jwfx3jAwDAWqnA6vD+cLNX4XxOMZ5efxwLf4zHj7GXIROA5VMD8cCAhg/Wm9a/A9rZKHH5Whl+PZHZEh/vljRlVfg5vub8MxpR378N+Ecg0OmavNAttVEMBERkkrydrPFFeDC+mdUfd/Vww+rwYIQFet72OHd1ze0HSwsZ9iXm4ef4TChkAj6Z3heTghrXFW+llOOR65MufbrvosG+ZJf/kYjiimp0dbNFSOemPzLY09Me1ko5CsurkZhz+yc2yLwwEBCRSRvh74ovwoMxotvNMx7WpbeXA5ZP7QMAUMpl+Ow//TCul0eTrv+fOzrCzlKBpNxi/HEmu0nnqE9ChgY/HKmZe+DVsJ71zt1wOwq5DP06OgLgbQO6GQMBEZmlcb08sG3uYPy2YChCe7jd/oA62Fta4OEQHwDAyr0XmzSjYl1qBjsmQCcC9/T2wOBGPmp4KxxHQHVhICAis9XH2wGdXWybfZ7ZQ3xhZSHHqQwNDly40gKV1dh87DKOpRXAWinHy+N7tMg5b8xHEJOa36LhhUwfAwERUTM52Sjx4PXBfp/sTWqRc2pKq/Dub+cAAAtC/eCubtg0xbfT20sNpUKGvKIKpF4tvf0BZDYYCIiIWsDjwzrBQi4gJiX/lhMfNdbSPxKRX1IJP1fbm+ZUaA5LCzn6eDsAMNx8BH+eyUFsC7QBtS4GAiKiFuCuttRPibyymb0Epy5rsOb6IkavT+jZ4tMM3xhHcNQA4wgOXMjDo9/HYvJnh7H6QHKLn58Mh2sZEBG1kCeGdcbGv9OxLzEPj34XCycbC6itrm/WSqitLOBkrUSwjyMsLW49hbNOJ+KVnxMgisC9gZ4Y1Ln5Awn/rb+PYQYW6nSi/jYHALy14ywyC8rx8vjujZ5qmVofAwERUQvxcbbBxD7tseV4Bv48m1Pnfo7WFnjojo74T0hHuNrVHhuwKS4d8ekFsFHK8dL47gaps29HR8hlAi5fK0NGQRnaO1i1yHm3n8rC6cxC2KoUmD3YBx/tScLXh1KQXViG5VP71BmCyDgwEBARtaC3JgUgtIcbrpZUorCsCpqyKmhKq1BQVglNWRVSr5Qiu7AcH+1JwmfRyZjQxxOPDPVFN3d7FJRW6v/CfnZ0V7jZt8xAwn+zVSkQ4GmPE5c1+DslH+2D2jf7nJXVOiy9vrz0E8M64elRfujsaotFm05g56lsXCmKwRfh/eBgrWz2tcgwGAiIiFqQtVJR7yRHWp2IP05nY/XBFMRduoZNcZexKe4yhvo5Q6WQ41ppFbq62TZoPYXmGODrhBOXNYhJzcfEFggE62PSkJZfCmdblX72xgl92sPFToUnvo9DTGo+Jn92GN/O6g8vR+tmX49aHgcVEhG1IrlMwNheHvjpyUHY8tQgjO/lAZkAHLhwRX+b4Y0JAS0+kPDf9PMRtMA4guKKany85wKAmkckrZX/+1tzUGdnbHoyBO72lkjKLcakT//C6UxNs69JLY+BgIhIIn07OGLljL6Ifn4EHhnii3Y2Sswe7Is7OjV9vYKG6u9TM4VxUm4xrhRXNOtcqw8k40pxJXydbTCtv/dN73dzt8fWuYPg72aHvKIKTPv8COIu8bFEYyOIJjBVVWFhIdRqNTQaDezt7aUuh4ioTbh7xX6cyy7CkC7OGNXdFXd0agd/N7tGPRFwpbgCd76/FyWVWqyc3hfje9d9u0RTVoXHv4/F0ZR82Cjl+GbWAP0KjGQ4Df0O5RgCIiIzdVdPd5zLLsLBpCs4mFQz5bKDtQUG+jphoG873NGpHbp72NW7oNIne5JQUqlFoJca43q513s9tZUFvp01AI99H4uDSVfw8Ncx+Hpm/2at4Nhc5VVaKGQCFAa+RWMK2ENARGSmRFHE8fQCHEm+iiPJ+YhNzUdppbbWPsEdHfHi+O7o28HxpuPTrpZi1PJ9qNKKWPfoQAxq4OJL5VVaPPZ9LA5cuAJLCxm+erh/iyzc1FgpV0owedVf6NDOGpvnDIK8jc6V0NDvUAYCIiICAFRpdUjI0OBIcv71kHAVFdU6AMD4Xh74v7v90bGdjX7/ZzYcx8/xmRjW1QXfzx7QqGuVV2kxZ00c9iXmQaWQ4cvwYAzr6nLTfqIoIu7SNWz8Ox3nsovw9qQA9PZyaNbnBICKai3uX/UXEjIKAQAfTO6NKcE3j39oCxgIiIioWbI15VgelYhNcZchioCFXMB/7uiI+SP9kFFQhns+PggA2P70EAS0Vzf6/BXVWjy55hj2nMuFUiHDFw/1w3B/VwBAXlEFthy7jB9j03Exr0R/jLeTFXbMHwp7S4tmfbY3t5/BVwdTIAiAKAKeakvsWTS8TU6exEBAREQt4mxWISJ/O4f95/MAAHaWCrjaqXAxrwQT+njiwweCmnzuimot5q07jqgzOVDKZVg0pitiU69hz7lcVOtqvp6sLOQY39sDR5Kv4vK1Mkzo44kV0/rUO7ahPnvP5WLWt38DAFZO74u3dpxBlqYcL43rjseGdWryZzFWDf0ObdIoipUrV8LHxweWlpYYOHAgYmJi6t1/xYoV8Pf3h5WVFby9vfHss8+ivLy8KZcmIqJW1t3DHt/PHoAfHhmA7h72KCqvxsW8EljIBTw32r9Z51Yp5Fg5vS/u7umOSq0O7+w8hz/O5KBaJ6KPtwMi7+uFmJdGYemUQHz4QBDkMgE/x2diy7GMJl0vp7Acz206AQCYOcgH43t74NnQrgCAlfuSoCmratbnMWWN7iHYuHEjwsPD8dlnn2HgwIFYsWIFNm3ahMTERLi6ut60/7p16zB79mx8/fXXGDRoEM6fP4+ZM2figQcewPLlyxt0TfYQEBEZB61OxNbjGfj+cCom9GmPR4a0zNLMVVodIracwqGkKxjXywPT+nujq5vdTft9vPsClkWdh41Sjh3zh8LH2eYWZ6u79oe+Ooq/Ll5FD4+auRFUCjmqtTrc/eEBJOUW46nhnfF/d3dr9me5kFOMsiotKqq1qKjWoaJKV/Pf1//Xz82uVeabAAx4y2DgwIHo378/PvnkEwCATqeDt7c3nn76aSxevPim/efNm4ezZ89i9+7d+teee+45HD16FAcPHmzRD0NERG2bVifiwS+PICYlH7291Ng8ZxCUioZ1dq/cm4QPfk+EtVKOX58egs4utvr3/jidjcd/iIOlhQzRz49o9DoSoijiWNo1bDueiR2nspBfUlnv/g/d0RFvTgxo1DWayiC3DCorKxEXF4fQ0ND/nUAmQ2hoKA4fPnzLYwYNGoS4uDj9bYXk5GTs3LkT48aNq/M6FRUVKCwsrLURERHJZQJWTOsDtZUFTl7WYHnU+QYdF3fpmn7f1+/tWSsMAMDoHm7o19ER5VU6rPjzQoPrScotxrI/EjHsg724f9Vh/HDkEvJLKmFnqUDHdtbo6maLXu3VCO7oiMFd2mFkN1eMDXBHD0/j++O2URMTXblyBVqtFm5ubrVed3Nzw7lz5255zPTp03HlyhUMGTIEoiiiuroac+bMwYsvvljndSIjI/H66683pjQiIjITng5WeO/+Xpiz5hg+338RQ/2c653HQFNWhfnrj0OrE3FvoCcm9/O6aR9BEPDC3d0w9fPD+DE2HY8O9b0pNNwgiiJ+OZGJLw8k6x9bBAAbpRxjAtwxsU97DOrczuQmOzJ4tfv27cM777yDTz/9FMeOHcOWLVuwY8cOvPnmm3UeExERAY1Go9/S09MNXSYREZmQuwM88OCADhBF4NmN8bhax3oMeUUVWPzTSWQUlKGDkzXenhRQ59MJA3ydMKqbK7Q6Ecv+SKzzfE/8EIdnNsQjIaMQCpmAUd1c8dGDQYh9eTSWT+2DYV1dTC4MAI3sIXB2doZcLkdOTk6t13NycuDufuspK1955RU89NBDePTRRwEAvXr1QklJCR5//HG89NJLkMlubjSVSgWVStWY0oiIyMwsuacHYlKu4mJeCV746SQixnXHmcxCnMkq1P9vXlFNUFDIBHz0YBDsbjN/wfN3+2NPYi52nspGfHoB+ng76N/beSoLL29LQH5JJSzkAuaO6ILwEB842SgN+TFbTaMCgVKpRL9+/bB7925MnDgRQM2gwt27d2PevHm3PKa0tPSmL325vGbiBxOYAoGIiIyUlVKOjx/si4krD+HPs7n482zuTfsIAuDrbINnRvnV+nKvSzd3e9wX5IWfjl3Ge7+dw7rHBkJTVoUlP5/GLycyAdQ8hrlsSqBRjgNojkYvbrRw4UI8/PDDCA4OxoABA7BixQqUlJRg1qxZAIDw8HC0b98ekZGRAICwsDAsX74cQUFBGDhwIJKSkvDKK68gLCxMHwyIiIiaooenPV4J64FXtiXAykKObh526OFhjx6e9ujhYQ9/dztYKxv3VffsaD/8eiITh5OvYtkf57ExNh15RRWQywQ8Nbwznh7p1+AnG0xJowPBtGnTkJeXhyVLliA7Oxt9+vTBrl279AMN09LSavUIvPzyyxAEAS+//DIyMjLg4uKCsLAwvP322y33KYiIyGw9dEdHhPX2gJ2lRYssUOTlaI3wkI5YfTAFn+xNAgB0drHBsql9GtTLYKo4dTEREdG/XCupxMhl+1BQVoVHBvti0Rh/k13noKHfoY3uISAiImrrHG2U2PnMUFRU6Ro1G6IpYyAgIiK6BQ+1ldQltKq2NyqCiIiIGo2BgIiIiBgIiIiIiIGAiIiIwEBAREREYCAgIiIiMBAQERERGAiIiIgIDAREREQEBgIiIiKCiUxdfGP9pcLCQokrISIiMi03vjtvt5ahSQSCoqIiAIC3t7fElRAREZmmoqIiqNXqOt83ieWPdTodMjMzYWdnB0Fo/lrXQE1i8vb2Rnp6OpdUvgW2T93YNvVj+9SP7VM3tk39mto+oiiiqKgInp6ekMnqHilgEj0EMpkMXl5eBjm3vb09/+HVg+1TN7ZN/dg+9WP71I1tU7+mtE99PQM3cFAhERERMRAQERGRGQcClUqFV199FSqVSupSjBLbp25sm/qxferH9qkb26Z+hm4fkxhUSERERIZltj0ERERE9D8MBERERMRAQERERAwEREREBAYCIiIigpkGgpUrV8LHxweWlpYYOHAgYmJipC5JEvv370dYWBg8PT0hCAK2bdtW631RFLFkyRJ4eHjAysoKoaGhuHDhgjTFSiAyMhL9+/eHnZ0dXF1dMXHiRCQmJtbap7y8HHPnzkW7du1ga2uL+++/Hzk5ORJV3HpWrVqF3r1762dMCwkJwW+//aZ/31zbpS7vvvsuBEHAggUL9K+Zcxu99tprEASh1tatWzf9++bcNgCQkZGB//znP2jXrh2srKzQq1cvxMbG6t831O9mswsEGzduxMKFC/Hqq6/i2LFjCAwMxJgxY5Cbmyt1aa2upKQEgYGBWLly5S3ff//99/HRRx/hs88+w9GjR2FjY4MxY8agvLy8lSuVRnR0NObOnYsjR44gKioKVVVVuOuuu1BSUqLf59lnn8Wvv/6KTZs2ITo6GpmZmbjvvvskrLp1eHl54d1330VcXBxiY2MxcuRITJgwAadPnwZgvu1yK3///Tc+//xz9O7du9br5t5GPXv2RFZWln47ePCg/j1zbptr165h8ODBsLCwwG+//YYzZ85g2bJlcHR01O9jsN/NopkZMGCAOHfuXP3PWq1W9PT0FCMjIyWsSnoAxK1bt+p/1ul0oru7u/jBBx/oXysoKBBVKpW4fv16CSqUXm5urghAjI6OFkWxpj0sLCzETZs26fc5e/asCEA8fPiwVGVKxtHRUVy9ejXb5R+KiopEPz8/MSoqSrzzzjvFZ555RhRF/tt59dVXxcDAwFu+Z+5t88ILL4hDhgyp831D/m42qx6CyspKxMXFITQ0VP+aTCZDaGgoDh8+LGFlxiclJQXZ2dm12kqtVmPgwIFm21YajQYA4OTkBACIi4tDVVVVrTbq1q0bOnToYFZtpNVqsWHDBpSUlCAkJITt8g9z587F+PHja7UFwH87AHDhwgV4enqiU6dOmDFjBtLS0gCwbX755RcEBwdjypQpcHV1RVBQEL788kv9+4b83WxWgeDKlSvQarVwc3Or9bqbmxuys7Mlqso43WgPtlUNnU6HBQsWYPDgwQgICABQ00ZKpRIODg619jWXNjp16hRsbW2hUqkwZ84cbN26FT169DD7drlhw4YNOHbsGCIjI296z9zbaODAgfj222+xa9curFq1CikpKRg6dCiKiorMvm2Sk5OxatUq+Pn54ffff8eTTz6J+fPn47vvvgNg2N/NJrH8MZHU5s6di4SEhFr3Oc2dv78/4uPjodFosHnzZjz88MOIjo6WuiyjkJ6ejmeeeQZRUVGwtLSUuhyjM3bsWP1/9+7dGwMHDkTHjh3x448/wsrKSsLKpKfT6RAcHIx33nkHABAUFISEhAR89tlnePjhhw16bbPqIXB2doZcLr9ptGpOTg7c3d0lqso43WgPthUwb948bN++HXv37oWXl5f+dXd3d1RWVqKgoKDW/ubSRkqlEl26dEG/fv0QGRmJwMBAfPjhh2bfLkBNt3dubi769u0LhUIBhUKB6OhofPTRR1AoFHBzczP7NvonBwcHdO3aFUlJSWb/78fDwwM9evSo9Vr37t31t1QM+bvZrAKBUqlEv379sHv3bv1rOp0Ou3fvRkhIiISVGR9fX1+4u7vXaqvCwkIcPXrUbNpKFEXMmzcPW7duxZ49e+Dr61vr/X79+sHCwqJWGyUmJiItLc1s2uifdDodKioq2C4ARo0ahVOnTiE+Pl6/BQcHY8aMGfr/Nvc2+qfi4mJcvHgRHh4eZv/vZ/DgwTc93nz+/Hl07NgRgIF/NzdrSKIJ2rBhg6hSqcRvv/1WPHPmjPj444+LDg4OYnZ2ttSltbqioiLx+PHj4vHjx0UA4vLly8Xjx4+Lly5dEkVRFN99913RwcFB/Pnnn8WTJ0+KEyZMEH19fcWysjKJK28dTz75pKhWq8V9+/aJWVlZ+q20tFS/z5w5c8QOHTqIe/bsEWNjY8WQkBAxJCREwqpbx+LFi8Xo6GgxJSVFPHnypLh48WJREATxjz/+EEXRfNulPv98ykAUzbuNnnvuOXHfvn1iSkqKeOjQITE0NFR0dnYWc3NzRVE077aJiYkRFQqF+Pbbb4sXLlwQ165dK1pbW4tr1qzR72Oo381mFwhEURQ//vhjsUOHDqJSqRQHDBggHjlyROqSJLF3714RwE3bww8/LIpizeMtr7zyiujm5iaqVCpx1KhRYmJiorRFt6JbtQ0A8ZtvvtHvU1ZWJj711FOio6OjaG1tLU6aNEnMysqSruhWMnv2bLFjx46iUqkUXVxcxFGjRunDgCiab7vU59+BwJzbaNq0aaKHh4eoVCrF9u3bi9OmTROTkpL075tz24iiKP76669iQECAqFKpxG7duolffPFFrfcN9btZEEVRbF4fAxEREZk6sxpDQERERLfGQEBEREQMBERERMRAQERERGAgICIiIjAQEBERERgIiIiICAwEREREBAYCIiIiAgMBERERgYGAiIiIAPw/mwTCcJbh7UYAAAAASUVORK5CYII=\n",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"model = get_model()\n",
"\n",
"metrics = MetricsCB(accuracy=MulticlassAccuracy())\n",
"cbs = [TrainCB(), DeviceCB(), metrics, ProgressCB(plot=True)]\n",
"learn = Learner(model, dls, F.cross_entropy, lr=0.2, cbs=cbs)\n",
"learn.fit(1)"
]
},
{
"cell_type": "markdown",
"id": "e36aef26",
"metadata": {},
"source": [
"## TrainLearner and MomentumLearner"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "51fe2944",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"class TrainLearner(Learner):\n",
" def predict(self): self.preds = self.model(self.batch[0])\n",
" def get_loss(self): self.loss = self.loss_func(self.preds, self.batch[1])\n",
" def backward(self): self.loss.backward()\n",
" def step(self): self.opt.step()\n",
" def zero_grad(self): self.opt.zero_grad()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c68148d5",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"class MomentumLearner(TrainLearner):\n",
" def __init__(self, model, dls, loss_func, lr=None, cbs=None, opt_func=optim.SGD, mom=0.85):\n",
" self.mom = mom\n",
" super().__init__(model, dls, loss_func, lr, cbs, opt_func)\n",
"\n",
" def zero_grad(self):\n",
" with torch.no_grad():\n",
" for p in self.model.parameters(): p.grad *= self.mom"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "452eff1d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n",
" \n",
" \n",
" accuracy | \n",
" loss | \n",
" epoch | \n",
" train | \n",
"
\n",
" \n",
" \n",
" \n",
" 0.674 | \n",
" 0.976 | \n",
" 0 | \n",
" train | \n",
"
\n",
" \n",
" 0.789 | \n",
" 0.588 | \n",
" 0 | \n",
" eval | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"