{"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":"markdown","source":"# Imports and Initializations","metadata":{}},{"cell_type":"code","source":"TRAIN = False\nKAGGLE = True","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:08.504207Z","iopub.execute_input":"2023-06-03T23:09:08.504818Z","iopub.status.idle":"2023-06-03T23:09:08.534648Z","shell.execute_reply.started":"2023-06-03T23:09:08.504780Z","shell.execute_reply":"2023-06-03T23:09:08.533678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Imports\nfrom sklearn.metrics import roc_auc_score, accuracy_score, f1_score, log_loss\nimport pickle\nfrom torch.utils.data import DataLoader\nfrom torch.cuda.amp import autocast, GradScaler\nimport warnings\nimport sys\nimport pandas as pd\nimport os\nimport gc\nimport sys\nimport math\nimport time\nimport random\nimport shutil\nfrom pathlib import Path\nfrom contextlib import contextmanager\nfrom collections import defaultdict, Counter\nimport cv2\n\nimport scipy as sp\nimport numpy as np\nimport pandas as pd\n\nimport matplotlib.pyplot as plt\nfrom tqdm.auto import tqdm\nfrom functools import partial\n\nimport argparse\nimport importlib\nimport torch\nimport torch.nn as nn\nfrom torch.optim import Adam, SGD, AdamW\n\nimport datetime\n\nimport numpy as np\nfrom torch.utils.data import DataLoader, Dataset\nimport cv2\nimport torch\nimport os\n\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nfrom albumentations import ImageOnlyTransform\n\nimport sklearn","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:08.537580Z","iopub.execute_input":"2023-06-03T23:09:08.538569Z","iopub.status.idle":"2023-06-03T23:09:12.467290Z","shell.execute_reply.started":"2023-06-03T23:09:08.538529Z","shell.execute_reply":"2023-06-03T23:09:12.466275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if KAGGLE:\n    sys.path.append('/kaggle/input/pretrainedmodels/pretrainedmodels-0.7.4')\n    sys.path.append('/kaggle/input/efficientnet-pytorch/EfficientNet-PyTorch-master')\n    sys.path.append('/kaggle/input/timm-pytorch-image-models/pytorch-image-models-master')\n    sys.path.append('/kaggle/input/segmentation-models-pytorch/segmentation_models.pytorch-master')\n    sys.path.append('/kaggle/input/best-model')\n\nimport segmentation_models_pytorch as smp\nfrom segmentation_models_pytorch import utils\nfrom tqdm import tqdm","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:12.468769Z","iopub.execute_input":"2023-06-03T23:09:12.469410Z","iopub.status.idle":"2023-06-03T23:09:15.219009Z","shell.execute_reply.started":"2023-06-03T23:09:12.469363Z","shell.execute_reply":"2023-06-03T23:09:15.217839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.cuda.is_available()\n\ntorch.cuda.empty_cache()","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.223289Z","iopub.execute_input":"2023-06-03T23:09:15.223614Z","iopub.status.idle":"2023-06-03T23:09:15.295912Z","shell.execute_reply.started":"2023-06-03T23:09:15.223580Z","shell.execute_reply":"2023-06-03T23:09:15.294013Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Configuration Class","metadata":{}},{"cell_type":"code","source":"class CFG:\n    # ============== comp exp name =============\n    comp_name = 'vesuvius'\n\n    if KAGGLE:\n        comp_dir_path = '/kaggle/input/'\n    else:\n        comp_dir_path = './'\n        \n    comp_folder_name = 'vesuvius-challenge-ink-detection'\n    # comp_dataset_path = f'{comp_dir_path}datasets/{comp_folder_name}/'\n    comp_dataset_path = f'{comp_dir_path}{comp_folder_name}/'\n    \n    exp_name = 'vesuvius_2d_slide_exp002'\n\n    # ============== pred target =============\n    target_size = 1\n\n    # ============== model cfg =============\n    #model_name = 'Unet'\n    backbone = 'timm-res2net50_14w_8s'\n\n    in_chans = 6 # 65\n    \n    # ============== training cfg =============\n    size = 224\n    tile_size = 224\n    stride = tile_size // 2\n\n    train_batch_size = 4 # 32\n    valid_batch_size = train_batch_size * 2\n    use_amp = True\n\n    scheduler = 'GradualWarmupSchedulerV2'\n    # scheduler = 'CosineAnnealingLR'\n    epochs = 5 # 30\n\n    warmup_factor = 10\n    lr = 1e-4 / warmup_factor\n\n    # ============== fold =============\n    valid_id = 1\n\n    # objective_cv = 'binary'  # 'binary', 'multiclass', 'regression'\n    metric_direction = 'maximize'  # maximize, 'minimize'\n    # metrics = 'dice_coef'\n\n    # ============== fixed =============\n    pretrained = True\n    inf_weight = 'best'  # 'best'\n\n    min_lr = 1e-6\n    weight_decay = 1e-6\n    max_grad_norm = 1000\n\n    print_freq = 50\n    num_workers = 0 #4\n\n    seed = 42\n\n    # ============== set dataset path =============\n    if KAGGLE:\n        outputs_path = f'/kaggle/working/outputs/{comp_name}/{exp_name}/'\n    else:\n        outputs_path = f'outputs/{comp_name}/{exp_name}/'\n\n    submission_dir = outputs_path + 'submissions/'\n    submission_path = submission_dir + f'submission_{exp_name}.csv'\n\n    model_dir = outputs_path + \\\n        f'{comp_name}-models/'\n\n    figures_dir = outputs_path + 'figures/'\n\n    log_dir = outputs_path + 'logs/'\n    log_path = log_dir + f'{exp_name}.txt'\n\n    # ============== augmentation =============\n    train_aug_list = [\n        A.RandomResizedCrop(\n            size, size, scale=(0.85, 1.0)),\n        A.Resize(size, size),\n        A.HorizontalFlip(p=0.5),\n        A.VerticalFlip(p=0.5),\n        A.RandomBrightnessContrast(p=0.75),\n        A.ShiftScaleRotate(p=0.75),\n        A.OneOf([\n                A.GaussNoise(var_limit=[10, 50]),\n                A.GaussianBlur(),\n                A.MotionBlur(),\n                ], p=0.4),\n        A.GridDistortion(num_steps=5, distort_limit=0.3, p=0.5),\n        A.CoarseDropout(max_holes=1, max_width=int(size * 0.3), max_height=int(size * 0.3), \n                        mask_fill_value=0, p=0.5),\n        # A.Cutout(max_h_size=int(size * 0.6),\n        #          max_w_size=int(size * 0.6), num_holes=1, p=1.0),\n        A.Normalize(\n            mean= [0] * in_chans,\n            std= [1] * in_chans\n        ),\n        ToTensorV2(transpose_mask=True),\n    ]\n\n    valid_aug_list = [\n        A.Resize(size, size),\n        A.Normalize(\n            mean= [0] * in_chans,\n            std= [1] * in_chans\n        ),\n        ToTensorV2(transpose_mask=True),\n    ]\n\n    # ========= test submission threshold ========\n    threshold = 0.5\n    \n    if KAGGLE:\n        model_load_path = \"/kaggle/input/best-model/best_model.pth\"\n        model_save_path = outputs_path + f'{comp_name}-models/'\n    else:\n        model_load_path = \"test_model.pth\"\n        model_save_path = \"best_model.pth\"\n","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.297923Z","iopub.execute_input":"2023-06-03T23:09:15.298543Z","iopub.status.idle":"2023-06-03T23:09:15.318801Z","shell.execute_reply.started":"2023-06-03T23:09:15.298485Z","shell.execute_reply":"2023-06-03T23:09:15.317762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Initialize Directories for Training","metadata":{}},{"cell_type":"code","source":"def make_dirs(cfg):\n    for dir in [cfg.model_dir, cfg.figures_dir, cfg.submission_dir, cfg.log_dir]:\n        os.makedirs(dir, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.320418Z","iopub.execute_input":"2023-06-03T23:09:15.320816Z","iopub.status.idle":"2023-06-03T23:09:15.331972Z","shell.execute_reply.started":"2023-06-03T23:09:15.320765Z","shell.execute_reply":"2023-06-03T23:09:15.330865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## helper","metadata":{}},{"cell_type":"code","source":"class AverageMeter(object):\n    \"\"\"Computes and stores the average and current value\"\"\"\n\n    def __init__(self):\n        self.reset()\n\n    def reset(self):\n        self.val = 0\n        self.avg = 0\n        self.sum = 0\n        self.count = 0\n\n    def update(self, val, n=1):\n        self.val = val\n        self.sum += val * n\n        self.count += n\n        self.avg = self.sum / self.count","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.333779Z","iopub.execute_input":"2023-06-03T23:09:15.334396Z","iopub.status.idle":"2023-06-03T23:09:15.344276Z","shell.execute_reply.started":"2023-06-03T23:09:15.334357Z","shell.execute_reply":"2023-06-03T23:09:15.343071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def init_logger(log_file):\n    from logging import getLogger, INFO, FileHandler, Formatter, StreamHandler\n    logger = getLogger(__name__)\n    logger.setLevel(INFO)\n    handler1 = StreamHandler()\n    handler1.setFormatter(Formatter(\"%(message)s\"))\n    handler2 = FileHandler(filename=log_file)\n    handler2.setFormatter(Formatter(\"%(message)s\"))\n    logger.addHandler(handler1)\n    logger.addHandler(handler2)\n    return logger\n\ndef set_seed(seed=None, cudnn_deterministic=True):\n    if seed is None:\n        seed = 42\n\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = cudnn_deterministic\n    torch.backends.cudnn.benchmark = False","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.345483Z","iopub.execute_input":"2023-06-03T23:09:15.345769Z","iopub.status.idle":"2023-06-03T23:09:15.356227Z","shell.execute_reply.started":"2023-06-03T23:09:15.345743Z","shell.execute_reply":"2023-06-03T23:09:15.355348Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def cfg_init(cfg, mode='train'):\n    set_seed(cfg.seed)\n    # set_env_name()\n    # set_dataset_path(cfg)\n\n    if mode == 'train':\n        make_dirs(cfg)","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.357463Z","iopub.execute_input":"2023-06-03T23:09:15.358214Z","iopub.status.idle":"2023-06-03T23:09:15.369506Z","shell.execute_reply.started":"2023-06-03T23:09:15.358175Z","shell.execute_reply":"2023-06-03T23:09:15.368484Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cfg_init(CFG)\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.375336Z","iopub.execute_input":"2023-06-03T23:09:15.376150Z","iopub.status.idle":"2023-06-03T23:09:15.384055Z","shell.execute_reply.started":"2023-06-03T23:09:15.376112Z","shell.execute_reply":"2023-06-03T23:09:15.383093Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## RLE Encode, Decode Functions","metadata":{}},{"cell_type":"code","source":"def rle_encode(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    pixels = img.flatten()\n    # pixels = (pixels >= thr).astype(int)\n    \n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.385574Z","iopub.execute_input":"2023-06-03T23:09:15.385991Z","iopub.status.idle":"2023-06-03T23:09:15.395014Z","shell.execute_reply.started":"2023-06-03T23:09:15.385953Z","shell.execute_reply":"2023-06-03T23:09:15.393304Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset Creation","metadata":{}},{"cell_type":"markdown","source":"## Image/Mask reader","metadata":{}},{"cell_type":"code","source":"def read_images(fragment_id, mode, labels):\n\n    images = []\n\n    mid = 65 // 2\n    start = mid - CFG.in_chans // 2\n    end = mid + CFG.in_chans // 2\n\n    idxs = range(start, end)\n\n    for i in tqdm(idxs):\n        \n        image = cv2.imread(CFG.comp_dataset_path + f\"{mode}/{fragment_id}/surface_volume/{i:02}.tif\", 0)\n\n        pad0 = (CFG.tile_size - image.shape[0] % CFG.tile_size)\n        pad1 = (CFG.tile_size - image.shape[1] % CFG.tile_size)\n\n        image = np.pad(image, [(0, pad0), (0, pad1)], constant_values=0)\n\n        images.append(image)\n    \n    images = np.stack(images, axis=2)\n\n    if mode == 'test' or labels is False:\n        return images\n    \n    mask = cv2.imread(CFG.comp_dataset_path + f\"{mode}/{fragment_id}/inklabels.png\", 0)\n    mask = np.pad(mask, [(0, pad0), (0, pad1)], constant_values=0)\n\n    mask = mask.astype('float32')\n    mask /= 255.0\n    \n    return images, mask","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.397007Z","iopub.execute_input":"2023-06-03T23:09:15.397377Z","iopub.status.idle":"2023-06-03T23:09:15.409659Z","shell.execute_reply.started":"2023-06-03T23:09:15.397349Z","shell.execute_reply":"2023-06-03T23:09:15.408870Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dataset Creation","metadata":{}},{"cell_type":"code","source":"def get_train_valid_dataset():\n    train_images = []\n    train_masks = []\n    train_xyxys = []\n    \n    valid_images = []\n    valid_masks = []\n    valid_xyxys = []\n\n    for fragment_id in range(1, 4):\n\n        image, mask = read_images(fragment_id, 'train', labels=True)\n\n        x1_list = list(range(0, image.shape[1]-CFG.tile_size+1, CFG.stride))\n        y1_list = list(range(0, image.shape[0]-CFG.tile_size+1, CFG.stride))\n\n        for y1 in y1_list:\n            for x1 in x1_list:\n                y2 = y1 + CFG.tile_size\n                x2 = x1 + CFG.tile_size\n        \n                if fragment_id == CFG.valid_id:\n                    valid_images.append(image[y1:y2, x1:x2])\n                    valid_masks.append(mask[y1:y2, x1:x2, None])\n\n                    valid_xyxys.append([x1, y1, x2, y2])\n                else:\n                    train_images.append(image[y1:y2, x1:x2])\n                    train_masks.append(mask[y1:y2, x1:x2, None])\n\n                    train_xyxys.append([x1, y1, x2, y2])\n\n    return train_images, train_masks, train_xyxys, valid_images, valid_masks, valid_xyxys","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.410974Z","iopub.execute_input":"2023-06-03T23:09:15.411615Z","iopub.status.idle":"2023-06-03T23:09:15.424873Z","shell.execute_reply.started":"2023-06-03T23:09:15.411575Z","shell.execute_reply":"2023-06-03T23:09:15.423861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if TRAIN:\n    train_images, train_masks, train_xyxys, valid_images, valid_masks, valid_xyxys = get_train_valid_dataset()\n    \n    train_xyxys = np.stack(train_xyxys)\n    valid_xyxys = np.stack(valid_xyxys)","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.427444Z","iopub.execute_input":"2023-06-03T23:09:15.428129Z","iopub.status.idle":"2023-06-03T23:09:15.436048Z","shell.execute_reply.started":"2023-06-03T23:09:15.428090Z","shell.execute_reply":"2023-06-03T23:09:15.435283Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dataset Class","metadata":{}},{"cell_type":"code","source":"def get_transforms(data, cfg):\n    if data == 'train':\n        aug = A.Compose(cfg.train_aug_list)\n    elif data == 'valid':\n        aug = A.Compose(cfg.valid_aug_list)\n\n    return aug\n\nclass ScrollDataset(Dataset):\n    def __init__(self, images, include_labels, cfg, labels=None, transform=None):\n        self.images = images\n        self.cfg = cfg\n        self.include_labels = include_labels\n        if self.include_labels == True:\n            self.labels = labels\n\n        self.transform = transform\n\n    def __len__(self):\n        # return len(self.df)\n        return len(self.images)\n\n    def __getitem__(self, idx):\n        image = self.images[idx]\n\n        if self.include_labels == True:\n            label = self.labels[idx]\n        else:\n            label = np.zeros_like(image)\n\n        if self.transform:\n            data = self.transform(image=image, mask=label)\n            image = data['image']\n            label = data['mask']\n        \n        if self.include_labels == True:\n            return image, label\n        else:\n            return image","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.437607Z","iopub.execute_input":"2023-06-03T23:09:15.438425Z","iopub.status.idle":"2023-06-03T23:09:15.450196Z","shell.execute_reply.started":"2023-06-03T23:09:15.438383Z","shell.execute_reply":"2023-06-03T23:09:15.449461Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if TRAIN:\n    train_dataset = ScrollDataset(\n        train_images, True, CFG, labels=train_masks, transform=get_transforms(data='train', cfg=CFG))\n    valid_dataset = ScrollDataset(\n        valid_images, True, CFG, labels=valid_masks, transform=get_transforms(data='valid', cfg=CFG))\n\n    train_loader = DataLoader(train_dataset,\n                            batch_size=CFG.train_batch_size,\n                            shuffle=True,\n                            num_workers=CFG.num_workers, pin_memory=True, drop_last=True)\n    valid_loader = DataLoader(valid_dataset,\n                            batch_size=CFG.valid_batch_size,\n                            shuffle=False,\n                            num_workers=CFG.num_workers, pin_memory=True, drop_last=False)","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.451659Z","iopub.execute_input":"2023-06-03T23:09:15.452411Z","iopub.status.idle":"2023-06-03T23:09:15.461433Z","shell.execute_reply.started":"2023-06-03T23:09:15.452372Z","shell.execute_reply":"2023-06-03T23:09:15.460692Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Display Dataset Results","metadata":{}},{"cell_type":"code","source":"if TRAIN:\n    display_dataset = ScrollDataset(train_images, True, CFG, labels = train_masks)\n    fig, axes = plt.subplots(4, CFG.in_chans+1)\n    fig.set_size_inches(20,16)\n    ax_id = 0\n    for slice_idx in range(0,1000,10):\n        img, mask = display_dataset[slice_idx]\n        if np.count_nonzero(mask) < (CFG.tile_size ** 2) // 4: # get a tile with a visible amount of pixels\n            continue\n\n        axes[ax_id,0].imshow(mask, cmap='gray')\n        axes[ax_id,0].set_title(\"Mask Slice\")\n        img = np.transpose(img, (2,0,1))\n        for j in range(CFG.in_chans):\n            axes[ax_id,j+1].imshow(img[j], cmap='gray')\n            axes[ax_id,j+1].set_title(f\"Subvolume: {65 // 2 - CFG.in_chans // 2 + j+1}\")\n        ax_id += 1\n        if ax_id >= 4:\n            break\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.462892Z","iopub.execute_input":"2023-06-03T23:09:15.463573Z","iopub.status.idle":"2023-06-03T23:09:15.477126Z","shell.execute_reply.started":"2023-06-03T23:09:15.463530Z","shell.execute_reply":"2023-06-03T23:09:15.476321Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model Creation\nFor this project, we will use Segmentation Models Pytorch (SMP) pretrained segmentation models and training functions.","metadata":{}},{"cell_type":"code","source":"#set up model parameters\nENCODER = 'timm-res2net50_14w_8s'\nENCODER_WEIGHTS = 'imagenet'\nCLASSES = ['ink']\nACTIVATION = None\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(DEVICE)","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.478643Z","iopub.execute_input":"2023-06-03T23:09:15.479344Z","iopub.status.idle":"2023-06-03T23:09:15.490166Z","shell.execute_reply.started":"2023-06-03T23:09:15.479303Z","shell.execute_reply":"2023-06-03T23:09:15.489078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if os.path.exists(CFG.model_load_path):\n    model = torch.load(CFG.model_load_path).to(DEVICE) #check if best model is saved\nelse:\n    model = smp.UnetPlusPlus(encoder_depth = 5,\n        encoder_name=ENCODER, \n        encoder_weights=ENCODER_WEIGHTS, \n        classes=len(CLASSES),\n        activation=ACTIVATION,\n        in_channels=CFG.in_chans\n    )  ","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:15.493220Z","iopub.execute_input":"2023-06-03T23:09:15.494514Z","iopub.status.idle":"2023-06-03T23:09:20.613354Z","shell.execute_reply.started":"2023-06-03T23:09:15.494423Z","shell.execute_reply":"2023-06-03T23:09:20.612280Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#set optimizer and scheduler\noptimizer = torch.optim.AdamW([ \n    dict(params=model.parameters(), lr=0.0001),\n])\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, CFG.epochs)\n\nBCELoss = smp.losses.SoftBCEWithLogitsLoss()\nBCELoss.__name__ = \"BCELoss\" #fixing minor bug with duct tape\n\n#define loss\nloss = BCELoss\n\n#define metrics\nmetrics = [utils.metrics.IoU(threshold=CFG.threshold), utils.metrics.Fscore(beta=0.5)]","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:20.618485Z","iopub.execute_input":"2023-06-03T23:09:20.621724Z","iopub.status.idle":"2023-06-03T23:09:20.640756Z","shell.execute_reply.started":"2023-06-03T23:09:20.621676Z","shell.execute_reply":"2023-06-03T23:09:20.639548Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_epoch = smp.utils.train.TrainEpoch(\n    model, \n    loss=loss, \n    metrics=metrics, \n    optimizer=optimizer,\n    device=DEVICE,\n    verbose=True\n)\n\nvalid_epoch = smp.utils.train.ValidEpoch(\n    model, \n    loss=loss, \n    metrics=metrics,\n    device=DEVICE,\n    verbose=True\n)","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:20.642599Z","iopub.execute_input":"2023-06-03T23:09:20.643071Z","iopub.status.idle":"2023-06-03T23:09:20.679276Z","shell.execute_reply.started":"2023-06-03T23:09:20.643027Z","shell.execute_reply":"2023-06-03T23:09:20.678278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training","metadata":{}},{"cell_type":"code","source":"if TRAIN:\n    max_score = 999\n    train_logs = []\n    valid_logs = []\n    for i in range(CFG.epochs):\n        \n        print('\\nEpoch: {}'.format(i+1))\n        train_logs.append(train_epoch.run(train_loader))\n        valid_logs.append(valid_epoch.run(valid_loader))\n\n        if max_score > valid_logs[-1]['BCELoss']:\n            max_score = valid_logs[-1]['BCELoss']\n            torch.save(model, CFG.model_save_path)\n            print('Model saved!')\n        scheduler.step()\n\n    #show training results\n    plt.figure(figsize=(15,8))\n    for i, metric in enumerate(['BCELoss', 'iou_score', 'fscore']):\n        plt.subplot(1,3,i+1)\n        plt.plot([train_log[metric] for train_log in train_logs], label='train')\n        plt.plot([valid_log[metric] for valid_log in valid_logs], label='valid')\n        plt.legend()\n        plt.xlabel('Epochs')\n        plt.ylabel(metric)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:20.681497Z","iopub.execute_input":"2023-06-03T23:09:20.681866Z","iopub.status.idle":"2023-06-03T23:09:20.693617Z","shell.execute_reply.started":"2023-06-03T23:09:20.681828Z","shell.execute_reply":"2023-06-03T23:09:20.692284Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Show Model Results on Training Fragments","metadata":{}},{"cell_type":"code","source":"def make_image_dataloader(mode, fragment_id):\n    images = read_images(fragment_id, mode, labels=False)\n    x1_list = list(range(0, images.shape[1]-CFG.tile_size+1, CFG.stride))\n    y1_list = list(range(0, images.shape[0]-CFG.tile_size+1, CFG.stride))\n    \n    images_list = []\n    xyxys = []\n    for y1 in y1_list:\n        for x1 in x1_list:\n            y2 = y1 + CFG.tile_size\n            x2 = x1 + CFG.tile_size\n            \n            images_list.append(images[y1:y2, x1:x2])\n            xyxys.append((x1, y1, x2, y2))\n    xyxys = np.stack(xyxys)\n            \n    img_dataset = ScrollDataset(images_list, False, CFG, transform=get_transforms(data='valid', cfg=CFG))\n    img_loader = DataLoader(img_dataset,\n                          batch_size=CFG.train_batch_size,\n                          shuffle=False,\n                          num_workers=CFG.num_workers, pin_memory=True, drop_last=False)\n    \n    return img_loader, xyxys","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:20.695400Z","iopub.execute_input":"2023-06-03T23:09:20.695832Z","iopub.status.idle":"2023-06-03T23:09:20.708099Z","shell.execute_reply.started":"2023-06-03T23:09:20.695795Z","shell.execute_reply":"2023-06-03T23:09:20.706997Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_full_model_pred(image_loader, binary_mask, xyxys):\n    ori_h = binary_mask.shape[0]\n    ori_w = binary_mask.shape[1]\n\n    pad0 = (CFG.tile_size - binary_mask.shape[0] % CFG.tile_size)\n    pad1 = (CFG.tile_size - binary_mask.shape[1] % CFG.tile_size)\n\n    binary_mask = np.pad(binary_mask, [(0, pad0), (0, pad1)], constant_values=0)\n    \n    mask_pred = np.zeros(binary_mask.shape)\n    mask_count = np.zeros(binary_mask.shape)\n\n    for step, (images) in tqdm(enumerate(image_loader), total=len(image_loader)):\n        images = images.to(device)\n        batch_size = images.size(0)\n\n        with torch.no_grad():\n            y_preds = model(images)\n        \n        start_idx = step*CFG.train_batch_size\n        end_idx = start_idx + batch_size\n        for i, (x1, y1, x2, y2) in enumerate(xyxys[start_idx:end_idx]):\n            mask_pred[y1:y2, x1:x2] = np.add(mask_pred[y1:y2, x1:x2],y_preds[i].squeeze(0).cpu().detach().numpy())\n            mask_count[y1:y2, x1:x2] = np.add(mask_count[y1:y2, x1:x2],np.ones((CFG.tile_size, CFG.tile_size)))\n            \n    mask_pred /= mask_count\n    del mask_count\n    \n    mask_pred = mask_pred[:ori_h, :ori_w]\n    binary_mask = binary_mask[:ori_h, :ori_w]\n    \n    mask_pred = (mask_pred >= CFG.threshold).astype(int)\n    mask_pred *= binary_mask\n\n    return mask_pred","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:20.709741Z","iopub.execute_input":"2023-06-03T23:09:20.710383Z","iopub.status.idle":"2023-06-03T23:09:20.725537Z","shell.execute_reply.started":"2023-06-03T23:09:20.710338Z","shell.execute_reply":"2023-06-03T23:09:20.724788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if TRAIN:\n    train_fragment_ids = sorted(os.listdir(CFG.comp_dataset_path + 'train'))\n    for fragment_id in train_fragment_ids:\n        \n        train_img_loader, xyxys = make_image_dataloader('train', fragment_id)\n        binary_mask = cv2.imread(CFG.comp_dataset_path + f\"train/{fragment_id}/mask.png\", 0)\n        binary_mask = (binary_mask / 255).astype(int)\n\n        mask_pred = get_full_model_pred(train_img_loader, binary_mask, xyxys)\n        plt.subplot(1,3,1)\n        plt.imshow(binary_mask, cmap='gray')\n        plt.title(\"Mask\")\n\n        inklabels = cv2.imread(CFG.comp_dataset_path + f\"train/{fragment_id}/inklabels.png\", 0)\n        plt.subplot(1,3,2)\n        plt.imshow(inklabels, cmap='gray')\n        plt.title(\"Ink Labels\")\n\n        plt.subplot(1,3,3)\n        plt.imshow(mask_pred, cmap='gray')\n        plt.title(\"Model Prediction\")\n        plt.show()\n\n        del mask_pred\n        del train_img_loader\n        \n        gc.collect()\n        torch.cuda.empty_cache()","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:20.727066Z","iopub.execute_input":"2023-06-03T23:09:20.727841Z","iopub.status.idle":"2023-06-03T23:09:20.742739Z","shell.execute_reply.started":"2023-06-03T23:09:20.727801Z","shell.execute_reply":"2023-06-03T23:09:20.741729Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"results = []\ntest_fragment_ids = sorted(os.listdir(CFG.comp_dataset_path + 'test'))\nfor fragment_id in test_fragment_ids:\n    \n    test_loader, xyxys = make_image_dataloader('test', fragment_id)\n\n    binary_mask = cv2.imread(CFG.comp_dataset_path + f\"test/{fragment_id}/mask.png\", 0)\n    binary_mask = (binary_mask / 255).astype(int)\n\n    mask_pred = get_full_model_pred(test_loader, binary_mask, xyxys)\n    plt.subplot(1,2,1)\n    plt.imshow(binary_mask, cmap='gray')\n    plt.title('Mask')\n\n    plt.subplot(1,2,2)\n    plt.imshow(mask_pred, cmap='gray')\n    plt.title('Prediction')\n    plt.show()\n    \n    inklabels_rle = rle_encode(mask_pred)\n\n    results.append((fragment_id, inklabels_rle))\n\n    del mask_pred\n    del test_loader\n    \n    gc.collect()\n    torch.cuda.empty_cache()","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:09:20.746210Z","iopub.execute_input":"2023-06-03T23:09:20.746721Z","iopub.status.idle":"2023-06-03T23:11:28.421657Z","shell.execute_reply.started":"2023-06-03T23:09:20.746655Z","shell.execute_reply":"2023-06-03T23:11:28.420614Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Submission Dataframe","metadata":{}},{"cell_type":"code","source":"submission_df = pd.DataFrame(results, columns=['Id', 'Predicted'])\ndisplay(submission_df)","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:11:28.423431Z","iopub.execute_input":"2023-06-03T23:11:28.423837Z","iopub.status.idle":"2023-06-03T23:11:28.443772Z","shell.execute_reply.started":"2023-06-03T23:11:28.423796Z","shell.execute_reply":"2023-06-03T23:11:28.442067Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2023-06-03T23:11:28.450312Z","iopub.execute_input":"2023-06-03T23:11:28.450598Z","iopub.status.idle":"2023-06-03T23:11:28.464293Z","shell.execute_reply.started":"2023-06-03T23:11:28.450571Z","shell.execute_reply":"2023-06-03T23:11:28.463142Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"https://towardsdatascience.com/the-best-approach-to-semantic-segmentation-of-biomedical-images-bbe4fd78733f\n\nhttps://www.fast.ai/posts/2018-07-02-adam-weight-decay.html","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}}]}