{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":4521,"databundleVersionId":326986,"sourceType":"competition"}],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport zipfile\nimport shutil\nfrom sklearn.model_selection import train_test_split\nimport cv2\nimport torch\nimport torch.nn as nn\nfrom torchvision.models import efficientnet_b0\nfrom torch.utils.checkpoint import checkpoint\nfrom fastai.vision.all import *\n\n# Clone YOLOv5 and install dependencies\nif not os.path.exists('./yolov5'):\n    !git clone https://github.com/ultralytics/yolov5.git\n    %cd yolov5\n    !pip install -r requirements.txt\n    %cd ..\n\n# Paths to files and folders\nbase_dir = '/kaggle/input/noaa-right-whale-recognition'\nzip_file_path = os.path.join(base_dir, 'imgs.zip')\nextraction_dir = './noaa-right-whale-recognition/'\nimgs_dir = os.path.join(extraction_dir, 'imgs')\ntrain_csv_path = os.path.join(base_dir, 'train.csv')\ntrain_images_dir = os.path.join(extraction_dir, 'train_images')\ntest_images_dir = os.path.join(extraction_dir, 'test_images')\nbbox_output_dir = './noaa-right-whale-recognition/bboxes'\ncropped_dir = './noaa-right-whale-recognition/cropped_images'\noutput_dir = './noaa-right-whale-recognition/processed'\n\n# Step 1: Extract Images\nif not os.path.exists(imgs_dir):\n    if not os.path.exists(zip_file_path):\n        raise FileNotFoundError(f\"Dataset not found at {zip_file_path}\")\n    else:\n        with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:\n            zip_ref.extractall(extraction_dir)\n        print(f\"Dataset extracted to: {extraction_dir}\")\n\n# Step 2: Organize Dataset\nos.makedirs(train_images_dir, exist_ok=True)\nos.makedirs(test_images_dir, exist_ok=True)\n\n# Load train.csv\ntrain_df = pd.read_csv(train_csv_path)\n\n# Extract the list of training images from the CSV\ntrain_image_files = train_df['Image'].tolist()\n\n# Organize images into train/test directories\nfor image_file in os.listdir(imgs_dir):\n    source_path = os.path.join(imgs_dir, image_file)\n    if image_file in train_image_files:\n        # Move the image to the train_images folder\n        dest_path = os.path.join(train_images_dir, image_file)\n    else:\n        # Move the image to the test_images folder\n        dest_path = os.path.join(test_images_dir, image_file)\n    shutil.move(source_path, dest_path)\n\nprint(f\"Training images moved to: {train_images_dir}\")\nprint(f\"Testing images moved to: {test_images_dir}\")\n\n# Step 3: Object Detection using YOLOv5\nos.makedirs(bbox_output_dir, exist_ok=True)\n\n# Perform object detection using YOLOv5\n!python yolov5/detect.py --weights yolov5s.pt --img 640 --conf 0.25 \\\n    --source {train_images_dir} --save-txt --save-conf --project {bbox_output_dir} --name results\n\n# Update bbox_output_dir path\nbbox_output_dir = os.path.join(bbox_output_dir, 'results', 'labels')\n\n# Step 4: Crop Whale Heads\nos.makedirs(cropped_dir, exist_ok=True)\n\nfor bbox_file in os.listdir(bbox_output_dir):\n    if bbox_file.endswith('.txt'):\n        img_file = bbox_file.replace('.txt', '.jpg')\n        img_path = os.path.join(train_images_dir, img_file)\n        bbox_path = os.path.join(bbox_output_dir, bbox_file)\n\n        if os.path.exists(img_path):\n            img = cv2.imread(img_path)\n            with open(bbox_path, 'r') as f:\n                for line in f:\n                    values = line.split()\n                    if len(values) == 6:  # Includes confidence\n                        _, x_center, y_center, width, height, _ = map(float, values)\n                    elif len(values) == 5:  # No confidence\n                        _, x_center, y_center, width, height = map(float, values)\n                    else:\n                        print(f\"Skipping invalid line in {bbox_path}: {line}\")\n                        continue\n\n                    x1 = int((x_center - width / 2) * img.shape[1])\n                    y1 = int((y_center - height / 2) * img.shape[0])\n                    x2 = int((x_center + width / 2) * img.shape[1])\n                    y2 = int((y_center + height / 2) * img.shape[0])\n\n                    cropped_img = img[max(0, y1):min(img.shape[0], y2), max(0, x1):min(img.shape[1], x2)]\n                    output_path = os.path.join(cropped_dir, img_file)\n                    cv2.imwrite(output_path, cropped_img)\n                    \n# Step 5: Organize Data for Training\ncropped_images = [img for img in os.listdir(cropped_dir) if img.endswith('.jpg')]\ntrain_imgs, valid_imgs = train_test_split(cropped_images, test_size=0.2, random_state=42)\n\nos.makedirs(output_dir, exist_ok=True)\nos.makedirs(os.path.join(output_dir, 'train'), exist_ok=True)\nos.makedirs(os.path.join(output_dir, 'valid'), exist_ok=True)\n\ndef organize_images(images, split, train_labels):\n    \"\"\"\n    Organizes images into class-specific directories under train/valid split.\n    Ensures all validation classes exist in training labels.\n    \"\"\"\n    for img in images:\n        # Retrieve the whaleID for the image\n        label = train_df.loc[train_df['Image'] == img, 'whaleID']\n        if label.empty:\n            print(f\"Warning: Label not found for image {img}\")\n            continue\n        label = str(label.values[0])  # Convert label to string\n\n        if split == 'valid' and label not in train_labels:\n            # Skip validation images with labels not in training set\n            print(f\"Skipping validation image {img} with label {label} as it is not in training labels.\")\n            continue\n\n        # Create a directory for the label if it doesn't exist\n        class_dir = os.path.join(output_dir, split, label)\n        os.makedirs(class_dir, exist_ok=True)\n\n        # Copy the image to the correct class directory\n        src_path = os.path.join(cropped_dir, img)\n        dest_path = os.path.join(class_dir, img)\n        shutil.copy(src_path, dest_path)\n        print(f\"Copied {img} to {class_dir}\")\n\n# Get all labels in the training set\ntrain_labels = train_df.loc[train_df['Image'].isin(train_imgs), 'whaleID'].unique()\n\n# Organize images into train and valid directories\norganize_images(train_imgs, 'train', train_labels)\norganize_images(valid_imgs, 'valid', train_labels)\n\n\n# Step 6: Define EfficientNet Model\nclass EfficientNetCheckpoint(nn.Module):\n    def __init__(self, num_classes):\n        super().__init__()\n        self.model = efficientnet_b0(pretrained=True)\n        self.adjust_dim = nn.Conv2d(320, 1280, kernel_size=1, stride=1)\n        self.model.classifier[1] = nn.Linear(1280, num_classes)\n\n    def forward(self, x):\n        x = self.model.features[0](x)\n        for i in range(1, 8):\n            x = checkpoint(self.model.features[i], x)\n        x = self.model.avgpool(x)\n        x = self.adjust_dim(x)\n        x = x.view(x.size(0), -1)\n        return self.model.classifier(x)\n\n# Data Augmentation and DataLoader\nbatch_tfms = [*aug_transforms(do_flip=True, flip_vert=True, max_rotate=30, max_zoom=1.1), Normalize.from_stats(*imagenet_stats)]\ndls = ImageDataLoaders.from_folder(output_dir, train='train', valid='valid', item_tfms=Resize(224), batch_tfms=batch_tfms)\n\n# Train the Model\nmodel = EfficientNetCheckpoint(num_classes=len(train_df['whaleID'].unique()))\nlearn = Learner(dls, model, metrics=accuracy, wd=0.01, opt_func=Adam).to_fp16()\n\n# Train the model\nprint(\"Training the model...\")\nlearn.fit_one_cycle(10, 3e-3)\nprint(\"Training completed.\")\n\n# Step 7: Generate Predictions\ntest_images = [os.path.join(test_images_dir, img) for img in os.listdir(test_images_dir) if img.endswith('.jpg')]\npredictions = []\n\nprint(\"Generating predictions on test images...\")\nfor img_path in test_images:\n    pred_class, pred_idx, probs = learn.predict(img_path)\n    predictions.append((os.path.basename(img_path), pred_class))\n\n# Step 8: Create Submission File\nsubmission_df = pd.DataFrame(predictions, columns=['Image', 'WhaleID'])\nsubmission_df.to_csv('submission.csv', index=False)\n\nprint(\"Submission file saved as 'submission.csv'\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}