{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":13836,"databundleVersionId":1718836,"sourceType":"competition"},{"sourceId":8143852,"sourceType":"datasetVersion","datasetId":4753915}],"dockerImageVersionId":30673,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport json\nimport gc\nimport cv2\nimport joblib\nimport sys\nimport random\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision.models as models\nfrom torch.utils.data import DataLoader, Dataset\nimport tensorflow as tf\nimport tensorflow_hub as hub\nfrom tensorflow import keras\nfrom tensorflow.keras.preprocessing.image import img_to_array, load_img\nfrom sklearn.metrics import accuracy_score\nfrom tqdm import tqdm\nfrom PIL import Image\nfrom albumentations import (Compose, OneOf, Normalize, Resize, RandomResizedCrop, RandomCrop, CenterCrop, \n                            HorizontalFlip, VerticalFlip, Rotate, ShiftScaleRotate, Transpose, ImageOnlyTransform)\nfrom albumentations.pytorch import ToTensorV2\nimport timm\nimport shutil\nimport pickle\nimport os\n","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:10:12.088523Z","iopub.execute_input":"2024-04-25T16:10:12.088891Z","iopub.status.idle":"2024-04-25T16:10:32.369619Z","shell.execute_reply.started":"2024-04-25T16:10:12.088849Z","shell.execute_reply":"2024-04-25T16:10:32.368671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Crop Net","metadata":{}},{"cell_type":"code","source":"path = \"/kaggle/input/cassava-leaf-disease-classification/\"\nprint(f\"Contents of the data folder: {os.listdir(path)}\")\nimage_path = path+\"test_images/\"\nimage_folder = os.path.join(path, 'test_images')\n\n\nIMAGE_SIZE = (512,512)\nsubmission_df = pd.DataFrame(columns=[\"image_id\", \"label\"])\nsubmission_df[\"image_id\"] = os.listdir(image_path)\nsubmission_df[\"label\"] = 0","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:10:32.371189Z","iopub.execute_input":"2024-04-25T16:10:32.371475Z","iopub.status.idle":"2024-04-25T16:10:32.389094Z","shell.execute_reply.started":"2024-04-25T16:10:32.371452Z","shell.execute_reply":"2024-04-25T16:10:32.388211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow_hub as hub\n\ndef load_model_cropnet():\n    model_path = '/kaggle/input/cropnet-model/cropnet_mobilenetv3/cropnet_mobilenetv3'\n    # Load the model from the local directory\n    classifier = hub.KerasLayer(model_path, trainable=False)\n    return classifier","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:10:32.390560Z","iopub.execute_input":"2024-04-25T16:10:32.391593Z","iopub.status.idle":"2024-04-25T16:10:32.491996Z","shell.execute_reply.started":"2024-04-25T16:10:32.391557Z","shell.execute_reply":"2024-04-25T16:10:32.491006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def center_crop_and_resize(image, target_size=(224, 224)):\n    \"\"\"Crop the center of the image and resize it to the target size.\"\"\"\n    original_height, original_width, _ = image.shape\n    target_height, target_width = target_size\n    \n    # Calculate the coordinates for the center crop\n    crop_height_start = (original_height - min(original_height, original_width)) // 2\n    crop_width_start = (original_width - min(original_height, original_width)) // 2\n    crop_height_end = crop_height_start + min(original_height, original_width)\n    crop_width_end = crop_width_start + min(original_height, original_width)\n    \n    # Perform the center crop\n    image_cropped = image[crop_height_start:crop_height_end, crop_width_start:crop_width_end]\n    \n    # Resize the cropped image to the target size\n    image_resized = tf.image.resize(image_cropped, target_size)\n    return image_resized.numpy()\n\ndef preprocess_image_cropnet(image_path, image_size):\n    \"\"\"\n    Load the image from the given path and resize it to the target size.\n    \"\"\"\n    image = load_img(image_path) # Load and resize to expected size\n    image = img_to_array(image) / 255.0 # Convert to array and normalize\n    image = center_crop_and_resize(image,image_size)\n    image = np.expand_dims(image, axis=0)\n    return image\n\ndef remap_probabilities(probabilities):\n    # Convert probabilities to a numpy array if it's a TensorFlow tensor\n    if isinstance(probabilities, tf.Tensor):\n        probabilities = probabilities.numpy()\n    num_known_classes = 5\n    # Check if the probabilities include the sixth 'Unknown' class. This comes with cropnet\n    if probabilities.shape[1] > num_known_classes:\n        # Extract the probability of the 'Unknown' class\n        unknown_prob = probabilities[:, -1] / num_known_classes\n        # Remove the 'Unknown' class probability\n        known_class_probs = probabilities[:, :num_known_classes]\n        # Evenly distribute the 'Unknown' class probability among the known classes\n        adjusted_probs = known_class_probs + unknown_prob[:, None]\n    else:\n        adjusted_probs = probabilities\n\n    return adjusted_probs\n","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:10:32.496685Z","iopub.execute_input":"2024-04-25T16:10:32.497376Z","iopub.status.idle":"2024-04-25T16:10:32.794808Z","shell.execute_reply.started":"2024-04-25T16:10:32.497349Z","shell.execute_reply":"2024-04-25T16:10:32.793720Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict_image_cropnet(model, image_name, image_folder):\n    image_path_full = os.path.join(image_folder, image_name)\n    image = preprocess_image_cropnet(image_path_full, (224,224))\n    probabilities = model(image)\n    probabilities = remap_probabilities(probabilities)\n    return probabilities","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:10:59.862446Z","iopub.execute_input":"2024-04-25T16:10:59.862801Z","iopub.status.idle":"2024-04-25T16:10:59.868227Z","shell.execute_reply.started":"2024-04-25T16:10:59.862772Z","shell.execute_reply":"2024-04-25T16:10:59.867154Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# EffecientNet","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\n\ndef extract_patches(image_path, patch_size=(224, 224)):\n    # Load the image from path\n    img = load_img(image_path)\n    img = img_to_array(img)  # Convert it to array\n    height, width, _ = img.shape\n\n    # Example of extracting a center patch\n    center_x, center_y = height // 2, width // 2\n    center_patch = img[center_x - patch_size[0]//2:center_x + patch_size[0]//2, \n                       center_y - patch_size[1]//2:center_y + patch_size[1]//2, :]\n\n    # Resize patch to the target size if necessary\n    center_patch = Image.fromarray(np.uint8(center_patch))  # Convert array to PIL Image\n    center_patch = center_patch.resize(patch_size, Image.ANTIALIAS)  # Resize image\n    center_patch = img_to_array(center_patch)  # Convert back to array if necessary for further processing\n\n    # Assuming you are handling multiple patches, append to a list\n    patches = [center_patch]  # Start with the center patch as an example\n\n    return np.array(patches)\n\ndef augment_patches(patches):\n    \"\"\"Apply augmentations to each patch.\"\"\"\n    # Assuming patches is a batch of images of shape (N, H, W, C)\n    flips = np.flip(patches, axis=2)  # Horizontal flip\n    rotates = np.rot90(patches, k=1, axes=(1, 2))  # 90 degree rotation\n    transposes = np.transpose(patches, (0, 2, 1, 3))  # Transpose\n    \n    return np.concatenate([flips, rotates, transposes], axis=0)\n\ndef preprocess_input_efficientnet(patches):\n    \"\"\"Normalize patches to the range expected by EfficientNet.\"\"\"\n    return patches / 255.0  # Adjust if your model expects a different range\n","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:11:07.371949Z","iopub.execute_input":"2024-04-25T16:11:07.372762Z","iopub.status.idle":"2024-04-25T16:11:07.382834Z","shell.execute_reply.started":"2024-04-25T16:11:07.372728Z","shell.execute_reply":"2024-04-25T16:11:07.381712Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_model_efficientnet():\n    # This is done to bypass some read only OS issues when loading model in kaggle \n    source_path = '/kaggle/input/cropnet-model/EffecientNet.keras'\n    target_path = '/kaggle/working/EffecientNet.keras'\n    shutil.copy(source_path, target_path)\n    efficient_net = tf.keras.models.load_model(target_path)\n    return efficient_net\n\n\ndef predict_image_efficientnet(model, image_name, image_folder):\n    image_path = os.path.join(image_folder, image_name)\n    patches = extract_patches(image_path)\n    patches_augmented = augment_patches(patches[:4])  # Apply augmentations to the first 4 patches\n    patches_combined = np.concatenate([patches, patches_augmented], axis=0)  # Combine all patches\n    patches_preprocessed = preprocess_input_efficientnet(patches_combined)\n    predictions = model.predict(patches_preprocessed, verbose=0)\n    overall_prediction = np.mean(predictions, axis=0)\n    return overall_prediction\n","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:11:19.490691Z","iopub.execute_input":"2024-04-25T16:11:19.491533Z","iopub.status.idle":"2024-04-25T16:11:19.498048Z","shell.execute_reply.started":"2024-04-25T16:11:19.491494Z","shell.execute_reply":"2024-04-25T16:11:19.497080Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# VGG","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing import image\nfrom keras.applications.vgg16 import preprocess_input\n\ndef preprocess_image_vgg16(img_path):\n    \"\"\"Load and preprocess an image for VGG16 model.\"\"\"\n    img = image.load_img(img_path, target_size=(300, 300))\n    \n    # Convert the image to a numpy array\n    img_array = image.img_to_array(img)\n    \n    # Add a dimension to the image to account for the batch size\n    img_array_expanded = np.expand_dims(img_array, axis=0)\n    \n    # Use the preprocess_input function from keras.applications.vgg16\n    img_preprocessed = preprocess_input(img_array_expanded)\n    \n    return img_preprocessed\n","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:11:22.295150Z","iopub.execute_input":"2024-04-25T16:11:22.295530Z","iopub.status.idle":"2024-04-25T16:11:22.302039Z","shell.execute_reply.started":"2024-04-25T16:11:22.295504Z","shell.execute_reply":"2024-04-25T16:11:22.301074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\n\ndef load_model_vgg():\n    # This is done to bypass some read only OS issues when loading model in kaggle \n    source_path = '/kaggle/input/cropnet-model/model_vgg16_v2.keras'\n    target_path = '/kaggle/working/model_vgg16_v2.keras'\n    shutil.copy(source_path, target_path)\n    vgg_model = tf.keras.models.load_model(target_path)\n    return vgg_model","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:11:25.845441Z","iopub.execute_input":"2024-04-25T16:11:25.845819Z","iopub.status.idle":"2024-04-25T16:11:25.851427Z","shell.execute_reply.started":"2024-04-25T16:11:25.845790Z","shell.execute_reply":"2024-04-25T16:11:25.850328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict_image_vgg(model, image_name, image_folder):\n    image_path_full = os.path.join(image_folder, image_name)\n    image = preprocess_image_vgg16(image_path_full)\n    prediction = model.predict(image, verbose=0)\n    return prediction","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:11:26.503145Z","iopub.execute_input":"2024-04-25T16:11:26.503495Z","iopub.status.idle":"2024-04-25T16:11:26.508604Z","shell.execute_reply.started":"2024-04-25T16:11:26.503470Z","shell.execute_reply":"2024-04-25T16:11:26.507682Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ViT","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision.models as models\n\ndef load_model_vit():\n    model_path = '/kaggle/input/cropnet-model/model_vit_8179acc.pth'\n    pretrain_model_path = '/kaggle/input/cropnet-model/vit_b_16-c867db91.pth'\n\n    # Initialize the ViT model with default pre-trained weights\n    model = models.vit_b_16(weights=None)\n    state_dict = torch.load(pretrain_model_path)\n    model.load_state_dict(state_dict, strict=False)  \n\n    # Freeze all the parameters in the model\n    for param in model.parameters():\n        param.requires_grad = False\n    \n    # Replace the classifier head\n    model.heads = nn.Sequential(\n        nn.Linear(in_features=768, out_features=5, bias=True)\n    )\n    \n    # Load the custom weights from a saved state\n    model.load_state_dict(torch.load(model_path))\n    \n    # Switch the model to evaluation mode\n    model.eval()\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:11:35.029099Z","iopub.execute_input":"2024-04-25T16:11:35.029950Z","iopub.status.idle":"2024-04-25T16:11:35.036514Z","shell.execute_reply.started":"2024-04-25T16:11:35.029921Z","shell.execute_reply":"2024-04-25T16:11:35.035445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torchvision import transforms\nfrom PIL import Image\n\ndef preprocess_image_vit(image_path):\n    # Define the standard ViT preprocessing\n    transform = transforms.Compose([\n        transforms.Resize((224, 224)),  # Resize to the input size expected by ViT\n        transforms.ToTensor(),  # Convert the image to a tensor\n        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # Normalize\n    ])\n    \n    # Load the image\n    image = Image.open(image_path).convert('RGB')\n    image_tensor = transform(image).unsqueeze(0)  # Add batch dimension\n    return image_tensor\n\ndef predict_image_vit(model, image_name, image_folder):\n    image_path = os.path.join(image_folder, image_name)\n    image_tensor = preprocess_image_vit(image_path)\n    # Perform prediction\n    with torch.no_grad():\n        outputs = model(image_tensor)\n    \n    probabilities = torch.nn.functional.softmax(outputs, dim=1)\n    probabilities = probabilities.cpu().detach().numpy()  # Detach from the graph, move to CPU and convert to numpy\n\n    return probabilities\n","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:11:43.091872Z","iopub.execute_input":"2024-04-25T16:11:43.092835Z","iopub.status.idle":"2024-04-25T16:11:43.101298Z","shell.execute_reply.started":"2024-04-25T16:11:43.092803Z","shell.execute_reply":"2024-04-25T16:11:43.100334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm import tqdm\n\ndef get_predictions_vgg(model, images, image_folder):\n    predictions = []\n    # Wrap the loop with tqdm for a progress bar\n    for image in tqdm(images, desc=\"Predicting with VGG\"):\n        predictions.append(predict_image_vgg(model, image, image_folder))\n    return predictions\n\ndef get_predictions_cropnet(model, images, image_folder, n_jobs=-1):\n    predictions = []\n    # Wrap the loop with tqdm for a progress bar\n    for image in tqdm(images, desc=\"Predicting with CropNet\"):\n        predictions.append(predict_image_cropnet(model, image, image_folder))\n    return predictions\n\ndef get_predictions_vit(model, images, image_folder, n_jobs=-1):\n    predictions = []\n    # Wrap the loop with tqdm for a progress bar\n    for image in tqdm(images, desc=\"Predicting with ViT\"):\n        predictions.append(predict_image_vit(model, image, image_folder))\n    return predictions\n\ndef get_predictions_efficient(model, images, image_folder, n_jobs=-1):\n    predictions = []\n    # Wrap the loop with tqdm for a progress bar\n    for image in tqdm(images, desc=\"Predicting with EfficientNet\"):\n        predictions.append(predict_image_efficientnet(model, image, image_folder))\n    return predictions","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:11:48.009878Z","iopub.execute_input":"2024-04-25T16:11:48.010261Z","iopub.status.idle":"2024-04-25T16:11:48.020196Z","shell.execute_reply.started":"2024-04-25T16:11:48.010232Z","shell.execute_reply":"2024-04-25T16:11:48.019089Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Running the experiment","metadata":{}},{"cell_type":"code","source":"def predict_image(image, image_folder, cropnet_model, vgg_model, vit_model, eff_model, meta_model):\n    pred_vit = predict_image_vit(vit_model, image, image_folder).flatten()\n    pred_cropnet = predict_image_cropnet(cropnet_model, image, image_folder).flatten()\n    pred_vgg = predict_image_vgg(vgg_model, image, image_folder).flatten()\n    pred_eff = predict_image_efficientnet(eff_model, image, image_folder).flatten()\n    \n    # Combine predictions shape is (4 models * 5 feature probabilities)\n    combined_predictions = np.concatenate([pred_vit, pred_cropnet, pred_vgg, pred_eff])\n    \n    # Make meta-model prediction\n    final_prediction = meta_model.predict([combined_predictions])\n    return final_prediction[0]","metadata":{"execution":{"iopub.status.busy":"2024-04-25T16:11:52.165503Z","iopub.execute_input":"2024-04-25T16:11:52.166180Z","iopub.status.idle":"2024-04-25T16:11:52.172566Z","shell.execute_reply.started":"2024-04-25T16:11:52.166146Z","shell.execute_reply":"2024-04-25T16:11:52.171532Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path = \"/kaggle/input/cassava-leaf-disease-classification/\"\nprint(f\"Contents of the data folder: {os.listdir(path)}\")\nimage_path = path + '/test_images'\nimage_folder = os.path.join(path, 'test_images')\n\n\nIMAGE_SIZE = (512,512)\nsubmission_df = pd.DataFrame(columns=[\"image_id\", \"label\"])\nsubmission_df[\"image_id\"] = os.listdir(image_path)\nsubmission_df[\"label\"] = 0\n\ncropnet_model = load_model_cropnet()\nvgg_model = load_model_vgg()\nvit_model = load_model_vit()\neff_model = load_model_efficientnet()\nmeta_model = pickle.load(open(\"/kaggle/input/cropnet-model/multinomial_lbfgs_8939.sav\", 'rb'))\n\nfor idx, row in submission_df.iterrows():\n    image_id = row['image_id']\n    prediction = predict_image(image_id, image_folder, cropnet_model, vgg_model, vit_model, eff_model, meta_model)\n    submission_df.at[idx, 'label'] = prediction\n\nsubmission_df.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2024-04-17T06:18:52.381185Z","iopub.execute_input":"2024-04-17T06:18:52.382016Z","iopub.status.idle":"2024-04-17T06:19:08.297618Z","shell.execute_reply.started":"2024-04-17T06:18:52.381980Z","shell.execute_reply":"2024-04-17T06:19:08.296748Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df","metadata":{"execution":{"iopub.status.busy":"2024-04-17T06:19:12.996099Z","iopub.execute_input":"2024-04-17T06:19:12.996767Z","iopub.status.idle":"2024-04-17T06:19:13.009547Z","shell.execute_reply.started":"2024-04-17T06:19:12.996725Z","shell.execute_reply":"2024-04-17T06:19:13.008547Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}