{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":10384,"databundleVersionId":120379,"sourceType":"competition"}],"dockerImageVersionId":12836,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Loading Libraries","metadata":{"_uuid":"609006646970a83c89ff8a332459ddceb2e02e4c"}},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom sklearn.metrics import log_loss\nfrom sklearn.model_selection import StratifiedKFold\nimport gc\nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns \nimport lightgbm as lgb\nfrom catboost import Pool, CatBoostClassifier\nimport itertools\nimport pickle, gzip\nimport glob\nfrom sklearn.preprocessing import StandardScaler\n\n# C1","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-25T18:20:50.988926Z","iopub.execute_input":"2025-05-25T18:20:50.989115Z","iopub.status.idle":"2025-05-25T18:20:51.907546Z","shell.execute_reply.started":"2025-05-25T18:20:50.989077Z","shell.execute_reply":"2025-05-25T18:20:51.906650Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Extracting Features from train set","metadata":{"_uuid":"7dbccfa992f29644a47a31341b2c68c6b42b835d"}},{"cell_type":"code","source":"import pandas as pd\ndf = pd.read_csv('/kaggle/input/training_set.csv')\nprint(df.head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T18:20:56.652103Z","iopub.execute_input":"2025-05-25T18:20:56.652362Z","iopub.status.idle":"2025-05-25T18:20:58.119164Z","shell.execute_reply.started":"2025-05-25T18:20:56.652320Z","shell.execute_reply":"2025-05-25T18:20:58.118214Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Load & Merge Training Data for Sequences\n\n# 🧩Group and Pad Sequences","metadata":{}},{"cell_type":"code","source":"## import torch\nfrom sklearn.preprocessing import LabelEncoder\n\n# Load data\ntrain = pd.read_csv('/kaggle/input/training_set.csv')\nmeta = pd.read_csv('/kaggle/input/training_set_metadata.csv')\n\n# Encode target labels\nlabels = meta[['object_id', 'target']]\nlabel_encoder = LabelEncoder()\nlabels['target'] = label_encoder.fit_transform(labels['target'])\n\n# Merge flux data with labels\ndata = train.merge(labels, on='object_id')\n\n#  --  --\nfeatures = ['flux', 'flux_err', 'passband']\nsequence_data = {}\nmax_len = 0\n\n# Group by object_id and get time-sorted sequences\nfor obj_id, group in data.groupby('object_id'):\n    seq = group.sort_values('mjd')[features].values\n    if len(seq) > max_len:\n        max_len = len(seq)\n    sequence_data[obj_id] = seq\n\n# Pad sequences to the same length\ndef pad_sequence(seq, max_len):\n    padded = np.zeros((max_len, len(features)))\n    padded[:len(seq)] = seq\n    return padded\n\nX = []\ny = []\n\nfor obj_id in sequence_data:\n    padded = pad_sequence(sequence_data[obj_id], max_len)\n    X.append(padded)\n    y.append(labels[labels['object_id'] == obj_id]['target'].values[0])\n\nX = np.array(X)\ny = np.array(y)\n\nprint(f\"Shape of X: {X.shape} | Shape of y: {y.shape}\")\n\n\n#C2","metadata":{"trusted":true,"_uuid":"631c418da4275fba3070f2a6cff3873d11591f95","execution":{"iopub.status.busy":"2025-05-25T18:21:00.314309Z","iopub.execute_input":"2025-05-25T18:21:00.314608Z","iopub.status.idle":"2025-05-25T18:21:13.099790Z","shell.execute_reply.started":"2025-05-25T18:21:00.314554Z","shell.execute_reply":"2025-05-25T18:21:13.099090Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **HA-TCN Model Code**","metadata":{"_uuid":"7ed21e25fb5678c78bb19a8297bf83db00ccae01"}},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.nn.functional as F\n\nclass TemporalBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, kernel_size, dilation):\n        super(TemporalBlock, self).__init__()\n        self.conv1 = nn.Conv1d(in_channels, out_channels, kernel_size, \n                               padding=(kernel_size - 1) * dilation, dilation=dilation)\n        self.relu = nn.ReLU()\n        self.dropout = nn.Dropout(0.5)\n        self.norm = nn.BatchNorm1d(out_channels)\n\n    def forward(self, x):\n        out = self.conv1(x)\n        out = self.relu(out)\n        out = self.dropout(out)\n        out = self.norm(out)\n        return out\n\nclass HA_TCN(nn.Module):\n    def __init__(self, input_size, num_classes, num_channels=[32, 64, 128], kernel_size=3):\n        super(HA_TCN, self).__init__()\n        layers = []\n        dilation = 1\n        for i in range(len(num_channels)):\n            in_ch = input_size if i == 0 else num_channels[i-1]\n            layers.append(TemporalBlock(in_ch, num_channels[i], kernel_size, dilation))\n            dilation *= 2\n        self.network = nn.Sequential(*layers)\n\n        # Attention: Temporal attention (HA-TCN)\n        self.attn = nn.Linear(num_channels[-1], 1)\n        self.classifier = nn.Linear(num_channels[-1], num_classes)\n\n    def forward(self, x):\n        x = x.permute(0, 2, 1)  # (B, C, T)\n        features = self.network(x).permute(0, 2, 1)  # (B, T, C)\n        attn_weights = F.softmax(self.attn(features), dim=1)  # (B, T, 1)\n        attended = torch.sum(features * attn_weights, dim=1)  # (B, C)\n        return self.classifier(attended)\n","metadata":{"trusted":true,"_uuid":"696ee870837c23375bc7f0388de1b07510351123","execution":{"iopub.status.busy":"2025-05-25T18:21:17.410183Z","iopub.execute_input":"2025-05-25T18:21:17.410447Z","iopub.status.idle":"2025-05-25T18:21:17.420999Z","shell.execute_reply.started":"2025-05-25T18:21:17.410407Z","shell.execute_reply":"2025-05-25T18:21:17.420109Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Prepare DataLoader and Split**","metadata":{}},{"cell_type":"code","source":"import torch\nfrom sklearn.model_selection import train_test_split\nfrom torch.utils.data import TensorDataset, DataLoader\n\nX_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.15, stratify=y, random_state=42)\n\ntrain_dataset = TensorDataset(torch.tensor(X_train).float(), torch.tensor(y_train))\nval_dataset = TensorDataset(torch.tensor(X_val).float(), torch.tensor(y_val))\n\ntrain_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=64)\n","metadata":{"trusted":true,"_uuid":"2b6f79b71d0e9b62266a52d9e7ac209c56e14aff","execution":{"iopub.status.busy":"2025-05-25T18:21:21.806599Z","iopub.execute_input":"2025-05-25T18:21:21.806907Z","iopub.status.idle":"2025-05-25T18:21:21.939017Z","shell.execute_reply.started":"2025-05-25T18:21:21.806857Z","shell.execute_reply":"2025-05-25T18:21:21.938446Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# > **Training Loop**","metadata":{"_uuid":"7aaadd7fb68f26be1aa78e0721332689365f2322"}},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = HA_TCN(input_size=3, num_classes=len(label_encoder.classes_)).to(device)\ncriterion = nn.CrossEntropyLoss()\nweight_decay = 1e-2  # Adjust this value as needed\noptimizer = torch.optim.Adam(model.parameters(), lr=0.0007, weight_decay=weight_decay)\n\n# Training\nfor epoch in range(500):  # keep this small for now\n    model.train()\n    train_loss = 0\n    for xb, yb in train_loader:\n        xb, yb = xb.to(device), yb.to(device)\n        optimizer.zero_grad()\n        preds = model(xb)\n        loss = criterion(preds, yb)\n        loss.backward()\n        optimizer.step()\n        train_loss += loss.item()\n    if(epoch +1)%20==0:\n        print(f\"Epoch {epoch+1} | Train Loss: {train_loss/len(train_loader):.4f}\")\n","metadata":{"trusted":true,"_uuid":"c1aaa4b97bec65047182097d08d33541aaf9a057","execution":{"iopub.status.busy":"2025-05-25T18:21:37.818734Z","iopub.execute_input":"2025-05-25T18:21:37.819009Z","iopub.status.idle":"2025-05-25T18:32:27.891683Z","shell.execute_reply.started":"2025-05-25T18:21:37.818969Z","shell.execute_reply":"2025-05-25T18:32:27.890884Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Basic Evaluation","metadata":{"_uuid":"92b0ae5a7f0b581b1f4e971a5c62eb97d2397455"}},{"cell_type":"code","source":"# Evaluate\nmodel.eval()\ncorrect = 0\ntotal = 0\n\nwith torch.no_grad():\n    for xb, yb in val_loader:\n        xb, yb = xb.to(device), yb.to(device)\n        preds = model(xb)\n        _, predicted = torch.max(preds, 1)\n        correct += (predicted == yb).sum().item()\n        total += yb.size(0)\n\nprint(f\"Validation Accuracy: {(correct / total) * 100:.2f}%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T18:34:08.293318Z","iopub.execute_input":"2025-05-25T18:34:08.293604Z","iopub.status.idle":"2025-05-25T18:34:08.358658Z","shell.execute_reply.started":"2025-05-25T18:34:08.293562Z","shell.execute_reply":"2025-05-25T18:34:08.357801Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Log-Loss Evaluation","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import log_loss\n\nmodel.eval()\ny_true = []\ny_probs = []\n\nwith torch.no_grad():\n    for xb, yb in val_loader:\n        xb = xb.to(device)\n        logits = model(xb)\n        probs = F.softmax(logits, dim=1).cpu().numpy()\n        y_probs.extend(probs)\n        y_true.extend(yb.numpy())\n\nlogloss = log_loss(y_true, y_probs)\nprint(f\"Validation Log Loss: {logloss:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T18:34:16.688587Z","iopub.execute_input":"2025-05-25T18:34:16.688908Z","iopub.status.idle":"2025-05-25T18:34:16.756050Z","shell.execute_reply.started":"2025-05-25T18:34:16.688848Z","shell.execute_reply":"2025-05-25T18:34:16.755114Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Loading Trained Model","metadata":{}},{"cell_type":"code","source":"torch.save(model.state_dict(), \"ha_tcn_phase1.pth\")\n","metadata":{"trusted":true,"_uuid":"59889ae9a9041a1c9efa8c42c59b75aa58249bf1","execution":{"iopub.status.busy":"2025-05-25T18:34:21.692874Z","iopub.execute_input":"2025-05-25T18:34:21.693165Z","iopub.status.idle":"2025-05-25T18:34:21.792477Z","shell.execute_reply.started":"2025-05-25T18:34:21.693112Z","shell.execute_reply":"2025-05-25T18:34:21.791629Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Phase 2\n\n# ","metadata":{}},{"cell_type":"code","source":"# # Reload libraries and model class\n# import torch\n# import torch.nn.functional as F\n\n# # Load the same HA-TCN model definition\n# # (Paste your model class again here)\n\n# # Instantiate model\n# device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n# model = HA_TCN(input_size=3, num_classes=14).to(device)\n# model.load_state_dict(torch.load(\"/kaggle/input/your-model-path/ha_tcn_phase1.pth\"))\n# model.eval()\n","metadata":{"trusted":true,"_uuid":"4c35b11a75cdc6aa926109ae876a1f2bb9f4078c"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Read Test Data in Chunks","metadata":{"_uuid":"6601f669629d8e1bf9182054206ef316341e0e3e"}},{"cell_type":"code","source":"# import pandas as pd\n\n# chunk_size = 500000  # Load in 500k row chunks\n# test_reader = pd.read_csv(\"/kaggle/input/PLAsTiCC-2018/test_set.csv\", chunksize=chunk_size)\n","metadata":{"trusted":true,"_uuid":"4a411f6097378ab0c3199064478f4ed4e064b6fb"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Create Sequences Object-Wise\n\n## Stream test_set.csv in Chunks","metadata":{"_uuid":"4b915ef7ac26164d0b83e265a277ea50e8557eac"}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport torch\nimport torch.nn.functional as F\n\nfrom collections import defaultdict\nfrom tqdm import tqdm  # nice progress bar\n\n# Required setup\ntest_path = \"/kaggle/input/test_set.csv\"\nchunk_size = 500_000\nmax_len = 352  # same as training\nfeatures = ['flux', 'flux_err', 'passband']\nobject_preds = {}\n\n# Padding function\ndef pad_sequence(seq, max_len):\n    padded = np.zeros((max_len, len(features)))\n    padded[:len(seq)] = seq\n    return padded\n\n# Reader loop\nreader = pd.read_csv(test_path, chunksize=chunk_size)\n\nfor i, chunk in enumerate(reader):\n    print(f\"\\n🔄 Processing chunk {i+1}\")\n    \n    sequences = []\n    obj_ids = []\n    \n    for obj_id, group in chunk.groupby('object_id'):\n        seq = group.sort_values('mjd')[features].values\n        padded = pad_sequence(seq, max_len)\n        sequences.append(padded)\n        obj_ids.append(obj_id)\n    \n    X_chunk = torch.tensor(sequences).float().to(device)\n    \n    with torch.no_grad():\n        preds = model(X_chunk)\n        probs = F.softmax(preds, dim=1).cpu().numpy()\n    \n    for obj_id, prob in zip(obj_ids, probs):\n        object_preds[obj_id] = prob\n","metadata":{"trusted":true,"_uuid":"fe95383168c5bd60e4349d6bce4999ffdff02471","execution":{"iopub.status.busy":"2025-05-25T18:36:06.984829Z","iopub.execute_input":"2025-05-25T18:36:06.985098Z","iopub.status.idle":"2025-05-25T20:02:51.725583Z","shell.execute_reply.started":"2025-05-25T18:36:06.985059Z","shell.execute_reply":"2025-05-25T20:02:51.724954Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Format for Kaggle Submission","metadata":{}},{"cell_type":"code","source":"# Load metadata to get actual target classes\nmeta = pd.read_csv(\"/kaggle/input/training_set_metadata.csv\")\nclasses = sorted(meta[\"target\"].unique())\ncolumns = ['class_' + str(c) for c in classes]\n\nsubmission = pd.DataFrame.from_dict(object_preds, orient='index', columns=columns)\nsubmission.index.name = \"object_id\"\nsubmission.reset_index(inplace=True)\n# Add a dummy class_99 column with very low probabilities\nsubmission['class_99'] = 1e-5\n\n# Normalize all class columns so they sum to 1\nclass_cols = [col for col in submission.columns if col.startswith(\"class_\")]\nsubmission[class_cols] = submission[class_cols].div(submission[class_cols].sum(axis=1), axis=0)\n\nsubmission.to_csv(\"V2Final.csv\", index=False)\n\n\n\n\nprint(\"✅ Fixed submission.csv saved with class_99 included.\")\n\n\n# # Convert dict to DataFrame\n# columns = ['class_' + str(c) for c in sorted(meta['target'].unique())]\n# submission = pd.DataFrame.from_dict(object_preds, orient='index', columns=columns)\n# submission.index.name = \"object_id\"\n# submission.reset_index(inplace=True)\n\n# submission.to_csv(\"V2Final.csv\", index=False)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-25T21:00:50.404495Z","iopub.execute_input":"2025-05-25T21:00:50.404769Z","iopub.status.idle":"2025-05-25T21:02:32.550242Z","shell.execute_reply.started":"2025-05-25T21:00:50.404717Z","shell.execute_reply":"2025-05-25T21:02:32.549160Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# def plot_loss_acc(history):\n#     plt.plot(history.history['loss'][1:])\n#     plt.plot(history.history['val_loss'][1:])\n#     plt.title('model loss')\n#     plt.ylabel('val_loss')\n#     plt.xlabel('epoch')\n#     plt.legend(['train','Validation'], loc='upper left')\n#     plt.show()\n    \n#     plt.plot(history.history['acc'][1:])\n#     plt.plot(history.history['val_acc'][1:])\n#     plt.title('model Accuracy')\n#     plt.ylabel('val_acc')\n#     plt.xlabel('epoch')\n#     plt.legend(['train','Validation'], loc='upper left')\n#     plt.show()","metadata":{"trusted":true,"_uuid":"449a0c6c0f3baa75ef4719ef8e76ac5fa62d094b"},"outputs":[],"execution_count":null}]}