{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.9.23"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":3004,"databundleVersionId":861823,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"6226ced1","cell_type":"markdown","source":"# Digit Recognizer","metadata":{}},{"id":"56c32e33-9794-41f9-8e70-b5654f338fbe","cell_type":"markdown","source":"Author: Izbassar Assylzhan Aidaruly\nDate: 6th November 2025\nTime: 19:43","metadata":{}},{"id":"09d0a153","cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\ntrain_df = pd.read_csv('./data/train.csv', sep=',')\ntrain_df.head()\nprint(train_df.shape)\nprint(len(train_df))","metadata":{},"outputs":[],"execution_count":null},{"id":"b0ec133d","cell_type":"code","source":"X_train = train_df.drop(labels=['label'], axis=1)\ny_train = train_df['label']\n\ny_train.head()","metadata":{},"outputs":[],"execution_count":null},{"id":"0507594d","cell_type":"code","source":"x = X_train.iloc[0]\nx_np = np.array(x)\nprint(f'Previous shape = {x_np.shape}')\nx_np = np.resize(x_np, (28, 28))\nprint(f'New shape = {x_np.shape}')\nprint(x_np)","metadata":{},"outputs":[],"execution_count":null},{"id":"fd4854a5","cell_type":"code","source":"fig = plt.figure(figsize=(2, 2))\nax = fig.add_subplot(1, 1, 1)\nax.imshow(x_np, cmap='gray')\nax.set_title(y_train[0])\nplt.show()","metadata":{},"outputs":[],"execution_count":null},{"id":"f93e981a","cell_type":"code","source":"def show_digit(sample):\n    \"\"\"Show digit from pixels.\"\"\"\n    x, y = sample.drop('label'), sample['label']\n    x_np = np.asarray(x, dtype=np.float32).reshape(28, 28)\n    fig = plt.figure(figsize=(2, 2))\n    ax = fig.add_subplot(1, 1, 1)\n    ax.imshow(x_np, cmap='gray')\n    ax.set_title(y)\n    plt.show()\n\nshow_digit(train_df.iloc[10])","metadata":{},"outputs":[],"execution_count":null},{"id":"1f8e0e23","cell_type":"markdown","source":"## Creating the Dataloader","metadata":{}},{"id":"d0003146","cell_type":"code","source":"import os\nimport torch\nfrom torch.utils.data import DataLoader, Dataset\nfrom torchvision.transforms import ToTensor\nfrom sklearn.model_selection import train_test_split\n\nimport warnings\nwarnings.filterwarnings('ignore')\n\nplt.ion()  # interactive mode\n\ndevice = (torch.accelerator.current_accelerator().type  # type: ignore\n          if torch.accelerator.is_available()\n          else 'cpu')\nprint(f'Using {device} device')\n\nclass DigitDataset(Dataset):\n    \"\"\"Digit dataset.\"\"\"\n\n    def __init__(self, root, train, transform=None):\n        self.csv_path = os.path.join(root, 'train.csv')\n        self.data = pd.read_csv(self.csv_path, sep=',')\n        self.train = train\n\n        self.train_data, self.test_data = train_test_split(\n            self.data,\n            test_size=0.3,\n            shuffle=True)\n            \n        self.transform = transform\n\n    def __len__(self):\n        if self.train:\n            return len(self.train_data)\n        return len(self.test_data)\n\n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n        if self.train:\n            sample = self.train_data.iloc[idx]\n        else:\n            sample = self.test_data.iloc[idx]\n\n        img, label = sample.drop('label'), sample['label']\n        img = np.asarray(img, dtype=np.float32).reshape(28, 28)\n\n        if self.transform:\n            img = self.transform(img)\n            label = torch.tensor(\n                label, dtype=torch.long)\n        return img, label","metadata":{},"outputs":[],"execution_count":null},{"id":"b6fcf591","cell_type":"code","source":"digits_train = DigitDataset(\n    root='data',\n    train=True,\n    transform=ToTensor()\n)\n\nfig = plt.figure(figsize=(6, 6))\ncols, rows = 3, 3\nfor i in range(1, cols * rows + 1):\n    sample_idx = torch.randint(len(digits_train), size=(1, )).item()\n    img, label = digits_train[sample_idx]\n    ax = fig.add_subplot(rows, cols, i)\n    plt.axis('off')\n    ax.set_title(label=str(label.item()))\n    ax.imshow(img.squeeze(), cmap='gray') # type: ignore\nplt.show()","metadata":{},"outputs":[],"execution_count":null},{"id":"7abc4753","cell_type":"code","source":"digits_test = DigitDataset(\n    root='data',\n    train=False,\n    transform=ToTensor()\n)\n\nfig = plt.figure(figsize=(6, 6))\ncols, rows = 3, 3\nfor i in range(1, cols * rows + 1):\n    sample_idx = torch.randint(len(digits_test), size=(1, )).item()\n    img, label = digits_test[sample_idx]\n    ax = fig.add_subplot(rows, cols, i)\n    plt.axis('off')\n    ax.set_title(str(label.item()))\n    ax.imshow(img.squeeze(), cmap='gray') # type: ignore\nplt.show()","metadata":{},"outputs":[],"execution_count":null},{"id":"7a5f520a","cell_type":"markdown","source":"## Constracting the neural network","metadata":{}},{"id":"b9a3ca6a","cell_type":"code","source":"from torch import nn\n\nclass DigitRecognizer(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.flatten = nn.Flatten()\n        self.seq_layers = nn.Sequential(\n            nn.Linear(28*28, 512),\n            nn.ReLU(),\n            nn.Linear(512, 128),\n            nn.ReLU(),\n            nn.Linear(128, 10)\n        )\n    \n    def forward(self, x):\n        x = self.flatten(x)\n        logits = self.seq_layers(x)\n        return logits\n\nmodel = DigitRecognizer()","metadata":{},"outputs":[],"execution_count":null},{"id":"b36a5461","cell_type":"code","source":"model(digits_test[1][0]) # type: ignore","metadata":{},"outputs":[],"execution_count":null},{"id":"88d0ef97","cell_type":"markdown","source":"## Training the neural networks","metadata":{}},{"id":"3c32edf7","cell_type":"code","source":"batch_size = 50\n\ntrain_data = DigitDataset(\n    root='data',\n    train=True,\n    transform=ToTensor()\n)\ntest_data = DigitDataset(\n    root='data',\n    train=False,\n    transform=ToTensor()\n)\n\ntrain_dataloader = DataLoader(\n    train_data,\n    batch_size=batch_size,\n    shuffle=True)\ntest_dataloader = DataLoader(\n    test_data,\n    batch_size=batch_size)","metadata":{},"outputs":[],"execution_count":null},{"id":"7e9bb9ca","cell_type":"code","source":"def train_loop(dataloader, model, loss_fn, optimizer, batch_size=64):\n    size = len(dataloader.dataset)\n    model.train()\n    \n    for batch, (X, y) in enumerate(dataloader):\n        logits = model(X)\n        loss = loss_fn(logits, y.long())\n\n        # backpropagation\n        loss.backward()\n        optimizer.step()\n        optimizer.zero_grad()\n\n        if not batch % 100:\n            loss, current = loss.item(), batch * batch_size + len(X)\n            print(f'loss={loss}, current={current}/{size}')\n\n\ndef test_loop(dataloader, model, loss_fn):\n    model.eval()\n    size = len(dataloader.dataset)\n    num_batches = len(dataloader)\n\n    test_loss, correct = 0, 0\n\n    with torch.no_grad():\n        for X, y in dataloader:\n            logits = model(X)\n            test_loss += loss_fn(logits, y.long()).item()\n            correct += (logits.argmax(1) == y).type(torch.float32).sum().item()\n\n    test_loss /= num_batches\n    correct /= size\n    print(f'Test Error:\\nAccuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f}\\n')","metadata":{},"outputs":[],"execution_count":null},{"id":"d400bce8","cell_type":"code","source":"learning_rate = 1e-3\nloss_fn = nn.CrossEntropyLoss()\noptimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)\n\nepochs = 10\n\nfor epoch in range(epochs):\n    print(f'Epoch {epoch+1}----------')\n    train_loop(train_dataloader, model, loss_fn, optimizer, batch_size)\n    test_loop(test_dataloader, model, loss_fn)\n\nprint('Done!')","metadata":{},"outputs":[],"execution_count":null},{"id":"4023624e","cell_type":"code","source":"validation_df = pd.read_csv('./data/test.csv', sep=',')\nvalidation_df.head()","metadata":{},"outputs":[],"execution_count":null},{"id":"cf7a39a0","cell_type":"code","source":"validation_df.info()","metadata":{},"outputs":[],"execution_count":null},{"id":"347f5a4a","cell_type":"code","source":"class DigitValidationDataset(Dataset):\n    def __init__(self, root, transform=None):\n        self.path = os.path.join(root, 'test.csv')\n        self.validation_data = pd.read_csv(self.path, sep=',')\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.validation_data)\n    \n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n\n        sample = self.validation_data.iloc[idx]\n        img = np.asarray(sample, dtype=np.float32).reshape(28, 28)\n\n        if self.transform:\n            img = self.transform(img)\n        return img","metadata":{},"outputs":[],"execution_count":null},{"id":"0535b010","cell_type":"code","source":"validation_data = DigitValidationDataset(\n    root='data',\n    transform=ToTensor()\n)\n\nvalidation_dataloader = DataLoader(\n    dataset=validation_data,\n    batch_size=64\n)\n\nvalidation_labels = []\n\nfor x_test in validation_dataloader:\n    model.eval()\n    with torch.no_grad():\n        pred = model(x_test)\n        validation_labels.append(pred.argmax(1).numpy())","metadata":{},"outputs":[],"execution_count":null},{"id":"5f0902a3","cell_type":"code","source":"validation_labels_np = []\nfor item in validation_labels:\n    for x in item:\n        validation_labels_np.append(x)\nvalidation_labels_np = np.array(validation_labels_np)\nprint(validation_labels_np)","metadata":{},"outputs":[],"execution_count":null},{"id":"6e435cb4","cell_type":"code","source":"validation_eval = {\n    'ImageId': [],\n    'Label': []\n}\n\nfor i in range(len(validation_labels_np)):\n    validation_eval['ImageId'].append(i)\n    validation_eval['Label'].append(validation_labels_np[i])\n\nvalidation_eval_df = pd.DataFrame(validation_eval)\nprint(validation_eval_df.shape)\nstored_path = os.path.join('data', 'submission.csv')\nvalidation_eval_df.to_csv(stored_path, index=False)\n","metadata":{},"outputs":[],"execution_count":null}]}