{"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":"## summary\n\n* 2.5d segmentation\n    *  segmentation_models_pytorch \n    *  Unet\n* use only 6 slices\n* slide inference","metadata":{}},{"cell_type":"code","source":"\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\nimport wandb","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:06:28.470956Z","iopub.execute_input":"2023-05-09T03:06:28.471676Z","iopub.status.idle":"2023-05-09T03:06:32.713182Z","shell.execute_reply.started":"2023-05-09T03:06:28.471631Z","shell.execute_reply":"2023-05-09T03:06:32.711817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sys.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')\n\nimport segmentation_models_pytorch as smp","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:06:32.715905Z","iopub.execute_input":"2023-05-09T03:06:32.716602Z","iopub.status.idle":"2023-05-09T03:06:35.565620Z","shell.execute_reply.started":"2023-05-09T03:06:32.716540Z","shell.execute_reply":"2023-05-09T03:06:35.564326Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nfrom torch.utils.data import DataLoader, Dataset\nimport cv2\nimport torch\nimport os\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nfrom albumentations import ImageOnlyTransform","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:07:51.237171Z","iopub.execute_input":"2023-05-09T03:07:51.237686Z","iopub.status.idle":"2023-05-09T03:07:51.243403Z","shell.execute_reply.started":"2023-05-09T03:07:51.237646Z","shell.execute_reply":"2023-05-09T03:07:51.242278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## config","metadata":{}},{"cell_type":"code","source":"import os\nimport albumentations as A \nfrom albumentations.pytorch import ToTensorV2\n# 数据增强工具\n\nclass CFG:\n    # ============== comp exp name ============= # 读取文件的名字\n    comp_name = 'vesuvius'\n\n    # comp_dir_path = './'\n    comp_dir_path = '/kaggle/input/'\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 ============= # 模型参数：需要查看unet的一些要求\n    model_name = 'Unet'\n    # backbone = 'efficientnet-b0'\n    backbone = 'se_resnext50_32x4d' \n\n    in_chans = 6 # 65（只使用6个？）\n    # ============== training cfg ============= # 训练\n    size = 224\n    tile_size = 224\n    stride = tile_size // 8\n\n    batch_size = 16 # 32\n    use_amp = True\n\n    scheduler = 'GradualWarmupSchedulerV2' #优化器设置\n    # scheduler = 'CosineAnnealingLR'\n    epochs = 15\n\n    warmup_factor = 10\n    lr = 1e-4 / warmup_factor\n\n    # ============== fold =============\n    valid_id = 2\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 = 4\n\n    seed = 42\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        # 非破坏性转换\n#         A.VerticalFlip(p=0.5),              \n#         A.RandomRotate90(p=0.5),\n        \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","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:22:56.242205Z","iopub.execute_input":"2023-05-09T03:22:56.242637Z","iopub.status.idle":"2023-05-09T03:22:56.258238Z","shell.execute_reply.started":"2023-05-09T03:22:56.242601Z","shell.execute_reply":"2023-05-09T03:22:56.257099Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IS_DEBUG = False\nmode = 'train' if IS_DEBUG else 'test'\nTH = 0.4","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:23:03.015474Z","iopub.execute_input":"2023-05-09T03:23:03.016261Z","iopub.status.idle":"2023-05-09T03:23:03.021271Z","shell.execute_reply.started":"2023-05-09T03:23:03.016218Z","shell.execute_reply":"2023-05-09T03:23:03.020131Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:23:06.944725Z","iopub.execute_input":"2023-05-09T03:23:06.945107Z","iopub.status.idle":"2023-05-09T03:23:07.003341Z","shell.execute_reply.started":"2023-05-09T03:23:06.945074Z","shell.execute_reply":"2023-05-09T03:23:07.002030Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## helper","metadata":{}},{"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":{"execution":{"iopub.status.busy":"2023-05-09T03:23:11.332591Z","iopub.execute_input":"2023-05-09T03:23:11.333286Z","iopub.status.idle":"2023-05-09T03:23:11.340193Z","shell.execute_reply.started":"2023-05-09T03:23:11.333249Z","shell.execute_reply":"2023-05-09T03:23:11.339021Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## dataset","metadata":{}},{"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        \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    images = np.stack(images, axis=2)\n    \n    return images","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:23:15.604080Z","iopub.execute_input":"2023-05-09T03:23:15.604448Z","iopub.status.idle":"2023-05-09T03:23:15.613829Z","shell.execute_reply.started":"2023-05-09T03:23:15.604415Z","shell.execute_reply":"2023-05-09T03:23:15.612634Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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    # print(aug)\n    return aug\n\nclass CustomDataset(Dataset):\n    def __init__(self, images, cfg, labels=None, transform=None):\n        self.images = images\n        self.cfg = cfg\n        self.labels = labels\n        self.transform = transform\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        data = self.transform(image=image)\n        image = data['image']\n        return image\n","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:23:23.250136Z","iopub.execute_input":"2023-05-09T03:23:23.250936Z","iopub.status.idle":"2023-05-09T03:23:23.259837Z","shell.execute_reply.started":"2023-05-09T03:23:23.250888Z","shell.execute_reply":"2023-05-09T03:23:23.258832Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def make_test_dataset(fragment_id):\n    test_images = read_image(fragment_id)\n    \n    x1_list = list(range(0, test_images.shape[1]-CFG.tile_size+1, CFG.stride))\n    y1_list = list(range(0, test_images.shape[0]-CFG.tile_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.tile_size\n            x2 = x1 + CFG.tile_size\n            \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, transform=get_transforms(data='valid', cfg=CFG))\n    \n    test_loader = DataLoader(test_dataset,\n                          batch_size=CFG.batch_size,\n                          shuffle=False,\n                          num_workers=CFG.num_workers, pin_memory=True, drop_last=False)\n    \n    return test_loader, xyxys","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:23:28.293934Z","iopub.execute_input":"2023-05-09T03:23:28.294905Z","iopub.status.idle":"2023-05-09T03:23:28.304855Z","shell.execute_reply.started":"2023-05-09T03:23:28.294848Z","shell.execute_reply":"2023-05-09T03:23:28.303694Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## model","metadata":{}},{"cell_type":"code","source":"class CustomModel(nn.Module):\n    def __init__(self, cfg, weight=None):\n        super().__init__()\n        self.cfg = cfg\n\n        self.encoder = smp.Unet(\n            encoder_name=cfg.backbone, \n            encoder_weights=weight,\n            in_channels=cfg.in_chans,\n            classes=cfg.target_size,\n            activation=None,\n        )\n\n    def forward(self, image):\n        output = self.encoder(image)\n        output = output.squeeze(-1)\n        return output\n\ndef build_model(cfg, weight=\"imagenet\"):\n    print('model_name', cfg.model_name)\n    print('backbone', cfg.backbone)\n\n    model = CustomModel(cfg, weight)\n    return model\n","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:23:38.424663Z","iopub.execute_input":"2023-05-09T03:23:38.425719Z","iopub.status.idle":"2023-05-09T03:23:38.433554Z","shell.execute_reply.started":"2023-05-09T03:23:38.425679Z","shell.execute_reply":"2023-05-09T03:23:38.432379Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class EnsembleModel:\n    def __init__(self, use_tta=False):\n        self.models = []\n        self.use_tta = use_tta\n\n    def __call__(self, x):\n        outputs = [torch.sigmoid(model(x)).to('cpu').numpy()\n                   for model in self.models]\n        avg_preds = np.mean(outputs, axis=0)\n        return avg_preds\n\n    def add_model(self, model):\n        self.models.append(model)\n\ndef build_ensemble_model():\n    model = EnsembleModel()\n    for fold in [1, 2, 3]:\n        _model = build_model(CFG, weight=None)\n        _model.to(device)\n\n        model_path = f'/kaggle/input/vesuvius-models-public/{CFG.exp_name}/vesuvius-models/Unet_fold{fold}_best.pth'\n        state = torch.load(model_path)['model']\n        _model.load_state_dict(state)\n        _model.eval()\n        \n        model.add_model(_model)\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:23:42.396373Z","iopub.execute_input":"2023-05-09T03:23:42.396784Z","iopub.status.idle":"2023-05-09T03:23:42.405350Z","shell.execute_reply.started":"2023-05-09T03:23:42.396748Z","shell.execute_reply":"2023-05-09T03:23:42.404200Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if mode == 'test':\n    fragment_ids = sorted(os.listdir(CFG.comp_dataset_path + mode))\nelse:\n    fragment_ids = [3]","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:23:45.624027Z","iopub.execute_input":"2023-05-09T03:23:45.624756Z","iopub.status.idle":"2023-05-09T03:23:45.640916Z","shell.execute_reply.started":"2023-05-09T03:23:45.624708Z","shell.execute_reply":"2023-05-09T03:23:45.639958Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = build_ensemble_model()","metadata":{"execution":{"iopub.status.busy":"2023-05-09T03:23:49.778423Z","iopub.execute_input":"2023-05-09T03:23:49.779162Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## main","metadata":{}},{"cell_type":"code","source":"sub = pd.DataFrame(results, columns=['Id', 'Predicted'])","metadata":{"execution":{"iopub.status.busy":"2023-04-04T05:04:59.791024Z","iopub.execute_input":"2023-04-04T05:04:59.79253Z","iopub.status.idle":"2023-04-04T05:04:59.80219Z","shell.execute_reply.started":"2023-04-04T05:04:59.792484Z","shell.execute_reply":"2023-04-04T05:04:59.801265Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub","metadata":{"execution":{"iopub.status.busy":"2023-04-04T05:04:59.803914Z","iopub.execute_input":"2023-04-04T05:04:59.804364Z","iopub.status.idle":"2023-04-04T05:04:59.832688Z","shell.execute_reply.started":"2023-04-04T05:04:59.804326Z","shell.execute_reply":"2023-04-04T05:04:59.831168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_sub = pd.read_csv(CFG.comp_dataset_path + 'sample_submission.csv')\nsample_sub = pd.merge(sample_sub[['Id']], sub, on='Id', how='left')","metadata":{"execution":{"iopub.status.busy":"2023-04-04T05:04:59.833854Z","iopub.execute_input":"2023-04-04T05:04:59.834119Z","iopub.status.idle":"2023-04-04T05:04:59.862057Z","shell.execute_reply.started":"2023-04-04T05:04:59.834093Z","shell.execute_reply":"2023-04-04T05:04:59.861126Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_sub","metadata":{"execution":{"iopub.status.busy":"2023-04-04T05:04:59.863677Z","iopub.execute_input":"2023-04-04T05:04:59.864045Z","iopub.status.idle":"2023-04-04T05:04:59.874408Z","shell.execute_reply.started":"2023-04-04T05:04:59.864009Z","shell.execute_reply":"2023-04-04T05:04:59.873278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_sub.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T05:04:59.875995Z","iopub.execute_input":"2023-04-04T05:04:59.876637Z","iopub.status.idle":"2023-04-04T05:04:59.890511Z","shell.execute_reply.started":"2023-04-04T05:04:59.8766Z","shell.execute_reply":"2023-04-04T05:04:59.88919Z"},"trusted":true},"execution_count":null,"outputs":[]}]}