{"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 numpy as np\nimport torch\nimport torch.nn as nn\nimport os\nfrom torchvision.transforms import Compose,ToTensor\nfrom torch.utils.data import Dataset\nfrom torch.utils.data import DataLoader\nimport matplotlib.pyplot as plt\nfrom tqdm.auto import tqdm\nimport pandas as pd\nimport seaborn as sns\n\n!pip install -q -U segmentation-models-pytorch albumentations > /dev/null\nimport segmentation_models_pytorch as smp\n\nfrom torchvision import models\ntry:\n    from torchsummary import summary\nexcept:\n    !pip install torchsummary > /dev/null\n    from torchsummary import summary\n    \nimport torch.nn.functional as F\nfrom torchvision import models","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-08-03T23:19:59.632866Z","iopub.execute_input":"2023-08-03T23:19:59.633279Z","iopub.status.idle":"2023-08-03T23:20:37.397096Z","shell.execute_reply.started":"2023-08-03T23:19:59.633246Z","shell.execute_reply":"2023-08-03T23:20:37.395284Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# config and devices","metadata":{}},{"cell_type":"code","source":"CONFIG = dict(\n    seed=42,\n    DATA_ROOT = '/kaggle/input/google-research-identify-contrails-reduce-global-warming/',\n    BATCH_SIZE = 16,\n    IMG_SIZE = (256,256),\n    NUM_TRAIN_SAMPLES = 1000,\n    NUM_VAL_SAMPLES = 300,\n    NUM_TEST_SAMPLES = 2)","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:20:37.400887Z","iopub.execute_input":"2023-08-03T23:20:37.401378Z","iopub.status.idle":"2023-08-03T23:20:37.407665Z","shell.execute_reply.started":"2023-08-03T23:20:37.401337Z","shell.execute_reply":"2023-08-03T23:20:37.406282Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if torch.cuda.is_available():\n    device = torch.device('cuda')\nelse:\n    device = torch.device('cpu')\n\ndevice","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:20:37.409373Z","iopub.execute_input":"2023-08-03T23:20:37.410084Z","iopub.status.idle":"2023-08-03T23:20:37.448962Z","shell.execute_reply.started":"2023-08-03T23:20:37.410047Z","shell.execute_reply":"2023-08-03T23:20:37.44819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"_T11_BOUNDS = (243, 303)\n_CLOUD_TOP_TDIFF_BOUNDS = (-4, 5)\n_TDIFF_BOUNDS = (-4, 2)\n\ndef normalize_range(data, bounds):\n    return (data - bounds[0]) / (bounds[1] - bounds[0])\n\ndef get_ash_img(band11, band14, band15):\n    r = normalize_range(band15 - band14, _TDIFF_BOUNDS)\n    g = normalize_range(band14 - band11, _CLOUD_TOP_TDIFF_BOUNDS)\n    b = normalize_range(band14, _T11_BOUNDS)\n    false_color = np.clip(np.stack([r, g, b], axis=2), 0, 1)\n    return false_color","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:20:37.452307Z","iopub.execute_input":"2023-08-03T23:20:37.453128Z","iopub.status.idle":"2023-08-03T23:20:37.46105Z","shell.execute_reply.started":"2023-08-03T23:20:37.453079Z","shell.execute_reply":"2023-08-03T23:20:37.460252Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Transfroms","metadata":{}},{"cell_type":"code","source":"train_transform = Compose([ToTensor()])\nval_transform = Compose([ToTensor()])\ntest_transform = Compose([ToTensor()])","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:20:37.463434Z","iopub.execute_input":"2023-08-03T23:20:37.464256Z","iopub.status.idle":"2023-08-03T23:20:37.473881Z","shell.execute_reply.started":"2023-08-03T23:20:37.46422Z","shell.execute_reply":"2023-08-03T23:20:37.473278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n# Data set","metadata":{}},{"cell_type":"code","source":"data_dir: str = '/kaggle/input/google-research-identify-contrails-reduce-global-warming'\n    \ndef get_band_images(idx: str, parrent_folder: str, band: str) -> np.array:\n    return np.load(os.path.join(data_dir, parrent_folder, idx, f'band_{band}.npy'))\n\n\ndef get_ash_values(record_dir, allchannels):\n\n    # get the bands of the record\n    bands_data = []\n        \n    bands_data.append(np.load(os.path.join(record_dir, f'band_11.npy')))\n    bands_data.append(np.load(os.path.join(record_dir, f'band_14.npy')))\n    bands_data.append(np.load(os.path.join(record_dir, f'band_15.npy')))\n        \n    if allchannels: \n        images = get_ash_img(bands_data[0], bands_data[1], bands_data[2])\n        ash = torch.tensor(np.reshape(images, (256, 256, 24))).to(torch.float32).permute(2, 0, 1)\n    \n    else:\n        # Stack band data along the channel axis\n        bands_data = np.stack(bands_data, axis=-1)\n        \n        #This is used to test the 3 channels data\n        band11 = bands_data[:,:,4,0]\n        band14 = bands_data[:,:,4,1]\n        band15 = bands_data[:,:,4,2]\n    \n        #This is used to test the 9 channels data\n        #band11 = np.stack([bands_data[:,:,5,0], bands_data[:,:,4,0], bands_data[:,:,6,0]], axis=-1)\n        #band14 = np.stack([bands_data[:,:,5,1], bands_data[:,:,4,1], bands_data[:,:,6,1]], axis=-1)\n        #band15 = np.stack([bands_data[:,:,5,2], bands_data[:,:,4,2], bands_data[:,:,6,2]], axis=-1)\n        \n        # get the false colour\n        ash = get_ash_img(band11, band14, band15)\n        #ash = torch.tensor(np.reshape(ash, (256, 256, 9))).to(torch.float32).permute(2, 0, 1)\n        \n    return ash\n\nclass contrailsDataset(Dataset):\n    def __init__(self,base_dir:str, mode:str, num_samples:int, transform, allchannels):\n        super().__init__()\n        \n        # init the attributes\n        self.base_dir:str = base_dir\n        self.mode:str = mode\n        self.transform = transform\n        self.records:list[str] = os.listdir(self.base_dir + self.mode)\n        self.allchannels = allchannels\n        \n        # get in-ordered samples in the population\n        self.records = self.records[:num_samples]\n        \n    def get_ash_img(self, bands):\n        band11 = bands[:,:,4,0]\n        band14 = bands[:,:,4,1]\n        band15 = bands[:,:,4,2]\n        return get_ash_img(band11,band14,band15)\n\n    def __getitem__(self, idx):\n        record_id = self.records[idx]\n        record_dir = os.path.join(self.base_dir,self.mode,record_id)\n        \n        ash = get_ash_values(record_dir, self.allchannels)\n        \n        pixel_masks = None        \n         # If the data type is 'train' or 'validation', load the masks\n        if self.mode in ['train', 'validation']:\n            pixel_masks_file = os.path.join(record_dir, 'human_pixel_masks.npy')\n            pixel_masks = np.load(pixel_masks_file)\n            \n            \n        if self.allchannels == False:\n            ash = self.transform(ash)\n            \n        if self.mode != 'test':\n            pixel_masks = self.transform(pixel_masks)\n            sample = {'mask': pixel_masks, 'ash': ash}\n        else:\n            sample = {'ash': ash}\n        return sample\n\n    def __len__(self):\n        return len(self.records)","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:20:37.475998Z","iopub.execute_input":"2023-08-03T23:20:37.476651Z","iopub.status.idle":"2023-08-03T23:20:37.495333Z","shell.execute_reply.started":"2023-08-03T23:20:37.476617Z","shell.execute_reply":"2023-08-03T23:20:37.494466Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainData = contrailsDataset(CONFIG['DATA_ROOT'], mode='train',num_samples=CONFIG['NUM_TRAIN_SAMPLES'], transform=train_transform, allchannels=True)\nvalData = contrailsDataset(CONFIG['DATA_ROOT'], mode='validation',num_samples=CONFIG['NUM_VAL_SAMPLES'], transform=val_transform, allchannels=True)\ntestData = contrailsDataset(CONFIG['DATA_ROOT'], mode='test', num_samples=CONFIG['NUM_TEST_SAMPLES'],transform=test_transform, allchannels=True)\n\n# allchannels binary value is True when we want to test 24 channels input, and false we want to have 3 channels input\n# This takes in 3 channels\ntrainData2 = contrailsDataset(CONFIG['DATA_ROOT'], mode='train',num_samples=CONFIG['NUM_TRAIN_SAMPLES'], transform=train_transform, allchannels=False)\nvalData2 = contrailsDataset(CONFIG['DATA_ROOT'], mode='validation',num_samples=CONFIG['NUM_VAL_SAMPLES'], transform=val_transform, allchannels=False)\ntestData2 = contrailsDataset(CONFIG['DATA_ROOT'], mode='test', num_samples=CONFIG['NUM_TEST_SAMPLES'],transform=test_transform, allchannels=False)","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:20:37.496696Z","iopub.execute_input":"2023-08-03T23:20:37.497274Z","iopub.status.idle":"2023-08-03T23:20:37.867621Z","shell.execute_reply.started":"2023-08-03T23:20:37.497241Z","shell.execute_reply":"2023-08-03T23:20:37.866612Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(trainData), len(valData), len(testData)","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:20:37.869166Z","iopub.execute_input":"2023-08-03T23:20:37.869562Z","iopub.status.idle":"2023-08-03T23:20:37.87663Z","shell.execute_reply.started":"2023-08-03T23:20:37.869527Z","shell.execute_reply":"2023-08-03T23:20:37.875714Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# DataLoader","metadata":{}},{"cell_type":"code","source":"train_dataloader = DataLoader(trainData, \n                              batch_size=CONFIG['BATCH_SIZE'], \n                              shuffle=True)\n\nval_dataloader = DataLoader(valData, \n                            batch_size=CONFIG['BATCH_SIZE'],\n                            shuffle=True)\n\ntest_dataloader = DataLoader(testData, \n                             batch_size=CONFIG['BATCH_SIZE'], \n                             shuffle=False)\n\ntrain_dataloader2 = DataLoader(trainData2, \n                              batch_size=16, \n                              shuffle=True)\n\nval_dataloader2 = DataLoader(valData2, \n                            batch_size=16,\n                            shuffle=True)\n\ntest_dataloader2 = DataLoader(testData2, \n                             batch_size=CONFIG['BATCH_SIZE'], \n                             shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:20:37.878271Z","iopub.execute_input":"2023-08-03T23:20:37.878939Z","iopub.status.idle":"2023-08-03T23:20:37.888108Z","shell.execute_reply.started":"2023-08-03T23:20:37.878906Z","shell.execute_reply":"2023-08-03T23:20:37.88708Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **DATA EXPLORATION AND FORMATION**","metadata":{}},{"cell_type":"code","source":"def data_explotary(all_data_loader, type_data):\n    contrail_image = 0\n    no_contrail_image = 0\n\n\n    for idx, batch in enumerate(all_data_loader): \n        mask = batch['mask']\n        mask = torch.moveaxis(mask,1,-1)\n\n        positive_count = 0\n        negative_count = 0\n        mask2 = mask[0].detach().numpy() \n\n        for row in range(256):\n            for col in range(256):\n                \n                pixel_value = mask2[row, col]\n                if pixel_value == 1:\n                    positive_count += 1\n                else:\n                    negative_count += 1\n\n        if positive_count > 0:\n            contrail_image += 1\n        else:\n            no_contrail_image += 1\n        \n\n    print(\"Number of dataset:\", len(all_train_data))\n    print(\"Number of contrail images:\", contrail_image)\n    print(\"Number of no contrail images:\", no_contrail_image)\n\n    # Data for the pie chart\n    data = [contrail_image, no_contrail_image]\n    labels = ['Contrails Images', 'No Contrails Images']\n\n    # Create a pie chart\n    plt.figure(figsize=(6, 6))\n    plt.pie(data, labels=labels, autopct='%1.1f%%', startangle=90)\n    plt.title(f\"Distribution of Contrails and Non-Contrails Images in the {type_data} Data\")\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:20:37.893346Z","iopub.execute_input":"2023-08-03T23:20:37.893612Z","iopub.status.idle":"2023-08-03T23:20:37.903177Z","shell.execute_reply.started":"2023-08-03T23:20:37.89359Z","shell.execute_reply":"2023-08-03T23:20:37.902055Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_train_data = contrailsDataset(CONFIG['DATA_ROOT'], mode='train',num_samples=1000, transform=train_transform, allchannels=False)\nall_train_data_loader = DataLoader(all_train_data, batch_size=1, shuffle=False)\n\nall_validation_data = contrailsDataset(CONFIG['DATA_ROOT'], mode='validation',num_samples=300, transform=train_transform, allchannels=False)\nall_validation_data_loader = DataLoader(all_validation_data, batch_size=1, shuffle=False)\n\n\n\n# Visualise the composition of contrails dataset in both (1000) training and (300) validation datasets\n# Training\ndata_explotary(all_train_data_loader, 'Training')\n#Validation\ndata_explotary(all_validation_data_loader, 'Validation')\n","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:20:37.904802Z","iopub.execute_input":"2023-08-03T23:20:37.905511Z","iopub.status.idle":"2023-08-03T23:26:57.395002Z","shell.execute_reply.started":"2023-08-03T23:20:37.905479Z","shell.execute_reply":"2023-08-03T23:26:57.391214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Models Loading and Setup","metadata":{}},{"cell_type":"code","source":"ENCODER = 'resnet101'\nENCODER_WEIGHTS = 'imagenet'\n\nACTIVATION = 'sigmoid' # could be None for logits \n\n# create segmentation model with pretrained encoder\n\ndeeplabv3 = smp.DeepLabV3Plus(\n    encoder_name=ENCODER,\n    in_channels=3,\n    encoder_weights=ENCODER_WEIGHTS, \n    classes=1, \n    activation=ACTIVATION,\n).to(device)\n\n\npspnet = smp.PSPNet(\n    encoder_name='mit_b3', \n    encoder_weights=ENCODER_WEIGHTS, \n    classes=1, \n    activation=ACTIVATION,\n).to(device)\n\npspnet2 = smp.PSPNet(\n    encoder_name=ENCODER, \n    in_channels=3,\n    encoder_weights=ENCODER_WEIGHTS, \n    classes=1, \n    activation=ACTIVATION,\n).to(device)\n\n# This is used to test the performances between the 24 transformed to 3 channels approach and other approaches \npspnet = smp.PSPNet(\n    encoder_name=ENCODER, \n    in_channels=3,\n    encoder_weights=ENCODER_WEIGHTS, \n    classes=1, \n    activation=ACTIVATION,\n).to(device)\n\nunet = smp.Unet(\n    encoder_name=ENCODER,\n    in_channels=3,\n    encoder_weights=ENCODER_WEIGHTS, \n    classes=1, \n    activation=ACTIVATION,\n).to(device)","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:26:57.39665Z","iopub.execute_input":"2023-08-03T23:26:57.397123Z","iopub.status.idle":"2023-08-03T23:27:12.085593Z","shell.execute_reply.started":"2023-08-03T23:26:57.397088Z","shell.execute_reply":"2023-08-03T23:27:12.084588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**FCN**","metadata":{}},{"cell_type":"code","source":"# Fully Connected NN\n\n# This is a self coded FCN, which takes in 3 channels and increases it\n# We then applies activation function and maxpooling function\n\n# After 3 rounds, we upsamples the data by using ConvTranspose2d\n# In the future, we can try bilinear interpolation \n\nclass FCN(nn.Module):\n    def __init__(self, num_classes=1):\n        super(FCN, self).__init__()\n        \n        # Encoder\n        self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=(3, 3), stride=1, padding=0)\n        self.relu1 = nn.ReLU()\n        self.maxpool1 = nn.MaxPool2d(kernel_size=(2, 2))\n        \n        self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=(3, 3), stride=1, padding=0)\n        self.relu2 = nn.ReLU()\n        self.maxpool2 = nn.MaxPool2d(kernel_size=(2, 2))\n        \n        self.conv3 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=(3, 3), stride=1, padding=0)\n        self.relu3 = nn.ReLU()\n        \n        # Decoder\n        self.upconv1 = nn.ConvTranspose2d(in_channels=64, out_channels=32, kernel_size=(2, 2), stride=2)\n        self.relu4 = nn.ReLU()\n        \n        self.upconv2 = nn.ConvTranspose2d(in_channels=32, out_channels=num_classes, kernel_size=(2, 2), stride=2)\n\n    def forward(self, x):\n        # Encoder\n        x1 = self.conv1(x)\n        x1 = self.relu1(x1)\n        x1 = self.maxpool1(x1)\n        \n        x2 = self.conv2(x1)\n        x2 = self.relu2(x2)\n        x2 = self.maxpool2(x2)\n        \n        x3 = self.conv3(x2)\n        x3 = self.relu3(x3)\n        \n        # Decoder\n        x4 = self.upconv1(x3)\n        x4 = self.relu4(x4)\n        \n        x5 = self.upconv2(x4)\n\n        return x5\n\n\n","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:27:12.087113Z","iopub.execute_input":"2023-08-03T23:27:12.087688Z","iopub.status.idle":"2023-08-03T23:27:12.103066Z","shell.execute_reply.started":"2023-08-03T23:27:12.087653Z","shell.execute_reply":"2023-08-03T23:27:12.099457Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!rm -rf /kaggle/working/checkpoints\n!mkdir /kaggle/working/checkpoints","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:27:12.10514Z","iopub.execute_input":"2023-08-03T23:27:12.106778Z","iopub.status.idle":"2023-08-03T23:27:14.750239Z","shell.execute_reply.started":"2023-08-03T23:27:12.105819Z","shell.execute_reply":"2023-08-03T23:27:14.748908Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":" # TRAINING","metadata":{}},{"cell_type":"code","source":"# Channel Reduction\n\nclass ChanneReduction(nn.Module):\n    def __init__(self, num_classes=1):\n        super(ChanneReduction, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels=24, out_channels=30, kernel_size=(1,1))\n        self.conv2 = nn.Conv2d(in_channels=30, out_channels=20, kernel_size=(1,1))\n        self.conv3 = nn.Conv2d(in_channels=20, out_channels=10, kernel_size=(1,1))\n        self.conv4 = nn.Conv2d(in_channels=10, out_channels=3, kernel_size=(1,1))\n        \n    def forward(self, x):\n        x1 = self.conv1(x)\n        x1 = self.conv2(x1)\n        x1 = self.conv3(x1)\n        x1 = self.conv4(x1)\n    \n        return x1\n","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:27:14.753534Z","iopub.execute_input":"2023-08-03T23:27:14.754626Z","iopub.status.idle":"2023-08-03T23:27:14.764217Z","shell.execute_reply.started":"2023-08-03T23:27:14.754587Z","shell.execute_reply":"2023-08-03T23:27:14.763223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"f_e = ChanneReduction()\n\n\nclass ProcessedDataDataset(torch.utils.data.Dataset):\n    def __init__(self, data_loader, f_e_model, transform):\n        super().__init__()\n        self.data_loader = data_loader\n        self.f_e_model = f_e_model\n        self.transform = transform\n    def __len__(self):\n        return len(self.data_loader)\n\n    def __getitem__(self, idx):\n        batch = self.data_loader.dataset[idx]\n        mask, ash = batch['mask'], batch['ash']\n        \n        ash = self.f_e_model(ash)\n        \n        sample = {'mask': mask, 'ash': ash}\n        return sample\n\n\n# This is used to transform 24 channels data to 3 channels data by applying the Channel Reduction function     \n    \n# Training Set\nnew_dataset = ProcessedDataDataset(train_dataloader, f_e, train_transform)\nnew_data_loader = DataLoader(new_dataset, batch_size=16, shuffle=True)\n\n# Validation Set\nnew_dataset2 = ProcessedDataDataset(val_dataloader, f_e, train_transform)\nnew_data_loader2 = DataLoader(new_dataset2, batch_size=16, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:27:14.767554Z","iopub.execute_input":"2023-08-03T23:27:14.767845Z","iopub.status.idle":"2023-08-03T23:27:14.783741Z","shell.execute_reply.started":"2023-08-03T23:27:14.767821Z","shell.execute_reply":"2023-08-03T23:27:14.782702Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Visualisation of Data**","metadata":{}},{"cell_type":"code","source":"def images_visualisation(batch): \n    mask, image = batch['mask'], batch['ash']\n\n    image = torch.moveaxis(image,1,-1)\n    mask = torch.moveaxis(mask,1,-1)\n\n    for i in range(1):\n    \n        rgb_img = image[i].detach().numpy()\n        rgb_mask = mask[i].detach().numpy()\n\n        plt.figure(figsize=(18, 6))\n    \n        ax = plt.subplot(1, 3, 1)\n        ax.imshow(rgb_img)\n        ax.set_title('False color image')\n    \n\n        ax = plt.subplot(1, 3, 2)\n        ax.imshow(rgb_mask, interpolation='none')\n        ax.set_title('Ground truth contrail mask')\n        \n        ax = plt.subplot(1, 3, 3)\n        ax.imshow(rgb_img)\n        ax.imshow(rgb_mask, alpha=.4, interpolation='none')\n        ax.set_title('Contrail mask on false color image');\n","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:27:14.785381Z","iopub.execute_input":"2023-08-03T23:27:14.786014Z","iopub.status.idle":"2023-08-03T23:27:14.798012Z","shell.execute_reply.started":"2023-08-03T23:27:14.785975Z","shell.execute_reply":"2023-08-03T23:27:14.79689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Comparision between two different datasets\n\n# This is from the transformed 24-channels-3-channels dataset\nbatch = next(iter(new_data_loader))\nimages_visualisation(batch)\n\n# This is from the 3 channels dataset\nbatch = next(iter(train_dataloader2))\nimages_visualisation(batch)","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:27:14.79993Z","iopub.execute_input":"2023-08-03T23:27:14.801328Z","iopub.status.idle":"2023-08-03T23:27:19.890741Z","shell.execute_reply.started":"2023-08-03T23:27:14.801295Z","shell.execute_reply":"2023-08-03T23:27:19.889551Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def data_visualisation(train):\n    \n    plt.figure(figsize=(18,6))\n    ax = plt.subplot(1, 3, 1)\n    df_data = pd.DataFrame({'Loss': train.epoch_losses})\n    sns.lineplot(data=df_data)\n    ax.set_xlabel('Epoch')\n    ax.set_ylabel('Loss')\n    ax.set_title('Model Average Training Loss over Epochs')\n\n    ax = plt.subplot(1, 3, 2)\n    df_data = pd.DataFrame({'Batch Losses': train.batch_losses})\n    sns.lineplot(data=df_data)\n    ax.set_xlabel('Batch')\n    ax.set_ylabel('Loss')\n    ax.set_title('Batch Loss')\n    \n    ax = plt.subplot(1, 3, 3)\n    df_data = pd.DataFrame({'Loss': train.validation_loss})\n    sns.lineplot(data=df_data)\n    ax.set_xlabel('Epoch')\n    ax.set_ylabel('Loss')\n    ax.set_title('Model Validation Loss over Epochs')\n    \n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:27:19.892622Z","iopub.execute_input":"2023-08-03T23:27:19.89304Z","iopub.status.idle":"2023-08-03T23:27:19.90558Z","shell.execute_reply.started":"2023-08-03T23:27:19.893006Z","shell.execute_reply":"2023-08-03T23:27:19.904718Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_iou_list = []\nvalid_iou_list = []\nvalid_iou_sum = 0\n\n# This code initialises, trains and validates model\nclass training:\n    \n    def __init__(self, model, optimizer, loss_fn):\n        self.validation_loss = []\n        self.batch_losses = []\n        self.epoch_losses = []\n        self.learning_rates = []\n        self.model = model\n        self.optimizer = optimizer\n        self.loss_fn = loss_fn\n    \n    \n    train_iou_list, valid_iou_list = [], []\n    \n    def fit(self, new_data_loader, new_data_loader2, is_implemented, is_fcn):\n        for epoch in range(10):\n            \n            # Perform training & validation steps\n            print('\\nEpoch: {}'.format(epoch+1))\n            \n            print(\"New learning rate: {}\".format(self.optimizer.param_groups[0]['lr']))\n            self.learning_rates.append(self.optimizer.param_groups[0]['lr'])\n        \n             # Stores data about the batch\n            batch_losses = []\n            sub_batch_losses = []\n            \n            self.model.train()\n            # Training loop\n            train_iou, train_loss = 0., 0.\n        \n            for idx, batch in enumerate(new_data_loader): \n            \n                mask, ash = batch['mask'], batch['ash']\n                ash = ash.to(device)                \n                self.optimizer.zero_grad()\n                \n                # forward\n                out = self.model(ash)\n                \n                if is_fcn:\n                    target_size = (240, 240)\n                    mask = mask.float()\n                    mask = F.interpolate(mask, size=target_size, mode='bilinear', align_corners=True)\n                \n                # loss\n                if is_implemented:\n                    mask = mask.float()\n                    mask = mask.cuda()\n\n                    loss = self.loss_fn(out, mask)\n \n                else:\n                    loss = self.loss_fn(out, mask_oh)\n            \n                # backpropagate gradients\n                loss.backward()\n            \n                # optimizer step\n                optimizer.step()         \n\n                train_loss += loss.detach().cpu().numpy()\n            \n                # Saves data\n                self.batch_losses.append(loss.item())\n                batch_losses.append(loss)\n                sub_batch_losses.append(loss)\n            \n                train_iou_list.append(1. * train_iou / len(train_dataloader))\n            \n            # Reports on the path\n            mean_epoch_loss = torch.Tensor(batch_losses).mean()\n            self.epoch_losses.append(mean_epoch_loss.item())\n            print('Train Epoch: {} Average Loss: {:.6f}'.format(idx, mean_epoch_loss))\n            \n            n_train_batches = len(train_dataloader)\n            train_iou_list.append(1. * train_iou / n_train_batches)\n        \n            print(\"\\nValidating\")\n    \n            # Validation loop\n            self.model.eval()\n            with torch.inference_mode():\n                valid = []\n                valid_iou, valid_loss = 0., 0.\n                valid_iou_sum, valid_loss_sum = 0., 0.\n                for idx, batch in enumerate(new_data_loader2):\n                    mask2, ash2 = batch['mask'], batch['ash']\n                \n                    ash2 = ash2.to(device)\n                    out2 = self.model(ash2)\n                    \n                    if is_fcn:\n                        target_size = (240, 240)\n                        mask2 = mask2.float()\n                        mask2 = F.interpolate(mask2, size=target_size, mode='bilinear', align_corners=True)\n                    \n                    # loss\n                    if is_implemented:\n                        mask2 = mask2.float()\n                        mask2 = mask2.cuda()\n                                                             \n                        loss_val = self.loss_fn(out2, mask2)\n                    else:\n                        loss_val = self.loss_fn(out2, mask_oh2)\n\n                    valid_loss += loss_val\n                    valid.append(loss_val.item())\n            \n                n_val_batches = len(val_dataloader)\n    \n                #valid_iou_list.append(1. * valid_iou / n_val_batches)\n                valid_iou_list.append(valid_iou_sum)\n            \n                avg_loss = torch.Tensor(valid).mean().item()\n                print('Train Epoch: {} Average Loss: {:.6f}'.format(idx, avg_loss))\n                self.validation_loss.append(avg_loss)\n                \n        ","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:27:19.907722Z","iopub.execute_input":"2023-08-03T23:27:19.908077Z","iopub.status.idle":"2023-08-03T23:27:20.556062Z","shell.execute_reply.started":"2023-08-03T23:27:19.908048Z","shell.execute_reply":"2023-08-03T23:27:20.554909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# define loss function\ndice_loss = smp.losses.DiceLoss(mode='binary', from_logits=False)\n\n# define optimizer\noptimizer = torch.optim.SGD([ \n    dict(params=deeplabv3.parameters(), lr=0.001),\n])\n\n\ntrain = training(deeplabv3, optimizer, dice_loss)\ntrain.fit(train_dataloader2, val_dataloader2, True, False)\ndata_visualisation(train)\n","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:27:20.558215Z","iopub.execute_input":"2023-08-03T23:27:20.55864Z","iopub.status.idle":"2023-08-03T23:34:22.930316Z","shell.execute_reply.started":"2023-08-03T23:27:20.558575Z","shell.execute_reply":"2023-08-03T23:34:22.929237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n# define loss function\ndice_loss = smp.losses.DiceLoss(mode='binary', from_logits=False)\n\n# define optimizer\noptimizer = torch.optim.SGD([ \n    dict(params=pspnet2.parameters(), lr=0.001),\n])\n\nprint('This is PSPNET')\n\n\ntrain = training(pspnet2, optimizer, dice_loss)\ntrain.fit(train_dataloader2, val_dataloader2, True, False)\n\ndata_visualisation(train)\n\n\n\n\n","metadata":{"execution":{"iopub.status.busy":"2023-08-03T23:34:22.931891Z","iopub.execute_input":"2023-08-03T23:34:22.936535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fcn = FCN().to('cuda')\n\ncriterion = nn.BCEWithLogitsLoss()\noptimizer = torch.optim.SGD(fcn.parameters(), lr=0.08, momentum=0.9)\n\ntrain = training(fcn, optimizer, criterion)\ntrain.fit(train_dataloader2, val_dataloader2, True, True)\ndata_visualisation(train)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('This is a UNET')\n\nunet = unet.to('cuda')\ndice_loss = smp.losses.DiceLoss(mode='binary', from_logits=False)\n\n\ncriterion = nn.BCEWithLogitsLoss()\n\n\n# define optimizer\noptimizer = torch.optim.SGD([ \n    dict(params=unet.parameters(), lr=0.001),\n])\n\ntrain = training(unet, optimizer, criterion)\ntrain.fit(train_dataloader2, val_dataloader2, True, False)\ndata_visualisation(train)\n\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Ensemble Deep Learning Method\n","metadata":{}},{"cell_type":"code","source":"\n# This is the implementation of the Ensemble Model, which takes in the inputs of deeplabv3, pspnet, and unet\n# It then concatenates all the inputs and passes them through a Convol(1x1) and applies the activiation function\n\nclass Ensemble_Stacking(nn.Module):\n    def __init__(self, deeplabv3, pspnet2, unet, num_classes):\n        super(Ensemble_Stacking, self).__init__()\n    \n        # Initialize models as attributes\n        self.deeplabv3 = deeplabv3\n        self.pspnet = pspnet2\n        self.unet = unet\n        \n        # Compute the aggregated results\n        self.stacking_model = nn.Sequential(\n            nn.Conv2d(3, num_classes, kernel_size=1),\n            nn.ReLU() \n        )\n\n    def forward(self, ash):\n\n        deeplab_prediction = self.deeplabv3(ash).squeeze(0)\n        pspnet_prediction = self.pspnet(ash).squeeze(0)\n        unet_prediction = self.unet(ash).squeeze(0)\n            \n        # Stack the predictions along the channel dimension (num_classes = 1)\n        stacked_predictions = torch.cat([deeplab_prediction, pspnet_prediction, unet_prediction], dim=1)\n            \n        # Pass the stacked predictions through the stacking model\n        final_prediction = self.stacking_model(stacked_predictions)\n\n        return final_prediction\n\n\nensemble_model = Ensemble_Stacking(deeplabv3, pspnet2, unet, 1)\nensemble_model.to(device)\n\ndice_loss = smp.losses.DiceLoss(mode='binary', from_logits=False)\ncriterion = nn.BCEWithLogitsLoss()\n\n# define optimizer\noptimizer = torch.optim.SGD([ \n    dict(params=ensemble_model.parameters(), lr=0.001),\n])\n\ntrain = training(ensemble_model, optimizer, criterion)\ntrain.fit(train_dataloader2, val_dataloader2, True, False)\ndata_visualisation(train)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 24 channels transformed to 3 channels approach","metadata":{}},{"cell_type":"code","source":"# To reproduce the performance of 24 channels transformed to 3 channels, uncomment the code below\n\n# From here, \n# define loss function\n#dice_loss = smp.losses.DiceLoss(mode='binary', from_logits=False)\n\n# define optimizer\n#optimizer = torch.optim.SGD([ \n#    dict(params=pspnet.parameters(), lr=0.001),\n#])\n\n#train = training(pspnet, optimizer, dice_loss)\n#train.fit(new_data_loader, new_data_loader2, True, False)\n\n#data_visualisation(train)\n\n# End here. ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prediction","metadata":{}},{"cell_type":"markdown","source":"Predict and Display the image","metadata":{}},{"cell_type":"code","source":"# The prediction image \nwith torch.no_grad():\n    batch = next(iter(val_dataloader2))\n\n    ash = batch['ash']\n    mask = batch['mask']\n\n    ash = ash.to(\"cpu\")\n    mask = mask.to(\"cpu\")\n    \n    \n    # The current model is deeplabv3\n\n    # To visualise others model's inputs,\n    # replace deeplabv3 with the defined names of the models such as fcn, unet, pspnet2   \n    model = deeplabv3.to(\"cpu\")\n    prediction = model(ash)\n    pred_mask = prediction\n\n\n    image = torch.moveaxis(ash,1,-1)\n    mask = torch.moveaxis(mask,1,-1)\n    pred_mask = torch.moveaxis(prediction,1,-1)\n\n\n    image, mask, pred_mask = image.cpu(), mask.cpu(), pred_mask.detach().cpu()\n\n    for i in range(16):\n    \n        img = image[i].detach().numpy()\n        mask_np  = mask[i].detach().numpy()\n        pred = pred_mask[i].detach().numpy()\n    \n        plt.figure(figsize=(18, 6))\n    \n        ax = plt.subplot(1, 3, 1)\n        ax.imshow(img)\n        ax.set_title('False color image')\n    \n\n        ax = plt.subplot(1, 3, 2)\n        ax.imshow(mask_np , interpolation='none')\n        ax.set_title('Ground truth contrail mask')\n    \n        ax = plt.subplot(1, 3, 3)\n        ax.imshow(pred, interpolation='none')\n        ax.set_title('Predicted_Mask')\n    \n    \n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n\n","metadata":{}}]}