{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"colab":{"machine_shape":"hm","gpuType":"T4"},"accelerator":"GPU","kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":20270,"databundleVersionId":1222630,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":9797223,"sourceType":"datasetVersion","datasetId":982170},{"sourceId":80230206,"sourceType":"kernelVersion"},{"sourceId":265828939,"sourceType":"kernelVersion"}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import sys\nsys.path.append(\"../input/tez-lib/\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-08T17:26:51.000964Z","iopub.execute_input":"2025-10-08T17:26:51.001206Z","iopub.status.idle":"2025-10-08T17:26:51.010484Z","shell.execute_reply.started":"2025-10-08T17:26:51.001183Z","shell.execute_reply":"2025-10-08T17:26:51.009546Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import timm\n# from pprint import pprint\n# model_names = timm.list_models(pretrained=True)\n# pprint(model_names)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-08T17:26:51.012447Z","iopub.execute_input":"2025-10-08T17:26:51.012722Z","iopub.status.idle":"2025-10-08T17:26:51.033092Z","shell.execute_reply.started":"2025-10-08T17:26:51.012699Z","shell.execute_reply":"2025-10-08T17:26:51.032266Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import random\nimport numpy as np\nimport torch\nimport os\n\ndef seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    \nseed_everything(42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-08T17:26:51.033938Z","iopub.execute_input":"2025-10-08T17:26:51.034196Z","iopub.status.idle":"2025-10-08T17:26:54.979204Z","shell.execute_reply.started":"2025-10-08T17:26:51.034173Z","shell.execute_reply":"2025-10-08T17:26:54.978284Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\n\nfrom tez import Tez, TezConfig\nimport tez\nimport albumentations\nimport pandas as pd\nimport cv2\nimport numpy as np\nimport timm\nimport torch.nn as nn\nfrom sklearn import metrics\nimport torch\nfrom tez.callbacks import EarlyStopping\nfrom tqdm import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-08T17:26:54.980137Z","iopub.execute_input":"2025-10-08T17:26:54.980481Z","iopub.status.idle":"2025-10-08T17:27:05.701948Z","shell.execute_reply.started":"2025-10-08T17:26:54.980460Z","shell.execute_reply":"2025-10-08T17:27:05.701330Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class args:\n    batch_size = 8\n    image_size = 384\n    epochs = 12 #10\n    fold = 0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-08T17:27:05.703151Z","iopub.execute_input":"2025-10-08T17:27:05.703671Z","iopub.status.idle":"2025-10-08T17:27:05.707524Z","shell.execute_reply.started":"2025-10-08T17:27:05.703640Z","shell.execute_reply":"2025-10-08T17:27:05.706681Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CustomDataset:\n    def __init__(self, image_paths, dense_features, targets, augmentations):\n        self.image_paths = image_paths\n        self.dense_features = dense_features\n        self.targets = targets\n        self.augmentations = augmentations\n        \n    def __len__(self):\n        return len(self.image_paths)\n    \n    def __getitem__(self, item):\n        image = cv2.imread(self.image_paths[item])\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        \n        if self.augmentations is not None:\n            augmented = self.augmentations(image=image)\n            image = augmented[\"image\"]\n            \n        image = np.transpose(image, (2, 0, 1)).astype(np.float32)\n        \n        features = self.dense_features[item, :]\n        targets = self.targets[item]\n        \n        return {\n            \"image\": torch.tensor(image, dtype=torch.float),\n            \"features\": torch.tensor(features, dtype=torch.float),\n            \"targets\": torch.tensor(targets, dtype=torch.float),\n        }","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-08T17:27:05.708261Z","iopub.execute_input":"2025-10-08T17:27:05.708491Z","iopub.status.idle":"2025-10-08T17:27:05.725642Z","shell.execute_reply.started":"2025-10-08T17:27:05.708475Z","shell.execute_reply":"2025-10-08T17:27:05.724828Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CustomModel(nn.Module):\n    def __init__(self, pos_weight: float = None):\n        super().__init__()\n        self.backbone = timm.create_model(\"resnet50\", pretrained=True, in_chans=3, num_classes=0)\n        in_features = getattr(self.backbone, \"num_features\", 2048)\n        self.dropout = nn.Dropout(0.5)\n        self.out = nn.Linear(in_features, 1)\n        self.step_scheduler_after = \"epoch\"\n\n        if pos_weight is not None:\n            self.register_buffer(\"pos_weight\", torch.tensor([pos_weight], dtype=torch.float))\n        else:\n            self.pos_weight = None\n\n    def monitor_metrics(self, outputs, targets, loss):\n        with torch.no_grad():\n            # collect per-batch safely; impute neutral AUC=0.5 if single-class\n            probs = torch.sigmoid(outputs).detach().view(-1)\n            t = targets.detach().view(-1)\n            t_np = t.cpu().numpy()\n            p_np = probs.cpu().numpy()\n            if len(np.unique(t_np)) < 2:\n                auc_val = 0.5\n            else:\n                try:\n                    auc_val = metrics.roc_auc_score(t_np, p_np)\n                except Exception:\n                    auc_val = 0.5\n        return {\n            \"binaryloss\": loss.detach(),\n            \"auc\": torch.tensor(auc_val, device=outputs.device, dtype=outputs.dtype),\n        }\n\n    def optimizer_scheduler(self):\n        opt = torch.optim.AdamW(self.parameters(), lr=2.5e-05, weight_decay=0.01)\n        sch = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(\n            opt, T_0=10, T_mult=1, eta_min=1e-6, last_epoch=-1\n        )\n        return opt, sch\n\n    def forward(self, image, features, targets=None):\n        feats = self.backbone(image)\n        x = self.dropout(feats)\n        logits = self.out(x)\n        if targets is not None:\n            loss_fn = nn.BCEWithLogitsLoss(pos_weight=self.pos_weight) if self.pos_weight is not None else nn.BCEWithLogitsLoss()\n            loss = loss_fn(logits, targets.view(-1, 1).type_as(logits))\n            metrics_dict = self.monitor_metrics(logits, targets, loss)\n            return logits, loss, metrics_dict\n        return logits, 0, {}\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-08T17:27:05.728084Z","iopub.execute_input":"2025-10-08T17:27:05.728298Z","iopub.status.idle":"2025-10-08T17:27:05.741553Z","shell.execute_reply.started":"2025-10-08T17:27:05.728281Z","shell.execute_reply":"2025-10-08T17:27:05.740839Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_aug = albumentations.Compose(\n    [\n#         albumentations.Resize(args.image_size, args.image_size, p=1),\n        albumentations.LongestMaxSize(args.image_size, p=1),\n        albumentations.PadIfNeeded(args.image_size,args.image_size, p=1,border_mode=0),\n        \n       albumentations.HorizontalFlip(p=0.5),\n       albumentations.VerticalFlip(p=0.1),\n       albumentations.Rotate(limit=180, p=0.5),\n       albumentations.ShiftScaleRotate(\n                shift_limit=0.1, scale_limit=0.1, rotate_limit=45, p=0.5\n            ),\n        \n        albumentations.HueSaturationValue(\n            hue_shift_limit=0.2, sat_shift_limit=0.2, val_shift_limit=0.2, p=0.5\n        ),\n        albumentations.RandomBrightnessContrast(\n            brightness_limit=(-0.1, 0.1), contrast_limit=(-0.1, 0.1), p=0.5\n        ),\n        albumentations.Normalize(\n            mean=[0.485, 0.456, 0.406],\n            std=[0.229, 0.224, 0.225],\n            max_pixel_value=255.0,\n            p=1.0,\n        ),\n    ],\n    p=1.0,\n)\n\nvalid_aug = albumentations.Compose(\n    [\n#         albumentations.Resize(args.image_size, args.image_size, p=1),\n        albumentations.LongestMaxSize(args.image_size, p=1),\n        albumentations.PadIfNeeded(args.image_size,args.image_size, p=1,border_mode=0),\n        albumentations.Normalize(\n            mean=[0.485, 0.456, 0.406],\n            std=[0.229, 0.224, 0.225],\n            max_pixel_value=255.0,\n            p=1.0,\n        ),\n    ],\n    p=1.0,\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-08T17:27:05.742505Z","iopub.execute_input":"2025-10-08T17:27:05.742756Z","iopub.status.idle":"2025-10-08T17:27:05.767231Z","shell.execute_reply.started":"2025-10-08T17:27:05.742728Z","shell.execute_reply":"2025-10-08T17:27:05.766316Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(\"/kaggle/input/vinay-reddy-10083/train_5folds.csv\")\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-08T17:27:05.768140Z","iopub.execute_input":"2025-10-08T17:27:05.768433Z","iopub.status.idle":"2025-10-08T17:27:05.832628Z","shell.execute_reply.started":"2025-10-08T17:27:05.768399Z","shell.execute_reply":"2025-10-08T17:27:05.831802Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"i = 0\nprint(f\"training fold: {i} start\")\nargs.fold = 0\n\n# pick valid target column and normalize to 0/1 ints\ntarget_candidates = [\"Custom\", \"target\", \"label\", \"is_malignant\", \"malignant\", \"cancer\"]\ntarget_col = next((c for c in target_candidates if c in df.columns), None)\nif target_col is None:\n    raise KeyError(f\"Target column not found. Tried: {target_candidates}. Available: {list(df.columns)}\")\ndf[target_col] = pd.to_numeric(df[target_col], errors=\"coerce\").fillna(0).astype(int).clip(0, 1)\n\n# split folds\ndf_train = df[df.kfold != args.fold].reset_index(drop=True)\ndf_valid = df[df.kfold == args.fold].reset_index(drop=True)\n\ndense_features = []\n\n# build paths\ntrain_img_paths = [f\"/kaggle/input/siim-isic-melanoma-classification/jpeg/train/{x}.jpg\" for x in df_train[\"image_name\"].values]\nvalid_img_paths = [f\"/kaggle/input/siim-isic-melanoma-classification/jpeg/train/{x}.jpg\" for x in df_valid[\"image_name\"].values]\n\n# datasets\ntrain_dataset = CustomDataset(\n    image_paths=train_img_paths,\n    dense_features=df_train[dense_features].values,\n    targets=df_train[target_col].values,\n    augmentations=train_aug,\n)\n\nvalid_dataset = CustomDataset(\n    image_paths=valid_img_paths,\n    dense_features=df_valid[dense_features].values,\n    targets=df_valid[target_col].values,\n    augmentations=valid_aug,\n)\n\n# class weight for BCEWithLogitsLoss\npos = int((df_train[target_col] == 1).sum())\nneg = int((df_train[target_col] == 0).sum())\npos_weight = float(neg / max(pos, 1))\n\n# model + trainer\nmodel = CustomModel(pos_weight=pos_weight)\nmodel = Tez(model)\n\nconfig = TezConfig(\n    training_batch_size=args.batch_size,\n    validation_batch_size=2 * args.batch_size,\n    epochs=args.epochs,\n    step_scheduler_after=\"epoch\",\n    # IMPORTANT: do not pass a metric to CosineAnnealingWarmRestarts; step without metric to avoid NaN issues\n    step_scheduler_metric=None,\n    fp16=True,\n    val_strategy=\"epoch\",\n)\n\nes = EarlyStopping(\n    monitor=\"valid_auc\",\n    model_path=f\"model_f{args.fold}.bin\",\n    patience=4,\n    mode=\"max\",\n    save_weights_only=True,\n)\n\nmodel.fit(\n    train_dataset,\n    valid_dataset=valid_dataset,\n    callbacks=[es],\n    config=config,\n)\nprint(f\"training fold: {i} complete\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-08T17:27:05.833502Z","iopub.execute_input":"2025-10-08T17:27:05.833731Z","iopub.status.idle":"2025-10-08T17:30:06.591837Z","shell.execute_reply.started":"2025-10-08T17:27:05.833713Z","shell.execute_reply":"2025-10-08T17:30:06.591089Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}