{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":9988,"databundleVersionId":868324,"sourceType":"competition"}],"dockerImageVersionId":30636,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\nfrom matplotlib.image import imread\nfrom tensorflow.keras.utils import Sequence\nfrom tensorflow.keras import layers, models\nfrom keras import backend as K\nfrom skimage.measure import label, regionprops\nfrom sklearn.model_selection import train_test_split","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-01-13T09:31:06.886349Z","iopub.execute_input":"2024-01-13T09:31:06.887095Z","iopub.status.idle":"2024-01-13T09:31:20.115754Z","shell.execute_reply.started":"2024-01-13T09:31:06.887065Z","shell.execute_reply":"2024-01-13T09:31:20.114774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load data","metadata":{}},{"cell_type":"code","source":"train_segmentations = pd.read_csv('/kaggle/input/airbus-ship-detection/train_ship_segmentations_v2.csv')\nsample_submission = pd.read_csv('/kaggle/input/airbus-ship-detection/sample_submission_v2.csv')\n\ntrain_v2_path = '/kaggle/input/airbus-ship-detection/train_v2'","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:20.117492Z","iopub.execute_input":"2024-01-13T09:31:20.118133Z","iopub.status.idle":"2024-01-13T09:31:21.302340Z","shell.execute_reply.started":"2024-01-13T09:31:20.118103Z","shell.execute_reply":"2024-01-13T09:31:21.301511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# EDA","metadata":{}},{"cell_type":"code","source":"print(f'train samples - {train_segmentations.shape[0]}')\ntrain_segmentations.head()","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:24.127603Z","iopub.execute_input":"2024-01-13T09:31:24.128459Z","iopub.status.idle":"2024-01-13T09:31:24.146400Z","shell.execute_reply.started":"2024-01-13T09:31:24.128427Z","shell.execute_reply":"2024-01-13T09:31:24.145304Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def display_images(folder_path, num_images=10, num_columns=5):\n    # Get a list of all files in the folder\n    image_files = [f for f in os.listdir(folder_path)[:num_images]]\n\n    # Calculate the number of rows needed\n    num_rows = (num_images + num_columns - 1) // num_columns\n\n    # Display the images in a grid\n    fig, axes = plt.subplots(num_rows, num_columns, figsize=(15, 6))\n\n    for i in range(num_images):\n        img_path = os.path.join(folder_path, image_files[i])\n        img = imread(img_path)\n        row_index, col_index = divmod(i, num_columns)\n        axes[row_index, col_index].imshow(img)\n        axes[row_index, col_index].axis('off')\n\n    plt.show()\n\ndisplay_images(train_v2_path, num_images=21, num_columns=7)","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:25.033276Z","iopub.execute_input":"2024-01-13T09:31:25.033999Z","iopub.status.idle":"2024-01-13T09:31:29.525534Z","shell.execute_reply.started":"2024-01-13T09:31:25.033968Z","shell.execute_reply":"2024-01-13T09:31:29.524564Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Run-length encoding (RLE)","metadata":{}},{"cell_type":"markdown","source":"To minimize the submission file size, the metric employs run-length encoding on pixel values. Consequently, it becomes necessary to define functions for both encoding and decoding processes.To minimize the submission file size, the metric employs run-length encoding on pixel values. Consequently, it becomes necessary to define functions for both encoding and decoding processes.","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:27:51.843943Z","iopub.execute_input":"2024-01-13T09:27:51.844656Z","iopub.status.idle":"2024-01-13T09:27:51.878958Z","shell.execute_reply.started":"2024-01-13T09:27:51.844592Z","shell.execute_reply":"2024-01-13T09:27:51.876622Z"}}},{"cell_type":"code","source":"def rle_encode(img):\n    \"\"\"\n    Encode a binary mask represented as a 2D numpy array using Run-Length Encoding (RLE).\n\n    Parameters:\n    - img (numpy.ndarray): A 2D binary array representing the mask.\n\n    Returns:\n    - str: The RLE-encoded string representing the binary mask.\n    \"\"\"\n\n    pixels = img.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    return ' '.join(str(x) for x in runs)\n\n\ndef rle_decode(mask_rle, shape=(768, 768)):\n    \"\"\"\n    Decode a Run-Length Encoded (RLE) binary mask into a 2D numpy array.\n\n    Parameters:\n    - mask_rle (str): The RLE-encoded string representing the binary mask.\n    - shape (tuple, optional): The shape of the target 2D array. Default is (768, 768).\n\n    Returns:\n    - numpy.ndarray: A 2D binary array representing the decoded mask.\n    \"\"\"\n\n    if type(mask_rle) != str:\n        return np.zeros(shape)\n\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    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n\n    return img.reshape(shape).T # Needed to align to RLE direction","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:30.372841Z","iopub.execute_input":"2024-01-13T09:31:30.373282Z","iopub.status.idle":"2024-01-13T09:31:30.383204Z","shell.execute_reply.started":"2024-01-13T09:31:30.373240Z","shell.execute_reply":"2024-01-13T09:31:30.382126Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def display_masks(folder_path, csv_file, num_images=5):\n    # Get a list of all files in the folder\n    image_files = [f for f in os.listdir(folder_path)[:num_images]]\n\n    # Calculate the number of rows needed\n    num_rows = 2\n\n    # Display the images in a grid\n    fig, axes = plt.subplots(num_rows, num_images, figsize=(15, 6))\n\n    for i in range(num_images):\n        img_path = os.path.join(folder_path, image_files[i])\n        img = imread(img_path)\n\n        all_masks = csv_file[csv_file['ImageId'] == image_files[i]].EncodedPixels\n        mask = np.zeros((768, 768))\n        for m in all_masks:\n            mask += rle_decode(m)\n        \n        axes[0, i].imshow(img)\n        axes[0, i].axis('off')\n\n        axes[1, i].imshow(mask)\n        axes[1, i].axis('off')\n\n    plt.show()\n\ndisplay_masks(train_v2_path, csv_file=train_segmentations, num_images=5)","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:31.307363Z","iopub.execute_input":"2024-01-13T09:31:31.307762Z","iopub.status.idle":"2024-01-13T09:31:32.679210Z","shell.execute_reply.started":"2024-01-13T09:31:31.307718Z","shell.execute_reply":"2024-01-13T09:31:32.678295Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Images without ships","metadata":{}},{"cell_type":"code","source":"images_with_ships = train_segmentations[train_segmentations.EncodedPixels.notna()].ImageId.nunique()\nimages_without_ships = train_segmentations[train_segmentations.EncodedPixels.isna()].ImageId.nunique()\n\nprint(f'Number of images with ships    - {images_with_ships}  | {round(images_with_ships / train_segmentations.ImageId.nunique() * 100)}%')\nprint(f'Number of images without ships - {images_without_ships} | {round(images_without_ships / train_segmentations.ImageId.nunique() * 100)}%')","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:32.680690Z","iopub.execute_input":"2024-01-13T09:31:32.681002Z","iopub.status.idle":"2024-01-13T09:31:32.900400Z","shell.execute_reply.started":"2024-01-13T09:31:32.680975Z","shell.execute_reply":"2024-01-13T09:31:32.899090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create subplots\nfig, axes = plt.subplots(1, 2, figsize=(15, 4))\n\n# Plot bar chart\naxes[0].bar(['No ships', 'Ships'], [images_without_ships, images_with_ships], color=plt.cm.viridis([0.2, 0.8]))\naxes[0].set_title('Distribution of Ships')\naxes[0].set_ylabel('Count')\naxes[0].grid(axis='y', linestyle='--', alpha=0.7)\n\n# Plot pie chart\naxes[1].pie([images_without_ships, images_with_ships], labels=['No ships', 'Ships'], autopct='%1.1f%%',\n            startangle=90, colors=plt.cm.viridis([0.2, 0.8]), wedgeprops={\"linewidth\": 1, \"edgecolor\": \"white\"})\naxes[1].set_title('Percentage of Ships')\naxes[1].set_aspect('equal')  # Equal aspect ratio ensures that pie is drawn as a circle\n\n# Display the plot\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:32.902317Z","iopub.execute_input":"2024-01-13T09:31:32.903495Z","iopub.status.idle":"2024-01-13T09:31:33.272838Z","shell.execute_reply.started":"2024-01-13T09:31:32.903457Z","shell.execute_reply":"2024-01-13T09:31:33.271932Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Number of Ships Distribution","metadata":{}},{"cell_type":"code","source":"n_ships_df = train_segmentations.dropna().groupby('ImageId').count()\nn_ships_df.rename({'EncodedPixels': 'n_ships'}, axis='columns', inplace=True)\n\nn_ships_df.describe()","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:39.671085Z","iopub.execute_input":"2024-01-13T09:31:39.671820Z","iopub.status.idle":"2024-01-13T09:31:39.794892Z","shell.execute_reply.started":"2024-01-13T09:31:39.671775Z","shell.execute_reply":"2024-01-13T09:31:39.793937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(10, 4))\nplt.title('Number of Ships Distribution')\nplt.xlabel('Number of Ships')\nplt.ylabel('Count')\nplt.bar(range(1, 16), n_ships_df.n_ships.value_counts(), color=plt.cm.viridis([0.2, 0.8]));","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:40.095634Z","iopub.execute_input":"2024-01-13T09:31:40.096489Z","iopub.status.idle":"2024-01-13T09:31:40.450245Z","shell.execute_reply.started":"2024-01-13T09:31:40.096454Z","shell.execute_reply":"2024-01-13T09:31:40.449263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_ships_df.n_ships.value_counts()","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:40.452169Z","iopub.execute_input":"2024-01-13T09:31:40.452775Z","iopub.status.idle":"2024-01-13T09:31:40.460636Z","shell.execute_reply.started":"2024-01-13T09:31:40.452716Z","shell.execute_reply":"2024-01-13T09:31:40.459696Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preparing Train and Validation Data","metadata":{}},{"cell_type":"code","source":"def split_data(data, empty_masks=2000, test_size=0.3, random_state=42):\n    \"\"\"\n    Parameters:\n    - data (DataFrame): The input DataFrame containing the dataset.\n    - empty_masks (int, optional): The number of images with empty masks. Defaults to 2000.\n    - test_size (float, optional): The proportion of the dataset to include in the test split. Defaults to 0.3.\n    - random_state (int, optional): Seed for random number generation to ensure reproducibility. Defaults to 42.\n\n    Returns: The training and testing sets.\n    \"\"\"\n\n    masks_df = data.copy()\n\n    # Create binary labels for the presence of ships in each image. Count the number of ships in each image.\n    masks_df['ship'] = masks_df['EncodedPixels'].map(lambda c_row: 1 if isinstance(c_row, str) else 0)\n    masks_df['n_ships'] = masks_df.groupby('ImageId')['ship'].transform('sum')\n    masks_df.drop_duplicates(subset='ImageId', keep='first', inplace=True)\n\n    # Keep only n empty masks\n    empty_masks_df = masks_df[masks_df.ship == 0]\n    masks_df = masks_df[masks_df.ship == 1]\n    masks_df = pd.concat([masks_df, empty_masks_df.sample(n=empty_masks, random_state=random_state)], axis=0)\n\n    # Stratified split based on the number of ships in each image\n    train_ids, test_ids = train_test_split(masks_df, test_size=test_size, stratify=masks_df['n_ships'].values,\n                                           random_state=random_state)\n\n    train_data = data[data['ImageId'].isin(train_ids.ImageId)]\n    test_data = data[data['ImageId'].isin(test_ids.ImageId)]\n\n    return train_data, test_data\n\n\ntrain_data, val_data = split_data(train_segmentations, empty_masks=2000, test_size=0.2)\n\nprint(f'Number of masks in train data - {train_data.shape[0]}')\nprint(f'Number of masks in test data - {val_data.shape[0]}')","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:41.191259Z","iopub.execute_input":"2024-01-13T09:31:41.191622Z","iopub.status.idle":"2024-01-13T09:31:41.717232Z","shell.execute_reply.started":"2024-01-13T09:31:41.191590Z","shell.execute_reply":"2024-01-13T09:31:41.716284Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# CustomDataGenerator","metadata":{}},{"cell_type":"code","source":"class CustomDataGenerator(Sequence):\n    def __init__(self, image_folder, csv_file, batch_size=32, image_size=(768, 768)):\n        self.image_folder = image_folder\n        self.batch_size = batch_size\n        self.image_size = image_size\n        self.data = csv_file\n\n    def __len__(self):\n        return int(len(self.data) / self.batch_size)\n\n    def __getitem__(self, index):\n        batch_data = self.data[index * self.batch_size:(index + 1) * self.batch_size]\n\n        X = []\n        y = []\n\n        for _, row in batch_data.iterrows():\n            image_path = os.path.join(self.image_folder, row['ImageId'])\n\n            # Load image\n            img = cv2.imread(image_path)\n            img = cv2.resize(img, self.image_size)\n            img = img / 255.0  # Normalize\n\n            # Decode RLE to mask\n            all_masks = self.data[self.data['ImageId'] == row['ImageId']].EncodedPixels\n            mask = np.zeros(self.image_size)\n            for m in all_masks:\n                decoded_mask = rle_decode(m)\n                mask += cv2.resize(decoded_mask, self.image_size)\n\n            mask = mask.astype(float)\n\n            X.append(img)\n            y.append(mask)\n\n        return np.array(X), np.array(y)","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:41.871162Z","iopub.execute_input":"2024-01-13T09:31:41.872103Z","iopub.status.idle":"2024-01-13T09:31:41.881767Z","shell.execute_reply.started":"2024-01-13T09:31:41.872066Z","shell.execute_reply":"2024-01-13T09:31:41.880796Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size = 16\nimage_size = (256, 256)\n\ntrain_generator = CustomDataGenerator(image_folder=train_v2_path,\n                                      csv_file=train_data,\n                                      batch_size=batch_size,\n                                      image_size=image_size)\n\nval_generator = CustomDataGenerator(image_folder=train_v2_path,\n                                     csv_file=val_data,\n                                     batch_size=batch_size,\n                                     image_size=image_size)","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:42.302682Z","iopub.execute_input":"2024-01-13T09:31:42.303477Z","iopub.status.idle":"2024-01-13T09:31:42.308513Z","shell.execute_reply.started":"2024-01-13T09:31:42.303441Z","shell.execute_reply":"2024-01-13T09:31:42.307532Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Define U-Net Model","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.layers import Conv2D, BatchNormalization, Activation, MaxPool2D, Conv2DTranspose, Concatenate, Input\nfrom tensorflow.keras.models import Model\n\n\ndef conv_block(input, num_filters):\n    x = Conv2D(num_filters, 3, padding=\"same\")(input)\n    x = BatchNormalization()(x)\n    x = Activation(\"relu\")(x)\n\n    x = Conv2D(num_filters, 3, padding=\"same\")(x)\n    x = BatchNormalization()(x)\n    x = Activation(\"relu\")(x)\n\n    return x\n\n\ndef encoder_block(input, num_filters):\n    x = conv_block(input, num_filters)\n    p = MaxPool2D((2, 2))(x)\n    return x, p\n\n\ndef decoder_block(input, skip_features, num_filters):\n    x = Conv2DTranspose(num_filters, (2, 2), strides=2, padding=\"same\")(input)\n    x = Concatenate()([x, skip_features])\n    x = conv_block(x, num_filters)\n    return x\n\n\ndef build_unet(input_shape=(256, 256, 3)):\n    inputs = Input(input_shape)\n\n    s1, p1 = encoder_block(inputs, 64)\n    s2, p2 = encoder_block(p1, 128)\n    s3, p3 = encoder_block(p2, 256)\n    s4, p4 = encoder_block(p3, 512)\n\n    b1 = conv_block(p4, 1024)\n\n    d1 = decoder_block(b1, s4, 512)\n    d2 = decoder_block(d1, s3, 256)\n    d3 = decoder_block(d2, s2, 128)\n    d4 = decoder_block(d3, s1, 64)\n\n    outputs = Conv2D(1, 1, padding=\"same\", activation=\"sigmoid\")(d4)\n\n    model = Model(inputs, outputs, name=\"U-Net\")\n    return model\n\n\n# Create the UNet model\nmodel = build_unet()\n\n# Display the model summary\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:43.166815Z","iopub.execute_input":"2024-01-13T09:31:43.167697Z","iopub.status.idle":"2024-01-13T09:31:44.778636Z","shell.execute_reply.started":"2024-01-13T09:31:43.167662Z","shell.execute_reply":"2024-01-13T09:31:44.777649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau\n\nreduceLROnPlate = ReduceLROnPlateau(monitor='val_loss', factor=0.33, patience=1, verbose=1, mode='min', min_delta=0.0001, cooldown=0, min_lr=1e-8)\nearly_stopping = EarlyStopping(monitor=\"val_loss\", mode=\"min\", verbose=0, patience=10)\n\ncallbacks_list = [reduceLROnPlate, early_stopping]","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:44.780793Z","iopub.execute_input":"2024-01-13T09:31:44.781414Z","iopub.status.idle":"2024-01-13T09:31:44.789709Z","shell.execute_reply.started":"2024-01-13T09:31:44.781370Z","shell.execute_reply":"2024-01-13T09:31:44.788785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def dice_coefficient(y_true, y_pred, smooth=1e-5):\n    intersection = K.sum(K.abs(y_true * y_pred), axis=-1)\n    return (2. * intersection + smooth) / (K.sum(K.square(y_true), -1) + K.sum(K.square(y_pred), -1) + smooth)","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:44.791055Z","iopub.execute_input":"2024-01-13T09:31:44.791465Z","iopub.status.idle":"2024-01-13T09:31:44.798772Z","shell.execute_reply.started":"2024-01-13T09:31:44.791437Z","shell.execute_reply":"2024-01-13T09:31:44.797965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"optimizer=tf.optimizers.Adam(learning_rate=0.001)\nloss=tf.losses.binary_crossentropy\n\nmodel.compile(optimizer=optimizer, loss=loss, metrics=[dice_coefficient])","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:44.800538Z","iopub.execute_input":"2024-01-13T09:31:44.800822Z","iopub.status.idle":"2024-01-13T09:31:44.827387Z","shell.execute_reply.started":"2024-01-13T09:31:44.800796Z","shell.execute_reply":"2024-01-13T09:31:44.826595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs = 20\nsteps_per_epoch = len(train_generator)\n\nhistory = model.fit(train_generator, validation_data=val_generator, epochs=epochs, steps_per_epoch=steps_per_epoch, callbacks=callbacks_list, shuffle=True, verbose=1)","metadata":{"execution":{"iopub.status.busy":"2024-01-13T09:31:45.360810Z","iopub.execute_input":"2024-01-13T09:31:45.361621Z","iopub.status.idle":"2024-01-13T21:08:35.651020Z","shell.execute_reply.started":"2024-01-13T09:31:45.361588Z","shell.execute_reply":"2024-01-13T21:08:35.650152Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(16, 5))\n\n# Plot training and validation loss\nplt.subplot(1, 2, 1)\nplt.plot(range(epochs), history.history['loss'], 'bo-', label='Training loss')\nplt.plot(range(epochs), history.history['val_loss'], 'ro-', label='Validation loss')\nplt.title('Training and Validation Loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend()\n\n# Plot training and validation dice coefficient\nplt.subplot(1, 2, 2)\nplt.plot(range(epochs), history.history['dice_coefficient'], 'bo-', label='Training Dice Coefficient')\nplt.plot(range(epochs), history.history['val_dice_coefficient'], 'ro-', label='Validation Dice Coefficient')\nplt.title('Training and Validation Dice Coefficient')\nplt.xlabel('Epochs')\nplt.ylabel('Dice Coefficient')\nplt.legend();","metadata":{"execution":{"iopub.status.busy":"2024-01-13T21:11:37.343564Z","iopub.execute_input":"2024-01-13T21:11:37.343959Z","iopub.status.idle":"2024-01-13T21:11:37.922779Z","shell.execute_reply.started":"2024-01-13T21:11:37.343927Z","shell.execute_reply":"2024-01-13T21:11:37.921865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualize predictions\n","metadata":{}},{"cell_type":"code","source":"# Load and preprocess the input image \ndef preprocess_input(image_path, target_size=(256, 256)):\n    image = cv2.imread(image_path)\n    if image is None:\n        print(f\"Error: Unable to load image from {image_path}\")\n    if image.shape[0] == 0 or image.shape[1] == 0:\n        print(\"Error: Loaded image has invalid dimensions.\")\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    image = cv2.resize(image, target_size)\n    image = image / 255.0  # Normalize pixel values to the range [0, 1]\n    image = np.expand_dims(image, axis=0)  # Add batch dimension\n    return image","metadata":{"execution":{"iopub.status.busy":"2024-01-13T21:11:44.944352Z","iopub.execute_input":"2024-01-13T21:11:44.945056Z","iopub.status.idle":"2024-01-13T21:11:44.951164Z","shell.execute_reply.started":"2024-01-13T21:11:44.945023Z","shell.execute_reply":"2024-01-13T21:11:44.950205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_path = os.path.join('/kaggle/input/airbus-ship-detection/test_v2', os.listdir('/kaggle/input/airbus-ship-detection/test_v2')[10])\noutput_mask = model.predict(preprocess_input(img_path), verbose=0)\noutput_mask = (output_mask > 0.3).astype(int)\nplt.imshow(np.squeeze(output_mask, axis=0));","metadata":{"execution":{"iopub.status.busy":"2024-01-13T21:11:45.632191Z","iopub.execute_input":"2024-01-13T21:11:45.632913Z","iopub.status.idle":"2024-01-13T21:11:47.440688Z","shell.execute_reply.started":"2024-01-13T21:11:45.632878Z","shell.execute_reply":"2024-01-13T21:11:47.439802Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(np.squeeze(preprocess_input(img_path), axis=0));","metadata":{"execution":{"iopub.status.busy":"2024-01-13T21:11:47.442239Z","iopub.execute_input":"2024-01-13T21:11:47.442531Z","iopub.status.idle":"2024-01-13T21:11:47.715679Z","shell.execute_reply.started":"2024-01-13T21:11:47.442499Z","shell.execute_reply":"2024-01-13T21:11:47.714778Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Make submission","metadata":{}},{"cell_type":"code","source":"def make_submission(folder_path, model):\n    list_of_images = os.listdir(folder_path)\n    image_id = []\n    encoded_pixels = []\n    \n    for img_name in list_of_images:\n        # Obtaining the model prediction.\n        img = preprocess_input(os.path.join(folder_path, img_name))\n        mask = model.predict(img, verbose=0)\n        mask = np.squeeze(mask, axis=(0, 3))\n        mask = cv2.resize(mask, (768, 768))\n        mask = (mask > 0.3).astype(int)\n        \n        if np.all(mask == 0):\n            image_id.append(img_name)\n            encoded_pixels.append('')\n        else:\n            # Apply morphological operation to distinguish individual objects\n            labeled_mask = label(mask)\n            for region in regionprops(labeled_mask):\n                # Create a mask for the current object\n                single_ship_mask = (labeled_mask == region.label).astype(np.uint8)\n\n                # Obtain RLE for the mask\n                rle = rle_encode(single_ship_mask)\n\n                # Add values to the lists\n                image_id.append(img_name)\n                encoded_pixels.append(rle)\n    \n    # Create a DataFrame\n    df = pd.DataFrame({\"ImageId\": image_id, \"EncodedPixels\": encoded_pixels})\n    return df","metadata":{"execution":{"iopub.status.busy":"2024-01-13T21:11:47.716809Z","iopub.execute_input":"2024-01-13T21:11:47.717090Z","iopub.status.idle":"2024-01-13T21:11:47.725411Z","shell.execute_reply.started":"2024-01-13T21:11:47.717064Z","shell.execute_reply":"2024-01-13T21:11:47.724544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"folder_path = '/kaggle/input/airbus-ship-detection/test_v2'\nsubmission = make_submission(folder_path, model)\nsubmission.to_csv('submission.csv', index=False)\nsubmission.head()","metadata":{"execution":{"iopub.status.busy":"2024-01-13T21:29:03.729408Z","iopub.execute_input":"2024-01-13T21:29:03.729929Z","iopub.status.idle":"2024-01-13T21:29:03.736350Z","shell.execute_reply.started":"2024-01-13T21:29:03.729893Z","shell.execute_reply":"2024-01-13T21:29:03.735515Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_name = '314f393ca.jpg'\none_sample_masks = submission[submission.ImageId == img_name]\none_sample_masks","metadata":{"execution":{"iopub.status.busy":"2024-01-13T21:29:04.015211Z","iopub.execute_input":"2024-01-13T21:29:04.015551Z","iopub.status.idle":"2024-01-13T21:29:04.019829Z","shell.execute_reply.started":"2024-01-13T21:29:04.015521Z","shell.execute_reply":"2024-01-13T21:29:04.018814Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_path = os.path.join(folder_path, img_name)\nimg = np.squeeze(preprocess_input(img_path), axis=0)\nmask = model.predict(preprocess_input(img_path), verbose=0)\nmask = (mask > 0.3).astype(int)\n\n# Set the figure size\nplt.figure(figsize=(15, 10))  # Adjust the width and height as needed\n\n# Row 1\nplt.subplot(2, 3, 1)\nplt.imshow(img)\nplt.title('Original Image')\n\nplt.subplot(2, 3, 2)\nplt.imshow(np.squeeze(mask, axis=0))\nplt.title('Model Output')\n\nplt.subplot(2, 3, 3)\nplt.imshow(label(np.squeeze(mask, axis=0)))\nplt.title('Labeled Output')\n\n# Row 2\nplt.subplot(2, 3, 4)\nplt.imshow(rle_decode(one_sample_masks.EncodedPixels.iloc[0]))\nplt.title('Decoded Mask 1')\n\nplt.subplot(2, 3, 5)\nplt.imshow(rle_decode(one_sample_masks.EncodedPixels.iloc[1]))\nplt.title('Decoded Mask 2')\n\nplt.subplot(2, 3, 6)\nplt.imshow(rle_decode(one_sample_masks.EncodedPixels.iloc[2]))\nplt.title('Decoded Mask 3')\n\n# Show the plot\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-01-13T21:30:50.712978Z","iopub.execute_input":"2024-01-13T21:30:50.713342Z","iopub.status.idle":"2024-01-13T21:30:50.718802Z","shell.execute_reply.started":"2024-01-13T21:30:50.713310Z","shell.execute_reply":"2024-01-13T21:30:50.717856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Save Model","metadata":{}},{"cell_type":"code","source":"model.save('/kaggle/working/model_v1.keras')","metadata":{"execution":{"iopub.status.busy":"2024-01-13T21:30:46.289297Z","iopub.execute_input":"2024-01-13T21:30:46.289669Z","iopub.status.idle":"2024-01-13T21:30:47.779096Z","shell.execute_reply.started":"2024-01-13T21:30:46.289638Z","shell.execute_reply":"2024-01-13T21:30:47.778249Z"},"trusted":true},"execution_count":null,"outputs":[]}]}