195 lines
5.6 KiB
Python
195 lines
5.6 KiB
Python
import lightning as L
|
|
import matplotlib.pyplot as plt
|
|
import pandas as pd
|
|
import torch
|
|
import torch.nn.functional as F
|
|
import torchmetrics
|
|
from torch.utils.data import DataLoader
|
|
from torch.utils.data.dataset import random_split
|
|
from torchvision import datasets, transforms
|
|
|
|
|
|
class LightningModel(L.LightningModule):
|
|
def __init__(self, model, learning_rate):
|
|
super().__init__()
|
|
|
|
self.learning_rate = learning_rate
|
|
self.model = model
|
|
|
|
self.save_hyperparameters(ignore=["model"])
|
|
|
|
self.train_acc = torchmetrics.Accuracy(task="multiclass", num_classes=10)
|
|
self.val_acc = torchmetrics.Accuracy(task="multiclass", num_classes=10)
|
|
self.test_acc = torchmetrics.Accuracy(task="multiclass", num_classes=10)
|
|
|
|
def forward(self, x):
|
|
return self.model(x)
|
|
|
|
def _shared_step(self, batch):
|
|
features, true_labels = batch
|
|
logits = self(features)
|
|
|
|
loss = F.cross_entropy(logits, true_labels)
|
|
predicted_labels = torch.argmax(logits, dim=1)
|
|
return loss, true_labels, predicted_labels
|
|
|
|
def training_step(self, batch, batch_idx):
|
|
loss, true_labels, predicted_labels = self._shared_step(batch)
|
|
|
|
self.log("train_loss", loss)
|
|
self.train_acc(predicted_labels, true_labels)
|
|
self.log(
|
|
"train_acc", self.train_acc, prog_bar=True, on_epoch=True, on_step=False
|
|
)
|
|
return loss
|
|
|
|
def validation_step(self, batch, batch_idx):
|
|
loss, true_labels, predicted_labels = self._shared_step(batch)
|
|
|
|
self.log("val_loss", loss, prog_bar=True)
|
|
self.val_acc(predicted_labels, true_labels)
|
|
self.log("val_acc", self.val_acc, prog_bar=True)
|
|
|
|
def test_step(self, batch, batch_idx):
|
|
loss, true_labels, predicted_labels = self._shared_step(batch)
|
|
self.test_acc(predicted_labels, true_labels)
|
|
self.log("test_acc", self.test_acc)
|
|
|
|
def configure_optimizers(self):
|
|
optimizer = torch.optim.SGD(self.parameters(), lr=self.learning_rate)
|
|
return optimizer
|
|
|
|
|
|
class Cifar10DataModule(L.LightningDataModule):
|
|
def __init__(
|
|
self, data_path="./", batch_size=64, num_workers=0, height_width=(32, 32),
|
|
train_transform=None, test_transform=None
|
|
):
|
|
super().__init__()
|
|
self.batch_size = batch_size
|
|
self.data_path = data_path
|
|
self.num_workers = num_workers
|
|
self.height_width = height_width
|
|
self.train_transform = train_transform
|
|
self.test_transform = test_transform
|
|
|
|
def prepare_data(self):
|
|
datasets.CIFAR10(root=self.data_path, download=True)
|
|
|
|
if self.train_transform is None:
|
|
self.train_transform = transforms.Compose(
|
|
[
|
|
transforms.Resize(self.height_width),
|
|
transforms.ToTensor(),
|
|
]
|
|
)
|
|
|
|
if self.test_transform is None:
|
|
self.test_transform = transforms.Compose(
|
|
[
|
|
transforms.Resize(self.height_width),
|
|
transforms.ToTensor(),
|
|
]
|
|
)
|
|
return
|
|
|
|
def setup(self, stage=None):
|
|
train = datasets.CIFAR10(
|
|
root=self.data_path,
|
|
train=True,
|
|
transform=self.train_transform,
|
|
download=False,
|
|
)
|
|
|
|
self.test = datasets.CIFAR10(
|
|
root=self.data_path,
|
|
train=False,
|
|
transform=self.test_transform,
|
|
download=False,
|
|
)
|
|
|
|
self.train, self.valid = random_split(train, lengths=[45000, 5000])
|
|
|
|
def train_dataloader(self):
|
|
train_loader = DataLoader(
|
|
dataset=self.train,
|
|
batch_size=self.batch_size,
|
|
drop_last=True,
|
|
shuffle=True,
|
|
num_workers=self.num_workers,
|
|
)
|
|
return train_loader
|
|
|
|
def val_dataloader(self):
|
|
valid_loader = DataLoader(
|
|
dataset=self.valid,
|
|
batch_size=self.batch_size,
|
|
drop_last=False,
|
|
shuffle=False,
|
|
num_workers=self.num_workers,
|
|
)
|
|
return valid_loader
|
|
|
|
def test_dataloader(self):
|
|
test_loader = DataLoader(
|
|
dataset=self.test,
|
|
batch_size=self.batch_size,
|
|
drop_last=False,
|
|
shuffle=False,
|
|
num_workers=self.num_workers,
|
|
)
|
|
return test_loader
|
|
|
|
|
|
def plot_val_acc(
|
|
log_dir, acc_ylim=(0.5, 1.0), save_loss=None, save_acc=None):
|
|
|
|
metrics = pd.read_csv(f"{log_dir}/metrics.csv")
|
|
|
|
aggreg_metrics = []
|
|
agg_col = "epoch"
|
|
|
|
for i, dfg in metrics.groupby(agg_col):
|
|
agg = dict(dfg.mean())
|
|
agg[agg_col] = i
|
|
aggreg_metrics.append(agg)
|
|
|
|
df_metrics = pd.DataFrame(aggreg_metrics)
|
|
df_metrics[["val_acc"]].plot(
|
|
grid=True, legend=True, xlabel="Epoch", ylabel="ACC"
|
|
)
|
|
|
|
plt.ylim(acc_ylim)
|
|
if save_acc is not None:
|
|
plt.savefig(save_acc)
|
|
|
|
|
|
def plot_loss_and_acc(
|
|
log_dir, loss_ylim=(0.0, 0.9), acc_ylim=(0.3, 1.0), save_loss=None, save_acc=None
|
|
):
|
|
|
|
metrics = pd.read_csv(f"{log_dir}/metrics.csv")
|
|
|
|
aggreg_metrics = []
|
|
agg_col = "epoch"
|
|
for i, dfg in metrics.groupby(agg_col):
|
|
agg = dict(dfg.mean())
|
|
agg[agg_col] = i
|
|
aggreg_metrics.append(agg)
|
|
|
|
df_metrics = pd.DataFrame(aggreg_metrics)
|
|
df_metrics[["train_loss"]].plot(
|
|
grid=True, legend=True, xlabel="Epoch", ylabel="Loss"
|
|
)
|
|
|
|
plt.ylim(loss_ylim)
|
|
if save_loss is not None:
|
|
plt.savefig(save_loss)
|
|
|
|
df_metrics[["train_acc", "val_acc"]].plot(
|
|
grid=True, legend=True, xlabel="Epoch", ylabel="ACC"
|
|
)
|
|
|
|
plt.ylim(acc_ylim)
|
|
if save_acc is not None:
|
|
plt.savefig(save_acc) |