{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"datasetVersion","sourceId":4891788,"datasetId":2836602,"databundleVersionId":4959076}],"dockerImageVersionId":31329,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:29.235072Z","iopub.execute_input":"2026-03-29T07:36:29.235399Z","iopub.status.idle":"2026-03-29T07:36:30.570656Z","shell.execute_reply.started":"2026-03-29T07:36:29.235358Z","shell.execute_reply":"2026-03-29T07:36:30.569565Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"file_path = \"/kaggle/input/datasets/deepaksirohiwal/delhi-air-quality/delhi_aqi.csv\"\ndf = pd.read_csv(file_path)\n\nprint(df.shape)\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:31.658208Z","iopub.execute_input":"2026-03-29T07:36:31.658706Z","iopub.status.idle":"2026-03-29T07:36:31.748671Z","shell.execute_reply.started":"2026-03-29T07:36:31.658659Z","shell.execute_reply":"2026-03-29T07:36:31.747663Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(df.dtypes)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:33.938471Z","iopub.execute_input":"2026-03-29T07:36:33.938819Z","iopub.status.idle":"2026-03-29T07:36:33.946055Z","shell.execute_reply.started":"2026-03-29T07:36:33.938788Z","shell.execute_reply":"2026-03-29T07:36:33.944863Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:35.738564Z","iopub.execute_input":"2026-03-29T07:36:35.738889Z","iopub.status.idle":"2026-03-29T07:36:35.765258Z","shell.execute_reply.started":"2026-03-29T07:36:35.738859Z","shell.execute_reply":"2026-03-29T07:36:35.764237Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset\nimport torch.nn as nn\n\nfrom sklearn.preprocessing import StandardScaler","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:37.218037Z","iopub.execute_input":"2026-03-29T07:36:37.218385Z","iopub.status.idle":"2026-03-29T07:36:41.516968Z","shell.execute_reply.started":"2026-03-29T07:36:37.218355Z","shell.execute_reply":"2026-03-29T07:36:41.515612Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AQIDataset:\n    def __init__(self, df, feature_cols, target_col, input_window=72, horizon=24):\n        self.X = df[feature_cols].values\n        self.y = df[target_col].values\n\n        self.input_window = input_window\n        self.horizon = horizon\n\n        self.samples = self._create_samples()\n\n    def _create_samples(self):\n        samples = []\n        total_length = len(self.X)\n\n        for t in range(self.input_window, total_length - self.horizon):\n            x = self.X[t - self.input_window:t]\n            y = self.y[t + self.horizon]\n\n            samples.append((x, y))\n        return samples\n\n    def __len__(self):\n        return len(self.samples)\n\n    def __getitem__(self, idx):\n        x, y = self.samples[idx]\n\n        x = torch.tensor(x, dtype=torch.float32).reshape(-1)\n        y = torch.tensor(y, dtype=torch.float32)\n\n        return x, y","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:41.518802Z","iopub.execute_input":"2026-03-29T07:36:41.519499Z","iopub.status.idle":"2026-03-29T07:36:41.528206Z","shell.execute_reply.started":"2026-03-29T07:36:41.519464Z","shell.execute_reply":"2026-03-29T07:36:41.527153Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def split_dataframe(df):\n    n = len(df)\n\n    train_end = int(0.7 * n)\n    val_end = int(0.85 * n)\n\n    train_df = df.iloc[:train_end].copy()\n    val_df = df.iloc[train_end:val_end].copy()\n    test_df = df.iloc[val_end:].copy()\n\n    return train_df, val_df, test_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:48.396533Z","iopub.execute_input":"2026-03-29T07:36:48.396867Z","iopub.status.idle":"2026-03-29T07:36:48.403082Z","shell.execute_reply.started":"2026-03-29T07:36:48.396833Z","shell.execute_reply":"2026-03-29T07:36:48.401806Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\n\nclass RegMLPwithRELU(nn.Module):\n    def __init__(self, input_dim):\n        super().__init__()\n\n        self.net = nn.Sequential(\n            nn.Linear(input_dim, 256),\n            nn.ReLU(),\n\n            nn.Linear(256, 128),\n            nn.ReLU(),\n\n            nn.Linear(128, 1)\n        )\n\n    def forward(self, x):\n        return self.net(x).squeeze(-1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:49.038692Z","iopub.execute_input":"2026-03-29T07:36:49.039059Z","iopub.status.idle":"2026-03-29T07:36:49.046117Z","shell.execute_reply.started":"2026-03-29T07:36:49.039028Z","shell.execute_reply":"2026-03-29T07:36:49.045019Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_model(model, train_loader, val_loader, epochs=20, lr=1e-5, device=\"cpu\"):\n    model.to(device)\n\n    optimizer = torch.optim.Adam(model.parameters(), lr=lr)\n    criterion = nn.MSELoss()\n\n    for epoch in range(epochs):\n        model.train()\n        train_loss = 0\n        total_samples = 0\n\n        for x, y in train_loader:\n            x, y = x.to(device), y.to(device)\n\n            optimizer.zero_grad()\n            preds = model(x)\n            loss = criterion(preds, y)\n            loss.backward()\n            optimizer.step()\n\n            batch_size = x.size(0)\n\n            train_loss += loss.item() * batch_size\n            total_samples += batch_size\n\n        val_loss = evaluate(model, val_loader, device)\n        \n        print(f\"Epoch {epoch+1}: Train Loss={train_loss/total_samples:.4f}, Val Loss={val_loss:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:51.178693Z","iopub.execute_input":"2026-03-29T07:36:51.179104Z","iopub.status.idle":"2026-03-29T07:36:51.187345Z","shell.execute_reply.started":"2026-03-29T07:36:51.179070Z","shell.execute_reply":"2026-03-29T07:36:51.186261Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def evaluate(model, loader, device=\"cpu\"):\n    model.eval()\n    criterion = nn.MSELoss()\n\n    total_loss = 0\n    total_samples = 0\n\n    with torch.no_grad():\n        for x, y in loader:\n            x, y = x.to(device), y.to(device)\n\n            preds = model(x)\n            loss = criterion(preds, y)\n\n            batch_size = x.size(0)\n\n            total_loss += loss.item() * batch_size\n            total_samples += batch_size\n\n    return total_loss / total_samples","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:53.428719Z","iopub.execute_input":"2026-03-29T07:36:53.429831Z","iopub.status.idle":"2026-03-29T07:36:53.436816Z","shell.execute_reply.started":"2026-03-29T07:36:53.429779Z","shell.execute_reply":"2026-03-29T07:36:53.435653Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import DataLoader\n\nfeature_cols = ['co', 'no', 'no2', 'o3', 'so2', 'pm2_5', 'pm10', 'nh3']\ntarget_col = 'pm2_5'\n\ntrain_df, val_df, test_df = split_dataframe(df)\n\n# scaler = StandardScaler()\n# train_df[feature_cols] = scaler.fit_transform(train_df[feature_cols])\n# val_df[feature_cols] = scaler.transform(val_df[feature_cols])\n# test_df[feature_cols] = scaler.transform(test_df[feature_cols])\n\ntrain_dataset = AQIDataset(train_df, feature_cols, target_col)\nval_dataset = AQIDataset(val_df, feature_cols, target_col)\ntest_dataset = AQIDataset(test_df, feature_cols, target_col)\n\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=False)\nval_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)\ntest_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)\n\ninput_dim = 72 * len(feature_cols)\n\nmodel = RegMLPwithRELU(input_dim)\ndevice = 'cpu'\n\ntrain_model(model, train_loader, val_loader, device=device)\n\ntest_mse = evaluate(model, test_loader, device=device)\n\nprint(\"Final Test MSE:\", test_mse)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:36:55.338742Z","iopub.execute_input":"2026-03-29T07:36:55.339084Z","iopub.status.idle":"2026-03-29T07:37:27.472197Z","shell.execute_reply.started":"2026-03-29T07:36:55.339054Z","shell.execute_reply":"2026-03-29T07:37:27.471161Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class RegMLPwithSIG(nn.Module):\n    def __init__(self, input_dim):\n        super().__init__()\n\n        self.fc1 = nn.Linear(input_dim, 256)\n        self.fc2 = nn.Linear(256, 128)\n        self.fc3 = nn.Linear(128, 1)\n\n        self.act = nn.Sigmoid()\n\n    def forward(self, x):\n        x = self.act(self.fc1(x))\n        x = self.act(self.fc2(x))\n        x = self.fc3(x)\n        return x.squeeze(-1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:37:48.518606Z","iopub.execute_input":"2026-03-29T07:37:48.519117Z","iopub.status.idle":"2026-03-29T07:37:48.526261Z","shell.execute_reply.started":"2026-03-29T07:37:48.519081Z","shell.execute_reply":"2026-03-29T07:37:48.524742Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gradients = {\n    \"fc1\": [],\n    \"fc2\": [],\n    \"fc3\": []\n}\n\ndef get_hook(name):\n    def hook(grad):\n        gradients[name].append(grad.norm().item())\n    return hook\n\ntrain_df, _, _ = split_dataframe(df)\n\nscaler = StandardScaler()\ntrain_df[feature_cols] = scaler.fit_transform(train_df[feature_cols])\n\ntrain_dataset = AQIDataset(train_df, feature_cols, target_col)\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=False)\ninput_dim = 72 * len(feature_cols)\n\nmodel = RegMLPwithSIG(input_dim)\n\nmodel.fc1.weight.register_hook(get_hook(\"fc1\"))\nmodel.fc2.weight.register_hook(get_hook(\"fc2\"))\nmodel.fc3.weight.register_hook(get_hook(\"fc3\"))\n\nmodel.to(device)\n\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-5)\ncriterion = nn.MSELoss()\nmodel.train()\n\nfor epoch in range(1):\n    for x, y in train_loader:\n        optimizer.zero_grad()\n    \n        preds = model(x)\n        loss = criterion(preds, y)\n    \n        loss.backward()\n        optimizer.step()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:39:32.898266Z","iopub.execute_input":"2026-03-29T07:39:32.898656Z","iopub.status.idle":"2026-03-29T07:39:34.285005Z","shell.execute_reply.started":"2026-03-29T07:39:32.898622Z","shell.execute_reply":"2026-03-29T07:39:34.283755Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(10,5))\nplt.plot(gradients[\"fc1\"], label=\"Layer 1\")\nplt.plot(gradients[\"fc2\"], label=\"Layer 2\")\nplt.plot(gradients[\"fc3\"], label=\"Layer 3\")\n\nplt.xlabel(\"Batch Index\")\nplt.ylabel(\"Gradient Norm\")\nplt.title(\"Gradient Flow (Sigmoid MLP)\")\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:39:34.286685Z","iopub.execute_input":"2026-03-29T07:39:34.287002Z","iopub.status.idle":"2026-03-29T07:39:34.510037Z","shell.execute_reply.started":"2026-03-29T07:39:34.286967Z","shell.execute_reply":"2026-03-29T07:39:34.509149Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"fc1:\", np.mean(gradients[\"fc1\"]))\nprint(\"fc2:\", np.mean(gradients[\"fc2\"]))\nprint(\"fc3:\", np.mean(gradients[\"fc3\"]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-29T07:39:37.909171Z","iopub.execute_input":"2026-03-29T07:39:37.909867Z","iopub.status.idle":"2026-03-29T07:39:37.920151Z","shell.execute_reply.started":"2026-03-29T07:39:37.909809Z","shell.execute_reply":"2026-03-29T07:39:37.918639Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AQIClasDataset()","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}