{"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":"## The details of my experiment:\n1. model: PSPNet\n2. No patch: Actually, I should cut the original images into patchs. But I just resize these images into 512x512 pixels.\n3. I have tried that train PSPNet with all slides which contain multiple organs. However, its performance is pretty bad. So I only train this model with images of spleen, since the only one test image is spleen.","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport cv2\n\nimport matplotlib.pyplot as plt\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\n\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:02.418137Z","iopub.execute_input":"2022-07-21T03:50:02.418914Z","iopub.status.idle":"2022-07-21T03:50:06.522071Z","shell.execute_reply.started":"2022-07-21T03:50:02.418697Z","shell.execute_reply":"2022-07-21T03:50:06.520966Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE_DIR = \"/kaggle/input/hubmap-organ-segmentation\"\nprint(os.listdir(BASE_DIR))","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:06.524110Z","iopub.execute_input":"2022-07-21T03:50:06.524597Z","iopub.status.idle":"2022-07-21T03:50:06.530761Z","shell.execute_reply.started":"2022-07-21T03:50:06.524570Z","shell.execute_reply":"2022-07-21T03:50:06.529663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv(os.path.join(BASE_DIR, \"train.csv\"))\ndisplay(train_df)\ntest_df = pd.read_csv(os.path.join(BASE_DIR, \"test.csv\"))\ndisplay(test_df)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:06.532287Z","iopub.execute_input":"2022-07-21T03:50:06.532914Z","iopub.status.idle":"2022-07-21T03:50:06.863105Z","shell.execute_reply.started":"2022-07-21T03:50:06.532880Z","shell.execute_reply":"2022-07-21T03:50:06.862164Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def rle2mask(mask_rle, shape):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n\n    '''\n    s = mask_rle.split()\n    starts, lengths = [\n        np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])\n    ]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo : hi] = 1\n    return img.reshape(shape).T","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:06.866587Z","iopub.execute_input":"2022-07-21T03:50:06.866885Z","iopub.status.idle":"2022-07-21T03:50:06.873739Z","shell.execute_reply.started":"2022-07-21T03:50:06.866858Z","shell.execute_reply":"2022-07-21T03:50:06.872755Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_list = [index for i, index in train_df[train_df['organ']=='spleen'].id.items()]\nfrom sklearn.model_selection import train_test_split\ntrain_list, val_list = train_test_split(all_list, train_size=0.8, random_state=1234)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:06.875272Z","iopub.execute_input":"2022-07-21T03:50:06.875912Z","iopub.status.idle":"2022-07-21T03:50:06.888058Z","shell.execute_reply.started":"2022-07-21T03:50:06.875873Z","shell.execute_reply":"2022-07-21T03:50:06.887160Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from collections import OrderedDict\nimport math\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils import model_zoo\nfrom torchvision.models.densenet import densenet121, densenet161\nfrom torchvision.models.squeezenet import squeezenet1_1\n\n\ndef load_weights_sequential(target, source_state):\n    new_dict = OrderedDict()\n    for (k1, v1), (k2, v2) in zip(target.state_dict().items(), source_state.items()):\n        new_dict[k1] = v2\n    target.load_state_dict(new_dict)\n\n'''\n    Implementation of dilated ResNet-101 with deep supervision. Downsampling is changed to 8x\n'''\nmodel_urls = {\n    'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',\n    'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',\n    'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',\n    'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',\n    'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',\n}\n\n\ndef conv3x3(in_planes, out_planes, stride=1, dilation=1):\n    return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,\n                     padding=dilation, dilation=dilation, bias=False)\n\n\nclass BasicBlock(nn.Module):\n    expansion = 1\n\n    def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1):\n        super(BasicBlock, self).__init__()\n        self.conv1 = conv3x3(inplanes, planes, stride=stride, dilation=dilation)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.relu = nn.ReLU(inplace=True)\n        self.conv2 = conv3x3(planes, planes, stride=1, dilation=dilation)\n        self.bn2 = nn.BatchNorm2d(planes)\n        self.downsample = downsample\n        self.stride = stride\n\n    def forward(self, x):\n        residual = x\n\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.relu(out)\n\n        out = self.conv2(out)\n        out = self.bn2(out)\n\n        if self.downsample is not None:\n            residual = self.downsample(x)\n\n        out += residual\n        out = self.relu(out)\n\n        return out\n\n\nclass Bottleneck(nn.Module):\n    expansion = 4\n\n    def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1):\n        super(Bottleneck, self).__init__()\n        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, dilation=dilation,\n                               padding=dilation, bias=False)\n        self.bn2 = nn.BatchNorm2d(planes)\n        self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * 4)\n        self.relu = nn.ReLU(inplace=True)\n        self.downsample = downsample\n        self.stride = stride\n\n    def forward(self, x):\n        residual = x\n\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.relu(out)\n\n        out = self.conv2(out)\n        out = self.bn2(out)\n        out = self.relu(out)\n\n        out = self.conv3(out)\n        out = self.bn3(out)\n\n        if self.downsample is not None:\n            residual = self.downsample(x)\n\n        out += residual\n        out = self.relu(out)\n\n        return out\n\n\nclass ResNet(nn.Module):\n    def __init__(self, block, layers=(3, 4, 23, 3)):\n        self.inplanes = 64\n        super(ResNet, self).__init__()\n        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,\n                               bias=False)\n        self.bn1 = nn.BatchNorm2d(64)\n        self.relu = nn.ReLU(inplace=True)\n        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)\n        self.layer1 = self._make_layer(block, 64, layers[0])\n        self.layer2 = self._make_layer(block, 128, layers[1], stride=2)\n        self.layer3 = self._make_layer(block, 256, layers[2], stride=1, dilation=2)\n        self.layer4 = self._make_layer(block, 512, layers[3], stride=1, dilation=4)\n\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels\n                m.weight.data.normal_(0, math.sqrt(2. / n))\n            elif isinstance(m, nn.BatchNorm2d):\n                m.weight.data.fill_(1)\n                m.bias.data.zero_()\n\n    def _make_layer(self, block, planes, blocks, stride=1, dilation=1):\n        downsample = None\n        if stride != 1 or self.inplanes != planes * block.expansion:\n            downsample = nn.Sequential(\n                nn.Conv2d(self.inplanes, planes * block.expansion,\n                          kernel_size=1, stride=stride, bias=False),\n                nn.BatchNorm2d(planes * block.expansion),\n            )\n\n        layers = [block(self.inplanes, planes, stride, downsample)]\n        self.inplanes = planes * block.expansion\n        for i in range(1, blocks):\n            layers.append(block(self.inplanes, planes, dilation=dilation))\n\n        return nn.Sequential(*layers)\n\n    def forward(self, x):\n        x = self.conv1(x)\n        x = self.bn1(x)\n        x = self.relu(x)\n        x = self.maxpool(x)\n\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x_3 = self.layer3(x)\n        x = self.layer4(x_3)\n\n        return x, x_3\n\n\n'''\n    Implementation of DenseNet with deep supervision. Downsampling is changed to 8x \n'''\n\n\nclass _DenseLayer(nn.Sequential):\n    def __init__(self, num_input_features, growth_rate, bn_size, drop_rate):\n        super(_DenseLayer, self).__init__()\n        self.add_module('norm.1', nn.BatchNorm2d(num_input_features)),\n        self.add_module('relu.1', nn.ReLU(inplace=True)),\n        self.add_module('conv.1', nn.Conv2d(num_input_features, bn_size *\n                                            growth_rate, kernel_size=1, stride=1, bias=False)),\n        self.add_module('norm.2', nn.BatchNorm2d(bn_size * growth_rate)),\n        self.add_module('relu.2', nn.ReLU(inplace=True)),\n        self.add_module('conv.2', nn.Conv2d(bn_size * growth_rate, growth_rate,\n                                            kernel_size=3, stride=1, padding=1, bias=False)),\n        self.drop_rate = drop_rate\n\n    def forward(self, x):\n        new_features = super(_DenseLayer, self).forward(x)\n        if self.drop_rate > 0:\n            new_features = F.dropout(new_features, p=self.drop_rate, training=self.training)\n        return torch.cat([x, new_features], 1)\n\n\nclass _DenseBlock(nn.Sequential):\n    def __init__(self, num_layers, num_input_features, bn_size, growth_rate, drop_rate):\n        super(_DenseBlock, self).__init__()\n        for i in range(num_layers):\n            layer = _DenseLayer(num_input_features + i * growth_rate, growth_rate, bn_size, drop_rate)\n            self.add_module('denselayer%d' % (i + 1), layer)\n\n\nclass _Transition(nn.Sequential):\n    def __init__(self, num_input_features, num_output_features, downsample=True):\n        super(_Transition, self).__init__()\n        self.add_module('norm', nn.BatchNorm2d(num_input_features))\n        self.add_module('relu', nn.ReLU(inplace=True))\n        self.add_module('conv', nn.Conv2d(num_input_features, num_output_features,\n                                          kernel_size=1, stride=1, bias=False))\n        if downsample:\n            self.add_module('pool', nn.AvgPool2d(kernel_size=2, stride=2))\n        else:\n            self.add_module('pool', nn.AvgPool2d(kernel_size=1, stride=1))  # compatibility hack\n\n\nclass DenseNet(nn.Module):\n    def __init__(self, growth_rate=32, block_config=(6, 12, 24, 16),\n                 num_init_features=64, bn_size=4, drop_rate=0, pretrained=True):\n\n        super(DenseNet, self).__init__()\n\n        # First convolution\n        self.start_features = nn.Sequential(OrderedDict([\n            ('conv0', nn.Conv2d(3, num_init_features, kernel_size=7, stride=2, padding=3, bias=False)),\n            ('norm0', nn.BatchNorm2d(num_init_features)),\n            ('relu0', nn.ReLU(inplace=True)),\n            ('pool0', nn.MaxPool2d(kernel_size=3, stride=2, padding=1)),\n        ]))\n\n        # Each denseblock\n        num_features = num_init_features\n\n        init_weights = list(densenet121(pretrained=True).features.children())\n        start = 0\n        for i, c in enumerate(self.start_features.children()):\n            if pretrained:\n                c.load_state_dict(init_weights[i].state_dict())\n            start += 1\n        self.blocks = nn.ModuleList()\n        for i, num_layers in enumerate(block_config):\n            block = _DenseBlock(num_layers=num_layers, num_input_features=num_features,\n                                bn_size=bn_size, growth_rate=growth_rate, drop_rate=drop_rate)\n            if pretrained:\n                block.load_state_dict(init_weights[start].state_dict())\n            start += 1\n            self.blocks.append(block)\n            setattr(self, 'denseblock%d' % (i + 1), block)\n\n            num_features = num_features + num_layers * growth_rate\n            if i != len(block_config) - 1:\n                downsample = i < 1\n                trans = _Transition(num_input_features=num_features, num_output_features=num_features // 2,\n                                    downsample=downsample)\n                if pretrained:\n                    trans.load_state_dict(init_weights[start].state_dict())\n                start += 1\n                self.blocks.append(trans)\n                setattr(self, 'transition%d' % (i + 1), trans)\n                num_features = num_features // 2\n\n    def forward(self, x):\n        out = self.start_features(x)\n        deep_features = None\n        for i, block in enumerate(self.blocks):\n            out = block(out)\n            if i == 5:\n                deep_features = out\n\n        return out, deep_features\n\n\nclass Fire(nn.Module):\n\n    def __init__(self, inplanes, squeeze_planes,\n                 expand1x1_planes, expand3x3_planes, dilation=1):\n        super(Fire, self).__init__()\n        self.inplanes = inplanes\n        self.squeeze = nn.Conv2d(inplanes, squeeze_planes, kernel_size=1)\n        self.squeeze_activation = nn.ReLU(inplace=True)\n        self.expand1x1 = nn.Conv2d(squeeze_planes, expand1x1_planes,\n                                   kernel_size=1)\n        self.expand1x1_activation = nn.ReLU(inplace=True)\n        self.expand3x3 = nn.Conv2d(squeeze_planes, expand3x3_planes,\n                                   kernel_size=3, padding=dilation, dilation=dilation)\n        self.expand3x3_activation = nn.ReLU(inplace=True)\n\n    def forward(self, x):\n        x = self.squeeze_activation(self.squeeze(x))\n        return torch.cat([\n            self.expand1x1_activation(self.expand1x1(x)),\n            self.expand3x3_activation(self.expand3x3(x))\n        ], 1)\n\n\nclass SqueezeNet(nn.Module):\n\n    def __init__(self, pretrained=False):\n        super(SqueezeNet, self).__init__()\n\n        self.feat_1 = nn.Sequential(\n            nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1),\n            nn.ReLU(inplace=True)\n        )\n        self.feat_2 = nn.Sequential(\n            nn.MaxPool2d(kernel_size=3, stride=2, padding=1),\n            Fire(64, 16, 64, 64),\n            Fire(128, 16, 64, 64)\n        )\n        self.feat_3 = nn.Sequential(\n            nn.MaxPool2d(kernel_size=3, stride=2, padding=1),\n            Fire(128, 32, 128, 128, 2),\n            Fire(256, 32, 128, 128, 2)\n        )\n        self.feat_4 = nn.Sequential(\n            Fire(256, 48, 192, 192, 4),\n            Fire(384, 48, 192, 192, 4),\n            Fire(384, 64, 256, 256, 4),\n            Fire(512, 64, 256, 256, 4)\n        )\n        if pretrained:\n            weights = squeezenet1_1(pretrained=True).features.state_dict()\n            load_weights_sequential(self, weights)\n\n    def forward(self, x):\n        f1 = self.feat_1(x)\n        f2 = self.feat_2(f1)\n        f3 = self.feat_3(f2)\n        f4 = self.feat_4(f3)\n        return f4, f3\n\n\n'''\n    Handy methods for construction\n'''\n\n\ndef squeezenet(pretrained=True):\n    return SqueezeNet(pretrained)\n\n\ndef densenet(pretrained=True):\n    return DenseNet(pretrained=pretrained)\n\n\ndef resnet18(pretrained=True):\n    model = ResNet(BasicBlock, [2, 2, 2, 2])\n    if pretrained:\n        load_weights_sequential(model, model_zoo.load_url(model_urls['resnet18']))\n    return model\n\n\ndef resnet34(pretrained=True):\n    model = ResNet(BasicBlock, [3, 4, 6, 3])\n    if pretrained:\n        load_weights_sequential(model, model_zoo.load_url(model_urls['resnet34']))\n    return model\n\n\ndef resnet50(pretrained=True):\n    model = ResNet(Bottleneck, [3, 4, 6, 3])\n    if pretrained:\n        load_weights_sequential(model, model_zoo.load_url(model_urls['resnet50']))\n    return model\n\n\ndef resnet101(pretrained=True):\n    model = ResNet(Bottleneck, [3, 4, 23, 3])\n    if pretrained:\n        load_weights_sequential(model, model_zoo.load_url(model_urls['resnet101']))\n    return model\n\n\ndef resnet152(pretrained=True):\n    model = ResNet(Bottleneck, [3, 8, 36, 3])\n    if pretrained:\n        load_weights_sequential(model, model_zoo.load_url(model_urls['resnet152']))\n    return model\n\nimport torch\nfrom torch import nn\nfrom torch.nn import functional as F\n\n\n\n\nclass PSPModule(nn.Module):\n    def __init__(self, features, out_features=1024, sizes=(1, 2, 3, 6)):\n        super().__init__()\n        self.stages = []\n        self.stages = nn.ModuleList([self._make_stage(features, size) for size in sizes])\n        self.bottleneck = nn.Conv2d(features * (len(sizes) + 1), out_features, kernel_size=1)\n        self.relu = nn.ReLU()\n\n    def _make_stage(self, features, size):\n        prior = nn.AdaptiveAvgPool2d(output_size=(size, size))\n        conv = nn.Conv2d(features, features, kernel_size=1, bias=False)\n        return nn.Sequential(prior, conv)\n\n    def forward(self, feats):\n        h, w = feats.size(2), feats.size(3)\n        priors = [F.upsample(input=stage(feats), size=(h, w), mode='bilinear') for stage in self.stages] + [feats]\n        bottle = self.bottleneck(torch.cat(priors, 1))\n        return self.relu(bottle)\n\n\nclass PSPUpsample(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super().__init__()\n        self.conv = nn.Sequential(\n            nn.Conv2d(in_channels, out_channels, 3, padding=1),\n            nn.BatchNorm2d(out_channels),\n            nn.PReLU()\n        )\n\n    def forward(self, x):\n        h, w = 2 * x.size(2), 2 * x.size(3)\n        p = F.upsample(input=x, size=(h, w), mode='bilinear')\n        return self.conv(p)\n\n\nclass PSPNet(nn.Module):\n    def __init__(self, n_classes=18, sizes=(1, 2, 3, 6), psp_size=2048, deep_features_size=1024, backend='resnet50',\n                 pretrained=True):\n        super().__init__()\n        self.feats = resnet50(pretrained)\n        self.psp = PSPModule(psp_size, 1024, sizes)\n        self.drop_1 = nn.Dropout2d(p=0.3)\n\n        self.up_1 = PSPUpsample(1024, 256)\n        self.up_2 = PSPUpsample(256, 64)\n        self.up_3 = PSPUpsample(64, 64)\n\n        self.drop_2 = nn.Dropout2d(p=0.15)\n        self.final = nn.Sequential(\n            nn.Conv2d(64, n_classes, kernel_size=1),\n#             nn.LogSoftmax()\n        )\n\n        self.classifier = nn.Sequential(\n            nn.Linear(deep_features_size, 256),\n            nn.ReLU(),\n            nn.Linear(256, n_classes)\n        )\n\n    def forward(self, x):\n        f, class_f = self.feats(x) \n        p = self.psp(f)\n        p = self.drop_1(p)\n\n        p = self.up_1(p)\n        p = self.drop_2(p)\n\n        p = self.up_2(p)\n        p = self.drop_2(p)\n\n        p = self.up_3(p)\n        p = self.drop_2(p)\n\n        auxiliary = F.adaptive_max_pool2d(input=class_f, output_size=(1, 1)).view(-1, class_f.size(1))\n        \n        return self.final(p)\n\n#         return self.final(p), self.classifier(auxiliary)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:06.890251Z","iopub.execute_input":"2022-07-21T03:50:06.890607Z","iopub.status.idle":"2022-07-21T03:50:06.977446Z","shell.execute_reply.started":"2022-07-21T03:50:06.890573Z","shell.execute_reply":"2022-07-21T03:50:06.976487Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nTRAIN_IMAGES_DIR = os.path.join(BASE_DIR, 'train_images')\n\nclass imgDataset(Dataset):\n    def __init__(self, data_id_list, transform, size=(256, 256)):\n        self.data_id_list = data_id_list\n        self.transform = transform\n        self.size = size\n        \n    def __len__(self):\n        return(len(self.data_id_list))\n    \n    def __getitem__(self, index):\n        img_path = TRAIN_IMAGES_DIR+'/'+str(self.data_id_list[index])+'.tiff'\n        img = cv2.imread(img_path)\n        h,w,c = img.shape\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        img = cv2.resize(img, self.size)\n        mask = rle2mask(train_df[train_df[\"id\"] == self.data_id_list[index]][\"rle\"].values[0], (h,w))\n        mask = cv2.resize(mask, self.size, interpolation=cv2.INTER_NEAREST)\n        if self.transform is not None:\n            img_and_mask = self.transform(image=img, mask=mask)\n        \n        return img_and_mask","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:06.979273Z","iopub.execute_input":"2022-07-21T03:50:06.979682Z","iopub.status.idle":"2022-07-21T03:50:06.991697Z","shell.execute_reply.started":"2022-07-21T03:50:06.979648Z","shell.execute_reply":"2022-07-21T03:50:06.990686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import albumentations as A\nfrom albumentations.pytorch import ToTensorV2\n\ntrain_transform = A.Compose([\n            A.Downscale(scale_min=0.5, scale_max=0.75, p=0.2),\n            A.HorizontalFlip(p=0.5),\n            A.Blur(p=0.2),\n            A.VerticalFlip(p=0.5),\n            A.RandomFog(p=0.2),\n            A.RandomBrightnessContrast(p=0.2),\n            A.RandomGamma(p=0.7),\n            A.Normalize(mean=(0.45734706, 0.43338275, 0.4005811), std=(0.23965294, 0.23532275, 0.2398498)),\n            ToTensorV2(),\n        ])\n\ntest_transform = A.Compose([\n            A.Normalize(mean=(0.45734706, 0.43338275, 0.4005811), std=(0.23965294, 0.23532275, 0.2398498)),\n            ToTensorV2(),\n        ])\n\ntrain_ds = imgDataset(train_list, train_transform)\nval_ds = imgDataset(val_list, test_transform)\n\ntrain_dl = DataLoader(train_ds, batch_size=2, shuffle=True, drop_last=True, num_workers=0)\nval_dl = DataLoader(val_ds, batch_size=2, shuffle=False, drop_last=True, num_workers=0)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:06.993113Z","iopub.execute_input":"2022-07-21T03:50:06.993641Z","iopub.status.idle":"2022-07-21T03:50:07.007089Z","shell.execute_reply.started":"2022-07-21T03:50:06.993605Z","shell.execute_reply":"2022-07-21T03:50:07.006004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = PSPNet(n_classes=2, pretrained=False).cuda()\nepoch_num = 50\nprint('    Total params: %.2fM' % (sum(p.numel() for p in model.parameters()) / 1000000.0))\nlr = 5.0e-4\nprint(f'lr = {lr}')\nloss_function = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=lr)\nscheduler = optim.lr_scheduler.StepLR(optimizer, 5, 0.5)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:07.009252Z","iopub.execute_input":"2022-07-21T03:50:07.009694Z","iopub.status.idle":"2022-07-21T03:50:10.679223Z","shell.execute_reply.started":"2022-07-21T03:50:07.009657Z","shell.execute_reply":"2022-07-21T03:50:10.678165Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def batch_pix_accuracy(predict, target, labeled):\n    pixel_labeled = labeled.sum()\n    pixel_correct = ((predict == target) * labeled).sum()\n    assert pixel_correct <= pixel_labeled, \"Correct area should be smaller than Labeled\"\n    return pixel_correct.cpu().numpy(), pixel_labeled.cpu().numpy()\n\ndef batch_intersection_union(predict, target, num_class, labeled):\n    intersection = predict * (predict == target).long()\n\n    area_inter = torch.histc(intersection.float(), bins=num_class, max=num_class, min=1)\n    area_pred = torch.histc(predict.float(), bins=num_class, max=num_class, min=1)\n    area_lab = torch.histc(target.float(), bins=num_class, max=num_class, min=1)\n    area_union = area_pred + area_lab - area_inter\n#     print(f'inter: {area_inter}')\n#     print(f'pred: {area_pred}')\n#     print(f'target: {area_lab}')\n#     print(f'union: {area_union}')\n    assert (area_inter <= area_union).all(), \"Intersection area should be smaller than Union area\"\n    return area_inter.cpu().numpy(), area_union.cpu().numpy()\n\ndef eval_metrics(output, target, num_class):\n    _, predict = torch.max(output.data, 1)\n    predict += 1\n    target += 1\n    labeled = (target > 0) * (target <= num_class)\n    correct, num_labeled = batch_pix_accuracy(predict, target, labeled)\n    inter, union = batch_intersection_union(predict, target, num_class, labeled)\n    return [np.round(correct, 5), np.round(num_labeled, 5), np.round(inter, 5), np.round(union, 5)]\n\n\ndef multi_vali(val_loader, model, num_class):\n    acc = 0.0\n    labeled = 0.0\n    inter = 0.0\n    union = 0.0 \n    step = 0\n    \n    model.eval()\n    with torch.no_grad():\n        for index, pack in enumerate(val_loader):\n            step = step + 1\n            inputs, targets = pack['image'].cuda(), pack['mask'].cuda()\n            outputs = model(inputs)\n                \n            num_acc, num_labeled, num_inter, num_union = eval_metrics(outputs, targets, num_class = num_class) \n            \n            acc += num_acc\n            labeled += num_labeled\n            inter += num_inter\n            union += num_union\n            \n    if hasattr(torch.cuda, 'empty_cache'):\n        torch.cuda.empty_cache()  \n    return acc/step, labeled/step, inter/step, union/step","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:10.683751Z","iopub.execute_input":"2022-07-21T03:50:10.684110Z","iopub.status.idle":"2022-07-21T03:50:10.698936Z","shell.execute_reply.started":"2022-07-21T03:50:10.684076Z","shell.execute_reply":"2022-07-21T03:50:10.697522Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from copy import deepcopy\n\nbest_iou = 0.0\nbest_model = deepcopy(model.state_dict())\nfor epoch in range(epoch_num):\n    print(\"-\"*30)\n    print(f'epoch: {epoch+1} / {epoch_num}')\n    print(\"====> validating\")\n    acc, labeled, inter, union = multi_vali(val_dl, model, num_class=2)\n    print(f'acc:{acc}, labeled:{labeled}, inter:{inter}, union:{union}')\n    print(f'acc = {acc/labeled}, iou = {inter/union}')\n    \n    current_iou = inter/union\n    if best_iou < current_iou[1]:\n        best_iou = current_iou[1]\n        best_model = deepcopy(model)\n    \n    model.train()\n    loss_ttl = 0.0\n    step = 0\n    print(\"====> training\")\n    for index, pack in enumerate(train_dl):\n        step += 1\n        inputs = pack['image'].cuda()\n        targets = pack['mask'].cuda()\n        \n        pred = model(inputs)\n#         print(pred.size())\n#         print(targets.size())\n        loss = loss_function(pred, targets.long())\n        loss_ttl += loss\n        \n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n    print(f'loss = {loss_ttl/step}')","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:50:10.700534Z","iopub.execute_input":"2022-07-21T03:50:10.701283Z","iopub.status.idle":"2022-07-21T03:57:41.210226Z","shell.execute_reply.started":"2022-07-21T03:50:10.701247Z","shell.execute_reply":"2022-07-21T03:57:41.208499Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\ndel model\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:57:41.211681Z","iopub.execute_input":"2022-07-21T03:57:41.212033Z","iopub.status.idle":"2022-07-21T03:57:41.342821Z","shell.execute_reply.started":"2022-07-21T03:57:41.211998Z","shell.execute_reply":"2022-07-21T03:57:41.341785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install staintools \n!pip install spams ","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:57:41.344554Z","iopub.execute_input":"2022-07-21T03:57:41.345325Z","iopub.status.idle":"2022-07-21T03:59:44.492209Z","shell.execute_reply.started":"2022-07-21T03:57:41.345287Z","shell.execute_reply":"2022-07-21T03:59:44.491004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## predict the image after stain normalization","metadata":{}},{"cell_type":"code","source":"import staintools\n\nto_transform = staintools.read_image(\"/kaggle/input/hubmap-organ-segmentation/test_images/10078.tiff\")\ntarget = staintools.read_image(\"/kaggle/input/hubmap-organ-segmentation/train_images/10392.tiff\")\n\n# Standardize brightness (optional, can improve the tissue mask calculation)\ntarget = staintools.LuminosityStandardizer.standardize(target)\nto_transform = staintools.LuminosityStandardizer.standardize(to_transform)\n\n# Stain normalize\nnormalizer = staintools.StainNormalizer(method='vahadane')\nnormalizer.fit(target)\ntransformed = normalizer.transform(to_transform)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:59:44.494245Z","iopub.execute_input":"2022-07-21T03:59:44.494631Z","iopub.status.idle":"2022-07-21T03:59:59.469969Z","shell.execute_reply.started":"2022-07-21T03:59:44.494593Z","shell.execute_reply":"2022-07-21T03:59:59.468690Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transformed = cv2.resize(transformed,(512,512))\ninput_img = torch.stack([test_transform(image=transformed)['image']]).cuda()","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:59:59.471589Z","iopub.execute_input":"2022-07-21T03:59:59.472275Z","iopub.status.idle":"2022-07-21T03:59:59.490357Z","shell.execute_reply.started":"2022-07-21T03:59:59.472237Z","shell.execute_reply":"2022-07-21T03:59:59.489706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"best_model.train()\nwith torch.no_grad():\n    pred = best_model(input_img)\n    mask = torch.argmax(pred, dim=1)\nplt.subplot(121)\nplt.imshow(transformed)\nplt.subplot(122)\nplt.imshow(mask.squeeze().cpu().numpy(), cmap='gray', alpha=0.5)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T04:02:14.384181Z","iopub.execute_input":"2022-07-21T04:02:14.384757Z","iopub.status.idle":"2022-07-21T04:02:14.859717Z","shell.execute_reply.started":"2022-07-21T04:02:14.384721Z","shell.execute_reply":"2022-07-21T04:02:14.858817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def rle_encode_less_memory(img):\n    #the image should be transposed\n    pixels = img.T.flatten()\n    \n    # This simplified method requires first and last pixel to be zero\n    pixels[0] = 0\n    pixels[-1] = 0\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 2\n    runs[1::2] -= runs[::2]\n    \n    return ' '.join(str(x) for x in runs)\nmask = mask.squeeze().cpu().numpy()\nmask = cv2.resize(mask, (2023,2023), interpolation=cv2.INTER_NEAREST)\nrle = rle_encode_less_memory(mask)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:59:59.827791Z","iopub.execute_input":"2022-07-21T03:59:59.829365Z","iopub.status.idle":"2022-07-21T03:59:59.878738Z","shell.execute_reply.started":"2022-07-21T03:59:59.829327Z","shell.execute_reply":"2022-07-21T03:59:59.877731Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(rle2mask(rle, (2023,2023)))","metadata":{"execution":{"iopub.status.busy":"2022-07-21T03:59:59.880132Z","iopub.execute_input":"2022-07-21T03:59:59.880995Z","iopub.status.idle":"2022-07-21T04:00:00.413289Z","shell.execute_reply.started":"2022-07-21T03:59:59.880954Z","shell.execute_reply":"2022-07-21T04:00:00.412332Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## predict the image without stain normalization","metadata":{}},{"cell_type":"code","source":"test_img = cv2.imread(\"/kaggle/input/hubmap-organ-segmentation/test_images/10078.tiff\")\ntest_img = cv2.resize(test_img,(512,512))\ninput_img = torch.stack([test_transform(image=test_img)['image']]).cuda()\nbest_model.train()\nwith torch.no_grad():\n    pred = best_model(input_img)\n    mask = torch.argmax(pred, dim=1)\nplt.imshow(test_img)\nplt.imshow(mask.squeeze().cpu().numpy(), cmap='gray', alpha=0.5)","metadata":{"execution":{"iopub.status.busy":"2022-07-21T04:00:00.414921Z","iopub.execute_input":"2022-07-21T04:00:00.415290Z","iopub.status.idle":"2022-07-21T04:00:00.745223Z","shell.execute_reply.started":"2022-07-21T04:00:00.415255Z","shell.execute_reply":"2022-07-21T04:00:00.744306Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}