{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":3004,"databundleVersionId":861823,"sourceType":"competition"}],"dockerImageVersionId":30732,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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)\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","execution":{"iopub.status.busy":"2024-07-01T08:08:05.040503Z","iopub.execute_input":"2024-07-01T08:08:05.040888Z","iopub.status.idle":"2024-07-01T08:08:06.141265Z","shell.execute_reply.started":"2024-07-01T08:08:05.040858Z","shell.execute_reply":"2024-07-01T08:08:06.140090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# torch interface\nimport torch \nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nfrom torchvision import transforms, utils\nimport pandas as pd\nimport numpy as np \nimport matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2024-07-01T09:53:57.507947Z","iopub.execute_input":"2024-07-01T09:53:57.508835Z","iopub.status.idle":"2024-07-01T09:53:57.514044Z","shell.execute_reply.started":"2024-07-01T09:53:57.508798Z","shell.execute_reply":"2024-07-01T09:53:57.512971Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class cfg:\n    train_csv_path='/kaggle/input/digit-recognizer/train.csv'\n    test_csv_path= '/kaggle/input/digit-recognizer/test.csv'\n    submit_csv_path= '/kaggle/input/digit-recognizer/sample_submission.csv'","metadata":{"execution":{"iopub.status.busy":"2024-07-01T09:53:57.977236Z","iopub.execute_input":"2024-07-01T09:53:57.977601Z","iopub.status.idle":"2024-07-01T09:53:57.982712Z","shell.execute_reply.started":"2024-07-01T09:53:57.977571Z","shell.execute_reply":"2024-07-01T09:53:57.981604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MinstDataset(Dataset):\n    \"\"\"Digit Recognizer.\"\"\"\n    \n    def __init__(self, \n                 df, \n                 transform=None,\n                 target_transform=None\n                ):\n        \"\"\"\n        Args: \n            df(DataFrame): dataframe\n            transform (callable, optional): optional albumentations transform\n        \"\"\"\n        self.df = df\n        self.transform = transform\n        self.target_transform = target_transform\n        \n    def __len__(self):\n        return len(self.df)\n    \n    \n    def __getitem__(self, idx):\n        # handle edge case\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n        \n        label = self.df['label'].iloc[idx]\n        image = self.df.iloc[idx, 1:]\n        image = np.array([image], dtype=float).reshape(28,28)\n\n        if self.transform:\n            transformed = self.transform(image=image)\n            image = transformed[\"image\"]\n        if self.target_transform:\n            label = self.target_transform(label)\n        \n        return image, label","metadata":{"execution":{"iopub.status.busy":"2024-07-01T09:53:58.622519Z","iopub.execute_input":"2024-07-01T09:53:58.622901Z","iopub.status.idle":"2024-07-01T09:53:58.631643Z","shell.execute_reply.started":"2024-07-01T09:53:58.622870Z","shell.execute_reply":"2024-07-01T09:53:58.630580Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ndf = pd.read_csv(cfg.train_csv_path)\ntrain_df, val_df = train_test_split(df, test_size=0.2, random_state=42)\n\n\ntrain_transform_pipeline = A.Compose([\n    A.Resize(28, 28),  # Keep original size or choose based on your model\n    A.ToFloat(max_value=255.0),  # Convert to float in [0,1] range\n    A.Normalize(mean=0.1307, std=0.3081),  # MNIST-specific values\n    A.RandomRotate90(),\n    A.ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.1, rotate_limit=15),\n    ToTensorV2(),\n])\ntest_transform_pipeline = A.Compose([\n    A.Resize(28, 28),  # Keep original size or choose based on your model\n    A.ToFloat(max_value=255.0),  # Convert to float in [0,1] range\n    A.Normalize(mean=0.1307, std=0.3081),  # MNIST-specific values\n    ToTensorV2(),\n])\n\ntrain_ds = MinstDataset(train_df, transform=train_transform_pipeline)\nval_ds = MinstDataset(val_df, transform=test_transform_pipeline)","metadata":{"execution":{"iopub.status.busy":"2024-07-01T09:53:58.819043Z","iopub.execute_input":"2024-07-01T09:53:58.819386Z","iopub.status.idle":"2024-07-01T09:54:01.905578Z","shell.execute_reply.started":"2024-07-01T09:53:58.819360Z","shell.execute_reply":"2024-07-01T09:54:01.904772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train_ds[0][0].max()\ntrain_ds.df.label.unique()","metadata":{"execution":{"iopub.status.busy":"2024-07-01T09:54:01.907145Z","iopub.execute_input":"2024-07-01T09:54:01.907428Z","iopub.status.idle":"2024-07-01T09:54:01.915519Z","shell.execute_reply.started":"2024-07-01T09:54:01.907404Z","shell.execute_reply":"2024-07-01T09:54:01.914499Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dl = DataLoader(train_ds, batch_size=256, shuffle=True)\nval_dl = DataLoader(val_ds, batch_size=256, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2024-07-01T09:56:29.561908Z","iopub.execute_input":"2024-07-01T09:56:29.562264Z","iopub.status.idle":"2024-07-01T09:56:29.567468Z","shell.execute_reply.started":"2024-07-01T09:56:29.562228Z","shell.execute_reply":"2024-07-01T09:56:29.566433Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Display image and label.\ntrain_features, train_labels = next(iter(train_dl))\nprint(f\"Feature batch shape: {train_features.size()}\")\nprint(f\"Labels batch shape: {train_labels.size()}\")\n\nimg = train_features[0]\nimage_transposed = np.transpose(img, (1, 2, 0))\nlabel = train_labels[0]\nplt.imshow(image_transposed)\nplt.show()\nprint(f\"Label: {label}\")","metadata":{"execution":{"iopub.status.busy":"2024-07-01T09:56:31.178055Z","iopub.execute_input":"2024-07-01T09:56:31.178763Z","iopub.status.idle":"2024-07-01T09:56:31.533758Z","shell.execute_reply.started":"2024-07-01T09:56:31.178721Z","shell.execute_reply":"2024-07-01T09:56:31.532879Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torchvision\nfrom torchvision import models\nimport torchmetrics \nimport torch.nn as nn\nfrom torchinfo import summary\nimport torch\n\n\n\n# Set the manual seeds\ntorch.manual_seed(42)\ntorch.cuda.manual_seed(42)\n\n# train setting\nepochs = 50\nlr = 1e-3\ndevice = (\n    \"cuda\"\n    if torch.cuda.is_available()\n    else \"mps\"\n    if torch.backends.mps.is_available()\n    else \"cpu\"\n)\nprint(f\"Using {device} device\")","metadata":{"execution":{"iopub.status.busy":"2024-07-01T09:56:46.412727Z","iopub.execute_input":"2024-07-01T09:56:46.413407Z","iopub.status.idle":"2024-07-01T09:56:46.420081Z","shell.execute_reply.started":"2024-07-01T09:56:46.413374Z","shell.execute_reply":"2024-07-01T09:56:46.419169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# weights = torchvision.models.AlexNet_Weights.DEFAULT\n# model = models.alexnet(weights=weights)\n# # Freeze all base layers in the \"features\" section of the model (the feature extractor) by setting requires_grad=False\n# for param in model.features.parameters():\n#     param.requires_grad = False\n\n# model.classifier[-1].out_features = 3\n\nimport torch.nn.functional as F\nimport torch.nn as nn\n\n# class MnistConvNet(nn.Module):\n#     def __init__(self, num_classes):\n#         super().__init__()\n#         self.num_classes = num_classes\n#         self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)\n#         self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)\n#         self.fc1 = nn.Linear(64 * 7 * 7, 128)\n#         self.fc2 = nn.Linear(128, self.num_classes)\n#         self.pool = nn.MaxPool2d(2, 2)\n#         self.relu = nn.ReLU()\n\n#     def forward(self, x):\n#         x = self.relu(self.conv1(x))\n#         x = self.pool(x)\n#         x = self.relu(self.conv2(x))\n#         x = self.pool(x)\n#         x = x.view(x.size(0), -1)  # Flatten while preserving batch size\n#         x = self.relu(self.fc1(x))\n#         x = self.fc2(x)\n#         return x\n\n# model = MnistConvNet(num_classes=10)\n\nclass MnistConvNet(nn.Module):\n  \n    def __init__(self, num_classes=10):\n        super().__init__()\n        self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=5, stride=1, padding=1)\n        self.bn1 = nn.BatchNorm2d(32)\n        self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5,stride=1, padding=1)\n        self.bn2 = nn.BatchNorm2d(64)\n        self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)\n        self.fc1 = nn.Linear(64 * 5 * 5, 256)\n        self.fc2 = nn.Linear(256, num_classes)\n\n    def forward(self, x):\n        x = F.relu(self.bn1(self.conv1(x)))\n        x = self.maxpool(x)\n        x = F.relu(self.bn2(self.conv2(x)))\n        x = self.maxpool(x)\n        x = x.view(-1, 64 * 5 * 5)\n        x = F.relu(self.fc1(x))\n        x = self.fc2(x)\n        return x\n    \n\n\nmodel = MnistConvNet()\n\n# Print a summary using torchinfo (uncomment for actual output)\nsummary(model=model, \n        input_size=(64, 1, 28, 28), # make sure this is \"input_size\", not \"input_shape\"\n#         col_names=[\"input_size\"], # uncomment for smaller output\n        col_names=[\"input_size\", \"output_size\", \"num_params\", \"trainable\"],\n        col_width=20,\n        row_settings=[\"var_names\"],\n)","metadata":{"execution":{"iopub.status.busy":"2024-07-01T10:14:31.218571Z","iopub.execute_input":"2024-07-01T10:14:31.218937Z","iopub.status.idle":"2024-07-01T10:14:31.266574Z","shell.execute_reply.started":"2024-07-01T10:14:31.218905Z","shell.execute_reply":"2024-07-01T10:14:31.265608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.to(device)\ntrain_acc_fn = torchmetrics.Accuracy('multiclass', num_classes=10).to(device)\nval_acc_fn = torchmetrics.Accuracy('multiclass', num_classes=10).to(device)\noptimizer = torch.optim.Adam(params=model.parameters(), lr=lr)\nscheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer=optimizer, mode='min', factor=0.1, patience=5)\ncriterion_fn = nn.CrossEntropyLoss()  # Note: This is a class, not a function\n\ntrain_losses, val_losses, train_accs, val_accs = [], [], [], []\n\nfor epoch in range(epochs):\n    model.train()\n    train_run_loss = 0\n    train_acc_fn.reset()\n\n    for idx, (x, y) in enumerate(train_dl):\n        optimizer.zero_grad()\n        x, y = x.to(device), y.to(device)\n        pred_logit = model(x)\n        loss = criterion_fn(pred_logit, y)\n        loss.backward()\n        optimizer.step()\n        \n        train_run_loss += loss.item()\n        train_acc_fn.update(pred_logit.softmax(dim=1), y)\n    \n    train_loss = train_run_loss / len(train_dl)\n    train_acc = train_acc_fn.compute().item()\n    print(f'Epoch {epoch+1}/{epochs} - Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.4f}')\n    train_losses.append(train_loss)\n    train_accs.append(train_acc)\n    \n    model.eval()\n    val_run_loss = 0\n    val_acc_fn.reset()\n\n    with torch.inference_mode():\n        for idx, (x, y) in enumerate(val_dl):\n            x, y = x.to(device), y.to(device)\n            val_logit = model(x)\n            val_loss = criterion_fn(val_logit, y)\n            val_run_loss += val_loss.item()\n            val_acc_fn.update(val_logit.softmax(dim=1), y)\n    \n    val_loss = val_run_loss / len(val_dl)\n    val_acc = val_acc_fn.compute().item()\n    print(f'Epoch {epoch+1}/{epochs} - Val Loss: {val_loss:.4f}, Val Acc: {val_acc:.4f}')\n    val_losses.append(val_loss)\n    val_accs.append(val_acc)\n    \n    scheduler.step(val_loss)  # Use test loss for LR scheduling\n\nprint(\"Training completed.\")","metadata":{"execution":{"iopub.status.busy":"2024-07-01T10:14:38.775521Z","iopub.execute_input":"2024-07-01T10:14:38.775947Z","iopub.status.idle":"2024-07-01T10:32:41.592689Z","shell.execute_reply.started":"2024-07-01T10:14:38.775914Z","shell.execute_reply":"2024-07-01T10:32:41.591743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\ntest_pred = [] \ntest_df = pd.read_csv('/kaggle/input/digit-recognizer/test.csv')\nsubmit_df = pd.read_csv('/kaggle/input/digit-recognizer/sample_submission.csv')\nmodel.eval()\nwith torch.inference_mode():\n    for idx, row in test_df.iterrows():\n        image = np.array(row).reshape(28,28)\n        image = test_transform_pipeline(image=image)['image']\n        image = image.unsqueeze(0).to(device)\n        pred = model(image)\n        pred_class = pred.argmax(dim=1).item()\n        \n        test_pred.append(pred_class)\n\n# Save predictions to submit_df\nsubmit_df['Label'] = test_pred\n\n# Save the submission file\nsubmit_df.to_csv('submission.csv', index=False)\nprint(\"Predictions saved to submission.csv\")","metadata":{"execution":{"iopub.status.busy":"2024-07-01T10:42:34.549508Z","iopub.execute_input":"2024-07-01T10:42:34.549999Z","iopub.status.idle":"2024-07-01T10:43:01.666914Z","shell.execute_reply.started":"2024-07-01T10:42:34.549967Z","shell.execute_reply":"2024-07-01T10:43:01.665919Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submit_df","metadata":{"execution":{"iopub.status.busy":"2024-07-01T10:44:05.013255Z","iopub.execute_input":"2024-07-01T10:44:05.013611Z","iopub.status.idle":"2024-07-01T10:44:05.026242Z","shell.execute_reply.started":"2024-07-01T10:44:05.013584Z","shell.execute_reply":"2024-07-01T10:44:05.025273Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}