Intro to Configuration

ganslate's configuration system is based on OmegaConf. If you have used hydra, you might already be familiar with it. Otherwise, please refer to OmegaConf documentation

Configuring a Run

Setting up an experiment is done through a YAML file. This is an example of a run on cityscapes dataset:

# Project path from which custom, non-framework, can be loaded.
# If not using any custom code, set it to `null`
project: "./projects/cityscapes_label2photo/"

train:
    output_dir: "./checkpoints/label2photo_cyclegan/"
    cuda: True
    n_iters: 297500  # 2975 images x 100 epochs 
    n_iters_decay: 297500
    batch_size: 1
    mixed_precision: False

    logging:
        freq: 100
        wandb:
            project: "cityscapes_label2photo"
            run: "cyclegan_trial"

    checkpointing:
        freq: 10000

    dataset: 
        # TODO: this should be PairedImageDataset i think
        _target_: project.datasets.Label2PhotoDataset
        root: "~/Downloads/Datasets/Cityscapes_label2photo/train"
        load_size: [572, 286]
        crop_size: [512, 256]
        paired: False  # Unpaired, for training
        random_flip: True
        random_crop: True
        masking: False
        num_workers: 8

    gan:  
        _target_: ganslate.nn.gans.unpaired.CycleGAN

        generator:  
            _target_: ganslate.nn.generators.Resnet2D
            n_residual_blocks: 9
            in_channels: 3
            out_channels: 3

        discriminator:  
            _target_: ganslate.nn.discriminators.PatchGAN2D
            n_layers: 3
            in_channels: 3

        optimizer:
            lr_D: 0.0002
            lr_G: 0.0002
            lambda_AB: 10.0
            lambda_BA: 10.0
            lambda_identity: 0
            proportion_ssim: 0

    metrics:
        discriminator_evolution: True
        ssim: True


val:
    freq: 200

    dataset: 
        _target_: project.datasets.Label2PhotoDataset
        root: "~/Downloads/Datasets/Cityscapes_label2photo/val"
        load_size: [512, 256]
        paired: True  # Paired, to compute similarity metrics 
        random_flip: False
        random_crop: False
        masking: False
        num_workers: 8

    metrics:
        cycle_metrics: False

# test:
    # Not defined

# infer:
    # Not defined

Config structure overview

At the root level, the configuration is separated into train, val, test, and inference. Each of these phases has a separate configuration, but some options in val, test, and inference default to their equivalents in train. For example, since gan isn't specified in val, it is interpolated (copied) from train, using OmegaConf's interpolation.
You don't need to define all the phases at once - running ganslate train uses train and, if defined, val config. With ganslate test it will only need the test config, and with ganslate infer the infer config.

At the sub-root levels, the configurations are separated into logical units such as checkpointing, logging, gan, etc. When an option's default value works for the experiment, you can ommit it in YAML. For example, train.checkpointing has the tensorboard option set to False by default. As a result, you don't have to explicitly set it to False when you don't want to log with tensorboard.

Note

Description of all configuration options can be found here.

Note

ganslate logs the whole config, including the default and overriden values, at the start of each run.

Overriding config from the command line

If you need a quick override of an option, you can do so from the command line instead of modifying the YAML file. For example, specifying another path to the training dataset from the command line would look like this:

ganslate train config=<CONFIG_PATH> train.dataset.root=./Downloads/cityscapes/train/

Configuration Structure Definition

The configuration structure in ganslate is defined using Python dataclasses and OmegaConf. Defining config like that enables modular config design, so that options differ based on the architecture, dataset, or some other choice. Additionally, it enables static type checking.

The following is CycleGAN's config structure:

from dataclasses import dataclass
from ganslate import configs

@dataclass
class CycleGANConfig(configs.base.BaseGANConfig):
    """CycleGAN Config"""
    pool_size: int = 50
    optimizer: OptimizerConfig = OptimizerConfig

CycleGANConfig specifies two different options: pool_size, and optimizer. Each has the type specified as well as the default value. For instance, pool_size option needs to be an int and defaults to 50. If we tried to set pool_size to a string "fifty", OmegaConf would raise an error.

We can also see that CycleGANConfig inherits from configs.base.BaseGANConfig. BaseGANConfig is an abstraction of a GAN config, and defines several options necessary for any GAN.

from dataclasses import dataclass
from omegaconf import MISSING

@dataclass
class BaseGANConfig:
    """Base GAN config."""
    _target_: str = MISSING  # refers to the class that this config describes
    norm_type: str = "instance"
    weight_init_type: str = "normal"
    weight_init_gain: float = 0.02

    optimizer: BaseOptimizerConfig = MISSING
    generator: BaseGeneratorConfig = MISSING
    # Discriminator optional as it is not used in inference
    discriminator: Optional[BaseDiscriminatorConfig] = None

As a result of inheriting from it, CycleGANConfig has the options defined in BaseGANConfig, such as norm_type or generator.

Note

When writing custom architecture or dataset classes, you also need to write such dataclass configs for them, as demonstrated in Custom Architecture and Custom Dataset sections.