Coding 4: Deep Networks on CIFAR10

In this exercise, we will improve our classifier from last week to a multi-layer perceptron

alt text

Note: torch.nn.Conv2d is not allowed.

Load CIFAR-10.

In [ ]:
import torch
import torchvision
import torchvision.transforms as transforms


def fetch_dataloader(transform=None, batch_size=-1, is_train=True):
    """
    Loads data from disk and returns a data_loader.
    A DataLoader is similar to a list of (image, label) tuples.
    """
    data = torchvision.datasets.CIFAR10(
        root='./data', train=is_train, download=True, transform=transform)
    batch = len(data) if batch_size is -1 else batch_size
    loader = torch.utils.data.DataLoader(
        data, batch_size=batch, shuffle=True, num_workers=4)
      
    return loader
  
  
classes = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

dataloader = fetch_dataloader(transform, is_train=True)
x, y = iter(dataloader).next()

Tensorboard for debugging.

In [ ]:
import torch.utils.tensorboard as tb
%load_ext tensorboard
import tempfile
log_dir = tempfile.mkdtemp()
%tensorboard --logdir {log_dir} --reload_interval 1
%reload_ext tensorboard

Implement the model here.

In [ ]:
import time


class DeepClassifier(torch.nn.Module):
    def __init__(self, input_dim, n_classes):
        """
        TODO: Implement this!
        """
        super().__init__()
        
        self.layer = torch.nn.Linear(input_dim, n_classes)
    
    def forward(self, x):
        """
        Calculate the classification score.
        Input: 
          x (float tensor N x 3072): input flattened images
        Output:
          y (float tensor N x 10): scores for each class
        """
        return self.layer(x)  
    
    def predict(self, image):
        """
        Predict the class label of the image.
        Input:
         image (float tensor 3 x 32 x 32): the test image
         Output:
           label (long): the class label in range [0, 9]
        """
        return self(image).argmax(dim=1)
      
    
def train_model(model, x_train, y_train, x_valid, y_valid,
                learning_rate=0.01, n_iterations=100):
    """
    Train the model.
    TODO: Implement batching.
    """
    writer = tb.SummaryWriter(log_dir + '/{}'.format(time.strftime('%m-%d-%H-%M')))
    optim = torch.optim.SGD(model.parameters(), lr=learning_rate)
    criterion = torch.nn.CrossEntropyLoss()

    for iteration in range(n_iterations):
        loss = criterion(model(x_train), y_train)
        acc = (model.predict(x_train) == y_train).float().mean()

        loss_valid = criterion(model(x_valid), y_valid)
        acc_valid = (model.predict(x_valid) == y_valid).float().mean()
        
        optim.zero_grad()
        loss.backward()
        optim.step()

        writer.add_scalar('loss/train', loss.item(), iteration)
        writer.add_scalar('loss/valid', loss_valid.item(), iteration)
        writer.add_scalar('accuracy/train', acc.item(), iteration)
        writer.add_scalar('accuracy/valid', acc_valid.item(), iteration)

Train your network

In [ ]:
n_train = 2000
n_valid = 1000

x_train = x[:n_train]
x_train = x_train.reshape(x_train.shape[0], -1)
y_train = y[:n_train]

x_valid = x[n_train:n_train+n_valid]
x_valid = x_valid.reshape(x_valid.shape[0], -1)
y_valid = y[n_train:n_train+n_valid]

model = DeepClassifier(3 * 32 * 32, 10)

train_model(model, x_train, y_train, x_valid, y_valid)