import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
import torchvision.transforms as transforms
from torch.utils.data.sampler import SubsetRandomSampler
import numpy as np
import seaborn as sns
from torchvision.datasets import CIFAR10
from ipywidgets import interact, interact_manual, interactive, fixed
import ipywidgets as widgets
from IPython.display import display
train_on_gpu = torch.cuda.is_available()
print(f"train_on_gpu = {train_on_gpu}")
# convert data to a normalized torch.FloatTensor
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
# choose the training and test datasets
train_data = CIFAR10('data', train=True, download=True, transform=transform)
test_data = CIFAR10('data', train=False, download=True, transform=transform)
# obtain training indices that will be used for validation
num_train = len(train_data)
indices = list(range(num_train))
np.random.shuffle(indices)
# percentage of training set to use as validation
valid_size = 0.15
split = int(np.floor(valid_size * num_train))
train_idx, valid_idx = indices[split:], indices[:split]
print (f"num_train = {num_train}")
batch_size = 20
# define samplers
train_sampler = SubsetRandomSampler(train_idx)
valid_sampler = SubsetRandomSampler(valid_idx)
# prepare data loaders (combine dataset and sampler)
train_loader = torch.utils.data.DataLoader(train_data,
batch_size=batch_size,
sampler=train_sampler,
num_workers=0)
valid_loader = torch.utils.data.DataLoader(train_data,
batch_size=batch_size,
sampler=valid_sampler,
num_workers=0)
test_loader = torch.utils.data.DataLoader(test_data,
batch_size=batch_size,
num_workers=0)
classes = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
import matplotlib.pyplot as plt
%matplotlib inline
iterator_data = iter(train_loader)
images, labels = iterator_data.next()
images = images.numpy()
fig = plt.figure(figsize=(30, 4))
rows = 2
for i in np.arange(batch_size):
ax = fig.add_subplot(rows, batch_size/rows, i+1, xticks=[], yticks=[])
img = images[i] / 2 + 0.5 # unnormalize
plt.imshow(np.transpose(img, (1, 2, 0)))
title = classes[labels[i]]
ax.set_title(title)
def show_image(title, image, color = None):
image = image / 2 + 0.5 # unnormalize
plt.imshow(np.transpose(image, (1, 2, 0)))
plt.axis("off")
if color: plt.title(title, color=color)
else: plt.title(title)
@interact(index = (0, 50000))
def show_image_dataset(index):
img, label = train_data.__getitem__(index=index)
title = classes[label]
show_image(title, img)
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# convolutional layer (sees 32x32x3 image tensor)
self.conv1 = nn.Conv2d(3, 64, 5, padding=1)
# convolutional layer (sees 64x64x64 tensor)
self.conv2 = nn.Conv2d(64, 32, 5, padding=1)
# max pooling layer
self.pool = nn.MaxPool2d(2, 2)
# linear layer (72 * 4 * 4 -> 384)
self.fc1 = nn.Linear(72 * 4 * 4, 384)
# linear layer (384 -> 192)
self.fc2 = nn.Linear(384, 192)
# linear layer (192 -> 10)
self.fc3 = nn.Linear(192, 10)
# dropout layer (p=0.25)
self.dropout = nn.Dropout(0.25)
def forward(self, x):
# add sequence of convolutional and max pooling layers
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
# flatten image input
x = x.view(-1, 72 * 4 * 4)
x = self.dropout(x)
x = F.relu(self.fc1(x))
x = self.dropout(x)
x = F.relu(self.fc2(x))
x = self.dropout(x)
x = F.relu(self.fc3(x))
return x
def evaluate(self, x):
output = self(x)
_, pred = torch.max(output, 1)
return pred
model = Net()
if train_on_gpu: model.cuda()
print(model)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.015)
n_epochs = 20
valid_loss_min = np.Inf
for epoch in range(1, n_epochs + 1):
train_loss, valid_loss = 0.0, 0.0
# train the model
model.train()
for data, target in train_loader:
if train_on_gpu: data, target = data.cuda(), target.cuda()
optimizer.zero_grad()
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
train_loss += loss.item() * data.size(0)
# validate the model
model.eval()
for data, target in valid_loader:
if train_on_gpu: data, target = data.cuda(), target.cuda()
output = model(data)
loss = criterion(output, target)
valid_loss += loss.item() * data.size(0)
train_loss = train_loss / len(train_loader.sampler)
valid_loss = valid_loss / len(valid_loader.sampler)
print(f'Epoch: {epoch} \t', end="")
print(f'Training Loss: {np.round(train_loss, 6)} \t', end="")
print(f'Validation Loss: {np.round(valid_loss, 6)}')
# save model if validation loss has decreased
if valid_loss <= valid_loss_min:
before, after = np.round(valid_loss_min, 6), np.round(valid_loss, 6)
print(f'Validation loss min: ({before} --> {after}). Saving model')
torch.save(model.state_dict(), 'best_model_cifar.pt')
valid_loss_min = valid_loss
print()
model.load_state_dict(torch.load('best_model_cifar.pt'))
def test_model(mode_name, mode_loader):
mode_loss = 0.0
class_correct = [0. for i in range(10)]
class_total = [0. for i in range(10)]
matrix_confusion_test = np.zeros((10, 10), dtype=int)
model.eval()
for data, target in mode_loader:
if train_on_gpu: data, target = data.cuda(), target.cuda()
output = model(data)
loss = criterion(output, target)
mode_loss += loss.item() * data.size(0)
# convert output probabilities to predicted class
_, pred = torch.max(output, 1)
# compare predictions to true label
targets_vals = target.data.view_as(pred)
correct_tensor = pred.eq(targets_vals)
correct = correct_tensor.numpy() if not train_on_gpu else correct_tensor.cpu().numpy()
correct = np.squeeze(correct)
# calculate test accuracy for each object class
for i in range(batch_size):
label = target.data[i]
prediction = pred[i]
class_correct[label] += correct[i].item()
class_total[label] += 1
matrix_confusion_test[label][prediction] += 1
# average test loss
mode_loss = mode_loss/len(test_loader.dataset)
print(f'Test Loss: {np.round(mode_loss, 6)}')
for i, class_name in enumerate(classes):
if class_total[i] > 0:
percentage = int(100 * class_correct[i] / class_total[i])
correct, total = int(np.sum(class_correct[i])), int(np.sum(class_total[i]))
print(f'{mode_name} Accuracy of {class_name}: {percentage}% ({correct}/{total})')
else:
print(f'{mode_name} Accuracy of {class_name}: \t N/A (no training examples)')
percentage = int(100. * np.sum(class_correct) / np.sum(class_total))
correct, total = int(np.sum(class_correct)), int(np.sum(class_total))
print(f'\n{mode_name} Accuracy (Overall): {percentage}% ({correct}/{total})\n\n')
print("Confusion Matrix")
print(matrix_confusion_test)
sns.set()
ax = sns.heatmap(matrix_confusion_test)
test_model("Test", test_loader)
test_model("Train", train_loader)
dataiter = iter(test_loader)
images, labels = dataiter.next()
images.numpy()
if train_on_gpu: images = images.cuda()
output = model(images)
_, preds_tensor = torch.max(output, 1)
preds = preds_tensor.numpy() if not train_on_gpu else preds_tensor.cpu().numpy()
preds = np.squeeze(preds)
# plot the images in the batch, with predicted and true labels
fig = plt.figure(figsize=(30, 4))
rows = 2
for i in np.arange(batch_size):
ax = fig.add_subplot(rows, batch_size/rows, i+1, xticks=[], yticks=[])
img = images.cpu()[i] / 2 + 0.5 # unnormalize
plt.imshow(np.transpose(img, (1, 2, 0)))
color = ("green" if preds[i]==labels[i].item() else "red")
ax.set_title(f'p={classes[preds[i]]} t={classes[labels[i]]}', color=color)
@interact(index = (0, 10000))
def show_image_dataset(index):
raw_img, expected = test_data.__getitem__(index=index)
image_as_expected = raw_img[None].type('torch.cuda.FloatTensor')
prediction = model.evaluate(image_as_expected).tolist()[0]
color = ("green" if prediction == expected else "red")
title = f"prediction={classes[prediction]} expected={classes[expected]}"
show_image(title, raw_img, color)
def plot_filters_multi_channel(t):
#get the number of kernals
num_kernels = t.shape[0]
#define number of columns for subplots
num_cols = 12
#rows = num of kernels
num_rows = num_kernels
#set the figure size
fig = plt.figure(figsize=(num_cols,num_rows))
#looping through all the kernels
for i in range(t.shape[0]):
ax1 = fig.add_subplot(num_rows,num_cols,i+1)
#for each kernel, we convert the tensor to numpy
npimg = np.array(t[i].cpu().numpy(), np.float32)
#standardize the numpy image
npimg = (npimg - np.mean(npimg)) / np.std(npimg)
npimg = np.minimum(1, np.maximum(0, (npimg + 0.5)))
npimg = npimg.transpose((1, 2, 0))
ax1.imshow(npimg)
ax1.axis('off')
ax1.set_title(str(i))
ax1.set_xticklabels([])
ax1.set_yticklabels([])
plt.tight_layout()
plt.show()
def plot_weights(model, layer_num, single_channel = True):
#extracting the model features at the particular layer number
layer = list(model.modules())[layer_num]
#checking whether the layer is convolution layer or not
if isinstance(layer, nn.Conv2d) and layer.weight.data.shape[1] == 3:
plot_filters_multi_channel(layer.weight.data)
plot_weights(model, 1, single_channel = False)