{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport sys\nimport numpy as np\nimport pandas as pd\nfrom matplotlib import animation\nimport matplotlib.pyplot as plt\nfrom IPython import display\n\n\n# choice of ML tool\nimport torch\nfrom tqdm import tqdm\n\n# for input of the model\nfrom torch.utils.data import Dataset\nfrom torch.utils.data import DataLoader\n\n\nimport torch.nn as nn\nfrom torchvision import models\nfrom torch.nn.functional import relu\n\nimport torch.optim as optim\nfrom torch.optim import lr_scheduler\nimport copy\nimport time\nfrom collections import defaultdict\nimport torch.nn.functional as F\n","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:04:31.597083Z","iopub.execute_input":"2023-08-09T11:04:31.597862Z","iopub.status.idle":"2023-08-09T11:04:31.6033Z","shell.execute_reply.started":"2023-08-09T11:04:31.597831Z","shell.execute_reply":"2023-08-09T11:04:31.602542Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = \"cuda:0\"","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:04:31.604549Z","iopub.execute_input":"2023-08-09T11:04:31.605263Z","iopub.status.idle":"2023-08-09T11:04:31.621986Z","shell.execute_reply.started":"2023-08-09T11:04:31.605236Z","shell.execute_reply":"2023-08-09T11:04:31.620994Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE_DIR = '/kaggle/input/google-research-identify-contrails-reduce-global-warming'\nTRAIN_DIR = '/kaggle/input/google-research-identify-contrails-reduce-global-warming/train'\nTEST_DIR = '/kaggle/input/google-research-identify-contrails-reduce-global-warming/test'","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:04:31.623043Z","iopub.execute_input":"2023-08-09T11:04:31.623412Z","iopub.status.idle":"2023-08-09T11:04:31.63808Z","shell.execute_reply.started":"2023-08-09T11:04:31.623384Z","shell.execute_reply":"2023-08-09T11:04:31.636675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#A custom Dataset class must implement three functions: __init__, __len__, and __getitem__\n_T11_BOUNDS = (243, 303)\n_CLOUD_TOP_TDIFF_BOUNDS = (-4, 5)\n_TDIFF_BOUNDS = (-4, 2)\n\nclass ContrailDataset(Dataset):\n    \n\n    \n    # params :  all params required for len and get item method\n    def __init__(self , base_dir :str, dataset_type: str , image_size :int):\n        self.base_dir = base_dir \n        self.dataset_type = dataset_type\n        self.dataset_dir = os.path.join(self.base_dir, self.dataset_type)\n        self.records = os.listdir(self.dataset_dir)\n        self.image_size = image_size\n        print(f\"dataset dir = {self.dataset_dir} -> _exists {os._exists(self.dataset_dir)}\")\n        \n    \n                \n    def __len__(self):\n        return len(self.records)\n    \n    def normalize_range(self , data, bounds):\n        \"\"\"Maps data to the range [0, 1].\"\"\"\n        return (data - bounds[0]) / (bounds[1] - bounds[0])\n    \n\n    def preprocess_item(self , record_id):\n        band11 = np.load(os.path.join(self.dataset_dir, record_id, 'band_11.npy'))[...,2:7]\n        band14 = np.load(os.path.join(self.dataset_dir, record_id, 'band_14.npy'))[...,2:7]\n        band15 = np.load(os.path.join(self.dataset_dir, record_id, 'band_15.npy'))[...,2:7]\n\n        r = self.normalize_range(band15 - band14, _TDIFF_BOUNDS)\n        g = self.normalize_range(band14 - band11, _CLOUD_TOP_TDIFF_BOUNDS)\n        b = self.normalize_range(band14, _T11_BOUNDS)\n\n        false_color = np.stack([r, g, b], axis=2)\n        false_color = np.clip(false_color, 0, 1)\n#         print(f'false_color {false_color.shape}')\n        human_pixel_mask = np.load(os.path.join(self.dataset_dir, record_id, 'human_pixel_masks.npy'))\n\n        false_color = np.swapaxes(false_color, 2, 3)\n        false_color= false_color.reshape(256, 256, -1)\n#         print(f'false_color {false_color.shape}')\n        return false_color , human_pixel_mask\n    \n    def __getitem__(self , idx):\n        \n        input_data ,output_labels = self.preprocess_item(self.records[idx])        \n\n        # start data augmentation\n        hflip = idx%30==0\n        vflip = idx%31==0\n        \n        if vflip: \n            input_data = np.flip(input_data,0) #0 vertical\n            output_labels = np.flip(output_labels,0)\n            \n        if hflip:\n            input_data = np.flip(input_data,1)# 1 horizontal\n            output_labels = np.flip(output_labels,1)\n        # end data augmentation\n        \n#         print(f'{input_data.shape=}, {output_labels.shape}')\n\n        # start data prep for torch training\n        # re arranges channels required for traning\n        input_data = torch.tensor(np.copy(input_data) ).permute(2,0,1)\n        output_labels = torch.tensor(np.copy(output_labels),  dtype=torch.float).permute(2,0,1)\n        # end  data prep for torch training\n        \n        return input_data ,output_labels","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:04:31.640858Z","iopub.execute_input":"2023-08-09T11:04:31.64132Z","iopub.status.idle":"2023-08-09T11:04:31.664081Z","shell.execute_reply.started":"2023-08-09T11:04:31.641283Z","shell.execute_reply":"2023-08-09T11:04:31.66283Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size=16\n\n# data loader\ntrain_data = ContrailDataset(base_dir=BASE_DIR, dataset_type='train' ,image_size =  256)\ntrain_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, num_workers=2)\n\nval_data = ContrailDataset(base_dir=BASE_DIR, dataset_type='validation' ,image_size =  256)\nval_loader = DataLoader(val_data, batch_size=batch_size, shuffle=True, num_workers=2)\n\ntrain_loader.__len__() # = total images/batchsize\nval_loader.__len__() # = total images/batchsize","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:04:31.665643Z","iopub.execute_input":"2023-08-09T11:04:31.665923Z","iopub.status.idle":"2023-08-09T11:04:31.698782Z","shell.execute_reply.started":"2023-08-09T11:04:31.665899Z","shell.execute_reply":"2023-08-09T11:04:31.69739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data.__getitem__(0)[0].shape","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:10:18.411087Z","iopub.execute_input":"2023-08-09T11:10:18.411453Z","iopub.status.idle":"2023-08-09T11:10:18.770565Z","shell.execute_reply.started":"2023-08-09T11:10:18.411426Z","shell.execute_reply":"2023-08-09T11:10:18.769265Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\n\nclass conv_block(nn.Module):\n    def __init__(self, in_c, out_c):\n        super().__init__()\n        self.conv = nn.Sequential(\n            nn.Conv2d(in_c, out_c, kernel_size=3, padding=1),\n            nn.BatchNorm2d(out_c),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(out_c, out_c, kernel_size=3, padding=1),\n            nn.BatchNorm2d(out_c),\n            nn.ReLU(inplace=True)\n        )\n \n    def forward(self, x):\n        return self.conv(x)\n\n        \nclass encoder_block(nn.Module):\n    def __init__(self, in_c, out_c):\n        super().__init__()\n \n        self.conv = conv_block(in_c, out_c)\n        self.pool = nn.MaxPool2d((2, 2))\n \n    def forward(self, x):\n        s = self.conv(x)\n        p = self.pool(s)\n        return s, p\n\n    \nclass attention_gate(nn.Module):\n    def __init__(self, in_c, out_c):\n        super().__init__()\n \n        self.Wg = nn.Sequential(\n            nn.Conv2d(in_c[0], out_c, kernel_size=1, padding=0),\n            nn.BatchNorm2d(out_c)\n        )\n        self.Ws = nn.Sequential(\n            nn.Conv2d(in_c[1], out_c, kernel_size=1, padding=0),\n            nn.BatchNorm2d(out_c)\n        )\n        self.relu = nn.ReLU(inplace=True)\n        self.output = nn.Sequential(\n            nn.Conv2d(out_c, out_c, kernel_size=1, padding=0),\n            nn.Sigmoid()\n        )\n \n    def forward(self, g, s):\n        Wg = self.Wg(g)\n        Ws = self.Ws(s)\n        out = self.relu(Wg + Ws)\n        out = self.output(out)\n        return out\n    \n    \nclass decoder_block(nn.Module):\n    def __init__(self, in_c, out_c):\n        super().__init__()\n \n        self.up = nn.Upsample(scale_factor=2, mode=\"bilinear\", align_corners=True)\n        self.ag = attention_gate(in_c, out_c)\n        self.c1 = conv_block(in_c[0]+out_c, out_c)\n \n    def forward(self, x, s):\n        x = self.up(x)\n        s = self.ag(x, s)\n        x = torch.cat([x, s], axis=1)\n        x = self.c1(x)\n        return x\n\n    \nclass attention_bottleneck_block(nn.Module):\n    def __init__(self, in_c, out_c):\n        super().__init__()\n \n        self.Wg = nn.Sequential(\n            nn.Conv2d(in_c[0], out_c, kernel_size=1, padding=0),\n            nn.BatchNorm2d(out_c)\n        )\n        self.Ws = nn.Sequential(\n            nn.Conv2d(in_c[1], out_c, kernel_size=1, padding=0),\n            nn.BatchNorm2d(out_c)\n        )\n        self.relu = nn.ReLU(inplace=True)\n        self.output = nn.Sequential(\n            nn.Conv2d(out_c, out_c, kernel_size=1, padding=0),\n            nn.Sigmoid()\n        )\n \n    def forward(self, g, s):\n        Wg = self.Wg(g)\n        Ws = self.Ws(s)\n        out = self.relu(Wg + Ws)\n        out = self.output(out)\n        return out\n\n    \nclass Temporal_AUNet(nn.Module):\n    def __init__(self):\n        super(Temporal_AUNet, self).__init__()\n\n#         \"\"\" Encoder \"\"\"\n        self.e1 = encoder_block(15, 64)\n        self.e2 = encoder_block(64, 128)\n        self.e3 = encoder_block(128, 256)\n        self.e4 = encoder_block(256, 512)\n        \n        # set of encoders for skip connection\n        self.e1F = encoder_block(3, 64)\n        self.e2F = encoder_block(64, 128)\n        self.e3F = encoder_block(128, 256)\n        self.e4F = encoder_block(256, 512)\n        \n\n#         \"\"\" Bottleneck \"\"\"\n        self.b = attention_bottleneck_block([512,512], 1024)\n    \n#          \"\"\" Decoder \"\"\"\n        self.d1 = decoder_block([1024 , 512], 512)\n        self.d2 = decoder_block([512, 256], 256)\n        self.d3 = decoder_block([256, 128], 128)\n        self.d4 = decoder_block([128, 64], 64)\n#          \"\"\" Classifier \"\"\"\n        self.outputs = nn.Conv2d(64, 1, kernel_size=1, padding=0)\n    \n    def forward(self, inputs):\n        \n        all_frames = inputs\n        frame = inputs[:,6:9,:,:]\n        \n#         \"\"\" Encoder \"\"\"\n        s1, p1 = self.e1(all_frames)\n        s2, p2 = self.e2(p1)\n        s3, p3 = self.e3(p2)\n        s4, p4 = self.e4(p3)\n        \n        # frame encoder for skip connection and bottleneck attention\n        s1F, p1F = self.e1F(frame)\n        s2F, p2F = self.e2F(p1F)\n        s3F, p3F = self.e3F(p2F)\n        s4F, p4F = self.e4F(p3F)\n        \n#          \"\"\" Bottleneck \"\"\"\n        b = self.b(p4 , p4F)\n#          \"\"\" Decoder \"\"\"\n        d1 = self.d1(b, s4F)\n        d2 = self.d2(d1, s3F)\n        d3 = self.d3(d2, s2F)\n        d4 = self.d4(d3, s1F)\n#          \"\"\" Classifier \"\"\"\n        outputs = self.outputs(d4)\n        pred = F.sigmoid(outputs)\n        return pred","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:04:31.785576Z","iopub.execute_input":"2023-08-09T11:04:31.785968Z","iopub.status.idle":"2023-08-09T11:04:31.809943Z","shell.execute_reply.started":"2023-08-09T11:04:31.78593Z","shell.execute_reply":"2023-08-09T11:04:31.808721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_path = \"/kaggle/input/anet-v5/Temporal_AUNet_5_e22_tl_0.2935_vl_0.4385.pth\"","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:04:31.811389Z","iopub.execute_input":"2023-08-09T11:04:31.812201Z","iopub.status.idle":"2023-08-09T11:04:31.830863Z","shell.execute_reply.started":"2023-08-09T11:04:31.812172Z","shell.execute_reply":"2023-08-09T11:04:31.82966Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# model = Temporal_AUNet()\n# model.to(device)\n\n\ndef load_checkpoint(filepath):\n    checkpoint = torch.load(filepath, map_location=torch.device(device))\n    model = checkpoint['model']\n    model.load_state_dict(checkpoint['state_dict'])\n    for parameter in model.parameters():\n        parameter.requires_grad = False\n\n    model.eval()\n    return model\n\nmodel = load_checkpoint(model_path)\nmodel.to(device)\nfor param in model.parameters():\n    param.requires_grad = True\n","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:04:31.832099Z","iopub.execute_input":"2023-08-09T11:04:31.83243Z","iopub.status.idle":"2023-08-09T11:04:32.107802Z","shell.execute_reply.started":"2023-08-09T11:04:31.832402Z","shell.execute_reply":"2023-08-09T11:04:32.107015Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# optimizer function\noptimizer = optim.Adam(model.parameters(), lr=0.000005)\n\ndef dice_coefficient(y_true, y_pred, smooth = 1e-7):\n    return 1- (2. * (y_true.view(-1) * y_pred.view(-1)).sum() + smooth) / ((y_true.view(-1).sum() + y_pred.view(-1).sum()) + smooth)\n\nnum_epochs = 25","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:04:32.108811Z","iopub.execute_input":"2023-08-09T11:04:32.109653Z","iopub.status.idle":"2023-08-09T11:04:32.116954Z","shell.execute_reply.started":"2023-08-09T11:04:32.109627Z","shell.execute_reply":"2023-08-09T11:04:32.115289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Training loop\n\nfor epoch in range(num_epochs):\n    model.train()\n    total_loss = 0.0\n    batch = 0\n    for inputs, targets in train_loader:\n        batch=batch+1\n        \n        # input data\n        inputs, targets = inputs.to(device), targets.to(device)\n        \n        \n        # zero the parameter gradients\n        optimizer.zero_grad()\n        \n        # Forward pass\n        outputs = model(inputs)\n        \n        # Calculate loss\n        loss = dice_coefficient(outputs, targets)\n        \n        \n#         if(batch%10==0):\n        #print(f\"epoch: {epoch}, batch: {batch} loss: {loss}\")\n        \n        \n            \n        # Backpropagation and optimization\n        loss.backward()\n#         accelerator.backward(loss)\n\n        optimizer.step()\n        \n      \n        total_loss += loss.item()\n\n\n    # Calculate and print average loss for the epoch\n    average_loss = total_loss / len(train_loader)\n    print(f\"Train :Epoch [{epoch+1}/{num_epochs}] - Loss: {average_loss:.4f}\")\n    \n    \n    # Validation\n    model.eval()\n    total_val_loss = 0.0\n    with torch.no_grad():\n        for val_inputs, val_targets in val_loader:\n            \n            val_inputs, val_targets = val_inputs.to(device), val_targets.to(device)\n\n            # Forward pass (inference)\n            val_outputs = model(val_inputs)\n\n            # Calculate validation loss\n            val_loss = dice_coefficient(val_outputs, val_targets)\n            \n            if(batch%10==0):\n                print(f\"epoch: {epoch}, batch: {batch} val_loss: {val_loss}\")\n            \n            total_val_loss += val_loss.item()\n\n    # Calculate average validation loss for the epoch\n    average_val_loss = total_val_loss / len(val_loader)\n    print(f\"validation : Epoch [{epoch+1}/{num_epochs}] - Val Loss: {average_val_loss:.4f} \")\n    \n#     accelerator.wait_for_everyone() \n    \n#     # Then we unwrap the model from any distributed wrapping that was performed\n#     model = accelerator.unwrap_model(model)\n    \n#     # and Acceleate can then save the model once (as all workers have the same model with the same weights now)\n#     accelerator.save(model, f'acc_v3_aunet_e_{epoch}_tl_{average_loss}_vl_{average_val_loss}.pth')\n    \n    checkpoint = {\n        'model': Temporal_AUNet(),\n        'state_dict': model.state_dict(),\n        'optimizer' : optimizer.state_dict()\n        }\n    tl_avg_loss =\"{:.4f}\".format(average_loss)\n    vl_avg_loss = \"{:.4f}\".format(average_val_loss)\n    torch.save(checkpoint, f'Temporal_AUNet_5_e{epoch}_tl_{tl_avg_loss}_vl_{vl_avg_loss}.pth')\n    \nprint('Train completed')","metadata":{"execution":{"iopub.status.busy":"2023-08-09T11:04:32.119339Z","iopub.execute_input":"2023-08-09T11:04:32.119715Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n#A custom Dataset class must implement three functions: __init__, __len__, and __getitem__\n_T11_BOUNDS = (243, 303)\n_CLOUD_TOP_TDIFF_BOUNDS = (-4, 5)\n_TDIFF_BOUNDS = (-4, 2)\n\nclass TestContrailDataset(Dataset):\n    \n\n    \n    # params :  all params required for len and get item method\n    def __init__(self , base_dir :str, dataset_type: str , image_size :int):\n        self.base_dir = base_dir \n        self.dataset_type = dataset_type\n        self.dataset_dir = os.path.join(self.base_dir, self.dataset_type)\n        self.records = os.listdir(self.dataset_dir)\n        self.image_size = image_size\n        print(f\"dataset dir = {self.dataset_dir} -> _exists {os._exists(self.dataset_dir)}\")\n        \n    \n                \n    def __len__(self):\n        return len(self.records)\n    \n    def normalize_range(self , data, bounds):\n        \"\"\"Maps data to the range [0, 1].\"\"\"\n        return (data - bounds[0]) / (bounds[1] - bounds[0])\n    \n\n    def preprocess_item(self , record_id):\n        band11 = np.load(os.path.join(self.dataset_dir, record_id, 'band_11.npy'))[...,2:7]\n        band14 = np.load(os.path.join(self.dataset_dir, record_id, 'band_14.npy'))[...,2:7]\n        band15 = np.load(os.path.join(self.dataset_dir, record_id, 'band_15.npy'))[...,2:7]\n\n        r = self.normalize_range(band15 - band14, _TDIFF_BOUNDS)\n        g = self.normalize_range(band14 - band11, _CLOUD_TOP_TDIFF_BOUNDS)\n        b = self.normalize_range(band14, _T11_BOUNDS)\n\n        false_color = np.stack([r, g, b], axis=2)\n        false_color = np.clip(false_color, 0, 1)\n#         print(f'false_color {false_color.shape}')\n\n        false_color = np.swapaxes(false_color, 2, 3)\n        false_color= false_color.reshape(256, 256, -1)\n#         print(f'false_color {false_color.shape}')\n        return false_color \n    \n    def __getitem__(self , idx):\n        \n        input_data = self.preprocess_item(self.records[idx])        \n\n\n#         print(f'{input_data.shape=}, {output_labels.shape}')\n\n        # start data prep for torch training\n        # re arranges channels required for traning\n        input_data = torch.tensor(np.copy(input_data) ).permute(2,0,1)\n        # end  data prep for torch training\n        \n        return input_data , self.records[idx]","metadata":{"execution":{"iopub.status.busy":"2023-08-26T08:08:07.04488Z","iopub.execute_input":"2023-08-26T08:08:07.045571Z","iopub.status.idle":"2023-08-26T08:08:07.470971Z","shell.execute_reply.started":"2023-08-26T08:08:07.045537Z","shell.execute_reply":"2023-08-26T08:08:07.469666Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_data = TestContrailDataset(base_dir=BASE_DIR, dataset_type='test' ,image_size =  256)\ntest_loader = DataLoader(test_data, batch_size=1, shuffle=True, num_workers=2)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.read_csv(BASE_DIR +\"/\"+ 'sample_submission.csv', index_col='record_id')\nsubmission.drop(submission.index, inplace=True)\nsubmission","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def rle_encode(x, fg_val=1):\n    \"\"\"\n    Args:\n        x:  numpy array of shape (height, width), 1 - mask, 0 - background\n    Returns: run length encoding as list\n    \"\"\"\n\n    dots = np.where(\n        x.T.flatten() == fg_val)[0]  # .T sets Fortran order down-then-right\n    run_lengths = []\n    prev = -2\n    for b in dots:\n        if b > prev + 1:\n            run_lengths.extend((b + 1, 0))\n        run_lengths[-1] += 1\n        prev = b\n    return run_lengths\n\n\ndef list_to_string(x):\n    \"\"\"\n    Converts list to a string representation\n    Empty list returns '-'\n    \"\"\"\n    if x: # non-empty list\n        s = str(x).replace(\"[\", \"\").replace(\"]\", \"\").replace(\",\", \"\")\n    else:\n        s = '-'\n    return s\n\n\ndef rle_decode(mask_rle, shape=(256, 256)):\n    '''\n    mask_rle: run-length as string formatted (start length)\n              empty predictions need to be encoded with '-'\n    shape: (height, width) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    '''\n\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    if mask_rle != '-': \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        for lo, hi in zip(starts, ends):\n            img[lo:hi] = 1\n    return img.reshape(shape, order='F')  # Needed to align to RLE direction","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.eval()\nbatch = 0\nwith torch.no_grad():\n    for test_inputs , record in test_loader:\n        batch += 1\n#         print(f\"-{batch}-\")\n        test_inputs = test_inputs.to(device)\n        \n        # Forward pass (inference)\n        test_outputs = model(test_inputs).cpu().detach().numpy()\n        \n        test_outputs[test_outputs >= 0.2] = 1\n        test_outputs[test_outputs < 0.2] = 0\n\n#         print(test_outputs.shape)\n        count_px_contrails = np.sum(np.concatenate(test_outputs),where=[1])\n\n        encoded_px = ''\n        if(count_px_contrails>=10):\n            encoded_px = list_to_string(rle_encode(test_outputs[0][0]))\n        else :\n            encoded_px = '-'\n        \n        submission.loc[int(record[0])] = encoded_px\n\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Sumbmission file ready with length : ')\nprint(len(submission))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission.to_csv('submission.csv')","metadata":{},"execution_count":null,"outputs":[]}]}