|
|
import numpy as np |
|
|
import random |
|
|
import matplotlib.pyplot as plt |
|
|
|
|
|
import torch |
|
|
import torchvision |
|
|
from torchinfo import summary |
|
|
from torch_lr_finder import LRFinder |
|
|
|
|
|
|
|
|
def find_lr(model, optimizer, criterion, device, trainloader, numiter, startlr, endlr): |
|
|
lr_finder = LRFinder( |
|
|
model=model, optimizer=optimizer, criterion=criterion, device=device |
|
|
) |
|
|
|
|
|
lr_finder.range_test( |
|
|
train_loader=trainloader, |
|
|
start_lr=startlr, |
|
|
end_lr=endlr, |
|
|
num_iter=numiter, |
|
|
step_mode="exp", |
|
|
) |
|
|
|
|
|
lr_finder.plot() |
|
|
|
|
|
lr_finder.reset() |
|
|
|
|
|
|
|
|
def one_cycle_lr(optimizer, maxlr, steps, epochs): |
|
|
scheduler = torch.optim.lr_scheduler.OneCycleLR( |
|
|
optimizer=optimizer, |
|
|
max_lr=maxlr, |
|
|
steps_per_epoch=steps, |
|
|
epochs=epochs, |
|
|
pct_start=5 / epochs, |
|
|
div_factor=100, |
|
|
three_phase=False, |
|
|
final_div_factor=100, |
|
|
anneal_strategy="linear", |
|
|
) |
|
|
return scheduler |
|
|
|
|
|
|
|
|
def show_random_images_for_each_class(train_data, num_images_per_class=16): |
|
|
for c, cls in enumerate(train_data.classes): |
|
|
rand_targets = random.sample( |
|
|
[n for n, x in enumerate(train_data.targets) if x == c], |
|
|
k=num_images_per_class, |
|
|
) |
|
|
show_img_grid(np.transpose(train_data.data[rand_targets], axes=(0, 3, 1, 2))) |
|
|
plt.title(cls) |
|
|
|
|
|
|
|
|
def show_img_grid(data): |
|
|
try: |
|
|
grid_img = torchvision.utils.make_grid(data.cpu().detach()) |
|
|
except: |
|
|
data = torch.from_numpy(data) |
|
|
grid_img = torchvision.utils.make_grid(data) |
|
|
|
|
|
plt.figure(figsize=(10, 10)) |
|
|
plt.imshow(grid_img.permute(1, 2, 0)) |
|
|
|
|
|
|
|
|
def show_random_images(data_loader): |
|
|
data, target = next(iter(data_loader)) |
|
|
show_img_grid(data) |
|
|
|
|
|
|
|
|
def show_model_summary(model, batch_size): |
|
|
summary( |
|
|
model=model, |
|
|
input_size=(batch_size, 3, 32, 32), |
|
|
col_names=["input_size", "output_size", "num_params", "kernel_size"], |
|
|
verbose=1, |
|
|
) |
|
|
|
|
|
|
|
|
def lossacc_plots(results): |
|
|
plt.plot(results["epoch"], results["trainloss"]) |
|
|
plt.plot(results["epoch"], results["testloss"]) |
|
|
plt.legend(["Train Loss", "Validation Loss"]) |
|
|
plt.xlabel("Epochs") |
|
|
plt.ylabel("Loss") |
|
|
plt.title("Loss vs Epochs") |
|
|
plt.show() |
|
|
|
|
|
plt.plot(results["epoch"], results["trainacc"]) |
|
|
plt.plot(results["epoch"], results["testacc"]) |
|
|
plt.legend(["Train Acc", "Validation Acc"]) |
|
|
plt.xlabel("Epochs") |
|
|
plt.ylabel("Accuracy") |
|
|
plt.title("Accuracy vs Epochs") |
|
|
plt.show() |
|
|
|
|
|
|
|
|
def lr_plots(results, length): |
|
|
plt.plot(range(length), results["lr"]) |
|
|
plt.xlabel("Epochs") |
|
|
plt.ylabel("Learning Rate") |
|
|
plt.title("Learning Rate vs Epochs") |
|
|
plt.show() |
|
|
|
|
|
|
|
|
def get_misclassified(model, testloader, device, mis_count=10): |
|
|
misimgs, mistgts, mispreds = [], [], [] |
|
|
with torch.no_grad(): |
|
|
for data, target in testloader: |
|
|
data, target = data.to(device), target.to(device) |
|
|
output = model(data) |
|
|
pred = output.argmax(dim=1, keepdim=True) |
|
|
misclassified = torch.argwhere(pred.squeeze() != target).squeeze() |
|
|
for idx in misclassified: |
|
|
if len(misimgs) >= mis_count: |
|
|
break |
|
|
misimgs.append(data[idx]) |
|
|
mistgts.append(target[idx]) |
|
|
mispreds.append(pred[idx].squeeze()) |
|
|
return misimgs, mistgts, mispreds |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_misclassified_data(model, device, test_loader, count): |
|
|
""" |
|
|
Function to run the model on test set and return misclassified images |
|
|
:param model: Network Architecture |
|
|
:param device: CPU/GPU |
|
|
:param test_loader: DataLoader for test set |
|
|
""" |
|
|
|
|
|
model.eval() |
|
|
|
|
|
|
|
|
misclassified_data = [] |
|
|
|
|
|
|
|
|
with torch.no_grad(): |
|
|
|
|
|
for data, target in test_loader: |
|
|
|
|
|
|
|
|
data, target = data.to(device), target.to(device) |
|
|
|
|
|
|
|
|
for image, label in zip(data, target): |
|
|
|
|
|
|
|
|
image = image.unsqueeze(0) |
|
|
|
|
|
|
|
|
output = model(image) |
|
|
|
|
|
|
|
|
pred = output.argmax(dim=1, keepdim=True) |
|
|
|
|
|
|
|
|
if pred != label: |
|
|
misclassified_data.append((image, label, pred)) |
|
|
if len(misclassified_data) >= count: |
|
|
break |
|
|
|
|
|
return misclassified_data[:count] |
|
|
|
|
|
def plot_misclassified(data, classes, size=(10, 10), rows=2, cols=5, inv_normalize=None): |
|
|
fig = plt.figure(figsize=size) |
|
|
number_of_samples = len(data) |
|
|
for i in range(number_of_samples): |
|
|
plt.subplot(rows, cols, i + 1) |
|
|
img = data[i][0].squeeze().to('cpu') |
|
|
if inv_normalize is not None: |
|
|
img = inv_normalize(img) |
|
|
plt.imshow(np.transpose(img, (1, 2, 0))) |
|
|
plt.title(f"Label: {classes[data[i][1].item()]} \n Prediction: {classes[data[i][2].item()]}") |
|
|
plt.xticks([]) |
|
|
plt.yticks([]) |
|
|
|
|
|
|