Quickstart

Starting a project

After installing pytorch, we need to clone bootstrap.pytorch. In this example, we will build our new project upon the existing mnist.bootstrap.pytorch submodule.

git clone https://github.com/Cadene/bootstrap.pytorch.git
cd bootstrap.pytorch
git submodule update --init mnist

Running an experiment

To display parsed options from the yaml file:

python -m bootstrap.run
       -o mnist/options/sgd.yaml
       -h

To run an experiment (training + evaluation):

python -m bootstrap.run
       -o mnist/options/sgd.yaml

You can also overwrite default options using the command line:

python -m bootstrap.run
       -o mnist/options/sgd.yaml
       --exp.dir logs/mnist/my_sgd

Running an experiment will create 4 files in your experiment directory (logs/mnist/my_sgd):

  • options.yaml contains the options used for the experiment;
  • logs.txt contains all the information printed by the logger;
  • logs.json contains trainin data logs, such as: train_epoch.loss, train_batch.loss, eval_epoch.accuracy_top1, etc;
  • view.html contains training and evaluation curves with javascript utilities (plotly).

Depending on your options, some checkpoints may also be created:

ls logs/mnist/my_sgd
> ckpt_last_engine.pth.tar
  ckpt_last_model.pth.tar
  ckpt_last_optimizer.pth.tar
  ckpt_best_acctop1_engine.pth.tar
  ckpt_best_acctop1_model.pth.tar
  ckpt_best_acctop1_optimizer.pth.tar
  logs.json
  logs.txt
  options.yaml
  view.html

Then, a model can be easily initialized from a checkpoint in order to resume training. You can also choose which checkpoint to initialize it from:

python -m bootstrap.run
       -o logs/mnist/my_sgd/options.yaml
       --exp.resume last

Evaluating a trained model is also simple. This time, let’s suppose you want to evaluate your model on the test set, but loading the checkpoint with the best top-1 accuracy on the validation set. The command then becomes:

python -m bootstrap.run
       -o logs/mnist/my_sgd/options.yaml
       --exp.resume best_acctop1
       --dataset.train_split
       --dataset.eval_split test

Adding a custom network

Create a new torch.nn.Module in mnist/models/networks/my_net.py.

import torch.nn as nn
import torch.nn.functional as F

class MyNet(nn.Module):

    def __init__(self, mul=2, drop=0.2):
        super(MyNet, self).__init__()
        self.mul = mul
        self.drop = drop
        self.conv1 = nn.Conv2d(1, 10*mul, kernel_size=5)
        self.conv2 = nn.Conv2d(10*mul, 20*mul, kernel_size=5)
        self.conv2_drop = nn.Dropout2d()
        self.fc1 = nn.Linear(320*mul, 50*mul)
        self.fc2 = nn.Linear(50*mul, 10)

    def forward(self, x):
        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
        x = x.view(-1, 320*self.mul)
        x = F.relu(self.fc1(x))
        x = F.dropout(x, p=self.drop, training=self.training)
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)

Add a new options yaml file for it in mnist/options/my_net.yaml:

exp:
  dir: logs/mnist/my_net
  resume: # last, best_[...], or empty (from scratch)
dataset:
  import: mnist.datasets.factory
  name: mnist
  dir: data/mnist
  train_split: train
  eval_split: val
  nb_threads: 4
  batch_size: 64
model:
  name: simple
  network:
    import: mnist.models.networks.factory
    name: my_net
    mul: 2
    drop: 0.2
  criterion:
    name: nll
  metric:
    name: accuracy
    topk: [1,5]
optimizer:
  name: sgd
  lr: 0.01
  momentum: 0.5
engine:
  name: default
  debug: False
  nb_epochs: 10
  print_freq: 10
  saving_criteria:
  - loss:min          # save when new_best < best
  - accuracy_top1:max # save when new_best > best
  - accuracy_top5:max # save when new_best > best
misc:
  cuda: False
  seed: 1337
view:
- logs:train_epoch.loss+logs:eval_epoch.loss
- logs:train_batch.loss
- logs:train_epoch.accuracy_top1+logs:eval_epoch.accuracy_top1
- logs:train_epoch.accuracy_top5+logs:eval_epoch.accuracy_top5

We could also extend the current mnist/options/abstract.yaml options file:

__include__: abstract.yaml
exp:
  dir: logs/mnist/my_net
model:
  network:
    name: my_net
    mul: 2
    drop: 0.2

Finally, add your new network in the factory in mnist/models/networks/factory.py.

from .net import Net
from .my_net import MyNet

def factory(engine=None):

  Logger()('Creating mnist network...')

  if Options()['model']['network']['name'] == 'net':
      network = Net()

  elif Options()['model']['network']['name'] == 'my_net':
      opt = Options()['model.network']
      network = MyNet(
          mul=opt['mul'],
          drop=opt['drop']
      )

  else:
      raise ValueError()

  if Options()['misc']['cuda'] and len(utils.available_gpu_ids()) >= 2:
          network = DataParallel(network)

  return network

Adding a custom criterion

Adding a custom metric

Adding a custom dataset

Adding a custom workflow

python -m mnist.custom_run
       -o logs/mnist/my_sgd/options.yaml
       --exp.resume best_acctop1
       --dataset.train_split
       --dataset.eval_split test