{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"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":"2023-06-30T15:26:46.832855Z","iopub.execute_input":"2023-06-30T15:26:46.833227Z","iopub.status.idle":"2023-06-30T15:26:46.843327Z","shell.execute_reply.started":"2023-06-30T15:26:46.833198Z","shell.execute_reply":"2023-06-30T15:26:46.841347Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport torch\nfrom torch import nn\nimport torchvision\nfrom torchvision import transforms\nfrom torch.utils.data import DataLoader\nfrom torch.utils.data import TensorDataset\nfrom sklearn.model_selection import train_test_split\nimport random","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:46.845649Z","iopub.execute_input":"2023-06-30T15:26:46.846413Z","iopub.status.idle":"2023-06-30T15:26:46.856204Z","shell.execute_reply.started":"2023-06-30T15:26:46.846377Z","shell.execute_reply":"2023-06-30T15:26:46.855111Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# setup gpu\nif torch.cuda.is_available():\n    device = 'cuda'\nelse:\n    device = 'cpu'\nprint(f\"Device: {device}\")","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:46.858686Z","iopub.execute_input":"2023-06-30T15:26:46.859215Z","iopub.status.idle":"2023-06-30T15:26:46.868428Z","shell.execute_reply.started":"2023-06-30T15:26:46.859161Z","shell.execute_reply":"2023-06-30T15:26:46.867258Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# load data\ntrain_df = pd.read_csv('/kaggle/input/digit-recognizer/train.csv')\ntest_df = pd.read_csv('/kaggle/input/digit-recognizer/test.csv')\nX_train_df = train_df.drop('label', axis=1).astype('float32')\ny_train_df = train_df['label']\nX_test_df = test_df.astype('float32')","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:46.870275Z","iopub.execute_input":"2023-06-30T15:26:46.870954Z","iopub.status.idle":"2023-06-30T15:26:51.639908Z","shell.execute_reply.started":"2023-06-30T15:26:46.870921Z","shell.execute_reply":"2023-06-30T15:26:51.638806Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Shape of training data: {X_train_df.shape}\")\nprint(f\"Shape of test data: {X_test_df.shape}\")\nprint(f\"Number of classes: {y_train_df.nunique()}\")","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:51.642866Z","iopub.execute_input":"2023-06-30T15:26:51.643271Z","iopub.status.idle":"2023-06-30T15:26:51.649235Z","shell.execute_reply.started":"2023-06-30T15:26:51.643220Z","shell.execute_reply":"2023-06-30T15:26:51.648220Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# function to plot images\ndef plot_images(image):\n    image = image.values.reshape(28, 28) \n    plt.imshow(image, cmap = 'gray')\n    plt.show()\n# use function to plot images\nfor i in range(5): \n    image = X_train_df.iloc[i] \n    plot_images(image)","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:51.650761Z","iopub.execute_input":"2023-06-30T15:26:51.651758Z","iopub.status.idle":"2023-06-30T15:26:52.827752Z","shell.execute_reply.started":"2023-06-30T15:26:51.651724Z","shell.execute_reply":"2023-06-30T15:26:52.826807Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# transform data into tensors\nX_train = torch.tensor(X_train_df.values, dtype=torch.float32)\ny_train = torch.tensor(y_train_df.values)\nX_test = torch.tensor(X_test_df.values, dtype=torch.float32)","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:52.829447Z","iopub.execute_input":"2023-06-30T15:26:52.829828Z","iopub.status.idle":"2023-06-30T15:26:52.984058Z","shell.execute_reply.started":"2023-06-30T15:26:52.829776Z","shell.execute_reply":"2023-06-30T15:26:52.983047Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# split train data into train/validation\nX_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size = 0.20, random_state=19)","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:52.985667Z","iopub.execute_input":"2023-06-30T15:26:52.986062Z","iopub.status.idle":"2023-06-30T15:26:53.594868Z","shell.execute_reply.started":"2023-06-30T15:26:52.986017Z","shell.execute_reply":"2023-06-30T15:26:53.593804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# reshape images\nX_train = X_train.reshape(-1, 28, 28).unsqueeze(dim=1)\nX_val = X_val.reshape(-1, 28, 28).unsqueeze(dim=1)\nX_test = X_test.reshape(-1, 28, 28).unsqueeze(dim=1)","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:53.596341Z","iopub.execute_input":"2023-06-30T15:26:53.596784Z","iopub.status.idle":"2023-06-30T15:26:53.603759Z","shell.execute_reply.started":"2023-06-30T15:26:53.596746Z","shell.execute_reply":"2023-06-30T15:26:53.602674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# combine train/val values and labels\ntrain_dataset = TensorDataset(X_train, y_train)\nval_dataset = TensorDataset(X_val, y_val)","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:53.605319Z","iopub.execute_input":"2023-06-30T15:26:53.605676Z","iopub.status.idle":"2023-06-30T15:26:53.614535Z","shell.execute_reply.started":"2023-06-30T15:26:53.605640Z","shell.execute_reply":"2023-06-30T15:26:53.612603Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# convert to dataloaders to allow for batch training\nBATCH_SIZE = 32\nNUM_WORKERS = os.cpu_count()\n\ntrain_dataloader = DataLoader(dataset = train_dataset,\n                             batch_size = BATCH_SIZE,\n                             num_workers = NUM_WORKERS,\n                             shuffle=True)\nval_dataloader = DataLoader(dataset = val_dataset,\n                               batch_size = BATCH_SIZE,\n                               num_workers = NUM_WORKERS,\n                               shuffle = False)","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:53.619494Z","iopub.execute_input":"2023-06-30T15:26:53.620396Z","iopub.status.idle":"2023-06-30T15:26:53.626059Z","shell.execute_reply.started":"2023-06-30T15:26:53.620371Z","shell.execute_reply":"2023-06-30T15:26:53.625013Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img, label= next(iter(train_dataloader))\nprint(f\"The shape of the the images is: {img.shape}\")","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:53.627617Z","iopub.execute_input":"2023-06-30T15:26:53.628074Z","iopub.status.idle":"2023-06-30T15:26:53.812002Z","shell.execute_reply.started":"2023-06-30T15:26:53.628031Z","shell.execute_reply":"2023-06-30T15:26:53.810759Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create model\nclass Model(nn.Module):\n    def __init__(self, input_shape: int, output_shape: int, hidden_units: int):\n        super().__init__()\n        self.conv_layer = nn.Sequential(\n        nn.Conv2d(in_channels=input_shape,\n                    out_channels=hidden_units,\n                    kernel_size=3,\n                    stride=1,\n                    padding=1),\n        nn.ReLU(),\n        nn.Conv2d(in_channels=hidden_units,\n                    out_channels=hidden_units,\n                    kernel_size=3,\n                    stride=1,\n                    padding=1),\n        nn.MaxPool2d(kernel_size=2,\n                          stride=2))\n        self.output_layer = nn.Sequential(\n        nn.Flatten(),\n        nn.Linear(in_features=hidden_units*14*14,\n                    out_features=output_shape))\n    def forward(self, x):\n        x = self.conv_layer(x)\n        x = self.output_layer(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:53.813506Z","iopub.execute_input":"2023-06-30T15:26:53.813912Z","iopub.status.idle":"2023-06-30T15:26:53.826943Z","shell.execute_reply.started":"2023-06-30T15:26:53.813880Z","shell.execute_reply":"2023-06-30T15:26:53.825885Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Instatiate model\nmodel = Model(input_shape=1, # color channels\n             hidden_units=8,\n             output_shape=y_train_df.nunique()).to(device)\n","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:53.828947Z","iopub.execute_input":"2023-06-30T15:26:53.829288Z","iopub.status.idle":"2023-06-30T15:26:53.843625Z","shell.execute_reply.started":"2023-06-30T15:26:53.829235Z","shell.execute_reply":"2023-06-30T15:26:53.842288Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create loss function and optimizer\nLR = 0.0001\nloss_fn = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(params=model.parameters(), lr=LR)","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:53.845279Z","iopub.execute_input":"2023-06-30T15:26:53.845600Z","iopub.status.idle":"2023-06-30T15:26:53.852452Z","shell.execute_reply.started":"2023-06-30T15:26:53.845576Z","shell.execute_reply":"2023-06-30T15:26:53.851355Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train model\nepochs = 10\ntrainLoss = torch.zeros(epochs)\nvalLoss = torch.zeros(epochs)\ntrainAcc = torch.zeros(epochs)\nvalAcc = torch.zeros(epochs)\n\nfor epoch in range(epochs):\n    model.train()\n    trainBatchLoss = []\n    trainCorrect = 0\n    trainTotal = 0\n    for (X, y) in train_dataloader:\n        X, y = X.to(device), y.to(device)\n        train_preds = model(X) \n        loss = loss_fn(train_preds, y)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        trainBatchLoss.append(loss.item())\n        _, train_predicted = torch.max(train_preds.data, dim=1) \n        trainTotal += y.size(0) \n        trainCorrect += (train_predicted == y).sum().item()\n        \n    trainLoss[epoch] = np.mean(trainBatchLoss) \n    trainAcc[epoch] = (trainCorrect / trainTotal) * 100 \n    \n    model.eval()\n    valBatchLoss = []\n    valCorrect = 0\n    valTotal = 0\n    \n    with torch.inference_mode():\n        for (X, y) in val_dataloader:\n            X, y = X.to(device), y.to(device)\n            val_preds = model(X) \n            loss = loss_fn(val_preds, y)\n            valBatchLoss.append(loss.item()) \n            _, val_predicted = torch.max(val_preds.data, dim=1)\n            valTotal += y.size(0)\n            valCorrect += (val_predicted == y).sum().item()\n                           \n        valLoss[epoch] = np.mean(valBatchLoss) \n        valAcc[epoch] = (valCorrect / valTotal) * 100\n        \n    print(f\"Epoch: {epoch} | Train Loss: {trainLoss[epoch]:.4f} | Train Acc: {trainAcc[epoch]:.2f}% | Validation Loss : {valLoss[epoch]:.4f} | Validation Acc: {valAcc[epoch]: .2f}%\")","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:26:53.854362Z","iopub.execute_input":"2023-06-30T15:26:53.854709Z","iopub.status.idle":"2023-06-30T15:27:46.174044Z","shell.execute_reply.started":"2023-06-30T15:26:53.854677Z","shell.execute_reply":"2023-06-30T15:27:46.172767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plot losses and acc\nfig,ax = plt.subplots(nrows=1, ncols=2, figsize=(17,6))\n\nax[0].plot(trainLoss, label='Train Loss')\nax[0].plot(valLoss, label='Val Loss')\nax[0].set_xlabel('Epoch')\nax[0].set_ylabel('Loss')\nax[0].set_title('Train/Test Loss')\nax[0].legend()\n\nax[1].plot(trainAcc, label='Train Acc')\nax[1].plot(valAcc, label='Val Acc')\nax[1].set_xlabel('Epoch')\nax[1].set_ylabel('Acc')\nax[1].set_title('Train/Test Acc')\nax[1].legend()\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:27:46.175751Z","iopub.execute_input":"2023-06-30T15:27:46.176206Z","iopub.status.idle":"2023-06-30T15:27:46.792025Z","shell.execute_reply.started":"2023-06-30T15:27:46.176162Z","shell.execute_reply":"2023-06-30T15:27:46.791120Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# test model on test data and plot results\nX_test = X_test.to(device)\nmodel.eval()\nwith torch.inference_mode():\n    test_preds = model(X_test)\n    _, predicted_labels = torch.max(test_preds, dim=1)\n    \n    num_samples = 10\n    random_indices = random.sample(range(len(X_test)), num_samples) \n    fig, ax = plt.subplots(nrows=2, ncols=5, figsize=(17, 6))\n    \n    for i, idx in enumerate(random_indices):\n        image = X_test[idx].squeeze().cpu().numpy()\n        predicted_labels_string = str(predicted_labels[idx].item()) \n        \n        ax[i // 5, i % 5].imshow(image, cmap='gray')\n        ax[i // 5, i % 5].set_title('Predicted: ' + predicted_labels_string)\n        ax[i // 5, i % 5].axis('off')\nplt.show()\n    ","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:27:46.793812Z","iopub.execute_input":"2023-06-30T15:27:46.794583Z","iopub.status.idle":"2023-06-30T15:27:47.641985Z","shell.execute_reply.started":"2023-06-30T15:27:46.794545Z","shell.execute_reply":"2023-06-30T15:27:47.641052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create submission\npredicted_labels = predicted_labels.cpu()\nsubmission_df = pd.DataFrame({'ImageId': range(1, len(predicted_labels) + 1),\n                             'Label': predicted_labels})\nsubmission_df","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:30:20.302288Z","iopub.execute_input":"2023-06-30T15:30:20.302678Z","iopub.status.idle":"2023-06-30T15:30:20.320294Z","shell.execute_reply.started":"2023-06-30T15:30:20.302648Z","shell.execute_reply":"2023-06-30T15:30:20.319279Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2023-06-30T15:30:23.838726Z","iopub.execute_input":"2023-06-30T15:30:23.839098Z","iopub.status.idle":"2023-06-30T15:30:23.903704Z","shell.execute_reply.started":"2023-06-30T15:30:23.839068Z","shell.execute_reply":"2023-06-30T15:30:23.902722Z"},"trusted":true},"execution_count":null,"outputs":[]}]}