{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"#### This notebook:\n1. Converts the npy files into ash transformed data to be ingested by the model\n    (ref: https://www.kaggle.com/code/soumyadeepkhandual/unet-trained-weights)\n    \n2. Creates a tensorflow model with a U-Net architecture\n3. Creates batches for training\n4. Trains the neural network\n\n\n\n#### Issues to be fixed:\n1. Image transformation to be sped up (ETC: 20th May)\n\n2. RLE submissions to be included     (ETC: 21st May)\n\n3. Architecture to be cleaned up      (ETC: 22nd May)\n\n4. Reading of files to be sped up     (ETC: 24th May)\n\n\nNaive submissions can be made using this file. Integrate RLE from here (https://www.kaggle.com/code/inversion/contrails-rle-submission) to do submissions","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-05-17T14:25:08.123439Z","iopub.execute_input":"2023-05-17T14:25:08.123808Z","iopub.status.idle":"2023-05-17T14:25:08.132086Z","shell.execute_reply.started":"2023-05-17T14:25:08.123779Z","shell.execute_reply":"2023-05-17T14:25:08.130924Z"}}},{"cell_type":"markdown","source":"# Create the neural network architecture","metadata":{}},{"cell_type":"code","source":"import os\nimport tensorflow as tf\n# from read_data import read_contrail_images\nfrom keras.layers import Input\nfrom keras.layers import Conv2D\nfrom keras.layers import MaxPooling2D\nfrom keras.layers import Dropout\nfrom keras.layers import Conv2DTranspose\nfrom keras.layers import concatenate\nfrom keras import backend as K\nimport numpy as np\n\ndef conv_block(inputs, n_filters, dropout_prob=0.1, max_pooling=True):\n    \"\"\"\n    Convolutional downsampling block\n\n    Arguments:\n        inputs -- Input tensor\n        n_filters -- Number of filters for the convolutional layers\n        dropout_prob -- Dropout probability\n        max_pooling -- Use MaxPooling2D to reduce the spatial dimensions of the output volume\n    Returns:\n        next_layer, skip_connection --  Next layer and skip connection outputs\n    \"\"\"\n\n    ### START CODE HERE\n    conv = Conv2D(n_filters,  # Number of filters\n                  3,  # Kernel size\n                  activation='relu',\n                  padding='same',\n                  kernel_initializer='he_normal')(inputs)\n\n    conv = Conv2D(n_filters,  # Number of filters\n                  3,  # Kernel size\n                  activation='relu',\n                  padding='same',\n                  # set 'kernel_initializer' same as above\n                  kernel_initializer='he_normal')(conv)\n    ### END CODE HERE\n\n    # if dropout_prob > 0 add a dropout layer, with the variable dropout_prob as parameter\n    if dropout_prob > 0:\n        ### START CODE HERE\n        conv = Dropout(dropout_prob)(conv)\n        ### END CODE HERE\n\n    # if max_pooling is True add a MaxPooling2D with 2x2 pool_size\n    if max_pooling:\n        ### START CODE HERE\n        next_layer = MaxPooling2D(2, strides=2)(conv)\n        ### END CODE HERE\n\n    else:\n        next_layer = conv\n\n    skip_connection = conv\n\n    return next_layer, skip_connection\n\n\ndef upsampling_block(expansive_input, contractive_input, n_filters):\n    \"\"\"\n    Convolutional upsampling block\n\n    Arguments:\n        expansive_input -- Input tensor from previous layer\n        contractive_input -- Input tensor from previous skip layer\n        n_filters -- Number of filters for the convolutional layers\n    Returns:\n        conv -- Tensor output\n    \"\"\"\n\n    ### START CODE HERE\n    up = Conv2DTranspose(\n        n_filters,  # number of filters\n        3,  # Kernel size\n        strides=2,\n        padding='same')(expansive_input)\n\n    # Merge the previous output and the contractive_input\n    merge = concatenate([up, contractive_input], axis=3)\n    conv = Conv2D(n_filters,  # Number of filters\n                  3,  # Kernel size\n                  activation='relu',\n                  padding='same',\n                  kernel_initializer='he_normal')(merge)\n\n    conv = Conv2D(n_filters,  # Number of filters\n                  3,  # Kernel size\n                  activation='relu',\n                  padding='same',\n                  # set 'kernel_initializer' same as above\n                  kernel_initializer='he_normal')(conv)\n    ### END CODE HERE\n\n    return conv\n\n\ndef unet_model(input_size, n_filters, n_classes):\n    \"\"\"\n    Unet model\n\n    Arguments:\n        input_size -- Input shape\n        n_filters -- Number of filters for the convolutional layers\n        n_classes -- Number of output classes\n    Returns:\n        model -- tf.keras.Model\n    \"\"\"\n    inputs = Input(input_size)\n    # Contracting Path (encoding)\n    # Add a conv_block with the inputs of the unet_ model and n_filters\n    ### START CODE HERE\n    cblock1 = conv_block(inputs=inputs, n_filters=n_filters * 1)\n    # Chain the first element of the output of each block to be the input of the next conv_block.\n    # Double the number of filters at each new step\n    cblock2 = conv_block(inputs=cblock1[0], n_filters=n_filters * 2)\n    cblock3 = conv_block(inputs=cblock2[0], n_filters=n_filters * 4)\n    cblock4 = conv_block(inputs=cblock3[0], n_filters=n_filters * 8,\n                         dropout_prob=0.3)  # Include a dropout_prob of 0.3 for this layer\n    # Include a dropout_prob of 0.3 for this layer, and avoid the max_pooling layer\n    cblock5 = conv_block(inputs=cblock4[0], n_filters=n_filters * 16, dropout_prob=0.3, max_pooling=False)\n    ### END CODE HERE\n\n    # Expanding Path (decoding)\n    # Add the first upsampling_block.\n    # Use the cblock5[0] as expansive_input and cblock4[1] as contractive_input and n_filters * 8\n    ### START CODE HERE\n    ublock6 = upsampling_block(cblock5[0], cblock4[1], n_filters * 8)\n    # Chain the output of the previous block as expansive_input and the corresponding contractive block output.\n    # Note that you must use the second element of the contractive block i.e before the maxpooling layer.\n    # At each step, use half the number of filters of the previous block\n    ublock7 = upsampling_block(ublock6, cblock3[1], n_filters * 4)\n    ublock8 = upsampling_block(ublock7, cblock2[1], n_filters * 2)\n    ublock9 = upsampling_block(ublock8, cblock1[1], n_filters * 1)\n    ### END CODE HERE\n\n    conv9 = Conv2D(n_filters,\n                   3,\n                   activation='relu',\n                   padding='same',\n                   # set 'kernel_initializer' same as above exercises\n                   kernel_initializer='he_normal')(ublock9)\n\n    # Add a Conv2D layer with n_classes filter, kernel size of 1 and a 'same' padding\n    ### START CODE HERE\n    conv10 = Conv2D(n_classes, 1, padding='same')(conv9)\n    ### END CODE HERE\n\n    model = tf.keras.Model(inputs=inputs, outputs=conv10)\n\n    return model\n\n\ndef upsampling_block(expansive_input, contractive_input, n_filters=32):\n    \"\"\"\n    Convolutional upsampling block\n\n    Arguments:\n        expansive_input -- Input tensor from previous layer\n        contractive_input -- Input tensor from previous skip layer\n        n_filters -- Number of filters for the convolutional layers\n    Returns:\n        conv -- Tensor output\n    \"\"\"\n\n    ### START CODE HERE\n    up = Conv2DTranspose(\n        n_filters,  # number of filters\n        3,  # Kernel size\n        strides=2,\n        padding='same')(expansive_input)\n\n    # Merge the previous output and the contractive_input\n    merge = concatenate([up, contractive_input], axis=3)\n    conv = Conv2D(n_filters,  # Number of filters\n                  3,  # Kernel size\n                  activation='relu',\n                  padding='same',\n                  kernel_initializer='he_normal')(merge)\n\n    conv = Conv2D(n_filters,  # Number of filters\n                  3,  # Kernel size\n                  activation='relu',\n                  padding='same',\n                  # set 'kernel_initializer' same as above\n                  kernel_initializer='he_normal')(conv)\n    ### END CODE HERE\n\n    return conv\n\n\ndef unet_model(input_size, n_filters, n_classes):\n    \"\"\"\n    Unet model\n\n    Arguments:\n        input_size -- Input shape\n        n_filters -- Number of filters for the convolutional layers\n        n_classes -- Number of output classes\n    Returns:\n        model -- tf.keras.Model\n    \"\"\"\n    inputs = Input(input_size)\n    # Contracting Path (encoding)\n    # Add a conv_block with the inputs of the unet_ model and n_filters\n    ### START CODE HERE\n    cblock1 = conv_block(inputs=inputs, n_filters=n_filters * 1)\n    # Chain the first element of the output of each block to be the input of the next conv_block.\n    # Double the number of filters at each new step\n    cblock2 = conv_block(inputs=cblock1[0], n_filters=n_filters * 2)\n    cblock3 = conv_block(inputs=cblock2[0], n_filters=n_filters * 4)\n    cblock4 = conv_block(inputs=cblock3[0], n_filters=n_filters * 8,\n                         dropout_prob=0.3)  # Include a dropout_prob of 0.3 for this layer\n    # Include a dropout_prob of 0.3 for this layer, and avoid the max_pooling layer\n    cblock5 = conv_block(inputs=cblock4[0], n_filters=n_filters * 16, dropout_prob=0.3, max_pooling=False)\n    ### END CODE HERE\n\n    # Expanding Path (decoding)\n    # Add the first upsampling_block.\n    # Use the cblock5[0] as expansive_input and cblock4[1] as contractive_input and n_filters * 8\n    ### START CODE HERE\n    ublock6 = upsampling_block(cblock5[0], cblock4[1], n_filters * 8)\n    # Chain the output of the previous block as expansive_input and the corresponding contractive block output.\n    # Note that you must use the second element of the contractive block i.e before the maxpooling layer.\n    # At each step, use half the number of filters of the previous block\n    ublock7 = upsampling_block(ublock6, cblock3[1], n_filters * 4)\n    ublock8 = upsampling_block(ublock7, cblock2[1], n_filters * 2)\n    ublock9 = upsampling_block(ublock8, cblock1[1], n_filters * 1)\n    ### END CODE HERE\n\n    conv9 = Conv2D(n_filters,\n                   3,\n                   activation='relu',\n                   padding='same',\n                   # set 'kernel_initializer' same as above exercises\n                   kernel_initializer='he_normal')(ublock9)\n\n    # Add a Conv2D layer with n_classes filter, kernel size of 1 and a 'same' padding\n    ### START CODE HERE\n    conv10 = Conv2D(1, 1, padding='same')(conv9)\n    ### END CODE HERE\n\n    model = tf.keras.Model(inputs=inputs, outputs=conv10)\n\n    return model\n\n\ndef dice_coef_loss(y_true, y_pred):\n    smooth = 1.\n    y_true_f = K.flatten(y_true)\n    y_pred_f = K.flatten(y_pred)\n    intersection = y_true_f * y_pred_f\n    score = (2. * K.sum(intersection) + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)\n    return 1. - score\n\ndef model_creation(img_height, img_width, num_channels):\n    unet = unet_model((img_height, img_width, num_channels), 32, 3)\n\n    unet.compile(optimizer='adam',\n                  # loss=tf.keras.losses.MeanSquaredError(),\n                  loss=dice_coef_loss,\n                 metrics=['accuracy'])\n\n    return unet","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:51:28.677525Z","iopub.execute_input":"2023-05-17T20:51:28.677887Z","iopub.status.idle":"2023-05-17T20:51:28.707803Z","shell.execute_reply.started":"2023-05-17T20:51:28.677859Z","shell.execute_reply":"2023-05-17T20:51:28.70686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\n\nprint(np.__version__)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Transform the dataset","metadata":{}},{"cell_type":"code","source":"\n\ndef get_parameters(base_dir, start, end):\n    # base_dir = r\"C:\\Competitions\\Contrails_new\"\n    train_path = os.path.join(base_dir, \"train\")\n    test_path = os.path.join(base_dir, \"test\")\n    val_path = os.path.join(base_dir, \"validation\")\n#     start = 1000\n#     end = 2000\n    train_ids = os.listdir(train_path)[start:end]\n    test_ids = os.listdir(test_path)[0:2]\n    val_ids = os.listdir(val_path)[int(start/10):int(end/10)]\n    return {'train_ids': train_ids, 'train_path': train_path, 'test_ids': test_ids, 'test_path': test_path,\n            'val_ids': val_ids,\n            'val_path': val_path}\n\n\ndef ash_transform(x, time_frame: int = 4):\n    time_frame = 4\n    _T11_BOUNDS = (243, 303)\n    _CLOUD_TOP_TDIFF_BOUNDS = (-4, 5)\n    _TDIFF_BOUNDS = (-4, 2)\n    if time_frame is not None:\n        x = x[:, time_frame, :, :]\n\n    def normalize_range(data, bounds):\n        \"\"\"Maps data to the range [0, 1].\"\"\"\n        return (data - bounds[0]) / (bounds[1] - bounds[0])\n\n    r = normalize_range(x[2] - x[1], _TDIFF_BOUNDS)\n    g = normalize_range(x[1] - x[0], _CLOUD_TOP_TDIFF_BOUNDS)\n    b = normalize_range(x[1], _T11_BOUNDS)\n    return np.clip(np.stack([r, g, b], axis=-3), 0, 1)  # (T,3,H,W) or (3,H,W)\n\n\nclass ContrailDataset():\n    def __init__(self, ids, base_dir, bands=None, transforms: list = [], test_mode: bool = False):\n        self.ids = ids\n        self.base_dir = base_dir\n        self.transforms = transforms\n        self.bands = bands\n        self.permute = (2, 0, 1)\n        self.test_mode = test_mode\n\n    def __iter__(self):\n        for element in range(self.__len__()):\n            yield self.__getitem__(element)\n\n    def __getitem__(self, index):\n        record_id = self.ids[index]\n\n        if self.bands is None:\n            band_list = [f'band_{band:02d}.npy' for band in range(8, 17)]\n        else:\n            band_list = [f'band_{int(band):02d}.npy' for band in self.bands]\n\n        x = list()\n        for band in band_list:\n            x_path = os.path.join(self.base_dir, record_id, band)\n            x.append(np.load(x_path).transpose(self.permute))\n#             x.append(np.load(x_path))\n\n        x = np.stack(x, axis=0)  ## X.shape = (Band,Time_frame,H,W)\n\n        for transformation in self.transforms:\n            x = transformation(x)\n        x = tf.convert_to_tensor(x, tf.float32)\n        x = tf.reshape(x, [256, 256, 3])\n\n        if self.test_mode:\n            return x\n        else:\n            y_path = os.path.join(self.base_dir, record_id, 'human_pixel_masks.npy')\n            y = tf.convert_to_tensor(np.load(y_path).transpose(self.permute), tf.float32)\n\n            return x, y\n\n    def __len__(self):\n        return len(self.ids)\n\n\n# Datasets\ndataset_params = {\n    \"bands\": [11, 14, 15],\n    \"transforms\": [ash_transform]\n}\n\n\ndef return_x_y(train_ids, train_path, test_ids, test_path, val_ids, val_path):\n    train_dataset = ContrailDataset(train_ids, train_path, **dataset_params)\n    test_dataset = ContrailDataset(test_ids, test_path, test_mode=True, **dataset_params)\n    val_dataset = ContrailDataset(val_ids, val_path, **dataset_params)\n    return train_dataset, test_dataset, val_dataset\n\n# base_dir = r\"C:\\Competitions\\Contrails_new\"\ndef return_x_y_train_test(base_path, start, end):\n    return return_x_y(**get_parameters(base_path, start, end))\n\n\n","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:51:38.396201Z","iopub.execute_input":"2023-05-17T20:51:38.396594Z","iopub.status.idle":"2023-05-17T20:51:38.416085Z","shell.execute_reply.started":"2023-05-17T20:51:38.396559Z","shell.execute_reply":"2023-05-17T20:51:38.41491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train","metadata":{}},{"cell_type":"code","source":"# img_height = 256\n# img_width = 256\n# num_channels = 3\n\n# over_images = []\n# batch_size = 1\n# epochs = 100\n\n# model = model_creation(img_height, img_width, num_channels)\n# # print(model.summary())\n# base_path = r'/kaggle/input/google-research-identify-contrails-reduce-global-warming'\n# over_images = []\n# batch_size = 1\n# images = os.listdir(base_path)\n\n# for i in range(200):\n#     try:\n#         start = i*100\n#         end = (i+1)*100\n#         train_dataset, test_dataset, val_dataset = return_x_y_train_test(base_path, start, end)\n#         x_train, y_train = tuple(zip(*train_dataset))\n#         x_train = tf.stack(x_train)\n#         y_train = tf.stack(y_train)\n#         x_val, y_val = tuple(zip(*val_dataset))\n#         x_val = tf.stack(x_val)\n#         y_val = tf.stack(y_val)\n#         history = model.fit( x_train, y_train, batch_size=10, epochs=2, validation_data=(x_val, y_val))\n#     except Exception as e:\n#         print(e)\n#     # with tf.device('/device:GPU:0'):\n#     #     history = model.fit(x_train,y_train, epochs=epochs, verbose=1)\n","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:51:42.364062Z","iopub.execute_input":"2023-05-17T20:51:42.364461Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# with tf.device('GPU:0'):\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}