Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
1 result

Target

Select target project
  • mcollas/mod-4-6-td-2-collas
  • mkhatib/mod_4_6-td2
  • adorson/mod_4_6-td2_Dorson
  • mguiller/mod_4_6-td2
  • mbabay/td-2-deep-learning
  • mtalec/mod_4_6-td2
  • dtibi/mod_4_6-td2
  • bbrudysa/mod_4_6-td2
  • tpoirier/mod_4_6-td2
  • tdesgreys/mod_4_6-td2
  • flegrand/td-2-deep-learning
  • mduhalde/mod_4_6-td2
  • lpoirson/mod_4_6-td2
  • pguerinc/mod_4_6-td2
  • asennevi/mod-4-6-td-2-as
  • mkosksi/deep-learning-td-2
  • tfassin/deep-learning
  • ykarouma/mod-4-6-td-2-karouma
  • pmarin/mod_4_6-td2
  • ggeiger/mod_4_6-td2
  • barryt/mod_4_6-td2
  • melbadao/mod_4_6-td2
  • svincent/mod-4-6-td-2-vincent-simon
  • ndelorme/mod-4-6-td-2-antonin-delorme
  • selalimi/mod_4_6-td2
  • edelland/mod_4_6-td2
  • pishida/mod_4_6-td2
  • amilford/mod_4_6-td2
  • laudard/mod_4_6-td2
  • moudet/mod_4_6-td2
  • jseksik/IA-td2
  • fhu/mod_4_6-td2
  • nlascoux/deep_learning
  • harteaga/mod_4_6-td2
  • bdeneuve/mod_4_6-td2
  • pdanjou/mod_4_6-td2
  • ochaufou/mod_4_6-td2
  • cmassala/mod_4_6-td2
  • ttraore/mod_4_6-td2
  • ykessi/mod-4-6-td-2
  • zzhengfe/mod-4-6-td-2-zhang
  • cgirard/mod_4_6-td2
  • cdurget/mod_4_6-td2
  • ebisson/mod_4_6-td2
  • nterbech/mod_4_6-td2
  • jcaty/mod_4_6-td2
  • afaytout/be-2-deep-learning
  • pramage/deep-learning
  • delkhadr/mod_4_6-td2
  • agiard/mod_4_6-td2
  • rrousse/mod-4-6-td-2-romain-rousse
  • sbessac/mod_4_6-td2
  • vkadkhod/mod_4_6-td2
  • mcart/mod_4_6-td2
  • gbeauvy/mod_4_6-td2
  • amaassen/mod_4_6-td2-fork
  • cgerest/mod-4-6-td-2-cgerest
  • rgirard/mod_4_6-td2
  • clemencm/mod_4_6-td2
  • hbettaie/deep-learning-td-2
  • bdarne/mod_4_6-td2
  • epaganel/mod_4_6-td2
  • mbenyahi/td-2-deep-learning
  • bosioa/mod-4-6-td-2-bosio
  • jmansion/mod-4-6-td-2
  • zkabbaj/mod_4_6-td2
  • tdenis/mod_4_6-td2
  • vludvig/mod_4_6-td2
68 results
Select Git revision
  • main
1 result
Show changes
Commits on Source (5)
%% Cell type:markdown id:7edf7168 tags:
# TD2: Deep learning
%% Cell type:markdown id:fbb8c8df tags:
In this TD, you must modify this notebook to answer the questions. To do this,
1. Fork this repository
2. Clone your forked repository on your local computer
3. Answer the questions
4. Commit and push regularly
The last commit is due on Wednesday, December 4, 11:59 PM. Later commits will not be taken into account.
%% Cell type:markdown id:3d167a29 tags:
Install and test PyTorch from https://pytorch.org/get-started/locally.
%% Cell type:code id:330a42f5 tags:
``` python
%pip install torch torchvision
```
%% Output
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: torch in /opt/conda/envs/pytorch/lib/python3.8/site-packages (1.7.0)
Requirement already satisfied: torchvision in /opt/conda/envs/pytorch/lib/python3.8/site-packages (0.8.1)
Requirement already satisfied: future in /home/jcaty/.local/lib/python3.8/site-packages (from torch) (1.0.0)
Requirement already satisfied: typing_extensions in /opt/conda/envs/pytorch/lib/python3.8/site-packages (from torch) (3.7.4.3)
Requirement already satisfied: dataclasses in /home/jcaty/.local/lib/python3.8/site-packages (from torch) (0.6)
Requirement already satisfied: numpy in /opt/conda/envs/pytorch/lib/python3.8/site-packages (from torch) (1.19.2)
Requirement already satisfied: numpy in /opt/conda/envs/pytorch/lib/python3.8/site-packages (from torch) (1.19.2)
Requirement already satisfied: torch in /opt/conda/envs/pytorch/lib/python3.8/site-packages (1.7.0)
Requirement already satisfied: pillow>=4.1.1 in /opt/conda/envs/pytorch/lib/python3.8/site-packages (from torchvision) (8.0.1)
Note: you may need to restart the kernel to use updated packages.
%% Cell type:markdown id:0882a636 tags:
To test run the following code
%% Cell type:code id:b1950f0a tags:
``` python
import torch
N, D = 14, 10
x = torch.randn(N, D).type(torch.FloatTensor)
print(x)
from torchvision import models
alexnet = models.alexnet()
print(alexnet)
```
%% Output
tensor([[-0.5495, 0.3131, 0.3228, 1.3840, 0.1736, -0.5699, -0.5469, -0.1029,
0.4430, -0.1313],
[ 1.6023, -0.0431, 0.1905, -1.2841, -0.6138, 1.2643, -2.4099, -1.4513,
0.6383, -0.2009],
[-0.8383, -0.6552, 1.0406, -1.5920, 0.4239, 0.4551, -0.2714, 0.5442,
-1.3059, -2.6276],
[-0.3160, 1.8964, -0.2690, -0.8876, 0.7519, -0.9116, -0.5473, -0.3028,
-0.3744, 0.6574],
[-0.6114, 0.4902, -0.4574, -0.7184, -1.7202, 0.1125, 0.7156, 2.1900,
0.2498, -0.7416],
[-1.2556, -1.1005, 0.5423, -0.4725, -0.1278, -1.4557, -0.3942, 0.4152,
-0.4224, -0.2448],
[-1.1054, -1.8207, -0.6234, 1.0362, -0.7470, -1.2543, -0.1024, -3.1436,
0.5020, 0.1043],
[-0.4296, 0.7543, -1.0903, 0.5653, 0.5865, -0.1357, 1.0432, -2.1515,
0.9859, 0.1869],
[ 1.2781, -0.0249, -2.4766, -0.6888, 2.4392, -0.3861, 1.1405, -0.3728,
-0.3757, 0.5114],
[-1.3493, 0.4288, 0.1204, -0.5416, -0.6372, 0.0356, 1.5299, 3.0577,
-0.0736, -0.6135],
[ 0.3671, -0.6893, -1.8283, 0.0539, -1.1218, 0.6083, 1.0533, -1.0715,
0.9260, 0.2665],
[ 0.3744, 0.5221, -0.5731, -1.8915, -1.7480, -1.1056, -0.9834, -2.1452,
0.2002, -0.1863],
[ 0.4086, -0.0441, 1.4076, 0.3931, -0.2699, 0.1125, -0.2010, 0.5686,
1.4326, 0.6409],
[-0.3705, 0.4681, -0.8285, -2.4345, -0.8233, 1.6192, 1.0805, -1.1024,
-0.8309, -0.8049]])
AlexNet(
(features): Sequential(
(0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))
(1): ReLU(inplace=True)
(2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
(3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(4): ReLU(inplace=True)
(5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
(6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(7): ReLU(inplace=True)
(8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(9): ReLU(inplace=True)
(10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): ReLU(inplace=True)
(12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(avgpool): AdaptiveAvgPool2d(output_size=(6, 6))
(classifier): Sequential(
(0): Dropout(p=0.5, inplace=False)
(1): Linear(in_features=9216, out_features=4096, bias=True)
(2): ReLU(inplace=True)
(3): Dropout(p=0.5, inplace=False)
(4): Linear(in_features=4096, out_features=4096, bias=True)
(5): ReLU(inplace=True)
(6): Linear(in_features=4096, out_features=1000, bias=True)
)
)
%% Cell type:markdown id:23f266da tags:
## Exercise 1: CNN on CIFAR10
The goal is to apply a Convolutional Neural Net (CNN) model on the CIFAR10 image dataset and test the accuracy of the model on the basis of image classification. Compare the Accuracy VS the neural network implemented during TD1.
Have a look at the following documentation to be familiar with PyTorch.
https://pytorch.org/tutorials/beginner/pytorch_with_examples.html
https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html
%% Cell type:markdown id:4ba1c82d tags:
You can test if GPU is available on your machine and thus train on it to speed up the process
%% Cell type:code id:6e18f2fd tags:
``` python
import torch
# check if CUDA is available
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print("CUDA is not available. Training on CPU ...")
else:
print("CUDA is available! Training on GPU ...")
```
%% Output
CUDA is available! Training on GPU ...
%% Cell type:markdown id:5cf214eb tags:
Next we load the CIFAR10 dataset
%% Cell type:code id:462666a2 tags:
``` python
import numpy as np
from torchvision import datasets, transforms
from torch.utils.data.sampler import SubsetRandomSampler
# number of subprocesses to use for data loading
num_workers = 0
# how many samples per batch to load
batch_size = 20
# percentage of training set to use as validation
valid_size = 0.2
# 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 = datasets.CIFAR10("data", train=True, download=True, transform=transform)
test_data = datasets.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)
split = int(np.floor(valid_size * num_train))
train_idx, valid_idx = indices[split:], indices[:split]
# define samplers for obtaining training and validation batches
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=num_workers
)
valid_loader = torch.utils.data.DataLoader(
train_data, batch_size=batch_size, sampler=valid_sampler, num_workers=num_workers
)
test_loader = torch.utils.data.DataLoader(
test_data, batch_size=batch_size, num_workers=num_workers
)
# specify the image classes
classes = [
"airplane",
"automobile",
"bird",
"cat",
"deer",
"dog",
"frog",
"horse",
"ship",
"truck",
]
```
%% Output
Files already downloaded and verified
Files already downloaded and verified
%% Cell type:markdown id:58ec3903 tags:
CNN definition (this one is an example)
%% Cell type:code id:317bf070 tags:
``` python
import torch.nn as nn
import torch.nn.functional as F
# define the CNN architecture
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# create a complete CNN
model = Net()
print(model)
# move tensors to GPU if CUDA is available
if train_on_gpu:
model.cuda()
```
%% Output
Net(
(conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear(in_features=400, out_features=120, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)
%% Cell type:markdown id:a2dc4974 tags:
Loss function and training using SGD (Stochastic Gradient Descent) optimizer
%% Cell type:code id:4b53f229 tags:
``` python
import torch.optim as optim
criterion = nn.CrossEntropyLoss() # specify loss function
optimizer = optim.SGD(model.parameters(), lr=0.01) # specify optimizer
n_epochs = 30 # number of epochs to train the model
train_loss_list = [] # list to store loss to visualize
valid_loss_min = np.Inf # track change in validation loss
for epoch in range(n_epochs):
# Keep track of training and validation loss
train_loss = 0.0
valid_loss = 0.0
# Train the model
model.train()
for data, target in train_loader:
# Move tensors to GPU if CUDA is available
if train_on_gpu:
data, target = data.cuda(), target.cuda()
# Clear the gradients of all optimized variables
optimizer.zero_grad()
# Forward pass: compute predicted outputs by passing inputs to the model
output = model(data)
# Calculate the batch loss
loss = criterion(output, target)
# Backward pass: compute gradient of the loss with respect to model parameters
loss.backward()
# Perform a single optimization step (parameter update)
optimizer.step()
# Update training loss
train_loss += loss.item() * data.size(0)
# Validate the model
model.eval()
for data, target in valid_loader:
# Move tensors to GPU if CUDA is available
if train_on_gpu:
data, target = data.cuda(), target.cuda()
# Forward pass: compute predicted outputs by passing inputs to the model
output = model(data)
# Calculate the batch loss
loss = criterion(output, target)
# Update average validation loss
valid_loss += loss.item() * data.size(0)
# Calculate average losses
train_loss = train_loss / len(train_loader)
valid_loss = valid_loss / len(valid_loader)
train_loss_list.append(train_loss)
# Print training/validation statistics
print(
"Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}".format(
epoch, train_loss, valid_loss
)
)
# Save model if validation loss has decreased
if valid_loss <= valid_loss_min:
print(
"Validation loss decreased ({:.6f} --> {:.6f}). Saving model ...".format(
valid_loss_min, valid_loss
)
)
torch.save(model.state_dict(), "model_cifar.pt")
valid_loss_min = valid_loss
```
%% Output
Epoch: 0 Training Loss: 43.364632 Validation Loss: 38.230504
Validation loss decreased (inf --> 38.230504). Saving model ...
Epoch: 1 Training Loss: 34.865927 Validation Loss: 33.684661
Validation loss decreased (38.230504 --> 33.684661). Saving model ...
Epoch: 2 Training Loss: 30.692502 Validation Loss: 29.130355
Validation loss decreased (33.684661 --> 29.130355). Saving model ...
Epoch: 3 Training Loss: 28.641049 Validation Loss: 28.378742
Validation loss decreased (29.130355 --> 28.378742). Saving model ...
Epoch: 4 Training Loss: 27.138877 Validation Loss: 26.230459
Validation loss decreased (28.378742 --> 26.230459). Saving model ...
Epoch: 5 Training Loss: 25.893545 Validation Loss: 25.292490
Validation loss decreased (26.230459 --> 25.292490). Saving model ...
Epoch: 6 Training Loss: 24.842854 Validation Loss: 24.485009
Validation loss decreased (25.292490 --> 24.485009). Saving model ...
Epoch: 7 Training Loss: 23.926138 Validation Loss: 24.722069
Epoch: 8 Training Loss: 23.031194 Validation Loss: 23.820090
Validation loss decreased (24.485009 --> 23.820090). Saving model ...
Epoch: 9 Training Loss: 22.231426 Validation Loss: 22.906112
Validation loss decreased (23.820090 --> 22.906112). Saving model ...
Epoch: 10 Training Loss: 21.461538 Validation Loss: 22.387376
Validation loss decreased (22.906112 --> 22.387376). Saving model ...
Epoch: 11 Training Loss: 20.719964 Validation Loss: 21.980570
Validation loss decreased (22.387376 --> 21.980570). Saving model ...
Epoch: 12 Training Loss: 20.001674 Validation Loss: 21.879977
Validation loss decreased (21.980570 --> 21.879977). Saving model ...
Epoch: 13 Training Loss: 19.320499 Validation Loss: 21.871980
Validation loss decreased (21.879977 --> 21.871980). Saving model ...
Epoch: 14 Training Loss: 18.759199 Validation Loss: 21.631741
Validation loss decreased (21.871980 --> 21.631741). Saving model ...
Epoch: 15 Training Loss: 18.190729 Validation Loss: 21.728372
Epoch: 16 Training Loss: 17.555403 Validation Loss: 21.431064
Validation loss decreased (21.631741 --> 21.431064). Saving model ...
Epoch: 17 Training Loss: 17.052087 Validation Loss: 21.122314
Validation loss decreased (21.431064 --> 21.122314). Saving model ...
Epoch: 18 Training Loss: 16.523702 Validation Loss: 21.020531
Validation loss decreased (21.122314 --> 21.020531). Saving model ...
Epoch: 19 Training Loss: 15.990338 Validation Loss: 21.419434
Epoch: 20 Training Loss: 15.540147 Validation Loss: 22.715216
Epoch: 21 Training Loss: 15.053955 Validation Loss: 21.344116
Epoch: 22 Training Loss: 14.620870 Validation Loss: 21.724516
Epoch: 23 Training Loss: 14.099778 Validation Loss: 23.172254
Epoch: 24 Training Loss: 13.740382 Validation Loss: 22.565675
Epoch: 25 Training Loss: 13.261968 Validation Loss: 23.687115
Epoch: 26 Training Loss: 12.842589 Validation Loss: 23.510745
Epoch: 27 Training Loss: 12.429801 Validation Loss: 22.843567
Epoch: 28 Training Loss: 12.002632 Validation Loss: 24.907918
Epoch: 29 Training Loss: 11.709404 Validation Loss: 25.430181
%% Cell type:markdown id:13e1df74 tags:
Does overfit occur? If so, do an early stopping.
%% Cell type:code id:d39df818 tags:
``` python
import matplotlib.pyplot as plt
plt.plot(range(n_epochs), train_loss_list)
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.title("Performance of Model 1")
plt.show()
```
%% Output
%% Cell type:markdown id:11df8fd4 tags:
Now loading the model with the lowest validation loss value
%% Cell type:code id:e93efdfc tags:
``` python
model.load_state_dict(torch.load("./model_cifar.pt"))
# track test loss
test_loss = 0.0
class_correct = list(0.0 for i in range(10))
class_total = list(0.0 for i in range(10))
model.eval()
# iterate over test data
for data, target in test_loader:
# move tensors to GPU if CUDA is available
if train_on_gpu:
data, target = data.cuda(), target.cuda()
# forward pass: compute predicted outputs by passing inputs to the model
output = model(data)
# calculate the batch loss
loss = criterion(output, target)
# update test loss
test_loss += loss.item() * data.size(0)
# convert output probabilities to predicted class
_, pred = torch.max(output, 1)
# compare predictions to true label
correct_tensor = pred.eq(target.data.view_as(pred))
correct = (
np.squeeze(correct_tensor.numpy())
if not train_on_gpu
else np.squeeze(correct_tensor.cpu().numpy())
)
# calculate test accuracy for each object class
for i in range(batch_size):
label = target.data[i]
class_correct[label] += correct[i].item()
class_total[label] += 1
# average test loss
test_loss = test_loss / len(test_loader)
print("Test Loss: {:.6f}\n".format(test_loss))
for i in range(10):
if class_total[i] > 0:
print(
"Test Accuracy of %5s: %2d%% (%2d/%2d)"
% (
classes[i],
100 * class_correct[i] / class_total[i],
np.sum(class_correct[i]),
np.sum(class_total[i]),
)
)
else:
print("Test Accuracy of %5s: N/A (no training examples)" % (classes[i]))
print(
"\nTest Accuracy (Overall): %2d%% (%2d/%2d)"
% (
100.0 * np.sum(class_correct) / np.sum(class_total),
np.sum(class_correct),
np.sum(class_total),
)
)
```
%% Output
Test Loss: 21.750090
Test Accuracy of airplane: 68% (685/1000)
Test Accuracy of automobile: 75% (752/1000)
Test Accuracy of bird: 51% (512/1000)
Test Accuracy of cat: 37% (374/1000)
Test Accuracy of deer: 61% (615/1000)
Test Accuracy of dog: 57% (570/1000)
Test Accuracy of frog: 68% (688/1000)
Test Accuracy of horse: 64% (646/1000)
Test Accuracy of ship: 73% (736/1000)
Test Accuracy of truck: 73% (739/1000)
Test Accuracy (Overall): 63% (6317/10000)
%% Cell type:markdown id:944991a2 tags:
Build a new network with the following structure.
- It has 3 convolutional layers of kernel size 3 and padding of 1.
- The first convolutional layer must output 16 channels, the second 32 and the third 64.
- At each convolutional layer output, we apply a ReLU activation then a MaxPool with kernel size of 2.
- Then, three fully connected layers, the first two being followed by a ReLU activation and a dropout whose value you will suggest.
- The first fully connected layer will have an output size of 512.
- The second fully connected layer will have an output size of 64.
Compare the results obtained with this new network to those obtained previously.
%% Cell type:code id: tags:
``` python
import torch.nn as nn
import torch.nn.functional as F
class CustomCNN(nn.Module):
def __init__(self, dropout_rate=0.3): # Suggested dropout rate
super(CustomCNN, self).__init__()
# Convolutional layers
self.conv1 = nn.Conv2d(3, 16, 3, 1)
self.conv2 = nn.Conv2d(16, 32, 3, 1)
self.conv3 = nn.Conv2d(32, 64, 3, 1)
# Fully connected layers
self.fc1 = nn.Linear(64 * 2 * 2, 512) # Corrigé en fonction de la forme réelle
# Adjust input size based on input dimensions after pooling
self.fc2 = nn.Linear(512, 64)
self.fc3 = nn.Linear(64, 10) # Assume 10 output classes
# Dropout
self.dropout = nn.Dropout(p=dropout_rate)
# Pooling
self.pool = nn.MaxPool2d(kernel_size=2)
def forward(self, x):
# Convolutional layers with ReLU and pooling
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = self.pool(F.relu(self.conv3(x)))
# Flatten for fully connected layers
x = x.view(x.size(0), -1) # Flatten the tensor
# Fully connected layers with dropout and ReLU
x = self.dropout(F.relu(self.fc1(x)))
x = self.dropout(F.relu(self.fc2(x)))
x = self.fc3(x)
return x
# create a complete CNN
model2 = CustomCNN()
print(model2)
# move tensors to GPU if CUDA is available
if train_on_gpu:
model2.cuda()
```
%% Output
CustomCNN(
(conv1): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1))
(conv2): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1))
(conv3): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1))
(fc1): Linear(in_features=256, out_features=512, bias=True)
(fc2): Linear(in_features=512, out_features=64, bias=True)
(fc3): Linear(in_features=64, out_features=10, bias=True)
(dropout): Dropout(p=0.3, inplace=False)
(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
%% Cell type:code id: tags:
``` python
print(f"Data type: {data.type()}")
print(f"Target type: {target.type()}")
print(f"Model weight type: {next(model2.parameters()).type()}")
```
%% Output
Data type: torch.cuda.FloatTensor
Target type: torch.cuda.LongTensor
Model weight type: torch.cuda.FloatTensor
%% Cell type:code id: tags:
``` python
import torch.optim as optim
criterion = nn.CrossEntropyLoss() # specify loss function
optimizer = optim.SGD(model2.parameters(), lr=0.01) # specify optimizer
n_epochs = 30 # number of epochs to train the model
train_loss_list2 = [] # list to store loss to visualize
valid_loss_min2 = np.Inf # track change in validation loss
for epoch in range(n_epochs):
# Keep track of training and validation loss
train_loss2 = 0.0
valid_loss2 = 0.0
# Train the model
model2.train()
for data, target in train_loader:
# Move tensors to GPU if CUDA is available
if train_on_gpu:
data, target = data.cuda(), target.cuda()
# Clear the gradients of all optimized variables
optimizer.zero_grad()
# Forward pass: compute predicted outputs by passing inputs to the model
output2 = model2(data)
# Calculate the batch loss
loss2 = criterion(output2, target)
# Backward pass: compute gradient of the loss with respect to model parameters
loss2.backward()
# Perform a single optimization step (parameter update)
optimizer.step()
# Update training loss
train_loss2 += loss2.item() * data.size(0)
# Validate the model
model2.eval()
with torch.no_grad():
for data, target in valid_loader:
if train_on_gpu:
data, target = data.cuda(), target.cuda()
else:
data, target = data.cpu(), target.cpu()
output2 = model2(data)
loss2 = criterion(output2, target)
valid_loss2 += loss2.item() * data.size(0)
# Calculate average losses
train_loss2 = train_loss2 / len(train_loader)
valid_loss2 = valid_loss2 / len(valid_loader)
train_loss_list2.append(train_loss2)
# Print training/validation statistics
print(
"Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}".format(
epoch, train_loss2, valid_loss2
)
)
# Save model if validation loss has decreased
if valid_loss2 <= valid_loss_min2:
print(
"Validation loss decreased ({:.6f} --> {:.6f}). Saving model ...".format(
valid_loss_min2, valid_loss2
)
)
torch.save(model2.state_dict(), "model_cifar2.pt")
valid_loss_min2 = valid_loss2
```
%% Output
Epoch: 0 Training Loss: 46.035675 Validation Loss: 45.975821
Validation loss decreased (inf --> 45.975821). Saving model ...
Epoch: 1 Training Loss: 44.774520 Validation Loss: 39.919449
Validation loss decreased (45.975821 --> 39.919449). Saving model ...
Epoch: 2 Training Loss: 37.829997 Validation Loss: 34.754118
Validation loss decreased (39.919449 --> 34.754118). Saving model ...
Epoch: 3 Training Loss: 34.342419 Validation Loss: 31.707682
Validation loss decreased (34.754118 --> 31.707682). Saving model ...
Epoch: 4 Training Loss: 31.886869 Validation Loss: 29.301074
Validation loss decreased (31.707682 --> 29.301074). Saving model ...
Epoch: 5 Training Loss: 29.959563 Validation Loss: 27.393316
Validation loss decreased (29.301074 --> 27.393316). Saving model ...
Epoch: 6 Training Loss: 28.335243 Validation Loss: 26.011092
Validation loss decreased (27.393316 --> 26.011092). Saving model ...
Epoch: 7 Training Loss: 26.877296 Validation Loss: 25.462102
Validation loss decreased (26.011092 --> 25.462102). Saving model ...
Epoch: 8 Training Loss: 25.688337 Validation Loss: 23.929076
Validation loss decreased (25.462102 --> 23.929076). Saving model ...
Epoch: 9 Training Loss: 24.511723 Validation Loss: 23.005517
Validation loss decreased (23.929076 --> 23.005517). Saving model ...
Epoch: 10 Training Loss: 23.442500 Validation Loss: 21.846585
Validation loss decreased (23.005517 --> 21.846585). Saving model ...
Epoch: 11 Training Loss: 22.508246 Validation Loss: 21.496349
Validation loss decreased (21.846585 --> 21.496349). Saving model ...
Epoch: 12 Training Loss: 21.597253 Validation Loss: 20.689961
Validation loss decreased (21.496349 --> 20.689961). Saving model ...
Epoch: 13 Training Loss: 20.734205 Validation Loss: 20.371868
Validation loss decreased (20.689961 --> 20.371868). Saving model ...
Epoch: 14 Training Loss: 19.955687 Validation Loss: 19.954705
Validation loss decreased (20.371868 --> 19.954705). Saving model ...
Epoch: 15 Training Loss: 19.160272 Validation Loss: 19.218016
Validation loss decreased (19.954705 --> 19.218016). Saving model ...
Epoch: 16 Training Loss: 18.510708 Validation Loss: 18.665482
Validation loss decreased (19.218016 --> 18.665482). Saving model ...
Epoch: 17 Training Loss: 17.827416 Validation Loss: 18.159658
Validation loss decreased (18.665482 --> 18.159658). Saving model ...
Epoch: 18 Training Loss: 17.263423 Validation Loss: 18.637613
Epoch: 19 Training Loss: 16.628417 Validation Loss: 18.351383
Epoch: 20 Training Loss: 16.099328 Validation Loss: 18.048815
Validation loss decreased (18.159658 --> 18.048815). Saving model ...
Epoch: 21 Training Loss: 15.631801 Validation Loss: 17.525234
Validation loss decreased (18.048815 --> 17.525234). Saving model ...
Epoch: 22 Training Loss: 15.120226 Validation Loss: 17.490126
Validation loss decreased (17.525234 --> 17.490126). Saving model ...
Epoch: 23 Training Loss: 14.537110 Validation Loss: 17.395222
Validation loss decreased (17.490126 --> 17.395222). Saving model ...
Epoch: 24 Training Loss: 14.215695 Validation Loss: 18.225738
Epoch: 25 Training Loss: 13.695718 Validation Loss: 17.967939
Epoch: 26 Training Loss: 13.258958 Validation Loss: 18.192724
Epoch: 27 Training Loss: 12.916577 Validation Loss: 17.067720
Validation loss decreased (17.395222 --> 17.067720). Saving model ...
Epoch: 28 Training Loss: 12.522411 Validation Loss: 16.906484
Validation loss decreased (17.067720 --> 16.906484). Saving model ...
Epoch: 29 Training Loss: 12.141524 Validation Loss: 17.213408
%% Cell type:code id: tags:
``` python
import matplotlib.pyplot as plt
plt.plot(range(n_epochs), train_loss_list2)
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.title("Performance of Model 2")
plt.show()
```
%% Output
%% Cell type:code id: tags:
``` python
model2.load_state_dict(torch.load("./model_cifar2.pt"))
# track test loss
test_loss2 = 0.0
class_correct2 = list(0.0 for i in range(10))
class_total2 = list(0.0 for i in range(10))
model2.eval()
# iterate over test data
for data, target in test_loader:
# move tensors to GPU if CUDA is available
if train_on_gpu:
data, target = data.cuda(), target.cuda()
# forward pass: compute predicted outputs by passing inputs to the model
output = model2(data)
# calculate the batch loss
loss2 = criterion(output, target)
# update test loss
test_loss2 += loss2.item() * data.size(0)
# convert output probabilities to predicted class
_, pred = torch.max(output, 1)
# compare predictions to true label
correct_tensor = pred.eq(target.data.view_as(pred))
correct = (
np.squeeze(correct_tensor.numpy())
if not train_on_gpu
else np.squeeze(correct_tensor.cpu().numpy())
)
# calculate test accuracy for each object class
for i in range(batch_size):
label = target.data[i]
class_correct2[label] += correct[i].item()
class_total2[label] += 1
# average test loss
test_loss2 = test_loss2 / len(test_loader)
print("Test Loss: {:.6f}\n".format(test_loss2))
for i in range(10):
if class_total2[i] > 0:
print(
"Test Accuracy of %5s: %2d%% (%2d/%2d)"
% (
classes[i],
100 * class_correct2[i] / class_total2[i],
np.sum(class_correct2[i]),
np.sum(class_total2[i]),
)
)
else:
print("Test Accuracy of %5s: N/A (no training examples)" % (classes[i]))
print(
"\nTest Accuracy (Overall): %2d%% (%2d/%2d)"
% (
100.0 * np.sum(class_correct2) / np.sum(class_total2),
np.sum(class_correct2),
np.sum(class_total2),
)
)
```
%% Output
Test Loss: 17.564571
Test Accuracy of airplane: 77% (776/1000)
Test Accuracy of automobile: 79% (793/1000)
Test Accuracy of bird: 63% (639/1000)
Test Accuracy of cat: 50% (506/1000)
Test Accuracy of deer: 65% (655/1000)
Test Accuracy of dog: 53% (536/1000)
Test Accuracy of frog: 83% (835/1000)
Test Accuracy of horse: 70% (709/1000)
Test Accuracy of ship: 80% (801/1000)
Test Accuracy of truck: 84% (841/1000)
Test Accuracy (Overall): 70% (7091/10000)
%% Cell type:markdown id:bc381cf4 tags:
## Exercise 2: Quantization: try to compress the CNN to save space
Quantization doc is available from https://pytorch.org/docs/stable/quantization.html#torch.quantization.quantize_dynamic
The Exercise is to quantize post training the above CNN model. Compare the size reduction and the impact on the classification accuracy
The size of the model is simply the size of the file.
%% Cell type:code id:ef623c26 tags:
``` python
import os
def print_size_of_model(model, label=""):
torch.save(model.state_dict(), "temp.p")
size = os.path.getsize("temp.p")
print("model: ", label, " \t", "Size (KB):", size / 1e3)
os.remove("temp.p")
return size
print_size_of_model(model, "fp32")
```
%% Output
model: fp32 Size (KB): 251.529
251529
%% Cell type:markdown id:05c4e9ad tags:
Post training quantization example
%% Cell type:code id:c4c65d4b tags:
``` python
import torch.quantization
quantized_model = torch.quantization.quantize_dynamic(model, dtype=torch.qint8)
print_size_of_model(quantized_model, "int8")
```
%% Output
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-22-b8bd12179156> in <module>
2
3
----> 4 quantized_model = torch.quantization.quantize_dynamic(model, dtype=torch.qint8)
5 print_size_of_model(quantized_model, "int8")
/opt/conda/envs/pytorch/lib/python3.8/site-packages/torch/quantization/quantize.py in quantize_dynamic(model, qconfig_spec, dtype, mapping, inplace)
347 model.eval()
348 propagate_qconfig_(model, qconfig_spec)
--> 349 convert(model, mapping, inplace=True)
350 return model
351
/opt/conda/envs/pytorch/lib/python3.8/site-packages/torch/quantization/quantize.py in convert(module, mapping, inplace, remove_qconfig)
412 if not inplace:
413 module = copy.deepcopy(module)
--> 414 _convert(module, mapping, inplace=True)
415 if remove_qconfig:
416 _remove_qconfig(module)
/opt/conda/envs/pytorch/lib/python3.8/site-packages/torch/quantization/quantize.py in _convert(module, mapping, inplace)
457 not is_observed_custom_module(mod):
458 _convert(mod, mapping, inplace=True)
--> 459 reassign[name] = swap_module(mod, mapping)
460
461 for key, value in reassign.items():
/opt/conda/envs/pytorch/lib/python3.8/site-packages/torch/quantization/quantize.py in swap_module(mod, mapping)
483 swapped = True
484 elif type(mod) in mapping:
--> 485 new_mod = mapping[type(mod)].from_float(mod)
486 swapped = True
487
/opt/conda/envs/pytorch/lib/python3.8/site-packages/torch/nn/quantized/dynamic/modules/linear.py in from_float(cls, mod)
93 dtype = weight_observer.dtype
94 assert dtype in [torch.qint8, torch.float16], 'The only supported dtypes for dynamic quantized linear are qint8 and float16'
---> 95 weight_observer(mod.weight)
96 if dtype == torch.qint8:
97 qweight = _quantize_weight(mod.weight.float(), weight_observer)
/opt/conda/envs/pytorch/lib/python3.8/site-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
725 result = self._slow_forward(*input, **kwargs)
726 else:
--> 727 result = self.forward(*input, **kwargs)
728 for hook in itertools.chain(
729 _global_forward_hooks.values(),
/opt/conda/envs/pytorch/lib/python3.8/site-packages/torch/quantization/observer.py in forward(self, x_orig)
391 x = x.to(self.min_val.dtype)
392 min_val_cur, max_val_cur = torch._aminmax(x)
--> 393 min_val = torch.min(min_val_cur, self.min_val)
394 max_val = torch.max(max_val_cur, self.max_val)
395 self.min_val.copy_(min_val)
RuntimeError: iter.device(arg).is_cuda() INTERNAL ASSERT FAILED at "/opt/conda/conda-bld/pytorch_1603729096996/work/aten/src/ATen/native/cuda/Loops.cuh":94, please report a bug to PyTorch.
%% Cell type:markdown id:7b108e17 tags:
For each class, compare the classification test accuracy of the initial model and the quantized model. Also give the overall test accuracy for both models.
%% Cell type:code id: tags:
``` python
model2.cpu()
quantized_model2 = torch.quantization.quantize_dynamic(model2, dtype=torch.qint8)
print_size_of_model(quantized_model2, "int8")
```
%% Output
model: int8 Size (KB): 267.281
267281
%% Cell type:code id: tags:
``` python
# Après la quantification du modèle (avant d'enregistrer)
quantized_model2 = quantized_model2.to('cpu') # Déplace le modèle quantifié sur le CPU
# Sauvegarder le modèle quantifié
torch.save(quantized_model2.state_dict(), "quantized_model_cifar2.pt")
# track test loss
test_loss2q = 0.0
class_correct2q = list(0.0 for i in range(10))
class_total2q = list(0.0 for i in range(10))
quantized_model2.eval() # Modèle en mode évaluation
# itérer sur les données de test
for data, target in test_loader:
# Déplacer les données sur le CPU si elles sont sur le GPU
data, target = data.to('cpu'), target.to('cpu') # Déplace les données et les cibles sur le CPU
# forward pass: calcul des sorties prédites en passant les entrées dans le modèle
output = quantized_model2(data)
# Calculer la perte par lot
loss2q = criterion(output, target)
test_loss2q += loss2q.item() * data.size(0)
# Convertir les probabilités de sortie en classes prédites
_, pred = torch.max(output, 1)
# Comparer les prédictions aux étiquettes vraies
correct_tensor = pred.eq(target.data.view_as(pred))
correct = (
np.squeeze(correct_tensor.numpy()) # Si non-CPU, utilisez CPU
if not train_on_gpu
else np.squeeze(correct_tensor.cpu().numpy())
)
# Calculer la précision de test pour chaque classe d'objet
for i in range(batch_size):
label = target.data[i]
class_correct2q[label] += correct[i].item()
class_total2q[label] += 1
# Calcul de la perte moyenne de test
test_loss2q = test_loss2q / len(test_loader)
print("Test Loss: {:.6f}\n".format(test_loss2q))
# Affichage de la précision pour chaque classe
for i in range(10):
if class_total2q[i] > 0:
print(
"Test Accuracy of %5s: %2d%% (%2d/%2d)"
% (
classes[i],
100 * class_correct2q[i] / class_total2q[i],
np.sum(class_correct2q[i]),
np.sum(class_total2q[i]),
)
)
else:
print("Test Accuracy of %5s: N/A (no training examples)" % (classes[i]))
# Affichage de la précision globale de test
print(
"\nTest Accuracy (Overall): %2d%% (%2d/%2d)"
% (
100.0 * np.sum(class_correct2q) / np.sum(class_total2q),
np.sum(class_correct2q),
np.sum(class_total2q),
)
)
```
%% Cell type:code id: tags:
``` python
torch.save(quantized_model2.state_dict(), "quantized_model_cifar2.pt")
# track test loss
test_loss2q = 0.0
class_correct2q = list(0.0 for i in range(10))
class_total2q = list(0.0 for i in range(10))
quantized_model2.eval()
# iterate over test data
for data, target in test_loader:
# move tensors to GPU if CUDA is available
if train_on_gpu:
data, target = data.cuda(), target.cuda()
# forward pass: compute predicted outputs by passing inputs to the model
output = quantized_model2(data)
# calculate the batch loss
loss2q = criterion(output, target)
# update test loss
test_loss2q += loss2q.item() * data.size(0)
# convert output probabilities to predicted class
_, pred = torch.max(output, 1)
# compare predictions to true label
correct_tensor = pred.eq(target.data.view_as(pred))
correct = (
np.squeeze(correct_tensor.numpy())
if not train_on_gpu
else np.squeeze(correct_tensor.cpu().numpy())
)
# calculate test accuracy for each object class
for i in range(batch_size):
label = target.data[i]
class_correct2q[label] += correct[i].item()
class_total2q[label] += 1
# average test loss
test_loss2q = test_loss2q / len(test_loader)
print("Test Loss: {:.6f}\n".format(test_loss2q))
for i in range(10):
if class_total2q[i] > 0:
print(
"Test Accuracy of %5s: %2d%% (%2d/%2d)"
% (
classes[i],
100 * class_correct2q[i] / class_total2q[i],
np.sum(class_correct2q[i]),
np.sum(class_total2q[i]),
)
)
else:
print("Test Accuracy of %5s: N/A (no training examples)" % (classes[i]))
print(
"\nTest Accuracy (Overall): %2d%% (%2d/%2d)"
% (
100.0 * np.sum(class_correct2q) / np.sum(class_total2q),
np.sum(class_correct2q),
np.sum(class_total2q),
)
)
```
%% Cell type:raw id: tags:
quantized_model.load_state_dict(torch.load("./model_cifarq.pt"))
# track test loss
test_lossq = 0.0
class_correctq = list(0.0 for i in range(10))
class_totalq = list(0.0 for i in range(10))
quantized_model.eval()
# iterate over test data
for data, target in test_loader:
# move tensors to GPU if CUDA is available
if train_on_gpu:
data, target = data.cuda(), target.cuda()
# forward pass: compute predicted outputs by passing inputs to the model
output = quantized_model(data)
# calculate the batch loss
lossq = criterion(output, target)
# update test loss
test_lossq += lossq.item() * data.size(0)
# convert output probabilities to predicted class
_, pred = torch.max(output, 1)
# compare predictions to true label
correct_tensor = pred.eq(target.data.view_as(pred))
correctq = (
np.squeeze(correct_tensor.numpy())
if not train_on_gpu
else np.squeeze(correct_tensor.cpu().numpy())
)
# calculate test accuracy for each object class
for i in range(batch_size):
label = target.data[i]
class_correctq[label] += correctq[i].item()
class_totalq[label] += 1
# average test loss
test_lossq = test_lossq / len(test_loader)
print("Test Loss: {:.6f}\n".format(test_lossq))
for i in range(10):
if class_totalq[i] > 0:
print(
"Test Accuracy of %5s: %2d%% (%2d/%2d)"
% (
classes[i],
100 * class_correctq[i] / class_totalq[i],
np.sum(class_correctq[i]),
np.sum(class_totalq[i]),
)
)
else:
print("Test Accuracy of %5s: N/A (no training examples)" % (classes[i]))
print(
"\nTest Accuracy (Overall): %2d%% (%2d/%2d)"
% (
100.0 * np.sum(class_correctq) / np.sum(class_totalq),
np.sum(class_correctq),
np.sum(class_totalq),
)
)
%% Cell type:markdown id:a0a34b90 tags:
Try training aware quantization to mitigate the impact on the accuracy (doc available here https://pytorch.org/docs/stable/quantization.html#torch.quantization.quantize_dynamic)
%% Cell type:markdown id:201470f9 tags:
## Exercise 3: working with pre-trained models.
PyTorch offers several pre-trained models https://pytorch.org/vision/0.8/models.html
We will use ResNet50 trained on ImageNet dataset (https://www.image-net.org/index.php). Use the following code with the files `imagenet-simple-labels.json` that contains the imagenet labels and the image dog.png that we will use as test.
%% Cell type:code id:b4d13080 tags:
``` python
import json
from PIL import Image
# Choose an image to pass through the model
test_image = "dog.png"
# Configure matplotlib for pretty inline plots
#%matplotlib inline
#%config InlineBackend.figure_format = 'retina'
# Prepare the labels
with open("imagenet-simple-labels.json") as f:
labels = json.load(f)
# First prepare the transformations: resize the image to what the model was trained on and convert it to a tensor
data_transform = transforms.Compose(
[
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
]
)
# Load the image
image = Image.open(test_image)
plt.imshow(image), plt.xticks([]), plt.yticks([])
# Now apply the transformation, expand the batch dimension, and send the image to the GPU
# image = data_transform(image).unsqueeze(0).cuda()
image = data_transform(image).unsqueeze(0)
# Download the model if it's not there already. It will take a bit on the first run, after that it's fast
model = models.resnet50(pretrained=True)
# Send the model to the GPU
# model.cuda()
# Set layers such as dropout and batchnorm in evaluation mode
model.eval()
# Get the 1000-dimensional model output
out = model(image)
# Find the predicted class
print("Predicted class is: {}".format(labels[out.argmax()]))
```
%% Cell type:markdown id:184cfceb tags:
Experiments:
Study the code and the results obtained. Possibly add other images downloaded from the internet.
What is the size of the model? Quantize it and then check if the model is still able to correctly classify the other images.
Experiment with other pre-trained CNN models.
%% Cell type:code id: tags:
``` python
import torch
import torch.quantization
from torchvision import models, transforms
from PIL import Image
import json
import numpy as np
import matplotlib.pyplot as plt
# Prepare the transformations for the input image
data_transform = transforms.Compose(
[
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
]
)
# Load the labels for ImageNet (a JSON file with label mappings)
with open("imagenet-simple-labels.json") as f:
labels = json.load(f)
# Choose an image to pass through the model
test_image = "dog.png"
# Load the image and apply transformations
image = Image.open(test_image)
plt.imshow(image)
plt.xticks([]), plt.yticks([]) # Hide axis ticks
plt.show()
# Apply the data transformation and add a batch dimension
image_tensor = data_transform(image).unsqueeze(0)
# Load the pre-trained ResNet50 model
model_resnet50 = models.resnet50(pretrained=True)
model_resnet50.eval() # Set model to evaluation mode
# Quantize the model dynamically (8-bit integer)
quantized_model_resnet50 = torch.quantization.quantize_dynamic(model_resnet50, dtype=torch.qint8)
# Check the original and quantized model sizes
def model_size(model):
return sum(p.numel() for p in model.parameters() if p.requires_grad) / 1e6 # In million parameters
original_size = model_size(model_resnet50)
quantized_size = model_size(quantized_model_resnet50)
print(f"Original model size (ResNet50): {original_size:.2f} million parameters")
print(f"Quantized model size (ResNet50): {quantized_size:.2f} million parameters")
# Function to predict using the model
def predict(model, image_tensor):
with torch.no_grad(): # No need to track gradients for inference
output = model(image_tensor)
_, predicted_class = torch.max(output, 1)
return labels[predicted_class.item()]
# Test the original model (ResNet50)
print("Original Model Prediction (ResNet50):", predict(model_resnet50, image_tensor))
# Test the quantized model (ResNet50)
quantized_model_resnet50.eval() # Set to eval mode
print("Quantized Model Prediction (ResNet50):", predict(quantized_model_resnet50, image_tensor))
# Experiment with another model, e.g., AlexNet
model_alexnet = models.alexnet(pretrained=True)
model_alexnet.eval()
print("AlexNet Prediction:", predict(model_alexnet, image_tensor))
# Experiment with another model, e.g., VGG16
model_vgg16 = models.vgg16(pretrained=True)
model_vgg16.eval()
print("VGG16 Prediction:", predict(model_vgg16, image_tensor))
# You can add more models like ResNet18, DenseNet, etc., in a similar way.
```
%% Output
Original model size (ResNet50): 25.56 million parameters
Quantized model size (ResNet50): 23.51 million parameters
Original Model Prediction (ResNet50): Golden Retriever
Quantized Model Prediction (ResNet50): Golden Retriever
Downloading: "https://download.pytorch.org/models/alexnet-owt-4df8aa71.pth" to /home/jcaty/.cache/torch/hub/checkpoints/alexnet-owt-4df8aa71.pth
70.5%IOPub message rate exceeded.
The notebook server will temporarily stop sending output
to the client in order to avoid crashing it.
To change this limit, set the config variable
`--NotebookApp.iopub_msg_rate_limit`.
Current values:
NotebookApp.iopub_msg_rate_limit=1000.0 (msgs/sec)
NotebookApp.rate_limit_window=3.0 (secs)
8.3%IOPub message rate exceeded.
The notebook server will temporarily stop sending output
to the client in order to avoid crashing it.
To change this limit, set the config variable
`--NotebookApp.iopub_msg_rate_limit`.
Current values:
NotebookApp.iopub_msg_rate_limit=1000.0 (msgs/sec)
NotebookApp.rate_limit_window=3.0 (secs)
33.0%IOPub message rate exceeded.
The notebook server will temporarily stop sending output
to the client in order to avoid crashing it.
To change this limit, set the config variable
`--NotebookApp.iopub_msg_rate_limit`.
Current values:
NotebookApp.iopub_msg_rate_limit=1000.0 (msgs/sec)
NotebookApp.rate_limit_window=3.0 (secs)
%% Cell type:markdown id:5d57da4b tags:
## Exercise 4: Transfer Learning
For this work, we will use a pre-trained model (ResNet18) as a descriptor extractor and will refine the classification by training only the last fully connected layer of the network. Thus, the output layer of the pre-trained network will be replaced by a layer adapted to the new classes to be recognized which will be in our case ants and bees.
Download and unzip in your working directory the dataset available at the address :
https://download.pytorch.org/tutorial/hymenoptera_data.zip
Execute the following code in order to display some images of the dataset.
%% Cell type:code id:be2d31f5 tags:
``` python
import os
import matplotlib.pyplot as plt
import numpy as np
import torch
import torchvision
from torchvision import datasets, transforms
# Data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
"train": transforms.Compose(
[
transforms.RandomResizedCrop(
224
), # ImageNet models were trained on 224x224 images
transforms.RandomHorizontalFlip(), # flip horizontally 50% of the time - increases train set variability
transforms.ToTensor(), # convert it to a PyTorch tensor
transforms.Normalize(
[0.485, 0.456, 0.406], [0.229, 0.224, 0.225]
), # ImageNet models expect this norm
]
),
"val": transforms.Compose(
[
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
]
),
}
data_dir = "hymenoptera_data"
# Create train and validation datasets and loaders
image_datasets = {
x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x])
for x in ["train", "val"]
}
dataloaders = {
x: torch.utils.data.DataLoader(
image_datasets[x], batch_size=4, shuffle=True, num_workers=0
)
for x in ["train", "val"]
}
dataset_sizes = {x: len(image_datasets[x]) for x in ["train", "val"]}
class_names = image_datasets["train"].classes
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# Helper function for displaying images
def imshow(inp, title=None):
"""Imshow for Tensor."""
inp = inp.numpy().transpose((1, 2, 0))
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
# Un-normalize the images
inp = std * inp + mean
# Clip just in case
inp = np.clip(inp, 0, 1)
plt.imshow(inp)
if title is not None:
plt.title(title)
plt.pause(0.001) # pause a bit so that plots are updated
plt.show()
# Get a batch of training data
inputs, classes = next(iter(dataloaders["train"]))
# Make a grid from batch
out = torchvision.utils.make_grid(inputs)
imshow(out, title=[class_names[x] for x in classes])
```
%% Cell type:markdown id:bbd48800 tags:
Now, execute the following code which uses a pre-trained model ResNet18 having replaced the output layer for the ants/bees classification and performs the model training by only changing the weights of this output layer.
%% Cell type:code id:572d824c tags:
``` python
import copy
import os
import time
import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
from torch.optim import lr_scheduler
from torchvision import datasets, transforms
# Data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
"train": transforms.Compose(
[
transforms.RandomResizedCrop(
224
), # ImageNet models were trained on 224x224 images
transforms.RandomHorizontalFlip(), # flip horizontally 50% of the time - increases train set variability
transforms.ToTensor(), # convert it to a PyTorch tensor
transforms.Normalize(
[0.485, 0.456, 0.406], [0.229, 0.224, 0.225]
), # ImageNet models expect this norm
]
),
"val": transforms.Compose(
[
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
]
),
}
data_dir = "hymenoptera_data"
# Create train and validation datasets and loaders
image_datasets = {
x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x])
for x in ["train", "val"]
}
dataloaders = {
x: torch.utils.data.DataLoader(
image_datasets[x], batch_size=4, shuffle=True, num_workers=4
)
for x in ["train", "val"]
}
dataset_sizes = {x: len(image_datasets[x]) for x in ["train", "val"]}
class_names = image_datasets["train"].classes
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# Helper function for displaying images
def imshow(inp, title=None):
"""Imshow for Tensor."""
inp = inp.numpy().transpose((1, 2, 0))
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
# Un-normalize the images
inp = std * inp + mean
# Clip just in case
inp = np.clip(inp, 0, 1)
plt.imshow(inp)
if title is not None:
plt.title(title)
plt.pause(0.001) # pause a bit so that plots are updated
plt.show()
# Get a batch of training data
# inputs, classes = next(iter(dataloaders['train']))
# Make a grid from batch
# out = torchvision.utils.make_grid(inputs)
# imshow(out, title=[class_names[x] for x in classes])
# training
def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
since = time.time()
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
epoch_time = [] # we'll keep track of the time needed for each epoch
for epoch in range(num_epochs):
epoch_start = time.time()
print("Epoch {}/{}".format(epoch + 1, num_epochs))
print("-" * 10)
# Each epoch has a training and validation phase
for phase in ["train", "val"]:
if phase == "train":
scheduler.step()
model.train() # Set model to training mode
else:
model.eval() # Set model to evaluate mode
running_loss = 0.0
running_corrects = 0
# Iterate over data.
for inputs, labels in dataloaders[phase]:
inputs = inputs.to(device)
labels = labels.to(device)
# zero the parameter gradients
optimizer.zero_grad()
# Forward
# Track history if only in training phase
with torch.set_grad_enabled(phase == "train"):
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
loss = criterion(outputs, labels)
# backward + optimize only if in training phase
if phase == "train":
loss.backward()
optimizer.step()
# Statistics
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_corrects.double() / dataset_sizes[phase]
print("{} Loss: {:.4f} Acc: {:.4f}".format(phase, epoch_loss, epoch_acc))
# Deep copy the model
if phase == "val" and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
# Add the epoch time
t_epoch = time.time() - epoch_start
epoch_time.append(t_epoch)
print()
time_elapsed = time.time() - since
print(
"Training complete in {:.0f}m {:.0f}s".format(
time_elapsed // 60, time_elapsed % 60
)
)
print("Best val Acc: {:4f}".format(best_acc))
# Load best model weights
model.load_state_dict(best_model_wts)
return model, epoch_time
# Download a pre-trained ResNet18 model and freeze its weights
model = torchvision.models.resnet18(pretrained=True)
for param in model.parameters():
param.requires_grad = False
# Replace the final fully connected layer
# Parameters of newly constructed modules have requires_grad=True by default
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 2)
# Send the model to the GPU
model = model.to(device)
# Set the loss function
criterion = nn.CrossEntropyLoss()
# Observe that only the parameters of the final layer are being optimized
optimizer_conv = optim.SGD(model.fc.parameters(), lr=0.001, momentum=0.9)
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_conv, step_size=7, gamma=0.1)
model, epoch_time = train_model(
model, criterion, optimizer_conv, exp_lr_scheduler, num_epochs=10
)
```
%% Cell type:markdown id:bbd48800 tags:
%% Cell type:markdown id:ca7cda74 tags:
Experiments:
Study the code and the results obtained.
Modify the code and add an "eval_model" function to allow
the evaluation of the model on a test set (different from the learning and validation sets used during the learning phase). Study the results obtained.
Now modify the code to replace the current classification layer with a set of two layers using a "relu" activation function for the middle layer, and the "dropout" mechanism for both layers. Renew the experiments and study the results obtained.
Apply ther quantization (post and quantization aware) and evaluate impact on model size and accuracy.
%% Cell type:markdown id:04a263f0 tags:
## Optional
Try this at home!!
Pytorch offers a framework to export a given CNN to your selfphone (either android or iOS). Have a look at the tutorial https://pytorch.org/mobile/home/
The Exercise consists in deploying the CNN of Exercise 4 in your phone and then test it on live.
%% Cell type:markdown id:fe954ce4 tags:
## Author
Alberto BOSIO - Ph. D.
%% Cell type:markdown id: tags:
## Author
Alberto BOSIO - Ph. D.
%% Cell type:markdown id: tags:
## Author
Alberto BOSIO - Ph. D.
......
File added
File added
File added