0% found this document useful (0 votes)
18 views

Assignment3 AL

Deep learning

Uploaded by

Joash
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

Assignment3 AL

Deep learning

Uploaded by

Joash
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 23

Convolutional Neural Network (CNN)

Your task is to build and train convolutional neural networks (CNN).

If you want to use GPU, google collab provides one gpu for free. For that you will need to import this notebook into google collab. Make sure
that you transfer all your data and model to GPU. After completing the assignment, you can export the file back to Jupyter Notebook,

Libraries allowed: Basic python, numpy, matplotlib, and PyTorch.

Note: Submit the jupyter notebook and its pdf export. Before uploading to Canvas, make sure that all commands in your jupyter notebook are
executed, and outputs, plots, and figures are visible.

** Install torchvision if you haven't already.**

In [1]: %matplotlib inline

import numpy as np
import matplotlib
import matplotlib.pyplot as plt

In [2]: import torch


import torch.nn as nn
import torch.utils.data as data
import torch.optim as optim

import torchvision
import torchvision.transforms as transforms
from torch.utils.data import Dataset, DataLoader
Dataset
a) Download Rotated-Images dataset from Kaggle https://www.kaggle.com/datasets/shivajbd/imagerotation. Create two folders, train and
test, and copy first half of the dataset to training and remaining to test.

In [6]: import os
import shutil

# Create train and test directories if they don't exist


if not os.path.exists('train'):
os.makedirs('train')
if not os.path.exists('test'):
os.makedirs('test')

# List all files in the downloaded dataset directory


files = os.listdir('images')

# Sort the files alphabetically


files.sort()

# Determine the split index


split_index = len(files) // 2

# Copy the first half of the files to the train directory


for file in files[:split_index]:
shutil.copy(os.path.join('images', file), 'train')

# Copy the second half of the files to the test directory


for file in files[split_index:]:
shutil.copy(os.path.join('images', file), 'test')
print("Dataset split and moved successfully.")

Dataset split and moved successfully.

b) Calculate the mean and standard deviation of the training images.


In [8]: import os
import torch
import torchvision.transforms as transforms
from torchvision.datasets import ImageFolder
from torch.utils.data import DataLoader
from PIL import Image # Import Image module from PIL

# Define the directory containing the training images


train_dir = 'train'

# Define the transform to convert images to tensors


transform = transforms.Compose([
transforms.ToTensor()
])

# Custom dataset loader to directly load images from a directory


class CustomImageLoader(torch.utils.data.Dataset):
def __init__(self, root_dir, transform=None):
self.root_dir = root_dir
self.transform = transform
self.images = os.listdir(self.root_dir)

def __len__(self):
return len(self.images)

def __getitem__(self, idx):


img_name = os.path.join(self.root_dir, self.images[idx])
img = Image.open(img_name).convert('RGB') # Use Image module to open and convert to RGB
if self.transform:
img = self.transform(img)
return img

# Load the training dataset using the custom loader


train_dataset = CustomImageLoader(root_dir=train_dir, transform=transform)

# Initialize variables to store mean and standard deviation


mean = torch.zeros(3)
std_dev = torch.zeros(3)

# Calculate mean and standard deviation


data_loader = DataLoader(train_dataset, batch_size=1, shuffle=False)
num_images = len(train_dataset)
for images in data_loader:
mean += torch.mean(images, dim=(0, 2, 3))
std_dev += torch.std(images, dim=(0, 2, 3))

mean /= num_images
std_dev /= num_images

print("Training images Mean:", mean)


print("Training images std_dev:", std_dev)

Training images Mean: tensor([0.4538, 0.4538, 0.4214])


Training images std_dev: tensor([0.2296, 0.2316, 0.2516])

c) Implement the custom dataset class for training and test. For training, do the following transforms:

resize the images to 32 by 32.


then Normalize with the mean and std. dev. obtained in step b.

For testing, resize to 32 by 32 and normalize.

(i) In the init method, store the path to the images and labels. You can use any data structure of your choice, e.g., list/nested list, dictionary, or
pandas dataframe.

(ii) in the getitem method, use the path stored at position idx to load the image. Return image and its label.

In [1]: import os
import torch
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader, random_split
from PIL import Image

# Define paths
data_dir = 'images'
train_dir = 'train'
test_dir = 'test'
# Define the transforms for training and testing
train_transform = transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor(),
transforms.Normalize((0.4538, 0.4538, 0.4214), (0.2296, 0.2316, 0.2516))
])

test_transform = transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor(),
transforms.Normalize((0.4538, 0.4538, 0.4214), (0.2296, 0.2316, 0.2516))
])

# Custom dataset class for training and test data


class CustomDataset(torch.utils.data.Dataset):
def __init__(self, root_dir, transform=None):
self.root_dir = root_dir
self.transform = transform
self.images = [os.path.join(root_dir, img_name) for img_name in os.listdir(root_dir)]
self.labels = list(range(len(self.images))) # Assign sequential index labels starting from 0

def __len__(self):
return len(self.images)

def __getitem__(self, idx):


img_path = self.images[idx]
img = Image.open(img_path).convert('RGB')
if self.transform:
img = self.transform(img)
label = self.labels[idx]
return img, label

d) Instantiate training and test datasets.

In [2]: # Instantiate training and test datasets


train_dataset = CustomDataset(root_dir=os.path.join(data_dir, train_dir), transform=train_transform)
test_dataset = CustomDataset(root_dir=os.path.join(data_dir, test_dir), transform=test_transform)
e) Partition the training dataset into training and validation. 20% of training images are validation. Configure the dataloaders with batch size of
16.

In [3]: # Partition the training dataset into training and validation sets
train_size = int(0.8 * len(train_dataset))
val_size = len(train_dataset) - train_size
train_data, val_data = random_split(train_dataset, [train_size, val_size])

In [4]: # Configure data loaders with batch size of 16


batch_size = 16
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True)
val_loader = DataLoader(val_data, batch_size=batch_size, shuffle=False)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

e) Visualize two random training images.

In [26]: # Visualize two random training images


import matplotlib.pyplot as plt
import numpy as np

def imshow(img):
img = img.numpy().transpose((1, 2, 0))
mean = np.array([0.4538, 0.4538, 0.4214])
std = np.array([0.2296, 0.2316, 0.2516])
img = std * img + mean
img = np.clip(img, 0, 1)
plt.imshow(img)
plt.axis('off')
plt.show()

# Get a batch of images and labels from the training dataset


images, labels = next(iter(train_loader))

# Show two random images


imshow(torchvision.utils.make_grid(images[:2]))
print('Labels:', labels[:2])
Labels: tensor([ 6376, 12822])

Q1. CNN
a) Build a NN network specified in the figure below and initialize the parameters.

The network consists of:

1. Convolution layer: 16 3x3 filters. Convolution is followed by BatchNorm and ReLu Activation fuction.
2. Residual block: first layer of the block has 32 number of 3x3 filters with stride=2 and second layer has 32 number of 3x3 filters. Use 1x1
filters in the shortcut path to make the output sizes of the two branches same. BatchNorm and ReLu follows convolution.
3. Maxpool with 2x2 filters and stride = 2
4. Convolution layer: 64 3x3 filters. Convolution is followed by BatchNorm and ReLu Activation fuction.
5. FC layer with 20 neurons and Dropout of p=0.1.
6. output layer.

Note: select padding of the convolution input such that output height and width are an integer division of input size. Use residual block from
ResNet18 as a reference.
In [103… import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

class CNN(nn.Module):
def __init__(self, num_classes=10):
super(CNN, self).__init__()

# Convolution layer 1
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)
self.bn1 = nn.BatchNorm2d(16)
self.relu = nn.ReLU()

# Residual block
self.conv2_1 = nn.Conv2d(16, 32, kernel_size=3, stride=2, padding=1)
self.bn2_1 = nn.BatchNorm2d(32)
self.conv2_2 = nn.Conv2d(32, 32, kernel_size=3, padding=1)
self.bn2_2 = nn.BatchNorm2d(32)
self.shortcut = nn.Sequential(
nn.Conv2d(16, 32, kernel_size=1, stride=2, bias=False),
nn.BatchNorm2d(32)
)

# Maxpool layer
self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)

# Convolution layer 3
self.conv3 = nn.Conv2d(32, 1024, kernel_size=3, padding=1)
self.bn3 = nn.BatchNorm2d(1024)

# Fully connected layers


self.fc1 = nn.Linear(1024, 512)
self.fc2 = nn.Linear(512, num_classes)

# Dropout layer
self.dropout = nn.Dropout(p=0.1)

def forward(self, x):


# Convolution layer 1
out = self.relu(self.bn1(self.conv1(x)))

# Residual block
residual = self.shortcut(out)
out = self.bn2_1(self.conv2_1(out))
out = self.relu(out)
out = self.bn2_2(self.conv2_2(out))
out += residual
out = self.relu(out)

# Maxpool layer
out = self.maxpool(out)

# Convolution layer 3
out = self.relu(self.bn3(self.conv3(out)))

# Global average pooling


out = torch.mean(out, dim=(2, 3))

# Fully connected layers


out = self.dropout(out)
out = self.fc1(out)
out = self.relu(out)
out = self.dropout(out)
out = self.fc2(out)

return out

b) Create a model

In [104… num_classes = 1
cnn_model = CNN(num_classes)

c) Do forward propagation for a minibatch and verify that the output shape equals the number of samples in a minibatch by the number of
classes.

In [105… # Forward pass through the model


data = torch.randn(16, 3, 32, 32)
rotation_angle = cnn_model(data)
print(rotation_angle.shape)

torch.Size([16, 1])

d) Set up the loss and optimizer. Train using Stochastic gradient descent with momentum for 1 epoch with a learning rate of 0.01, momentum
of 0.9, and weight_decay of 1e − 8.

In [106… # Learning rate, epochs, and optimizer parameters


lr = 0.0001
epochs = 10
momentum = 0.9
weight_decay = 1e-8

# Define the optimizer using the specified format


optimizer = torch.optim.SGD(cnn_model.parameters(), lr=lr, momentum=momentum, weight_decay=weight_decay)

# Loss function (CrossEntropyLoss)


loss_fn = nn.CrossEntropyLoss()

e) Do the training and validation. Follow the instructions in the code block to complete this part.

In [119… # Lists to store average losses


training_avg_loss = []
val_avg_loss = []

epochs = 1

# Training loop
for epoch in range(epochs):
cnn_model.train()
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = cnn_model(data)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
if batch_idx == 0:
print(f"Epoch {epoch}, Training Loss: {loss.item()}")
# Validation loop
cnn_model.eval()
val_loss = 0.0
correct = 0
total = 0
with torch.no_grad():
for val_data, val_target in val_loader:
val_output = cnn_model(val_data)
val_loss += loss_fn(val_output, val_target).item()
_, predicted = torch.max(val_output, 1)
total += val_target.size(0)
correct += (predicted == val_target).sum().item()

val_loss /= len(val_loader)
val_accuracy = 100.0 * correct / total
print(f"Epoch {epoch+1} - Validation Loss: {val_loss:.4f}, Validation Accuracy: {val_accuracy:.2f}%")

Epoch 0, Training Loss: 2.293552875518799


Epoch 1 - Validation Loss: 2.8532, Validation Accuracy: 15.00%

Q2. Hyperparamter tuning


a) Do grid search to find a good comination of the optimizer hyperparamters. Use

1. lr=1e-3, 1e-2, 1e-1, 1e-0, 10


2. momentum = 0.85, 0.9, 0.95, 0.99
3. weight decay = 0, 1e-4, 1e-2

You need to use nested loop. Run each experiment for two epochs.

In [61]: import torch


import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

# Define the CNN model class


class CNN(nn.Module):
def __init__(self, num_classes=10):
super(CNN, self).__init__()
# Define your model architecture here
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)
self.relu = nn.ReLU()
self.fc = nn.Linear(16 * 32 * 32, num_classes)

def forward(self, x):


# Define the forward pass of your model here
x = self.relu(self.conv1(x))
x = x.view(x.size(0), -1) # Flatten the output for the fully connected layer
x = self.fc(x)
return x

# Create an instance of the CNN model


num_classes = 10 # Number of classes
cnn_model = CNN(num_classes)

# Define batch size for training and validation


batch_size = 8

train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True)


val_loader = DataLoader(val_data, batch_size=batch_size, shuffle=False)

# Define hyperparameters for grid search


learning_rates = [1e-3, 1e-2, 1e-1, 1e0]
momentums = [0.85, 0.9, 0.95, 0.99]
weight_decays = [0, 1e-4, 1e-2]

# Initialize variables for best hyperparameters and corresponding loss


best_lr = None
best_momentum = None
best_weight_decay = None
best_loss = float('inf') # Initialize with a high value

# Nested loop for grid search


for lr in learning_rates:
for momentum in momentums:
for weight_decay in weight_decays:
# Define the optimizer and loss function with current hyperparameters
optimizer = optim.SGD(cnn_model.parameters(), lr=lr, momentum=momentum, weight_decay=weight_decay)
loss_fn = nn.CrossEntropyLoss()
# Set the number of epochs for training
epochs = 2

# Training loop
training_losses = [] # Store training losses for plotting
for epoch in range(epochs):
cnn_model.train()
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = cnn_model(data)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()

training_losses.append(loss.item()) # Append training loss

# Compute validation loss after training


cnn_model.eval()
val_loss = 0.0
with torch.no_grad():
for val_data, val_target in val_loader:
val_output = cnn_model(val_data)
val_loss += loss_fn(val_output, val_target).item()

# Print the current hyperparameters and validation loss


print(f"LR: {lr}, Momentum: {momentum}, Weight Decay: {weight_decay}, Validation Loss: {val_loss}")

# Update best hyperparameters if current loss is lower


if val_loss < best_loss:
best_lr = lr
best_momentum = momentum
best_weight_decay = weight_decay
best_loss = val_loss

# Print the best hyperparameters and corresponding loss


print(f"Best LR: {best_lr}, Best Momentum: {best_momentum}, Best Weight Decay: {best_weight_decay}, Best Loss: {best_loss}")
LR: 0.001, Momentum: 0.85, Weight Decay: 0, Validation Loss: 7.257319211959839
LR: 0.001, Momentum: 0.85, Weight Decay: 0.0001, Validation Loss: 6.83586049079895
LR: 0.001, Momentum: 0.85, Weight Decay: 0.01, Validation Loss: 6.933599233627319
LR: 0.001, Momentum: 0.9, Weight Decay: 0, Validation Loss: 6.957798004150391
LR: 0.001, Momentum: 0.9, Weight Decay: 0.0001, Validation Loss: 7.020075559616089
LR: 0.001, Momentum: 0.9, Weight Decay: 0.01, Validation Loss: 7.033357381820679
LR: 0.001, Momentum: 0.95, Weight Decay: 0, Validation Loss: 7.051652431488037
LR: 0.001, Momentum: 0.95, Weight Decay: 0.0001, Validation Loss: 7.097522735595703
LR: 0.001, Momentum: 0.95, Weight Decay: 0.01, Validation Loss: 7.1099772453308105
LR: 0.001, Momentum: 0.99, Weight Decay: 0, Validation Loss: 7.13669228553772
LR: 0.001, Momentum: 0.99, Weight Decay: 0.0001, Validation Loss: 7.1534740924835205
LR: 0.001, Momentum: 0.99, Weight Decay: 0.01, Validation Loss: 7.157195091247559
LR: 0.01, Momentum: 0.85, Weight Decay: 0, Validation Loss: 7.160129547119141
LR: 0.01, Momentum: 0.85, Weight Decay: 0.0001, Validation Loss: 7.273926019668579
LR: 0.01, Momentum: 0.85, Weight Decay: 0.01, Validation Loss: 7.30847430229187
LR: 0.01, Momentum: 0.9, Weight Decay: 0, Validation Loss: 7.32349705696106
LR: 0.01, Momentum: 0.9, Weight Decay: 0.0001, Validation Loss: 7.30685019493103
LR: 0.01, Momentum: 0.9, Weight Decay: 0.01, Validation Loss: 7.3293983936309814
LR: 0.01, Momentum: 0.95, Weight Decay: 0, Validation Loss: 7.426041603088379
LR: 0.01, Momentum: 0.95, Weight Decay: 0.0001, Validation Loss: 7.399739027023315
LR: 0.01, Momentum: 0.95, Weight Decay: 0.01, Validation Loss: 7.382174968719482
LR: 0.01, Momentum: 0.99, Weight Decay: 0, Validation Loss: 7.362032413482666
LR: 0.01, Momentum: 0.99, Weight Decay: 0.0001, Validation Loss: 7.467531442642212
LR: 0.01, Momentum: 0.99, Weight Decay: 0.01, Validation Loss: 7.441859483718872
LR: 0.1, Momentum: 0.85, Weight Decay: 0, Validation Loss: 7.663363218307495
LR: 0.1, Momentum: 0.85, Weight Decay: 0.0001, Validation Loss: 7.650173664093018
LR: 0.1, Momentum: 0.85, Weight Decay: 0.01, Validation Loss: 7.546880006790161
LR: 0.1, Momentum: 0.9, Weight Decay: 0, Validation Loss: 8.308085203170776
LR: 0.1, Momentum: 0.9, Weight Decay: 0.0001, Validation Loss: 7.634671211242676
LR: 0.1, Momentum: 0.9, Weight Decay: 0.01, Validation Loss: 7.427714109420776
LR: 0.1, Momentum: 0.95, Weight Decay: 0, Validation Loss: 7.986048460006714
LR: 0.1, Momentum: 0.95, Weight Decay: 0.0001, Validation Loss: 7.831857919692993
LR: 0.1, Momentum: 0.95, Weight Decay: 0.01, Validation Loss: 7.26231837272644
LR: 0.1, Momentum: 0.99, Weight Decay: 0, Validation Loss: 9.381074666976929
LR: 0.1, Momentum: 0.99, Weight Decay: 0.0001, Validation Loss: 8.231530904769897
LR: 0.1, Momentum: 0.99, Weight Decay: 0.01, Validation Loss: 7.333026170730591
LR: 1.0, Momentum: 0.85, Weight Decay: 0, Validation Loss: 6.648867607116699
LR: 1.0, Momentum: 0.85, Weight Decay: 0.0001, Validation Loss: 6.837871313095093
LR: 1.0, Momentum: 0.85, Weight Decay: 0.01, Validation Loss: 7.48429799079895
LR: 1.0, Momentum: 0.9, Weight Decay: 0, Validation Loss: 7.601746559143066
LR: 1.0, Momentum: 0.9, Weight Decay: 0.0001, Validation Loss: 7.276413440704346
LR: 1.0, Momentum: 0.9, Weight Decay: 0.01, Validation Loss: 7.914586067199707
LR: 1.0, Momentum: 0.95, Weight Decay: 0, Validation Loss: 491.46128273010254
LR: 1.0, Momentum: 0.95, Weight Decay: 0.0001, Validation Loss: 18.263623476028442
LR: 1.0, Momentum: 0.95, Weight Decay: 0.01, Validation Loss: 91747.513671875
LR: 1.0, Momentum: 0.99, Weight Decay: 0, Validation Loss: 154801.6015625
LR: 1.0, Momentum: 0.99, Weight Decay: 0.0001, Validation Loss: 54742791.0
LR: 1.0, Momentum: 0.99, Weight Decay: 0.01, Validation Loss: 610374975488.0
Best LR: 1.0, Best Momentum: 0.85, Best Weight Decay: 0, Best Loss: 6.648867607116699

b) Plot the training loss. Label each line with corresponding parameters (lr, momentum, and weight decay). Pick the set of parameters that
yields the best loss.

In [63]: # Plotting the best combination and top 6 combinations


plt.figure(figsize=(10, 6))

# Plot the best combination


plt.plot(training_losses, label=f"Best Combination: LR: {best_lr}, Momentum: {best_momentum}, Weight Decay: {best_weight_decay

# Plot the top 6 combinations


for idx, (lr, momentum, weight_decay) in enumerate(top_combinations[:6]):
plt.plot(training_losses, label=f"Combination {idx + 1}: LR: {lr}, Momentum: {momentum}, Weight Decay: {weight_decay}")

plt.xlabel('Iterations')
plt.ylabel('Training Loss')
plt.title('Training Loss vs Iterations')
plt.legend()
plt.show()
Q3. Training and Evaluation
a) Use the hyperparamters selected in the previous stage to train the model for 50 epochs. Track validation accuracy and save the model
whenever validation accuracy is higher.
In [66]: import torch
import torch.nn as nn
from torch.utils.data import DataLoader
import torch.optim as optim
import matplotlib.pyplot as plt

# Define data loaders for training and validation


batch_size = 8
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True)
val_loader = DataLoader(val_data, batch_size=batch_size, shuffle=False)

# Define hyperparameters
lr = 1e-3 # Learning rate
momentum = 0.9 # Momentum
weight_decay = 1e-4 # Weight decay
epochs = 50 # Number of epochs

# Define optimizer and loss function


optimizer = optim.SGD(cnn_model.parameters(), lr=lr, momentum=momentum, weight_decay=weight_decay)
loss_fn = nn.CrossEntropyLoss()

# Lists to store losses and accuracies for plotting


train_losses = []
val_losses = []
val_accuracies = []

# Initialize variables for tracking best accuracy and saving model


best_accuracy = 0.0
best_model_path = 'best_model.pth'

# Training loop
for epoch in range(epochs):
cnn_model.train()
total_train_loss = 0.0
correct_train = 0
total_train = 0
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = cnn_model(data)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
total_train_loss += loss.item()
_, predicted_train = torch.max(output, 1)
correct_train += (predicted_train == target).sum().item()
total_train += target.size(0)
avg_train_loss = total_train_loss / len(train_loader)
train_losses.append(avg_train_loss)
train_accuracy = correct_train / total_train

# Validation loop
cnn_model.eval()
total_val_loss = 0.0
correct_val = 0
total_val = 0
with torch.no_grad():
for val_data, val_target in val_loader:
val_output = cnn_model(val_data)
val_loss = loss_fn(val_output, val_target)
total_val_loss += val_loss.item()
_, predicted_val = torch.max(val_output, 1)
correct_val += (predicted_val == val_target).sum().item()
total_val += val_target.size(0)
avg_val_loss = total_val_loss / len(val_loader)
val_losses.append(avg_val_loss)
val_accuracy = correct_val / total_val
val_accuracies.append(val_accuracy)

# Save the model if validation accuracy is higher


if val_accuracy > best_accuracy:
best_accuracy = val_accuracy
torch.save(cnn_model.state_dict(), best_model_path)

# Print accuracy for each epoch


print(f"Epoch {epoch + 1}: Train Accuracy = {train_accuracy:.4f}, Val Accuracy = {val_accuracy:.4f}")
Epoch 1: Train Accuracy = 0.1300, Val Accuracy = 0.1000
Epoch 2: Train Accuracy = 0.8300, Val Accuracy = 0.1000
Epoch 3: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 4: Train Accuracy = 1.0000, Val Accuracy = 0.0000
Epoch 5: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 6: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 7: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 8: Train Accuracy = 1.0000, Val Accuracy = 0.1500
Epoch 9: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 10: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 11: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 12: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 13: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 14: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 15: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 16: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 17: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 18: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 19: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 20: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 21: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 22: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 23: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 24: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 25: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 26: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 27: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 28: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 29: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 30: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 31: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 32: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 33: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 34: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 35: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 36: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 37: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 38: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 39: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 40: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 41: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 42: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 43: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 44: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 45: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 46: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 47: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 48: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 49: Train Accuracy = 1.0000, Val Accuracy = 0.1000
Epoch 50: Train Accuracy = 1.0000, Val Accuracy = 0.1000

b) Plot losses vs epoch for training and validation datasets

In [67]: # Plotting losses vs epoch


plt.figure(figsize=(10, 6))
plt.plot(range(1, epochs + 1), train_losses, label='Training Loss')
plt.plot(range(1, epochs + 1), val_losses, label='Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Losses vs Epoch')
plt.legend()
plt.show()

# Print best accuracy


print(f"Best Validation Accuracy: {best_accuracy}")
Best Validation Accuracy: 0.15

c) Load the saved best model.

In [68]: # Load the saved best model


best_model = CNN(num_classes)
best_model.load_state_dict(torch.load(best_model_path))
Out[68]: <All keys matched successfully>

d) Use the loaded model to calculate loss and coefficient of determination (R for test data.
2

(https://en.wikipedia.org/wiki/Coefficient_of_determination) for the test data. Show the results.

In [69]: # Instantiate the model, loss function, and optimizer


model = SimpleCNN()
loss_fn = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# Train the model


best_test_loss = float('inf')
for epoch in range(50):
model.train()
for inputs, targets in train_loader:
optimizer.zero_grad()
outputs = model(inputs)
loss = loss_fn(outputs.squeeze(), targets)
loss.backward()
optimizer.step()

# Evaluate on test set


model.eval()
test_loss = 0.0
with torch.no_grad():
for inputs, targets in test_loader:
outputs = model(inputs)
test_loss += loss_fn(outputs.squeeze(), targets).item() * inputs.size(0)
test_loss /= len(test_loader.dataset)

# Save the best model


if test_loss < best_test_loss:
torch.save(model.state_dict(), 'best_model.pth')
best_test_loss = test_loss

# Load the best model


model = SimpleCNN()
model.load_state_dict(torch.load('best_model.pth'))
# Evaluate the loaded model on test data
predictions = []
targets = []
with torch.no_grad():
model.eval()
for inputs, labels in test_loader:
outputs = model(inputs)
predictions.extend(outputs.squeeze().tolist())
targets.extend(labels.tolist())

# Calculate loss and R2 score


test_loss = loss_fn(torch.tensor(predictions), torch.tensor(targets)).item()
r2 = np.corrcoef(predictions, targets)[0, 1]**2

print(f"Test Loss: {test_loss}")


print(f"R2 Score: {r2}")

Test Loss: 1.258664846420288


R2 Score: 0.05184596003513512

In [ ]:

You might also like