Imports here
%matplotlib inline
%config InlineBackend.figure_format = ‘retina’
import matplotlib.pyplot as plt
import torch
import numpy as np
from torch import nn
from torch import optim
from torchvision import datasets, models, transforms
import torch.nn.functional as F
import torch.utils.data
import pandas as pd
#import helper
from collections import OrderedDict
from PIL import Image
import seaborn as sns
TODO: Define your transforms for the training, validation, and testing sets
train_data_transforms = transforms.Compose ([transforms.RandomRotation (30),
transforms.RandomResizedCrop (224),
transforms.RandomHorizontalFlip (),
transforms.ToTensor (),
transforms.Normalize ([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
])
valid_data_transforms = transforms.Compose ([transforms.Resize (255),
transforms.CenterCrop (224),
transforms.ToTensor (),
transforms.Normalize ([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
])
test_data_transforms = transforms.Compose ([transforms.Resize (255),
transforms.CenterCrop (224),
transforms.ToTensor (),
transforms.Normalize ([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
])
TODO: Load the datasets with ImageFolder
train_image_datasets = datasets.ImageFolder (train_dir, transform = train_data_transforms)
valid_image_datasets = datasets.ImageFolder (valid_dir, transform = valid_data_transforms)
test_image_datasets = datasets.ImageFolder (test_dir, transform = test_data_transforms)
TODO: Using the image datasets and the trainforms, define the dataloaders
train_loader = torch.utils.data.DataLoader(train_image_datasets, batch_size = 64, shuffle = True)
valid_loader = torch.utils.data.DataLoader(valid_image_datasets, batch_size = 64, shuffle = True)
test_loader = torch.utils.data.DataLoader(test_image_datasets, batch_size = 64, shuffle = True)
#Label mapping
#This will give you a dictionary mapping the integer encoded categories to the actual names of the flowers
import json
with open(‘cat_to_name.json’, ‘r’) as f:
cat_to_name = json.load(f)
cat_to_name
updating classifer in the network
for param in model.parameters():
param.requires_grad = False
classifier = nn.Sequential (OrderedDict ([
(‘fc1’, nn.Linear (9216, 4096)),
(‘relu1’, nn.ReLU ()),
(‘dropout1’, nn.Dropout (p = 0.4)),
(‘fc2’, nn.Linear (4096, 2048)),
(‘relu2’, nn.ReLU ()),
(‘dropout2’, nn.Dropout (p = 0.4)),
(‘fc3’, nn.Linear (2048, 102)),
(‘output’, nn.LogSoftmax (dim =1))
]))
model.classifier = classifier
model
--------------------#initializing criterion and optimizer
criterion = nn.NLLLoss ()
optimizer = optim.Adam (model.classifier.parameters (), lr = 0.001)
Defining validation for the model
def validation(model, valid_loader, criterion):
model.to (‘cuda’)
valid_loss = 0
accuracy = 0
for inputs, labels in valid_loader:
inputs, labels = inputs.to('cuda'), labels.to('cuda')
output = model.forward(inputs)
valid_loss += criterion(output, labels).item()
ps = torch.exp(output)
equality = (labels.data == ps.max(dim=1)[1])
accuracy += equality.type(torch.FloatTensor).mean()
return valid_loss, accuracy
#training a model
#change to cuda if enabled
model.to (‘cuda’)
epochs = 12
print_every = 40
steps = 0
for e in range (epochs):
running_loss = 0
for ii, (inputs, labels) in enumerate (train_loader):
steps += 1
inputs, labels = inputs.to('cuda'), labels.to('cuda')
optimizer.zero_grad () #where optimizer is working on classifier paramters only
# Forward and backward passes
outputs = model.forward (inputs) #calculating output
loss = criterion (outputs, labels) #calculating loss
loss.backward ()
optimizer.step () #performs single optimization step
running_loss += loss.item () # loss.item () returns scalar value of Loss function
if steps % print_every == 0:
model.eval () #switching to evaluation mode so that dropout is turned off
# Turn off gradients for validation, saves memory and computations
with torch.no_grad():
valid_loss, accuracy = validation(model, valid_loader, criterion)
print("Epoch: {}/{}.. ".format(e+1, epochs),
"Training Loss: {:.3f}.. ".format(running_loss/print_every),
"Valid Loss: {:.3f}.. ".format(valid_loss/len(valid_loader)),
"Valid Accuracy: {:.3f}%".format(accuracy/len(valid_loader)*100))
running_loss = 0
# Make sure training is back on
model.train()
------------------------------------------
def check_accuracy_on_test(test_loader):
right = 0
total = 0
#training a model
#change to cuda if enabled
model.to('cuda:0')
#switching to evaluation mode so that dropout is turned off
Turn off gradients for validation, saves memory and computations
with torch.no_grad():
for data in test_loader:
images, labels = data
images, labels = images.to('cuda'), labels.to('cuda')
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
right += (predicted == labels).sum().item()
print('kindly be informed that the accuracy of the network on the test images: %d %%' % (100 * right / total))
check_accuracy_on_test(test_loader)
model.to (‘cpu’) #no need to use cuda for saving/loading model.
TODO: Save the checkpoint
model.class_to_idx = train_image_datasets.class_to_idx #saving mapping between predicted class and class name,
#second variable is a class name in numeric
#creating dictionary
checkpoint = {‘classifier’: model.classifier,
‘state_dict’: model.state_dict (),
‘mapping’: model.class_to_idx
}
torch.save (checkpoint, ‘project_checkpoint.pth’)
#you should also store other hyper-parameters like the number of epochs, the learning_rate, arch param
#along with the checkpoint. This parameters are required in case you need to continue training your model
TODO: Write a function that loads a checkpoint and rebuilds the model
def loading_model (file_path):
checkpoint = torch.load (file_path) #loading checkpoint from a file
model = models.alexnet (pretrained = True) #function works solely for Alexnet
#you can use the arch from the checkpoint and choose the model architecture in a more generic way:
#model = getattr(models, checkpoint[‘arch’]
model.classifier = checkpoint ['classifier']
model.load_state_dict (checkpoint ['state_dict'])
model.class_to_idx = checkpoint ['mapping']
for param in model.parameters():
param.requires_grad = False #turning off tuning of the model
return model
print (model)
def process_image(image):
‘’’ Scales, crops, and normalizes a PIL image for a PyTorch model,
returns an Numpy array
‘’’
#size = 256, 256
img = Image.open (image) #loading image
Image_width, Image_height = img.size #original size
#proportion = Image_width/ float (Image_height) #to keep aspect ratio
if Image_width > Image_height:
Image_height = 256
img.thumbnail ((50000, Image_height), Image.ANTIALIAS)
else:
Image_width = 256
img.thumbnail ((Image_width,50000), Image.ANTIALIAS)
Image_width, Image_height = img.size
#new size of img
#resize 224x224 in the center
img_reduce = 224
img_left = (Image_width - img_reduce)/2
img_top = (Image_height - img_reduce)/2
img_right = img_left + 224
img_bottom = img_top + 224
img = img.crop ((img_left, img_top, img_right, img_bottom))
#preparing numpy array
np_image = np.array (img)/255
np_image -= np.array ([0.485, 0.456, 0.406])
np_image /= np.array ([0.229, 0.224, 0.225])
np_image= np_image.transpose ((2,0,1))
return np_image
img_1 = (data_dir +'/test' + '/1/' + 'image_06743.jpg')
img_1 = process_image(img_1)
print(img_1.shape)
(np.array([0.229, 0.224, 0.225])).shape
img_1 = img_1.transpose ((1,2,0))
img_1
def imshow(image, ax=None, title=None):
“”“Imshow for Tensor.”“”
if ax is None:
fig, ax = plt.subplots()
# PyTorch tensors assume the color channel is the first dimension
# but matplotlib assumes is the third dimension
image = np.array(image)
image = image.transpose((1, 2, 0))
# Undo preprocessing
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean
# Image needs to be clipped between 0 and 1 or it looks like noise when displayed
image = np.clip(image, 0, 1)
ax.imshow(image)
return ax
image_path = ‘flowers/train/13/image_05744.jpg’
img = process_image(image_path)
#img.shape
imshow(img)
#mapping = train_image_datasets.class_to_idx
#indeces = np.array ([1, 10, 100, 101, 102])
#classes = pd.DataFrame ([mapping [item] for item in indeces]) #replacing indeces with classes
#classes = np.array (classes) #converting to Numpy array
def predict(image_path, model, topk = 5):
‘’’ Predict the class (or classes) of an image using a trained deep learning model.
'''
print (type(model))
# TODO: Implement the code to predict the class from an image file
image = process_image (image_path) #loading image and processing it using above defined function
#we cannot pass image to model.forward 'as is' as it is expecting tensor, not numpy array
#converting to tensor
img = torch.from_numpy (image).type(torch.FloatTensor)
img = img.unsqueeze (dim = 0) #used to make size of torch as expected. as forward method is working with batches,
#doing that we will have batch size = 1
with torch.no_grad ():
output = model.forward (img)
output_prob = torch.exp (output) #converting into a probability
probs, indeces = output_prob.topk (topk=5)
probs = probs.numpy () #converting both to numpy array
indeces = indeces.numpy ()
probs = probs.tolist () [0] #converting both to list
indeces = indeces.tolist () [0]
mapping = {val: key for key, val in
model.class_to_idx.items()
}
classes = [mapping [item] for item in indeces]
#classes = pd.DataFrame ([mapping [item] for item in indeces]) #replacing indeces with classes
classes = np.array (classes) #converting to Numpy array
return probs, classes
TODO: Display an image along with the top 5 classes
#using the restored one
model=loading_model(‘project_checkpoint.pth’)
file_path = ‘flowers/test/11/image_03130.jpg’
img = process_image (file_path)
imshow (img)
plt.show()
probs, classes = predict(file_path, model, 5)
#probs = probs.numpy ()
#indeces = indeces.numpy ()
#print (probs)
#print (classes)
class ‘torchvision.models.alexnet.AlexNet’>
TypeError Traceback (most recent call last)
in ()
10 imshow (img)
11 plt.show()
—> 12 probs, classes = predict(file_path, model, 5)
13 #probs = probs.numpy ()
14 #indeces = indeces.numpy ()
in predict(image_path, model, topk)
24 output_prob = torch.exp (output) #converting into a probability
25
—> 26 probs, indeces = output_prob.topk (topk=5)
27 probs = probs.numpy () #converting both to numpy array
28 indeces = indeces.numpy ()
TypeError: topk() missing 1 required positional arguments: “k”
#preparing class_names using mapping with cat_to_name
class_names = [cat_to_name [item] for item in classes]
#fig, (ax2) = plt.subplots(figsize=(6,9), ncols=2)
plt.figure(figsize = (6,10))
plt.subplot(2,1,2)
sns.barplot(x=probs, y=class_names, color= ‘red’);
plt.show()