{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"name":"unet_pytorch.ipynb","varInspector":{"cols":{"lenName":16,"lenType":16,"lenVar":40},"kernels_config":{"python":{"delete_cmd_postfix":"","delete_cmd_prefix":"del ","library":"var_list.py","varRefreshCmd":"print(var_dic_list())"},"r":{"delete_cmd_postfix":") ","delete_cmd_prefix":"rm(","library":"var_list.r","varRefreshCmd":"cat(var_dic_list()) "}},"types_to_exclude":["module","function","builtin_function_or_method","instance","_Feature"],"window_display":false},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":9988,"databundleVersionId":868324,"sourceType":"competition"}],"dockerImageVersionId":12836,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install flask==0.12.2\n!pip install Flask\n!pip install flask-ngrok","metadata":{"execution":{"iopub.status.busy":"2024-07-03T10:18:52.877763Z","iopub.execute_input":"2024-07-03T10:18:52.878069Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install langchain","metadata":{"execution":{"iopub.status.busy":"2024-07-03T10:16:02.698021Z","iopub.execute_input":"2024-07-03T10:16:02.698365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(flask-ngrok.__version__)","metadata":{"execution":{"iopub.status.busy":"2024-07-03T10:13:57.989910Z","iopub.execute_input":"2024-07-03T10:13:57.990211Z","iopub.status.idle":"2024-07-03T10:13:58.088760Z","shell.execute_reply.started":"2024-07-03T10:13:57.990166Z","shell.execute_reply":"2024-07-03T10:13:58.087449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport random\nimport shutil\n\nfrom multiprocessing.dummy import Pool\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nfrom PIL import Image\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.externals import joblib\n\nfrom skimage.morphology import binary_opening, disk, label\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nfrom torch.autograd import Variable\nfrom torch.utils.data import DataLoader, Dataset\n\nimport torchvision.transforms as transforms","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"7dd476b71131c51c0392ebcd09843bf3c4de4313","execution":{"iopub.status.busy":"2024-07-03T10:12:50.597211Z","iopub.execute_input":"2024-07-03T10:12:50.597534Z","iopub.status.idle":"2024-07-03T10:12:51.520806Z","shell.execute_reply.started":"2024-07-03T10:12:50.597475Z","shell.execute_reply":"2024-07-03T10:12:51.520173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%matplotlib inline","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"13428284fe657373fa036d52f6e9e78aba3d141a","execution":{"iopub.status.busy":"2024-07-03T10:12:51.523021Z","iopub.execute_input":"2024-07-03T10:12:51.523253Z","iopub.status.idle":"2024-07-03T10:12:51.531688Z","shell.execute_reply.started":"2024-07-03T10:12:51.523214Z","shell.execute_reply":"2024-07-03T10:12:51.531040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dpath = '../input/train_v2/'\ntest_dpath = '../input/test_v2/'\n\nanno_fpath = '../input/train_ship_segmentations_v2.csv'\nbst_model_fpath = 'model/bst_unet.model'\n\nsample_submission_fpath = '../input/sample_submission_v2.csv'\nsubmission_fpath = 'submission_1.csv'\n\n\noriginal_img_size = (768, 768)","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"5144bc9049d81ecfc54d7dc9540391080f069a38","execution":{"iopub.status.busy":"2024-07-03T10:12:51.534076Z","iopub.execute_input":"2024-07-03T10:12:51.534314Z","iopub.status.idle":"2024-07-03T10:12:51.539738Z","shell.execute_reply.started":"2024-07-03T10:12:51.534267Z","shell.execute_reply":"2024-07-03T10:12:51.538976Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"annos = pd.read_csv(anno_fpath)\nannos.to_csv(\"/kaggle/working/adveat.csv\", index=False)\nannos.head()","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"bffb8dfe8377ddbcb12d7bed539c63f024c9e3bc","execution":{"iopub.status.busy":"2024-07-03T10:12:51.540526Z","iopub.execute_input":"2024-07-03T10:12:51.540787Z","iopub.status.idle":"2024-07-03T10:12:55.178494Z","shell.execute_reply.started":"2024-07-03T10:12:51.540745Z","shell.execute_reply":"2024-07-03T10:12:55.177721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"_uuid":"2a28eb113573332ba23b5035491801f57147f4ae","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Split data","metadata":{"_uuid":"1f5cc6f8f6a84bc85338588ebebaef88f3458a74"}},{"cell_type":"markdown","source":"###### Balance","metadata":{"_uuid":"4190d22a2fd7fd7583eaaf39ef7ccb0dd13e16f5"}},{"cell_type":"code","source":"annos['EncodedPixels_flag'] = annos['EncodedPixels'].map(lambda v: 1 if isinstance(v, str) else 0)\nimgs = annos.groupby('ImageId').agg({'EncodedPixels_flag': 'sum'}).reset_index().rename(columns={'EncodedPixels_flag': 'ships'})\n\nimgs_w_ships = imgs[imgs['ships'] > 0]\nimgs_wo_ships = imgs[imgs['ships'] == 0].sample(20000, random_state=69278)\n\nselected_imgs = pd.concat((imgs_w_ships, imgs_wo_ships))\nselected_imgs['has_ship'] = selected_imgs['ships'] > 0","metadata":{"_uuid":"35b3c7aa2ddd5babf832bdb7b9337f5a54e136cb","execution":{"iopub.status.busy":"2024-07-03T10:12:55.179691Z","iopub.execute_input":"2024-07-03T10:12:55.179975Z","iopub.status.idle":"2024-07-03T10:12:55.631052Z","shell.execute_reply.started":"2024-07-03T10:12:55.179922Z","shell.execute_reply":"2024-07-03T10:12:55.630268Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###### Train and validate","metadata":{"_uuid":"92ab6e7ebc3c900aed9565031c5deee35fd313a0"}},{"cell_type":"code","source":"train_imgs, val_imgs = train_test_split(selected_imgs, test_size=0.15, stratify=selected_imgs['has_ship'], random_state=69278)\n\ntrain_fnames = train_imgs['ImageId'].values\nval_fnames = val_imgs['ImageId'].values","metadata":{"_uuid":"e430864a5ed8eb4b515ab106187e3cccb229d1fb","execution":{"iopub.status.busy":"2024-07-03T10:12:55.631995Z","iopub.execute_input":"2024-07-03T10:12:55.632256Z","iopub.status.idle":"2024-07-03T10:12:55.662180Z","shell.execute_reply.started":"2024-07-03T10:12:55.632206Z","shell.execute_reply":"2024-07-03T10:12:55.661511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###### Sampling","metadata":{"_uuid":"a710c9f79a8e84d458fb86a75ddce5cf607035b7"}},{"cell_type":"code","source":"_, train_fnames = train_test_split(train_fnames, test_size=0.1, random_state=69278)\n_, val_fnames = train_test_split(val_fnames, test_size=0.1, random_state=69278)","metadata":{"_uuid":"47d0ffbdf5ffcc44f43786faa7c88c980df8094b","execution":{"iopub.status.busy":"2024-07-03T10:12:55.663046Z","iopub.execute_input":"2024-07-03T10:12:55.663299Z","iopub.status.idle":"2024-07-03T10:12:55.673553Z","shell.execute_reply.started":"2024-07-03T10:12:55.663250Z","shell.execute_reply":"2024-07-03T10:12:55.672866Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Dataset","metadata":{"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"e1af6e488a6a1e4e1d6e80f583b3e5f66de27989"}},{"cell_type":"code","source":"class ImgDataset(Dataset):\n\n    def __init__(self,\n                 img_dpath,\n                 img_fnames,\n                 img_transform,\n                 mask_encodings=None,\n                 mask_size=None,\n                 mask_transform=None):\n        self.img_dpath = img_dpath\n        self.img_fnames = img_fnames\n        self.img_transform = img_transform\n\n        self.mask_encodings = mask_encodings\n        self.mask_size = mask_size\n        self.mask_transform = mask_transform\n\n    def __getitem__(self, i):\n        # https://github.com/pytorch/vision/issues/9#issuecomment-304224800\n        seed = np.random.randint(2147483647)\n\n        fname = self.img_fnames[i]\n        fpath = os.path.join(self.img_dpath, fname)\n        img = Image.open(fpath)\n        if self.img_transform is not None:\n            random.seed(seed)\n            img = self.img_transform(img)\n\n        if self.mask_encodings is None:\n            return img, fname\n\n        if self.mask_size is None or self.mask_transform is None:\n            raise ValueError('If mask_dpath is not None, mask_size and mask_transform must not be None.')\n\n        mask = np.zeros(self.mask_size, dtype=np.uint8)\n        if self.mask_encodings[fname][0] == self.mask_encodings[fname][0]: # NaN doesn't equal to itself\n            for encoding in self.mask_encodings[fname]:\n                mask += rle_decode(encoding, self.mask_size)\n        mask = np.clip(mask, 0, 1)\n\n        mask = Image.fromarray(mask)\n\n        random.seed(seed)\n        mask = self.mask_transform(mask)\n\n        return img, torch.from_numpy(np.array(mask, dtype=np.int64))\n\n    def __len__(self):\n        return len(self.img_fnames)","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"5abf9ec299e16419f7f5a4c7fc78ba0a226422ae","execution":{"iopub.status.busy":"2024-07-03T10:12:55.674473Z","iopub.execute_input":"2024-07-03T10:12:55.674748Z","iopub.status.idle":"2024-07-03T10:12:55.689216Z","shell.execute_reply.started":"2024-07-03T10:12:55.674698Z","shell.execute_reply":"2024-07-03T10:12:55.688463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Methods","metadata":{"ein.tags":"worksheet-0","heading_collapsed":true,"slideshow":{"slide_type":"-"},"_uuid":"0d2d9402003303b9705cdba3c1a1c6bceede40f8"}},{"cell_type":"code","source":"# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode\ndef rle_decode(mask_rle, shape=(768, 768)):\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    ends = starts + lengths\n    im = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        im[lo:hi] = 1\n    return im.reshape(shape).T\n\ndef rle_encode(im):\n    '''\n    im: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    pixels = im.T.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    runs[::2] -= 1\n    return ' '.join(str(x) for x in runs)","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","hidden":true,"slideshow":{"slide_type":"-"},"_uuid":"3a40035b7712eda0d67011a2101d951df6cd08ba","execution":{"iopub.status.busy":"2024-07-03T10:12:55.690210Z","iopub.execute_input":"2024-07-03T10:12:55.690470Z","iopub.status.idle":"2024-07-03T10:12:55.702143Z","shell.execute_reply.started":"2024-07-03T10:12:55.690420Z","shell.execute_reply":"2024-07-03T10:12:55.701400Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_mask_encodings(annos, fnames):\n    a = annos[annos['ImageId'].isin(fnames)]\n    return a.groupby('ImageId')['EncodedPixels'].apply(lambda x: x.tolist()).to_dict()","metadata":{"_uuid":"ae090b2d6ac782fe715ff74578b81ac4eed9081c","execution":{"iopub.status.busy":"2024-07-03T10:12:55.706131Z","iopub.execute_input":"2024-07-03T10:12:55.706360Z","iopub.status.idle":"2024-07-03T10:12:55.715770Z","shell.execute_reply.started":"2024-07-03T10:12:55.706308Z","shell.execute_reply":"2024-07-03T10:12:55.715054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Model","metadata":{"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"2f8ec0abd2e349bd52688490db3c65009faf6af3"}},{"cell_type":"markdown","source":"https://github.com/jaxony/unet-pytorch\nhttps://github.com/jvanvugt/pytorch-unet","metadata":{"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"c3a17b40f73e1fe57f83fd8288133e8a06d07130"}},{"cell_type":"code","source":"def conv1x1(in_channels, out_channels, groups=1):\n    return nn.Conv2d(in_channels,\n                     out_channels,\n                     kernel_size=1,\n                     groups=groups,\n                     stride=1)\n\ndef conv3x3(in_channels, out_channels, stride=1, padding=1, bias=True, groups=1):\n    return nn.Conv2d(in_channels,\n                     out_channels,\n                     kernel_size=3,\n                     stride=stride,\n                     padding=padding,\n                     bias=bias,\n                     groups=groups)\n\ndef upconv2x2(in_channels, out_channels, mode='transpose'):\n    if mode == 'transpose':\n        return nn.ConvTranspose2d(in_channels,\n                                  out_channels,\n                                  kernel_size=2,\n                                  stride=2)\n    else:\n        return nn.Sequential(\n            nn.Upsample(mode='bilinear', scale_factor=2),\n            conv1x1(in_channels, out_channels))","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"2af67d8b888cd922d1520f17471f5c09b276bfef","execution":{"iopub.status.busy":"2024-07-03T10:12:55.717464Z","iopub.execute_input":"2024-07-03T10:12:55.717715Z","iopub.status.idle":"2024-07-03T10:12:55.727019Z","shell.execute_reply.started":"2024-07-03T10:12:55.717674Z","shell.execute_reply":"2024-07-03T10:12:55.726331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DownConv(nn.Module):\n    \"\"\"\n    A helper Module that performs 2 convolutions and 1 MaxPool.\n    A ReLU activation follows each convolution.\n    \"\"\"\n    def __init__(self, in_channels, out_channels, pooling=True):\n        super(DownConv, self).__init__()\n\n        self.in_channels = in_channels\n        self.out_channels = out_channels\n        self.pooling = pooling\n\n        self.conv1 = conv3x3(self.in_channels, self.out_channels)\n        self.conv2 = conv3x3(self.out_channels, self.out_channels)\n\n        if self.pooling:\n            self.pool = nn.MaxPool2d(kernel_size=2, stride=2)\n\n    def forward(self, x):\n        x = F.relu(self.conv1(x))\n        x = F.relu(self.conv2(x))\n        before_pool = x\n        if self.pooling:\n            x = self.pool(x)\n        return x, before_pool\n\nclass UpConv(nn.Module):\n    \"\"\"\n    A helper Module that performs 2 convolutions and 1 UpConvolution.\n    A ReLU activation follows each convolution.\n    \"\"\"\n    def __init__(self,\n                 in_channels,\n                 out_channels,\n                 merge_mode='concat',\n                 up_mode='transpose'):\n        super(UpConv, self).__init__()\n\n        self.in_channels = in_channels\n        self.out_channels = out_channels\n        self.merge_mode = merge_mode\n        self.up_mode = up_mode\n\n        self.upconv = upconv2x2(self.in_channels,\n                                self.out_channels,\n                                mode=self.up_mode)\n\n        if self.merge_mode == 'concat':\n            self.conv1 = conv3x3(2*self.out_channels,\n                                 self.out_channels)\n        else:\n            # num of input channels to conv2 is same\n            self.conv1 = conv3x3(self.out_channels, self.out_channels)\n\n        self.conv2 = conv3x3(self.out_channels, self.out_channels)\n\n    def forward(self, from_down, from_up):\n        \"\"\" Forward pass\n        Arguments:\n            from_down: tensor from the encoder pathway\n            from_up: upconv'd tensor from the decoder pathway\n        \"\"\"\n        from_up = self.upconv(from_up)\n        if self.merge_mode == 'concat':\n            x = torch.cat((from_up, from_down), 1)\n        else:\n            x = from_up + from_down\n        x = F.relu(self.conv1(x))\n        x = F.relu(self.conv2(x))\n        return x","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"11151befdcb4aae62792a55a22a30cfae9541b33","execution":{"iopub.status.busy":"2024-07-03T10:12:55.728116Z","iopub.execute_input":"2024-07-03T10:12:55.728418Z","iopub.status.idle":"2024-07-03T10:12:55.746725Z","shell.execute_reply.started":"2024-07-03T10:12:55.728367Z","shell.execute_reply":"2024-07-03T10:12:55.746024Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class UNet(nn.Module):\n    \"\"\" `UNet` class is based on https://arxiv.org/abs/1505.04597\n    The U-Net is a convolutional encoder-decoder neural network.\n    Contextual spatial information (from the decoding,\n    expansive pathway) about an input tensor is merged with\n    information representing the localization of details\n    (from the encoding, compressive pathway).\n    Modifications to the original paper:\n    (1) padding is used in 3x3 convolutions to prevent loss\n        of border pixels\n    (2) merging outputs does not require cropping due to (1)\n    (3) residual connections can be used by specifying\n        UNet(merge_mode='add')\n    (4) if non-parametric upsampling is used in the decoder\n        pathway (specified by upmode='upsample'), then an\n        additional 1x1 2d convolution occurs after upsampling\n        to reduce channel dimensionality by a factor of 2.\n        This channel halving happens with the convolution in\n        the tranpose convolution (specified by upmode='transpose')\n    \"\"\"\n\n    def __init__(self, num_classes, in_channels=3, depth=5,\n                 start_filts=64, up_mode='transpose',\n                 merge_mode='concat'):\n        \"\"\"\n        Arguments:\n            in_channels: int, number of channels in the input tensor.\n                Default is 3 for RGB images.\n            depth: int, number of MaxPools in the U-Net.\n            start_filts: int, number of convolutional filters for the\n                first conv.\n            up_mode: string, type of upconvolution. Choices: 'transpose'\n                for transpose convolution or 'upsample' for nearest neighbour\n                upsampling.\n        \"\"\"\n        super(UNet, self).__init__()\n\n        if up_mode in ('transpose', 'upsample'):\n            self.up_mode = up_mode\n        else:\n            raise ValueError(\"\\\"{}\\\" is not a valid mode for \"\n                             \"upsampling. Only \\\"transpose\\\" and \"\n                             \"\\\"upsample\\\" are allowed.\".format(up_mode))\n\n        if merge_mode in ('concat', 'add'):\n            self.merge_mode = merge_mode\n        else:\n            raise ValueError(\"\\\"{}\\\" is not a valid mode for\"\n                             \"merging up and down paths. \"\n                             \"Only \\\"concat\\\" and \"\n                             \"\\\"add\\\" are allowed.\".format(up_mode))\n\n        # NOTE: up_mode 'upsample' is incompatible with merge_mode 'add'\n        if self.up_mode == 'upsample' and self.merge_mode == 'add':\n            raise ValueError(\"up_mode \\\"upsample\\\" is incompatible \"\n                             \"with merge_mode \\\"add\\\" at the moment \"\n                             \"because it doesn't make sense to use \"\n                             \"nearest neighbour to reduce \"\n                             \"depth channels (by half).\")\n\n        self.num_classes = num_classes\n        self.in_channels = in_channels\n        self.start_filts = start_filts\n        self.depth = depth\n\n        self.down_convs = []\n        self.up_convs = []\n\n        # create the encoder pathway and add to a list\n        for i in range(depth):\n            ins = self.in_channels if i == 0 else outs\n            outs = self.start_filts*(2**i)\n            pooling = True if i < depth-1 else False\n\n            down_conv = DownConv(ins, outs, pooling=pooling)\n            self.down_convs.append(down_conv)\n\n        # create the decoder pathway and add to a list\n        # - careful! decoding only requires depth-1 blocks\n        for i in range(depth-1):\n            ins = outs\n            outs = ins // 2\n            up_conv = UpConv(ins, outs, up_mode=up_mode,\n                merge_mode=merge_mode)\n            self.up_convs.append(up_conv)\n\n        self.conv_final = conv1x1(outs, self.num_classes)\n\n        # add the list of modules to current module\n        self.down_convs = nn.ModuleList(self.down_convs)\n        self.up_convs = nn.ModuleList(self.up_convs)\n\n        self.reset_params()\n\n    @staticmethod\n    def weight_init(m):\n        if isinstance(m, nn.Conv2d):\n            nn.init.xavier_normal(m.weight)\n            nn.init.constant(m.bias, 0)\n\n\n    def reset_params(self):\n        for i, m in enumerate(self.modules()):\n            self.weight_init(m)\n\n    def forward(self, x):\n        encoder_outs = []\n\n        # encoder pathway, save outputs for merging\n        for i, module in enumerate(self.down_convs):\n            x, before_pool = module(x)\n            encoder_outs.append(before_pool)\n\n        for i, module in enumerate(self.up_convs):\n            before_pool = encoder_outs[-(i+2)]\n            x = module(before_pool, x)\n\n        # No softmax is used. This means you need to use\n        # nn.CrossEntropyLoss is your training script,\n        # as this module includes a softmax already.\n        x = self.conv_final(x)\n        return x","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"703a1a903a9a97f1e55e201e0e5e899a4989631b","execution":{"iopub.status.busy":"2024-07-03T10:12:55.747788Z","iopub.execute_input":"2024-07-03T10:12:55.748055Z","iopub.status.idle":"2024-07-03T10:12:55.770512Z","shell.execute_reply.started":"2024-07-03T10:12:55.747984Z","shell.execute_reply":"2024-07-03T10:12:55.769707Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Train","metadata":{"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"f1cec8c14a2806eeb37cd6ed6f28b1710f2aee3d"}},{"cell_type":"code","source":"class param:\n    img_size = (80, 80)\n    bs = 8\n    num_workers = 4\n    lr = 0.0001\n    epochs = 30\n    unet_depth = 5\n    unet_start_filters = 8\n    log_interval = 70 # less then len(train_dl)\n\nchannel_means = (0.20166926, 0.28220195, 0.31729624)\nchannel_stds = (0.20769505, 0.18813899, 0.16692209)","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"c53cf6b6f46ec6a53b505d5ca6c7ea81359f6922","execution":{"iopub.status.busy":"2024-07-03T10:12:55.771671Z","iopub.execute_input":"2024-07-03T10:12:55.771999Z","iopub.status.idle":"2024-07-03T10:12:55.782786Z","shell.execute_reply.started":"2024-07-03T10:12:55.771902Z","shell.execute_reply":"2024-07-03T10:12:55.782105Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_tfms = transforms.Compose([transforms.Resize(param.img_size),\n                                 transforms.RandomRotation(360),\n                                 transforms.ToTensor(),\n                                 transforms.Normalize(channel_means, channel_stds)])\nval_tfms = transforms.Compose([transforms.Resize(param.img_size),\n                               transforms.ToTensor(),\n                               transforms.Normalize(channel_means, channel_stds)])\nmask_tfms = transforms.Compose([transforms.Resize(param.img_size),\n                                transforms.RandomRotation(360)])\n\ntrain_dl = DataLoader(ImgDataset(train_dpath,\n                                 train_fnames,\n                                 train_tfms,\n                                 get_mask_encodings(annos, train_fnames),\n                                 original_img_size,\n                                 mask_tfms),\n                      batch_size=param.bs,\n                      shuffle=True,\n                      pin_memory=torch.cuda.is_available(),\n                      num_workers=param.num_workers)\nval_dl = DataLoader(ImgDataset(train_dpath,\n                               val_fnames,\n                               val_tfms,\n                               get_mask_encodings(annos, val_fnames),\n                               original_img_size,\n                               mask_tfms),\n                    batch_size=param.bs,\n                    shuffle=False,\n                    pin_memory=torch.cuda.is_available(),\n                    num_workers=param.num_workers)\n\nmodel = UNet(2,\n             depth=param.unet_depth,\n             start_filts=param.unet_start_filters,\n             merge_mode='concat').cuda()\noptim = torch.optim.Adam(model.parameters(), lr=param.lr)","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"8d602c2fdcfe2ce53207ca0a32ac5a4e0a15df77","execution":{"iopub.status.busy":"2024-07-03T10:12:55.783981Z","iopub.execute_input":"2024-07-03T10:12:55.784291Z","iopub.status.idle":"2024-07-03T10:13:01.055332Z","shell.execute_reply.started":"2024-07-03T10:12:55.784233Z","shell.execute_reply":"2024-07-03T10:13:01.054557Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def converter(array):\n    thres = 0.5\n    tensor = torch.tensor(array, dtype=torch.float32)\n    softmax_tensor = torch.softmax(tensor, dim=0)\n    \n#     average_prob = (softmax_tensor[0] + softmax_tensor[1]) / 2\n\n    binary_array = np.zeros((768, 768), dtype=np.uint8)  # Initialize binary array\n#     binary_array[average_prob > thres] = 1\n    binary_array[softmax_tensor[0] > thres] = 1\n    \n    return binary_array\n\ntester=converter(np.random.randn(2, 768, 768))\nprint(type(tester))\nprint(tester.shape)\nprint(np.min(tester))\nprint(np.max(tester))","metadata":{"execution":{"iopub.status.busy":"2024-07-03T10:13:01.056328Z","iopub.execute_input":"2024-07-03T10:13:01.056582Z","iopub.status.idle":"2024-07-03T10:13:01.175419Z","shell.execute_reply.started":"2024-07-03T10:13:01.056529Z","shell.execute_reply":"2024-07-03T10:13:01.174425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Start of Adveat's Section","metadata":{}},{"cell_type":"code","source":"from flask import Flask, jsonify, request, render_template, send_from_directory\nfrom flask_ngrok import run_with_ngrok\nimport torch\nimport threading\nimport time\nimport base64\nimport numpy as np\nimport os\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom sklearn.metrics import average_precision_score\nimport torch\nimport torch.nn as nn\nimport torchvision.transforms as transforms\nimport requests\nimport json\n\n","metadata":{"execution":{"iopub.status.busy":"2024-07-03T10:13:01.176420Z","iopub.execute_input":"2024-07-03T10:13:01.176668Z","iopub.status.idle":"2024-07-03T10:13:01.644207Z","shell.execute_reply.started":"2024-07-03T10:13:01.176618Z","shell.execute_reply":"2024-07-03T10:13:01.642737Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"app = Flask(__name__)\nrun_with_ngrok(app)  # Start ngrok when app is run\n\nmetrics_data = {}\npredictions_data = {}\ntarget_masks_data = {}\n\n@app.route('/data', methods=['GET'])\ndef data():\n    return jsonify(metrics=metrics_data, predictions=predictions_data, target_masks=target_masks_data)\n\n@app.route('/update', methods=['POST'])\ndef update():\n    global metrics_data, predictions_data, target_masks_data\n    data = request.get_json()\n    metrics_data = data.get('metrics', {})\n    predictions_data = data.get('predictions', {})\n    target_masks_data = data.get('target_masks', {})\n    return jsonify(success=True)\n\n# Function to start Flask app in a separate thread\ndef start_flask_app():\n    thread = threading.Thread(target=app.run)\n    thread.start()\n    time.sleep(5)  # Give the server some time to start\n\n# Start Flask app\nstart_flask_app()\n\n# Helper function to convert images to base64\ndef image_to_base64(image):\n    buffered = BytesIO()\n    image.save(buffered, format=\"PNG\")\n    return base64.b64encode(buffered.getvalue()).decode(\"utf-8\")","metadata":{"execution":{"iopub.status.busy":"2024-07-03T10:13:01.645085Z","iopub.status.idle":"2024-07-03T10:13:01.645437Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def update_flask(metrics, predictions, target_masks):\n    url = 'http://localhost:5000/update'\n    data = {\n        'metrics': metrics,\n        'predictions': predictions,\n        'target_masks': target_masks\n    }\n    headers = {'Content-Type': 'application/json'}\n    response = requests.post(url, data=json.dumps(data), headers=headers)\n    if response.status_code != 200:\n#         print('Failed to update Flask app')","metadata":{"execution":{"iopub.status.busy":"2024-07-03T10:13:01.646157Z","iopub.status.idle":"2024-07-03T10:13:01.646498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_loss(dl, model):\n    loss = 0\n    for X, y in dl:\n        X, y = Variable(X).cuda(), Variable(y).cuda()\n        output = model(X)\n        loss += F.cross_entropy(output, y).data[0]\n    loss = loss / len(dl)\n    return loss","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"ae5cddfee556e3f213074f5903d2256b225647c7","execution":{"iopub.status.busy":"2024-07-03T10:13:01.647166Z","iopub.status.idle":"2024-07-03T10:13:01.647645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndef decode_rle(rleMask):\n    rleMask = rleMask.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (rleMask[0:][::2], rleMask[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(768*768, dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(768, 768).T\n\ndef generate_mask_image(masksList):\n    maskImage = np.zeros((768, 768), dtype=np.uint8)\n    for mask in masksList:\n        decodedMask = decode_rle(mask)\n        maskImage += decodedMask\n    return maskImage\n\n# Functions for extracting instances, computing IoU, and metrics\ndef extract_instances(mask):\n    labeled_mask = np.zeros_like(mask, dtype=int)\n    label = 1\n    instances = []\n    height, width = mask.shape\n\n    for y in range(height):\n        for x in range(width):\n            if mask[y, x] == 1 and labeled_mask[y, x] == 0:\n                component = []\n                stack = [(y, x)]\n\n                while stack:\n                    cy, cx = stack.pop()\n                    if labeled_mask[cy, cx] == 0:\n                        labeled_mask[cy, cx] = label\n                        component.append((cy, cx))\n                        for dy, dx in [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]:\n                            ny, nx = cy + dy, cx + dx\n                            if 0 <= ny < height and 0 <= nx < width and mask[ny, nx] == 1 and labeled_mask[ny, nx] == 0:\n                                stack.append((ny, nx))\n\n                instance_mask = np.zeros_like(mask)\n                for (iy, ix) in component:\n                    instance_mask[iy, ix] = 1\n                instances.append(instance_mask)\n                label += 1\n\n    return instances\n\ndef compute_iou(pred_mask, target_mask):\n    intersection = np.logical_and(target_mask, pred_mask).sum()\n    union = np.logical_or(target_mask, pred_mask).sum()\n    iou = intersection / union if union != 0 else 0\n    return iou\n\ndef dice_score(pred, targs):\n    pred = (pred>0).astype(float)\n    return 2.0 * (pred*targs).sum() / ((pred+targs).sum() + 1.0)\n\n\ndef compute_metrics(pred_masks):\n    all_metrics = []\n\n    for idx in range(len(all_target_masks)):\n        pred_instances = extract_instances(pred_masks[idx])\n        target_instances = all_target_instances[idx]\n\n        all_ious = []\n        all_precisions = []\n        all_recalls = []\n        all_average_precisions = []\n        all_dice = []\n        \n        i = 0\n\n        for target_mask in target_instances:\n            best_iou = 0\n            argmax_best_iou = -1\n            \n            i += 1\n\n            for pred_mask in pred_instances:\n                iou = compute_iou(pred_mask, target_mask)\n                if iou > best_iou:\n                    best_iou = iou\n                    argmax_best_iou = pred_mask\n\n            tp = best_iou >= threshold\n            fp = best_iou < threshold and best_iou > 0\n            fn = target_mask.sum() > 0 and best_iou == 0\n\n            precision = tp\n\n            target_mask_flat = target_mask.flatten() \n            best_pred_mask_flat = argmax_best_iou.flatten() if best_iou > 0 else np.zeros_like(target_mask_flat)\n            average_precision = average_precision_score(target_mask_flat, best_pred_mask_flat)\n            dice = dice_score(best_pred_mask_flat,target_mask_flat)\n\n            #print(f\"idx: {idx},instance: {i}, precision: {precision}, iou: {best_iou}, recall: {recall}, ap: {average_precision}, dice: {dice}\")\n            \n            all_ious.append(best_iou)\n            all_precisions.append(precision)\n            all_recalls.append(recall)\n            all_average_precisions.append(average_precision)\n            all_dice.append(dice)\n            \n            \n        #print(idx,len(all_precisions),len(all_recalls),len(all_average_precisions),len(all_ious),len(dice))\n        metrics = {\n            'Precision': (np.mean(all_precisions) if len(all_precisions) > 0 else 0),\n            'Recall': (np.mean(all_recalls) if len(all_recalls) > 0 else 0),\n            'Average Precision': (np.mean(all_average_precisions) if len(all_recalls) > 0 else 0),\n            'Jaccard': (np.mean(all_ious) if len(all_ious) > 0 else 0),\n            'Dice Score': (np.mean(all_dice) if len(all_dice) > 0 else 0)\n        }\n        \n\n        all_metrics.append(metrics)\n\n    average_metrics = {}\n    num_metrics = len(all_metrics)\n    for d in all_metrics:\n        for key in d:\n            if key in average_metrics:\n                average_metrics[key] += d[key]\n            else:\n                average_metrics[key] = d[key]\n\n    for key in average_metrics:\n        average_metrics[key] /= num_metrics\n\n    return average_metrics\n\n# Function to show masks\ndef show_masks(pred_mask, target_mask):\n    plt.figure(figsize=(10, 5))\n\n    plt.subplot(1, 2, 1)\n    plt.imshow(pred_mask, cmap='gray')\n    plt.title('Predicted Mask')\n    plt.axis('off')\n\n    plt.subplot(1, 2, 2)\n    plt.imshow(target_mask, cmap='gray')\n    plt.title('Target Mask')\n    plt.axis('off')\n\n    plt.tight_layout()\n    plt.show()\n\n\n\n\n    \n\n\n\n# # Example usage\n\n\n# # Define your model\n# model = ...  # Your PyTorch model\n# optimizer = ...  # Your optimizer\n# loss_function = ...  # Your loss function\n\n# # Define any necessary transformations\n# transform = transforms.Compose([\n#     transforms.Resize((768, 768)),\n#     transforms.ToTensor(),\n# ])\n\n# # Train the model\n# train_model(model, optimizer, loss_function, num_epochs=10)\n","metadata":{"execution":{"iopub.status.busy":"2024-07-03T10:13:01.648358Z","iopub.status.idle":"2024-07-03T10:13:01.648882Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load target images and masks\nimg_path = \"../input/train_v2/\"\nfilenames = [\"0005d01c8.jpg\", \"00140e597.jpg\",\"00113a75c.jpg\",\"001dd855d.jpg\",\"00269a792.jpg\",\"001f3caca.jpg\",\"0041d7084.jpg\",\"002943412.jpg\",\"002abd5df.jpg\",\"002e85393.jpg\"]\ntrainCsv = pd.read_csv(\"/kaggle/working/adveat.csv\", index_col=0).dropna()\ntrainCsv = trainCsv.groupby(\"ImageId\")[['EncodedPixels']].agg(lambda rle_codes: ' '.join(rle_codes)).reset_index()\nthreshold = 0.8\n\nall_target_images = [Image.open(os.path.join(img_path, file)) for file in filenames]\nall_target_masks = [generate_mask_image(trainCsv.loc[trainCsv[\"ImageId\"] == file][\"EncodedPixels\"]) for file in filenames]\nall_target_instances = [extract_instances(mask) for mask in all_target_masks]\nbest_weights = None\ninterval = 20\npatience= 3\nwait = 0\nbest_average_precision = -np.Inf\nbest_epoch = 0\nnum_epochs = 100","metadata":{"execution":{"iopub.status.busy":"2024-07-03T10:13:01.649672Z","iopub.status.idle":"2024-07-03T10:13:01.650192Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#os.makedirs(os.path.dirname(bst_model_fpath), exist_ok=True)\n\ntransform = transforms.Compose([\n    transforms.Resize((768, 768)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # Example normalization for RGB images\n])\n\ndef display_image(array):\n    plt.imshow(array, cmap='gray')\n    plt.axis('off')  # Optional: turn off axis numbers\n    plt.show()\n\nfor epoch in range(num_epochs):\n    model.train()\n    for i, (X, y) in enumerate(train_dl):\n        X = Variable(X).cuda()  # [N, 1, H, W]\n        y = Variable(y).cuda()  # [N, H, W] with class indices (0, 1)\n        output = model(X)  # [N, 2, H, W]\n        loss = F.cross_entropy(output, y)\n\n        optim.zero_grad()\n        loss.backward()\n        optim.step()\n        \n    model.eval()\n    if epoch%interval == 0:\n        predictions = []\n        for idx,image in enumerate(all_target_images):\n            input_tensor = transform(image).unsqueeze(0).cuda()  # Apply necessary transformations\n            with torch.no_grad():\n                pred_mask = model(input_tensor)\n                pred_mask = pred_mask.squeeze(0).cpu().numpy()\n                predictions.append(converter(pred_mask))\n    \n        metrics = compute_metrics(predictions)\n        \n        # Display metrics\n#         print(f\"\\nMetrics at epoch {epoch + 1}:\")\n#         for metric, value in metrics.items():\n#             print(f\"{metric}: {value:.4f}\")\n        \n#         # Show masks for a sample image\n#         for sample_index in range(len(predictions)):  \n#             pred_mask = predictions[sample_index]\n#             target_mask = all_target_masks[sample_index]\n#             show_masks(pred_mask, target_mask)\n        \n        update_flask(metrics, predictions, target_masks)\n        \n        # Early stopping based on average precision\n        current_avg_precision = metrics['Average Precision']\n        if current_avg_precision > best_average_precision:\n            best_average_precision = current_avg_precision\n            best_weights = model.state_dict()\n            best_epoch = epoch\n            wait = 0\n        else:\n            wait += 1\n            if wait >= patience:\n                print(f\"\\nEarly stopping implemented\")\n                model.load_state_dict(best_weights)\n                break\n\nprint(f\"\\nBest Average Precision of {best_average_precision:.4f} at epoch {best_epoch}.\")\n","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"f789fd785a3d01245125677bfb64fac695c5c0b2","execution":{"iopub.status.busy":"2024-07-03T10:13:01.650967Z","iopub.status.idle":"2024-07-03T10:13:01.651413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(iters, train_losses)\nplt.plot(iters, val_losses)\nplt.show()","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"b4e8822d838abf84a753525dfccb9e1d3c380539","execution":{"iopub.status.busy":"2024-07-03T10:13:01.652198Z","iopub.status.idle":"2024-07-03T10:13:01.652656Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Prediction","metadata":{"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"8a07f32e0356017e52c2227482f8f124899e7151"}},{"cell_type":"code","source":"sample_submission = pd.read_csv(sample_submission_fpath)\ntest_fnames = sample_submission['ImageId'].values\n\ntest_dl = DataLoader(ImgDataset(test_dpath,\n                                test_fnames,\n                                val_tfms),\n                     batch_size=param.bs,\n                     shuffle=False,\n                     pin_memory=torch.cuda.is_available(),\n                     num_workers=param.num_workers)","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"ce93ea3eec9d75875e180b828422c7a007d8ec32","execution":{"iopub.status.busy":"2024-07-03T10:13:01.653449Z","iopub.status.idle":"2024-07-03T10:13:01.654052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = {'ImageId': [], 'EncodedPixels': []}\n\nmodel.eval()\nfor X, fnames in test_dl:\n    X = Variable(X).cuda()\n    output = model(X)\n    for i, fname in enumerate(fnames):\n        mask = F.sigmoid(output[i, 0]).data.cpu().numpy()\n        mask = binary_opening(mask > 0.5, disk(2))\n        mask = Image.fromarray(mask.astype(np.uint8)).resize(original_img_size)\n        mask = np.array(mask).astype(np.bool)\n\n        labels = label(mask)\n        encodings = [rle_encode(labels == k) for k in np.unique(labels[labels > 0])]\n        if len(encodings) > 0:\n            for encoding in encodings:\n                submission['ImageId'].append(fname)\n                submission['EncodedPixels'].append(encoding)\n        else:\n            submission['ImageId'].append(fname)\n            submission['EncodedPixels'].append(None)","metadata":{"_uuid":"5e62a1e186340b66d8087d1710be4b7aad68bc57","execution":{"iopub.status.busy":"2024-07-03T10:13:01.654901Z","iopub.status.idle":"2024-07-03T10:13:01.655332Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Submission","metadata":{"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"0f1b43aa9fe4d7f7f18af2de0c949b91a9f32aec"}},{"cell_type":"code","source":"submission_df = pd.DataFrame(submission, columns=['ImageId', 'EncodedPixels'])\nsubmission_df.to_csv('submission_1.csv', index=False)\nsubmission_df.sample(10)","metadata":{"autoscroll":false,"ein.hycell":false,"ein.tags":"worksheet-0","slideshow":{"slide_type":"-"},"_uuid":"d6966a092134651d58a1507c33a66cdeb28879ed","execution":{"iopub.status.busy":"2024-07-03T10:13:01.656263Z","iopub.status.idle":"2024-07-03T10:13:01.656661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"_uuid":"fb2b4a251559225650116a295b7bfe303bb1d6fb","collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]}]}