{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport gc\nimport matplotlib.pyplot as plt\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport tifffile as tif\nimport cv2\nimport imagecodecs\nfrom sklearn import metrics as skmetrics\nimport torch\nimport torch.nn as nn\n\nimport torch.optim as optim\nimport torch.nn.functional as F\nimport pytorch_lightning as pl\n\nfrom pytorch_lightning.callbacks import EarlyStopping\nfrom pytorch_lightning.loggers.tensorboard import TensorBoardLogger\n\nimport seaborn as sns\n\nfrom logging import basicConfig, getLogger, INFO\nbasicConfig(level=INFO, format='%(asctime)s %(levelname)s :%(message)s')\nlogger = getLogger(__name__)\n\nDEBUG = False\n\nNUM_WORKERS = 0 if os.name == 'nt' else 2\nBATCH_SIZE = 2\nEPOCHS = 2 if DEBUG == True else 100\nPATIENCE = 4\n\nn_train = 2 if DEBUG == True else 15\n# UNet\nIN_CHS = 3\nOUT_CHS = 1\nUNET_DEPTH = 4\n\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n\nIMG_SHAPE = (2400, 2400)# (width, height)\n\nimport multiprocessing as mp\nmp.set_start_method('spawn')\n\n#for dirname, _, filenames in os.walk('hubmap-kidney-segmentation'):\n    #for filename in filenames:\n        #print(os.path.join(dirname, filename))\n\n# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\n#import numpy as np # linear algebra\n#import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\n#import os\n#for dirname, _, filenames in os.walk('/kaggle/input'):\n    #for filename in filenames:\n        #print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE_PATH = \"/kaggle/input/hubmap-kidney-segmentation/\"\nTRAIN_PATH = os.path.join(BASE_PATH, \"train\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train = pd.read_csv(\"/kaggle/input/hubmap-kidney-segmentation/train.csv\")\ndf_train","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tr_ids = df_train[\"id\"]\ntr_ids_l = []\nfor i, ids in enumerate(tr_ids):\n    tr_ids_l.append(ids)\n    \nprint(tr_ids_l)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# RLEfunction","metadata":{}},{"cell_type":"code","source":"def rle2mask(mask_rle, shape=IMG_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    Source: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\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\n\ndef mask2rle(img):\n    '''\n    Efficient implementation of mask2rle, from @paulorzp\n    --\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    Source: https://www.kaggle.com/xhlulu/efficient-mask2rle\n    '''\n    pixels = img.T.flatten()\n    pixels = np.pad(pixels, ((1, 1), ))\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":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# DataLoader","metadata":{}},{"cell_type":"code","source":"predictors = []\ntarget = []\n\nfor id in tr_ids_l[:n_train]:\n    image = tif.imread(os.path.join(BASE_PATH, f\"train/{id}.tiff\"))\n    print(id, image.shape)\n    if len(image.shape) == 5:\n        image = image.squeeze().transpose(1, 2, 0)\n        mask = rle2mask(df_train[df_train[\"id\"] == id][\"encoding\"].values[0],\n                        (image.shape[1], image.shape[0]))\n    elif image.shape[0] == 3:\n        image = image.transpose(1, 2, 0)\n        mask = rle2mask(df_train[df_train[\"id\"] == id][\"encoding\"].values[0],\n                        (image.shape[1], image.shape[0]))\n    else:\n        mask = rle2mask(df_train[df_train[\"id\"] == id][\"encoding\"].values[0],\n                        (image.shape[1], image.shape[0]))\n    image = cv2.resize(image, IMG_SHAPE)\n    mask = cv2.resize(mask, IMG_SHAPE)\n    predictors.append(image)\n    target.append(mask)\n    print(f\"{id}\")\n    \nlogger.info('Finish dataload')\n\ndel image, mask\ngc.collect()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictors = np.array(predictors)\ntarget = np.array(target)\n\npredictors = predictors / 255 \npredictors = predictors.astype(np.float32)\ntarget = target.astype(np.float32)\n\npredictors = np.transpose(predictors, (0, 3, 1, 2))\ntarget = np.expand_dims(target, axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred = predictors[:10]\ntgt = target[:10]\nval_pred = predictors[10:15]\nval_tgt = target[10:15]\n\ndel predictors, target\ngc.collect()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"class ConvBNReLU(nn.Module):\n    def __init__(self, in_chs, out_chs, kernel_size, padding):\n        super().__init__()\n        self.block = nn.Sequential(\n            nn.Conv2d(in_chs,\n                      out_chs,\n                      kernel_size=kernel_size,\n                      padding=padding), nn.BatchNorm2d(out_chs),\n            nn.ReLU(inplace=True))\n\n    def forward(self, x):\n        return self.block(x)\n\n\nclass Encoder(nn.Module):\n    def __init__(self, in_chs: int, mid_chs: int, out_chs: int,\n                 kernel_size: int, padding: int):\n        super().__init__()\n        self.out_chs = out_chs\n        self.block = nn.Sequential(\n            ConvBNReLU(in_chs, mid_chs, kernel_size, padding),\n            ConvBNReLU(mid_chs, out_chs, kernel_size, padding),\n        )\n\n    def forward(self, x):\n        return self.block(x)\n\n\nclass Decoder(nn.Module):\n    def __init__(self,\n                 in_chs,\n                 out_chs,\n                 kernel_size,\n                 padding,\n                 scale_factor: int,\n                 apply_dropout=False):\n        super().__init__()\n        self.out_chs = out_chs\n        mid_chs = (in_chs + out_chs) // 2\n        self.up = nn.Upsample(scale_factor=scale_factor,\n                              mode='bilinear',\n                              align_corners=True)\n        self.block = nn.Sequential(\n            ConvBNReLU(in_chs, mid_chs, kernel_size, padding),\n            ConvBNReLU(mid_chs, out_chs, kernel_size, padding),\n        )\n\n        if apply_dropout:\n            self.dropout = nn.Dropout(.25)\n        else:\n            self.dropout = None\n\n    def forward(self, x1, x2):\n        cat = torch.cat([self.up(x1), x2], dim=1)\n        x = self.block(cat)\n        if self.dropout:\n            x = self.dropout(x)\n        return x\n\n\nclass UNet(nn.Module):\n    def __init__(self,\n                 in_chs,\n                 out_chs,\n                 depth,\n                 ini_chs=8,\n                 kernel_size=3,\n                 padding=1,\n                 scale_factor=2):\n        '''\n        Args:\n            depth (int): UNets depth i.e # of downsampling layers\n        '''\n        super().__init__()\n        self.depth = depth\n        self.encs = nn.ModuleList()\n        self.decs = nn.ModuleList()\n        self.pools = nn.ModuleList()\n        chs = ini_chs\n        for i in range(depth):\n            enc = Encoder(in_chs if i == 0 else chs, chs, chs * 2, kernel_size,\n                          padding)\n            self.encs.append(enc)\n            chs = chs * 2\n            if i < (depth - 1):\n                self.pools.append(nn.MaxPool2d(scale_factor))\n\n        for i in range(depth - 1):\n            enc_below = self.encs[-i - 1]\n            enc_left = self.encs[-i - 2]\n            dec = Decoder(enc_left.out_chs + enc_below.out_chs,\n                          enc_left.out_chs,\n                          kernel_size,\n                          padding,\n                          scale_factor,\n                          apply_dropout=i < depth // 2)\n            self.decs.append(dec)\n\n        self.output_layer = nn.Conv2d(self.decs[-1].out_chs,\n                                      out_chs,\n                                      kernel_size=1,\n                                      padding=0)\n\n    def forward(self, x):\n        skips = []\n        for i in range(self.depth):\n            x = self.encs[i](x)\n            if i < (self.depth - 1):\n                skips.append(x)\n                x = self.pools[i](x)\n\n        for i in range(self.depth - 1):\n            x = self.decs[i](x, skips[-(i + 1)])\n\n        return self.output_layer(x)\n    \n#summary(UNet(IN_CHS, OUT_CHS, UNET_DEPTH), (3, IMG_SHAPE[1], IMG_SHAPE[0]),\n        #device='cpu')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class LitUNet(pl.LightningModule):\n    def __init__(self, in_chs, out_chs, depth):\n        super().__init__()\n        self.model = UNet(in_chs, out_chs, depth)\n\n    def forward(self, x):\n        return self.model(x)\n\n    def training_step(self, batch, batch_idx):\n        x, y = batch\n        y_hat = self.model(x)\n        loss = F.binary_cross_entropy_with_logits(y_hat, y)\n        self.log('train_loss', loss)\n        return loss\n\n    def validation_step(self, batch, batch_idx): #汎化性能確認のため実施\n        x, y = batch\n        y_hat = self.model(x)\n        loss = F.binary_cross_entropy_with_logits(y_hat, y)\n        self.log('val_loss', loss)\n        return loss    \n    \n    def configure_optimizers(self):\n        optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)\n        return optimizer","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train","metadata":{}},{"cell_type":"code","source":"data = torch.from_numpy(pred).to(device)\nlabels = torch.FloatTensor(tgt).to(device)\ntrain_dataset = torch.utils.data.TensorDataset(data, labels)\ntrain_loader = torch.utils.data.DataLoader(train_dataset, \n                                           batch_size=BATCH_SIZE,\n                                           shuffle=True,\n                                           num_workers=NUM_WORKERS)\n\nval_data = torch.from_numpy(val_pred).to(\"cpu\")\nval_labels = torch.FloatTensor(val_tgt).to(\"cpu\")\nval_dataset = torch.utils.data.TensorDataset(val_data, val_labels)\nval_loader = torch.utils.data.DataLoader(val_dataset, \n                                         batch_size=BATCH_SIZE,\n                                         shuffle=False,\n                                         num_workers=NUM_WORKERS)\n\ndel pred, tgt, data, labels\ngc.collect()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"early_stop_callback = EarlyStopping(monitor='val_loss',\n                                    patience=PATIENCE,\n                                    verbose=False,\n                                    mode='min')\nLOGGER = TensorBoardLogger('train_logs', name='hubk_segmentation')\ntrainer = pl.Trainer(gpus=1 if torch.cuda.is_available() else 0,\n                     max_epochs=EPOCHS,\n                     logger=LOGGER,\n                     log_every_n_steps=len(train_loader),\n                     callbacks=[early_stop_callback])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = LitUNet(IN_CHS, OUT_CHS, UNET_DEPTH)\n\nlogger.info('Start training')\ntrainer.fit(model, train_loader, val_loader)\nlogger.info('Finish training')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Test data load","metadata":{}},{"cell_type":"code","source":"df_sub = pd.read_csv(\n    os.path.join(BASE_PATH, \"sample_submission.csv\"))\ndf_sub","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_ids = df_sub[\"id\"]\n\ntest_ids_l = []\nfor i, ids in enumerate(test_ids):\n    test_ids_l.append(ids)\n    \nprint(test_ids_l)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictors = []\ntarget = []\n\nfor id in test_ids_l[:n_train]:\n    image = tif.imread(os.path.join(BASE_PATH, f\"test/{id}.tiff\"))\n    print(id, image.shape)\n    if len(image.shape) == 5:\n        image = image.squeeze().transpose(1, 2, 0)\n        #mask = rle2mask(df_train[df_train[\"id\"] == id][\"encoding\"].values[0],\n                        #(image.shape[1], image.shape[0]))\n    elif image.shape[0] == 3:\n        image = image.transpose(1, 2, 0)\n        #mask = rle2mask(df_train[df_train[\"id\"] == id][\"encoding\"].values[0],\n                        #(image.shape[1], image.shape[0]))\n    #else:\n        #mask = rle2mask(df_train[df_train[\"id\"] == id][\"encoding\"].values[0],\n                        #(image.shape[1], image.shape[0]))\n    image = cv2.resize(image, IMG_SHAPE)\n    #mask = cv2.resize(mask, IMG_SHAPE)\n    predictors.append(image)\n    #target.append(mask)\n    print(f\"{id}\")\n    \nprint(len(predictors))\n#print(len(target))\nprint(\"end\")\n\ndel image\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictors = np.array(predictors)\n\npredictors = predictors / 255 \npredictors = predictors.astype(np.float32)\n\npredictors = np.transpose(predictors, (0, 3, 1, 2))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"pred_l = []\n\nfor i, dt in enumerate(predictors):\n    dt = np.expand_dims(dt, axis=0)\n\n    with torch.no_grad():\n        prediction = torch.sigmoid(model(torch.FloatTensor(dt)))\n        prediction = prediction.cpu().numpy().squeeze()\n    _ = plt.hist(prediction, bins=20)\n    plt.show()\n    pred_bin = (prediction > .5).astype(np.uint8)\n    pred_l.append(pred_bin)\n    _ = plt.figure(figsize=(100, 100))\n    plt.subplot(5, 1, i+1)\n    plt.imshow(np.transpose(dt.squeeze(), (1, 2, 0)))\n    plt.imshow(pred_bin, cmap=\"hot\", alpha=0.5)\n    plt.axis(\"off\")\n    if DEBUG==True:\n        if i == 1:\n            break\n            \ndel dt, pred_bin, predictors, prediction\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Result","metadata":{}},{"cell_type":"code","source":"shape_dic = {}\n\nfor id in test_ids_l[:n_train]:\n    image = tif.imread(os.path.join(BASE_PATH, f\"test/{id}.tiff\"))\n    print(id, image.shape)\n    #if len(image.shape) == 5:\n        #image = image.squeeze().transpose(1, 2, 0)\n        #mask = rle2mask(df_train[df_train[\"id\"] == id][\"encoding\"].values[0],\n                        #(image.shape[1], image.shape[0]))\n    if image.shape[0] == 3:\n        shape_dic[id] = (image.shape[2], image.shape[1])\n        #image = image.transpose(1, 2, 0)\n        #mask = rle2mask(df_train[df_train[\"id\"] == id][\"encoding\"].values[0],\n                        #(image.shape[1], image.shape[0]))\n    else:\n        shape_dic[id] = (image.shape[1], image.shape[0])\n        #mask = rle2mask(df_train[df_train[\"id\"] == id][\"encoding\"].values[0],\n                        #(image.shape[1], image.shape[0]))\n    #image = cv2.resize(image, IMG_SHAPE)\n    #mask = cv2.resize(mask, IMG_SHAPE)\n    #predictors.append(image)\n    #target.append(mask)\n    print(f\"{id}\")\n\n# shape_dicのvalueは(width, height)\nprint(shape_dic)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mask_l = []\nfor i, index in enumerate(shape_dic):\n    image = tif.imread(os.path.join(BASE_PATH, f\"test/{index}.tiff\"))\n    mask = pred_l[i]\n    mask = cv2.resize(mask, shape_dic[index], interpolation=cv2.INTER_LINEAR)\n    mask_l.append(mask)\n    #_ = plt.figure(figsize=(100, 100))\n    #plt.subplot(5, 1, i+1)\n    #plt.imshow(image)\n    #plt.imshow(mask, cmap=\"hot\", alpha=0.5)\n    #plt.axis(\"off\")","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Mask to RLE","metadata":{}},{"cell_type":"code","source":"mask_rle_l = []\nfor msk in mask_l:\n    rle = mask2rle(msk)\n    mask_rle_l.append(rle)\n    \ndel msk\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub[\"predicted\"] = mask_rle_l\n\ndf_sub","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"filepath = \"/kaggle/input/submissioncsv/submission.csv\"\nif os.path.exists(filepath):\n    df_sub = pd.read_csv(\"/kaggle/input/submissioncsv/submission.csv\")\n    \ndf_sub","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}