Custom Module and Sequential

Simple tools to provide a Keras-like interface to PyTorch.

source

History

This object inherits from base dict to provide a History object similar to Keras’, allowing the automatic logging of the loss and the different metrics during training. It’s automatically used in .fit() (as it is in Keras).


source

Module

 Module (**kwargs)

Modification of PyTorch base nn.Module to provide a basic predefined training loop with logging and a Keras-like interface to be able to customize the training. This Module implements as well a .compile() method and an .evaluate() one. All is done to obtain a behaviour as similar to Keras as possible.


source

Module.fit

 Module.fit (trainloader:torch.utils.data.dataloader.DataLoader, epochs,
             validationloader=None)

Fit a model to the desired trainloader for epochs epochs. Returns the corresponding History.

Type Default Details
trainloader DataLoader Training DataLoader.
epochs Number of epochs to train.
validationloader NoneType None Validation DataLoader (optional).
Returns History History object with the training dynamics as in Keras.

source

Module.compile

 Module.compile (loss:Optional=None,
                 optimizer:Optional[torch.optim.optimizer.Optimizer]=None,
                 metrics=None)

Sets the loss, optimizer and desired metrics to train the model.

Type Default Details
loss Optional None Loss function to be used.
optimizer Optional None Optimizer to be used.
metrics NoneType None MetricCollection containing the desired metrics.

source

Module.evaluate

 Module.evaluate (dataloader)

Evaluates the model on a set of data.

Type Details
dataloader DataLoader to evaluate the model with.
Returns Dict Results from the evaluation

Example of usage

We can perform a very simple example using the Fashion MNIST dataset (as is done in the official PyTorch docs.

transform = transforms.Compose(
    [transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))])

# Create datasets for training & validation, download if necessary
training_set = torchvision.datasets.FashionMNIST('./data', train=True, transform=transform, download=True)
validation_set = torchvision.datasets.FashionMNIST('./data', train=False, transform=transform, download=True)

# Create data loaders for our datasets; shuffle for training, not for validation
training_loader = torch.utils.data.DataLoader(training_set, batch_size=128, shuffle=True, num_workers=0)
validation_loader = torch.utils.data.DataLoader(validation_set, batch_size=256, shuffle=False, num_workers=0)

See that the only different with respect to basic PyTorch is that we’re inhereting from our custom Module, not from PyTorch’s nn.Module:

class SimpleModel(Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 4 * 4, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 4 * 4)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

Following the usual Keras way, we instantiate the model and compile it, providing the loss and the optimizer:

model = SimpleModel()
model.compile(loss=torch.nn.CrossEntropyLoss(),
              optimizer=torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9),
              metrics = MetricCollection([Accuracy()]))
model
SimpleModel(
  (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
  (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  (fc1): Linear(in_features=256, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
  (loss_fn): CrossEntropyLoss()
  (metrics): MetricCollection(
    (Accuracy): Accuracy()
  )
)
model.evaluate(training_loader), model.evaluate(validation_loader)
({'Accuracy': 0.11770944386275846, 'Loss': 2.3061464941069514},
 {'Accuracy': 0.12353515625, 'Loss': 2.3057154595851896})
history = model.fit(trainloader=training_loader, epochs=1, validationloader=validation_loader)
history
{'Accuracy': [0.18737784294939752],
 'Loss': [2.2949233914235],
 'Val_Accuracy': [0.2640625],
 'Val_Loss': [2.2760460674762726]}
model.evaluate(training_loader), model.evaluate(validation_loader)
({'Accuracy': 0.25996690654932564, 'Loss': 2.276174947905388},
 {'Accuracy': 0.2640625, 'Loss': 2.2760460674762726})