CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/main/intermediate_source/spatial_transformer_tutorial.py
Views: 494
# -*- coding: utf-8 -*-1"""2Spatial Transformer Networks Tutorial3=====================================4**Author**: `Ghassen HAMROUNI <https://github.com/GHamrouni>`_56.. figure:: /_static/img/stn/FSeq.png78In this tutorial, you will learn how to augment your network using9a visual attention mechanism called spatial transformer10networks. You can read more about the spatial transformer11networks in the `DeepMind paper <https://arxiv.org/abs/1506.02025>`__1213Spatial transformer networks are a generalization of differentiable14attention to any spatial transformation. Spatial transformer networks15(STN for short) allow a neural network to learn how to perform spatial16transformations on the input image in order to enhance the geometric17invariance of the model.18For example, it can crop a region of interest, scale and correct19the orientation of an image. It can be a useful mechanism because CNNs20are not invariant to rotation and scale and more general affine21transformations.2223One of the best things about STN is the ability to simply plug it into24any existing CNN with very little modification.25"""26# License: BSD27# Author: Ghassen Hamrouni2829import torch30import torch.nn as nn31import torch.nn.functional as F32import torch.optim as optim33import torchvision34from torchvision import datasets, transforms35import matplotlib.pyplot as plt36import numpy as np3738plt.ion() # interactive mode3940######################################################################41# Loading the data42# ----------------43#44# In this post we experiment with the classic MNIST dataset. Using a45# standard convolutional network augmented with a spatial transformer46# network.4748from six.moves import urllib49opener = urllib.request.build_opener()50opener.addheaders = [('User-agent', 'Mozilla/5.0')]51urllib.request.install_opener(opener)5253device = torch.device("cuda" if torch.cuda.is_available() else "cpu")5455# Training dataset56train_loader = torch.utils.data.DataLoader(57datasets.MNIST(root='.', train=True, download=True,58transform=transforms.Compose([59transforms.ToTensor(),60transforms.Normalize((0.1307,), (0.3081,))61])), batch_size=64, shuffle=True, num_workers=4)62# Test dataset63test_loader = torch.utils.data.DataLoader(64datasets.MNIST(root='.', train=False, transform=transforms.Compose([65transforms.ToTensor(),66transforms.Normalize((0.1307,), (0.3081,))67])), batch_size=64, shuffle=True, num_workers=4)6869######################################################################70# Depicting spatial transformer networks71# --------------------------------------72#73# Spatial transformer networks boils down to three main components :74#75# - The localization network is a regular CNN which regresses the76# transformation parameters. The transformation is never learned77# explicitly from this dataset, instead the network learns automatically78# the spatial transformations that enhances the global accuracy.79# - The grid generator generates a grid of coordinates in the input80# image corresponding to each pixel from the output image.81# - The sampler uses the parameters of the transformation and applies82# it to the input image.83#84# .. figure:: /_static/img/stn/stn-arch.png85#86# .. note::87# We need the latest version of PyTorch that contains88# affine_grid and grid_sample modules.89#909192class Net(nn.Module):93def __init__(self):94super(Net, self).__init__()95self.conv1 = nn.Conv2d(1, 10, kernel_size=5)96self.conv2 = nn.Conv2d(10, 20, kernel_size=5)97self.conv2_drop = nn.Dropout2d()98self.fc1 = nn.Linear(320, 50)99self.fc2 = nn.Linear(50, 10)100101# Spatial transformer localization-network102self.localization = nn.Sequential(103nn.Conv2d(1, 8, kernel_size=7),104nn.MaxPool2d(2, stride=2),105nn.ReLU(True),106nn.Conv2d(8, 10, kernel_size=5),107nn.MaxPool2d(2, stride=2),108nn.ReLU(True)109)110111# Regressor for the 3 * 2 affine matrix112self.fc_loc = nn.Sequential(113nn.Linear(10 * 3 * 3, 32),114nn.ReLU(True),115nn.Linear(32, 3 * 2)116)117118# Initialize the weights/bias with identity transformation119self.fc_loc[2].weight.data.zero_()120self.fc_loc[2].bias.data.copy_(torch.tensor([1, 0, 0, 0, 1, 0], dtype=torch.float))121122# Spatial transformer network forward function123def stn(self, x):124xs = self.localization(x)125xs = xs.view(-1, 10 * 3 * 3)126theta = self.fc_loc(xs)127theta = theta.view(-1, 2, 3)128129grid = F.affine_grid(theta, x.size())130x = F.grid_sample(x, grid)131132return x133134def forward(self, x):135# transform the input136x = self.stn(x)137138# Perform the usual forward pass139x = F.relu(F.max_pool2d(self.conv1(x), 2))140x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))141x = x.view(-1, 320)142x = F.relu(self.fc1(x))143x = F.dropout(x, training=self.training)144x = self.fc2(x)145return F.log_softmax(x, dim=1)146147148model = Net().to(device)149150######################################################################151# Training the model152# ------------------153#154# Now, let's use the SGD algorithm to train the model. The network is155# learning the classification task in a supervised way. In the same time156# the model is learning STN automatically in an end-to-end fashion.157158159optimizer = optim.SGD(model.parameters(), lr=0.01)160161162def train(epoch):163model.train()164for batch_idx, (data, target) in enumerate(train_loader):165data, target = data.to(device), target.to(device)166167optimizer.zero_grad()168output = model(data)169loss = F.nll_loss(output, target)170loss.backward()171optimizer.step()172if batch_idx % 500 == 0:173print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(174epoch, batch_idx * len(data), len(train_loader.dataset),175100. * batch_idx / len(train_loader), loss.item()))176#177# A simple test procedure to measure the STN performances on MNIST.178#179180181def test():182with torch.no_grad():183model.eval()184test_loss = 0185correct = 0186for data, target in test_loader:187data, target = data.to(device), target.to(device)188output = model(data)189190# sum up batch loss191test_loss += F.nll_loss(output, target, size_average=False).item()192# get the index of the max log-probability193pred = output.max(1, keepdim=True)[1]194correct += pred.eq(target.view_as(pred)).sum().item()195196test_loss /= len(test_loader.dataset)197print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'198.format(test_loss, correct, len(test_loader.dataset),199100. * correct / len(test_loader.dataset)))200201######################################################################202# Visualizing the STN results203# ---------------------------204#205# Now, we will inspect the results of our learned visual attention206# mechanism.207#208# We define a small helper function in order to visualize the209# transformations while training.210211212def convert_image_np(inp):213"""Convert a Tensor to numpy image."""214inp = inp.numpy().transpose((1, 2, 0))215mean = np.array([0.485, 0.456, 0.406])216std = np.array([0.229, 0.224, 0.225])217inp = std * inp + mean218inp = np.clip(inp, 0, 1)219return inp220221# We want to visualize the output of the spatial transformers layer222# after the training, we visualize a batch of input images and223# the corresponding transformed batch using STN.224225226def visualize_stn():227with torch.no_grad():228# Get a batch of training data229data = next(iter(test_loader))[0].to(device)230231input_tensor = data.cpu()232transformed_input_tensor = model.stn(data).cpu()233234in_grid = convert_image_np(235torchvision.utils.make_grid(input_tensor))236237out_grid = convert_image_np(238torchvision.utils.make_grid(transformed_input_tensor))239240# Plot the results side-by-side241f, axarr = plt.subplots(1, 2)242axarr[0].imshow(in_grid)243axarr[0].set_title('Dataset Images')244245axarr[1].imshow(out_grid)246axarr[1].set_title('Transformed Images')247248for epoch in range(1, 20 + 1):249train(epoch)250test()251252# Visualize the STN transformation on some input batch253visualize_stn()254255plt.ioff()256plt.show()257258259