Chapter 15
Chapter 13: Going Deeper -- the Mechanics of PyTorch (Part 3/3)
NotebookPython 318 cells
Chapter 13: Going Deeper -- the Mechanics of PyTorch (Part 3/3)
Higher-level PyTorch APIs: a short introduction to PyTorch-Ignite
Setting up the PyTorch model
In [1]python · cell 4
python
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision import transforms
image_path = './'
torch.manual_seed(1)
transform = transforms.Compose([
transforms.ToTensor()
])
mnist_train_dataset = MNIST(
root=image_path,
train=True,
transform=transform,
download=True
)
mnist_val_dataset = MNIST(
root=image_path,
train=False,
transform=transform,
download=False
)
batch_size = 64
train_loader = DataLoader(
mnist_train_dataset, batch_size, shuffle=True
)
val_loader = DataLoader(
mnist_val_dataset, batch_size, shuffle=False
)
def get_model(image_shape=(1, 28, 28), hidden_units=(32, 16)):
input_size = image_shape[0] * image_shape[1] * image_shape[2]
all_layers = [nn.Flatten()]
for hidden_unit in hidden_units:
layer = nn.Linear(input_size, hidden_unit)
all_layers.append(layer)
all_layers.append(nn.ReLU())
input_size = hidden_unit
all_layers.append(nn.Linear(hidden_units[-1], 10))
all_layers.append(nn.Softmax(dim=1))
model = nn.Sequential(*all_layers)
return model
device = "cuda" if torch.cuda.is_available() else "cpu"
model = get_model().to(device)
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)Setting up training and validation engines with PyTorch-Ignite
In [2]python · cell 6
python
from ignite.engine import Events, create_supervised_trainer, create_supervised_evaluator
from ignite.metrics import Accuracy, Loss
trainer = create_supervised_trainer(
model, optimizer, loss_fn, device=device
)
val_metrics = {
"accuracy": Accuracy(),
"loss": Loss(loss_fn)
}
evaluator = create_supervised_evaluator(
model, metrics=val_metrics, device=device
)Creating event handlers for logging and validation
In [3]python · cell 8
python
# How many batches to wait before logging training status
log_interval = 100
@trainer.on(Events.ITERATION_COMPLETED(every=log_interval))
def log_training_loss():
e = trainer.state.epoch
max_e = trainer.state.max_epochs
i = trainer.state.iteration
batch_loss = trainer.state.output
print(f"Epoch[{e}/{max_e}], Iter[{i}] Loss: {batch_loss:.2f}")In [4]python · cell 9
python
@trainer.on(Events.EPOCH_COMPLETED)
def log_validation_results():
eval_state = evaluator.run(val_loader)
metrics = eval_state.metrics
e = trainer.state.epoch
max_e = trainer.state.max_epochs
acc = metrics['accuracy']
avg_loss = metrics['loss']
print(f"Validation Results - Epoch[{e}/{max_e}] Avg Accuracy: {acc:.2f} Avg Loss: {avg_loss:.2f}")Setting up training checkpoints and saving the best model
In [5]python · cell 11
python
from ignite.handlers import Checkpoint, DiskSaver
# We will save in the checkpoint the following:
to_save = {"model": model, "optimizer": optimizer, "trainer": trainer}
# We will save checkpoints to the local disk
output_path = "./output"
save_handler = DiskSaver(dirname=output_path, require_empty=False)
# Set up the handler:
checkpoint_handler = Checkpoint(
to_save, save_handler, filename_prefix="training")
# Attach the handler to the trainer
trainer.add_event_handler(Events.EPOCH_COMPLETED, checkpoint_handler)Output
<ignite.engine.events.RemovableEventHandle at 0x1060993d0>
In [6]python · cell 12
python
# Store best model by validation accuracy
best_model_handler = Checkpoint(
{"model": model},
save_handler,
filename_prefix="best",
n_saved=1,
score_name="accuracy",
score_function=Checkpoint.get_default_score_fn("accuracy"),
)
evaluator.add_event_handler(Events.COMPLETED, best_model_handler)Output
<ignite.engine.events.RemovableEventHandle at 0x106088430>
Setting up TensorBoard as an experiment tracking system
In [7]python · cell 14
python
from ignite.contrib.handlers import TensorboardLogger, global_step_from_engine
tb_logger = TensorboardLogger(log_dir=output_path)
# Attach handler to plot trainer's loss every 100 iterations
tb_logger.attach_output_handler(
trainer,
event_name=Events.ITERATION_COMPLETED(every=100),
tag="training",
output_transform=lambda loss: {"batch_loss": loss},
)
# Attach handler for plotting both evaluators' metrics after every epoch completes
tb_logger.attach_output_handler(
evaluator,
event_name=Events.EPOCH_COMPLETED,
tag="validation",
metric_names="all",
global_step_transform=global_step_from_engine(trainer),
)Output
<ignite.engine.events.RemovableEventHandle at 0x16605ff70>
Executing the PyTorch-Ignite model training code
In [8]python · cell 16
python
trainer.run(train_loader, max_epochs=5)Output
Epoch[1/5], Iter[100] Loss: 1.87 Epoch[1/5], Iter[200] Loss: 1.82 Epoch[1/5], Iter[300] Loss: 1.67 Epoch[1/5], Iter[400] Loss: 1.55 Epoch[1/5], Iter[500] Loss: 1.65 Epoch[1/5], Iter[600] Loss: 1.59 Epoch[1/5], Iter[700] Loss: 1.59 Epoch[1/5], Iter[800] Loss: 1.56 Epoch[1/5], Iter[900] Loss: 1.63 Validation Results - Epoch[1/5] Avg Accuracy: 0.91 Avg Loss: 1.56 Epoch[2/5], Iter[1000] Loss: 1.61 Epoch[2/5], Iter[1100] Loss: 1.56 Epoch[2/5], Iter[1200] Loss: 1.54 Epoch[2/5], Iter[1300] Loss: 1.54 Epoch[2/5], Iter[1400] Loss: 1.51 Epoch[2/5], Iter[1500] Loss: 1.53 Epoch[2/5], Iter[1600] Loss: 1.50 Epoch[2/5], Iter[1700] Loss: 1.50 Epoch[2/5], Iter[1800] Loss: 1.52 Validation Results - Epoch[2/5] Avg Accuracy: 0.92 Avg Loss: 1.54 Epoch[3/5], Iter[1900] Loss: 1.61 Epoch[3/5], Iter[2000] Loss: 1.60 Epoch[3/5], Iter[2100] Loss: 1.54 Epoch[3/5], Iter[2200] Loss: 1.51 Epoch[3/5], Iter[2300] Loss: 1.48 Epoch[3/5], Iter[2400] Loss: 1.56 Epoch[3/5], Iter[2500] Loss: 1.57 Epoch[3/5], Iter[2600] Loss: 1.52 Epoch[3/5], Iter[2700] Loss: 1.54 Epoch[3/5], Iter[2800] Loss: 1.54 Validation Results - Epoch[3/5] Avg Accuracy: 0.93 Avg Loss: 1.53 Epoch[4/5], Iter[2900] Loss: 1.53 Epoch[4/5], Iter[3000] Loss: 1.49 Epoch[4/5], Iter[3100] Loss: 1.51 Epoch[4/5], Iter[3200] Loss: 1.51 Epoch[4/5], Iter[3300] Loss: 1.54 Epoch[4/5], Iter[3400] Loss: 1.50 Epoch[4/5], Iter[3500] Loss: 1.58 Epoch[4/5], Iter[3600] Loss: 1.59 Epoch[4/5], Iter[3700] Loss: 1.50 Validation Results - Epoch[4/5] Avg Accuracy: 0.94 Avg Loss: 1.53 Epoch[5/5], Iter[3800] Loss: 1.52 Epoch[5/5], Iter[3900] Loss: 1.60 Epoch[5/5], Iter[4000] Loss: 1.50 Epoch[5/5], Iter[4100] Loss: 1.50 Epoch[5/5], Iter[4200] Loss: 1.51 Epoch[5/5], Iter[4300] Loss: 1.57 Epoch[5/5], Iter[4400] Loss: 1.56 Epoch[5/5], Iter[4500] Loss: 1.55 Epoch[5/5], Iter[4600] Loss: 1.50 Validation Results - Epoch[5/5] Avg Accuracy: 0.94 Avg Loss: 1.52
State: iteration: 4690 epoch: 5 epoch_length: 938 max_epochs: 5 output: 1.5042390823364258 batch: <class 'list'> metrics: <class 'dict'> dataloader: <class 'torch.utils.data.dataloader.DataLoader'> seed: <class 'NoneType'> times: <class 'dict'>
Readers may ignore the next cell.
In [10]python · cell 18
python
! python ../.convert_notebook_to_script.py --input ch13_part3.ipynb --output ch13_part3.pyOutput
[NbConvertApp] Converting notebook ch13_part3.ipynb to script [NbConvertApp] Writing 4864 bytes to ch13_part3.py
