|
|
import torch |
|
|
import torch.nn as nn |
|
|
import numpy as np |
|
|
import matplotlib as plt |
|
|
from torch.utils.data import DataLoader, TensorDataset |
|
|
|
|
|
def show_example(img,label): |
|
|
print('Label: ', classes[label], '('+str(label)+')') |
|
|
plt.imshow(img.permute(1, 2, 0)) |
|
|
|
|
|
|
|
|
def denormalize(images, means, stds): |
|
|
means = torch.tensor(means).reshape(1, 3, 1, 1) |
|
|
stds = torch.tensor(stds).reshape(1, 3, 1, 1) |
|
|
return images * stds + means |
|
|
|
|
|
|
|
|
def accuracy(out,labels): |
|
|
_, preds = torch.max(out,dim=1) |
|
|
total = torch.sum(preds == labels).item()/len(preds) |
|
|
return torch.tensor(total) |
|
|
|
|
|
@torch.inference_mode() |
|
|
def evaluation(model,val_loader): |
|
|
model.eval() |
|
|
results = [model.validation_step(batch) for batch in val_loader] |
|
|
outputs = model.validation_end_epoch(results) |
|
|
return outputs |
|
|
|
|
|
|
|
|
def to_device(data, device): |
|
|
if isinstance(data, (tuple, list)): |
|
|
return [to_device(x, device) for x in data] |
|
|
return data.to(device, non_blocking=True) |
|
|
|
|
|
class DeviceDataLoader(DataLoader): |
|
|
def __init__(self, dl, device): |
|
|
self.dl = dl |
|
|
self.device = device |
|
|
|
|
|
def __iter__(self): |
|
|
"""Yield a batch of data after moving it to device""" |
|
|
for x in self.dl: |
|
|
yield to_device(x, self.device) |
|
|
|
|
|
def __len__(self): |
|
|
"""Number of batches""" |
|
|
return len(self.dl) |
|
|
|
|
|
|
|
|
def get_lr(optimizer): |
|
|
for param_group in optimizer.param_groups: |
|
|
return param_group['lr'] |
|
|
|
|
|
def fit_one_cycle(epochs, max_lr, model, train_loader, val_loader, |
|
|
weight_decay=0, grad_clip=None, opt_func=torch.optim.SGD): |
|
|
torch.cuda.empty_cache() |
|
|
history = [] |
|
|
|
|
|
|
|
|
optimizer = opt_func(model.parameters(), max_lr, weight_decay=weight_decay) |
|
|
|
|
|
|
|
|
sched = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr, epochs=epochs, |
|
|
steps_per_epoch=len(train_loader)) |
|
|
|
|
|
for epoch in range(epochs): |
|
|
|
|
|
model.train() |
|
|
train_losses = [] |
|
|
train_acc = [] |
|
|
lrs = [] |
|
|
for batch in train_loader: |
|
|
loss, acc = model.training_step(batch) |
|
|
train_losses.append(loss) |
|
|
train_acc.append(acc) |
|
|
loss.backward() |
|
|
|
|
|
|
|
|
if grad_clip: |
|
|
nn.utils.clip_grad_value_(model.parameters(), grad_clip) |
|
|
|
|
|
optimizer.step() |
|
|
optimizer.zero_grad() |
|
|
|
|
|
|
|
|
lrs.append(get_lr(optimizer)) |
|
|
sched.step() |
|
|
|
|
|
|
|
|
result = evaluation(model, val_loader) |
|
|
result['train_losses'] = torch.stack(train_losses).mean().item() |
|
|
result['train_acc'] = torch.stack(train_acc).mean().item() |
|
|
result['lrs'] = lrs |
|
|
model.epoch_end(epoch, result) |
|
|
history.append(result) |
|
|
return history |
|
|
|
|
|
|
|
|
def plot_accuracies(history): |
|
|
plt.plot([x['val_acc'] for x in history], '-rx') |
|
|
plt.plot([x['train_acc'] for x in history[1:]], '-bx') |
|
|
plt.xlabel('epoch') |
|
|
plt.ylabel('accuracy') |
|
|
plt.legend(['Validation', 'Training']) |
|
|
plt.title('Accuracy vs. No. of epochs'); |
|
|
|
|
|
def plot_losses(history): |
|
|
plt.plot([x['val_loss'] for x in history], '-rx') |
|
|
plt.plot([x['train_losses'] for x in history[1:]], '-bx') |
|
|
plt.xlabel('epoch') |
|
|
plt.ylabel('loss') |
|
|
plt.legend(['Validation', 'Training']) |
|
|
plt.title('Loss vs. No. of epochs'); |
|
|
|
|
|
|
|
|
def plot_lrs(history): |
|
|
lrs = np.concatenate([x.get('lrs', []) for x in history]) |
|
|
plt.plot(lrs) |
|
|
plt.xlabel('Batch no.') |
|
|
plt.ylabel('Learning rate') |
|
|
plt.title('Learning Rate vs. Batch no.'); |
|
|
|