{"cells":[{"metadata":{"id":"DM1xWRMKd7TQ"},"cell_type":"markdown","source":"# Imports"},{"metadata":{"id":"kcRqhpxudhMR","outputId":"f1ffe283-cc5d-4d03-8ef0-be75b829885d","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport torch\nimport numpy as np\nprint(\"Torch Version:\",torch.__version__)\n","execution_count":null,"outputs":[]},{"metadata":{"id":"Z8z_KTKad5N2","trusted":true},"cell_type":"code","source":"from torch import nn\nimport torch.nn.functional as F\nfrom torchvision import datasets,transforms","execution_count":null,"outputs":[]},{"metadata":{"id":"Ix2Gexw7d6cp","outputId":"9ef96e68-0d3d-4e53-82d2-570e63aa09e0","trusted":true},"cell_type":"code","source":"train_on_gpu = torch.cuda.is_available()\n\nif not train_on_gpu:\n    print('CUDA is not available.  Training on CPU ...')\nelse:\n    print('CUDA is available!  Training on GPU ...')","execution_count":null,"outputs":[]},{"metadata":{"id":"hDuJD3ebd5Qr","trusted":true},"cell_type":"code","source":"transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])\ntrainset=datasets.MNIST('~/.pytorch/MNIST_data/',train=True,transform=transform,download=True)\nvalidset=datasets.MNIST('~/.pytorch/MNIST_data/',train=False,transform=transform,download=True)\n\ntrain_loader=torch.utils.data.DataLoader(trainset,batch_size=64,shuffle=True,num_workers=0)\nvalid_loader=torch.utils.data.DataLoader(validset,batch_size=64,shuffle=True,num_workers=0)","execution_count":null,"outputs":[]},{"metadata":{"id":"QJ7vf0g8eYSx"},"cell_type":"markdown","source":"# Network"},{"metadata":{"id":"6V3_8Yns5uAm","outputId":"1016f773-2d30-431a-fbf7-a795dcaa287b","trusted":true},"cell_type":"code","source":"class Net(nn.Module):\n    def __init__(self):\n        super(Net, self).__init__()\n        self.conv1 = nn.Conv2d(1, 5, 5, 1)  #[in_channel,out_channel,filter_size,stride=1]\n        self.conv2 = nn.Conv2d(5, 5, 3, 1)\n        self.fc1 = nn.Linear(5*5*5, 100)\n        self.fc2 = nn.Linear(100, 10)\n\n    def forward(self, x):\n        x = F.relu(self.conv1(x))\n        x = F.max_pool2d(x,2)\n        x = F.relu(self.conv2(x))\n        x = F.max_pool2d(x,2)\n        x = x.view(-1, 5*5*5)\n        x = F.relu(self.fc1(x))\n        x = self.fc2(x)\n        return F.log_softmax(x, dim=1)\n      \n# create a complete CNN\nmodel = Net()\nprint(model)\n\n# move tensors to GPU if CUDA is available\nif train_on_gpu:\n    model.cuda()","execution_count":null,"outputs":[]},{"metadata":{"id":"cUSBYYk3hWiB"},"cell_type":"markdown","source":"input Image  [1,28,28] <br> \nconv1 -          [10,26,26] <br>\nMaxpool       [10,13,13] <br>\nConv2 -         [16,9,9] <br>\nMaxpool -     [16,4,4] <br>\nfc1 -               [16x4x4 , 200] <br>\nfc2 -               [200,10]"},{"metadata":{"id":"2AcPrNy398cs","outputId":"fe8e92ae-8755-4c9a-f1ca-4e23e56f1ab8","trusted":true},"cell_type":"code","source":"pytorch_total_params = sum(p.numel() for p in model.parameters())\nprint(\"Total_params\",pytorch_total_params)\npytorch_total_params = sum(p.numel() for p in model.parameters() if p.requires_grad)\nprint(\"Trainable_params\",pytorch_total_params)","execution_count":null,"outputs":[]},{"metadata":{"id":"EwfV1JZ5d5Vy","trusted":true},"cell_type":"code","source":"import torch.optim as optim\ncriterion = nn.NLLLoss()\n\n# specify optimizer\noptimizer = optim.SGD(model.parameters(), lr=0.01)","execution_count":null,"outputs":[]},{"metadata":{"id":"jzxWxIhDd5Xt","outputId":"f2b733e3-3181-4f7e-f9f3-1ed15b7718d9","trusted":true},"cell_type":"code","source":"# number of epochs to train the model\nn_epochs = 10\n\nvalid_loss_min = np.Inf # track change in validation loss\n\nfor epoch in range(1, n_epochs+1):\n\n    # keep track of training and validation loss\n    train_loss = 0.0\n    valid_loss = 0.0\n    \n    ###################\n    # train the model #\n    ###################\n    model.train()\n    for data, target in train_loader:\n        # move tensors to GPU if CUDA is available\n        if train_on_gpu:\n            data, target = data.cuda(), target.cuda()\n        # clear the gradients of all optimized variables\n        optimizer.zero_grad()\n        # forward pass: compute predicted outputs by passing inputs to the model\n        output = model(data)\n        # calculate the batch loss\n        loss = criterion(output, target)\n        # backward pass: compute gradient of the loss with respect to model parameters\n        loss.backward()\n        # perform a single optimization step (parameter update)\n        optimizer.step()\n        # update training loss\n        train_loss += loss.item()*data.size(0)\n        \n    ######################    \n    # validate the model #\n    ######################\n    model.eval()\n    for data, target in valid_loader:\n        # move tensors to GPU if CUDA is available\n        if train_on_gpu:\n            data, target = data.cuda(), target.cuda()\n        # forward pass: compute predicted outputs by passing inputs to the model\n        output = model(data)\n        # calculate the batch loss\n        loss = criterion(output, target)\n        # update average validation loss \n        valid_loss += loss.item()*data.size(0)\n    \n    # calculate average losses\n    train_loss = train_loss/len(train_loader.sampler)\n    valid_loss = valid_loss/len(valid_loader.sampler)\n        \n    # print training/validation statistics \n    print('Epoch: {} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f}'.format(\n        epoch, train_loss, valid_loss))\n    \n    # save model if validation loss has decreased\n    if valid_loss <= valid_loss_min:\n        print('Validation loss decreased ({:.6f} --> {:.6f}).  Saving model ...'.format(\n        valid_loss_min,\n        valid_loss))\n        torch.save(model.state_dict(), 'model_mnist.pt')\n        valid_loss_min = valid_loss","execution_count":null,"outputs":[]},{"metadata":{"id":"uFfrCDUzqWo8","trusted":true},"cell_type":"code","source":"# specify the image classes\nclasses = ['0', '1', '2', '3', '4',\n           '5', '6', '7', '8', '9']","execution_count":null,"outputs":[]},{"metadata":{"id":"2cja3x2tpeRz","outputId":"22d0add1-3277-4d89-f0d9-d6d419d8e2c6","trusted":true},"cell_type":"code","source":"batch_size=16\n# track test loss\ntest_loss = 0.0\nclass_correct = list(0. for i in range(10))\nclass_total = list(0. for i in range(10))\n\nmodel.eval()\n# iterate over test data\nfor data, target in valid_loader:\n    # move tensors to GPU if CUDA is available\n    if train_on_gpu:\n        data, target = data.cuda(), target.cuda()\n    # forward pass: compute predicted outputs by passing inputs to the model\n    output = model(data)\n    # calculate the batch loss\n    loss = criterion(output, target)\n    # update test loss \n    test_loss += loss.item()*data.size(0)\n    # convert output probabilities to predicted class\n    _, pred = torch.max(output, 1)    \n    # compare predictions to true label\n    correct_tensor = pred.eq(target.data.view_as(pred))\n    correct = np.squeeze(correct_tensor.numpy()) if not train_on_gpu else np.squeeze(correct_tensor.cpu().numpy())\n    # calculate test accuracy for each object class\n    for i in range(batch_size):\n        label = target.data[i]\n        class_correct[label] += correct[i].item()\n        class_total[label] += 1\n\n# average test loss\ntest_loss = test_loss/len(valid_loader.dataset)\nprint('Test Loss: {:.6f}\\n'.format(test_loss))\n\nfor i in range(10):\n    if class_total[i] > 0:\n        print('Test Accuracy of %5s: %2d%% (%2d/%2d)' % (\n            classes[i], 100 * class_correct[i] / class_total[i],\n            np.sum(class_correct[i]), np.sum(class_total[i])))\n    else:\n        print('Test Accuracy of %5s: N/A (no training examples)' % (classes[i]))\n\nprint('\\nTest Accuracy (Overall): %2d%% (%2d/%2d)' % (\n    100. * np.sum(class_correct) / np.sum(class_total),\n    np.sum(class_correct), np.sum(class_total)))","execution_count":null,"outputs":[]},{"metadata":{"id":"tiiMSFdatHaL","trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\n%matplotlib inline\n# helper function to de-normalize and display an image\ndef imshow(img):\n    #img = img / 2 + 0.5  # unnormalize\n    plt.imshow(np.transpose(img, (1, 2, 0)).squeeze())  # convert from Tensor image","execution_count":null,"outputs":[]},{"metadata":{"id":"3F1H_mBOsnyG","outputId":"93c14d02-d052-4341-8fa2-0b8d1248e156","trusted":true},"cell_type":"code","source":"valid_loader=torch.utils.data.DataLoader(validset,batch_size=20,shuffle=True,num_workers=0)\n\n\n# obtain one batch of test images\ndataiter = iter(valid_loader)\nimages, labels = dataiter.next()\nimages.numpy()\n\n\n# move model inputs to cuda, if GPU available\nif train_on_gpu:\n    images = images.cuda()\n\n# get sample outputs\noutput = model(images)\n# convert output probabilities to predicted class\n_, preds_tensor = torch.max(output, 1)\npreds = np.squeeze(preds_tensor.numpy()) if not train_on_gpu else np.squeeze(preds_tensor.cpu().numpy())\n\n# plot the images in the batch, along with predicted and true labels\nfig = plt.figure(figsize=(25, 4))\nfor idx in np.arange(20):\n    ax = fig.add_subplot(2, 20/2, idx+1, xticks=[], yticks=[])\n    imshow(images.cpu()[idx])\n    ax.set_title(\"{} ({})\".format(classes[preds[idx]], classes[labels[idx]]),\n                 color=(\"green\" if preds[idx]==labels[idx].item() else \"red\"))","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}