{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":98450,"databundleVersionId":11749951,"sourceType":"competition"},{"sourceId":239995795,"sourceType":"kernelVersion"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Spectrum 128 Lightning CNN Regressor","metadata":{"papermill":{"duration":0.003895,"end_time":"2023-06-30T09:39:19.33539","exception":false,"start_time":"2023-06-30T09:39:19.331495","status":"completed"},"tags":[]}},{"cell_type":"code","source":"!pip install lightning","metadata":{"papermill":{"duration":0.003048,"end_time":"2023-06-30T09:39:19.341832","exception":false,"start_time":"2023-06-30T09:39:19.338784","status":"completed"},"tags":[],"trusted":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2025-05-16T13:28:42.041727Z","iopub.execute_input":"2025-05-16T13:28:42.041938Z","iopub.status.idle":"2025-05-16T13:30:07.421787Z","shell.execute_reply.started":"2025-05-16T13:28:42.041920Z","shell.execute_reply":"2025-05-16T13:30:07.420728Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport random\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import random_split\nfrom torch.utils.data import DataLoader, Dataset, Subset\nfrom torch.utils.data import random_split, SubsetRandomSampler\nfrom torchvision import datasets, transforms, models \nfrom torchvision.datasets import ImageFolder\nfrom torchvision.transforms import ToTensor\nfrom torchvision.utils import make_grid\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau\n\nfrom lightning.pytorch import LightningDataModule\nfrom lightning.pytorch import LightningModule\nfrom lightning.pytorch import Trainer\nimport lightning.pytorch as L\nprint(L.__version__)\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import classification_report\nfrom PIL import Image","metadata":{"papermill":{"duration":13.262195,"end_time":"2023-06-30T09:39:32.607264","exception":false,"start_time":"2023-06-30T09:39:19.345069","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-05-16T13:30:07.423858Z","iopub.execute_input":"2025-05-16T13:30:07.424156Z","iopub.status.idle":"2025-05-16T13:30:23.810957Z","shell.execute_reply.started":"2025-05-16T13:30:07.424127Z","shell.execute_reply":"2025-05-16T13:30:23.809999Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = transforms.Compose([\n            #transforms.Resize(224),             # resize shortest side to 224 pixels\n            #transforms.CenterCrop(224),         # crop longest side to 224 pixels at center            \n            transforms.ToTensor(),\n            transforms.Normalize([0.485, 0.456, 0.406],\n                                 [0.229, 0.224, 0.225])\n        ])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T13:30:23.811900Z","iopub.execute_input":"2025-05-16T13:30:23.812350Z","iopub.status.idle":"2025-05-16T13:30:23.817363Z","shell.execute_reply.started":"2025-05-16T13:30:23.812328Z","shell.execute_reply":"2025-05-16T13:30:23.816251Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df1=pd.read_csv('/kaggle/input/visible-spectrum-split-data-by-shape/data128.csv')\ndf2=pd.read_csv('/kaggle/input/visible-spectrum-split-data-by-shape/data057.csv')\ndf=pd.concat([df1,df2],axis=0)\ndisplay(df[0:3])\nprint(len(df))\ntrain=df[df['traintest']=='train']\ntest=df[df['traintest']=='test']\nprint(len(train),len(test))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T13:30:23.818735Z","iopub.execute_input":"2025-05-16T13:30:23.819065Z","iopub.status.idle":"2025-05-16T13:30:23.884808Z","shell.execute_reply.started":"2025-05-16T13:30:23.819035Z","shell.execute_reply":"2025-05-16T13:30:23.883898Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"path_label = list(train[['path','label']].itertuples(index=False, name=None))\ntpath_label = list(test[['path','label']].itertuples(index=False, name=None))\nprint(path_label[0:3])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T13:30:23.885652Z","iopub.execute_input":"2025-05-16T13:30:23.885935Z","iopub.status.idle":"2025-05-16T13:30:23.896597Z","shell.execute_reply.started":"2025-05-16T13:30:23.885909Z","shell.execute_reply":"2025-05-16T13:30:23.895457Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Custom3DDataset(Dataset):\n    def __init__(self, path_label, transform=None):\n        self.path_label = path_label\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.path_label)\n\n    def __getitem__(self, idx):\n        file_path, label = self.path_label[idx]\n        \n        # Load the 3D data (assumes it's a NumPy array)\n        data = np.load(file_path)  # shape: (128, 128, 125)\n        \n        # Add channel dimension: (C, D, H, W)\n        data = torch.from_numpy(data).float().unsqueeze(0)\n        \n        if self.transform:\n            data = self.transform(data)\n            \n        return data, torch.tensor(label, dtype=torch.float)","metadata":{"papermill":{"duration":0.012446,"end_time":"2023-06-30T09:39:33.013124","exception":false,"start_time":"2023-06-30T09:39:33.000678","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-05-16T13:30:23.897733Z","iopub.execute_input":"2025-05-16T13:30:23.898027Z","iopub.status.idle":"2025-05-16T13:30:23.912870Z","shell.execute_reply.started":"2025-05-16T13:30:23.897997Z","shell.execute_reply":"2025-05-16T13:30:23.912038Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class DataModule(LightningDataModule):\n    def __init__(\n        self,\n        train_path_label: str,  # Required\n        test_path_label: str = None,  # Optional\n        root_dir: str = None,\n        batch_size: int = 32,\n        val_split: float = 0.2,  # 20% for validation\n    ):\n        super().__init__()\n        self.train_path_label = train_path_label\n        self.test_path_label = test_path_label\n        self.root_dir = root_dir\n        self.batch_size = batch_size\n        self.val_split = val_split\n\n        # Transformations for 3D data\n        self.transform = transforms.Compose([\n            transforms.Lambda(lambda x: x.float()),\n            transforms.Normalize(mean=[0.5], std=[0.5])\n        ])\n\n        self.train_dataset = None\n        self.val_dataset = None\n        self.test_dataset = None\n\n    def setup(self, stage=None):\n        # Load full training dataset\n        full_dataset = Custom3DDataset(\n            self.train_path_label, \n            transform=self.transform\n        )\n\n        # Split into train/val\n        dataset_size = len(full_dataset)\n        val_size = int(self.val_split * dataset_size)\n        train_size = dataset_size - val_size\n        \n        indices = list(range(dataset_size))\n        self.train_dataset = Subset(full_dataset, indices[:train_size])\n        self.val_dataset = Subset(full_dataset, indices[train_size:])\n\n        # Load test data if provided\n        if self.test_path_label:\n            self.test_dataset = Custom3DDataset(\n                self.test_path_label,\n                transform=self.transform\n            )\n\n    def train_dataloader(self):\n        return DataLoader(\n            self.train_dataset,\n            batch_size=self.batch_size,\n            shuffle=True\n        )\n\n    def val_dataloader(self):\n        return DataLoader(\n            self.val_dataset,\n            batch_size=self.batch_size\n        )\n\n    def test_dataloader(self):\n        if self.test_dataset is None:\n            raise ValueError(\"Test dataset not provided. Set test_path_label.\")\n        return DataLoader(\n            self.test_dataset,\n            batch_size=self.batch_size\n        )","metadata":{"papermill":{"duration":0.012953,"end_time":"2023-06-30T09:39:33.049085","exception":false,"start_time":"2023-06-30T09:39:33.036132","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-05-16T13:30:23.914955Z","iopub.execute_input":"2025-05-16T13:30:23.915211Z","iopub.status.idle":"2025-05-16T13:30:23.932513Z","shell.execute_reply.started":"2025-05-16T13:30:23.915190Z","shell.execute_reply":"2025-05-16T13:30:23.931690Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---","metadata":{}},{"cell_type":"markdown","source":"## ConvolutionalRegressor","metadata":{}},{"cell_type":"code","source":"class ConvolutionalRegressor3D(LightningModule):\n    def __init__(self):\n        super(ConvolutionalRegressor3D, self).__init__()\n        \n        # Input shape: [batch, 1, 128, 128, 125]\n        self.conv1 = nn.Conv3d(1, 6, kernel_size=3, stride=1, padding=1)\n        self.bn1 = nn.BatchNorm3d(6)\n        self.pool1 = nn.MaxPool3d(kernel_size=2, stride=2)  # -> [batch, 6, 64, 64, 62]\n        \n        self.conv2 = nn.Conv3d(6, 16, kernel_size=3, stride=1, padding=1)\n        self.bn2 = nn.BatchNorm3d(16)\n        self.pool2 = nn.MaxPool3d(kernel_size=2, stride=2)  # -> [batch, 16, 32, 32, 31]\n        \n        # Compute the input size of the fully connected layer\n        self.flattened_size = self._get_flattened_size()\n        \n        # Fully connected layers\n        self.fc1 = nn.Linear(self.flattened_size, 256)\n        self.fc2 = nn.Linear(256, 128)\n        self.fc3 = nn.Linear(128, 64)\n        self.fc4 = nn.Linear(64, 1)  # Output is 1 for regression task\n        \n        # Initialize weights\n        self._initialize_weights()\n        \n    def _get_flattened_size(self):\n        \"\"\"Calculate the size after flattening using dummy input\"\"\"\n        dummy_input = torch.zeros(1, 1, 128, 128, 125)\n        x = self.pool1(F.relu(self.bn1(self.conv1(dummy_input))))\n        x = self.pool2(F.relu(self.bn2(self.conv2(x))))\n        return x.numel()  # 16 * 32 * 32 * 31 = 507,904\n        \n    def _initialize_weights(self):\n        \"\"\"Initialize weights\"\"\"\n        for m in self.modules():\n            if isinstance(m, nn.Conv3d):\n                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')\n                if m.bias is not None:\n                    nn.init.constant_(m.bias, 0)\n            elif isinstance(m, nn.BatchNorm3d):\n                nn.init.constant_(m.weight, 1)\n                nn.init.constant_(m.bias, 0)\n            elif isinstance(m, nn.Linear):\n                nn.init.normal_(m.weight, 0, 0.01)\n                nn.init.constant_(m.bias, 0)\n    \n    def forward(self, x):\n        # Input shape: [batch, 1, 128, 128, 125]\n        x = self.pool1(F.relu(self.bn1(self.conv1(x))))  # -> [batch, 6, 64, 64, 62]\n        x = self.pool2(F.relu(self.bn2(self.conv2(x))))  # -> [batch, 16, 32, 32, 31]\n        \n        x = x.view(x.size(0), -1)  # Flatten\n        x = F.relu(self.fc1(x))\n        x = F.relu(self.fc2(x))\n        x = F.relu(self.fc3(x))\n        x = self.fc4(x)  # No activation since this is a regression task\n        return x\n\n    def preprocess_data(self, x):\n        \"\"\"\n        Normalize each sample individually to zero mean and unit variance\n        across spatial dimensions (D, H, W) only\n        \"\"\"\n        # Calculate mean and std over spatial dimensions for each sample\n        mean = x.mean(dim=(2, 3, 4), keepdim=True)\n        std = x.std(dim=(2, 3, 4), keepdim=True)\n        \n        # Normalize with numerical stability\n        eps = 1e-5\n        normalized_x = (x - mean) / (std + eps)\n        \n        # Clamp values to prevent extreme outliers\n        normalized_x = torch.clamp(normalized_x, -5.0, 5.0)\n        \n        return normalized_x\n\n    def training_step(self, batch, batch_idx):\n        x, y = batch\n        x = self.preprocess_data(x)\n        y_hat = self(x)\n        \n        # Ensure target has correct shape and type\n        y = y.float()\n        if len(y.shape) > 1:\n            y = y.squeeze(-1)\n        \n        loss = F.mse_loss(y_hat, y)\n        \n        # Log training metrics\n        self.log(\"train_loss\", loss, prog_bar=True)\n        self.log(\"lr\", self.optimizers().param_groups[0]['lr'], prog_bar=True)\n        \n        return loss\n\n    def validation_step(self, batch, batch_idx):\n        x, y = batch\n        x = self.preprocess_data(x)\n        y_hat = self(x)\n        \n        y = y.float()\n        if len(y.shape) > 1:\n            y = y.squeeze(-1)\n        \n        loss = F.mse_loss(y_hat, y)\n        self.log(\"val_loss\", loss, prog_bar=True)\n        return loss\n\n    def test_step(self, batch, batch_idx):\n        x, y = batch\n        x = self.preprocess_data(x)\n        y_hat = self(x)\n        \n        y = y.float()\n        if len(y.shape) > 1:\n            y = y.squeeze(-1)\n        \n        loss = F.mse_loss(y_hat, y)\n        self.log(\"test_loss\", loss, prog_bar=True)\n        return loss\n    \n    def configure_optimizers(self):\n        optimizer = torch.optim.AdamW(self.parameters(), lr=0.0005, weight_decay=1e-4)\n        \n        scheduler = ReduceLROnPlateau(\n            optimizer, \n            mode='min', \n            factor=0.5, \n            patience=5, \n            verbose=True,\n            min_lr=1e-6\n        )\n        \n        return {\n            'optimizer': optimizer,\n            'lr_scheduler': {\n                'scheduler': scheduler,\n                'monitor': 'val_loss',\n                'interval': 'epoch',\n                'frequency': 1\n            },\n            'gradient_clip_val': 0.5,\n            'gradient_clip_algorithm': 'value'\n        }\n","metadata":{"papermill":{"duration":0.01833,"end_time":"2023-06-30T09:39:33.071843","exception":false,"start_time":"2023-06-30T09:39:33.053513","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-05-16T13:30:23.933419Z","iopub.execute_input":"2025-05-16T13:30:23.933725Z","iopub.status.idle":"2025-05-16T13:30:23.956947Z","shell.execute_reply.started":"2025-05-16T13:30:23.933701Z","shell.execute_reply":"2025-05-16T13:30:23.956054Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if __name__ == '__main__':\n    # Initialize data module and model\n    datamodule = DataModule(train_path_label=path_label, test_path_label=tpath_label)\n    datamodule.setup()\n    \n    # Initialize model with additional debugging\n    model = ConvolutionalRegressor3D()\n    \n    # Setup trainer with early stopping and checkpointing\n    trainer = L.Trainer(\n        max_epochs=30,\n        callbacks=[\n            L.callbacks.EarlyStopping(\n                monitor='val_loss',\n                patience=10,\n                mode='min'\n            ),\n            L.callbacks.ModelCheckpoint(\n                monitor='val_loss',\n                save_top_k=1,\n                mode='min'\n            )\n        ],\n        log_every_n_steps=10,\n        detect_anomaly=True  # Enable anomaly detection for debugging\n    )\n    \n    # Train the model\n    trainer.fit(model, datamodule)\n    \n    # Test the model\n    test_loader = datamodule.test_dataloader()\n    trainer.test(dataloaders=test_loader)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T13:30:23.957831Z","iopub.execute_input":"2025-05-16T13:30:23.958070Z","iopub.status.idle":"2025-05-16T13:30:56.833412Z","shell.execute_reply.started":"2025-05-16T13:30:23.958051Z","shell.execute_reply":"2025-05-16T13:30:56.832568Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cpu\")   #\"cuda:0\"\nmodel.eval()\ny_pred=[]\nwith torch.no_grad():\n    for test_data in datamodule.test_dataloader():\n        test_images, test_labels = test_data[0].to(device), test_data[1].to(device)\n        pred = model(test_images)  ##########\n        for i in range(len(pred)):\n            y_pred.append(pred[i].item())","metadata":{"papermill":{"duration":5.368379,"end_time":"2023-06-30T09:55:39.113208","exception":false,"start_time":"2023-06-30T09:55:33.744829","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-05-16T13:30:56.834331Z","iopub.execute_input":"2025-05-16T13:30:56.835290Z","iopub.status.idle":"2025-05-16T13:30:57.751312Z","shell.execute_reply.started":"2025-05-16T13:30:56.834590Z","shell.execute_reply":"2025-05-16T13:30:57.750370Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test['label']=y_pred\ndisplay(test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T13:30:57.752106Z","iopub.execute_input":"2025-05-16T13:30:57.752344Z","iopub.status.idle":"2025-05-16T13:30:57.764041Z","shell.execute_reply.started":"2025-05-16T13:30:57.752326Z","shell.execute_reply":"2025-05-16T13:30:57.763159Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test.to_csv('submission_128.csv',index=False)","metadata":{"papermill":{"duration":0.008862,"end_time":"2023-06-30T09:55:39.131596","exception":false,"start_time":"2023-06-30T09:55:39.122734","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T13:30:57.764859Z","iopub.execute_input":"2025-05-16T13:30:57.765171Z","iopub.status.idle":"2025-05-16T13:30:57.785051Z","shell.execute_reply.started":"2025-05-16T13:30:57.765144Z","shell.execute_reply":"2025-05-16T13:30:57.784020Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"papermill":{"duration":0.009079,"end_time":"2023-06-30T09:55:39.150422","exception":false,"start_time":"2023-06-30T09:55:39.141343","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null}]}