{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tiny Imagenet"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"os.environ['CUDA_VISIBLE_DEVICES']='2'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import shutil,timm,os,torch,random,datasets,math\n",
"import fastcore.all as fc, numpy as np, matplotlib as mpl, matplotlib.pyplot as plt\n",
"import k_diffusion as K, torchvision.transforms as T\n",
"import torchvision.transforms.functional as TF,torch.nn.functional as F\n",
"\n",
"from torch.utils.data import DataLoader,default_collate\n",
"from pathlib import Path\n",
"from torch.nn import init\n",
"from fastcore.foundation import L\n",
"from torch import nn,tensor\n",
"from operator import itemgetter\n",
"from torcheval.metrics import MulticlassAccuracy\n",
"from functools import partial\n",
"from torch.optim import lr_scheduler\n",
"from torch import optim\n",
"from torchvision.io import read_image,ImageReadMode\n",
"from glob import glob\n",
"\n",
"from miniai.datasets import *\n",
"from miniai.conv import *\n",
"from miniai.learner import *\n",
"from miniai.activations import *\n",
"from miniai.init import *\n",
"from miniai.sgd import *\n",
"from miniai.resnet import *\n",
"from miniai.augment import *\n",
"from miniai.accel import *\n",
"from miniai.training import *"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from fastprogress import progress_bar"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"torch.set_printoptions(precision=5, linewidth=140, sci_mode=False)\n",
"torch.manual_seed(1)\n",
"mpl.rcParams['figure.dpi'] = 70\n",
"\n",
"set_seed(42)\n",
"if fc.defaults.cpus>8: fc.defaults.cpus=8"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"path_data = Path('data')\n",
"path_data.mkdir(exist_ok=True)\n",
"path = path_data/'tiny-imagenet-200'\n",
"\n",
"url = 'http://cs231n.stanford.edu/tiny-imagenet-200.zip'\n",
"if not path.exists():\n",
" path_zip = fc.urlsave(url, path_data)\n",
" shutil.unpack_archive('data/tiny-imagenet-200.zip', 'data')\n",
"\n",
"bs = 512\n",
"\n",
"class TinyDS:\n",
" def __init__(self, path):\n",
" self.path = Path(path)\n",
" self.files = glob(str(path/'**/*.JPEG'), recursive=True)\n",
" def __len__(self): return len(self.files)\n",
" def __getitem__(self, i): return self.files[i],Path(self.files[i]).parent.parent.name\n",
"\n",
"tds = TinyDS(path/'train')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"path_anno = path/'val'/'val_annotations.txt'\n",
"anno = dict(o.split('\\t')[:2] for o in path_anno.read_text().splitlines())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class TinyValDS(TinyDS):\n",
" def __getitem__(self, i): return self.files[i],anno[os.path.basename(self.files[i])]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"vds = TinyValDS(path/'val')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class TfmDS:\n",
" def __init__(self, ds, tfmx=fc.noop, tfmy=fc.noop): self.ds,self.tfmx,self.tfmy = ds,tfmx,tfmy\n",
" def __len__(self): return len(self.ds)\n",
" def __getitem__(self, i):\n",
" x,y = self.ds[i]\n",
" return self.tfmx(x),self.tfmy(y)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"id2str = (path/'wnids.txt').read_text().splitlines()\n",
"str2id = {v:k for k,v in enumerate(id2str)}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"xmean,xstd = (tensor([0.47565, 0.40303, 0.31555]), tensor([0.28858, 0.24402, 0.26615]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def tfmx(x):\n",
" img = read_image(x, mode=ImageReadMode.RGB)/255\n",
" return (img-xmean[:,None,None])/xstd[:,None,None]\n",
"\n",
"def tfmy(y): return tensor(str2id[y])\n",
"\n",
"tfm_tds = TfmDS(tds, tfmx, tfmy)\n",
"tfm_vds = TfmDS(vds, tfmx, tfmy)\n",
"\n",
"def denorm(x): return (x*xstd[:,None,None]+xmean[:,None,None]).clip(0,1)\n",
"\n",
"all_synsets = [o.split('\\t') for o in (path/'words.txt').read_text().splitlines()]\n",
"synsets = {k:v.split(',', maxsplit=1)[0] for k,v in all_synsets if k in id2str}\n",
"\n",
"dls = DataLoaders(*get_dls(tfm_tds, tfm_vds, bs=bs, num_workers=8))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def tfm_batch(b, tfm_x=fc.noop, tfm_y = fc.noop): return tfm_x(b[0]),tfm_y(b[1])\n",
"\n",
"tfms = nn.Sequential(T.Pad(4), T.RandomCrop(64),\n",
" T.RandomHorizontalFlip(),\n",
" RandErase())\n",
"augcb = BatchTransformCB(partial(tfm_batch, tfm_x=tfms), on_val=False)\n",
"\n",
"act_gr = partial(GeneralRelu, leak=0.1, sub=0.4)\n",
"iw = partial(init_weights, leaky=0.1)\n",
"\n",
"nfs = (32,64,128,256,512,1024)\n",
"\n",
"def get_dropmodel(act=act_gr, nfs=nfs, norm=nn.BatchNorm2d, drop=0.1):\n",
" layers = [nn.Conv2d(3, nfs[0], 5, padding=2)]\n",
"# layers += [ResBlock(nfs[0], nfs[0], ks=3, stride=1, act=act, norm=norm)]\n",
" layers += [ResBlock(nfs[i], nfs[i+1], act=act, norm=norm, stride=2)\n",
" for i in range(len(nfs)-1)]\n",
" layers += [nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Dropout(drop)]\n",
" layers += [nn.Linear(nfs[-1], 200, bias=False), nn.BatchNorm1d(200)]\n",
" return nn.Sequential(*layers).apply(iw)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def res_blocks(n_bk, ni, nf, stride=1, ks=3, act=act_gr, norm=None):\n",
" return nn.Sequential(*[\n",
" ResBlock(ni if i==0 else nf, nf, stride=stride if i==n_bk-1 else 1, ks=ks, act=act, norm=norm)\n",
" for i in range(n_bk)])\n",
"\n",
"nbks = (3,2,2,1,1)\n",
"\n",
"def get_dropmodel(act=act_gr, nfs=nfs, nbks=nbks, norm=nn.BatchNorm2d, drop=0.2):\n",
" layers = [ResBlock(3, nfs[0], ks=5, stride=1, act=act, norm=norm)]\n",
" layers += [res_blocks(nbks[i], nfs[i], nfs[i+1], act=act, norm=norm, stride=2)\n",
" for i in range(len(nfs)-1)]\n",
" layers += [nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Dropout(drop)]\n",
" layers += [nn.Linear(nfs[-1], 200, bias=False), nn.BatchNorm1d(200)]\n",
" return nn.Sequential(*layers).apply(iw)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"opt_func = partial(optim.AdamW, eps=1e-5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"metrics = MetricsCB(accuracy=MulticlassAccuracy())\n",
"cbs = [DeviceCB(), metrics, ProgressCB(plot=True), MixedPrecision()]\n",
"\n",
"epochs = 25\n",
"lr = 3e-2\n",
"tmax = epochs * len(dls.train)\n",
"sched = partial(lr_scheduler.OneCycleLR, max_lr=lr, total_steps=tmax)\n",
"xtra = [BatchSchedCB(sched), augcb]\n",
"learn = Learner(get_dropmodel(), dls, F.cross_entropy, lr=lr, cbs=cbs+xtra, opt_func=opt_func)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"aug_tfms = nn.Sequential(T.Pad(4), T.RandomCrop(64),\n",
" T.RandomHorizontalFlip(),\n",
" T.TrivialAugmentWide())\n",
"\n",
"norm_tfm = T.Normalize(xmean, xstd)\n",
"erase_tfm = RandErase()\n",
"\n",
"from PIL import Image\n",
"\n",
"def tfmx(x, aug=False):\n",
" x = Image.open(x).convert('RGB')\n",
" if aug: x = aug_tfms(x)\n",
" x = TF.to_tensor(x)\n",
" x = norm_tfm(x)\n",
" if aug: x = erase_tfm(x[None])[0]\n",
" return x\n",
"\n",
"tfm_tds = TfmDS(tds, partial(tfmx, aug=True), tfmy)\n",
"tfm_vds = TfmDS(vds, tfmx, tfmy)\n",
"\n",
"dls = DataLoaders(*get_dls(tfm_tds, tfm_vds, bs=bs, num_workers=8))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def conv(ni, nf, ks=3, stride=1, act=nn.ReLU, norm=None, bias=True):\n",
" layers = []\n",
" if norm: layers.append(norm(ni))\n",
" if act : layers.append(act())\n",
" layers.append(nn.Conv2d(ni, nf, stride=stride, kernel_size=ks, padding=ks//2, bias=bias))\n",
" return nn.Sequential(*layers)\n",
"\n",
"def _conv_block(ni, nf, stride, act=act_gr, norm=None, ks=3):\n",
" return nn.Sequential(conv(ni, nf, stride=1 , act=act, norm=norm, ks=ks),\n",
" conv(nf, nf, stride=stride, act=act, norm=norm, ks=ks))\n",
"\n",
"class ResBlock(nn.Module):\n",
" def __init__(self, ni, nf, stride=1, ks=3, act=act_gr, norm=None):\n",
" super().__init__()\n",
" self.convs = _conv_block(ni, nf, stride, act=act, ks=ks, norm=norm)\n",
" self.idconv = fc.noop if ni==nf else conv(ni, nf, ks=1, stride=1, act=None, norm=norm)\n",
" self.pool = fc.noop if stride==1 else nn.AvgPool2d(2, ceil_mode=True)\n",
"\n",
" def forward(self, x): return self.convs(x) + self.idconv(self.pool(x))\n",
"\n",
"def get_dropmodel(act=act_gr, nfs=nfs, nbks=nbks, norm=nn.BatchNorm2d, drop=0.2):\n",
" layers = [nn.Conv2d(3, nfs[0], 5, padding=2)]\n",
" layers += [res_blocks(nbks[i], nfs[i], nfs[i+1], act=act, norm=norm, stride=2)\n",
" for i in range(len(nfs)-1)]\n",
" layers += [act_gr(), norm(nfs[-1]), nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Dropout(drop)]\n",
" layers += [nn.Linear(nfs[-1], 200, bias=False), nn.BatchNorm1d(200)]\n",
" return nn.Sequential(*layers).apply(iw)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"epochs = 50\n",
"lr = 0.1\n",
"tmax = epochs * len(dls.train)\n",
"sched = partial(lr_scheduler.OneCycleLR, max_lr=lr, total_steps=tmax)\n",
"xtra = [BatchSchedCB(sched)]\n",
"model = get_dropmodel(nbks=(1,2,8,2,2), nfs=(32, 64, 128, 512, 1024, 1536), drop=0.1)\n",
"learn = Learner(model, dls, F.cross_entropy, lr=lr, cbs=cbs+xtra, opt_func=opt_func)"
]
},
{
"cell_type": "code",
"execution_count": null,
"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.015 | \n",
" 5.158 | \n",
" 0 | \n",
" train | \n",
"
\n",
" \n",
" 0.023 | \n",
" 5.090 | \n",
" 0 | \n",
" eval | \n",
"
\n",
" \n",
" 0.034 | \n",
" 4.887 | \n",
" 1 | \n",
" train | \n",
"
\n",
" \n",
" 0.046 | \n",
" 4.680 | \n",
" 1 | \n",
" eval | \n",
"
\n",
" \n",
" 0.061 | \n",
" 4.598 | \n",
" 2 | \n",
" train | \n",
"
\n",
" \n",
" 0.071 | \n",
" 4.396 | \n",
" 2 | \n",
" eval | \n",
"
\n",
" \n",
" 0.087 | \n",
" 4.372 | \n",
" 3 | \n",
" train | \n",
"
\n",
" \n",
" 0.113 | \n",
" 4.117 | \n",
" 3 | \n",
" eval | \n",
"
\n",
" \n",
" 0.116 | \n",
" 4.149 | \n",
" 4 | \n",
" train | \n",
"
\n",
" \n",
" 0.129 | \n",
" 3.990 | \n",
" 4 | \n",
" eval | \n",
"
\n",
" \n",
" 0.148 | \n",
" 3.926 | \n",
" 5 | \n",
" train | \n",
"
\n",
" \n",
" 0.172 | \n",
" 3.757 | \n",
" 5 | \n",
" eval | \n",
"
\n",
" \n",
" 0.179 | \n",
" 3.731 | \n",
" 6 | \n",
" train | \n",
"
\n",
" \n",
" 0.148 | \n",
" 4.018 | \n",
" 6 | \n",
" eval | \n",
"
\n",
" \n",
" 0.202 | \n",
" 3.588 | \n",
" 7 | \n",
" train | \n",
"
\n",
" \n",
" 0.191 | \n",
" 3.779 | \n",
" 7 | \n",
" eval | \n",
"
\n",
" \n",
" 0.225 | \n",
" 3.445 | \n",
" 8 | \n",
" train | \n",
"
\n",
" \n",
" 0.219 | \n",
" 3.526 | \n",
" 8 | \n",
" eval | \n",
"
\n",
" \n",
" 0.246 | \n",
" 3.335 | \n",
" 9 | \n",
" train | \n",
"
\n",
" \n",
" 0.270 | \n",
" 3.160 | \n",
" 9 | \n",
" eval | \n",
"
\n",
" \n",
" 0.266 | \n",
" 3.219 | \n",
" 10 | \n",
" train | \n",
"
\n",
" \n",
" 0.253 | \n",
" 3.446 | \n",
" 10 | \n",
" eval | \n",
"
\n",
" \n",
" 0.282 | \n",
" 3.139 | \n",
" 11 | \n",
" train | \n",
"
\n",
" \n",
" 0.272 | \n",
" 3.223 | \n",
" 11 | \n",
" eval | \n",
"
\n",
" \n",
" 0.300 | \n",
" 3.042 | \n",
" 12 | \n",
" train | \n",
"
\n",
" \n",
" 0.255 | \n",
" 3.408 | \n",
" 12 | \n",
" eval | \n",
"
\n",
" \n",
" 0.309 | \n",
" 2.981 | \n",
" 13 | \n",
" train | \n",
"
\n",
" \n",
" 0.291 | \n",
" 3.183 | \n",
" 13 | \n",
" eval | \n",
"
\n",
" \n",
" 0.323 | \n",
" 2.907 | \n",
" 14 | \n",
" train | \n",
"
\n",
" \n",
" 0.344 | \n",
" 2.821 | \n",
" 14 | \n",
" eval | \n",
"
\n",
" \n",
" 0.335 | \n",
" 2.850 | \n",
" 15 | \n",
" train | \n",
"
\n",
" \n",
" 0.310 | \n",
" 3.166 | \n",
" 15 | \n",
" eval | \n",
"
\n",
" \n",
" 0.349 | \n",
" 2.782 | \n",
" 16 | \n",
" train | \n",
"
\n",
" \n",
" 0.316 | \n",
" 3.086 | \n",
" 16 | \n",
" eval | \n",
"
\n",
" \n",
" 0.360 | \n",
" 2.734 | \n",
" 17 | \n",
" train | \n",
"
\n",
" \n",
" 0.357 | \n",
" 2.740 | \n",
" 17 | \n",
" eval | \n",
"
\n",
" \n",
" 0.367 | \n",
" 2.689 | \n",
" 18 | \n",
" train | \n",
"
\n",
" \n",
" 0.371 | \n",
" 2.696 | \n",
" 18 | \n",
" eval | \n",
"
\n",
" \n",
" 0.375 | \n",
" 2.644 | \n",
" 19 | \n",
" train | \n",
"
\n",
" \n",
" 0.341 | \n",
" 2.891 | \n",
" 19 | \n",
" eval | \n",
"
\n",
" \n",
" 0.385 | \n",
" 2.595 | \n",
" 20 | \n",
" train | \n",
"
\n",
" \n",
" 0.395 | \n",
" 2.646 | \n",
" 20 | \n",
" eval | \n",
"
\n",
" \n",
" 0.394 | \n",
" 2.551 | \n",
" 21 | \n",
" train | \n",
"
\n",
" \n",
" 0.419 | \n",
" 2.420 | \n",
" 21 | \n",
" eval | \n",
"
\n",
" \n",
" 0.403 | \n",
" 2.503 | \n",
" 22 | \n",
" train | \n",
"
\n",
" \n",
" 0.400 | \n",
" 2.573 | \n",
" 22 | \n",
" eval | \n",
"
\n",
" \n",
" 0.415 | \n",
" 2.454 | \n",
" 23 | \n",
" train | \n",
"
\n",
" \n",
" 0.398 | \n",
" 2.589 | \n",
" 23 | \n",
" eval | \n",
"
\n",
" \n",
" 0.423 | \n",
" 2.412 | \n",
" 24 | \n",
" train | \n",
"
\n",
" \n",
" 0.415 | \n",
" 2.497 | \n",
" 24 | \n",
" eval | \n",
"
\n",
" \n",
" 0.430 | \n",
" 2.376 | \n",
" 25 | \n",
" train | \n",
"
\n",
" \n",
" 0.370 | \n",
" 2.784 | \n",
" 25 | \n",
" eval | \n",
"
\n",
" \n",
" 0.440 | \n",
" 2.320 | \n",
" 26 | \n",
" train | \n",
"
\n",
" \n",
" 0.403 | \n",
" 2.591 | \n",
" 26 | \n",
" eval | \n",
"
\n",
" \n",
" 0.452 | \n",
" 2.267 | \n",
" 27 | \n",
" train | \n",
"
\n",
" \n",
" 0.400 | \n",
" 2.698 | \n",
" 27 | \n",
" eval | \n",
"
\n",
" \n",
" 0.462 | \n",
" 2.219 | \n",
" 28 | \n",
" train | \n",
"
\n",
" \n",
" 0.453 | \n",
" 2.326 | \n",
" 28 | \n",
" eval | \n",
"
\n",
" \n",
" 0.474 | \n",
" 2.156 | \n",
" 29 | \n",
" train | \n",
"
\n",
" \n",
" 0.441 | \n",
" 2.400 | \n",
" 29 | \n",
" eval | \n",
"
\n",
" \n",
" 0.485 | \n",
" 2.099 | \n",
" 30 | \n",
" train | \n",
"
\n",
" \n",
" 0.466 | \n",
" 2.261 | \n",
" 30 | \n",
" eval | \n",
"
\n",
" \n",
" 0.497 | \n",
" 2.037 | \n",
" 31 | \n",
" train | \n",
"
\n",
" \n",
" 0.477 | \n",
" 2.204 | \n",
" 31 | \n",
" eval | \n",
"
\n",
" \n",
" 0.514 | \n",
" 1.964 | \n",
" 32 | \n",
" train | \n",
"
\n",
" \n",
" 0.504 | \n",
" 2.081 | \n",
" 32 | \n",
" eval | \n",
"
\n",
" \n",
" 0.528 | \n",
" 1.899 | \n",
" 33 | \n",
" train | \n",
"
\n",
" \n",
" 0.514 | \n",
" 2.075 | \n",
" 33 | \n",
" eval | \n",
"
\n",
" \n",
" 0.543 | \n",
" 1.826 | \n",
" 34 | \n",
" train | \n",
"
\n",
" \n",
" 0.516 | \n",
" 2.073 | \n",
" 34 | \n",
" eval | \n",
"
\n",
" \n",
" 0.562 | \n",
" 1.743 | \n",
" 35 | \n",
" train | \n",
"
\n",
" \n",
" 0.506 | \n",
" 2.135 | \n",
" 35 | \n",
" eval | \n",
"
\n",
" \n",
" 0.581 | \n",
" 1.652 | \n",
" 36 | \n",
" train | \n",
"
\n",
" \n",
" 0.543 | \n",
" 1.935 | \n",
" 36 | \n",
" eval | \n",
"
\n",
" \n",
" 0.602 | \n",
" 1.566 | \n",
" 37 | \n",
" train | \n",
"
\n",
" \n",
" 0.544 | \n",
" 1.965 | \n",
" 37 | \n",
" eval | \n",
"
\n",
" \n",
" 0.624 | \n",
" 1.466 | \n",
" 38 | \n",
" train | \n",
"
\n",
" \n",
" 0.568 | \n",
" 1.855 | \n",
" 38 | \n",
" eval | \n",
"
\n",
" \n",
" 0.644 | \n",
" 1.377 | \n",
" 39 | \n",
" train | \n",
"
\n",
" \n",
" 0.596 | \n",
" 1.684 | \n",
" 39 | \n",
" eval | \n",
"
\n",
" \n",
" 0.672 | \n",
" 1.259 | \n",
" 40 | \n",
" train | \n",
"
\n",
" \n",
" 0.599 | \n",
" 1.689 | \n",
" 40 | \n",
" eval | \n",
"
\n",
" \n",
" 0.698 | \n",
" 1.156 | \n",
" 41 | \n",
" train | \n",
"
\n",
" \n",
" 0.609 | \n",
" 1.716 | \n",
" 41 | \n",
" eval | \n",
"
\n",
" \n",
" 0.725 | \n",
" 1.049 | \n",
" 42 | \n",
" train | \n",
"
\n",
" \n",
" 0.627 | \n",
" 1.622 | \n",
" 42 | \n",
" eval | \n",
"
\n",
" \n",
" 0.749 | \n",
" 0.954 | \n",
" 43 | \n",
" train | \n",
"
\n",
" \n",
" 0.629 | \n",
" 1.606 | \n",
" 43 | \n",
" eval | \n",
"
\n",
" \n",
" 0.774 | \n",
" 0.861 | \n",
" 44 | \n",
" train | \n",
"
\n",
" \n",
" 0.638 | \n",
" 1.577 | \n",
" 44 | \n",
" eval | \n",
"
\n",
" \n",
" 0.794 | \n",
" 0.790 | \n",
" 45 | \n",
" train | \n",
"
\n",
" \n",
" 0.643 | \n",
" 1.572 | \n",
" 45 | \n",
" eval | \n",
"
\n",
" \n",
" 0.809 | \n",
" 0.737 | \n",
" 46 | \n",
" train | \n",
"
\n",
" \n",
" 0.648 | \n",
" 1.564 | \n",
" 46 | \n",
" eval | \n",
"
\n",
" \n",
" 0.821 | \n",
" 0.687 | \n",
" 47 | \n",
" train | \n",
"
\n",
" \n",
" 0.652 | \n",
" 1.549 | \n",
" 47 | \n",
" eval | \n",
"
\n",
" \n",
" 0.827 | \n",
" 0.665 | \n",
" 48 | \n",
" train | \n",
"
\n",
" \n",
" 0.654 | \n",
" 1.545 | \n",
" 48 | \n",
" eval | \n",
"
\n",
" \n",
" 0.830 | \n",
" 0.660 | \n",
" 49 | \n",
" train | \n",
"
\n",
" \n",
" 0.654 | \n",
" 1.546 | \n",
" 49 | \n",
" eval | \n",
"
\n",
" \n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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",
"text/plain": [
"