In [1]:
import torch
import numpy as np

In [15]:
import torch.nn.functional as F

from torch import nn, optim

In [3]:
from torchvision import datasets
import torchvision.transforms as transforms

In [4]:
num_workers = 0

batch_size = 20

In [5]:
transform = transforms.ToTensor()

train_data = datasets.MNIST(root="MNIST_data", train=True, download=True, transform=transform)
test_data = datasets.MNIST(root="MNIST_data", train=False, download=True, transform=transform)

train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, num_workers=num_workers)
test_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size, num_workers=num_workers)

Data visualization


In [6]:
import matplotlib.pyplot as plt

dataiter = iter(train_loader)

images, labels = dataiter.next()

images = images.numpy()

In [8]:
fig = plt.figure(figsize=(25, 4))

for idx in np.arange(20):
    ax = fig.add_subplot(2, 20/2, idx + 1, xticks=[], yticks=[])
    ax.imshow(np.squeeze(images[idx]), cmap='gray')
    
    ax.set_title(str(labels[idx].item()))



In [14]:
img = np.squeeze(images[0])

fig = plt.figure(figsize=(12, 12))
ax = fig.add_subplot(111)
ax.imshow(img, cmap='gray')

width, height = img.shape
thresh = img.max() / 2.5

for x in range(width):
    for y in range(height):
        val = round(img[x][y], 2) if img[x][y] != 0 else 0
        ax.annotate(str(val), xy=(y, x),
                   horizontalalignment='center',
                   verticalalignment='center',
                   color='white' if img[x][y] < thresh else 'black')


Define the network


In [42]:
class Net(nn.Module):
    def __init__(self):
        super().__init__()
        
        self.fc1 = nn.Linear(28 * 28, 512)
        self.fc2 = nn.Linear(512, 512)
        self.fc3 = nn.Linear(512, 10)
        
        self.dropout = nn.Dropout(0.2)
        self.log_softmax = nn.LogSoftmax(dim=1)
        
    def forward(self, x):
        # flatten
        x = x.view(-1, 28 * 28)
        x = self.dropout(F.relu(self.fc1(x)))
        x = self.dropout(F.relu(self.fc2(x)))
        x = self.log_softmax(self.fc3(x))
        
        return x

In [43]:
model = Net()
print(model)


Net(
  (fc1): Linear(in_features=784, out_features=512, bias=True)
  (fc2): Linear(in_features=512, out_features=512, bias=True)
  (fc3): Linear(in_features=512, out_features=10, bias=True)
  (dropout): Dropout(p=0.2)
  (log_softmax): LogSoftmax()
)

In [44]:
criterion = nn.NLLLoss()

optimizer = optim.Adam(model.parameters(), lr=0.01)

Training the network


In [45]:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

In [46]:
n_epochs = 10

model.to(device)

for epoch in range(n_epochs):
    train_loss = 0.0
    
    for data, target in train_loader:
        optimizer.zero_grad()
        
        data, target = data.to(device), target.to(device)
        
        output = model(data)
        
        loss = criterion(output, target)
        
        loss.backward()
        
        optimizer.step()
        
        train_loss += loss.item() * data.size(0)
    
    train_loss = train_loss / len(train_loader.dataset)
    print("Epoch {}: Training loss {:.6f}".format(epoch, train_loss))


Epoch 0: Training loss 0.609376
Epoch 1: Training loss 0.519175
Epoch 2: Training loss 0.484656
Epoch 3: Training loss 0.441775
Epoch 4: Training loss 0.446916
Epoch 5: Training loss 0.442686
Epoch 6: Training loss 0.442412
Epoch 7: Training loss 0.403153
Epoch 8: Training loss 0.421706
Epoch 9: Training loss 0.416354

Test the network


In [49]:
test_loss = 0.0
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))

with torch.no_grad():
    #!Important: Change model to evaluation mode to deactivate dropout
    model.eval()
    for data, target in test_loader:
        data, target = data.to(device), target.to(device)
                
        output = model(data)
        
        loss = criterion(output, target)
        
        test_loss += loss.item() * data.size(0)
        
        _, pred = torch.max(output, 1)
        
        correct = np.squeeze(pred.eq(target.data.view_as(pred)))
        
        for i in range(batch_size):
            label = target.data[i]
            class_correct[label] += correct[i].item()
            class_total[label] += 1
            
    #!Important: Change model to training mode to activate dropout
    model.train()

In [51]:
test_loss = test_loss / len(test_loader.dataset)
print("Test loss: {:.3f}\n".format(test_loss))

for i in range(10):
    if class_total[i] > 0:
        print('Test Accuracy of %5s: %2d%% (%2d/%2d)' % (
            str(i), 100 * class_correct[i] / class_total[i],
            np.sum(class_correct[i]), np.sum(class_total[i])))
    else:
        print('Test Accuracy of %5s: N/A (no training examples)' % (classes[i]))

print('\nTest Accuracy (Overall): %2d%% (%2d/%2d)' % (
    100. * np.sum(class_correct) / np.sum(class_total),
    np.sum(class_correct), np.sum(class_total)))


Test loss: 0.000

Test Accuracy of     0: 97% (955/980)
Test Accuracy of     1: 97% (1101/1135)
Test Accuracy of     2: 90% (931/1032)
Test Accuracy of     3: 91% (927/1010)
Test Accuracy of     4: 94% (931/982)
Test Accuracy of     5: 96% (857/892)
Test Accuracy of     6: 93% (896/958)
Test Accuracy of     7: 94% (969/1028)
Test Accuracy of     8: 93% (913/974)
Test Accuracy of     9: 92% (934/1009)

Test Accuracy (Overall): 94% (9414/10000)

In [53]:
# obtain one batch of test images
dataiter = iter(test_loader)
images, labels = dataiter.next()

images, labels = images.to(device), labels.to(device)

# get sample outputs
output = model(images)
# convert output probabilities to predicted class
_, preds = torch.max(output, 1)
# prep images for display
images = images.cpu().numpy()

# plot the images in the batch, along with predicted and true labels
fig = plt.figure(figsize=(25, 4))
for idx in np.arange(20):
    ax = fig.add_subplot(2, 20/2, idx+1, xticks=[], yticks=[])
    ax.imshow(np.squeeze(images[idx]), cmap='gray')
    ax.set_title("{} ({})".format(str(preds[idx].item()), str(labels[idx].item())),
                 color=("green" if preds[idx]==labels[idx] else "red"))



In [ ]: