Vvaann's picture
Upload 4 files
6254023 verified
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import matplotlib.pyplot as plt
from tqdm import tqdm
import numpy as np
from torch_lr_finder import LRFinder
from pytorch_grad_cam import GradCAM
from pytorch_grad_cam.utils.model_targets import ClassifierOutputTarget
from pytorch_grad_cam.utils.image import show_cam_on_image
import albumentations as A
from albumentations.pytorch import ToTensorV2
# Train data transformations
means = [0.4914, 0.4822, 0.4465]
stds = [0.2470, 0.2435, 0.2616]
train_transforms = A.Compose(
[
A.Normalize(mean=means, std=stds, always_apply=True),
A.PadIfNeeded(min_height=36, min_width=36, always_apply=True),
A.RandomCrop(height=32, width=32, always_apply=True),
A.HorizontalFlip(),
A.CoarseDropout(max_holes=1, max_height=16, max_width=16, min_holes=1, min_height=8, min_width=8, fill_value=means),
ToTensorV2(),
]
)
test_transforms = A.Compose(
[
A.Normalize(mean=means, std=stds, always_apply=True),
ToTensorV2(),
]
)
class Cifar10SearchDataset(torchvision.datasets.CIFAR10):
def __init__(self, root="~/data", train=True, download=True, transform=None):
super().__init__(root=root, train=train, download=download, transform=transform)
def __getitem__(self, index):
image, label = self.data[index], self.targets[index]
if self.transform is not None:
transformed = self.transform(image=image)
image = transformed["image"]
return image, label
def dataloader(data_path,batch_size):#,train_transforms,test_transforms):
trainset = Cifar10SearchDataset(root=data_path, train=True,download=True, transform=train_transforms)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,shuffle=True)
testset = Cifar10SearchDataset(root=data_path, train=False, download=True, transform=test_transforms)
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,shuffle=False)
classes = trainset.classes
return trainloader, testloader, classes
def plot_sample_data(dataloader):
batch_data, batch_label = next(iter(dataloader))
fig = plt.figure()
for i in range(12):
plt.subplot(3, 4, i + 1)
plt.tight_layout()
plt.imshow(torch.permute(batch_data[i], (1, 2, 0)))
plt.title(batch_label[i].item())
plt.xticks([])
plt.yticks([])
class trainer:
def __init__(self,model,device,optimizer,scheduler):
self.model = model
self.device = device
self.optimizer = optimizer
self.scheduler = scheduler
self.device = device
self.train_losses = []
self.test_losses = []
self.train_acc = []
self.test_acc = []
def getcorrectpredcount(self,prediction, labels):
return prediction.argmax(dim=1).eq(labels).sum().item()
def train(self,train_loader):
self.model.train()
pbar = tqdm(train_loader)
train_loss = 0
correct = 0
processed = 0
criterion = nn.CrossEntropyLoss()
for batch_idx, (data, target) in enumerate(pbar):
data, target = data.to(self.device), target.to(self.device)
self.optimizer.zero_grad()
# Predict
pred = self.model(data)
# Calculate loss
loss = criterion(pred, target)
train_loss += loss.item()
# Backpropagation
loss.backward()
self.optimizer.step()
correct += self.getcorrectpredcount(pred, target)
processed += len(data)
pbar.set_description(
desc=f'Train: Loss={loss.item():0.4f} Batch_id={batch_idx} Accuracy={100 * correct / processed:0.2f}')
self.train_acc.append(100 * correct / processed)
self.train_losses.append(train_loss / len(train_loader))
return self.train_acc, self.train_losses
def test(self,test_loader):
self.model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for batch_idx, (data, target) in enumerate(test_loader):
data, target = data.to(self.device), target.to(self.device)
output = self.model(data)
test_loss += F.cross_entropy(output, target, reduction='sum').item() # sum up batch loss
correct += self.getcorrectpredcount(output, target)
test_loss /= len(test_loader.dataset)
self.test_acc.append(100. * correct / len(test_loader.dataset))
self.test_losses.append(test_loss)
print('Test set: Average loss: {:.4f}, Accuracy: {}/{} ({:.2f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
return self.test_acc, self.test_losses
def visualize_graphs(self):
t = [t_items.item() for t_items in self.train_losses]
fig, axs = plt.subplots(2,2,figsize=(15,10))
axs[0, 0].plot(t)
axs[0, 0].set_title("Training Loss")
axs[1, 0].plot(self.train_acc[4000:])
axs[1, 0].set_title("Training Accuracy")
axs[0, 1].plot(self.test_losses)
axs[0, 1].set_title("Test Loss")
axs[1, 1].plot(self.test_acc)
axs[1, 1].set_title("Test Accuracy")
def evaluate_all_class(self,classes,test_loader):
# prepare to count predictions for each class
correct_pred = {classname: 0 for classname in classes}
total_pred = {classname: 0 for classname in classes}
# again no gradients needed
with torch.no_grad():
for data in test_loader:
images, labels = data
outputs = self.model(images)
_, predictions = torch.max(outputs, 1)
# collect the correct predictions for each class
for label, prediction in zip(labels, predictions):
if label == prediction:
correct_pred[classes[label]] += 1
total_pred[classes[label]] += 1
# print accuracy for each class
for classname, correct_count in correct_pred.items():
accuracy = 100 * float(correct_count) / total_pred[classname]
print(f'Accuracy for class: {classname:5s} is {accuracy:.1f} %')
def evaluate_model(model, loader, device):
cols, rows = 4, 6
figure = plt.figure(figsize=(20, 20))
for index in range(1, cols * rows + 1):
k = np.random.randint(0, len(loader.dataset)) # random points from test dataset
img, label = loader.dataset[k] # separate the image and label
img = img.unsqueeze(0) # adding one dimention
pred = model(img.to(device)) # Prediction
figure.add_subplot(rows, cols, index) # making the figure
plt.title(f"Predcited label {pred.argmax().item()}\n True Label: {label}") # title of plot
plt.axis("off") # hiding the axis
plt.imshow(img.squeeze(), cmap="gray") # showing the plot
plt.show()
def get_lr(optimizer):
""""
for tracking how your learning rate is changing throughout training
"""
for param_group in optimizer.param_groups:
return param_group['lr']
def lr_calc(model, train_loader, optimizer, criterion):
# model = Net().to(device)
# optimizer = optim.Adam(model.parameters(), lr=0.03, weight_decay=1e-4)
# criterion = nn.CrossEntropyLoss()
lr_finder = LRFinder(model, optimizer, criterion, device="cuda")
lr_finder.range_test(train_loader, end_lr=10, num_iter=200, step_mode="exp")
lr_finder.plot() # to inspect the loss-learning rate graph
lr_finder.reset() # to reset the model and optimizer to their initial state
def unnormalize(img):
channel_means = (0.4914, 0.4822, 0.4465)
channel_stdevs = (0.2470, 0.2435, 0.2616)
img = img.numpy().astype(dtype=np.float32)
for i in range(img.shape[0]):
img[i] = (img[i]*channel_stdevs[i])+channel_means[i]
return np.transpose(img, (1,2,0))
def plot_grad_cam_images(model, test_loader, classes, device):
# set model to evaluation mode
model.eval()
target_layers = [model.layer4[-1]]
# Construct the CAM object once, and then re-use it on many images:
cam = GradCAM(model=model, target_layers=target_layers)
misclassified_images = []
actual_labels = []
actual_targets = []
predicted_labels = []
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
_, pred = torch.max(output, 1)
for i in range(len(pred)):
if pred[i] != target[i]:
actual_targets.append(target[i])
misclassified_images.append(data[i])
actual_labels.append(classes[target[i]])
predicted_labels.append(classes[pred[i]])
# Plot the misclassified images
fig = plt.figure(figsize=(12, 5))
for i in range(10):
sub = fig.add_subplot(2, 5, i+1)
input_tensor = misclassified_images[i].unsqueeze(dim=0)
targets = [ClassifierOutputTarget(actual_targets[i])]
grayscale_cam = cam(input_tensor=input_tensor, targets=targets)
grayscale_cam = grayscale_cam[0, :]
visualization = show_cam_on_image(unnormalize(misclassified_images[i].cpu()), grayscale_cam, use_rgb=True,image_weight=0.7)
plt.imshow(visualization)
sub.set_title("Actual: {}, Pred: {}".format(actual_labels[i], predicted_labels[i]), color='red')
plt.tight_layout()
plt.show()
def plot_misclassified_images(model, test_loader, classes, device):
# set model to evaluation mode
model.eval()
misclassified_images = []
actual_labels = []
predicted_labels = []
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
_, pred = torch.max(output, 1)
for i in range(len(pred)):
if pred[i] != target[i]:
misclassified_images.append(data[i])
actual_labels.append(classes[target[i]])
predicted_labels.append(classes[pred[i]])
# Plot the misclassified images
fig = plt.figure(figsize=(12, 5))
for i in range(10):
sub = fig.add_subplot(2, 5, i+1)
npimg = unnormalize(misclassified_images[i].cpu())
plt.imshow(npimg, cmap='gray', interpolation='none')
sub.set_title("Actual: {}, Pred: {}".format(actual_labels[i], predicted_labels[i]),color='red')
plt.tight_layout()
plt.show()