Open In Colab

Lecture 6: CNNs for Human Understanding: Faces -Part 02 Code #

#@title 
from ipywidgets import widgets
out1 = widgets.Output()
with out1:
  from IPython.display import YouTubeVideo
  video = YouTubeVideo(id=f"k4mNPA7WOVs", width=854, height=480, fs=1, rel=0)
  print("Video available at https://youtube.com/watch?v=" + video.id)
  display(video)
display(out1)
#@title 
from IPython import display as IPyDisplay
IPyDisplay.HTML(
    f"""
  <div>
    <a href= "https://github.com/DL4CV-NPTEL/Deep-Learning-For-Computer-Vision/blob/main/Slides/Week_7/DL4CV_Week07_Part04.pdf" target="_blank">
    <img src="https://github.com/DL4CV-NPTEL/Deep-Learning-For-Computer-Vision/blob/main/Data/Slides_Logo.png?raw=1"
  alt="button link to Airtable" style="width:200px"></a>
    </div>""" )

Imports

import torch
import torchvision
import torchvision.transforms as transforms

Feature learnings using contrastive learning on MNIST Dataset#

from torchvision.datasets import MNIST
from torchvision import transforms

mean, std = 0.1307, 0.3081

train_dataset = MNIST('../data/MNIST', train=True, download=True,
                             transform=transforms.Compose([
                                 transforms.ToTensor(),
                                 transforms.Normalize((mean,), (std,))
                             ]))
test_dataset = MNIST('../data/MNIST', train=False, download=True,
                            transform=transforms.Compose([
                                transforms.ToTensor(),
                                transforms.Normalize((mean,), (std,))
                            ]))
n_classes = 10
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to ../data/MNIST/MNIST/raw/train-images-idx3-ubyte.gz
Extracting ../data/MNIST/MNIST/raw/train-images-idx3-ubyte.gz to ../data/MNIST/MNIST/raw
Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to ../data/MNIST/MNIST/raw/train-labels-idx1-ubyte.gz
Extracting ../data/MNIST/MNIST/raw/train-labels-idx1-ubyte.gz to ../data/MNIST/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to ../data/MNIST/MNIST/raw/t10k-images-idx3-ubyte.gz
Extracting ../data/MNIST/MNIST/raw/t10k-images-idx3-ubyte.gz to ../data/MNIST/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to ../data/MNIST/MNIST/raw/t10k-labels-idx1-ubyte.gz
Extracting ../data/MNIST/MNIST/raw/t10k-labels-idx1-ubyte.gz to ../data/MNIST/MNIST/raw

Training Procedures#

import torch
import numpy as np


def fit(train_loader, val_loader, model, loss_fn, optimizer, scheduler, n_epochs, cuda, log_interval, metrics=[],
        start_epoch=0):
    """
    Loaders, model, loss function and metrics should work together for a given task,
    i.e. The model should be able to process data output of loaders,
    loss function should process target output of loaders and outputs from the model

    Examples: Classification: batch loader, classification model, NLL loss, accuracy metric
    Siamese network: Siamese loader, siamese model, contrastive loss
    Online triplet learning: batch loader, embedding model, online triplet loss
    """
    for epoch in range(0, start_epoch):
        scheduler.step()

    for epoch in range(start_epoch, n_epochs):
        scheduler.step()

        # Train stage
        train_loss, metrics = train_epoch(train_loader, model, loss_fn, optimizer, cuda, log_interval, metrics)

        message = 'Epoch: {}/{}. Train set: Average loss: {:.4f}'.format(epoch + 1, n_epochs, train_loss)
        for metric in metrics:
            message += '\t{}: {}'.format(metric.name(), metric.value())

        val_loss, metrics = test_epoch(val_loader, model, loss_fn, cuda, metrics)
        val_loss /= len(val_loader)

        message += '\nEpoch: {}/{}. Validation set: Average loss: {:.4f}'.format(epoch + 1, n_epochs,
                                                                                 val_loss)
        for metric in metrics:
            message += '\t{}: {}'.format(metric.name(), metric.value())

        print(message)


def train_epoch(train_loader, model, loss_fn, optimizer, cuda, log_interval, metrics):
    for metric in metrics:
        metric.reset()

    model.train()
    losses = []
    total_loss = 0

    for batch_idx, (data, target) in enumerate(train_loader):
        target = target if len(target) > 0 else None
        if not type(data) in (tuple, list):
            data = (data,)
        if cuda:
            data = tuple(d.cuda() for d in data)
            if target is not None:
                target = target.cuda()


        optimizer.zero_grad()
        outputs = model(*data)

        if type(outputs) not in (tuple, list):
            outputs = (outputs,)

        loss_inputs = outputs
        if target is not None:
            target = (target,)
            loss_inputs += target

        loss_outputs = loss_fn(*loss_inputs)
        loss = loss_outputs[0] if type(loss_outputs) in (tuple, list) else loss_outputs
        losses.append(loss.item())
        total_loss += loss.item()
        loss.backward()
        optimizer.step()

        for metric in metrics:
            metric(outputs, target, loss_outputs)

        if batch_idx % log_interval == 0:
            message = 'Train: [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                batch_idx * len(data[0]), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), np.mean(losses))
            for metric in metrics:
                message += '\t{}: {}'.format(metric.name(), metric.value())

            print(message)
            losses = []

    total_loss /= (batch_idx + 1)
    return total_loss, metrics


def test_epoch(val_loader, model, loss_fn, cuda, metrics):
    with torch.no_grad():
        for metric in metrics:
            metric.reset()
        model.eval()
        val_loss = 0
        for batch_idx, (data, target) in enumerate(val_loader):
            target = target if len(target) > 0 else None
            if not type(data) in (tuple, list):
                data = (data,)
            if cuda:
                data = tuple(d.cuda() for d in data)
                if target is not None:
                    target = target.cuda()

            outputs = model(*data)

            if type(outputs) not in (tuple, list):
                outputs = (outputs,)
            loss_inputs = outputs
            if target is not None:
                target = (target,)
                loss_inputs += target

            loss_outputs = loss_fn(*loss_inputs)
            loss = loss_outputs[0] if type(loss_outputs) in (tuple, list) else loss_outputs
            val_loss += loss.item()

            for metric in metrics:
                metric(outputs, target, loss_outputs)

    return val_loss, metrics

Common Setup#

import torch
from torch.optim import lr_scheduler
import torch.optim as optim
from torch.autograd import Variable
import numpy as np
cuda = torch.cuda.is_available()

%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt

mnist_classes = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728',
              '#9467bd', '#8c564b', '#e377c2', '#7f7f7f',
              '#bcbd22', '#17becf']

def plot_embeddings(embeddings, targets, xlim=None, ylim=None):
    plt.figure(figsize=(10,10))
    for i in range(10):
        inds = np.where(targets==i)[0]
        plt.scatter(embeddings[inds,0], embeddings[inds,1], alpha=0.5, color=colors[i])
    if xlim:
        plt.xlim(xlim[0], xlim[1])
    if ylim:
        plt.ylim(ylim[0], ylim[1])
    plt.legend(mnist_classes)

def extract_embeddings(dataloader, model):
    with torch.no_grad():
        model.eval()
        embeddings = np.zeros((len(dataloader.dataset), 2))
        labels = np.zeros(len(dataloader.dataset))
        k = 0
        for images, target in dataloader:
            if cuda:
                images = images.cuda()
            embeddings[k:k+len(images)] = model.get_embedding(images).data.cpu().numpy()
            labels[k:k+len(images)] = target.numpy()
            k += len(images)
    return embeddings, labels

Siamese network#

from PIL import Image

from torch.utils.data import Dataset
from torch.utils.data.sampler import BatchSampler


class SiameseMNIST(Dataset):
    """
    Train: For each sample creates randomly a positive or a negative pair
    Test: Creates fixed pairs for testing
    """

    def __init__(self, mnist_dataset):
        self.mnist_dataset = mnist_dataset

        self.train = self.mnist_dataset.train
        self.transform = self.mnist_dataset.transform

        if self.train:
            self.train_labels = self.mnist_dataset.train_labels
            self.train_data = self.mnist_dataset.train_data
            self.labels_set = set(self.train_labels.numpy())
            self.label_to_indices = {label: np.where(self.train_labels.numpy() == label)[0]
                                     for label in self.labels_set}
        else:
            # generate fixed pairs for testing
            self.test_labels = self.mnist_dataset.test_labels
            self.test_data = self.mnist_dataset.test_data
            self.labels_set = set(self.test_labels.numpy())
            self.label_to_indices = {label: np.where(self.test_labels.numpy() == label)[0]
                                     for label in self.labels_set}

            random_state = np.random.RandomState(29)

            positive_pairs = [[i,
                               random_state.choice(self.label_to_indices[self.test_labels[i].item()]),
                               1]
                              for i in range(0, len(self.test_data), 2)]

            negative_pairs = [[i,
                               random_state.choice(self.label_to_indices[
                                                       np.random.choice(
                                                           list(self.labels_set - set([self.test_labels[i].item()]))
                                                       )
                                                   ]),
                               0]
                              for i in range(1, len(self.test_data), 2)]
            self.test_pairs = positive_pairs + negative_pairs

    def __getitem__(self, index):
        if self.train:
            target = np.random.randint(0, 2)
            img1, label1 = self.train_data[index], self.train_labels[index].item()
            if target == 1:
                siamese_index = index
                while siamese_index == index:
                    siamese_index = np.random.choice(self.label_to_indices[label1])
            else:
                siamese_label = np.random.choice(list(self.labels_set - set([label1])))
                siamese_index = np.random.choice(self.label_to_indices[siamese_label])
            img2 = self.train_data[siamese_index]
        else:
            img1 = self.test_data[self.test_pairs[index][0]]
            img2 = self.test_data[self.test_pairs[index][1]]
            target = self.test_pairs[index][2]

        img1 = Image.fromarray(img1.numpy(), mode='L')
        img2 = Image.fromarray(img2.numpy(), mode='L')
        if self.transform is not None:
            img1 = self.transform(img1)
            img2 = self.transform(img2)
        return (img1, img2), target

    def __len__(self):
        return len(self.mnist_dataset)
import torch.nn as nn
import torch.nn.functional as F


class EmbeddingNet(nn.Module):
    def __init__(self):
        super(EmbeddingNet, self).__init__()
        self.convnet = nn.Sequential(nn.Conv2d(1, 32, 5), nn.PReLU(),
                                     nn.MaxPool2d(2, stride=2),
                                     nn.Conv2d(32, 64, 5), nn.PReLU(),
                                     nn.MaxPool2d(2, stride=2))

        self.fc = nn.Sequential(nn.Linear(64 * 4 * 4, 256),
                                nn.PReLU(),
                                nn.Linear(256, 256),
                                nn.PReLU(),
                                nn.Linear(256, 2)
                                )

    def forward(self, x):
        output = self.convnet(x)
        output = output.view(output.size()[0], -1)
        output = self.fc(output)
        return output

    def get_embedding(self, x):
        return self.forward(x)


class EmbeddingNetL2(EmbeddingNet):
    def __init__(self):
        super(EmbeddingNetL2, self).__init__()

    def forward(self, x):
        output = super(EmbeddingNetL2, self).forward(x)
        output /= output.pow(2).sum(1, keepdim=True).sqrt()
        return output

    def get_embedding(self, x):
        return self.forward(x)


class ClassificationNet(nn.Module):
    def __init__(self, embedding_net, n_classes):
        super(ClassificationNet, self).__init__()
        self.embedding_net = embedding_net
        self.n_classes = n_classes
        self.nonlinear = nn.PReLU()
        self.fc1 = nn.Linear(2, n_classes)

    def forward(self, x):
        output = self.embedding_net(x)
        output = self.nonlinear(output)
        scores = F.log_softmax(self.fc1(output), dim=-1)
        return scores

    def get_embedding(self, x):
        return self.nonlinear(self.embedding_net(x))


class SiameseNet(nn.Module):
    def __init__(self, embedding_net):
        super(SiameseNet, self).__init__()
        self.embedding_net = embedding_net

    def forward(self, x1, x2):
        output1 = self.embedding_net(x1)
        output2 = self.embedding_net(x2)
        return output1, output2

    def get_embedding(self, x):
        return self.embedding_net(x)


class TripletNet(nn.Module):
    def __init__(self, embedding_net):
        super(TripletNet, self).__init__()
        self.embedding_net = embedding_net

    def forward(self, x1, x2, x3):
        output1 = self.embedding_net(x1)
        output2 = self.embedding_net(x2)
        output3 = self.embedding_net(x3)
        return output1, output2, output3

    def get_embedding(self, x):
        return self.embedding_net(x)

Siamese Network#

Now we’ll train a siamese network that takes a pair of images and trains the embeddings so that the distance between them is minimized if their from the same class or greater than some margin value if they represent different classes. We’ll minimize a contrastive loss function(Raia Hadsell, Sumit Chopra, Yann LeCun, Dimensionality reduction by learning an invariant mapping, CVPR 2006): ![contrastive_learn.png](data:image/png;base64,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)

class ContrastiveLoss(nn.Module):
    """
    Contrastive loss
    Takes embeddings of two samples and a target label == 1 if samples are from the same class and label == 0 otherwise
    """

    def __init__(self, margin):
        super(ContrastiveLoss, self).__init__()
        self.margin = margin
        self.eps = 1e-9

    def forward(self, output1, output2, target, size_average=True):
        distances = (output2 - output1).pow(2).sum(1)  # squared distances
        losses = 0.5 * (target.float() * distances +
                        (1 + -1 * target).float() * F.relu(self.margin - (distances + self.eps).sqrt()).pow(2))
        return losses.mean() if size_average else losses.sum()
# Set up data loaders
siamese_train_dataset = SiameseMNIST(train_dataset) # Returns pairs of images and target same/different
siamese_test_dataset = SiameseMNIST(test_dataset)
batch_size = 128
kwargs = {'num_workers': 1, 'pin_memory': True} if cuda else {}
siamese_train_loader = torch.utils.data.DataLoader(siamese_train_dataset, batch_size=batch_size, shuffle=True, **kwargs)
siamese_test_loader = torch.utils.data.DataLoader(siamese_test_dataset, batch_size=batch_size, shuffle=False, **kwargs)

# Set up the network and training parameters
margin = 1.
embedding_net = EmbeddingNet()
model = SiameseNet(embedding_net)
if cuda:
    model.cuda()
loss_fn = ContrastiveLoss(margin)
lr = 1e-3
optimizer = optim.Adam(model.parameters(), lr=lr)
scheduler = lr_scheduler.StepLR(optimizer, 8, gamma=0.1, last_epoch=-1)
n_epochs = 5
log_interval = 100
/usr/local/lib/python3.7/dist-packages/torchvision/datasets/mnist.py:65: UserWarning: train_labels has been renamed targets
  warnings.warn("train_labels has been renamed targets")
/usr/local/lib/python3.7/dist-packages/torchvision/datasets/mnist.py:75: UserWarning: train_data has been renamed data
  warnings.warn("train_data has been renamed data")
/usr/local/lib/python3.7/dist-packages/torchvision/datasets/mnist.py:70: UserWarning: test_labels has been renamed targets
  warnings.warn("test_labels has been renamed targets")
/usr/local/lib/python3.7/dist-packages/torchvision/datasets/mnist.py:80: UserWarning: test_data has been renamed data
  warnings.warn("test_data has been renamed data")
fit(siamese_train_loader, siamese_test_loader, model, loss_fn, optimizer, scheduler, n_epochs, cuda, log_interval)
/usr/local/lib/python3.7/dist-packages/torch/optim/lr_scheduler.py:136: UserWarning: Detected call of `lr_scheduler.step()` before `optimizer.step()`. In PyTorch 1.1.0 and later, you should call them in the opposite order: `optimizer.step()` before `lr_scheduler.step()`.  Failure to do this will result in PyTorch skipping the first value of the learning rate schedule. See more details at https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate
  "https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate", UserWarning)
Train: [0/60000 (0%)]	Loss: 0.214045
Train: [12800/60000 (21%)]	Loss: 0.070558
Train: [25600/60000 (43%)]	Loss: 0.039938
Train: [38400/60000 (64%)]	Loss: 0.029317
Train: [51200/60000 (85%)]	Loss: 0.021358
Epoch: 1/5. Train set: Average loss: 0.0376
Epoch: 1/5. Validation set: Average loss: 0.0179
Train: [0/60000 (0%)]	Loss: 0.018129
Train: [12800/60000 (21%)]	Loss: 0.017003
Train: [25600/60000 (43%)]	Loss: 0.014276
Train: [38400/60000 (64%)]	Loss: 0.012290
Train: [51200/60000 (85%)]	Loss: 0.011505
Epoch: 2/5. Train set: Average loss: 0.0130
Epoch: 2/5. Validation set: Average loss: 0.0095
Train: [0/60000 (0%)]	Loss: 0.007402
Train: [12800/60000 (21%)]	Loss: 0.009552
Train: [25600/60000 (43%)]	Loss: 0.008338
Train: [38400/60000 (64%)]	Loss: 0.007823
Train: [51200/60000 (85%)]	Loss: 0.006631
Epoch: 3/5. Train set: Average loss: 0.0081
Epoch: 3/5. Validation set: Average loss: 0.0073
Train: [0/60000 (0%)]	Loss: 0.007715
Train: [12800/60000 (21%)]	Loss: 0.007476
Train: [25600/60000 (43%)]	Loss: 0.004673
Train: [38400/60000 (64%)]	Loss: 0.005973
Train: [51200/60000 (85%)]	Loss: 0.004725
Epoch: 4/5. Train set: Average loss: 0.0057
Epoch: 4/5. Validation set: Average loss: 0.0063
Train: [0/60000 (0%)]	Loss: 0.005345
Train: [12800/60000 (21%)]	Loss: 0.004021
Train: [25600/60000 (43%)]	Loss: 0.004697
Train: [38400/60000 (64%)]	Loss: 0.003915
Train: [51200/60000 (85%)]	Loss: 0.003818
Epoch: 5/5. Train set: Average loss: 0.0042
Epoch: 5/5. Validation set: Average loss: 0.0056
# Set up data loaders
batch_size = 256
kwargs = {'num_workers': 1, 'pin_memory': True} if cuda else {}
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True, **kwargs)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False, **kwargs)


train_embeddings_cl, train_labels_cl = extract_embeddings(train_loader, model)
plot_embeddings(train_embeddings_cl, train_labels_cl)
val_embeddings_cl, val_labels_cl = extract_embeddings(test_loader, model)
plot_embeddings(val_embeddings_cl, val_labels_cl)
../../_images/Week_7_Lecture_6_19_0.png ../../_images/Week_7_Lecture_6_19_1.png