{"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 torch\nfrom torch import nn\nfrom torch import optim\nfrom torch.utils.tensorboard import SummaryWriter\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\n# import torchvision.transforms.functional as TF\n\nimport random\nimport os, shutil\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nfrom tqdm.auto import tqdm\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\n\nimport os\nfrom os.path import join\nimport matplotlib.pyplot as plt\nplt.rcParams.update({'font.size': 18})\nimport cv2\n\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader, Dataset, sampler\nfrom albumentations import (HorizontalFlip, VerticalFlip, ShiftScaleRotate, Normalize, Resize, Compose, GaussNoise)\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score, f1_score","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:43.121973Z","iopub.execute_input":"2021-11-25T14:22:43.122948Z","iopub.status.idle":"2021-11-25T14:22:47.099925Z","shell.execute_reply.started":"2021-11-25T14:22:43.122846Z","shell.execute_reply":"2021-11-25T14:22:47.099161Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_train = pd.read_csv('../input/sartorius-cell-instance-segmentation/train.csv')","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:47.101410Z","iopub.execute_input":"2021-11-25T14:22:47.101667Z","iopub.status.idle":"2021-11-25T14:22:47.626694Z","shell.execute_reply.started":"2021-11-25T14:22:47.101629Z","shell.execute_reply":"2021-11-25T14:22:47.625831Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torchvision.models import resnet34, resnet152, resnet50, resnet101","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:47.628550Z","iopub.execute_input":"2021-11-25T14:22:47.628961Z","iopub.status.idle":"2021-11-25T14:22:47.632773Z","shell.execute_reply.started":"2021-11-25T14:22:47.628924Z","shell.execute_reply":"2021-11-25T14:22:47.632104Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_net():\n    n = resnet50(True)\n    n.fc = nn.Linear(2048, 65)\n    return n","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:47.634758Z","iopub.execute_input":"2021-11-25T14:22:47.635153Z","iopub.status.idle":"2021-11-25T14:22:47.643305Z","shell.execute_reply.started":"2021-11-25T14:22:47.635119Z","shell.execute_reply":"2021-11-25T14:22:47.642245Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_train.head()","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:47.644524Z","iopub.execute_input":"2021-11-25T14:22:47.644906Z","iopub.status.idle":"2021-11-25T14:22:47.669732Z","shell.execute_reply.started":"2021-11-25T14:22:47.644873Z","shell.execute_reply":"2021-11-25T14:22:47.669100Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def imshow(num_to_show=9):\n    \n    plt.figure(figsize=(20,20))\n    \n    for i in range(num_to_show):\n        plt.subplot(3, 3, i+1)\n        plt.grid(False)\n        plt.xticks([])\n        plt.yticks([])\n        \n        img = mpimg.imread(f'../input/sartorius-cell-instance-segmentation/train/{data_train.iloc[i,0]}.png')\n        plt.imshow(img, cmap='plasma')\n\nimshow()","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:47.671405Z","iopub.execute_input":"2021-11-25T14:22:47.671797Z","iopub.status.idle":"2021-11-25T14:22:48.814182Z","shell.execute_reply.started":"2021-11-25T14:22:47.671763Z","shell.execute_reply":"2021-11-25T14:22:48.813392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DATA_PATH = '../input/sartorius-cell-instance-segmentation'\nSAMPLE_SUBMISSION = join(DATA_PATH,'train')\nTRAIN_CSV = join(DATA_PATH,'train.csv')\nTRAIN_PATH = join(DATA_PATH,'train')\nTEST_PATH = join(DATA_PATH,'test')\n\ndf_train = pd.read_csv(TRAIN_CSV)\nprint(f'Training Set Shape: {df_train.shape} - {df_train[\"id\"].nunique()} \\\nImages - Memory Usage: {df_train.memory_usage().sum() / 1024 ** 2:.2f} MB')","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:48.815274Z","iopub.execute_input":"2021-11-25T14:22:48.815532Z","iopub.status.idle":"2021-11-25T14:22:49.127256Z","shell.execute_reply.started":"2021-11-25T14:22:48.815499Z","shell.execute_reply":"2021-11-25T14:22:49.126278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def rle_decode(mask_rle, shape, color=1):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (height,width) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n\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.float32)\n    for lo, hi in zip(starts, ends):\n        img[lo : hi] = color\n    return img.reshape(shape)\n\ndef build_masks(df_train, image_id, input_shape):\n    height, width = input_shape\n    labels = df_train[df_train[\"id\"] == image_id][\"annotation\"].tolist()\n    mask = np.zeros((height, width))\n    for label in labels:\n        mask += rle_decode(label, shape=(height, width))\n    mask = mask.clip(0, 1)\n    return np.array(mask)","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:49.129072Z","iopub.execute_input":"2021-11-25T14:22:49.129387Z","iopub.status.idle":"2021-11-25T14:22:49.139742Z","shell.execute_reply.started":"2021-11-25T14:22:49.129347Z","shell.execute_reply":"2021-11-25T14:22:49.138623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CellDataset(Dataset):\n    def __init__(self, df: pd.core.frame.DataFrame, train:bool):\n        self.IMAGE_RESIZE = (224, 224)\n        self.RESNET_MEAN = (0.485, 0.456, 0.406)\n        self.RESNET_STD = (0.229, 0.224, 0.225)\n        self.df = df\n        self.base_path = TRAIN_PATH\n        self.gb = self.df.groupby('id')\n        self.transforms = Compose([Resize( self.IMAGE_RESIZE[0],  self.IMAGE_RESIZE[1]), \n                                   Normalize(mean=self.RESNET_MEAN, std= self.RESNET_STD, p=1), \n                                   HorizontalFlip(p=0.5),\n                                   VerticalFlip(p=0.5)])\n        \n        # Split train and val set\n        all_image_ids = np.array(df_train.id.unique())\n        np.random.seed(42)\n        iperm = np.random.permutation(len(all_image_ids))\n        num_train_samples = int(len(all_image_ids) * 0.9)\n\n        if train:\n            self.image_ids = all_image_ids[iperm[:num_train_samples]]\n        else:\n             self.image_ids = all_image_ids[iperm[num_train_samples:]]\n\n    def __getitem__(self, idx: int) -> dict:\n\n        image_id = self.image_ids[idx]\n        df = self.gb.get_group(image_id)\n\n        # Read image\n        image_path = os.path.join(self.base_path, image_id + \".png\")\n        image = cv2.imread(image_path)\n\n        # Create the mask\n        mask = build_masks(df_train, image_id, input_shape=(520, 704))\n        mask = (mask >= 1).astype('float32')\n        augmented = self.transforms(image=image, mask=mask)\n        image = augmented['image']\n        mask = augmented['mask']\n        # print(np.moveaxis(image,0,2).shape)\n        return np.moveaxis(np.array(image),2,0), mask.reshape((1, self.IMAGE_RESIZE[0], self.IMAGE_RESIZE[1]))\n\n\n    def __len__(self):\n        return len(self.image_ids)","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:49.141892Z","iopub.execute_input":"2021-11-25T14:22:49.142194Z","iopub.status.idle":"2021-11-25T14:22:49.160536Z","shell.execute_reply.started":"2021-11-25T14:22:49.142156Z","shell.execute_reply":"2021-11-25T14:22:49.159802Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ds_train = CellDataset(df_train, train = True)\ndl_train = DataLoader(ds_train, batch_size = 16,\n                     num_workers = 2, pin_memory = True,\n                     shuffle = False)","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:49.165275Z","iopub.execute_input":"2021-11-25T14:22:49.165591Z","iopub.status.idle":"2021-11-25T14:22:49.179715Z","shell.execute_reply.started":"2021-11-25T14:22:49.165547Z","shell.execute_reply":"2021-11-25T14:22:49.178886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ds_test = CellDataset(df_train, train =  False)\ndl_test = DataLoader(ds_test, batch_size = 4, \n                    num_workers = 2, pin_memory = True,\n                    shuffle = False)","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:49.181124Z","iopub.execute_input":"2021-11-25T14:22:49.181546Z","iopub.status.idle":"2021-11-25T14:22:49.193502Z","shell.execute_reply.started":"2021-11-25T14:22:49.181508Z","shell.execute_reply":"2021-11-25T14:22:49.192613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualization of the images and masks","metadata":{}},{"cell_type":"code","source":"# plot simages and mask from dataloader\nbatch = next(iter(dl_train))\nimages, masks = batch\nprint(f\"image shape: {images.shape},\\nmask shape:{masks.shape},\\nbatch len: {len(batch)}\")\n\nplt.figure(figsize=(20, 20))\n        \nplt.subplot(1, 3, 1)\nplt.xticks([])\nplt.yticks([])\nplt.imshow(images[1][1])\nplt.title('Original image')\n\nplt.subplot( 1, 3, 2)\nplt.xticks([])\nplt.yticks([])\nplt.imshow(masks[1][0])\nplt.title('Mask')\n\nplt.subplot( 1, 3, 3)\nplt.xticks([])\nplt.yticks([])\nplt.imshow(images[1][1])\nplt.imshow(masks[1][0],alpha=0.2)\nplt.title('Both')\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:49.194950Z","iopub.execute_input":"2021-11-25T14:22:49.195218Z","iopub.status.idle":"2021-11-25T14:22:57.130120Z","shell.execute_reply.started":"2021-11-25T14:22:49.195183Z","shell.execute_reply":"2021-11-25T14:22:57.129469Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DoubleConv(nn.Module):\n    def __init__(self, in_ch, out_ch):\n        super(DoubleConv, self).__init__()\n        self.conv = nn.Sequential( \n            nn.Conv2d(in_ch, out_ch, kernel_size=3, stride=1, padding=1),\n            nn.BatchNorm2d(out_ch),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(out_ch, out_ch, kernel_size=3, stride=1, padding=1),\n            nn.BatchNorm2d(out_ch),\n            nn.ReLU(inplace=True)\n         )\n    def forward(self, x):\n        x = self.conv(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:57.131519Z","iopub.execute_input":"2021-11-25T14:22:57.131919Z","iopub.status.idle":"2021-11-25T14:22:57.140227Z","shell.execute_reply.started":"2021-11-25T14:22:57.131882Z","shell.execute_reply":"2021-11-25T14:22:57.138981Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class InConv(nn.Module):\n    def __init__(self, in_ch, out_ch):\n        super(InConv, self).__init__()\n        self.conv = DoubleConv(in_ch, out_ch)\n    def forward(self, x):\n        x = self.conv(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:57.141543Z","iopub.execute_input":"2021-11-25T14:22:57.142483Z","iopub.status.idle":"2021-11-25T14:22:57.150990Z","shell.execute_reply.started":"2021-11-25T14:22:57.142445Z","shell.execute_reply":"2021-11-25T14:22:57.150249Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"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,2),\n            DoubleConv(in_ch, out_ch)\n         )\n    def forward(self, x):\n        x = self.mpconv(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:57.152367Z","iopub.execute_input":"2021-11-25T14:22:57.153169Z","iopub.status.idle":"2021-11-25T14:22:57.160351Z","shell.execute_reply.started":"2021-11-25T14:22:57.153059Z","shell.execute_reply":"2021-11-25T14:22:57.159604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Up(nn.Module):\n    def __init__(self, in_ch, out_ch):\n        super(Up, self).__init__()\n        self.up = nn.ConvTranspose2d(in_ch // 2, in_ch // 2, kernel_size=2, stride=2)\n        self.conv = DoubleConv(in_ch, out_ch)\n    def forward(self, x1, x2):\n        x1 = self.up(x1)\n        x = torch.cat([x2, x1], dim=1)\n        x = self.conv(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:57.161769Z","iopub.execute_input":"2021-11-25T14:22:57.162397Z","iopub.status.idle":"2021-11-25T14:22:57.169970Z","shell.execute_reply.started":"2021-11-25T14:22:57.162363Z","shell.execute_reply":"2021-11-25T14:22:57.169317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"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        self.sigmoid = nn.Sigmoid()\n    def forward(self, x):\n        x = self.conv(x)\n        x = self.sigmoid(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:22:57.172285Z","iopub.execute_input":"2021-11-25T14:22:57.172797Z","iopub.status.idle":"2021-11-25T14:22:57.181689Z","shell.execute_reply.started":"2021-11-25T14:22:57.172761Z","shell.execute_reply":"2021-11-25T14:22:57.180860Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class UNet(nn.Module):\n    def __init__(self, in_channels, num_classes):\n        super(UNet, self).__init__()\n        self.inc = InConv(in_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, num_classes)\n    def forward(self, x):\n        # print(x.shape)\n        x1 = self.inc(x)\n        # print(x1.shape)\n        x2 = self.down1(x1)\n        # print(x2.shape)\n        x3 = self.down2(x2)\n        # print(x3.shape)\n        x4 = self.down3(x3)\n        # print(x4.shape)\n        x5 = self.down4(x4)\n        # print(x5.shape)\n        # print('up')\n        x = self.up1(x5, x4)\n        # print(x.shape)\n        x = self.up2(x, x3)\n        # print(x.shape)\n        x = self.up3(x, x2)\n        # print(x.shape)\n        x = self.up4(x, x1)\n        # print(x.shape)\n        x = self.outc(x)\n        # print(x.shape)\n        return x","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:24:44.298254Z","iopub.execute_input":"2021-11-25T14:24:44.298853Z","iopub.status.idle":"2021-11-25T14:24:44.310023Z","shell.execute_reply.started":"2021-11-25T14:24:44.298804Z","shell.execute_reply":"2021-11-25T14:24:44.309244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:24:45.961787Z","iopub.execute_input":"2021-11-25T14:24:45.962092Z","iopub.status.idle":"2021-11-25T14:24:45.970587Z","shell.execute_reply.started":"2021-11-25T14:24:45.962058Z","shell.execute_reply":"2021-11-25T14:24:45.969895Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_loop(model, optimizer, criterion, train_loader, device=device):\n    running_loss = 0\n    model.train()\n    pbar = tqdm(train_loader, desc='Iterating over train data')\n    for imgs, masks in pbar:\n        # pass to device\n        imgs = imgs.to(device)\n        masks = masks.to(device)\n        # forward\n        out = model(imgs)\n        loss = criterion(out, masks)\n        running_loss += loss.item()*imgs.shape[0]  # += loss * current batch size\n        # optimize\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n    running_loss /= len(train_loader.sampler)\n    return running_loss","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:24:46.642381Z","iopub.execute_input":"2021-11-25T14:24:46.642768Z","iopub.status.idle":"2021-11-25T14:24:46.649732Z","shell.execute_reply.started":"2021-11-25T14:24:46.642732Z","shell.execute_reply":"2021-11-25T14:24:46.648467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def eval_loop(model, criterion, eval_loader, device=device):\n    running_loss = 0\n    model.eval()\n    with torch.no_grad():\n        accuracy, f1_scores = [], []\n        pbar = tqdm(eval_loader, desc='Iterating over evaluation data')\n        for imgs, masks in pbar:\n            # pass to device\n            imgs = imgs.to(device)\n            masks = masks.to(device)\n            # forward\n            out = model(imgs)\n            loss = criterion(out, masks)\n            running_loss += loss.item()*imgs.shape[0]\n            # calculate predictions using output\n            predicted = (out > 0.5).float()\n            predicted = predicted.view(-1).cpu().numpy()\n            labels = masks.view(-1).cpu().numpy()\n            accuracy.append(accuracy_score(labels, predicted))\n            f1_scores.append(f1_score(labels, predicted))\n    acc = sum(accuracy)/len(accuracy)\n    f1 = sum(f1_scores)/len(f1_scores)\n    running_loss /= len(eval_loader.sampler)\n    return {\n        'accuracy':acc,\n        'f1_macro':f1, \n        'loss':running_loss}","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:24:48.995311Z","iopub.execute_input":"2021-11-25T14:24:48.995857Z","iopub.status.idle":"2021-11-25T14:24:49.007619Z","shell.execute_reply.started":"2021-11-25T14:24:48.995817Z","shell.execute_reply":"2021-11-25T14:24:49.006425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train(model, optimizer, criterion, train_loader, valid_loader,\n          device=device, \n          num_epochs=30, \n          valid_loss_min=np.inf,\n          logdir='logdir'):\n    \n    tb_writer = SummaryWriter(log_dir=logdir)\n    for e in range(num_epochs):\n        # train for epoch\n        train_loss = train_loop(\n            model, optimizer, criterion, train_loader, device=device)\n        # evaluate on validation set\n        metrics = eval_loop(\n            model, criterion, valid_loader, device=device\n        )\n        # show progress\n        print_string = f'Epoch: {e+1} '\n        print_string+= f'TrainLoss: {train_loss:.5f} '\n        print_string+= f'ValidLoss: {metrics[\"loss\"]:.5f} '\n        print_string+= f'ACC: {metrics[\"accuracy\"]:.5f} '\n        print_string+= f'F1: {metrics[\"f1_macro\"]:.3f}'\n        print(print_string)\n\n        # Tensorboards Logging\n        tb_writer.add_scalar('UNet/Train Loss', train_loss, e)\n        tb_writer.add_scalar('UNet/Valid Loss', metrics[\"loss\"], e)\n        tb_writer.add_scalar('UNet/Accuracy', metrics[\"accuracy\"], e)\n        tb_writer.add_scalar('UNet/F1 Macro', metrics[\"f1_macro\"], e)\n\n        # save the model \n        if metrics[\"loss\"] <= valid_loss_min:\n            torch.save(model.state_dict(), 'UNet.pt')\n            valid_loss_min = metrics[\"loss\"]","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:24:49.703778Z","iopub.execute_input":"2021-11-25T14:24:49.704303Z","iopub.status.idle":"2021-11-25T14:24:49.712547Z","shell.execute_reply.started":"2021-11-25T14:24:49.704267Z","shell.execute_reply":"2021-11-25T14:24:49.711434Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# set_seed(21)\nmodel = UNet(3, 1).to(device)\noptimizer = optim.Adam(model.parameters(), lr=0.001)\ncriterion = nn.BCELoss()\ntrain(model, optimizer, criterion, dl_train, dl_test)","metadata":{"execution":{"iopub.status.busy":"2021-11-25T14:24:50.557704Z","iopub.execute_input":"2021-11-25T14:24:50.558286Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.load_state_dict(torch.load('UNet.pt'))\nmetrics = eval_loop(model, criterion, dl_test)\nprint('accuracy:', metrics['accuracy'])\nprint('f1 macro:', metrics['f1_macro'])\nprint('test loss:', metrics['loss'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}