{"nbformat_minor": 2, "nbformat": 4, "cells": [{"cell_type": "code", "execution_count": null, "outputs": [], "metadata": {"_cell_guid": "d28262f1-d45b-4239-8f22-1d995dc31678", "_uuid": "8d293ba91db7d2ca60af5301f3882a4493f268b1", "collapsed": true}, "source": ["import os\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "from tqdm import tqdm\n", "\n", "import torch as t\n", "from torch.utils import data\n", "from torchvision import transforms as tsf\n", "\n", "TRAIN_PATH = './train.pth'\n", "TEST_PATH = './test.tph'\n", "%matplotlib inline"]}, {"cell_type": "markdown", "metadata": {"_cell_guid": "809986f9-e4ec-442d-8d1e-1074a61f9674", "_uuid": "a580a3dd265e8d52e09895ff6a73b27f0733c945"}, "source": ["## Data Preprocessing\n", "Preprocess data and save it to disk"]}, {"cell_type": "code", "execution_count": null, "outputs": [], "metadata": {"_cell_guid": "45a72d08-aa24-4a52-a886-306eea16a09f", "_uuid": "c402595750b1053b6050b54de311970dc5eff511", "collapsed": true}, "source": ["import os\n", "from pathlib import Path\n", "from PIL import Image\n", "from skimage import io\n", "import numpy as np\n", "from tqdm import tqdm\n", "import torch as t\n", "\n", "\n", "def process(file_path, has_mask=True):\n", "    file_path = Path(file_path)\n", "    files = sorted(list(Path(file_path).iterdir()))\n", "    datas = []\n", "\n", "    for file in tqdm(files):\n", "        item = {}\n", "        imgs = []\n", "        for image in (file/'images').iterdir():\n", "            img = io.imread(image)\n", "            imgs.append(img)\n", "        assert len(imgs)==1\n", "        if img.shape[2]>3:\n", "            assert(img[:,:,3]!=255).sum()==0\n", "        img = img[:,:,:3]\n", "\n", "        if has_mask:\n", "            mask_files = list((file/'masks').iterdir())\n", "            masks = None\n", "            for ii,mask in enumerate(mask_files):\n", "                mask = io.imread(mask)\n", "                assert (mask[(mask!=0)]==255).all()\n", "                if masks is None:\n", "                    H,W = mask.shape\n", "                    masks = np.zeros((len(mask_files),H,W))\n", "                masks[ii] = mask\n", "            tmp_mask = masks.sum(0)\n", "            assert (tmp_mask[tmp_mask!=0] == 255).all()\n", "            for ii,mask in enumerate(masks):\n", "                masks[ii] = mask/255 * (ii+1)\n", "            mask = masks.sum(0)\n", "            item['mask'] = t.from_numpy(mask)\n", "        item['name'] = str(file).split('/')[-1]\n", "        item['img'] = t.from_numpy(img)\n", "        datas.append(item)\n", "    return datas\n", "\n", "# You can skip this if you have alreadly done it.\n", "test = process('../input/stage1_test/',False)\n", "t.save(test, TEST_PATH)\n", "train_data = process('../input/stage1_train/')\n", "# t.save(train_data, TRAIN_PATH)"]}, {"cell_type": "markdown", "metadata": {"_cell_guid": "044d0516-207c-40e7-9491-4b4308dbeb17", "_uuid": "c1378fe0f41dd484d2bd90017a931c0c2c015474"}, "source": ["## Data Loader\n", "Wrap it with pytorch `Dataset` and `DataLoader` "]}, {"cell_type": "code", "execution_count": null, "outputs": [], "metadata": {"_cell_guid": "93ee96bc-b4f8-4fbb-be12-51b1278ec609", "_uuid": "abf16769cb47dc681209228912c10254d2832f78", "collapsed": true}, "source": ["import PIL\n", "class Dataset():\n", "    def __init__(self,data,source_transform,target_transform):\n", "        self.datas = data\n", "#         self.datas = train_data\n", "        self.s_transform = source_transform\n", "        self.t_transform = target_transform\n", "    def __getitem__(self, index):\n", "        data = self.datas[index]\n", "        img = data['img'].numpy()\n", "        mask = data['mask'][:,:,None].byte().numpy()\n", "        img = self.s_transform(img)\n", "        mask = self.t_transform(mask)\n", "        return img, mask\n", "    def __len__(self):\n", "        return len(self.datas)\n", "s_trans = tsf.Compose([\n", "    tsf.ToPILImage(),\n", "    tsf.Resize((128,128)),\n", "    tsf.ToTensor(),\n", "    tsf.Normalize(mean = [0.5,0.5,0.5],std = [0.5,0.5,0.5])\n", "]\n", ")\n", "t_trans = tsf.Compose([\n", "    tsf.ToPILImage(),\n", "    tsf.Resize((128,128),interpolation=PIL.Image.NEAREST),\n", "    tsf.ToTensor(),]\n", ")\n", "dataset = Dataset(train_data,s_trans,t_trans)\n", "dataloader = t.utils.data.DataLoader(dataset,num_workers=2,batch_size=4)"]}, {"cell_type": "code", "execution_count": null, "outputs": [], "metadata": {"_cell_guid": "dd704a3d-f237-40f8-80a0-872126e2aa24", "_uuid": "d190b9fd42c274934db93312d505f74ea25fc9cf", "collapsed": true}, "source": ["img,mask = dataset[12]\n", "plt.subplot(121)\n", "plt.imshow(img.permute(1,2,0).numpy()*0.5+0.5)\n", "plt.subplot(122)\n", "plt.imshow(mask[0].numpy())"]}, {"cell_type": "markdown", "metadata": {"_cell_guid": "30b3971d-d86a-4a98-b05f-bdcd6f0b4d96", "_uuid": "cc8678071f646425263b9cc618d8c26e3f7088ec"}, "source": ["## Model: UNet"]}, {"cell_type": "code", "execution_count": null, "outputs": [], "metadata": {"_cell_guid": "17a487c7-149c-4e3c-9273-04ea64fd87dc", "_uuid": "12709d595fdc8a30c30331d1674d9498b8839f82", "collapsed": true}, "source": ["# sub-parts of the U-Net model\n", "\n", "from torch import nn\n", "import torch.nn.functional as F\n", "\n", "\n", "class double_conv(nn.Module):\n", "    '''(conv => BN => ReLU) * 2'''\n", "    def __init__(self, in_ch, out_ch):\n", "        super(double_conv, self).__init__()\n", "        self.conv = nn.Sequential(\n", "            nn.Conv2d(in_ch, out_ch, 3, padding=1),\n", "            nn.BatchNorm2d(out_ch),\n", "            nn.ReLU(inplace=True),\n", "            nn.Conv2d(out_ch, out_ch, 3, padding=1),\n", "            nn.BatchNorm2d(out_ch),\n", "            nn.ReLU(inplace=True)\n", "        )\n", "\n", "    def forward(self, x):\n", "        x = self.conv(x)\n", "        return x\n", "\n", "\n", "class inconv(nn.Module):\n", "    def __init__(self, in_ch, out_ch):\n", "        super(inconv, self).__init__()\n", "        self.conv = double_conv(in_ch, out_ch)\n", "\n", "    def forward(self, x):\n", "        x = self.conv(x)\n", "        return x\n", "\n", "\n", "class down(nn.Module):\n", "    def __init__(self, in_ch, out_ch):\n", "        super(down, self).__init__()\n", "        self.mpconv = nn.Sequential(\n", "            nn.MaxPool2d(2),\n", "            double_conv(in_ch, out_ch)\n", "        )\n", "\n", "    def forward(self, x):\n", "        x = self.mpconv(x)\n", "        return x\n", "\n", "\n", "class up(nn.Module):\n", "    def __init__(self, in_ch, out_ch, bilinear=True):\n", "        super(up, self).__init__()\n", "\n", "        #  would be a nice idea if the upsampling could be learned too,\n", "        #  but my machine do not have enough memory to handle all those weights\n", "        if bilinear:\n", "            self.up = nn.Upsample(scale_factor=2)\n", "        else:\n", "            self.up = nn.ConvTranspose2d(in_ch, out_ch, 2, stride=2)\n", "\n", "        self.conv = double_conv(in_ch, out_ch)\n", "\n", "    def forward(self, x1, x2):\n", "        x1 = self.up(x1)\n", "        diffX = x1.size()[2] - x2.size()[2]\n", "        diffY = x1.size()[3] - x2.size()[3]\n", "        x2 = F.pad(x2, (diffX // 2, int(diffX / 2),\n", "                        diffY // 2, int(diffY / 2)))\n", "        x = t.cat([x2, x1], dim=1)\n", "        x = self.conv(x)\n", "        return x\n", "\n", "\n", "class outconv(nn.Module):\n", "    def __init__(self, in_ch, out_ch):\n", "        super(outconv, self).__init__()\n", "        self.conv = nn.Conv2d(in_ch, out_ch, 1)\n", "\n", "    def forward(self, x):\n", "        x = self.conv(x)\n", "        return x\n", "\n", "\n", "class UNet(nn.Module):\n", "    def __init__(self, n_channels, n_classes):\n", "        super(UNet, self).__init__()\n", "        self.inc = inconv(n_channels, 64)\n", "        self.down1 = down(64, 128)\n", "        self.down2 = down(128, 256)\n", "        self.down3 = down(256, 512)\n", "        self.down4 = down(512, 512)\n", "        self.up1 = up(1024, 256)\n", "        self.up2 = up(512, 128)\n", "        self.up3 = up(256, 64)\n", "        self.up4 = up(128, 64)\n", "        self.outc = outconv(64, n_classes)\n", "\n", "    def forward(self, x):\n", "        x1 = self.inc(x)\n", "        x2 = self.down1(x1)\n", "        x3 = self.down2(x2)\n", "        x4 = self.down3(x3)\n", "        x5 = self.down4(x4)\n", "        x = self.up1(x5, x4)\n", "        x = self.up2(x, x3)\n", "        x = self.up3(x, x2)\n", "        x = self.up4(x, x1)\n", "        x = self.outc(x)\n", "        x = t.nn.functional.sigmoid(x)\n", "        return x"]}, {"cell_type": "markdown", "metadata": {"_cell_guid": "d43f397b-6791-45ff-b8ab-e76337ffea84", "_uuid": "dcae54e479d7743fa87ae60e8a77498c9a2e1b03"}, "source": ["## Loss definition\n", "Use Soft Dice Loss"]}, {"cell_type": "code", "execution_count": null, "outputs": [], "metadata": {"_cell_guid": "bdfa3837-5a1d-46d9-8c38-c46385cf177d", "_uuid": "40bee47d4935d1b1b62549f6143378722435ee41", "collapsed": true}, "source": ["def soft_dice_loss(inputs, targets):\n", "        num = targets.size(0)\n", "        m1  = inputs.view(num,-1)\n", "        m2  = targets.view(num,-1)\n", "        intersection = (m1 * m2)\n", "        score = 2. * (intersection.sum(1)+1) / (m1.sum(1) + m2.sum(1)+1)\n", "        score = 1 - score.sum()/num\n", "        return score"]}, {"cell_type": "markdown", "metadata": {"_cell_guid": "620ac0ef-b09c-4c38-aa61-9454f80a3cb7", "_uuid": "e5c6f260e3cdbfb3c358c81cd784b34dd1f3598c"}, "source": ["## Train\n", "Train it within **1 minutes** with GPU"]}, {"cell_type": "code", "execution_count": null, "outputs": [], "metadata": {"_cell_guid": "c26c66a2-1b55-473f-998d-de504f4dfa54", "_uuid": "4fb7fcb768f95d0a9d040a0fe603719dbff398d1", "collapsed": true}, "source": ["model = UNet(3,1)#.cuda()\n", "optimizer = t.optim.Adam(model.parameters(),lr = 1e-3)\n", "\n", "for epoch in range(2):\n", "    for x_train, y_train  in tqdm(dataloader):\n", "        x_train = t.autograd.Variable(x_train)#.cuda())\n", "        y_train = t.autograd.Variable(y_train)#.cuda())\n", "        optimizer.zero_grad()\n", "        o = model(x_train)\n", "        loss = soft_dice_loss(o, y_train)\n", "        loss.backward()\n", "        optimizer.step()\n"]}, {"cell_type": "markdown", "metadata": {"_cell_guid": "3cf45631-629f-4fa1-bc3f-b9ad98a910e4", "_uuid": "c41bf60e0caaff4f85f65317e8d078ed5bd85d3a"}, "source": ["## Test"]}, {"cell_type": "code", "execution_count": null, "outputs": [], "metadata": {"_cell_guid": "5d02473f-c036-47d0-9806-475316630834", "_uuid": "2981c1384e42c8d74994e97408a3ce9019e9b1c5", "collapsed": true}, "source": ["class TestDataset():\n", "    def __init__(self,path,source_transform):\n", "        self.datas = t.load(path)\n", "        self.s_transform = source_transform\n", "    def __getitem__(self, index):\n", "        data = self.datas[index]\n", "        img = data['img'].numpy()\n", "        img = self.s_transform(img)\n", "        return img\n", "    def __len__(self):\n", "        return len(self.datas)\n", "\n", "testset = TestDataset(TEST_PATH, s_trans)\n", "testdataloader = t.utils.data.DataLoader(testset,num_workers=2,batch_size=2)"]}, {"cell_type": "code", "execution_count": null, "outputs": [], "metadata": {"_cell_guid": "2363ef81-3407-4c2b-8549-8fb5beff9aa8", "_uuid": "c796d469303fb5511f79199a3caaca2ebe5e3958", "collapsed": true}, "source": ["model = model.eval()\n", "for data in testdataloader:\n", "    data = t.autograd.Variable(data, volatile=True)#.cuda())\n", "    o = model(data)\n", "    break"]}, {"cell_type": "code", "execution_count": null, "outputs": [], "metadata": {"_cell_guid": "02ea6ca2-d28f-4b7d-b31c-43fb2bc317e3", "_uuid": "763b2b1747aec850e8c0de6e2b25da4d5476e7c1", "collapsed": true}, "source": ["tm=o[1][0].data.cpu().numpy()\n", "plt.subplot(121)\n", "plt.imshow(data[1].data.cpu().permute(1,2,0).numpy()*0.5+0.5)\n", "plt.subplot(122)\n", "plt.imshow(tm)"]}], "metadata": {"language_info": {"name": "python", "file_extension": ".py", "codemirror_mode": {"name": "ipython", "version": 3}, "mimetype": "text/x-python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.4"}, "kernelspec": {"name": "python3", "language": "python", "display_name": "Python 3"}}}