{"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":"## Overview","metadata":{"_uuid":"1b8c18e1d49e580b84b194084a08d59e2a497b54"}},{"cell_type":"code","source":"from fastai.conv_learner import *\nfrom fastai.dataset import *\n\nimport pandas as pd\nimport numpy as np\nimport os\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Data + Pretrained code","metadata":{"_uuid":"ddd71a95c05902b29ce4e3768a8127c2a0b7098d"}},{"cell_type":"code","source":"PATH = './'\nTRAIN = '../input/airbus-ship-detection/train_v2/'\nTEST = '../input/airbus-ship-detection/test_v2/'\nSEGMENTATION = '../input/airbus-ship-detection/train_ship_segmentations_v2.csv'\n# PRETRAINED = '../input/fine-tuning-resnet34-on-ship-detection/models/Resnet34_lable_256_1.h5'\nexclude_list = ['6384c3e78.jpg','13703f040.jpg', '14715c06d.jpg',  '33e0ff2d5.jpg',\n                '4d4e09f2a.jpg', '877691df8.jpg', '8b909bb20.jpg', 'a8d99130e.jpg', \n                'ad55c3143.jpg', 'c8260c541.jpg', 'd6c7f17c7.jpg', 'dc3e7c901.jpg',\n                'e44dffe88.jpg', 'ef87bad36.jpg', 'f083256d8.jpg'] #corrupted images","metadata":{"_uuid":"b93d5422dfd31f43df9cdd3e301547cc95f25980","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tr_arr = np.array(pd.read_csv('../input/traintestval-airbus/train_df.csv')['0'].reset_index(drop=True))\nval_arr = np.array(pd.read_csv('../input/traintestval-airbus/val_df.csv')['0'].reset_index(drop=True))\ntest_arr = np.array(pd.read_csv('../input/traintestval-airbus/test_df.csv')['0'].reset_index(drop=True))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"nw = 2   #number of workers for data loader\narch = resnet34 #specify target architecture","metadata":{"_uuid":"9a72e076dc04cf1786edae26a1d2f15ec3de234a","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for el in exclude_list:\n    if(el in tr_arr): tr_arr.remove(el)\n    if(el in val_arr): val_arr.remove(el)\n    if(el in test_arr): test_arr.remove(el)\nsegmentation_df = pd.read_csv(os.path.join(PATH, SEGMENTATION)).set_index('ImageId')","metadata":{"_uuid":"49199ea17e9e9ba9893c10d06c1fb419e22aeb1b","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tr_n = tr_arr\nval_n = val_arr\ntest_n = test_arr","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def cut_empty(names):\n    return [name for name in names \n            if(type(segmentation_df.loc[name]['EncodedPixels']) != float)]\n\ntr_n = cut_empty(tr_n)\nval_n = cut_empty(val_n)","metadata":{"_uuid":"6a3d8c70e03964738322ca99084f088adc1c5f3e","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"total_n = tr_n + val_n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_mask(img_id, df):\n    shape = (768,768)\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    masks = df.loc[img_id]['EncodedPixels']\n    if(type(masks) == float): return img.reshape(shape)\n    if(type(masks) == str): masks = [masks]\n    for mask in masks:\n        s = mask.split()\n        for i in range(len(s)//2):\n            start = int(s[2*i]) - 1\n            length = int(s[2*i+1])\n            img[start:start+length] = 1\n    return img.reshape(shape).T\n\ndef Show_images(x,yp,yt):\n    columns = 3\n    rows = min(bs,8)\n    fig=plt.figure(figsize=(columns*4, rows*4))\n    for i in range(rows):\n        fig.add_subplot(rows, columns, 3*i+1)\n        plt.axis('off')\n        plt.imshow(x[i])\n        fig.add_subplot(rows, columns, 3*i+2)\n        plt.axis('off')\n        plt.imshow(yp[i])\n        fig.add_subplot(rows, columns, 3*i+3)\n        plt.axis('off')\n        plt.imshow(yt[i])\n    plt.show()","metadata":{"_uuid":"505f803555b8d9d0378a73d227da4b8174f2086d","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class pdFilesDataset(FilesDataset):\n    def __init__(self, fnames, path, transform):\n        self.segmentation_df = pd.read_csv(SEGMENTATION).set_index('ImageId')\n        super().__init__(fnames, transform, path)\n    \n    def get_x(self, i):\n        img = open_image(os.path.join(self.path, self.fnames[i]))\n        if self.sz == 768: return img \n        else: return cv2.resize(img, (self.sz, self.sz))\n    \n    def get_y(self, i):\n        mask = np.zeros((768,768), dtype=np.uint8) if (self.path == TEST) \\\n            else get_mask(self.fnames[i], self.segmentation_df)\n        img = Image.fromarray(mask).resize((self.sz, self.sz)).convert('RGB')\n        return np.array(img).astype(np.float32)\n    \n    def get_c(self): return 0\n     \n\ndef get_data(sz,bs):\n    #data augmentation\n    aug_tfms = [RandomRotate(45,p=0.75, tfm_y=TfmType.CLASS)]\n    tfms = tfms_from_model(arch, sz, crop_type=CropType.NO, tfm_y=TfmType.CLASS,aug_tfms=aug_tfms)\n    tr_names = tr_n if (len(tr_n)%bs == 0) else tr_n[:-(len(tr_n)%bs)] #cut incomplete batch\n    ds = ImageData.get_ds(pdFilesDataset, (tr_names,TRAIN), (val_n,TRAIN), tfms, test=(test_n,TRAIN))\n    md = ImageData(PATH, ds, bs, num_workers=nw, classes=None)\n    #md.is_multi = False\n    return md\n\ndef get_data_no_aug(sz,bs):\n    #data augmentation\n    tfms = tfms_from_model(arch, sz, crop_type=CropType.NO, tfm_y=TfmType.CLASS)\n    tr_names = tr_n if (len(tr_n)%bs == 0) else tr_n[:-(len(tr_n)%bs)] #cut incomplete batch\n    ds = ImageData.get_ds(pdFilesDataset, (tr_names,TRAIN), (val_n,TRAIN), tfms, test=(test_n,TRAIN))\n    md = ImageData(PATH, ds, bs, num_workers=nw, classes=None)\n    #md.is_multi = False\n    return md","metadata":{"_uuid":"f67a326e1269bffca392fcf4ac10bf4a532ca56b","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model","metadata":{"_uuid":"2b77a79e1e1e3f4c8a9e7120feb9a843b41492f8","trusted":true}},{"cell_type":"code","source":"cut,lr_cut = model_meta[arch]","metadata":{"_uuid":"5bfefb757e1d40da7d8761c824170214a4bec08b","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_base():                   #load ResNet34 model\n    layers = cut_model(arch(True), cut)\n    return nn.Sequential(*layers)","metadata":{"_uuid":"7b0649b17721919f475a99f41f47f09c4fcc41d6","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class UnetBlock(nn.Module):\n    def __init__(self, up_in, x_in, n_out):\n        super().__init__()\n        up_out = x_out = n_out//2\n        self.x_conv  = nn.Conv2d(x_in,  x_out,  1)\n        self.tr_conv = nn.ConvTranspose2d(up_in, up_out, 2, stride=2)\n        self.bn = nn.BatchNorm2d(n_out)\n        \n    def forward(self, up_p, x_p):\n        up_p = self.tr_conv(up_p)\n        x_p = self.x_conv(x_p)\n        cat_p = torch.cat([up_p,x_p], dim=1)\n        return self.bn(F.relu(cat_p))\n\nclass SaveFeatures():\n    features=None\n    def __init__(self, m): self.hook = m.register_forward_hook(self.hook_fn)\n    def hook_fn(self, module, input, output): self.features = output\n    def remove(self): self.hook.remove()\n    \nclass Unet34(nn.Module):\n    def __init__(self, rn):\n        super().__init__()\n        self.rn = rn\n        self.sfs = [SaveFeatures(rn[i]) for i in [2,4,5,6]]\n        self.up1 = UnetBlock(512,256,256)\n        self.up2 = UnetBlock(256,128,256)\n        self.up3 = UnetBlock(256,64,256)\n        self.up4 = UnetBlock(256,64,256)\n        self.up5 = nn.ConvTranspose2d(256, 1, 2, stride=2)\n        \n    def forward(self,x):\n        x = F.relu(self.rn(x))\n        x = self.up1(x, self.sfs[3].features)\n        x = self.up2(x, self.sfs[2].features)\n        x = self.up3(x, self.sfs[1].features)\n        x = self.up4(x, self.sfs[0].features)\n        x = self.up5(x)\n        return x[:,0]\n    \n    def close(self):\n        for sf in self.sfs: sf.remove()\n            \nclass UnetModel():\n    def __init__(self,model,name='Unet'):\n        self.model,self.name = model,name\n\n    def get_layer_groups(self, precompute):\n        lgs = list(split_by_idxs(children(self.model.rn), [lr_cut]))\n        return lgs + [children(self.model)[1:]]","metadata":{"_uuid":"77ca73006aec0c9dfe4be6deb2d6cf524840cd62","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Loss function","metadata":{"_uuid":"9c71a3af2a83b1122902a3f39e6fda1af5afbb99","trusted":true}},{"cell_type":"code","source":"def dice_loss(input, target):\n    input = torch.sigmoid(input)\n    smooth = 1.0\n\n    iflat = input.view(-1)\n    tflat = target.view(-1)\n    intersection = (iflat * tflat).sum()\n    \n    return ((2.0 * intersection + smooth) / (iflat.sum() + tflat.sum() + smooth))","metadata":{"_uuid":"8de4222fd28596dbae5d55f8172ac28271f678f2","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class FocalLoss(nn.Module):\n    def __init__(self, gamma):\n        super().__init__()\n        self.gamma = gamma\n        \n    def forward(self, input, target):\n        if not (target.size() == input.size()):\n            raise ValueError(\"Target size ({}) must be the same as input size ({})\"\n                             .format(target.size(), input.size()))\n\n        max_val = (-input).clamp(min=0)\n        loss = input - input * target + max_val + \\\n            ((-max_val).exp() + (-input - max_val).exp()).log()\n\n        invprobs = F.logsigmoid(-input * (target * 2.0 - 1.0))\n        loss = (invprobs * self.gamma).exp() * loss\n        \n        return loss.mean()","metadata":{"_uuid":"456acf8ffe7b80cd94eb73bfaeb6b1061bbb44c7","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MixedLoss(nn.Module):\n    def __init__(self, alpha, gamma):\n        super().__init__()\n        self.alpha = alpha\n        self.focal = FocalLoss(gamma)\n        \n    def forward(self, input, target):\n        loss = self.alpha*self.focal(input, target) - torch.log(dice_loss(input, target))\n        return loss.mean()","metadata":{"_uuid":"1cfb00a50821861c69534ee7398bd220c02900d8","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def dice(pred, targs):\n    pred = (pred>0).float()\n    return 2.0 * (pred*targs).sum() / ((pred+targs).sum() + 1.0)\n\ndef IoU(pred, targs):\n    pred = (pred>0).float()\n    intersection = (pred*targs).sum()\n    return intersection / ((pred+targs).sum() - intersection + 1.0)","metadata":{"_uuid":"37baddf38bb569cbf2d2f186a5171767402b94fa","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train Augmented Learner","metadata":{"_uuid":"0b3a20e5e2fdedf1439737f40c14c78f9a69e29a"}},{"cell_type":"code","source":"sz = 768 #image size\nbs = 8  #batch size\n\nmd = get_data(sz,bs)\nno_aug_md = get_data_no_aug(sz,bs)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"m_base = get_base()\nstate = torch.load('../input/traintestval-airbus/Unet34_768_aug_0.h5')\nm_base.load_state_dict(state, strict=False)\n\nm = to_gpu(Unet34(m_base))\nmodels = UnetModel(m)","metadata":{"_uuid":"1a3b8f6b454a8d8b48505fbc5964e900a59ef09e","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn = ConvLearner(md, models)\nlearn.opt_fn=optim.Adam\nlearn.crit = MixedLoss(10.0, 2.0)\nlearn.metrics=[accuracy_thresh(0.5),dice,IoU]\nwd=1e-7\nlr = 1e-2","metadata":{"_uuid":"eb1016214b0de75f56d2036241a27684b4c4bd1b","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.freeze_to(1)\nlearn.fit(lr,1,wds=wd,cycle_len=1,use_clr=(5,8))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.save('Unet34_768_aug_0')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":" The lr of the head part is still 1e-3, while the middle layers of the model are trained with 1e-4 lr, and the base is trained with even smaller lr, 1e-5, since low level detectors do not vary much from one image data set to another.","metadata":{}},{"cell_type":"code","source":"# Unfreeze and train with differential learning rate\nlrs = np.array([lr/100,lr/10,lr])\nlearn.unfreeze() #unfreeze the encoder\nlearn.bn_freeze(True)\n\nlearn.fit(lrs,2,wds=wd,cycle_len=1,use_clr=(20,8))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.sched.plot_lr()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.save('Unet34_768_aug_1')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training non-augmented learner","metadata":{}},{"cell_type":"code","source":"sz = 768 #image size\nbs = 8  #batch size\n\nno_aug_md = get_data_no_aug(sz,bs)\n\nm_base = get_base()\nstate_na = torch.load('../input/traintestval-airbus/Unet34_768_no_aug_0.h5')\nm_base.load_state_dict(state_na, strict=False)\nm = to_gpu(Unet34(m_base))\n\nlearn_na = ConvLearner(no_aug_md, models)\nlearn_na.opt_fn=optim.Adam\nlearn_na.crit = MixedLoss(10.0, 2.0)\nlearn_na.metrics=[accuracy_thresh(0.5),dice,IoU]\nwd=1e-7\nlr = 1e-2","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Deprecated\nlearn_na.freeze_to(1)\nlearn_na.fit(lr,1,wds=wd,cycle_len=1,use_clr=(5,8))\nlearn_na.save('Unet34_768_no_aug_0')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Unfreeze and train with differential learning rate\nlrs = np.array([lr/100,lr/10,lr])\nlearn_na.unfreeze() #unfreeze the encoder\nlearn_na.bn_freeze(True)\n\nlearn_na.fit(lrs,2,wds=wd,cycle_len=1,use_clr=(20,8))\n\nlearn_na.save('Unet34_768_no_aug_1')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualization","metadata":{"_uuid":"a5f92ae7e3e348f95129a3742ad76e4a502bf6d1"}},{"cell_type":"code","source":"def Show_images(x,yp,yt):\n    columns = 3\n    rows = min(bs,8)\n    fig=plt.figure(figsize=(columns*4, rows*4))\n    for i in range(rows):\n        fig.add_subplot(rows, columns, 3*i+1)\n        plt.axis('off')\n        plt.imshow(x[i])\n        fig.add_subplot(rows, columns, 3*i+2)\n        plt.axis('off')\n        plt.imshow(yp[i])\n        fig.add_subplot(rows, columns, 3*i+3)\n        plt.axis('off')\n        plt.imshow(yt[i])\n    plt.show()\n    \n    \ndef Show_images(x,y,x1,y1):\n    columns = 4\n    rows = min(bs,8)\n    fig=plt.figure(figsize=(columns*4, rows*4))\n    for i in range(rows):\n        fig.add_subplot(rows, columns, 4*i+1)\n        plt.axis('off')\n        plt.imshow(x[i])\n        fig.add_subplot(rows, columns, 4*i+2)\n        plt.axis('off')\n        plt.imshow(y[i])\n        fig.add_subplot(rows, columns, 4*i+3)\n        plt.axis('off')\n        plt.imshow(x1[i])\n        fig.add_subplot(rows, columns, 4*i+4)\n        plt.axis('off')\n        plt.imshow(y1[i])\n    plt.show()","metadata":{"_uuid":"fb4a8386560ebde1f2277d94ecb5ee4a1bbc50d2","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sz = 768 #image size\nbs = 8  #batch size\n\nmd = get_data(sz,bs)\nno_aug_md = get_data_no_aug(sz,bs)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x,y= md[0].trn_ds[2]\nox,oy = md[1].trn_ds[2]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(md[0].trn_ds.denorm(x)[0])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(y)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(md[1].trn_ds.denorm(ox)[0])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(oy)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}