{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session\n\n# Use the kagglehub client library to attach Kaggle resources like competitions, datasets, and models to your session\n# Learn more about kagglehub: https://github.com/Kaggle/kagglehub/blob/main/README.md\n\nimport kagglehub\n# kagglehub.dataset_download('<owner>/<dataset-slug>')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-09-23T16:18:12.228959Z","iopub.execute_input":"2026-09-23T16:18:12.229384Z","iopub.status.idle":"2026-09-23T16:18:18.459156Z","shell.execute_reply.started":"2026-09-23T16:18:12.229355Z","shell.execute_reply":"2026-09-23T16:18:18.458247Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport shutil\nimport pandas as pd\n\n# 1. Reset destination folder to clear any broken links\ndest_dir = '/kaggle/working/train_folder'\nif os.path.exists(dest_dir):\n    shutil.rmtree(dest_dir)\nos.makedirs(dest_dir, exist_ok=True)\n\n# 2. Read train annotations and define source directory\ndf = pd.read_csv('/kaggle/input/competitions/cloud-type-classification2/train.csv')\nsrc_dir = '/kaggle/input/competitions/cloud-type-classification2/images/train'\n\n# 3. Create subdirectories for each label\nfor label in df['label'].unique():\n    os.makedirs(os.path.join(dest_dir, str(label)), exist_ok=True)\n\n# 4. Link each image to its respective label folder\nlinked_count = 0\nfor _, row in df.iterrows():\n    img_name = str(row['id'])\n    if not img_name.endswith('.jpg'):\n        img_name += '.jpg'\n        \n    src_file = os.path.join(src_dir, img_name)\n    dst_file = os.path.join(dest_dir, str(row['label']), img_name)\n    \n    if os.path.exists(src_file):\n        os.symlink(src_file, dst_file)\n        linked_count += 1\n\nprint(f\"Successfully linked {linked_count} images into {dest_dir}!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-23T16:18:18.46061Z","iopub.execute_input":"2026-09-23T16:18:18.461176Z","iopub.status.idle":"2026-09-23T16:18:18.826671Z","shell.execute_reply.started":"2026-09-23T16:18:18.461152Z","shell.execute_reply":"2026-09-23T16:18:18.825854Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision.datasets import ImageFolder\nfrom torchvision import transforms\nfrom torch.utils.data import DataLoader\n\ntrain_transforms = train_transforms = transforms.Compose([\n    transforms.Resize((128, 128)),\n    transforms.RandomHorizontalFlip(p=0.5),\n    transforms.RandomRotation(degrees=15),\n    transforms.ColorJitter(brightness=0.1, contrast=0.1),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\ndataset_train = ImageFolder(\n    root=\"/kaggle/working/train_folder\",\n    transform=train_transforms\n)\n\ntrain_loader = DataLoader(dataset_train, batch_size=32, shuffle=True, num_workers=2, pin_memory=True)\n\ndataset_train = ImageFolder(\n    root=\"/kaggle/working/train_folder\",\n    transform=train_transforms\n)\n\nprint(f\"Total images found: {len(dataset_train)}\")\nprint(f\"Classes detected: {dataset_train.classes}\")\n\ntrain_loader = DataLoader(dataset_train, batch_size=32, shuffle=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-23T16:18:18.828011Z","iopub.execute_input":"2026-09-23T16:18:18.828265Z","iopub.status.idle":"2026-09-23T16:18:18.855423Z","shell.execute_reply.started":"2026-09-23T16:18:18.828243Z","shell.execute_reply":"2026-09-23T16:18:18.854874Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"images, labels = next(iter(train_loader))\nprint(\"Images shape:\", images.shape)  # Expected: [32, 3, 128, 128]\nprint(\"Labels shape:\", labels.shape)  # Expected: [32]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-23T16:18:18.856659Z","iopub.execute_input":"2026-09-23T16:18:18.856899Z","iopub.status.idle":"2026-09-23T16:18:22.255754Z","shell.execute_reply.started":"2026-09-23T16:18:18.856877Z","shell.execute_reply":"2026-09-23T16:18:22.255082Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#environment setup\nimport torch.nn as nn","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-23T16:18:22.256885Z","iopub.execute_input":"2026-09-23T16:18:22.2572Z","iopub.status.idle":"2026-09-23T16:18:22.261228Z","shell.execute_reply.started":"2026-09-23T16:18:22.257177Z","shell.execute_reply":"2026-09-23T16:18:22.260417Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\n\nclass CloudCNN(nn.Module):\n    def __init__(self, num_classes=7):\n        super(CloudCNN, self).__init__()\n        \n        self.features = nn.Sequential(\n            # Block 1: 3 -> 32\n            nn.Conv2d(3, 32, kernel_size=3, padding=1),\n            nn.BatchNorm2d(32),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(2),  # 128 -> 64\n            \n            # Block 2: 32 -> 64\n            nn.Conv2d(32, 64, kernel_size=3, padding=1),\n            nn.BatchNorm2d(64),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(2),  # 64 -> 32\n            \n            # Block 3: 64 -> 128\n            nn.Conv2d(64, 128, kernel_size=3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(2),  # 32 -> 16\n            \n            nn.AdaptiveAvgPool2d((4, 4))\n        )\n        \n        self.classifier = nn.Sequential(\n            nn.Flatten(),\n            nn.Linear(128 * 4 * 4, 256),\n            nn.BatchNorm1d(256),\n            nn.ReLU(inplace=True),\n            nn.Dropout(0.4),\n            nn.Linear(256, num_classes)\n        )\n\n    def forward(self, x):\n        x = self.features(x)\n        x = self.classifier(x)\n        return x\n\nmodel = CloudCNN(num_classes=len(dataset_train.classes))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-23T17:08:23.38594Z","iopub.execute_input":"2026-09-23T17:08:23.386502Z","iopub.status.idle":"2026-09-23T17:08:23.403114Z","shell.execute_reply.started":"2026-09-23T17:08:23.386468Z","shell.execute_reply":"2026-09-23T17:08:23.402303Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.optim as optim\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.AdamW(model.parameters(), lr=0.001, weight_decay=1e-3)\nscheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=7)\n\nnum_epochs = 7\n\nfor epoch in range(num_epochs):\n    model.train()\n    running_loss, correct, total = 0.0, 0, 0\n\n    for images, labels in train_loader:\n        images, labels = images.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item() * images.size(0)\n        _, predicted = torch.max(outputs, 1)\n        total += labels.size(0)\n        correct += (predicted == labels).sum().item()\n\n    scheduler.step()\n\n    epoch_loss = running_loss / total\n    epoch_acc = (correct / total) * 100\n    print(f\"Epoch [{epoch+1:02d}/{num_epochs}] - Loss: {epoch_loss:.4f} - Accuracy: {epoch_acc:.2f}%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-23T16:41:29.917958Z","iopub.execute_input":"2026-09-23T16:41:29.91867Z","iopub.status.idle":"2026-09-23T16:53:26.939132Z","shell.execute_reply.started":"2026-09-23T16:41:29.918643Z","shell.execute_reply":"2026-09-23T16:53:26.938337Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\nimport pandas as pd\nfrom PIL import Image\nfrom torchvision import transforms\nfrom tqdm import tqdm\n\n# 1. Matching evaluation transforms\ntest_transforms = transforms.Compose([\n    transforms.Resize((128, 128)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# 2. File paths\ntest_csv = '/kaggle/input/competitions/cloud-type-classification2/test.csv'\ntest_img_dir = '/kaggle/input/competitions/cloud-type-classification2/images/test'\ntest_df = pd.read_csv(test_csv)\n\n# 3. Inference\nmodel.eval()\npredictions = []\n\nwith torch.no_grad():\n    for img_id in tqdm(test_df['id'], desc=\"Predicting Test Set\"):\n        img_name = str(img_id) if str(img_id).endswith('.jpg') else f\"{img_id}.jpg\"\n        img_path = os.path.join(test_img_dir, img_name)\n        \n        img = Image.open(img_path).convert('RGB')\n        img_tensor = test_transforms(img).unsqueeze(0).to(device)\n        \n        output = model(img_tensor)\n        pred_label_idx = torch.argmax(output, dim=1).item()\n        \n        # Map predicted index back to original class label\n        pred_label = dataset_train.classes[pred_label_idx]\n        predictions.append(pred_label)\n\n# 4. Generate and save submission\nsubmission = pd.DataFrame({\n    'id': test_df['id'],\n    'label': predictions\n})\n\nsubmission.to_csv('submission.csv', index=False)\nprint(\"Saved submission.csv successfully!\\n\")\n\nprint(\"--- Preview First 5 Rows ---\")\nprint(submission.head())\n\nprint(\"\\n--- Prediction Distribution (Sanity Check) ---\")\nprint(submission['label'].value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-23T16:53:38.776544Z","iopub.execute_input":"2026-09-23T16:53:38.777269Z","iopub.status.idle":"2026-09-23T16:54:55.572278Z","shell.execute_reply.started":"2026-09-23T16:53:38.777238Z","shell.execute_reply":"2026-09-23T16:54:55.571192Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission['label'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-23T16:58:24.555629Z","iopub.execute_input":"2026-09-23T16:58:24.556455Z","iopub.status.idle":"2026-09-23T16:58:24.562815Z","shell.execute_reply.started":"2026-09-23T16:58:24.556423Z","shell.execute_reply":"2026-09-23T16:58:24.562047Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}