diff --git a/pysegcnn/core/__init__.py b/pysegcnn/core/__init__.py
index 388c61c288ec765b56e7f5a0e0a67d222cc3d1a4..d6c1e9353720b591eb71100148ff1e8f23a4f73e 100644
--- a/pysegcnn/core/__init__.py
+++ b/pysegcnn/core/__init__.py
@@ -1,7 +1,2 @@
+# !/usr/bin/env python
 # -*- coding: utf-8 -*-
-"""
-Created on Tue Jun 30 09:38:26 2020
-
-@author: Daniel
-"""
-
diff --git a/pysegcnn/core/constants.py b/pysegcnn/core/constants.py
index b64b17b52674e2e6936e5b76b6a2bb5d3458d23c..ffe0e82e33f73e83e23e9745f40ee9cb3b16413c 100644
--- a/pysegcnn/core/constants.py
+++ b/pysegcnn/core/constants.py
@@ -1,4 +1,15 @@
-"""A collection of enumerations of constant values."""
+"""A collection of constant values.
+
+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 -*-
diff --git a/pysegcnn/core/dataset.py b/pysegcnn/core/dataset.py
index d09b713630f5520ad3dd9b4c73cf796fe51af08c..55f23e088a4a73e5a89aaf55460e5851a4d94aaf 100644
--- a/pysegcnn/core/dataset.py
+++ b/pysegcnn/core/dataset.py
@@ -6,6 +6,16 @@ during model training.
 
 For any kind of image-like dataset, inherit the ImageDataset class to create
 your custom dataset.
+
+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
diff --git a/pysegcnn/core/graphics.py b/pysegcnn/core/graphics.py
index e760d9dda5c3b995bd406db3e0bf5424476a703f..5303d9741e0b0ac7ce26471b681e734fe31b6a52 100644
--- a/pysegcnn/core/graphics.py
+++ b/pysegcnn/core/graphics.py
@@ -1,4 +1,15 @@
-"""Functions to plot multispectral image data and model output."""
+"""Functions to plot multispectral image data and model output.
+
+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 -*-
diff --git a/pysegcnn/core/layers.py b/pysegcnn/core/layers.py
index ab6c59a1b85b5c1f9065a54c807b315fb2b60633..d9585551f95065d805305167d5aa4b0a563c0302 100644
--- a/pysegcnn/core/layers.py
+++ b/pysegcnn/core/layers.py
@@ -1,4 +1,15 @@
-"""Layers of a convolutional encoder-decoder network."""
+"""Layers of a convolutional encoder-decoder network.
+
+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 -*-
diff --git a/pysegcnn/core/logging.py b/pysegcnn/core/logging.py
index 283b6ca734704a14f84da59e908101e6427510bb..edcdbbd58daae0a9346775186d0e2af868584198 100644
--- a/pysegcnn/core/logging.py
+++ b/pysegcnn/core/logging.py
@@ -1,4 +1,15 @@
-"""Logging configuration."""
+"""Logging configuration.
+
+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 -*-
diff --git a/pysegcnn/core/models.py b/pysegcnn/core/models.py
index 0cd85f4db17a8bf3938d4865280d0674be1ebaeb..df3c3a697cdb124a1d64992e80d33ad4a8ae2a37 100644
--- a/pysegcnn/core/models.py
+++ b/pysegcnn/core/models.py
@@ -1,4 +1,15 @@
-"""Neural networks for semantic image segmentation."""
+"""Neural networks for semantic image segmentation.
+
+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 -*-
diff --git a/pysegcnn/core/predict.py b/pysegcnn/core/predict.py
index 17dffb68690512bddb52a0eaae43d1e2b1a16761..d3798d9a56cc787c138ddc0cba890c43a97f862b 100644
--- a/pysegcnn/core/predict.py
+++ b/pysegcnn/core/predict.py
@@ -1,4 +1,15 @@
-"""Functions for model inference."""
+"""Functions for model inference.
+
+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 -*-
diff --git a/pysegcnn/core/split.py b/pysegcnn/core/split.py
index 2be0aacbc7e9d56cdb5674b6651de16054a0ad71..db63f78847a2099b6c709a75c30fea21f9c148f6 100644
--- a/pysegcnn/core/split.py
+++ b/pysegcnn/core/split.py
@@ -1,4 +1,15 @@
-"""Split the dataset to training, validation and test set."""
+"""Split the dataset into training, validation and test set.
+
+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 -*-
diff --git a/pysegcnn/core/trainer.py b/pysegcnn/core/trainer.py
index 1e0916147652bae3c52e4ec59f33c35a81826366..92014fb84f49539e627448a15d3fde1d5c583635 100644
--- a/pysegcnn/core/trainer.py
+++ b/pysegcnn/core/trainer.py
@@ -1,4 +1,20 @@
-"""Model configuration and training."""
+"""Model configuration and training.
+
+This module provides an end-to-end framework of dataclasses designed to train
+segmentation models on image datasets.
+
+See pysegcnn/main/train.py for a complete walkthrough.
+
+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 -*-
@@ -70,6 +86,8 @@ class BaseConfig:
 class DatasetConfig(BaseConfig):
     """Dataset configuration class.
 
+    Instanciate a dataset.
+
     Parameters
     ----------
     dataset_name : `str`
@@ -105,6 +123,10 @@ class DatasetConfig(BaseConfig):
         corresponding ground truth image is padded with a "no data" label.
         The default is False.
 
+    Returns
+    -------
+    None.
+
     """
 
     dataset_name: str
@@ -122,6 +144,8 @@ class DatasetConfig(BaseConfig):
 
         Raises
         ------
+        ValueError
+            Raised if ``dataset_name`` is not supported.
         FileNotFoundError
             Raised if ``root_dir`` does not exist.
         TypeError
@@ -178,6 +202,8 @@ class DatasetConfig(BaseConfig):
 class SplitConfig(BaseConfig):
     """Dataset split configuration class.
 
+    Split a dataset into training, validation and test set.
+
     Parameters
     ----------
     split_mode : `str`
@@ -200,6 +226,10 @@ class SplitConfig(BaseConfig):
         pixels equal to the constant padding value >= ``drop``. ``drop`` = 0
         means, do not drop any samples. The default is 0.
 
+    Returns
+    -------
+    None.
+
     """
 
     split_mode: str
@@ -373,6 +403,8 @@ class SplitConfig(BaseConfig):
 class ModelConfig(BaseConfig):
     """Model configuration class.
 
+    Instanciate a (pretrained) model.
+
     Parameters
     ----------
     model_name : `str`
@@ -435,6 +467,10 @@ class ModelConfig(BaseConfig):
     .. _early stopping:
         https://en.wikipedia.org/wiki/Early_stopping
 
+    Returns
+    -------
+    None.
+
     """
 
     model_name: str
@@ -461,6 +497,8 @@ class ModelConfig(BaseConfig):
     def __post_init__(self):
         """Check the type of each argument.
 
+        Configure path to save model state.
+
         Raises
         ------
         ValueError
@@ -547,7 +585,7 @@ class ModelConfig(BaseConfig):
             An instance of `pysegcnn.core.models.Network`.
         optimizer : `torch.optim.Optimizer`
             An instance of `torch.optim.Optimizer`.
-        checkpoint_state : `dict`
+        checkpoint_state : `dict` [`str`, `numpy.ndarray`]
             If the model checkpoint ``state_file`` exists, ``checkpoint_state``
             has keys:
                 ``'ta'``
@@ -618,7 +656,7 @@ class ModelConfig(BaseConfig):
             An instance of `pysegcnn.core.models.Network`.
         optimizer : `torch.optim.Optimizer`
             An instance of `torch.optim.Optimizer`.
-        checkpoint_state : `dict`
+        checkpoint_state : `dict` [`str`, `numpy.ndarray`]
             If the model checkpoint ``state_file`` exists, ``checkpoint_state``
             has keys:
                 ``'ta'``
@@ -725,15 +763,51 @@ class ModelConfig(BaseConfig):
 
 @dataclasses.dataclass
 class StateConfig(BaseConfig):
+    """Model state configuration class.
+
+    Generate the model state filename according to the following naming
+    convention:
+
+    model_dataset_optimizer_splitmode_splitparams_tilesize_batchsize_bands.pt
+
+    Parameters
+    ----------
+    ds : `pysegcnn.core.dataset.ImageDataset`
+        An instance of `pysegcnn.core.dataset.ImageDataset`.
+    sc : `pysegcnn.core.trainer.SplitConfig`
+        An instance of `pysegcnn.core.trainer.SplitConfig`.
+    mc : `pysegcnn.core.trainer.ModelConfig`
+        An instance of `pysegcnn.core.trainer.SplitConfig`.
+
+    Returns
+    -------
+    None.
+
+    """
+
     ds: ImageDataset
     sc: SplitConfig
     mc: ModelConfig
 
     def __post_init__(self):
+        """Check the type of each argument.
+
+        Returns
+        -------
+        None.
+
+        """
         super().__post_init__()
 
     def init_state(self):
+        """Generate the model state filename.
 
+        Returns
+        -------
+        state : `pathlib.Path`
+            The path to the model state file.
+
+        """
         # file to save model state to:
         # network_dataset_optim_split_splitparams_tilesize_batchsize_bands.pt
 
@@ -787,6 +861,48 @@ class StateConfig(BaseConfig):
 
 @dataclasses.dataclass
 class EvalConfig(BaseConfig):
+    """Model inference configuration.
+
+    Evaluate a model.
+
+    Parameters
+    ----------
+    state_file : `pathlib.Path`
+        Path to the model to evaluate.
+    test : `bool` or `None`
+        Whether to evaluate the model on the training(``test`` = `None`), the
+        validation (``test`` = False) or the test set (``test`` = True).
+    predict_scene : `bool`, optional
+        The model prediction order. If False, the samples (tiles) of a dataset
+        are predicted in any order and the scenes are not reconstructed.
+        If True, the samples (tiles) are ordered according to the scene they
+        belong to and a model prediction for each entire reconstructed scene is
+        returned. The default is False.
+    plot_samples : `bool`, optional
+        Whether to save a plot of false color composite, ground truth and model
+        prediction for each sample (tile). Only used if ``predict_scene`` =
+        False. The default is False.
+    plot_scenes : `bool`, optional
+        Whether to save a plot of false color composite, ground truth and model
+        prediction for each entire scene. Only used if ``predict_scene`` =
+        True. The default is False.
+    plot_bands : `list` [`str`], optional
+        The bands to build the false color composite. The default is
+        ['nir', 'red', 'green'].
+    cm : `bool`, optional
+        Whether to compute and plot the confusion matrix. The default is True.
+    figsize : `tuple`, optional
+        The figure size in centimeters. The default is (10, 10).
+    alpha : `int`, optional
+        The level of the percentiles for contrast stretching of the false color
+        compsite. The default is 0, i.e. no stretching.
+
+    Returns
+    -------
+    None.
+
+    """
+
     state_file: pathlib.Path
     test: object
     predict_scene: bool = False
@@ -799,6 +915,20 @@ class EvalConfig(BaseConfig):
     alpha: int = 5
 
     def __post_init__(self):
+        """Check the type of each argument.
+
+        Configure figure output paths.
+
+        Raises
+        ------
+        TypeError
+            Raised if ``test`` is not of type `bool` or `None`.
+
+        Returns
+        -------
+        None.
+
+        """
         super().__post_init__()
 
         # check whether the test input parameter is correctly specified
@@ -810,7 +940,11 @@ class EvalConfig(BaseConfig):
         self.base_path = pathlib.Path(HERE)
         self.sample_path = self.base_path.joinpath('_samples')
         self.scenes_path = self.base_path.joinpath('_scenes')
-        self.models_path = self.base_path.joinpath('_graphics')
+        self.perfmc_path = self.base_path.joinpath('_graphics')
+
+        # input path for model state files
+        self.models_path = self.base_path.joinpath('_models')
+        self.state_file = self.models_path.joinpath(self.state_file)
 
         # write initialization string to log file
         LogConfig.init_log('{}: ' + 'Evaluating model: {}.'.format(
@@ -819,9 +953,29 @@ class EvalConfig(BaseConfig):
 
 @dataclasses.dataclass
 class LogConfig(BaseConfig):
+    """Logging configuration class.
+
+    Generate the model log file.
+
+    Parameters
+    ----------
+    state_file : `pathlib.Path`
+        Path to a model state file.
+
+    """
+
     state_file: pathlib.Path
 
     def __post_init__(self):
+        """Check the type of each argument.
+
+        Generate model log file.
+
+        Returns
+        -------
+        None.
+
+        """
         super().__post_init__()
 
         # the path to store model logs
@@ -833,11 +987,31 @@ class LogConfig(BaseConfig):
 
     @staticmethod
     def now():
+        """Return the current date and time.
+
+        Returns
+        -------
+        date : `datetime.datetime`
+            The current date and time.
+
+        """
         return datetime.datetime.strftime(datetime.datetime.now(),
                                           '%Y-%m-%dT%H:%M:%S')
 
     @staticmethod
     def init_log(init_str):
+        """Generate a string to identify a new model run.
+
+        Parameters
+        ----------
+        init_str : `str`
+            The string to write to the model log file.
+
+        Returns
+        -------
+        None.
+
+        """
         LOGGER.info(80 * '-')
         LOGGER.info(init_str.format(LogConfig.now()))
         LOGGER.info(80 * '-')
@@ -845,6 +1019,74 @@ class LogConfig(BaseConfig):
 
 @dataclasses.dataclass
 class NetworkTrainer(BaseConfig):
+    """Model training class.
+
+    Generic class to train an instance of `pysegcnn.core.models.Network` on
+    a dataset of type `pysegcnn.core.dataset.ImageDataset`.
+
+    Parameters
+    ----------
+    model : `pysegcnn.core.models.Network`
+        The model to train. An instance of `pysegcnn.core.models.Network`.
+    optimizer : `torch.optim.Optimizer`
+        The optimizer to update the model weights. An instance of
+        `torch.optim.Optimizer`.
+    loss_function : `torch.nn.Module`
+        The loss function to compute the model error. An instance of
+        `torch.nn.Module`.
+    train_dl : `torch.utils.data.DataLoader`
+        The training `torch.utils.data.DataLoader` instance.
+    valid_dl : `torch.utils.data.DataLoader`
+        The validation `torch.utils.data.DataLoader` instance.
+    test_dl : `torch.utils.data.DataLoader`
+        The test `torch.utils.data.DataLoader` instance.
+    state_file : `pathlib.Path`
+        Path to save the model state.
+    epochs : `int`, optional
+        The maximum number of epochs to train. The default is 1.
+    nthreads : `int`, optional
+        The number of cpu threads to use during training. The default is
+        torch.get_num_threads().
+    early_stop : `bool`, optional
+        Whether to apply `early stopping`_. The default is False.
+    mode : `str`, optional
+        The mode of the early stopping. Depends on the metric measuring
+        performance. When using model loss as metric, use ``mode`` = 'min',
+        however, when using accuracy as metric, use ``mode`` = 'max'. For now,
+        only ``mode`` = 'max' is supported. Only used if ``early_stop`` = True.
+        The default is 'max'.
+    delta : `float`, optional
+        Minimum change in early stopping metric to be considered as an
+        improvement. Only used if ``early_stop`` = True. The default is 0.
+    patience : `int`, optional
+        The number of epochs to wait for an improvement in the early stopping
+        metric. If the model does not improve over more than ``patience``
+        epochs, quit training. Only used if ``early_stop`` = True.
+        The default is 10.
+    checkpoint_state : `dict` [`str`, `numpy.ndarray`], optional
+        A model checkpoint for ``model``. If specified, ``checkpoint_state``
+        should be a dictionary with keys:
+            ``'ta'``
+                The accuracy on the training set (`numpy.ndarray`).
+            ``'tl'``
+                The loss on the training set (`numpy.ndarray`).
+            ``'va'``
+                The accuracy on the validation set (`numpy.ndarray`).
+            ``'vl'``
+                The loss on the validation set (`numpy.ndarray`).
+        The default is {}.
+    save : `bool`, optional
+        Whether to save the model state to ``state_file``. The default is True.
+
+    .. _early stopping:
+        https://en.wikipedia.org/wiki/Early_stopping
+
+    Returns
+    -------
+    None.
+
+    """
+
     model: Network
     optimizer: Optimizer
     loss_function: nn.Module
@@ -862,12 +1104,27 @@ class NetworkTrainer(BaseConfig):
     save: bool = True
 
     def __post_init__(self):
+        """Check the type of each argument.
+
+        Configure the device to train the model on, i.e. train on the gpu if
+        available.
+
+        Configure early stopping if required.
+
+        Returns
+        -------
+        None.
+
+        """
         super().__post_init__()
 
         # whether to use the gpu
         self.device = torch.device("cuda:0" if torch.cuda.is_available()
                                    else "cpu")
 
+        # send the model to the gpu if available
+        self.model = self.model.to(self.device)
+
         # maximum accuracy on the validation dataset
         self.max_accuracy = 0
         if self.checkpoint_state:
@@ -884,7 +1141,22 @@ class NetworkTrainer(BaseConfig):
         LOGGER.info(repr(self))
 
     def train(self):
+        """Train the model.
 
+        Returns
+        -------
+        training_state : `dict` [`str`, `numpy.ndarray`]
+            The training state dictionary with keys:
+            ``'ta'``
+                The accuracy on the training set (`numpy.ndarray`).
+            ``'tl'``
+                The loss on the training set (`numpy.ndarray`).
+            ``'va'``
+                The accuracy on the validation set (`numpy.ndarray`).
+            ``'vl'``
+                The loss on the validation set (`numpy.ndarray`).
+
+        """
         LOGGER.info(35 * '-' + ' Training ' + 35 * '-')
 
         # set the number of threads
@@ -902,10 +1174,7 @@ class NetworkTrainer(BaseConfig):
                                'va': np.zeros(shape=vshape)
                                }
 
-        # send the model to the gpu if available
-        self.model = self.model.to(self.device)
-
-        # initialize the training: iterate over the entire training data set
+        # initialize the training: iterate over the entire training dataset
         for epoch in range(self.epochs):
 
             # set the model to training mode
@@ -988,14 +1257,20 @@ class NetworkTrainer(BaseConfig):
                 # saved after each epoch
                 self.save_state()
 
-
         return self.training_state
 
     def predict(self):
+        """Model inference at training time.
 
-        # send the model to the gpu if available
-        self.model = self.model.to(self.device)
+        Returns
+        -------
+        accuracies : `numpy.ndarray`
+            The mean model prediction accuracy on each mini-batch in the
+            validation set.
+        losses : `numpy.ndarray`
+            The model loss for each mini-batch in the validation set.
 
+        """
         # set the model to evaluation mode
         LOGGER.info('Setting model to evaluation mode ...')
         self.model.eval()
@@ -1038,7 +1313,13 @@ class NetworkTrainer(BaseConfig):
         return accuracies, losses
 
     def save_state(self):
+        """Save the model state.
+
+        Returns
+        -------
+        None.
 
+        """
         # whether to save the model state
         if self.save:
 
@@ -1064,9 +1345,15 @@ class NetworkTrainer(BaseConfig):
                 state=state,
                 )
 
-
     def __repr__(self):
+        """Representation of `~pysegcnn.core.trainer.NetworkTrainer`.
+
+        Returns
+        -------
+        fs : `str`
+            Representation string.
 
+        """
         # representation string to print
         fs = self.__class__.__name__ + '(\n'
 
@@ -1108,6 +1395,47 @@ class NetworkTrainer(BaseConfig):
 
 
 class EarlyStopping(object):
+    """`Early stopping`_ algorithm.
+
+    This implementation of the early stopping algorithm advances a counter each
+    time a metric did not improve over a training epoch. If the metric does not
+    improve over more than ``patience`` epochs, the early stopping criterion is
+    met.
+
+    See `pysegcnn.core.trainer.NetworkTrainer.train` for an example
+    implementation.
+
+    Parameters
+    ----------
+    mode : `str`, optional
+        The mode of the early stopping. Depends on the metric measuring
+        performance. When using model loss as metric, use ``mode`` = 'min',
+        however, when using accuracy as metric, use ``mode`` = 'max'. The
+        default is 'max'.
+    best : `float`, optional
+        Threshold indicating the best metric score. At instanciation, set
+        ``best`` to the worst possible score of the metric. ``best`` will be
+        overwritten during training. The default is 0.
+    min_delta : `float`, optional
+        Minimum change in early stopping metric to be considered as an
+        improvement. The default is 0.
+    patience : `int`, optional
+        The number of epochs to wait for an improvement in the early stopping
+        metric. The default is 10.
+
+    Raises
+    ------
+    ValueError
+        Raised if ``mode`` is not either 'min' or 'max'.
+
+    Returns
+    -------
+    None.
+
+    .. _Early stopping:
+        https://en.wikipedia.org/wiki/Early_stopping
+
+    """
 
     def __init__(self, mode='max', best=0, min_delta=0, patience=10):
 
@@ -1141,7 +1469,19 @@ class EarlyStopping(object):
         self.counter = 0
 
     def stop(self, metric):
+        """Advance early stopping counter.
+
+        Parameters
+        ----------
+        metric : `float`
+            The current metric score.
+
+        Returns
+        -------
+        early_stop : `bool`
+            Whether the early stopping criterion is met.
 
+        """
         # if the metric improved, reset the epochs counter, else, advance
         if self.is_better(metric, self.best, self.min_delta):
             self.counter = 0
@@ -1160,13 +1500,62 @@ class EarlyStopping(object):
         return self.early_stop
 
     def decreased(self, metric, best, min_delta):
+        """Whether a metric decreased with respect to a best score.
+
+        Measure improvement for metrics that are considered as 'better' when
+        they decrease, e.g. model loss, mean squared error, etc.
+
+        Parameters
+        ----------
+        metric : `float`
+            The current score.
+        best : `float`
+            The current best score.
+        min_delta : `float`
+            Minimum change to be considered as an improvement.
+
+        Returns
+        -------
+        `bool`
+            Whether the metric improved.
+
+        """
         return metric < best - min_delta
 
     def increased(self, metric, best, min_delta):
+        """Whether a metric increased with respect to a best score.
+
+        Measure improvement for metrics that are considered as 'better' when
+        they increase, e.g. accuracy, precision, recall, etc.
+
+        Parameters
+        ----------
+        metric : `float`
+            The current score.
+        best : `float`
+            The current best score.
+        min_delta : `float`
+            Minimum change to be considered as an improvement.
+
+        Returns
+        -------
+        `bool`
+            Whether the metric improved.
+
+        """
         return metric > best + min_delta
 
     def __repr__(self):
+        """Representation of `~pysegcnn.core.trainer.EarlyStopping`.
+
+        Returns
+        -------
+        fs : `str`
+            Representation string.
+
+        """
         fs = self.__class__.__name__
         fs += '(mode={}, best={:.2f}, delta={}, patience={})'.format(
             self.mode, self.best, self.min_delta, self.patience)
+
         return fs
diff --git a/pysegcnn/core/transforms.py b/pysegcnn/core/transforms.py
index 77fcad18257202e3e552b7ebaa996dea4d583500..0045c5a87031c4f0d07dd946582252631ba76273 100644
--- a/pysegcnn/core/transforms.py
+++ b/pysegcnn/core/transforms.py
@@ -1,6 +1,18 @@
 """Data augmentation.
 
-Image transformations to artificially increase a dataset.
+This module provides classes implementing common image augmentation methods.
+
+These methods may be used to artificially increase a dataset.
+
+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
@@ -420,7 +432,7 @@ class Augment(object):
         return image, gt
 
     def __repr__(self):
-        """Representation of the container.
+        """Representation of `~pysegcnn.core.transforms.Augment`.
 
         Returns
         -------
diff --git a/pysegcnn/core/utils.py b/pysegcnn/core/utils.py
index 4d09c8028bfd44a5b5d06d02d887f01e962fbe0b..59d08f9c73d8d6e90137b66546c0dd9e9dfb29eb 100644
--- a/pysegcnn/core/utils.py
+++ b/pysegcnn/core/utils.py
@@ -1,4 +1,15 @@
-"""Utility functions mainly for image IO and reshaping."""
+"""Utility functions mainly for image IO and reshaping.
+
+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 -*-
diff --git a/pysegcnn/main/__init__.py b/pysegcnn/main/__init__.py
index df1472ab2ff4e639ea8c1280eb0bddd6bb32afd6..d6c1e9353720b591eb71100148ff1e8f23a4f73e 100644
--- a/pysegcnn/main/__init__.py
+++ b/pysegcnn/main/__init__.py
@@ -1,7 +1,2 @@
+# !/usr/bin/env python
 # -*- coding: utf-8 -*-
-"""
-Created on Tue Jun 30 09:52:28 2020
-
-@author: Daniel
-"""
-
diff --git a/pysegcnn/main/config.py b/pysegcnn/main/config.py
index 6f985b2e3ee3c81627a58a0d322d8ae8ae04e9b2..9e46c1adda4f1909d4a4b348ede3333b19317f64 100644
--- a/pysegcnn/main/config.py
+++ b/pysegcnn/main/config.py
@@ -1,8 +1,18 @@
 """The configuration file to train and evaluate a model.
 
-The configuration is handled by the config dictionary.
+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.
 
-Modify the variable values to your needs, but DO NOT modify the variable names.
 """
 
 # !/usr/bin/env python
@@ -17,7 +27,7 @@ import os
 HERE = os.path.abspath(os.path.dirname(__file__))
 
 # path to the datasets on the current machine
-DRIVE_PATH ='C:/Eurac/2020/_Datasets/'
+DRIVE_PATH = 'C:/Eurac/2020/_Datasets/'
 # DRIVE_PATH = '/mnt/CEPH_PROJECTS/cci_snow/dfrisinghelli/_Datasets/'
 
 # name of the datasets
@@ -30,12 +40,6 @@ DATASET_PATH = os.path.join(DRIVE_PATH, DATASET_NAME)
 # DATASET_PATH = os.path.join(DRIVE_PATH, DATASET_NAME, 'Training')
 # DATASET_PATH = os.path.join(DRIVE_PATH, 'ProSnow', DATASET_NAME)
 
-# path to store the model states
-MODEL_PATH = os.path.join(HERE, '_models/')
-
-# path to store model logs
-LOG_PATH = os.path.join(HERE, '_logs/')
-
 # the dataset configuration dictionary
 dataset_config = {
 
@@ -266,8 +270,7 @@ eval_config = {
     # pysegcnn.main.eval.py
 
     # the model to evaluate
-    'state_file': os.path.join(MODEL_PATH,
-                               'UNet_SparcsDataset_Adam_SceneSplit_s0_t005v05_t125_b64_r4g3b2n5.pt'),
+    'state_file': 'UNet_SparcsDataset_Adam_SceneSplit_s0_t005v05_t125_b64_r4g3b2n5.pt',
 
     # the dataset to evaluate the model on
     # test=False, 0 means evaluating on the validation set
diff --git a/pysegcnn/main/eval.py b/pysegcnn/main/eval.py
index 687c5bb487776898d20b83c9e9db6ab0c47be0e5..dee7f91be04c3a08385d7caac7b2e11638f57b40 100644
--- a/pysegcnn/main/eval.py
+++ b/pysegcnn/main/eval.py
@@ -1,9 +1,27 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Wed Jul 29 15:57:01 2020
+"""Main script to evaluate a model.
+
+Steps to run a model evaluation:
+
+    (1) Configure the dictionary 'eval_config' in pysegcnn/main/config.py
+    (2) Save pysegcnn/main/config.py
+    (3) In a terminal, navigate to the repository's root directory
+    (4) run "python pysegcnn/main/eval.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.
 
-@author: Daniel
 """
+
+# !/usr/bin/env python
+# -*- coding: utf-8 -*-
+
 # builtins
 from logging.config import dictConfig
 
@@ -29,7 +47,7 @@ if __name__ == '__main__':
     model, _, model_state = Network.load(ec.state_file)
 
     # plot loss and accuracy
-    plot_loss(ec.state_file, outpath=ec.models_path)
+    plot_loss(ec.state_file, outpath=ec.perfmc_path)
 
     # check whether to evaluate the model on the training set, validation set
     # or the test set
@@ -60,4 +78,4 @@ if __name__ == '__main__':
     if ec.cm:
         plot_confusion_matrix(cm, ds.dataset.labels,
                               state=ec.state_file.name.replace('.pt', '.png'),
-                              outpath=ec.models_path)
+                              outpath=ec.perfmc_path)
diff --git a/pysegcnn/main/train.py b/pysegcnn/main/train.py
index e28f55f0b18c8addaaceda704bda5d6c8ebcf8b1..6d75060b2b68a274582f9dd2955fa45c8328d9be 100644
--- a/pysegcnn/main/train.py
+++ b/pysegcnn/main/train.py
@@ -1,10 +1,29 @@
+"""Main script to train a model.
+
+Steps to launch a model run:
+
+    (1) Configure the model run in pysegcnn/main/config.py
+        (i) configure the dataset      : dictionary 'dataset_config'
+        (j) configure the dataset split: dictionary 'split_config'
+        (k) configure the model        : dictionary 'model_config'
+    (2) Save pysegcnn/main/config.py
+    (3) In a terminal, navigate to the repository's root directory
+    (4) run "python pysegcnn/main/train.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 -*-
-"""
-Created on Tue Jun 30 09:33:38 2020
 
-@author: Daniel
-"""
 # builtins
 from logging.config import dictConfig
 
@@ -12,8 +31,7 @@ from logging.config import dictConfig
 from pysegcnn.core.trainer import (DatasetConfig, SplitConfig, ModelConfig,
                                    StateConfig, LogConfig, NetworkTrainer)
 from pysegcnn.core.logging import log_conf
-from pysegcnn.main.config import (dataset_config, split_config, model_config,
-                                  LOG_PATH)
+from pysegcnn.main.config import (dataset_config, split_config, model_config)
 
 
 if __name__ == '__main__':
diff --git a/pysegcnn/preprocessing/__init__.py b/pysegcnn/preprocessing/__init__.py
index 1c79e84051174d776c925b95f539fde6b904a98a..d6c1e9353720b591eb71100148ff1e8f23a4f73e 100644
--- a/pysegcnn/preprocessing/__init__.py
+++ b/pysegcnn/preprocessing/__init__.py
@@ -1,6 +1,2 @@
+# !/usr/bin/env python
 # -*- coding: utf-8 -*-
-"""
-Created on Mon Jul 27 10:02:36 2020
-
-@author: Daniel
-"""
diff --git a/pysegcnn/preprocessing/sparcs.py b/pysegcnn/preprocessing/sparcs.py
index f1cf2514cc6a2687ba46a1c33debfb6d2f4e13ff..a8096f6f17a411a717b1ca95a224901475b60727 100644
--- a/pysegcnn/preprocessing/sparcs.py
+++ b/pysegcnn/preprocessing/sparcs.py
@@ -1,4 +1,15 @@
-"""Functions to preprocess the Sparcs dataset to work with pylandsat."""
+"""Functions to preprocess the Sparcs dataset.
+
+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
@@ -18,16 +29,16 @@ from pylandsat.core.calibration import landsat_radiometric_calibration
 
 
 def sparcs2pylandsat(source_path, target_path, overwrite=True):
-    """Convert the Sparcs dataset structure to the pylandsat standard.
+    """Convert the Sparcs dataset structure to standard EO structure.
 
     Parameters
     ----------
-    source_path : string
-        path to the Sparcs archive downloaded `here`_
-    target_path : string
-        path to save the preprocessed sparcs dataset
-    overwrite : bool
-        whether to overwrite existing files
+    source_path : `str`
+        Path to the Sparcs archive downloaded `here`_.
+    target_path : `str`
+        Path to save the preprocessed sparcs dataset.
+    overwrite : `bool`
+        Whether to overwrite existing files.
 
     Returns
     -------
@@ -83,10 +94,10 @@ def destack_sparcs_raster(inpath, outpath=None, suffix='*_toa.tif'):
 
     Parameters
     ----------
-    inpath : string
-        path to a directory containing the TIFF file to destack
-    outpath : string, optional
-        path to save the output TIFF files. The default is None. If None,
+    inpath : `str`
+        Path to a directory containing the TIFF file to destack.
+    outpath : `str`, optional
+        Path to save the output TIFF files. The default is None. If None,
         ``outpath`` = ``inpath``.
 
     Returns
diff --git a/tests/__init__.py b/tests/__init__.py
index 20e5e4cf8a7a1110fa7b0b5e7bd35540314f349d..d6c1e9353720b591eb71100148ff1e8f23a4f73e 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,6 +1,2 @@
+# !/usr/bin/env python
 # -*- coding: utf-8 -*-
-"""
-Created on Wed Jul 22 14:44:09 2020
-
-@author: Daniel
-"""
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 6bacaa9befc8004dc711b20b1eb5c533e5dd575d..e145b3db7e7bcc806542983dadb5df5fafd78aa3 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -1,9 +1,19 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Wed Jul 22 09:06:45 2020
+"""Test suite for pysegcnn.core.utils.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.
 
-@author: Daniel
 """
+
+# !/usr/bin/env python
+# -*- coding: utf-8 -*-
+
 # externals
 import pytest
 import numpy as np