{"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":"# Introduction\nThis notebook is based on:\n1. [2.5d segmentaion baseline [training]](https://www.kaggle.com/code/tanakar/2-5d-segmentaion-baseline-training)\n2. [2.5d segmentaion baseline [inference]](https://www.kaggle.com/code/tanakar/2-5d-segmentaion-baseline-inference)\n3. [Vesuvius Challenge - 3D ResNet Training](https://www.kaggle.com/code/samfc10/vesuvius-challenge-3d-resnet-training)\n4. [3D ResNet baseline [inference]](https://www.kaggle.com/code/yoyobar/3d-resnet-baseline-inference)","metadata":{"id":"h7IxCWulWMb-"}},{"cell_type":"markdown","source":"# Imports","metadata":{"id":"2ihL6qNxWMb_"}},{"cell_type":"code","source":"import sys\nimport os\n\nsys.path.append('/kaggle/input/pretrainedmodels/pretrainedmodels-0.7.4')\nsys.path.append('/kaggle/input/efficientnet-pytorch/EfficientNet-PyTorch-master')\nsys.path.append('/kaggle/input/timm-pytorch-image-models/pytorch-image-models-master')\nsys.path.append('/kaggle/input/segmentation-models-pytorch/segmentation_models.pytorch-master')\nsys.path.append('/kaggle/input/torch-xla/torch_xla-2.0-cp310-cp310-linux_x86_64.whl')\nsys.path.append('/kaggle/input/torch-xla/pytorch-xla-env-setup.py')","metadata":{"execution":{"iopub.status.busy":"2023-06-04T00:52:21.263612Z","iopub.execute_input":"2023-06-04T00:52:21.263993Z","iopub.status.idle":"2023-06-04T00:52:21.286720Z","shell.execute_reply.started":"2023-06-04T00:52:21.263959Z","shell.execute_reply":"2023-06-04T00:52:21.285841Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\nimport os\nimport gc\nimport glob\nimport json\nimport multiprocessing as mp\nimport warnings\nimport time\n\nimport albumentations as A\n\nimport matplotlib.pyplot as plt\nimport PIL.Image as Image\nimport cv2\n\nimport numpy as np\nimport pandas as pd\nimport random\n\nimport torch\nimport torch as tc\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.utils.data as thd\n\nimport segmentation_models_pytorch as smp\nimport segmentation_models_pytorch.utils as smp_utils\nimport segmentation_models_pytorch.utils.losses as smp_losses\n\nfrom torchvision import transforms\nfrom torch.optim import Adam, SGD, AdamW\nfrom torch.optim.lr_scheduler import CosineAnnealingWarmRestarts, CosineAnnealingLR, ReduceLROnPlateau, OneCycleLR\nfrom torch.cuda.amp import autocast, GradScaler\nfrom torch.utils.data import Dataset, DataLoader\n\nfrom segmentation_models_pytorch.encoders import get_preprocessing_fn\n\nfrom pathlib import Path\n\nfrom sklearn.metrics import fbeta_score\nfrom sklearn.exceptions import UndefinedMetricWarning\n\nfrom albumentations.pytorch import ToTensorV2\n\nfrom tqdm import tqdm\n\nwarnings.simplefilter('ignore')","metadata":{"id":"vOMCpxF8WMcB","execution":{"iopub.status.busy":"2023-06-04T00:52:21.295157Z","iopub.execute_input":"2023-06-04T00:52:21.299291Z","iopub.status.idle":"2023-06-04T00:52:30.482173Z","shell.execute_reply.started":"2023-06-04T00:52:21.299259Z","shell.execute_reply":"2023-06-04T00:52:30.481144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Config","metadata":{"id":"Ns-2-GUEWMcC"}},{"cell_type":"code","source":"class CFG:\n    # ============== set paths =============\n    base_path = \"/kaggle/input\"\n    base_output_path = '/kaggle/working/'\n    comp_folder_name = 'vesuvius-challenge-ink-detection'\n    \n    comp_dataset_path = os.path.join(base_path, comp_folder_name)\n    train_dataset_path = os.path.join(comp_dataset_path, 'train')\n    test_dataset_path = os.path.join(comp_dataset_path, 'test')\n    \n    save_base_path = '/kaggle/working/'\n    trained_models_path = '/kaggle/input/vesuvius-models-efficientnetb6/Unet_EfficientNetB6_model.pth'\n    \n    # ============== pred target =============\n    target_size = 1\n\n    # ============== model cfg =============\n    model_name = 'Unet'\n    backbone = 'efficientnet-b6'\n#     backbone = 'efficientnet-b4'\n#     backbone = 'se_resnext50_32x4d'\n#     backbone = 'resnet3d'\n#     backbone = 'efficientnet-b0'\n    \n    z_chans = 65\n    in_chans = 6 # 65\n    \n    # ============== training cfg =============\n    size = 384\n    prd_size = size\n    stride = 32\n    \n    batch_size = 16 # 32\n    use_amp = True\n    \n    epochs = 5 # 30    \n    \n    lr = 1e-3\n\n    # ============== fold =============\n    valid_id = 1\n\n    # ============== fixed =============\n    pre_trained = True\n    inf_weight = 'best'  # 'best'\n    \n    min_lr = 1e-6\n    weight_decay = 1e-3 # 1e-4\n    max_grad_norm = 1000\n\n    num_workers = 4\n\n    seed = 42\n\n    # ============== augmentation =============\n    test_aug_list = [\n        transforms.Normalize(mean=[0] * in_chans, std=[1] * in_chans),\n        transforms.ToTensor()\n    ]","metadata":{"id":"nAGSV-YnWMcC","execution":{"iopub.status.busy":"2023-06-04T00:52:39.054227Z","iopub.execute_input":"2023-06-04T00:52:39.055025Z","iopub.status.idle":"2023-06-04T00:52:39.064801Z","shell.execute_reply.started":"2023-06-04T00:52:39.054990Z","shell.execute_reply":"2023-06-04T00:52:39.063737Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = tc.device(\"cuda\" if tc.cuda.is_available() else \"cpu\")\nprint(device)","metadata":{"id":"E0FoaZg-WMcD","outputId":"964d7aa9-c80c-4612-9742-ba3f8a7cd6de","execution":{"iopub.status.busy":"2023-06-04T00:52:43.818729Z","iopub.execute_input":"2023-06-04T00:52:43.819221Z","iopub.status.idle":"2023-06-04T00:52:43.852954Z","shell.execute_reply.started":"2023-06-04T00:52:43.819180Z","shell.execute_reply":"2023-06-04T00:52:43.851952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Helper","metadata":{"id":"1inuO1dJWMcD"}},{"cell_type":"code","source":"# ref.: https://www.kaggle.com/stainsby/fast-tested-rle\ndef rle(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":{"id":"5Sp3snPBWMcD","execution":{"iopub.status.busy":"2023-06-04T00:52:45.078329Z","iopub.execute_input":"2023-06-04T00:52:45.078868Z","iopub.status.idle":"2023-06-04T00:52:45.087457Z","shell.execute_reply.started":"2023-06-04T00:52:45.078837Z","shell.execute_reply":"2023-06-04T00:52:45.085156Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Set up data","metadata":{"id":"B5DPr9PrWMcD"}},{"cell_type":"code","source":"def read_image(fragment_id):\n    images = []\n\n    # idxs = range(65)\n    mid = 65 // 2\n    start = mid - CFG.in_chans // 2\n    end = mid + CFG.in_chans // 2\n    idxs = range(start, end)\n\n    for i in tqdm(idxs):\n        image = cv2.imread(f\"{CFG.test_dataset_path}/{fragment_id}/surface_volume/{i:02}.tif\", 0)\n\n        pad0 = (CFG.prd_size - image.shape[0] % CFG.prd_size)\n        pad1 = (CFG.prd_size - image.shape[1] % CFG.prd_size)\n\n        image = np.pad(image, [(0, pad0), (0, pad1)], constant_values=0)\n\n        images.append(image)\n    images = np.stack(images, axis=2)\n    \n    return images\n\ndef slice_fragment_to_subvolumes(fragment_ids):\n    test_images = []\n    test_xyxys = []\n\n    for fragment_id in fragment_ids:\n        image  = read_image_mask(fragment_id)\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                sliced_image = image[y1:y2, x1:x2]\n                \n                test_images.append(sliced_image)\n                test_xyxys.append([x1, y1, x2, y2])\n\n    return test_images, test_xyxys\n\n\ndef make_test_dataset(fragment_id):\n    test_images = read_image(fragment_id)\n    \n    x1_list = list(range(0, test_images.shape[1]-CFG.prd_size+1, CFG.stride))\n    y1_list = list(range(0, test_images.shape[0]-CFG.prd_size+1, CFG.stride))\n    \n    test_images_list = []\n    xyxys = []\n    for y1 in y1_list:\n        for x1 in x1_list:\n            y2 = y1 + CFG.prd_size\n            x2 = x1 + CFG.prd_size\n            if np.all(test_images[y1:y2, x1:x2]==0):\n                continue\n            test_images_list.append(test_images[y1:y2, x1:x2])\n            xyxys.append((x1, y1, x2, y2))\n    xyxys = np.stack(xyxys)\n            \n    test_dataset = CustomDataset(test_images_list, CFG,xys=xyxys)\n    \n    test_loader = DataLoader(test_dataset,\n                             batch_size=CFG.batch_size,\n                             shuffle=False,\n                             drop_last=False)\n    \n    return test_loader, xyxys","metadata":{"id":"Zn69hQLTWMcD","execution":{"iopub.status.busy":"2023-06-04T00:52:46.015284Z","iopub.execute_input":"2023-06-04T00:52:46.016376Z","iopub.status.idle":"2023-06-04T00:52:46.031425Z","shell.execute_reply.started":"2023-06-04T00:52:46.016332Z","shell.execute_reply":"2023-06-04T00:52:46.030521Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomDataset(Dataset):\n    def __init__(self, images, cfg,xys, labels=None):\n        self.images = images\n        self.cfg = cfg\n        self.labels = labels\n        self.xys=xys\n\n    def __len__(self):\n        # return len(self.xyxys)\n        return len(self.images)\n\n    def __getitem__(self, idx):\n        # x1, y1, x2, y2 = self.xyxys[idx]\n        image = self.images[idx]\n        image=tc.from_numpy(image).permute(2,0,1).to(tc.float32)/255\n        image = (image - 0.45)/0.225\n        return image,self.xys[idx]","metadata":{"id":"hvUVFLXDWMcD","execution":{"iopub.status.busy":"2023-06-04T00:52:46.588220Z","iopub.execute_input":"2023-06-04T00:52:46.589221Z","iopub.status.idle":"2023-06-04T00:52:46.596669Z","shell.execute_reply.started":"2023-06-04T00:52:46.589180Z","shell.execute_reply":"2023-06-04T00:52:46.595567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def TTA(x:tc.Tensor,model:nn.Module):\n    #x.shape=(batch,c,h,w)\n    shape=x.shape\n    x = [x, *[tc.rot90(x,k=i,dims=(-2, -1)) for i in range(1, 4)]]\n    x = tc.cat(x, dim=0)\n    x = model(x)\n    x = torch.sigmoid(x)\n    x = x.reshape(4, shape[0], *shape[2:])\n    x = [tc.rot90(x[i],k=-i, dims=(-2,-1)) for i in range(4)]\n    x = tc.stack(x, dim=0)\n    return x.mean(0)","metadata":{"id":"xdYOkBwHWMcE","execution":{"iopub.status.busy":"2023-06-04T00:52:47.212316Z","iopub.execute_input":"2023-06-04T00:52:47.212664Z","iopub.status.idle":"2023-06-04T00:52:47.219832Z","shell.execute_reply.started":"2023-06-04T00:52:47.212637Z","shell.execute_reply":"2023-06-04T00:52:47.218962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"in_submission=True\nIS_DEBUG = False\nmode = 'train' if IS_DEBUG else 'test'\nTH = 0.6\nfragment_ids = sorted(os.listdir(f'{CFG.comp_dataset_path}/{mode}'))","metadata":{"id":"uBG05qwNWMcE","execution":{"iopub.status.busy":"2023-06-04T00:52:48.057472Z","iopub.execute_input":"2023-06-04T00:52:48.058340Z","iopub.status.idle":"2023-06-04T00:52:48.066646Z","shell.execute_reply.started":"2023-06-04T00:52:48.058297Z","shell.execute_reply":"2023-06-04T00:52:48.065595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{"id":"UUYgaHvLWMcE"}},{"cell_type":"code","source":"model = torch.load(CFG.trained_models_path, map_location=device).to(device)","metadata":{"id":"-8FVKhpHWMcE","execution":{"iopub.status.busy":"2023-06-04T00:52:57.494694Z","iopub.execute_input":"2023-06-04T00:52:57.495245Z","iopub.status.idle":"2023-06-04T00:53:02.670926Z","shell.execute_reply.started":"2023-06-04T00:52:57.495206Z","shell.execute_reply":"2023-06-04T00:53:02.669941Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Predictions","metadata":{"id":"nwp0rSHFWMcE"}},{"cell_type":"code","source":"results = []\nfor fragment_id in fragment_ids:\n    if not in_submission:\n        break\n    test_loader, xyxys = make_test_dataset(fragment_id)\n    \n    binary_mask = cv2.imread(f\"{CFG.test_dataset_path}/{fragment_id}/mask.png\", 0)\n    binary_mask = (binary_mask / 255).astype(int)\n    \n    ori_h = binary_mask.shape[0]\n    ori_w = binary_mask.shape[1]\n\n    pad0 = (CFG.prd_size - binary_mask.shape[0] % CFG.prd_size)\n    pad1 = (CFG.prd_size - binary_mask.shape[1] % CFG.prd_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,xys) in tqdm(enumerate(test_loader), total=len(test_loader)):\n        images = images.to(device)\n        batch_size = images.size(0)\n\n        with torch.no_grad():\n            y_preds = TTA(images,model)\n            # y_preds = model(images)\n        \n        for k, (x1, y1, x2, y2) in enumerate(xys):\n            mask_pred[y1:y2, x1:x2] += y_preds[k].squeeze(0).cpu().numpy()\n            mask_count[y1:y2, x1:x2] += 1\n        \n    print(f'mask_count_min: {mask_count.min()}')\n    mask_pred /= (mask_count+1e-7)\n    \n    fig, axes = plt.subplots(1, 4, figsize=(15, 8))\n    axes[0].imshow(mask_count)\n    axes[1].imshow(mask_pred.copy())\n    \n    axes[2].imshow(mask_pred)\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 >= TH).astype(np.uint8)\n    mask_pred = mask_pred.astype(int)\n    mask_pred *= binary_mask\n    \n    axes[3].imshow(mask_pred)\n    plt.show()\n    \n    inklabels_rle = rle(mask_pred)\n    \n    results.append((fragment_id, inklabels_rle))\n    \n\n    del mask_pred, mask_count\n    del test_loader\n    \n    gc.collect()\n    torch.cuda.empty_cache()","metadata":{"id":"rnXgWXklWMcE","outputId":"0d288e81-f4be-40e2-f1d5-4da67bec4f11","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{"id":"LtjvrOH2WMcF"}},{"cell_type":"code","source":"# !cp /kaggle/input/vesuvius-challenge-ink-detection/sample_submission.csv submission.csv\nif in_submission:\n    sub = pd.DataFrame(results, columns=['Id', 'Predicted'])\n    #sub\n    sample_sub = pd.read_csv(CFG.comp_dataset_path + '/sample_submission.csv')\n    sample_sub = pd.merge(sample_sub[['Id']], sub, on='Id', how='left')\n    #sample_sub\n    sample_sub.to_csv(\"submission.csv\", index=False)\n    print(\"ok\")","metadata":{"id":"hvEyFtYxWMcF","outputId":"7415eae5-958c-4366-df45-e1c9c778a5c1","execution":{"iopub.status.busy":"2023-06-04T01:10:30.254912Z","iopub.status.idle":"2023-06-04T01:10:30.255630Z","shell.execute_reply.started":"2023-06-04T01:10:30.255370Z","shell.execute_reply":"2023-06-04T01:10:30.255394Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Resources\n1. [Segmentation Models Pytorch](https://smp.readthedocs.io/en/latest/models.html#id9)\n2. [UNet](https://www.youtube.com/watch?v=oLvmLJkmXuc&list=PLhhyoLH6IjfwqKKZhVLp7diKFxTmj4Q6s&index=12)\n2. [ResNet vs EfficientNet](https://medium.com/@enrico.randellini/image-classification-resnet-vs-efficientnet-vs-efficientnet-v2-vs-compact-convolutional-c205838bbf49)\n3. [Papers with Code](https://paperswithcode.com/)\n4. [Visual Guide to learning rate schedulers](https://towardsdatascience.com/a-visual-guide-to-learning-rate-schedulers-in-pytorch-24bbb262c863)\n","metadata":{"id":"xjFcye8VWMcF"}},{"cell_type":"code","source":"","metadata":{"id":"36VKuEm8WMcF"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"id":"AOwbRLIsWMcF"},"execution_count":null,"outputs":[]}]}