{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"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","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# import required libraries\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset\n\nimport pandas as pd\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data exploration"},{"metadata":{"trusted":true},"cell_type":"code","source":"# read in the mnist training csv data\nmnist_train_data = pd.read_csv('../input/digit-recognizer/train.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# check the first few rows of data\nmnist_train_data.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# get overview of data properties\nmnist_train_data.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# access specific digit information\nrow = 1700\ndata = mnist_train_data.iloc[row]\nlabel = data[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# reformat pixel values for graphing\nimg = data[1:].values.reshape(28, 28)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Setup MNIST dataset class"},{"metadata":{"trusted":true},"cell_type":"code","source":"# visualise selected image\nplt.title(\"Label\" + str(label))\nplt.imshow(img, interpolation=None, cmap=\"Blues\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_values = torch.FloatTensor(mnist_train_data.iloc[row, 1:].values) / 255.0\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class MnistDataset(Dataset):\n  \n    def __init__(self, csv_file):\n        self.data_df = pd.read_csv(csv_file)\n\n    def __len__(self):\n        return len(self.data_df)\n\n    def __getitem__(self, index):\n        # mage target (label)\n        label = self.data_df.iloc[index, 0]\n        target = torch.zeros((10))  # create target tensor \n        target[label] = 1.0  # using one hot encoding\n\n        # image data (normalise from 0-255 to 0-1)\n        image_values = torch.FloatTensor(self.data_df.iloc[index, 1:].values) / 255.0\n\n        # return label, image data and target tensor\n        return label, image_values, target\n\n    def plot_image(self, index):\n        # visualise image from pixels\n        img_arr = self.data_df.iloc[index, 1:].values.reshape(28, 28) \n        plt.title(\"Label: \" + str(self.data_df.iloc[index, 0]))\n        plt.imshow(img_arr, interpolation='none', cmap=\"Blues\")\n        plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mnist_train_dataset = MnistDataset('../input/digit-recognizer/train.csv');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# check dataset format is correct\nmnist_train_dataset[1700]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# display example digit\nmnist_train_dataset.plot_image(9)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Setup neural network "},{"metadata":{"trusted":true},"cell_type":"code","source":"# helper class for transforming data\nclass View(nn.Module):\n    def __init__(self, shape):\n        super().__init__()\n        self.shape = shape,\n\n    def forward(self, x):\n        return x.view(*self.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class Classifier(nn.Module):\n\n    def __init__(self):\n        # initialise parent pytorch class\n        super().__init__()\n\n        # setup neural network architecture\n        self.model = nn.Sequential(\n            # expand 1 channel to 10 convolutional filters\n            nn.Conv2d(1, 10, kernel_size=5, stride=2), # 1 input channel, 10 output channels\n            nn.LeakyReLU(0.02),  # apply LeakyReLU to ouput of convolutional layer\n            nn.BatchNorm2d(10), # normalise each channel in the layer\n\n            # 10 filters to 10 filters\n            nn.Conv2d(10, 10, kernel_size=3, stride=2), # apply conv fiter to the 10 filter maps\n            nn.LeakyReLU(0.02), # apply LeakyReLU to output of conv layer\n            nn.BatchNorm2d(10), # normalise each channel in the layer\n\n            View(250), # reshape 10 feat. maps of size 5 * 5 into 1d list of 250 values\n            nn.Linear(250, 10),  # map 250 values to 10 nodes for classification\n            nn.Sigmoid()  # apply sigmoid to output of 10 nodes to get final output\n        )\n\n\n        # setup loss function\n        self.loss_function = torch.nn.BCELoss()\n\n        # setup optimiser using simple stochastic gradient descent\n        self.optimiser = torch.optim.Adam(self.parameters())\n\n        # counter and accumulator to track progress\n        self.counter = 0\n        self.progress = []\n\n    # setup forward method for passing information through network\n    def forward(self, inputs):\n        # run the model\n        return self.model(inputs)\n\n    def train(self, inputs, targets):\n        # calculate nn outputs\n        outputs = self.forward(inputs)\n\n        # calculate loss\n        loss = self.loss_function(outputs, targets)\n\n        # update training progress trackers, accumulate loss val after 10 train ex\n        self.counter += 1\n        if (self.counter % 10 == 0):  \n            self.progress.append(loss.item())  # loss.item() unwraps tensor\n        \n        # indicate speed of training to user\n        if (self.counter % 10000 == 0):\n            print(\"counter = \", self.counter)\n\n        # process nn updates\n        self.optimiser.zero_grad() # set gradients to zero\n        loss.backward() # calculate gradients via backward pass\n        self.optimiser.step() # update nn weights using gradients\n\n\n    def plot_progress(self):\n      df = pd.DataFrame(self.progress, columns=[\"loss\"])\n      df.plot(ylim=(0, 1.0), figsize=(16, 8), alpha=0.1, marker=\".\",\n              grid=True, yticks=(0, 0.25, 0.5))\n\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Train neural network"},{"metadata":{"trusted":true},"cell_type":"code","source":"# create neural network\nnn_classifier = Classifier()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\n\nepochs = 6 # how mnay times to work through entire dataset \n\nfor i in range(epochs):\n  print(\"Training epoch: \", i+1, \"of\", epochs)\n  # train nn on MNIST dataset\n  for label, image_data_tensor, target_tensor in mnist_train_dataset:\n    # batch size 1, channels 1, 28x 28 image   \n    nn_classifier.train(image_data_tensor.view(1, 1, 28, 28), target_tensor)\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# view loss during training\nnn_classifier.plot_progress()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Querying trained network"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_data = pd.read_csv('../input/digit-recognizer/test.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_data.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_data.head()\ntest_data.insert(loc=0, column='label', value=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# load mnist test data\nmnist_test_data = MnistDataset('../input/digit-recognizer/test.csv')\n# add an empty label column (since MnistDataset expects 785 columns)\nmnist_test_data.data_df.insert(loc=0, column='label', value=0)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# pick a record\nrecord = 35 # nth test example\n\n# plot image with label\nmnist_test_data.plot_image(record)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# extract image values for specified record\nimage_data = mnist_test_data[record][1]\n\n# query trained network for prediction\noutput = nn_classifier.forward(image_data.view(1, 1, 28, 28))\n\n# plot output tensor \npd.DataFrame(output.detach().numpy()).plot(kind=\"bar\", legend=False, ylim=(0, 1))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Make predictions on test set"},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions = []\n\nfor _, image_data_tensor, _ in mnist_test_data:\n    # make prediction using model\n    answer = nn_classifier.forward(image_data_tensor.view(1, 1, 28, 28)).detach().numpy().argmax()\n    # collect predictions\n    predictions.append(answer)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Prepare submission file"},{"metadata":{"trusted":true},"cell_type":"code","source":"# make DataFrame according to expected submission format\nsubmission = pd.DataFrame(predictions, columns=['Label'])\nsubmission.index.name = \"ImageId\"\nsubmission.index += 1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Check submission format"},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.tail()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# save submission\nsubmission.to_csv(\"submission.csv\")\nprint(\"Submission successfully saved!\")","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}