{"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":"gpu","dataSources":[{"sourceId":98450,"databundleVersionId":11749951,"sourceType":"competition"}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"#!pip install umap-learn","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:22:51.768030Z","iopub.execute_input":"2025-05-16T19:22:51.768813Z","iopub.status.idle":"2025-05-16T19:22:51.772392Z","shell.execute_reply.started":"2025-05-16T19:22:51.768782Z","shell.execute_reply":"2025-05-16T19:22:51.771838Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom sklearn.decomposition import PCA\nimport umap.umap_ as umap\nimport os\nfrom scipy.cluster.hierarchy import dendrogram, linkage\nfrom scipy.stats import f_oneway, kruskal\nfrom scipy.stats import levene, bartlett\nfrom scipy.stats import ttest_ind, mannwhitneyu\nfrom scipy.stats import shapiro\nfrom sklearn.decomposition import PCA\nfrom sklearn.cluster import KMeans\n\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:22:51.779210Z","iopub.execute_input":"2025-05-16T19:22:51.779443Z","iopub.status.idle":"2025-05-16T19:23:27.347818Z","shell.execute_reply.started":"2025-05-16T19:22:51.779425Z","shell.execute_reply":"2025-05-16T19:23:27.347249Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_DIR = '/kaggle/input/beyond-visible-spectrum-ai-for-agriculture-2025/ot/ot'\nCSV_PATH = '/kaggle/input/beyond-visible-spectrum-ai-for-agriculture-2025/train.csv'\n\ndf = pd.read_csv(CSV_PATH)\n\ndata_list = []\nlabels = []\n\nexpected_shape = (128,128,125)\n\nfor _, row in df.iterrows():\n    file_path = os.path.join(DATA_DIR, row['id'])\n    \n    try:\n        cube = np.load(file_path)\n\n        if cube.shape != expected_shape:\n            continue\n        mean_spectrum = cube.reshape(-1, cube.shape[2]).mean(axis=0)\n        data_list.append(mean_spectrum)\n        labels.append(row['label'])\n\n    except Exception as e:\n        print(f'Error with {file_path} {e}')\n        \n\nX = np.array(data_list)\ny = np.array(labels)\n\n\nreducer = umap.UMAP(random_state=42)\nX_embedded = reducer.fit_transform(X)\n\nplt.figure(figsize=(10, 8), constrained_layout=True)\nsns.scatterplot(x=X_embedded[:, 0], y=X_embedded[:, 1], hue=y, palette='tab10')\nplt.title('UMAP Projection of Hyperspectral Data by Label')\nplt.xlabel('UMAP 1')\nplt.ylabel('UMAP 2')\nplt.legend(title='Label', bbox_to_anchor=(1.05, 1), loc='upper left')\nplt.savefig(\"umap_plot.png\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:23:27.349053Z","iopub.execute_input":"2025-05-16T19:23:27.349665Z","iopub.status.idle":"2025-05-16T19:24:58.556637Z","shell.execute_reply.started":"2025-05-16T19:23:27.349639Z","shell.execute_reply":"2025-05-16T19:24:58.555875Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_spectra = pd.DataFrame(X)\ndf_spectra['id'] = y\n\nplt.figure(figsize=(12, 6))\nfor label in df_spectra['id'].unique():\n    mean_spectrum = df_spectra[df_spectra['id'] == label].drop('id', axis=1).mean()\n    plt.plot(mean_spectrum, label=label)\n\nplt.title('Mean Reflectance Spectra per Class')\nplt.xlabel('Bands (Spectral Channels)')\nplt.ylabel('Reflectance')\nplt.legend(title='Class Label')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:24:58.557489Z","iopub.execute_input":"2025-05-16T19:24:58.557708Z","iopub.status.idle":"2025-05-16T19:25:00.350000Z","shell.execute_reply.started":"2025-05-16T19:24:58.557691Z","shell.execute_reply":"2025-05-16T19:25:00.349194Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_plot = df_spectra.copy()\nselected_bands = [10, 50, 100] \n\nfor band in selected_bands:\n    plt.figure(figsize=(14, 5))\n    sns.boxplot(data=df_plot, x='id', y=band)\n    plt.title(f'Boxplot for Band {band}')\n    plt.xlabel('Class')\n    plt.ylabel(f'Reflectance at Band {band}')\n    plt.tight_layout()\n    plt.show()\n\n    plt.figure(figsize=(14, 5))\n    sns.violinplot(data=df_plot, x='id', y=band)\n    plt.title(f'Violinplot for Band {band}')\n    plt.xlabel('Class')\n    plt.ylabel(f'Reflectance at Band {band}')\n    plt.tight_layout()\n    plt.show","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:00.351528Z","iopub.execute_input":"2025-05-16T19:25:00.351749Z","iopub.status.idle":"2025-05-16T19:25:10.299512Z","shell.execute_reply.started":"2025-05-16T19:25:00.351732Z","shell.execute_reply":"2025-05-16T19:25:10.298655Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"correlation_matrix = df_spectra.drop('id', axis=1).corr()\n\ncorr_unstacked = correlation_matrix.where(np.triu(np.ones(correlation_matrix.shape), k=1).astype(bool))\ncorr_pairs = corr_unstacked.unstack().dropna()\ntop_corr = corr_pairs.abs().sort_values(ascending=False).head(10)\n\nprint(\"Top 10 most correlated band pairs (by absolute correlation):\")\nfor (band1, band2), corr_val in top_corr.items():\n    print(f\"Bands {band1} & {band2}: correlation = {corr_val:.3f}\")\n\nplt.figure(figsize=(12, 10))\nsns.heatmap(correlation_matrix, cmap='coolwarm', center=0, square=True)\nplt.title('Spectral Band Correlation Heatmap')\nplt.xlabel('Band')\nplt.ylabel('Band')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:10.300398Z","iopub.execute_input":"2025-05-16T19:25:10.300646Z","iopub.status.idle":"2025-05-16T19:25:11.123630Z","shell.execute_reply.started":"2025-05-16T19:25:10.300621Z","shell.execute_reply":"2025-05-16T19:25:11.122819Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mean_spectra_by_class = df_spectra.groupby('id').mean()\nlinked = linkage(mean_spectra_by_class, method='ward')\n\nplt.figure(figsize=(10, 6))\ndendrogram(linked, labels=mean_spectra_by_class.index.tolist(), leaf_rotation=90)\nplt.title('Dendrogram of Class Mean Spectra')\nplt.xlabel('Class')\nplt.ylabel('Distance')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:11.124591Z","iopub.execute_input":"2025-05-16T19:25:11.124954Z","iopub.status.idle":"2025-05-16T19:25:12.132965Z","shell.execute_reply.started":"2025-05-16T19:25:11.124934Z","shell.execute_reply":"2025-05-16T19:25:12.132152Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"R_band, G_band, B_band = 90, 60, 30\n\ndef create_rgb_image_for_class(class_label):\n    sample_path = os.path.join(DATA_DIR, df[df['label'] == class_label]['id'].iloc[0])\n    cube = np.load(sample_path)\n\n    rgb_image = np.stack([\n        cube[:, :, R_band],\n        cube[:, :, G_band],\n        cube[:, :, B_band]\n    ], axis=-1)\n\n    \n    rgb_image = (rgb_image - rgb_image.min()) / (rgb_image.max() - rgb_image.min())\n    return rgb_image\n\n\nclass_labels = df['label'].unique()[:4]  \nfig, axes = plt.subplots(2, 2, figsize=(10, 10))\n\nfor ax, class_label in zip(axes.flatten(), class_labels):\n    rgb_image = create_rgb_image_for_class(class_label)\n    ax.imshow(rgb_image)\n    ax.set_title(f'Class: {class_label}')\n    ax.axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:12.133697Z","iopub.execute_input":"2025-05-16T19:25:12.133896Z","iopub.status.idle":"2025-05-16T19:25:12.509563Z","shell.execute_reply.started":"2025-05-16T19:25:12.133878Z","shell.execute_reply":"2025-05-16T19:25:12.508696Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"anova_results = {}\nfor band in range(X.shape[1]): \n    groups = [X[y == label, band] for label in np.unique(y)]  \n    f_stat, p_value = f_oneway(*groups)\n    anova_results[band] = p_value\n\n\nsignificant_bands_anova = {band: p for band, p in anova_results.items() if p < 0.05}\nprint(\"ANOVA significant bands:\", significant_bands_anova)\n\nkruskal_results = {}\nfor band in range(X.shape[1]):\n    groups = [X[y == label, band] for label in np.unique(y)] \n    h_stat, p_value = kruskal(*groups)\n    kruskal_results[band] = p_value\n\nsignificant_bands_kruskal = {band: p for band, p in kruskal_results.items() if p < 0.05}\nprint(\"Kruskal-Wallis significant bands:\", significant_bands_kruskal)\n\nplt.figure(figsize=(8, 6))\nsns.countplot(x=y)\nplt.title(\"Class Distribution\")\nplt.xlabel(\"Class\")\nplt.ylabel(\"Frequency\")\nplt.show()\n\nfor band in range(X.shape[1]):\n    _, p_value = shapiro(X[:, band])\n    print(f\"Shapiro-Wilk test for Band {band}: p-value = {p_value}\")\n\npca = PCA(n_components=2)\nX_pca = pca.fit_transform(X)\n\nplt.figure(figsize=(10, 8))\nsns.scatterplot(x=X_pca[:, 0], y=X_pca[:, 1], hue=y, palette='tab10')\nplt.title('PCA Projection')\nplt.xlabel('PCA 1')\nplt.ylabel('PCA 2')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:12.510403Z","iopub.execute_input":"2025-05-16T19:25:12.510648Z","iopub.status.idle":"2025-05-16T19:25:17.249527Z","shell.execute_reply.started":"2025-05-16T19:25:12.510630Z","shell.execute_reply":"2025-05-16T19:25:17.248655Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class1_data = X[y == df['label'].unique()[0]]  \nclass2_data = X[y == df['label'].unique()[1]] \n\n\nt_stat, p_value_t = ttest_ind(class1_data, class2_data, axis=0)\n\nu_stat, p_value_u = mannwhitneyu(class1_data.flatten(), class2_data.flatten())\n\nprint(\"t-test p-values:\", p_value_t)\nprint(\"Mann-Whitney U test p-value:\", p_value_u)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:17.250181Z","iopub.execute_input":"2025-05-16T19:25:17.250430Z","iopub.status.idle":"2025-05-16T19:25:17.262783Z","shell.execute_reply.started":"2025-05-16T19:25:17.250413Z","shell.execute_reply":"2025-05-16T19:25:17.261997Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"levene_results = {}\nfor band in range(X.shape[1]):\n    groups = [X[y == label, band] for label in np.unique(y)]\n    stat, p_value = levene(*groups)\n    levene_results[band] = p_value\n\nbartlett_results = {}\nfor band in range(X.shape[1]):\n    groups = [X[y == label, band] for label in np.unique(y)]\n    stat, p_value = bartlett(*groups)\n    bartlett_results[band] = p_value\n\nsignificant_bands_levene = {band: p for band, p in levene_results.items() if p < 0.05}\nsignificant_bands_bartlett = {band: p for band, p in bartlett_results.items() if p < 0.05}\n\nprint(\"Levene Test significant bands:\", significant_bands_levene)\nprint(\"Bartlett Test significant bands:\", significant_bands_bartlett)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:17.265563Z","iopub.execute_input":"2025-05-16T19:25:17.266072Z","iopub.status.idle":"2025-05-16T19:25:19.720912Z","shell.execute_reply.started":"2025-05-16T19:25:17.266048Z","shell.execute_reply":"2025-05-16T19:25:19.720260Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def calculate_ndvi(cube, red_band=30, nir_band=90):\n    red = cube[:, :, red_band]\n    nir = cube[:, :, nir_band]\n    return (nir - red) / (nir + red)\n\nsample_path = os.path.join(DATA_DIR, df[df['label'] == df['label'].unique()[0]]['id'].iloc[0])\ncube = np.load(sample_path)\nndvi_image = calculate_ndvi(cube)\n\nplt.imshow(ndvi_image, cmap='RdYlGn')\nplt.title(\"NDVI (NIR-Red)/(NIR+Red)\")\nplt.colorbar()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:19.721567Z","iopub.execute_input":"2025-05-16T19:25:19.721768Z","iopub.status.idle":"2025-05-16T19:25:19.996588Z","shell.execute_reply.started":"2025-05-16T19:25:19.721747Z","shell.execute_reply":"2025-05-16T19:25:19.995496Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.cluster import KMeans\n\nkmeans = KMeans(n_clusters=25, random_state=42)\nkmeans.fit(X)\n\nplt.scatter(X_embedded[:, 0], X_embedded[:, 1], c=kmeans.labels_, cmap='viridis')\nplt.title(\"KMeans Clustering\")\nplt.xlabel('UMAP 1')\nplt.ylabel('UMAP 2')\nplt.colorbar(label='Cluster')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:19.997479Z","iopub.execute_input":"2025-05-16T19:25:19.997735Z","iopub.status.idle":"2025-05-16T19:25:20.592066Z","shell.execute_reply.started":"2025-05-16T19:25:19.997717Z","shell.execute_reply":"2025-05-16T19:25:20.591301Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def calculate_snr(X, y, class_label):\n    class_data = X[y == class_label]\n    mean_signal = class_data.mean(axis=0)\n    noise = class_data.std(axis=0)\n    snr = mean_signal / noise\n    return snr\n\nsnr_values = {}\nfor label in np.unique(y):\n    snr_values[label] = calculate_snr(X, y, label)\n\nfor label, snr in snr_values.items():\n    print(f\"SNR for class {label}: {snr[:5]}\")  ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:20.592880Z","iopub.execute_input":"2025-05-16T19:25:20.593101Z","iopub.status.idle":"2025-05-16T19:25:20.618381Z","shell.execute_reply.started":"2025-05-16T19:25:20.593078Z","shell.execute_reply":"2025-05-16T19:25:20.617560Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nimport torchvision.transforms as T\nfrom torch.utils.data import Dataset, DataLoader\nimport kornia.augmentation as K\nimport numpy as np\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom tqdm import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:20.619215Z","iopub.execute_input":"2025-05-16T19:25:20.619562Z","iopub.status.idle":"2025-05-16T19:25:23.168036Z","shell.execute_reply.started":"2025-05-16T19:25:20.619543Z","shell.execute_reply":"2025-05-16T19:25:23.167267Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" train_df = pd.read_csv('/kaggle/input/beyond-visible-spectrum-ai-for-agriculture-2025/train.csv')\nbase_path = '/kaggle/input/beyond-visible-spectrum-ai-for-agriculture-2025/ot/ot'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:23.168949Z","iopub.execute_input":"2025-05-16T19:25:23.169198Z","iopub.status.idle":"2025-05-16T19:25:23.177683Z","shell.execute_reply.started":"2025-05-16T19:25:23.169181Z","shell.execute_reply":"2025-05-16T19:25:23.176857Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BANDS = 100\nBATCH_SIZE = 32\nEPOCHS = 50\nLEARNING_RATE = 0.001\nNUM_BANDS = 100\nDEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\nclass HyperspectralDataset(Dataset):\n    def __init__(self, df, base_path, patch_size=64, augment=False, num_bands=100):\n        self.df = df\n        self.base_path = base_path\n        self.patch_size = patch_size\n        self.augment = augment\n        self.num_bands = num_bands\n        \n        self.transform = nn.Sequential(\n            K.RandomHorizontalFlip(p=0.3),     \n            K.RandomVerticalFlip(p=0.3),\n            K.RandomAffine(degrees=5, translate=(0.05, 0.05), scale=(0.95, 1.05), p=0.5),\n            K.RandomCrop((patch_size, patch_size), padding=4, p=0.5)\n        )\n        \n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        img_path = f\"{self.base_path}/{row['id']}\"\n\n        try:\n            img = np.load(img_path)\n\n            if len(img.shape) == 2:\n                img = np.repeat(img[:, :, np.newaxis], self.num_bands, axis=2)\n            elif len(img.shape) == 3:\n                if img.shape[2] > self.num_bands:\n                    img = img[:, :, :self.num_bands]\n                elif img.shape[2] < self.num_bands:\n                    pad_width = ((0, 0), (0, 0), (0, self.num_bands - img.shape[2]))\n                    img = np.pad(img, pad_width, mode='constant')\n\n            img = img.astype(np.float32) / 65535.0  # Normalize image\n\n            img = torch.tensor(img, dtype=torch.float32).permute(2, 0, 1)  # Convert to [C, H, W]\n\n            if self.augment:\n                img = self.transform(img.unsqueeze(0)).squeeze(0)\n\n            if img.shape[1] != self.patch_size or img.shape[2] != self.patch_size:\n                img = F.interpolate(img.unsqueeze(0), size=(self.patch_size, self.patch_size), mode='bilinear').squeeze(0)\n\n            label = torch.tensor(row['label'], dtype=torch.long)  \n\n            if label > 0:\n                label = label - 1\n\n            return img, label\n\n        except Exception as e:\n            print(f\"Error loading {img_path}: {str(e)}\")\n            dummy_img = torch.zeros(self.num_bands, self.patch_size, self.patch_size)\n            dummy_label = torch.tensor(0, dtype=torch.long)  \n            return dummy_img, dummy_label\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:23.178660Z","iopub.execute_input":"2025-05-16T19:25:23.178958Z","iopub.status.idle":"2025-05-16T19:25:23.197278Z","shell.execute_reply.started":"2025-05-16T19:25:23.178933Z","shell.execute_reply":"2025-05-16T19:25:23.196582Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ChannelAttention(nn.Module):\n    def __init__(self, in_channels, reduction_ratio=16):\n        super(ChannelAttention, self).__init__()\n        self.avg_pool = nn.AdaptiveAvgPool2d(1)\n        self.max_pool = nn.AdaptiveMaxPool2d(1)\n        \n        self.fc = nn.Sequential(\n            nn.Linear(in_channels, in_channels // reduction_ratio),\n            nn.ReLU(inplace=True),\n            nn.Linear(in_channels // reduction_ratio, in_channels),\n            nn.Sigmoid()\n        )\n\n    def forward(self, x):\n        b, c, _, _ = x.size()\n        avg_out = self.fc(self.avg_pool(x).view(b, c))\n        max_out = self.fc(self.max_pool(x).view(b, c))\n        out = avg_out + max_out\n        return out.view(b, c, 1, 1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:23.198207Z","iopub.execute_input":"2025-05-16T19:25:23.198552Z","iopub.status.idle":"2025-05-16T19:25:23.217913Z","shell.execute_reply.started":"2025-05-16T19:25:23.198527Z","shell.execute_reply":"2025-05-16T19:25:23.217272Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SpatialAttention(nn.Module):\n    def __init__(self, kernel_size=7):\n        super(SpatialAttention, self).__init__()\n        self.conv = nn.Sequential(\n            nn.Conv2d(2, 8, kernel_size, padding=kernel_size//2),\n            nn.ReLU(),\n            nn.Conv2d(8, 1, kernel_size=1)\n        )\n        self.sigmoid = nn.Sigmoid()\n    \n    def forward(self, x):\n        avg_out = torch.mean(x, dim=1, keepdim=True)\n        max_out, _ = torch.max(x, dim=1, keepdim=True)\n        concat = torch.cat([avg_out, max_out], dim=1)\n        attention = self.sigmoid(self.conv(concat))\n        return x * attention","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:23.218906Z","iopub.execute_input":"2025-05-16T19:25:23.219157Z","iopub.status.idle":"2025-05-16T19:25:23.235842Z","shell.execute_reply.started":"2025-05-16T19:25:23.219125Z","shell.execute_reply":"2025-05-16T19:25:23.235105Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class HyperspectralCNN(nn.Module):\n    def __init__(self, in_channels=NUM_BANDS, num_classes=100):\n        super().__init__()\n        \n        self.conv1 = nn.Sequential(\n            nn.Conv2d(in_channels, 64, kernel_size=3, padding=1),\n            nn.BatchNorm2d(64),\n            nn.LeakyReLU(0.1, inplace=True),\n            nn.MaxPool2d(2)\n        )\n        \n        self.ca1 = ChannelAttention(64)\n        self.sa1 = SpatialAttention()\n        \n        self.conv2 = nn.Sequential(\n            nn.Conv2d(64, 128, kernel_size=3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.LeakyReLU(0.1, inplace=True),\n            nn.MaxPool2d(2)\n        )\n        \n        self.ca2 = ChannelAttention(128)\n        self.sa2 = SpatialAttention()\n        \n        self.conv3 = nn.Sequential(\n            nn.Conv2d(128, 256, kernel_size=3, padding=1),\n            nn.BatchNorm2d(256),\n            nn.LeakyReLU(0.1, inplace=True),\n            nn.AdaptiveAvgPool2d(1)\n        )\n        \n        self.classifier = nn.Sequential(\n            nn.Linear(256, 128),\n            nn.SiLU(),\n            nn.Dropout(0.5),\n            nn.Linear(128, 64),\n            nn.SiLU(),\n            nn.Linear(64, num_classes) \n        )\n        \n    def forward(self, x):\n        x = self.conv1(x)\n        x = self.ca1(x) * x\n        x = self.sa1(x) * x\n        \n        x = self.conv2(x)\n        x = self.ca2(x) * x\n        x = self.sa2(x) * x\n        \n        x = self.conv3(x)\n        x = x.view(x.size(0), -1)\n        return self.classifier(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:23.236768Z","iopub.execute_input":"2025-05-16T19:25:23.236980Z","iopub.status.idle":"2025-05-16T19:25:23.255772Z","shell.execute_reply.started":"2025-05-16T19:25:23.236966Z","shell.execute_reply":"2025-05-16T19:25:23.255032Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample = np.load('/kaggle/input/beyond-visible-spectrum-ai-for-agriculture-2025/ot/ot/sample1024.npy')  # (128, 128, 125)\nplt.imshow(sample[:, :, 0])\nplt.title('First channel')\nplt.colorbar()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:23.257127Z","iopub.execute_input":"2025-05-16T19:25:23.257336Z","iopub.status.idle":"2025-05-16T19:25:23.532801Z","shell.execute_reply.started":"2025-05-16T19:25:23.257321Z","shell.execute_reply":"2025-05-16T19:25:23.531974Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def evaluate_model(model, loader, criterion, device = DEVICE):\n    model.eval()\n    total_loss = 0.0\n    all_preds = []\n    all_labels = []\n    \n    with torch.no_grad():\n        for inputs, labels in loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            outputs = model(inputs)\n            \n            probabilities = torch.softmax(outputs, dim=1)\n            preds = torch.argmax(probabilities, dim=1)\n            \n            loss = criterion(outputs.squeeze(), labels)\n            total_loss += loss.item() * inputs.size(0)\n            \n            all_preds.extend(preds.cpu().numpy())\n            all_labels.extend(labels.cpu().numpy())\n    \n    return total_loss / len(loader.dataset), np.array(all_preds), np.array(all_labels)\n\n\n\n\ndef train_model(model, train_loader, val_loader, epochs, criterion, optimizer):\n    best_loss = float('inf')\n    train_losses = []\n    val_losses = []\n    \n    for epoch in range(epochs):\n        model.train()\n        train_loss = 0.0\n        valid_samples = 0\n        \n        for inputs, labels in tqdm(train_loader, desc=f\"Epoch {epoch+1}/{epochs}\"):\n            inputs, labels = inputs.to(DEVICE), labels.to(DEVICE)\n            \n            if torch.isnan(inputs).any() or torch.isnan(labels).any():\n                continue\n                \n            optimizer.zero_grad()\n            outputs = model(inputs)\n            \n            if torch.isnan(outputs).any():\n                continue\n                \n            loss = criterion(outputs.squeeze(), labels) \n            \n            if not torch.isnan(loss):\n                loss.backward()\n                optimizer.step()\n                train_loss += loss.item() * inputs.size(0)\n                valid_samples += inputs.size(0)\n        \n        if valid_samples > 0:\n            train_loss /= valid_samples\n            val_loss, val_preds, val_labels = evaluate_model(model, val_loader, criterion)\n            train_losses.append(train_loss)\n            val_losses.append(val_loss)\n            \n            if len(val_preds.shape) == 2: \n                val_preds = np.argmax(val_preds, axis=1)\n            \n            print(f\"Epoch {epoch+1}: Train Loss: {train_loss:.4f}, Val Loss: {val_loss:.4f}\")\n            print(f\"Sample predictions: {val_preds[:5]}, True labels: {val_labels[:5]}\")\n            \n            \n            if val_loss < best_loss:\n                best_loss = val_loss\n                torch.save(model.state_dict(), 'Spectrum_CNN.pth')\n        else:\n            print(f\"Epoch {epoch+1}: No valid training samples\")\n    \n    plt.figure(figsize=(8, 5))\n    plt.plot(train_losses, label='Train Loss', marker='o')\n    plt.plot(val_losses, label='Validation Loss', marker='o')\n    plt.xlabel('Epoch')\n    plt.ylabel('Loss')\n    plt.title('Training and Validation Loss')\n    plt.legend()\n    plt.grid(True)\n    plt.tight_layout()\n    plt.show()\n    \n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:23.533735Z","iopub.execute_input":"2025-05-16T19:25:23.533995Z","iopub.status.idle":"2025-05-16T19:25:23.546750Z","shell.execute_reply.started":"2025-05-16T19:25:23.533963Z","shell.execute_reply":"2025-05-16T19:25:23.546173Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df, val_df = train_test_split(train_df, test_size=0.2, random_state=42)\n    \ntrain_dataset = HyperspectralDataset(train_df, base_path, augment=True)\nval_dataset = HyperspectralDataset(val_df, base_path, augment=False)\n    \ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=4)\nval_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=4)\n    \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:23.547533Z","iopub.execute_input":"2025-05-16T19:25:23.547783Z","iopub.status.idle":"2025-05-16T19:25:23.581015Z","shell.execute_reply.started":"2025-05-16T19:25:23.547759Z","shell.execute_reply":"2025-05-16T19:25:23.580447Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = HyperspectralCNN().to(DEVICE)\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE, weight_decay=1e-5)\n\n\nmodel = train_model(model, train_loader, val_loader, EPOCHS, criterion, optimizer)\n    \nmodel.load_state_dict(torch.load('Spectrum_CNN.pth'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:25:23.581744Z","iopub.execute_input":"2025-05-16T19:25:23.582009Z","iopub.status.idle":"2025-05-16T19:43:50.517471Z","shell.execute_reply.started":"2025-05-16T19:25:23.581986Z","shell.execute_reply":"2025-05-16T19:43:50.516665Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = HyperspectralCNN(in_channels=100).to(DEVICE)\nmodel.load_state_dict(torch.load('Spectrum_CNN.pth'))\nmodel.eval()\nprint(\"Model weights:\", list(model.parameters())[0][0, 0, :5])\ntest_input = torch.randn(1, 100, 64, 64).to(DEVICE)\n\nclass TestHyperspectralDataset(Dataset):\n    def __init__(self, test_csv, base_path, patch_size=64, num_bands=100):\n        self.df = pd.read_csv(test_csv)\n        self.base_path = base_path\n        self.patch_size = patch_size\n        self.num_bands = num_bands\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        img_path = os.path.join(self.base_path, row['id'])\n        \n        try:\n            img = np.load(img_path)\n            \n            if len(img.shape) == 2:\n                img = np.repeat(img[:, :, np.newaxis], self.num_bands, axis=2)\n            elif len(img.shape) == 3:\n                if img.shape[2] > self.num_bands:\n                    img = img[:, :, :self.num_bands] \n                elif img.shape[2] < self.num_bands:\n                    pad_width = ((0, 0), (0, 0), (0, self.num_bands - img.shape[2]))\n                    img = np.pad(img, pad_width, mode='constant')\n            \n            normalized_img = np.zeros_like(img)\n            for band in range(img.shape[2]):\n                band_data = img[:, :, band]\n                if np.max(band_data) > 0:  \n                    normalized_img[:, :, band] = (band_data - np.min(band_data)) / (np.max(band_data) - np.min(band_data))\n            \n            img_tensor = torch.tensor(normalized_img, dtype=torch.float32).permute(2, 0, 1)\n            \n            if img_tensor.shape[1] != self.patch_size or img_tensor.shape[2] != self.patch_size:\n                img_tensor = F.interpolate(img_tensor.unsqueeze(0), \n                                         size=(self.patch_size, self.patch_size),\n                                         mode='bilinear').squeeze(0)\n            \n            return img_tensor, row['id']\n        \n        except Exception as e:\n            print(f\"Error loading {img_path}: {str(e)}\")\n            dummy_img = torch.zeros(self.num_bands, self.patch_size, self.patch_size)\n            return dummy_img, row['id']\n\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:43:50.521104Z","iopub.execute_input":"2025-05-16T19:43:50.521386Z","iopub.status.idle":"2025-05-16T19:43:50.889593Z","shell.execute_reply.started":"2025-05-16T19:43:50.521354Z","shell.execute_reply":"2025-05-16T19:43:50.888802Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_csv_path = '/kaggle/input/beyond-visible-spectrum-ai-for-agriculture-2025/test.csv'\nbase_path = '/kaggle/input/beyond-visible-spectrum-ai-for-agriculture-2025/ot/ot'\n\ntest_dataset = TestHyperspectralDataset(test_csv_path, base_path, num_bands=100)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=4)\n\npredictions = []\nids = []\n\nwith torch.no_grad():\n    for inputs, img_ids in test_loader:\n        inputs = inputs.to(DEVICE)\n        \n        if torch.isnan(inputs).any():\n            print(f\"Skipping batch with NaN values\")\n            predictions.extend([50] * len(img_ids))  \n            ids.extend(img_ids)\n            continue\n            \n        outputs = model(inputs)\n        preds = outputs.squeeze().cpu().numpy()\n        print(preds)\n        preds = np.clip(preds, 1, 100).round().astype(int)\n        print(preds)\n        if isinstance(preds, np.ndarray) and preds.ndim > 1:\n            preds = np.max(preds, axis=1)  \n\n        if len(preds) != len(img_ids):\n            preds = preds[:len(img_ids)]  \n\n        predictions.extend(preds.tolist())  \n        ids.extend(img_ids)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:43:50.890458Z","iopub.execute_input":"2025-05-16T19:43:50.890729Z","iopub.status.idle":"2025-05-16T19:44:08.262937Z","shell.execute_reply.started":"2025-05-16T19:43:50.890706Z","shell.execute_reply":"2025-05-16T19:44:08.262077Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission_df = pd.DataFrame({'ID': ids, 'TARGET': predictions})\nsubmission_df.to_csv('submission.csv', index=False)\nprint(\"Submission created successfully\")\nprint(\"\\nSubmission preview:\")\nprint(submission_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:44:08.263960Z","iopub.execute_input":"2025-05-16T19:44:08.264180Z","iopub.status.idle":"2025-05-16T19:44:08.285859Z","shell.execute_reply.started":"2025-05-16T19:44:08.264157Z","shell.execute_reply":"2025-05-16T19:44:08.285296Z"}},"outputs":[],"execution_count":null}]}