{"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":10418,"databundleVersionId":862236,"isSourceIdPinned":false,"sourceType":"competition"}],"dockerImageVersionId":30887,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## No cutmix but BCE","metadata":{}},{"cell_type":"code","source":"# import os\n# import numpy as np\n# import pandas as pd\n# from PIL import Image\n# import torch\n# import torch.nn as nn\n# import torch.optim as optim\n# import torch.nn.functional as F\n# from torchvision import models, transforms\n# from torch.utils.data import Dataset, DataLoader\n# import albumentations as A\n# from albumentations.pytorch import ToTensorV2\n# from sklearn.metrics import average_precision_score, f1_score\n# import random\n\n# # Paths\n# DATA_DIR = \"/kaggle/input/humanatlas/d\"\n# DATA_DIR = \"/kaggle/input/human-protein-atlas-image-classification\"\n# TRAIN_DIR = os.path.join(DATA_DIR, \"train\")\n# CSV_PATH = os.path.join(DATA_DIR, \"train.csv\")\n\n# # Load CSV\n# df = pd.read_csv(CSV_PATH)\n# df['Target'] = df['Target'].apply(lambda x: list(map(int, str(x).split())) if pd.notna(x) else [])\n\n# # Define Custom Dataset\n# class ProteinDataset(Dataset):\n#     def __init__(self, df, img_dir, transform=None):\n#         self.df = df\n#         self.img_dir = img_dir\n#         self.transform = transform\n#         self.num_classes = 28\n\n#     def __len__(self):\n#         return len(self.df)\n\n#     def __getitem__(self, idx):\n#         img_id = self.df.iloc[idx]['Id']\n#         img_paths = [os.path.join(self.img_dir, f\"{img_id}_{color}.png\") for color in [\"red\", \"green\", \"blue\", \"yellow\"]]\n\n#         # Load 4-channel image\n#         channels = [np.array(Image.open(img_path), dtype=np.float32) if os.path.exists(img_path) else np.zeros((512, 512), dtype=np.float32) for img_path in img_paths]\n#         image = np.stack(channels, axis=-1)  # Shape: (H, W, 4)\n\n#         # Normalize to 0-1\n#         image = image / 255.0\n\n#         # Apply transforms\n#         if self.transform:\n#             augmented = self.transform(image=image)\n#             image = augmented[\"image\"]\n\n#         # Multi-label target\n#         target = np.zeros(self.num_classes, dtype=np.float32)\n#         for label in self.df.iloc[idx]['Target']:\n#             target[label] = 1.0\n#         return image, torch.tensor(target, dtype=torch.float32)\n\n# # Define Data Augmentation\n# train_transform = A.Compose([\n#     A.RandomResizedCrop(224, 224),\n#     A.HorizontalFlip(p=0.5),\n#     A.VerticalFlip(p=0.5),\n#     A.Rotate(limit=30),\n#     A.Normalize(mean=[0.5]*4, std=[0.5]*4, max_pixel_value=1.0),\n#     ToTensorV2()\n# ])\n\n# val_transform = A.Compose([\n#     A.Resize(224, 224),\n#     A.Normalize(mean=[0.5]*4, std=[0.5]*4, max_pixel_value=1.0),\n#     ToTensorV2()\n# ])\n\n# # Dataloaders\n# train_dataset = ProteinDataset(df, TRAIN_DIR, transform=train_transform)\n# train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=2, pin_memory=True, persistent_workers=True)\n\n\n# # Modify ResNet to accept 4 channels\n# class CustomResNet(nn.Module):\n#     def __init__(self, num_classes=28):\n#         super().__init__()\n#         from torchvision.models import ResNet50_Weights\n#         self.model = models.resnet50(weights=ResNet50_Weights.DEFAULT)\n\n#         # Modify first conv layer for 4-channel input\n#         self.model.conv1 = nn.Conv2d(4, 64, kernel_size=7, stride=2, padding=3, bias=False)\n\n#         # Modify output layer\n#         self.model.fc = nn.Linear(self.model.fc.in_features, num_classes)\n\n#     def forward(self, x):\n#         return self.model(x)\n\n# # Weighted BCE Loss for Imbalanced Labels\n# class WeightedBCELoss(nn.Module):\n#     def __init__(self, pos_weight):\n#         super().__init__()\n#         self.criterion = nn.BCEWithLogitsLoss(pos_weight=pos_weight)\n\n#     def forward(self, inputs, targets):\n#         return self.criterion(inputs, targets)\n\n# # Calculate class weights based on frequency\n# label_counts = np.sum([target.numpy() for _, target in train_dataset], axis=0)\n# pos_weight = torch.tensor((len(train_dataset) - label_counts) / (label_counts + 1e-6), dtype=torch.float32)\n\n# # Training Loop\n# device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# model = CustomResNet().to(device)\n# criterion = WeightedBCELoss(pos_weight.to(device))\n# optimizer = optim.Adam(model.parameters(), lr=1e-4)\n\n# num_epochs = 30\n\n# # Evaluation Metrics\n# def mean_average_precision(y_true, y_pred):\n#     ap_per_class = []\n#     for i in range(y_true.shape[1]):\n#         ap = average_precision_score(y_true[:, i], y_pred[:, i])\n#         ap_per_class.append(ap)\n#     return np.mean(ap_per_class)\n\n# def f1_metric(y_true, y_pred, threshold=0.5):\n#     y_pred = (y_pred > threshold).astype(int)\n#     return f1_score(y_true, y_pred, average=\"macro\")\n\n# # Training with mAP and F1 Score Tracking\n# for epoch in range(num_epochs):\n#     model.train()\n#     running_loss = 0.0\n\n#     for images, targets in train_loader:\n#         images, targets = images.to(device), targets.to(device)\n\n#         optimizer.zero_grad()\n#         outputs = model(images)\n\n#         loss = criterion(outputs, targets)\n#         loss.backward()\n#         optimizer.step()\n\n#         running_loss += loss.item()\n\n#     # Evaluation after each epoch\n#     model.eval()\n#     y_true_list, y_pred_list = [], []\n\n#     with torch.no_grad():\n#         for images, targets in train_loader:\n#             images, targets = images.to(device), targets.to(device)\n#             outputs = model(images)\n#             y_true_list.append(targets.cpu().numpy())\n#             y_pred_list.append(torch.sigmoid(outputs).cpu().numpy())  # Apply sigmoid to get probabilities\n\n#     y_true = np.vstack(y_true_list)\n#     y_pred = np.vstack(y_pred_list)\n\n#     map_score = mean_average_precision(y_true, y_pred)\n#     f1_score_macro = f1_metric(y_true, y_pred)\n\n#     print(f\"Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss / len(train_loader):.4f}, mAP: {map_score:.4f}, F1 Score: {f1_score_macro:.4f}\")\n\n# print(\"Training Completed.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-07T23:57:25.926207Z","iopub.execute_input":"2025-03-07T23:57:25.926542Z","iopub.status.idle":"2025-03-07T23:57:25.965928Z","shell.execute_reply.started":"2025-03-07T23:57:25.926513Z","shell.execute_reply":"2025-03-07T23:57:25.965087Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Cutmix and BCE","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nfrom torchvision import models, transforms\nfrom torch.utils.data import Dataset, DataLoader, random_split\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nfrom sklearn.metrics import average_precision_score, f1_score\nimport random\n\ndef rand_bbox(size, lam):\n    W = size[2]\n    H = size[3]\n    cut_rat = np.sqrt(1. - lam)\n    cut_w = int(W * cut_rat)\n    cut_h = int(H * cut_rat)\n\n    # uniform\n    cx = np.random.randint(W)\n    cy = np.random.randint(H)\n\n    bbx1 = np.clip(cx - cut_w // 2, 0, W)\n    bby1 = np.clip(cy - cut_h // 2, 0, H)\n    bbx2 = np.clip(cx + cut_w // 2, 0, W)\n    bby2 = np.clip(cy + cut_h // 2, 0, H)\n\n    return bbx1, bby1, bbx2, bby2\n\n\n# Paths\nDATA_DIR = \"/kaggle/input/human-protein-atlas-image-classification\"\nTRAIN_DIR = os.path.join(DATA_DIR, \"train\")\nCSV_PATH = os.path.join(DATA_DIR, \"train.csv\")\n\n# Load CSV\ndf = pd.read_csv(CSV_PATH)\ndf['Target'] = df['Target'].apply(lambda x: list(map(int, str(x).split())) if pd.notna(x) else [])\n\n# Define Custom Dataset\nclass ProteinDataset(Dataset):\n    def __init__(self, df, img_dir, transform=None):\n        self.df = df\n        self.img_dir = img_dir\n        self.transform = transform\n        self.num_classes = 28\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        img_id = self.df.iloc[idx]['Id']\n        img_paths = [os.path.join(self.img_dir, f\"{img_id}_{color}.png\") for color in [\"red\", \"green\", \"blue\", \"yellow\"]]\n\n        # Load 4-channel image\n        channels = [np.array(Image.open(img_path), dtype=np.float32) if os.path.exists(img_path) else np.zeros((512, 512), dtype=np.float32) for img_path in img_paths]\n        image = np.stack(channels, axis=-1)  # Shape: (H, W, 4)\n\n        # Normalize to 0-1\n        image = image / 255.0\n\n        # Apply transforms\n        if self.transform:\n            augmented = self.transform(image=image)\n            image = augmented[\"image\"]\n\n        # Multi-label target\n        target = np.zeros(self.num_classes, dtype=np.float32)\n        for label in self.df.iloc[idx]['Target']:\n            target[label] = 1.0\n        return image, torch.tensor(target, dtype=torch.float32)\n\n# Define Data Augmentation\ntrain_transform = A.Compose([\n    A.RandomResizedCrop(224, 224),\n    A.HorizontalFlip(p=0.5),\n    A.VerticalFlip(p=0.5),\n    A.Rotate(limit=30),\n    A.Normalize(mean=[0.5]*4, std=[0.5]*4, max_pixel_value=1.0),\n    ToTensorV2()\n])\n\nval_transform = A.Compose([\n    A.Resize(224, 224),\n    A.Normalize(mean=[0.5]*4, std=[0.5]*4, max_pixel_value=1.0),\n    ToTensorV2()\n])\n\n# Split dataset into train and validation sets\ntrain_size = int(0.8 * len(df))  # 80% train, 20% validation\nval_size = len(df) - train_size\ntrain_df, val_df = random_split(df, [train_size, val_size], generator=torch.Generator().manual_seed(42))\n\n# Create datasets\ntrain_dataset = ProteinDataset(train_df, TRAIN_DIR, transform=train_transform)\nval_dataset = ProteinDataset(val_df, TRAIN_DIR, transform=val_transform)\n\n# Create data loaders\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=2, pin_memory=True, persistent_workers=True)\nval_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=2, pin_memory=True, persistent_workers=True)\n\n# Modify ResNet to accept 4 channels\nclass CustomResNet(nn.Module):\n    def __init__(self, num_classes=28):\n        super().__init__()\n        from torchvision.models import ResNet50_Weights\n        self.model = models.resnet50(weights=ResNet50_Weights.DEFAULT)\n\n        # Modify first conv layer for 4-channel input\n        self.model.conv1 = nn.Conv2d(4, 64, kernel_size=7, stride=2, padding=3, bias=False)\n\n        # Modify output layer\n        self.model.fc = nn.Linear(self.model.fc.in_features, num_classes)\n\n    def forward(self, x):\n        return self.model(x)\n\n# Weighted BCE Loss for Imbalanced Labels\nclass WeightedBCELoss(nn.Module):\n    def __init__(self, pos_weight):\n        super().__init__()\n        self.criterion = nn.BCEWithLogitsLoss(pos_weight=pos_weight)\n\n    def forward(self, inputs, targets):\n        return self.criterion(inputs, targets)\n\n# Calculate class weights based on frequency\nlabel_counts = np.sum([target.numpy() for _, target in train_dataset], axis=0)\npos_weight = torch.tensor((len(train_dataset) - label_counts) / (label_counts + 1e-6), dtype=torch.float32)\n\n# Training Loop\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = CustomResNet().to(device)\ncriterion = WeightedBCELoss(pos_weight.to(device))\noptimizer = optim.Adam(model.parameters(), lr=1e-4)\n\nnum_epochs = 50\n\n# Evaluation Metrics\ndef mean_average_precision(y_true, y_pred):\n    ap_per_class = []\n    for i in range(y_true.shape[1]):\n        ap = average_precision_score(y_true[:, i], y_pred[:, i])\n        ap_per_class.append(ap)\n    return np.mean(ap_per_class)\n\ndef f1_metric(y_true, y_pred, threshold=0.5):\n    y_pred = (y_pred > threshold).astype(int)\n    return f1_score(y_true, y_pred, average=\"macro\")\n\n# Training loop with CutMix\nfor epoch in range(num_epochs):\n    model.train()\n    running_loss = 0.0\n\n    for images, targets in train_loader:\n        images, targets = images.to(device), targets.to(device)\n\n        r = np.random.rand(1)\n        cutmix_prob = 0.5  # Probability to apply CutMix\n        if r < cutmix_prob:\n            # generate mixed sample\n            lam = np.random.beta(1.0, 1.0)\n            rand_index = torch.randperm(images.size()[0]).to(device)\n            target_a = targets\n            target_b = targets[rand_index]\n            bbx1, bby1, bbx2, bby2 = rand_bbox(images.size(), lam)\n            images[:, :, bbx1:bbx2, bby1:bby2] = images[rand_index, :, bbx1:bbx2, bby1:bby2]\n\n            # adjust lambda to exactly match pixel ratio\n            lam = 1 - ((bbx2 - bbx1) * (bby2 - bby1) / (images.size()[-1] * images.size()[-2]))\n\n            optimizer.zero_grad()\n            outputs = model(images)\n            loss = criterion(outputs, target_a) * lam + criterion(outputs, target_b) * (1. - lam)\n        else:\n            optimizer.zero_grad()\n            outputs = model(images)\n            loss = criterion(outputs, targets)\n\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n\n    # Validation loop\n    model.eval()\n    y_true_list, y_pred_list = [], []\n\n    with torch.no_grad():\n        for images, targets in val_loader:\n            images, targets = images.to(device), targets.to(device)\n            outputs = model(images)\n            y_true_list.append(targets.cpu().numpy())\n            y_pred_list.append(torch.sigmoid(outputs).cpu().numpy())\n\n    y_true = np.vstack(y_true_list)\n    y_pred = np.vstack(y_pred_list)\n\n    map_score = mean_average_precision(y_true, y_pred)\n    f1_score_macro = f1_metric(y_true, y_pred)\n\n    print(f\"Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss / len(train_loader):.4f}, mAP: {map_score:.4f}, F1 Score: {f1_score_macro:.4f}\")\n\nprint(\"Training Completed.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}