Skip to content
Snippets Groups Projects
Commit e2498b78 authored by Frisinghelli Daniel's avatar Frisinghelli Daniel
Browse files

Split the configuration files for different types of training and evaluation.

parent 04830e41
No related branches found
No related tags found
No related merge requests found
...@@ -2,9 +2,8 @@ ...@@ -2,9 +2,8 @@
Steps to run a model evaluation: Steps to run a model evaluation:
1. Configure the dictionary ``eval_config`` in 1. Configure the model evaluation in :py:mod:`pysegcnn.main.eval_config.py`
:py:mod:`pysegcnn.main.config.py` 2. Save :py:mod:`pysegcnn.main.eval_config.py`
2. Save :py:mod:`pysegcnn.main.config.py`
3. In a terminal, navigate to the repository's root directory 3. In a terminal, navigate to the repository's root directory
4. Run 4. Run
...@@ -29,7 +28,7 @@ License ...@@ -29,7 +28,7 @@ License
# locals # locals
from pysegcnn.core.trainer import NetworkInference from pysegcnn.core.trainer import NetworkInference
from pysegcnn.main.config import eval_config from pysegcnn.main.eval_config import eval_config
if __name__ == '__main__': if __name__ == '__main__':
......
"""The configuration file to train and evaluate a model.
The configuration is handled by the configuration dictionaries.
Modify the values to your needs, but DO NOT modify the keys.
License
-------
Copyright (c) 2020 Daniel Frisinghelli
This source code is licensed under the GNU General Public License v3.
See the LICENSE file in the repository's root directory.
"""
# !/usr/bin/env python
# -*- coding: utf-8 -*-
# builtins
import pathlib
# locals
from pysegcnn.core.utils import search_files
# path to this file
HERE = pathlib.Path(__file__).resolve().parent
# path to the datasets on the current machine
DRIVE_PATH = pathlib.Path('C:/Eurac/Projects/CCISNOW/_Datasets/')
# DRIVE_PATH = pathlib.Path('/mnt/CEPH_PROJECTS/cci_snow/dfrisinghelli/_Datasets/') # nopep8
# name and paths to the datasets
DATASETS = {'Sparcs': DRIVE_PATH.joinpath('Sparcs'),
'Alcd': DRIVE_PATH.joinpath('Alcd/60m')
}
# name of the target dataset
TRG_DS = 'Alcd'
# spectral bands to use for training
BANDS = ['red', 'green', 'blue', 'nir', 'swir1', 'swir2']
# tile size of a single sample
TILE_SIZE = 128
# the target dataset configuration dictionary
trg_ds = {
'dataset_name': 'Sparcs',
'root_dir': DATASETS[TRG_DS],
'gt_pattern': '(.*)Labels\\.tif',
'bands': BANDS,
'tile_size': TILE_SIZE,
'pad': True,
'sort': True,
'transforms': [],
'merge_labels': {'Cirrus': 'Cloud',
'Not_used': 'No_data'}
}
# the target dataset split configuration dictionary
trg_ds_split = {
# 'split_mode': 'tile',
'split_mode': 'scene',
'k_folds': 1, # keep k_folds=1 for evaluating models
'seed': 0,
'shuffle': True,
'ttratio': 1,
'tvratio': 0.8,
}
# the evaluation configuration
eval_config = {
# -------------------------------------------------------------------------
# ----------------------------- Evaluation --------------------------------
# -------------------------------------------------------------------------
# these options are only used for evaluating a trained model using
# pysegcnn.main.eval.py
# the model(s) to evaluate
'state_files': search_files(HERE, '*.pt'),
# Evaluate on datasets defined at training time ---------------------------
# implicit=True, models are evaluated on the training, validation
# and test datasets defined at training time
# implicit=False, models are evaluated on an explicitly defined dataset
# 'ds'
'implicit': True,
# 'implicit': False,
# The options 'domain' and 'test' define on which domain (source, target)
# and on which set (training, validation, test) to evaluate the model.
# NOTE: If the specified set was not available at training time, an error
# is raised.
# whether to evaluate the model on the labelled source domain or the
# (un)labelled target domain
# if domain='trg', target domain
# if domain='src', source domain
# 'domain': 'src',
'domain': 'trg',
# the subset to evaluate the model on
# test=False, 0 means evaluating on the validation set
# test=True, 1 means evaluating on the test set
# test=None means evaluating on the training set
# 'test': True,
'test': None,
# 'test': False,
# whether to map the model labels from the model source domain to the
# defined 'domain'
# For models trained via unsupervised domain adaptation, the classes of the
# source domain, i.e. the classes the model is trained with, may differ
# from the classes of the target domain. Setting 'map_labels'=True, means
# mapping the source classes to the target classes. Obviously, this is only
# possible if the target classes are a subset of the source classes.
'map_labels': False,
# Evaluate on an explicitly defined dataset -------------------------------
# OPTIONAL: If 'trg_ds' is specified and 'implicit'=False, the model is not
# evaluated on the datasets defined at training time, but on the
# dataset defined by 'trg_ds'.
# the dataset to evaluate the model on (optional)
'ds': trg_ds,
# the dataset split to use for 'ds'
'ds_split': trg_ds_split,
# Evaluation options ------------------------------------------------------
# whether to compute and plot the confusion matrix
# output path is: pysegcnn/main/_graphics/
# 'cm': True,
'cm': False,
# whether to predict each sample or each scene individually
# False: each sample is predicted individually and the scenes are not
# reconstructed
# True: each scene is first reconstructed and then the whole scene is
# predicted at once
# NOTE: this option works only for datasets split by split_mode="scene"
'predict_scene': True,
# whether to save plots of (input, ground truth, prediction) for each scene
# in the train/validation/test dataset to disk, applies if
# predict_scene=True
# output path is: pysegcnn/main/_scenes/
'plot_scenes': True,
# plot_bands defines the bands used to plot a false color composite of
# the input scene: red': bands[0], green': bands[1], blue': bands[2]
'plot_bands': ['nir', 'red', 'green'],
# size of the figures
'figsize': (16, 9),
# degree of constrast stretching for false color composite
'alpha': 5
}
"""The configuration file to train a model on a single domain.
The configuration is handled by the configuration dictionaries.
Modify the values to your needs, but DO NOT modify the keys.
The models can be trained with :py:mod:`pysegcnn.main.train_source.py`.
License
-------
Copyright (c) 2020 Daniel Frisinghelli
This source code is licensed under the GNU General Public License v3.
See the LICENSE file in the repository's root directory.
"""
# !/usr/bin/env python
# -*- coding: utf-8 -*-
# builtins
import pathlib
# from pysegcnn.core.transforms import Augment, FlipLr, FlipUd, Noise
# path to this file
HERE = pathlib.Path(__file__).resolve().parent
# path to the datasets on the current machine
DRIVE_PATH = pathlib.Path('C:/Eurac/Projects/CCISNOW/_Datasets/')
# DRIVE_PATH = pathlib.Path('/mnt/CEPH_PROJECTS/cci_snow/dfrisinghelli/_Datasets/') # nopep8
# name and paths to the datasets
DATASETS = {'Sparcs': DRIVE_PATH.joinpath('Sparcs'),
'Alcd': DRIVE_PATH.joinpath('Alcd/60m')
}
# name of the dataset
DS_NAME = 'Sparcs'
# spectral bands to use for training
BANDS = ['red', 'green', 'blue', 'nir', 'swir1', 'swir2']
# tile size of a single sample
TILE_SIZE = 128
# number of folds for cross validation
K_FOLDS = 1
# the source dataset configuration dictionary
ds_config = {
# -------------------------------------------------------------------------
# Dataset -----------------------------------------------------------------
# -------------------------------------------------------------------------
# name of the dataset
'dataset_name': DS_NAME,
# path to the dataset
'root_dir': DATASETS[DS_NAME],
# a regex pattern to match the ground truth file naming convention
'gt_pattern': '(.*)mask\\.png',
# 'gt_pattern': '(.*)class\\.img',
# define the bands to use to train the segmentation network:
# either a list of bands, e.g. ['red', 'green', 'nir', 'swir2', ...]
# or [], which corresponds to using all available bands
# IMPORTANT: the list of bands should be equal for the source and target
# domains, when using any sort of transfer learning
'bands': BANDS,
# define the size of the network input
# if None, the size will default to the size of a scene
'tile_size': TILE_SIZE,
# whether to central pad the scenes with a constant value
# if True, padding is used if the scenes are not evenly divisible into
# tiles of size (tile_size, tile_size)
# 'pad': False,
'pad': True,
# whether to sort the dataset in chronological order, useful for time
# series data
# 'sort': True,
'sort': False,
# whether to artificially increase the training data size using data
# augmentation methods
# Supported data augmentation methods are:
# - FlipLr: horizontally flip an image
# - FlipUd: vertically flip an image
# - Noise: add gaussian noise with defined mean and variance to an image
# two modes for adding noise are available
# - speckle: image = image + image * noise,
# - add: image = image + noise
# pixel values = exclude (default=0) are not modified by adding
# noise (i.e., the "no data" pixels added by the padding)
# More detail can be found in pytorch.transforms.py
# A probability can be assigned to each transformation so that it may or
# may not be applied, thus
# - set p=1 to a transformation to always apply it
# - set p=0 to a transformation to never apply it
# - set 0 < p < 1 to apply a transformation with randomness
# transforms is a list of transformations to apply to the original data
# if transforms=[], no transformation is applied and only the original
# dataset is used
'transforms': [],
# if you provide lists to transforms, each list represents a distinct
# transformation of the original dataset
# here an example if you want to perform two sets of transformations:
# 1: FlipLr + Noise
# 2: FlipLr + Noise + FlipUd
# the resulting dataset will have 3 times the size of the original dataset,
# i.e. the original dataset + the two transformed versions of it
# 'transforms': [
# Augment([
# FlipLr(p=0.5),
# Noise(mode='speckle', mean=0, var=0.1, p=0.5, exclude=0)
# ]),
# Augment([
# FlipLr(p=0.5),
# Noise(mode='speckle', mean=0, var=0.1, p=0.5, exclude=0),
# FlipUd(p=0.5)
# ]),
# ],
# The label mapping dictionary, where each (key, value) pair represents a
# distinct label mapping. The keys are the labels to be mapped and the
# values are the corresponding labels to be mapped to.
# NOTE: Passing an empty dictionary means all labels are preserved as is
# 'merge_labels': {}
'merge_labels': {'Shadow_over_water': 'Shadow',
'Flooded': 'Land'}
# EXAMPLE: merge label class 'Shadow over Water' to label class 'Shadow'
# 'merge_labels': {'Shadow_over_water': 'Shadow'}
}
# the source dataset split configuration dictionary
ds_split_config = {
# -------------------------------------------------------------------------
# Dataset split -----------------------------------------------------------
# -------------------------------------------------------------------------
# the mode to split the dataset:
#
# - 'tile': for each scene, the tiles can be distributed among the
# training, validation and test set
#
# - 'scene': for each scene, all the tiles of the scene are included in
# either the training set, the validation set or the test
# set, respectively
# 'split_mode': 'tile',
'split_mode': 'scene',
# the number of folds for cross validation
#
# k_folds = 1 : The model is trained with a single dataset split based on
# 'tvratio' and 'ttratio'
# k_folds > 1 : The model is trained via cross validation on k_folds splits
# of the dataset
'k_folds': K_FOLDS,
# the random seed for the random number generator
# ensures reproducibility of the training, validation and test data split
'seed': 0,
# whether to shuffle the data before splitting
'shuffle': True,
# -------------------------------------------------------------------------
# IMPORTANT: these setting only apply if 'kfolds=1'
# -------------------------------------------------------------------------
# (ttratio * 100) % of the dataset will be used for training and
# validation
# used if 'kfolds=1'
'ttratio': 1,
# (ttratio * tvratio) * 100 % will be used for training
# (1 - ttratio * tvratio) * 100 % will be used for validation
# used if 'kfolds=1'
'tvratio': 0.8,
}
# the model configuration dictionary
model_config = {
# -------------------------------------------------------------------------
# Network -----------------------------------------------------------------
# -------------------------------------------------------------------------
# define the model
'model_name': 'Segnet',
# -------------------------------------------------------------------------
# Optimizer ---------------------------------------------------------------
# -------------------------------------------------------------------------
# define an optimizer to update the network weights
'optim_name': 'Adam',
# optimizer keyword arguments
'optim_kwargs': {
'lr': 0.001, # the learning rate
'weight_decay': 0, # the weight decay rate
'amsgrad': False # whether to use AMSGrad variant (for Adam)
},
# -------------------------------------------------------------------------
# Training configuration --------------------------------------------------
# -------------------------------------------------------------------------
# whether to save the model state to disk
# model states are saved in: pysegcnn/main/_models
# model log files are saved in: pysegcnn/main/_logs
'save': True,
# whether to resume training from an existing model checkpoint
'checkpoint': False,
# define the batch size
# determines how many samples of the dataset are processed until the
# weights of the network are updated (via mini-batch gradient descent)
'batch_size': 128,
# the seed for the random number generator intializing the network weights
'torch_seed': 0,
# whether to early stop training if the accuracy (loss) on the validation
# set does not increase (decrease) more than delta over patience epochs
# -------------------------------------------------------------------------
# The early stopping metric is chosen as:
# - validation set accuracy if mode='max'
# - validation set loss if mode='min'
# -------------------------------------------------------------------------
'early_stop': True,
'mode': 'max',
'delta': 0,
'patience': 10,
# define the number of epochs: the number of maximum iterations over
# the whole training dataset
'epochs': 100,
}
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
Steps to launch a model run: Steps to launch a model run:
1. Configure the model run in :py:mod:`pysegcnn.main.config.py` 1. Configure the model run in :py:mod:`pysegcnn.main.train_config.py`
- configure the dataset : ``src_ds_config`` - configure the dataset : ``ds_config``
- configure the split : ``src_ds_config` - configure the split : ``ds_split_config`
- configure the model : ``model_config`` - configure the model : ``model_config``
2. Save :py:mod:`pysegcnn.main.config.py` 2. Save :py:mod:`pysegcnn.main.train_config.py`
3. In a terminal, navigate to the repository's root directory 3. In a terminal, navigate to the repository's root directory
4. Run 4. Run
.. code-block:: bash .. code-block:: bash
python pysegcnn/main/train.py python pysegcnn/main/train_source.py
License License
...@@ -36,16 +36,15 @@ from logging.config import dictConfig ...@@ -36,16 +36,15 @@ from logging.config import dictConfig
from pysegcnn.core.trainer import (DatasetConfig, SplitConfig, ModelConfig, from pysegcnn.core.trainer import (DatasetConfig, SplitConfig, ModelConfig,
StateConfig, LogConfig, StateConfig, LogConfig,
ClassificationNetworkTrainer) ClassificationNetworkTrainer)
from pysegcnn.main.config import (src_ds_config, src_split_config, from pysegcnn.main.train_config import ds_config, ds_split_config, model_config
model_config)
from pysegcnn.core.logging import log_conf from pysegcnn.core.logging import log_conf
if __name__ == '__main__': if __name__ == '__main__':
# (i) instanciate the source domain configurations # (i) instanciate the source domain configurations
src_dc = DatasetConfig(**src_ds_config) # source domain dataset src_dc = DatasetConfig(**ds_config) # source domain dataset
src_sc = SplitConfig(**src_split_config) # source domain dataset split src_sc = SplitConfig(**ds_split_config) # source domain dataset split
# (ii) instanciate the model configuration # (ii) instanciate the model configuration
net_mc = ModelConfig(**model_config) net_mc = ModelConfig(**model_config)
...@@ -97,4 +96,5 @@ if __name__ == '__main__': ...@@ -97,4 +96,5 @@ if __name__ == '__main__':
) )
# (xii) train the model # (xii) train the model
LogConfig.init_log('Fold {} / {}'.format(fold + 1, len(src_folds)))
training_state = trainer.train() training_state = trainer.train()
"""Main script to train a model using transfer learning.
Steps to launch a model run:
1. Configure the model run in
:py:mod:`pysegcnn.main.train_transfer_config.py`
- configure the dataset(s) : ``src_ds_config`` and ``trg_ds_config``
- configure the split(s) : ``src_ds_config`` and ``trg_ds_config``
- configure the model : ``model_config``
- configure transfer learning: ``tlda_config``
2. Save :py:mod:`pysegcnn.main.train_transfer_config.py`
3. In a terminal, navigate to the repository's root directory
4. Run
.. code-block:: bash
python pysegcnn/main/train_transfer.py
License
-------
Copyright (c) 2020 Daniel Frisinghelli
This source code is licensed under the GNU General Public License v3.
See the LICENSE file in the repository's root directory.
"""
# !/usr/bin/env python
# -*- coding: utf-8 -*-
# builtins
from logging.config import dictConfig
# locals
from pysegcnn.core.trainer import (
DatasetConfig, SplitConfig, ModelConfig, TransferLearningConfig,
StateConfig, LogConfig, DomainAdaptationTrainer)
from pysegcnn.main.train_transfer_config import (
src_ds_config, src_split_config, trg_ds_config, trg_split_config,
model_config, tlda_config)
from pysegcnn.core.logging import log_conf
if __name__ == '__main__':
# (i) instanciate the source domain configurations
src_dc = DatasetConfig(**src_ds_config) # source domain dataset
src_sc = SplitConfig(**src_split_config) # source domain dataset split
# (ii) instanciate the target domain configuration
trg_dc = DatasetConfig(**trg_ds_config) # target domain dataset
trg_sc = SplitConfig(**trg_split_config) # target domain dataset split
# (iii) instanciate the datasets to train the model on
src_ds = src_dc.init_dataset()
trg_ds = trg_dc.init_dataset()
# (iv) instanciate the model configuration
net_mc = ModelConfig(**model_config)
# (v) instanciate transfer learning configuration
trn_sf = TransferLearningConfig(**tlda_config)
# (vi) instanciate the model state configuration
net_sc = StateConfig()
# (vii) instanciate the source training, validation and test dataset folds
src_folds = src_sc.train_val_test_split(src_ds)
# (viii) instanciate the target training, validation and test dataset folds
trg_folds = trg_sc.train_val_test_split(trg_ds)
# (ix) iterate over the different folds
for fold, (src_fold, trg_fold) in enumerate(zip(src_folds, trg_folds)):
# (x) the source dataloaders
src_tra_dl, src_val_dl, src_tes_dl = src_sc.dataloaders(
*src_fold.values(), batch_size=net_mc.batch_size, shuffle=True,
drop_last=False)
# (xi) the target dataloaders
trg_tra_dl, trg_val_dl, trg_tes_dl = trg_sc.dataloaders(
*trg_fold.values(), batch_size=net_mc.batch_size, shuffle=True,
drop_last=False)
# (xii) instanciate the model state file
state_file = net_sc.init_state(src_dc, src_sc, net_mc,
trg_dc=trg_dc, trg_sc=trg_sc, tc=trn_sf,
fold=fold)
# (xiii) instanciate logging configuration
net_lc = LogConfig(state_file)
dictConfig(log_conf(net_lc.log_file))
# (xiv) instanciate the model
if trn_sf.supervised or trn_sf.uda_from_pretrained:
# check whether to load a pretrained model for (un)supervised
# transfer learning
net, optimizer, checkpoint = trn_sf.transfer_model(
trn_sf.pretrained_path,
nclasses=len(src_ds).labels,
optim_kwargs=net_mc.optim_kwargs,
freeze=trn_sf.freeze)
else:
# initialize model from scratch or from an existing model
# checkpoint
net, optimizer, checkpoint = net_mc.init_model(
len(src_ds.use_bands), len(src_ds.labels), state_file)
# (xv) instanciate the network trainer class
trainer = DomainAdaptationTrainer(
model=net,
optimizer=optimizer,
state_file=net.state_file,
src_train_dl=src_tra_dl,
src_valid_dl=src_val_dl,
src_test_dl=src_tes_dl,
epochs=net_mc.epochs,
nthreads=net_mc.nthreads,
early_stop=net_mc.early_stop,
mode=net_mc.mode,
delta=net_mc.delta,
patience=net_mc.patience,
checkpoint_state=checkpoint,
save=net_mc.save,
supervised=trn_sf.supervised,
trg_train_dl=trg_tra_dl,
trg_valid_dl=trg_val_dl,
trg_test_dl=trg_tes_dl,
uda_loss_function=trn_sf.uda_loss_function,
uda_lambda=trn_sf.uda_lambda,
uda_pos=trn_sf.uda_pos)
# (xvi) train the model
LogConfig.init_log('Fold {} / {}'.format(fold + 1, len(src_folds)))
training_state = trainer.train()
...@@ -243,7 +243,7 @@ model_config = { ...@@ -243,7 +243,7 @@ model_config = {
# optimizer keyword arguments # optimizer keyword arguments
'optim_kwargs': { 'optim_kwargs': {
'lr': 0.001, # the learning rate 'lr': 0.001, # the learning rate
'weight_decay': 0.01, # the weight decay rate 'weight_decay': 0, # the weight decay rate
'amsgrad': False # whether to use AMSGrad variant (for Adam) 'amsgrad': False # whether to use AMSGrad variant (for Adam)
}, },
...@@ -358,101 +358,4 @@ tlda_config = { ...@@ -358,101 +358,4 @@ tlda_config = {
# whether to freeze the pretrained model weights # whether to freeze the pretrained model weights
'freeze': True, 'freeze': True,
}
# the evaluation configuration
eval_config = {
# -------------------------------------------------------------------------
# ----------------------------- Evaluation --------------------------------
# -------------------------------------------------------------------------
# these options are only used for evaluating a trained model using
# pysegcnn.main.eval.py
# the model(s) to evaluate
'state_files': [''],
# Evaluate on datasets defined at training time ---------------------------
# implicit=True, models are evaluated on the training, validation
# and test datasets defined at training time
# implicit=False, models are evaluated on an explicitly defined dataset
# 'ds'
'implicit': True,
# 'implicit': False,
# The options 'domain' and 'test' define on which domain (source, target)
# and on which set (training, validation, test) to evaluate the model.
# NOTE: If the specified set was not available at training time, an error
# is raised.
# whether to evaluate the model on the labelled source domain or the
# (un)labelled target domain
# if domain='trg', target domain
# if domain='src', source domain
# 'domain': 'src',
'domain': 'trg',
# the subset to evaluate the model on
# test=False, 0 means evaluating on the validation set
# test=True, 1 means evaluating on the test set
# test=None means evaluating on the training set
# 'test': True,
'test': None,
# 'test': False,
# whether to map the model labels from the model source domain to the
# defined 'domain'
# For models trained via unsupervised domain adaptation, the classes of the
# source domain, i.e. the classes the model is trained with, may differ
# from the classes of the target domain. Setting 'map_labels'=True, means
# mapping the source classes to the target classes. Obviously, this is only
# possible if the target classes are a subset of the source classes.
'map_labels': False,
# Evaluate on an explicitly defined dataset -------------------------------
# OPTIONAL: If 'ds' is specified and 'implicit'=False, the model is not
# evaluated on the datasets defined at training time, but on the
# dataset defined by 'ds'.
# the dataset to evaluate the model on (optional)
'ds': trg_ds_config,
# the dataset split to use for 'ds'
'ds_split': trg_split_config,
# Evaluation options ------------------------------------------------------
# whether to compute and plot the confusion matrix
# output path is: pysegcnn/main/_graphics/
# 'cm': True,
'cm': False,
# whether to predict each sample or each scene individually
# False: each sample is predicted individually and the scenes are not
# reconstructed
# True: each scene is first reconstructed and then the whole scene is
# predicted at once
# NOTE: this option works only for datasets split by split_mode="scene" or
# split_mode="date"
'predict_scene': True,
# whether to save plots of (input, ground truth, prediction) for each scene
# in the train/validation/test dataset to disk, applies if
# predict_scene=True
# output path is: pysegcnn/main/_scenes/
'plot_scenes': True,
# plot_bands defines the bands used to plot a false color composite of
# the input scene: red': bands[0], green': bands[1], blue': bands[2]
'plot_bands': ['nir', 'red', 'green'],
# size of the figures
'figsize': (16, 9),
# degree of constrast stretching for false color composite
'alpha': 5
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment