{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import time\nimport os\nimport skimage.io\nimport numpy as np\nimport pandas as pd\nimport cv2\nimport rasterio\nfrom rasterio.windows import Window\nimport torch\nimport random\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torchsampler import ImbalancedDatasetSampler\nfrom torch.optim import lr_scheduler\nfrom torch.utils.data import DataLoader, Dataset\nfrom torch.utils.data.sampler import SubsetRandomSampler, RandomSampler, SequentialSampler\nfrom warmup_scheduler import GradualWarmupScheduler\n#from efficientnet_pytorch import model as enet\n#from efficientnet_pytorch import EfficientNet\nimport segmentation_models_pytorch as smp\nimport albumentations as albu\nfrom albumentations.pytorch import ToTensorV2\nfrom sklearn.model_selection import StratifiedKFold\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import cohen_kappa_score\n#from tqdm import tqdm_notebook as tqdm\nfrom tqdm.notebook import tqdm\n#from lookahead import Lookahead\n#from radam import *\nfrom losses import *\nfrom utils import rle_decode, make_grid, seed_everything\nfrom prefetch_generator import BackgroundGenerator","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","papermill":{"duration":3.992399,"end_time":"2020-12-10T08:24:28.245734","exception":false,"start_time":"2020-12-10T08:24:24.253335","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"smp.__version__,torch.__version__,albu.__version__","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.backends.cudnn.benchmark = True","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"seed_everything(42)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Config","metadata":{"papermill":{"duration":0.027476,"end_time":"2020-12-10T08:24:28.302255","exception":false,"start_time":"2020-12-10T08:24:28.274779","status":"completed"},"tags":[]}},{"cell_type":"code","source":"data_dir = 'F:/hubmap-kidney-segmentation/'\n\nlogdir = 'F:/HuBMAP/exp007/'\nencoder = 'timm-efficientnet-b4'  # 'efficientnet-b3'  timm-efficientnet-b4\nENCODER_WEIGHTS = 'noisy-student'  # noisy-student\nmix_up = False\nuse_amp = True\nimage_size = 512\nbatch_size = 8\nnum_workers = 0\ninit_lr = 3e-4  # 1e-4\nwarmup_factor = 10\nwarmup_epo = 1\nn_epochs = 50\nn_epochs_stop = 5\nepochs_no_improve1 = 0\nepochs_no_improve2 = 0\nearly_stop = True\nscaler = torch.cuda.amp.GradScaler(enabled=use_amp)\ndevice = torch.device('cuda')","metadata":{"papermill":{"duration":0.078322,"end_time":"2020-12-10T08:24:28.409109","exception":false,"start_time":"2020-12-10T08:24:28.330787","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv('disk_folds_1024-128.csv');df.shape","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.head()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{"papermill":{"duration":0.020971,"end_time":"2020-12-10T08:24:28.611867","exception":false,"start_time":"2020-12-10T08:24:28.590896","status":"completed"},"tags":[]}},{"cell_type":"code","source":"model = smp.Unet(\n    encoder_name=encoder,        # choose encoder, e.g. mobilenet_v2 or efficientnet-b7\n    encoder_weights=ENCODER_WEIGHTS,     # use `imagenet` pretrained weights for encoder initialization\n    in_channels=3,                  # model input channels (1 for grayscale images, 3 for RGB, etc.)\n    classes=1,                      # model output channels (number of classes in your dataset)\n)","metadata":{"papermill":{"duration":1.150389,"end_time":"2020-12-10T08:24:29.837324","exception":false,"start_time":"2020-12-10T08:24:28.686935","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset","metadata":{"papermill":{"duration":0.023606,"end_time":"2020-12-10T08:24:29.886451","exception":false,"start_time":"2020-12-10T08:24:29.862845","status":"completed"},"tags":[]}},{"cell_type":"code","source":"class HubMapDataset(Dataset):\n    def __init__(self, df, train=True, transform=None):\n        super().__init__()\n        self.df = df.reset_index(drop=True)\n        self.train = train\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    # get data operation    \n    def __gen_data__(self, index):\n        item = self.df.iloc[index]\n        filename = item.image_id\n        image_pth = item.path\n        mask_pth = image_pth.replace('images', 'masks').replace('.png', '.jpg')\n        image = cv2.imread(image_pth)\n        mask = cv2.imread(mask_pth, 0) / 255\n        \n        return image, mask\n    \n    def __getitem__(self, idx):\n        image, mask = self.__gen_data__(idx)\n            \n        if self.transform is not None:\n            augments = self.transform(image=image, mask=mask)\n            image = augments['image']\n            mask = augments['mask'].unsqueeze(0).float()\n        return image, mask#, mask.sum()","metadata":{"papermill":{"duration":0.037,"end_time":"2020-12-10T08:24:29.946567","exception":false,"start_time":"2020-12-10T08:24:29.909567","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Augmentations","metadata":{"papermill":{"duration":0.022571,"end_time":"2020-12-10T08:24:29.991950","exception":false,"start_time":"2020-12-10T08:24:29.969379","status":"completed"},"tags":[]}},{"cell_type":"code","source":"transforms_train = albu.Compose([\n    #albu.RandomResizedCrop(832, 832, p=0.4),\n    albu.Resize(image_size, image_size),\n    \n    albu.HorizontalFlip(p=0.5),\n    albu.VerticalFlip(p=0.5),\n    albu.RandomRotate90(p=0.5),\n    albu.Transpose(p=0.5),\n    albu.ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.2, rotate_limit=15, p=0.5, border_mode=cv2.BORDER_REFLECT),\n    \n    albu.RandomBrightnessContrast(p=0.5),\n    albu.HueSaturationValue(hue_shift_limit=0.2, sat_shift_limit=0.2, val_shift_limit=0.2, p=0.5),\n    albu.CLAHE(p=0.5),\n    \n    albu.OneOf([\n        albu.OpticalDistortion(p=0.3),\n        albu.GridDistortion(p=.1),\n        albu.IAAPiecewiseAffine(p=0.3),\n    ], p=0.3),\n    \n    # https://www.kaggle.com/c/hubmap-kidney-segmentation/discussion/202375, improve CV, but hurt LB\n    albu.CoarseDropout(max_holes=8, max_height=64, max_width=64, fill_value=0, mask_fill_value=0, p=0.2),\n    \n    albu.Normalize(),\n    ToTensorV2()\n])\n\ntransforms_val = albu.Compose([\n    albu.Resize(image_size, image_size),\n    albu.Normalize(),\n    ToTensorV2()\n])","metadata":{"papermill":{"duration":0.033339,"end_time":"2020-12-10T08:24:30.049453","exception":false,"start_time":"2020-12-10T08:24:30.016114","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":" if 1:\n    dataset_show = HubMapDataset(df=df, train=True, transform=transforms_train)\n    mean = np.array([0.485, 0.456, 0.406])\n    std = np.array([0.229, 0.224, 0.225])\n    # from pylab import rcParams\n    # rcParams['figure.figsize'] = 20,10\n    # for i in range(2):\n    #     f, axarr = plt.subplots(1,6)\n    #     for p in range(6):\n    #         idx = np.random.randint(0, len(dataset_show))\n    #         img, mask = dataset_show[idx]\n    #         if p == 0 or p == 2 or p == 4:\n    #             axarr[p].imshow(img.transpose(0, 1).transpose(1,2).squeeze())\n    #             axarr[p+1].imshow(mask[0,:,:])\n\n            #axarr[p].set_title(str(label))\n\n    dl = DataLoader(dataset_show, batch_size=32, shuffle=False)\n    imgs, masks = next(iter(dl))\n\n    plt.figure(figsize=(16, 16))\n    for i, (img, mask) in enumerate(zip(imgs, masks)):\n        #print(s)\n        img = ((img.permute(1,2,0)*std + mean)*255.0).numpy().astype(np.uint8)\n        plt.subplot(8, 8, i+1)\n        #plt.imshow(img.permute(1,2,0), vmin=0, vmax=255)\n        plt.imshow(img)\n        plt.imshow(mask.squeeze().numpy(), alpha=0.2)\n        plt.axis('off')\n        plt.subplots_adjust(wspace=None, hspace=None)\n    plt.savefig('./viz.jpg')\n    plt.show()\n\n    #del dataset_show, dl, imgs, masks","metadata":{"papermill":{"duration":1.994811,"end_time":"2020-12-10T08:24:32.067729","exception":false,"start_time":"2020-12-10T08:24:30.072918","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Utils","metadata":{}},{"cell_type":"code","source":"#Dice系数\ndef dice_coeff(pred, target):\n    smooth = 1.\n    num = pred.size(0)\n    m1 = pred.view(num, -1)  # Flatten\n    m2 = target.view(num, -1)  # Flatten\n    intersection = (m1 * m2).sum()\n \n    return (2. * intersection + smooth) / (m1.sum() + m2.sum() + smooth)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# https://github.com/facebookresearch/mixup-cifar10/blob/master/train.py\ndef mixup_data(x, y, alpha=1.0, use_cuda=True):\n    '''Returns mixed inputs, pairs of targets, and lambda'''\n    if alpha > 0:\n        lam = np.random.beta(alpha, alpha)\n    else:\n        lam = 1\n\n    batch_size = x.size()[0]\n    if use_cuda:\n        index = torch.randperm(batch_size).cuda()\n    else:\n        index = torch.randperm(batch_size)\n\n    mixed_x = lam * x + (1 - lam) * x[index, :]\n    y_a, y_b = y, y[index]\n    return mixed_x, y_a, y_b, lam\n\n\ndef mixup_criterion(criterion, pred, y_a, y_b, lam):\n    return lam * criterion(pred, y_a) + (1 - lam) * criterion(pred, y_b)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Meter:\n    def __init__(self, threshold=0.5):\n        self.dice = []\n        self.threshold = threshold\n\n    def update(self, targets, outputs):\n        probs = torch.sigmoid(outputs.float())\n        probs = (probs > self.threshold)\n        dice = dice_coeff(probs, targets)\n        self.dice.append(dice)\n\n    def get_metrics(self):\n        dice = np.mean(self.dice)\n        return dice\n\ndef save_log(fold_id, phase, epoch, epoch_loss, acc):\n    with open(os.path.join(logdir, f'result_fold{fold_id}.txt'), 'a') as f:\n        f.write(f'epoch:{epoch} phase:{phase} loss:{epoch_loss} acc:{acc} \\n')\n\ndef epoch_log(phase, epoch, epoch_loss, meter, start):\n    '''logging the metrics at the end of an epoch'''\n    dice = meter.get_metrics()\n    print(\"{} loss: {:0.4f} | {} dice: {:0.4f}\".format(phase, epoch_loss, phase, dice))\n    return dice\n\ndef plot(scores, name, idx=None):\n    plt.figure(figsize=(15,5))\n    x1, y1 = range(len(scores[\"train\"])), scores[\"train\"]\n    x2, y2 = range(len(scores[\"val\"])), scores[\"val\"]\n    plt.plot(x1, y1, label=f'train {name}')\n    plt.plot(x2, y2, label=f'val {name}')\n    plt.title(f'{name} plot'); plt.xlabel('Epoch'); plt.ylabel(f'{name}');\n    \n    # show min/max point\n    if name.startswith('loss'):\n        indx1=np.argmin(y1)\n        indx2=np.argmin(y2)\n    else:\n        indx1=np.argmax(y1)\n        indx2=np.argmax(y2)\n    \n    plt.plot(indx1, y1[indx1], 'ks')\n    plt.plot(indx2, y2[indx2], 'ks')\n    show_max1 = '['+str(indx1)+', {:.4f}'.format(y1[indx1])+']'\n    show_max2 = '['+str(indx2)+', {:.4f}'.format(y2[indx2])+']'\n    plt.annotate(show_max1, xytext=(indx1, y1[indx1]), xy=(indx1, y1[indx1]))\n    plt.annotate(show_max2, xytext=(indx2, y2[indx2]), xy=(indx2, y2[indx2]))\n    plt.plot(indx1, y1[indx1],'gs')\n    plt.plot(indx2, y2[indx2],'gs')\n    \n    if idx is not None:\n        plt.plot(idx, y2[idx], 'ks')\n        show = '['+str(idx)+', {:.4f}'.format(y2[idx])+']'\n        plt.annotate(show, xytext=(idx, y2[idx]), xy=(idx, y2[idx]))\n        plt.plot(idx, y2[idx],'gs')\n    \n    plt.legend();\n    plt.savefig(os.path.join(logdir, f'{name}.jpg'))\n    plt.show()\n    \n    return indx2\n    \ndef utils(file):\n    with open(os.path.join(logdir, file), 'r') as f:\n        data = f.read().splitlines()\n        losses, accs = {}, {}\n        losses['train'], losses['val'] = [], []\n        accs['train'], accs['val'] = [], []\n        for line in data:\n            phase = line.split(' ')[1].split(':')[1]\n            loss = line.split(' ')[2].split(':')[1]\n            acc = line.split(' ')[3].split(':')[1]\n            losses[phase].append(float(loss))\n            accs[phase].append(float(acc))\n            \n    return losses, accs","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# label smooth\nclass LS(nn.Module):\n    def __init__(self, smooth=0.2):\n        super().__init__()\n        self.label_smoothing = smooth\n    def forward(self, inputs, targets):\n        #comment out if your model contains a sigmoid or equivalent activation layer \n        #inputs = torch.sigmoid(inputs)\n        \n        targets = targets.float() * (1 - self.label_smoothing) + 0.5 * self.label_smoothing\n        loss  = F.binary_cross_entropy_with_logits(inputs, targets, reduction='mean')\n        return loss","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Trainer","metadata":{"papermill":{"duration":0.051976,"end_time":"2020-12-10T08:24:32.782815","exception":false,"start_time":"2020-12-10T08:24:32.730839","status":"completed"},"tags":[]}},{"cell_type":"code","source":"class Trainer(object):\n    def __init__(self, fold_id, model, criterion, optimizer, epochs, scheduler, train_loader, valid_loader, use_amp, mix_up=False):\n        self.best_loss = float(\"inf\")\n        self.best_dice = -float(\"inf\")\n        self.phases = [\"train\", \"val\"]\n        self.num_epochs = epochs\n        self.fold_id = fold_id\n        self.logdir = logdir\n        self.device = device\n        self.use_amp = use_amp\n        self.net = model\n        self.criterion = criterion\n        self.optimizer = optimizer\n        self.scheduler = scheduler\n        \n        self.dataloaders = {\n            self.phases[0]: train_loader,\n            self.phases[1]: valid_loader\n        }\n        self.mix_up = mix_up\n        self.net.to(self.device)\n        \n        self.losses = {phase: [] for phase in self.phases}\n        self.dice = {phase: [] for phase in self.phases}\n    \n    def loss_fn(self, pred, gt):\n        loss = self.criterion(pred, gt.to(self.device))\n        return loss\n    \n    def forward(self, x, y=None):\n        x = x.to(self.device)\n        outputs = self.net(x)\n        return outputs\n\n    def iterate(self, epoch, phase):\n        meter = Meter()\n        start = time.strftime(\"%H:%M:%S\")\n        print(f\"Epoch: {epoch} | phase: {phase} | Time: {start}\")\n        self.net.train(phase == \"train\")\n        dataloader = self.dataloaders[phase]\n        running_loss = 0.0\n        total_batches = len(dataloader)\n        tk0 = tqdm(BackgroundGenerator(dataloader), total=total_batches)\n        self.optimizer.zero_grad(set_to_none=True)\n        for itr, batch in enumerate(tk0):\n            images, targets = batch\n                \n            if phase == \"train\":\n                with torch.cuda.amp.autocast(enabled=self.use_amp):\n                    if self.mix_up and np.random.rand() > 0.5:\n                        images, targets_a, targets_b, lam = mixup_data(images, targets)\n                        outputs = self.forward(images)\n                        loss = mixup_criterion(self.criterion, outputs, targets_a.to(self.device), targets_b.to(self.device), lam)\n                    else:\n                        outputs = self.forward(images)\n                        loss = self.loss_fn(outputs, targets)\n                scaler.scale(loss).backward()\n                scaler.step(self.optimizer)\n                scaler.update()\n                self.optimizer.zero_grad(set_to_none=True)\n            else:\n                outputs = self.forward(images)\n                loss = self.loss_fn(outputs, targets)\n                \n            running_loss += loss.item()\n            outputs = outputs.detach().cpu()\n            meter.update(targets, outputs)\n            tk0.set_postfix(loss=(running_loss / (itr + 1)))\n        epoch_loss = running_loss / total_batches\n        epoch_dice = epoch_log(phase, epoch, epoch_loss, meter, start)\n        save_log(self.fold_id, phase, epoch, epoch_loss, epoch_dice)\n        self.losses[phase].append(epoch_loss)\n        self.dice[phase].append(epoch_dice)\n        torch.cuda.empty_cache()\n        return epoch_loss, epoch_dice\n\n    def fit(self):\n        for epoch in range(self.num_epochs):\n            self.iterate(epoch, \"train\")\n            \n            with torch.no_grad():\n                val_loss, val_dice = self.iterate(epoch, \"val\")\n                self.scheduler.step(val_loss)\n            \n            # monitor val loss\n            if val_loss < self.best_loss:\n                print(f\"****** New optimal loss found @ {epoch}, saving state ******\")\n                epochs_no_improve1 = 0\n                self.best_loss = val_loss\n                torch.save(self.net.state_dict(), f\"{self.logdir}/best_loss_fold{self.fold_id}.pth\")\n            else:\n                epochs_no_improve1 += 1\n            \n            # monitor val metric\n            if val_dice > self.best_dice:\n                print(f\"****** New optimal dice found @ {epoch}, saving state ******\")\n                epochs_no_improve2 = 0\n                self.best_dice = val_dice\n                torch.save(self.net.state_dict(), f\"{self.logdir}/best_metric_fold{self.fold_id}.pth\")\n            else:\n                epochs_no_improve2 += 1\n            \n            if early_stop and epochs_no_improve1 >= n_epochs_stop and epochs_no_improve2 >= n_epochs_stop:\n                print('Early stopping!' )\n                break\n            print()\n            \n        print(f'train finished. best loss: {self.best_loss}, best dice: {self.best_dice}')","metadata":{"papermill":{"duration":0.164108,"end_time":"2020-12-10T08:24:32.999203","exception":false,"start_time":"2020-12-10T08:24:32.835095","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train","metadata":{"papermill":{"duration":0.053164,"end_time":"2020-12-10T08:24:33.106513","exception":false,"start_time":"2020-12-10T08:24:33.053349","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def train(fold_id):\n    print(f'###################### training fold: {fold_id} ######################')\n    ###################### data ###########################\n    dataset_train = HubMapDataset(df=df[df.fold != fold_id], train=True, transform=transforms_train)\n    dataset_valid = HubMapDataset(df=df[df.fold == fold_id], train=False, transform=transforms_val)\n\n    train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=batch_size, shuffle=True,  num_workers=num_workers, pin_memory=True)\n    valid_loader = torch.utils.data.DataLoader(dataset_valid, batch_size=batch_size, shuffle=False, num_workers=num_workers, pin_memory=True)\n    \n    ###################### model ###########################\n    model = smp.Unet(\n    encoder_name=encoder, \n    encoder_weights=ENCODER_WEIGHTS, \n    in_channels=3, \n    classes=1, \n    activation=None,\n    decoder_use_batchnorm=True\n    )\n    criterion = LS() # BCEDiceLoss()  # FocalTverskyLoss() #nn.BCEWithLogitsLoss() #smp.utils.losses.DiceLoss() #Jaccardloss  # nn.BCEWithLogitsLoss() , nn.BCELoss()\n    optimizer = optim.Adam(model.parameters(), lr=init_lr/warmup_factor)\n    #optimizer = Lookahead(RAdam(filter(lambda p: p.requires_grad, model.parameters()),lr=init_lr), alpha=0.5, k=5)\n    #scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, factor=1.0 / 3, mode=\"min\", patience=3, verbose=True)\n    scheduler_cosine = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, n_epochs-warmup_epo)\n    scheduler = GradualWarmupScheduler(optimizer, multiplier=warmup_factor, total_epoch=warmup_epo, after_scheduler=scheduler_cosine)\n    \n    ###################### trainer ###########################\n    trainer = Trainer(\n        fold_id=fold_id,\n        model=model,\n        criterion=criterion,\n        optimizer=optimizer, \n        scheduler=scheduler, \n        epochs=n_epochs,\n        train_loader=train_loader, \n        valid_loader=valid_loader,\n        use_amp=use_amp,\n        mix_up=mix_up\n    )\n    trainer.fit()","metadata":{"papermill":{"duration":4.871929,"end_time":"2020-12-10T08:24:38.031034","exception":false,"start_time":"2020-12-10T08:24:33.159105","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Run Training","metadata":{"papermill":{"duration":0.079932,"end_time":"2020-12-10T08:24:38.196348","exception":false,"start_time":"2020-12-10T08:24:38.116416","status":"completed"},"tags":[]}},{"cell_type":"code","source":"train(0)","metadata":{"papermill":{"duration":2656.314654,"end_time":"2020-12-10T09:08:54.615489","exception":false,"start_time":"2020-12-10T08:24:38.300835","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"losses, dice = utils('result_fold0.txt')\nbest_val_idx = plot(losses, 'loss_0')\nplot(dice, 'dice_0', idx=best_val_idx)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train(1)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"losses, dice = utils('result_fold1.txt')\nbest_val_idx = plot(losses, 'loss_1')\nplot(dice, 'dice_1', idx=best_val_idx)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train(2)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"losses, dice = utils('result_fold2.txt')\nbest_val_idx = plot(losses, 'loss_2')\nplot(dice, 'dice_2', idx=best_val_idx)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train(3)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"losses, dice = utils('result_fold3.txt')\nbest_val_idx = plot(losses, 'loss_3')\nplot(dice, 'dice_3', idx=best_val_idx)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train(4)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"losses, dice = utils('result_fold4.txt')\nbest_val_idx = plot(losses, 'loss_4')\nplot(dice, 'dice_4', idx=best_val_idx)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}