diff --git a/docs/conf.py b/docs/conf.py
index c3ffaec690db1aad2cec9bdc03662c2f87fa6b5f..c4ba79164c898cd0cdb8f31610b20c1fca61ba89 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -34,15 +34,23 @@ extensions = [
     'sphinx.ext.autodoc',
     'sphinx.ext.autosummary',
     'sphinx.ext.viewcode',
+    'sphinx.ext.intersphinx',
     'numpydoc',
 ]
 
 # numpydoc options
 numpydoc_show_class_members = False
 numpydoc_show_inherited_class_members = False
+numpydoc_attributes_as_param_list = True
+# numpydoc_xref_param_type = True
+# numpydoc_xref_ignore = {'type', 'optional', 'default'}
 
 # autosummary options
 autosummary_generate = True
+autodoc_default_options = {
+    'inherited-members': False,
+    'show-inheritance': True,
+    }
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
diff --git a/pysegcnn/core/cli.py b/pysegcnn/core/cli.py
index 9576209e62a85c9eeb966d10ad32831eaf54056d..07c8759bdb50db3af6cfedebc4c29eeed6c0122e 100644
--- a/pysegcnn/core/cli.py
+++ b/pysegcnn/core/cli.py
@@ -18,19 +18,12 @@ License
 import pathlib
 import argparse
 
-
 # epilogue to display at the end of each parser
 EPILOGUE = 'Author: Daniel Frisinghelli, daniel.frisinghelli@gmail.com'
 
 
 def structure_parser():
-    """Command line argument parser to standardize dataset structure.
-
-    Returns
-    -------
-    None.
-
-    """
+    """Command line argument parser to standardize dataset structure."""
     parser = argparse.ArgumentParser(
         description='Standardize the dataset directory structure.',
         epilog=EPILOGUE,
diff --git a/pysegcnn/core/constants.py b/pysegcnn/core/constants.py
index ffe0e82e33f73e83e23e9745f40ee9cb3b16413c..491efe1b5822bbbc7c9be840ec8d1fd3611f9d9b 100644
--- a/pysegcnn/core/constants.py
+++ b/pysegcnn/core/constants.py
@@ -1,4 +1,4 @@
-"""A collection of constant values.
+"""A collection of constants.
 
 License
 -------
@@ -20,12 +20,15 @@ import enum
 
 # Landsat 8 bands
 class Landsat8(enum.Enum):
-    """The spectral bands of the Landsat 8 sensors.
+    """The spectral bands of the `Landsat-8`_ sensors.
 
     sensors:
         - Operational Land Imager (OLI), (bands 1-9)
         - Thermal Infrared Sensor (TIRS), (bands 10, 11)
 
+    .. _Landsat-8:
+        https://www.usgs.gov/land-resources/nli/landsat/landsat-8?qt-science_support_page_related_con=0#qt-science_support_page_related_con
+
     """
 
     violet = 1
@@ -43,7 +46,12 @@ class Landsat8(enum.Enum):
 
 # Sentinel 2 bands
 class Sentinel2(enum.Enum):
-    """The spectral bands of the Sentinel-2 MultiSpectral Instrument (MSI)."""
+    """The spectral bands of the `Sentinel-2`_ MultiSpectral Instrument (MSI).
+
+    .. _Sentinel-2:
+        https://sentinel.esa.int/web/sentinel/missions/sentinel-2
+
+    """
 
     aerosol = 1
     blue = 2
diff --git a/pysegcnn/core/dataset.py b/pysegcnn/core/dataset.py
index d8dfc714e9ed539f7a5b404573e363a603a5943b..b8eee01491ccbdbfd0468a77166227468d8ae844 100644
--- a/pysegcnn/core/dataset.py
+++ b/pysegcnn/core/dataset.py
@@ -45,54 +45,108 @@ LOGGER = logging.getLogger(__name__)
 
 
 class ImageDataset(Dataset):
-    r"""Base class for multispectral image data.
+    """Base class for multispectral image data.
 
-    Inheriting from `torch.utils.data.Dataset` to be compliant to the PyTorch
-    standard. Furthermore, using instances of `torch.utils.data.Dataset`
-    enables the use of the handy `torch.utils.data.DataLoader` class during
-    model training.
+    Inheriting from :py:class:`torch.utils.data.Dataset` to be compliant to the
+    PyTorch standard. This enables the use of the handy
+    :py:class:`torch.utils.data.DataLoader` class during model training.
 
-    Parameters
+    Attributes
     ----------
     root_dir : `str`
         The root directory, path to the dataset.
-    use_bands : `list` [`str`], optional
-        A list of the spectral bands to use. The default is [].
-    tile_size : `int` or `None`, optional
-        The size of the tiles. If not `None`, each scene is divided into square
-        tiles of shape (tile_size, tile_size). The default is None.
-    pad : `bool`, optional
-        Whether to center pad the input image. Set ``pad`` = True, if the
-        images are not evenly divisible by the ``tile_size``. The image data is
-        padded with a constant padding value of zero. For each image, the
-        corresponding ground truth image is padded with a "no data" label.
-        The default is False.
-    gt_pattern : `str`, optional
+    use_bands : `list` [`str`]
+        List of the spectral bands to use during model training.
+    tile_size : `int` or `None`
+        The size of the tiles.
+    pad : `bool`
+        Whether to center pad the input image.
+    gt_pattern : `str`
         A regural expression to match the ground truth naming convention.
-        All directories and subdirectories in ``root_dir`` are searched for
-        files matching ``gt_pattern``. The default is '(.*)gt\\.tif'.
-    sort : `bool`, optional
-        Whether to chronologically sort the samples. Useful for time series
-        data. The default is False.
-    seed : `int`, optional
-        The random seed. Used to split the dataset into training, validation
-        and test set. Useful for reproducibility. The default is 0.
-    transforms : `list` [`pysegcnn.core.split.Augment`], optional
-        List of `pysegcnn.core.split.Augment` instances. Each item in
-        ``transforms`` generates a distinct transformed version of the dataset.
-        The total dataset is composed of the original untransformed dataset
-        together with each transformed version of it.
-        If ``transforms`` = [], only the original dataset is used.
-        The default is [].
-
-    Returns
-    -------
-    None.
+    sort : `bool`
+        Whether to chronologically sort the samples.
+    seed : `int`
+        The random seed.
+    transforms : `list`
+        List of :py:class:`pysegcnn.core.transforms.Augment` instances.
+    size : `tuple` [`int`]
+        The size of an image of the dataset.
+    sensor : :py:class:`enum.Enum`
+        An enumeration of the bands of sensor the dataset is derived from,
+        see e.g. :py:class:`pysegcnn.core.constants.Landsat8`.
+    bands : `dict` [`int`, `str`]
+        The spectral bands of ``sensor``. The keys are the number and the
+        values are the name of the spectral bands.
+    labels : `dict` [`int`, `dict`]
+        The label dictionary. The keys are the values of the class labels
+        in the ground truth. Each nested `dict` has keys:
+            ``'color'``
+                A named color (`str`).
+            ``'label'``
+                The name of the class label (`str`).
+    tiles : `int`
+        Number of tiles with size ``(tile_size, tile_size)`` within an image.
+    padding : `tuple` [`int`]
+        The amount of padding, (bottom, left, top, right).
+    height : `int`
+        The height of a padded image.
+    width : `int`
+        The width of a padded image.
+    topleft : `dict` [`int`, `tuple`]
+        The topleft corners of the tiles. The keys of are the tile ids (`int`)
+        and the values are the topleft corners (y, x) of the tiles.
+    cval : `int`
+        When padding, ``cval`` is the value of the "no data" label in the
+        ground truth. Otherwise, ``cval=0``.
+    gt : `list` [`str` or :py:class:`pathlib.Path`]
+        List of the ground truth images.
+    keys : `list`
+        List of required keys for each dictionary in ``scenes``.
+    scenes : `list` [`dict`]
+        List of dictionaries representing the samples of the dataset.
 
     """
 
     def __init__(self, root_dir, use_bands=[], tile_size=None, pad=False,
-                 gt_pattern='(.*)gt.tif', sort=False, seed=0, transforms=[]):
+                 gt_pattern='(.*)gt\\.tif', sort=False, seed=0, transforms=[]):
+        r"""Initialize.
+
+        Parameters
+        ----------
+        root_dir : `str`
+            The root directory, path to the dataset.
+        use_bands : `list` [`str`], optional
+            A list of the spectral bands to use. The default is `[]`.
+        tile_size : `int` or `None`, optional
+            The size of the tiles. If not `None`, each scene is divided into
+            square tiles of shape ``(tile_size, tile_size)``. The default is
+            `None`.
+        pad : `bool`, optional
+            Whether to center pad the input image. Set ``pad=True``, if the
+            images are not evenly divisible by the ``tile_size``. The image
+            data is padded with a constant padding value of zero. For each
+            image, the corresponding ground truth image is padded with a
+            "no data" label. The default is `False`.
+        gt_pattern : `str`, optional
+            A regural expression to match the ground truth naming convention.
+            All directories and subdirectories in ``root_dir`` are searched for
+            files matching ``gt_pattern``. The default is `(.*)gt\\.tif`.
+        sort : `bool`, optional
+            Whether to chronologically sort the samples. Useful for time series
+            data. The default is `False`.
+        seed : `int`, optional
+            The random seed. Used to split the dataset into training,
+            validation and test set. Useful for reproducibility. The default is
+            `0`.
+        transforms : `list`, optional
+            List of :py:class:`pysegcnn.core.transforms.Augment` instances.
+            Each item in ``transforms`` generates a distinct transformed
+            version of the dataset. The total dataset is composed of the
+            original untransformed dataset together with each transformed
+            version of it. If ``transforms=[]``, only the original dataset is
+            used. The default is `[]`.
+
+        """
         super().__init__()
 
         # dataset configuration
@@ -159,6 +213,9 @@ class ImageDataset(Dataset):
             LOGGER.info('Adding label "No data" with value={} to ground truth.'
                         .format(self.cval))
 
+        # list of ground truth images
+        self.gt = []
+
     def _build_labels(self):
         """Build the label dictionary.
 
@@ -166,7 +223,7 @@ class ImageDataset(Dataset):
         -------
         labels : `dict` [`int`, `dict`]
             The label dictionary. The keys are the values of the class labels
-            in the ground truth ``y``. Each nested `dict` should have keys:
+            in the ground truth. Each nested `dict` should have keys:
                 ``'color'``
                     A named color (`str`).
                 ``'label'``
@@ -492,7 +549,7 @@ class ImageDataset(Dataset):
         -------
         stack : `numpy.ndarray`
             The input data of the sample.
-        gt : TYPE
+        gt : `numpy.ndarray`
             The ground truth of the sample.
 
         """
@@ -503,7 +560,7 @@ class ImageDataset(Dataset):
         return stack, gt
 
     def to_tensor(self, x, dtype):
-        """Convert ``x`` to `torch.Tensor`.
+        """Convert ``x`` to :py:class:`torch.Tensor`.
 
         Parameters
         ----------
@@ -565,75 +622,32 @@ class ImageDataset(Dataset):
 class StandardEoDataset(ImageDataset):
     r"""Base class for standard Earth Observation style datasets.
 
-    `pysegcnn.core.dataset.StandardEoDataset` implements the
-    `~pysegcnn.core.dataset.StandardEoDataset.compose_scenes` method for
-    datasets with the following directory structure:
+    :py:class:`pysegcnn.core.dataset.StandardEoDataset` implements the
+    :py:meth:`~pysegcnn.core.dataset.StandardEoDataset.compose_scenes` method
+    for datasets with the following directory structure:
 
     root_dir/
-        scene_id_1/
-            scene_id_1_B1.tif
-            scene_id_1_B2.tif
-            .
-            .
-            .
-            scene_id_1_BN.tif
-        scene_id_2/
-            scene_id_2_B1.tif
-            scene_id_2_B2.tif
-            .
-            .
-            .
-            scene_id_2_BN.tif
-        .
-        .
-        .
-        scene_id_N/
-            .
-            .
-            .
+        - scene_id_1/
+             - scene_id_1_B1.tif
+             - scene_id_1_B2.tif
+             - ...
+             - scene_id_1_BN.tif
+        - scene_id_2/
+             - scene_id_2_B1.tif
+             - scene_id_2_B2.tif
+             - ...
+             - scene_id_2_BN.tif
+        - ...
+        - scene_id_N/
+            - ...
 
     If your dataset shares this directory structure, you can directly inherit
-    `pysegcnn.core.dataset.StandardEoDataset` and implement the remaining
-    methods.
+    :py:class:`pysegcnn.core.dataset.StandardEoDataset` and implement the
+    remaining methods. If not, you can use
+    :py:func:`pysegcnn.core.utils.standard_eo_structure` to transfer your
+    dataset to the above directory structure.
 
-    See `pysegcnn.core.dataset.SparcsDataset` for an example.
-
-    Parameters
-    ----------
-    root_dir : `str`
-        The root directory, path to the dataset.
-    use_bands : `list` [`str`], optional
-        A list of the spectral bands to use. The default is [].
-    tile_size : `int` or `None`, optional
-        The size of the tiles. If not `None`, each scene is divided into square
-        tiles of shape (tile_size, tile_size). The default is None.
-    pad : `bool`, optional
-        Whether to center pad the input image. Set ``pad`` = True, if the
-        images are not evenly divisible by the ``tile_size``. The image data is
-        padded with a constant padding value of zero. For each image, the
-        corresponding ground truth image is padded with a "no data" label.
-        The default is False.
-    gt_pattern : `str`, optional
-        A regural expression to match the ground truth naming convention. All
-        directories and subdirectories in ``root_dir`` are searched for files
-        matching ``gt_pattern``. The default is '(.*)gt\\.tif'.
-    sort : `bool`, optional
-        Whether to chronologically sort the samples. Useful for time series
-        data. The default is False.
-    seed : `int`, optional
-        The random seed. Used to split the dataset into training, validation
-        and test set. Useful for reproducibility. The default is 0.
-    transforms : `list` [`pysegcnn.core.split.Augment`], optional
-        List of `pysegcnn.core.split.Augment` instances. Each item in
-        ``transforms`` generates a distinct transformed version of the dataset.
-        The total dataset is composed of the original untransformed dataset
-        together with each transformed version of it.
-        If ``transforms`` = [], only the original dataset is used.
-        The default is [].
-
-    Returns
-    -------
-    None.
+    See :py:class:`pysegcnn.core.dataset.SparcsDataset` for an example.
 
     """
 
@@ -709,35 +723,9 @@ class StandardEoDataset(ImageDataset):
         return scene_data
 
     def compose_scenes(self):
-        """Build the list of samples of the dataset.
-
-        Each sample is represented by a dictionary.
-
-        Returns
-        -------
-        scenes : `list` [`dict`]
-            Each item in ``scenes`` is a `dict` with keys:
-                ``'band_name_1'``
-                    Path to the file of band_1.
-                ``'band_name_2'``
-                    Path to the file of band_2.
-                ``'band_name_n'``
-                    Path to the file of band_n.
-                ``'gt'``
-                    Path to the ground truth file.
-                ``'date'``
-                    The date of the sample.
-                ``'tile'``
-                    The tile id of the sample.
-                ``'transform'``
-                    The transformation to apply.
-                ``'id'``
-                    The scene identifier.
-
-        """
+        """Build the list of samples of the dataset."""
         # search the root directory
         scenes = []
-        self.gt = []
         for dirpath, dirname, files in os.walk(self.root):
 
             # search for a ground truth in the current directory
@@ -800,47 +788,13 @@ class StandardEoDataset(ImageDataset):
 
 
 class SparcsDataset(StandardEoDataset):
-    r"""Class for the `Sparcs`_ dataset.
+    """Class for the `Sparcs`_ dataset by `Hughes & Hayes (2014)`_.
 
     .. _Sparcs:
         https://www.usgs.gov/land-resources/nli/landsat/spatial-procedures-automated-removal-cloud-and-shadow-sparcs-validation
 
-    Parameters
-    ----------
-    root_dir : `str`
-        The root directory, path to the dataset.
-    use_bands : `list` [`str`], optional
-        A list of the spectral bands to use. The default is [].
-    tile_size : `int` or `None`, optional
-        The size of the tiles. If not `None`, each scene is divided into square
-        tiles of shape (tile_size, tile_size). The default is None.
-    pad : `bool`, optional
-        Whether to center pad the input image. Set ``pad`` = True, if the
-        images are not evenly divisible by the ``tile_size``. The image data is
-        padded with a constant padding value of zero. For each image, the
-        corresponding ground truth image is padded with a "no data" label.
-        The default is False.
-    gt_pattern : `str`, optional
-        A regural expression to match the ground truth naming convention. All
-        directories and subdirectories in ``root_dir`` are searched for files
-        matching ``gt_pattern``. The default is '(.*)gt\\.tif'.
-    sort : `bool`, optional
-        Whether to chronologically sort the samples. Useful for time series
-        data. The default is False.
-    seed : `int`, optional
-        The random seed. Used to split the dataset into training, validation
-        and test set. Useful for reproducibility. The default is 0.
-    transforms : `list` [`pysegcnn.core.split.Augment`], optional
-        List of `pysegcnn.core.split.Augment` instances. Each item in
-        ``transforms`` generates a distinct transformed version of the dataset.
-        The total dataset is composed of the original untransformed dataset
-        together with each transformed version of it.
-        If ``transforms`` = [], only the original dataset is used.
-        The default is [].
-
-    Returns
-    -------
-    None.
+    .. _Hughes & Hayes (2014):
+        https://www.mdpi.com/2072-4292/6/6/4907
 
     """
 
@@ -923,46 +877,7 @@ class SparcsDataset(StandardEoDataset):
 
 
 class ProSnowDataset(StandardEoDataset):
-    r"""Class for the ProSnow datasets.
-
-    Parameters
-    ----------
-    root_dir : `str`
-        The root directory, path to the dataset.
-    use_bands : `list` [`str`], optional
-        A list of the spectral bands to use. The default is [].
-    tile_size : `int` or `None`, optional
-        The size of the tiles. If not `None`, each scene is divided into square
-        tiles of shape (tile_size, tile_size). The default is None.
-    pad : `bool`, optional
-        Whether to center pad the input image. Set ``pad`` = True, if the
-        images are not evenly divisible by the ``tile_size``. The image data is
-        padded with a constant padding value of zero. For each image, the
-        corresponding ground truth image is padded with a "no data" label.
-        The default is False.
-    gt_pattern : `str`, optional
-        A regural expression to match the ground truth naming convention. All
-        directories and subdirectories in ``root_dir`` are searched for files
-        matching ``gt_pattern``. The default is '(.*)gt\\.tif'.
-    sort : `bool`, optional
-        Whether to chronologically sort the samples. Useful for time series
-        data. The default is False.
-    seed : `int`, optional
-        The random seed. Used to split the dataset into training, validation
-        and test set. Useful for reproducibility. The default is 0.
-    transforms : `list` [`pysegcnn.core.split.Augment`], optional
-        List of `pysegcnn.core.split.Augment` instances. Each item in
-        ``transforms`` generates a distinct transformed version of the dataset.
-        The total dataset is composed of the original untransformed dataset
-        together with each transformed version of it.
-        If ``transforms`` = [], only the original dataset is used.
-        The default is [].
-
-    Returns
-    -------
-    None.
-
-    """
+    """Class for the ProSnow datasets."""
 
     def __init__(self, root_dir, use_bands=[], tile_size=None, pad=False,
                  gt_pattern='(.*)gt\\.tif', sort=False, seed=0, transforms=[]):
@@ -1032,46 +947,7 @@ class ProSnowDataset(StandardEoDataset):
 
 
 class ProSnowGarmisch(ProSnowDataset):
-    r"""Class for the ProSnow Garmisch dataset.
-
-    Parameters
-    ----------
-    root_dir : `str`
-        The root directory, path to the dataset.
-    use_bands : `list` [`str`], optional
-        A list of the spectral bands to use. The default is [].
-    tile_size : `int` or `None`, optional
-        The size of the tiles. If not `None`, each scene is divided into square
-        tiles of shape (tile_size, tile_size). The default is None.
-    pad : `bool`, optional
-        Whether to center pad the input image. Set ``pad`` = True, if the
-        images are not evenly divisible by the ``tile_size``. The image data is
-        padded with a constant padding value of zero. For each image, the
-        corresponding ground truth image is padded with a "no data" label.
-        The default is False.
-    gt_pattern : `str`, optional
-        A regural expression to match the ground truth naming convention. All
-        directories and subdirectories in ``root_dir`` are searched for files
-        matching ``gt_pattern``. The default is '(.*)gt\\.tif'.
-    sort : `bool`, optional
-        Whether to chronologically sort the samples. Useful for time series
-        data. The default is False.
-    seed : `int`, optional
-        The random seed. Used to split the dataset into training, validation
-        and test set. Useful for reproducibility. The default is 0.
-    transforms : `list` [`pysegcnn.core.split.Augment`], optional
-        List of `pysegcnn.core.split.Augment` instances. Each item in
-        ``transforms`` generates a distinct transformed version of the dataset.
-        The total dataset is composed of the original untransformed dataset
-        together with each transformed version of it.
-        If ``transforms`` = [], only the original dataset is used.
-        The default is [].
-
-    Returns
-    -------
-    None.
-
-    """
+    """Class for the ProSnow Garmisch dataset."""
 
     def __init__(self, root_dir, use_bands=[], tile_size=None, pad=False,
                  gt_pattern='(.*)gt\\.tif', sort=False, seed=0, transforms=[]):
@@ -1092,46 +968,7 @@ class ProSnowGarmisch(ProSnowDataset):
 
 
 class ProSnowObergurgl(ProSnowDataset):
-    r"""Class for the ProSnow Obergurgl dataset.
-
-    Parameters
-    ----------
-    root_dir : `str`
-        The root directory, path to the dataset.
-    use_bands : `list` [`str`], optional
-        A list of the spectral bands to use. The default is [].
-    tile_size : `int` or `None`, optional
-        The size of the tiles. If not `None`, each scene is divided into square
-        tiles of shape (tile_size, tile_size). The default is None.
-    pad : `bool`, optional
-        Whether to center pad the input image. Set ``pad`` = True, if the
-        images are not evenly divisible by the ``tile_size``. The image data is
-        padded with a constant padding value of zero. For each image, the
-        corresponding ground truth image is padded with a "no data" label.
-        The default is False.
-    gt_pattern : `str`, optional
-        A regural expression to match the ground truth naming convention. All
-        directories and subdirectories in ``root_dir`` are searched for files
-        matching ``gt_pattern``. The default is '(.*)gt\\.tif'.
-    sort : `bool`, optional
-        Whether to chronologically sort the samples. Useful for time series
-        data. The default is False.
-    seed : `int`, optional
-        The random seed. Used to split the dataset into training, validation
-        and test set. Useful for reproducibility. The default is 0.
-    transforms : `list` [`pysegcnn.core.split.Augment`], optional
-        List of `pysegcnn.core.split.Augment` instances. Each item in
-        ``transforms`` generates a distinct transformed version of the dataset.
-        The total dataset is composed of the original untransformed dataset
-        together with each transformed version of it.
-        If ``transforms`` = [], only the original dataset is used.
-        The default is [].
-
-    Returns
-    -------
-    None.
-
-    """
+    """Class for the ProSnow Obergurgl dataset."""
 
     def __init__(self, root_dir, use_bands=[], tile_size=None, pad=False,
                  gt_pattern='(.*)gt\\.tif', sort=False, seed=0, transforms=[]):
@@ -1152,50 +989,13 @@ class ProSnowObergurgl(ProSnowDataset):
 
 
 class Cloud95Dataset(ImageDataset):
-    r"""Class for the `Cloud-95`_ dataset by `Mohajerani & Saeedi (2020)`_.
+    """Class for the `Cloud-95`_ dataset by `Mohajerani & Saeedi (2020)`_.
 
     .. _Cloud-95:
         https://github.com/SorourMo/95-Cloud-An-Extension-to-38-Cloud-Dataset
     .. _Mohajerani & Saeedi (2020):
         https://arxiv.org/abs/2001.08768
 
-    Parameters
-    ----------
-    root_dir : `str`
-        The root directory, path to the dataset.
-    use_bands : `list` [`str`], optional
-        A list of the spectral bands to use. The default is [].
-    tile_size : `int` or `None`, optional
-        The size of the tiles. If not `None`, each scene is divided into square
-        tiles of shape (tile_size, tile_size). The default is None.
-    pad : `bool`, optional
-        Whether to center pad the input image. Set ``pad`` = True, if the
-        images are not evenly divisible by the ``tile_size``. The image data is
-        padded with a constant padding value of zero. For each image, the
-        corresponding ground truth image is padded with a "no data" label.
-        The default is False.
-    gt_pattern : `str`, optional
-        A regural expression to match the ground truth naming convention. All
-        directories and subdirectories in ``root_dir`` are searched for files
-        matching ``gt_pattern``. The default is '(.*)gt\\.tif'.
-    sort : `bool`, optional
-        Whether to chronologically sort the samples. Useful for time series
-        data. The default is False.
-    seed : `int`, optional
-        The random seed. Used to split the dataset into training, validation
-        and test set. Useful for reproducibility. The default is 0.
-    transforms : `list` [`pysegcnn.core.split.Augment`], optional
-        List of `pysegcnn.core.split.Augment` instances. Each item in
-        ``transforms`` generates a distinct transformed version of the dataset.
-        The total dataset is composed of the original untransformed dataset
-        together with each transformed version of it.
-        If ``transforms`` = [], only the original dataset is used.
-        The default is [].
-
-    Returns
-    -------
-    None.
-
     """
 
     def __init__(self, root_dir, use_bands=[], tile_size=None, pad=False,
@@ -1285,32 +1085,7 @@ class Cloud95Dataset(ImageDataset):
         return parse_landsat_scene(scene_id)
 
     def compose_scenes(self):
-        """Build the list of samples of the dataset.
-
-        Each sample is represented by a dictionary.
-
-        Returns
-        -------
-        scenes : `list` [`dict`]
-            Each item in ``scenes`` is a `dict` with keys:
-                ``'band_name_1'``
-                    Path to the file of band_1.
-                ``'band_name_2'``
-                    Path to the file of band_2.
-                ``'band_name_n'``
-                    Path to the file of band_n.
-                ``'gt'``
-                    Path to the ground truth file.
-                ``'date'``
-                    The date of the sample.
-                ``'tile'``
-                    The tile id of the sample.
-                ``'transform'``
-                    The transformation to apply.
-                ``'id'``
-                    The scene identifier.
-
-        """
+        """Build the list of samples of the dataset."""
         # whether to exclude patches with more than 80% black pixels
         ipatches = []
         if self.exclude is not None:
diff --git a/pysegcnn/core/layers.py b/pysegcnn/core/layers.py
index b2a51d2c35c7d6bf8cf7876219e07c0f486cca3b..f4fbebab8e642c34ad226978acb17c7fafe62676 100644
--- a/pysegcnn/core/layers.py
+++ b/pysegcnn/core/layers.py
@@ -28,29 +28,30 @@ class Conv2dSame(nn.Conv2d):
     calculated such that the output of the convolution has the same spatial
     dimensions as the input.
 
-    Parameters
+    Attributes
     ----------
-    *args: `list` [`str`]
-        positional arguments passed to `torch.nn.Conv2d`:
-            ``'in_channels'``: `int`
-                Number of input channels.
-            ``'out_channels'``: `int`
-                Number of output channels.
-            ``'kernel_size'``: `int` or `tuple` [`int`]
-                Size of the convolving kernel.
-    **kwargs: 'dict' [`str`]
-        Additional keyword arguments passed to `torch.nn.Conv2d`_.
-
-    .. _torch.nn.Conv2d:
-        https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html#torch.nn.Conv2d
-
-    Returns
-    -------
-    None.
+    padding : `tuple` [`int`]
+        The amount of padding, (pad_height, pad_width).
 
     """
 
     def __init__(self, *args, **kwargs):
+        """Initialize.
+
+        Parameters
+        ----------
+        *args: `list` [`str`]
+            positional arguments passed to :py:class:`torch.nn.Conv2d`:
+                ``'in_channels'``: `int`
+                    Number of input channels.
+                ``'out_channels'``: `int`
+                    Number of output channels.
+                ``'kernel_size'``: `int` or `tuple` [`int`]
+                    Size of the convolving kernel.
+        **kwargs: `dict` [`str`]
+            Additional keyword arguments passed to :py:class:`torch.nn.Conv2d`.
+
+        """
         super().__init__(*args, **kwargs)
 
         # define tensorflows "SAME" padding for stride = 1
@@ -73,7 +74,7 @@ class Conv2dSame(nn.Conv2d):
         Returns
         -------
         p : `int`
-            the amount of padding.
+            The amount of padding.
 
         """
         # calculates the padding so that the convolution
@@ -90,7 +91,7 @@ def conv_bn_relu(in_channels, out_channels, **kwargs):
         Number of input channels.
     out_channels : `int`
         Number of output channels.
-    **kwargs: 'dict' [`str`]
+    **kwargs: `dict` [`str`]
         Additional arguments passed to `pysegcnn.core.layers.Conv2dSame`.
 
     Returns
@@ -113,28 +114,39 @@ def conv_bn_relu(in_channels, out_channels, **kwargs):
 class Block(nn.Module):
     """Basic convolutional block.
 
-    Parameters
+    Attributes
     ----------
     in_channels : `int`
         Number of input channels.
     out_channels : `int`
         Number of output channels.
-    **kwargs: 'dict' [`str`]
-         Additional arguments passed to `pysegcnn.core.layers.Conv2dSame`.
-
-    Raises
-    ------
-    TypeError
-        Raised if `~pysegcnn.core.layers.Block.layers` method does not return
-        an instance of `torch.nn.Sequential`.
-
-    Returns
-    -------
-    None.
+    kwargs: `dict` [`str`]
+        Additional arguments passed to
+        :py:class:`pysegcnn.core.layers.Conv2dSame`.
+    conv : :py:class:`torch.nn.Sequential`
+        The convolutional layers of the block.
 
     """
 
     def __init__(self, in_channels, out_channels, **kwargs):
+        """Initialize.
+
+        Parameters
+        ----------
+        in_channels : `int`
+            Number of input channels.
+        out_channels : `int`
+            Number of output channels.
+        **kwargs: `dict` [`str`]
+             Additional arguments passed to
+             :py:class:`pysegcnn.core.layers.Conv2dSame`.
+
+        Raises
+        ------
+        TypeError
+            Raised if :py:meth:`~pysegcnn.core.layers.Block.layers` method does
+            not return an instance of :py:class:`torch.nn.Sequential`.
+        """
         super().__init__()
 
         # number of input and output channels
@@ -157,13 +169,13 @@ class Block(nn.Module):
         Raises
         ------
         NotImplementedError
-            Raised if `pysegcnn.core.layers.Block` is not inherited.
+            Raised if :py:class:`pysegcnn.core.layers.Block` is not inherited.
 
         Returns
         -------
-        layers : `torch.nn.Sequential` [`torch.nn.Module`]
-            Return an instance of `torch.nn.Sequential` containing a sequence
-            of layer (`torch.nn.Module` ) instances.
+        layers : :py:class:`torch.nn.Sequential` [:py:class:`torch.nn.Module`]
+            Return an instance of :py:class:`torch.nn.Sequential` containing a
+            sequence of layer (:py:class:`torch.nn.Module` ) instances.
 
         """
         raise NotImplementedError('Return an instance of {}.'
@@ -175,33 +187,14 @@ class Block(nn.Module):
         Raises
         ------
         NotImplementedError
-            Raised if `pysegcnn.core.layers.Block` is not inherited.
-
-        Returns
-        -------
-        None.
+            Raised if :py:class:`pysegcnn.core.layers.Block` is not inherited.
 
         """
         raise NotImplementedError('Implement the forward pass.')
 
 
 class EncoderBlock(Block):
-    """Block of a convolutional encoder.
-
-    Parameters
-    ----------
-    in_channels : `int`
-        Number of input channels.
-    out_channels : `int`
-        Number of output channels.
-    **kwargs: 'dict' [`str`]
-         Additional arguments passed to `pysegcnn.core.layers.Conv2dSame`.
-
-    Returns
-    -------
-    None.
-
-    """
+    """Block of a convolutional encoder."""
 
     def __init__(self, in_channels, out_channels, **kwargs):
         super().__init__(in_channels, out_channels, **kwargs)
@@ -211,21 +204,21 @@ class EncoderBlock(Block):
 
         Parameters
         ----------
-        x : `torch.Tensor`
+        x : :py:class:`torch.Tensor`
             Input tensor, e.g. output of the previous block/layer.
 
         Returns
         -------
-        y : `torch.Tensor`, shape=(batch, channel, height, width)
+        y : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Output of the encoder block.
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Intermediate output before applying downsampling. Useful to
             implement skip connections.
-        indices : `torch.Tensor` or `None`
+        indices : :py:class:`torch.Tensor` or `None`
             Optional indices of the downsampling method, e.g. indices of the
-            maxima when using `torch.nn.functional.max_pool2d`. Useful for
-            upsampling later. If no indices are required to upsample, simply
-            return ``indices`` = `None`.
+            maxima when using :py:func:`torch.nn.functional.max_pool2d`. Useful
+            for upsampling later. If no indices are required to upsample,
+            simply return ``indices=None``.
 
         """
         # the forward pass of the layers of the block
@@ -239,57 +232,43 @@ class EncoderBlock(Block):
     def downsample(self, x):
         """Define the downsampling method.
 
-        The `~pysegcnn.core.layers.EncoderBlock.downsample` method should
-        implement the spatial pooling operation.
+        The :py:meth:`~pysegcnn.core.layers.EncoderBlock.downsample` method
+        should implement the spatial pooling operation.
 
         Use one of the following functions to downsample:
-            - `torch.nn.functional.max_pool2d`
-            - `torch.nn.functional.interpolate`
+            - :py:func:`torch.nn.functional.max_pool2d`
+            - :py:func:`torch.nn.functional.interpolate`
 
-        See `pysegcnn.core.layers.ConvBnReluMaxPool` for an example
+        See :py:class:`pysegcnn.core.layers.ConvBnReluMaxPool` for an example
         implementation.
 
         Parameters
         ----------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Input tensor, e.g. output of a convolutional block.
 
         Raises
         ------
         NotImplementedError
-            Raised if `pysegcnn.core.layers.EncoderBlock` is not inherited.
+            Raised if :py:class:`pysegcnn.core.layers.EncoderBlock` is not
+            inherited.
 
         Returns
         -------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             The spatially downsampled tensor.
-        indices : `torch.Tensor` or `None`
+        indices : :py:class:`torch.Tensor` or `None`
             Optional indices of the downsampling method, e.g. indices of the
-            maxima when using `torch.nn.functional.max_pool2d`. Useful for
-            upsampling later. If no indices are required to upsample, simply
-            return ``indices`` = `None`.
+            maxima when using :py:func:`torch.nn.functional.max_pool2d`. Useful
+            for upsampling later. If no indices are required to upsample,
+            simply return ``indices=None``.
 
         """
         raise NotImplementedError('Implement the downsampling function.')
 
 
 class DecoderBlock(Block):
-    """Block of a convolutional decoder.
-
-    Parameters
-    ----------
-    in_channels : `int`
-        Number of input channels.
-    out_channels : `int`
-        Number of output channels.
-    **kwargs: 'dict' [`str`]
-         Additional arguments passed to `pysegcnn.core.layers.Conv2dSame`.
-
-    Returns
-    -------
-    None.
-
-    """
+    """Block of a convolutional decoder."""
 
     def __init__(self, in_channels, out_channels, **kwargs):
         super().__init__(in_channels, out_channels, **kwargs)
@@ -299,21 +278,21 @@ class DecoderBlock(Block):
 
         Parameters
         ----------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Input tensor.
-        feature : `torch.Tensor`, shape=(batch, channel, height, width)
-            Intermediate output of a layer in the encoder.
-            If ``skip`` = True, ``feature`` is concatenated (along the channel
-            axis) to the output of the respective upsampling layer in the
-            decoder (skip connection).
-        indices : `torch.Tensor` or `None`
+        feature : :py:class:`torch.Tensor`, shape=(b, c, h, w)
+            Intermediate output of a layer in the encoder. If ``skip=True``,
+            ``feature`` is concatenated (along the channel axis) to the output
+            of the respective upsampling layer in the decoder (skip connection)
+            .
+        indices : :py:class:`torch.Tensor` or `None`
             Indices of the encoder downsampling method.
         skip : `bool`
             Whether to apply the skip connection.
 
         Returns
         -------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Output of the decoder block.
 
         """
@@ -334,35 +313,36 @@ class DecoderBlock(Block):
     def upsample(self, x, feature, indices):
         """Define the upsampling method.
 
-        The `~pysegcnn.core.layers.DecoderBlock.upsample` method should
-        implement the spatial upsampling operation.
+        The :py:meth:`~pysegcnn.core.layers.DecoderBlock.upsample` method
+        should implement the spatial upsampling operation.
 
         Use one of the following functions to upsample:
-            - `torch.nn.functional.max_unpool2d`
-            - `torch.nn.functional.interpolate`
+            - :py:func:`torch.nn.functional.max_unpool2d`
+            - :py:func:`torch.nn.functional.interpolate`
 
-        See `pysegcnn.core.layers.ConvBnReluMaxUnpool` or
-        `pysegcnn.core.layers.ConvBnReluUpsample` for an example
+        See :py:class:`pysegcnn.core.layers.ConvBnReluMaxUnpool` or
+        :py:class:`pysegcnn.core.layers.ConvBnReluUpsample` for an example
         implementation.
 
         Parameters
         ----------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Input tensor, e.g. output of a convolutional block.
-        feature : `torch.Tensor`, shape=(batch, channel, height, width)
+        feature : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Intermediate output of a layer in the encoder. Used to implement
             skip connections.
-        indices : `torch.Tensor` or `None`
+        indices : :py:class:`torch.Tensor` or `None`
             Indices of the encoder downsampling method.
 
         Raises
         ------
         NotImplementedError
-            Raised if `pysegcnn.core.layers.DecoderBlock` is not inherited.
+            Raised if :py:class:`pysegcnn.core.layers.DecoderBlock` is not
+            inherited.
 
         Returns
         -------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             The spatially upsampled tensor.
 
         """
@@ -373,31 +353,50 @@ class Encoder(nn.Module):
     """Generic convolutional encoder.
 
     When instanciating an encoder-decoder architechure, ``filters`` should be
-    the same for `pysegcnn.core.layers.Encoder` and
-    `pysegcnn.core.layers.Decoder`.
+    the same for :py:class:`pysegcnn.core.layers.Encoder` and
+    :py:class:`pysegcnn.core.layers.Decoder`.
 
-    See `pysegcnn.core.models.UNet` for an example implementation.
+    See :py:class:`pysegcnn.core.models.UNet` for an example implementation.
 
-    Parameters
+    Attributes
     ----------
-    filters : `list` [`int`]
-        List of input channels to each convolutional block. The length of
-        ``filters`` determines the depth of the encoder. The first element of
-        ``filters`` has to be the number of channels of the input images.
-    block : `pysegcnn.core.layers.EncoderBlock`
+    features : :py:class:`numpy.ndarray`
+        Input channels to each convolutional block, i.e. ``filters``.
+    block : :py:class:`pysegcnn.core.layers.EncoderBlock`
         The convolutional block defining a layer in the encoder.
-        A subclass of `pysegcnn.core.layers.EncoderBlock`, e.g.
-        `pysegcnn.core.layers.ConvBnReluMaxPool`.
-    **kwargs: 'dict' [`str`]
-        Additional arguments passed to `pysegcnn.core.layers.Conv2dSame`.
-
-    Returns
-    -------
-    None.
+        A subclass of :py:class:`pysegcnn.core.layers.EncoderBlock`, e.g.
+        :py:class:`pysegcnn.core.layers.ConvBnReluMaxPool`.
+    layers : :py:class:`torch.nn.ModuleList`
+        List of blocks in the encoder.
+    cache : `dict`
+        Intermediate encoder outputs. Dictionary with keys:
+            ``'feature'``
+                The intermediate encoder outputs (:py:class:`torch.Tensor`).
+            ``'indices'``
+                The indices of the max pooling layer, if required
+                (:py:class:`torch.Tensor`).
 
     """
 
     def __init__(self, filters, block, **kwargs):
+        """Initialize.
+
+        Parameters
+        ----------
+        filters : `list` [`int`]
+            List of input channels to each convolutional block. The length of
+            ``filters`` determines the depth of the encoder. The first element
+            of ``filters`` has to be the number of channels of the input
+            images.
+        block : :py:class:`pysegcnn.core.layers.EncoderBlock`
+            The convolutional block defining a layer in the encoder.
+            A subclass of :py:class:`pysegcnn.core.layers.EncoderBlock`, e.g.
+            :py:class:`pysegcnn.core.layers.ConvBnReluMaxPool`.
+        **kwargs: `dict` [`str`]
+            Additional arguments passed to
+            :py:class:`pysegcnn.core.layers.Conv2dSame`.
+
+        """
         super().__init__()
 
         # the number of filters for each block: the first element of filters
@@ -423,22 +422,22 @@ class Encoder(nn.Module):
         """Forward pass of the encoder.
 
         Stores intermediate outputs in a dictionary. The keys of the dictionary
-        are the number of the network layers and the values are dictionaries
+        are the numbers of the network layers and the values are dictionaries
         with the following (key, value) pairs:
-            ``"feature"``
-                The intermediate encoder outputs (`torch.Tensor`).
-            ``"indices"``
+            ``'feature'``
+                The intermediate encoder outputs (:py:class:`torch.Tensor`).
+            ``'indices'``
                 The indices of the max pooling layer, if required
-                (`torch.Tensor`).
+                (:py:class:`torch.Tensor`).
 
         Parameters
         ----------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Input image.
 
         Returns
         -------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Output of the encoder.
 
         """
@@ -459,33 +458,47 @@ class Decoder(nn.Module):
     """Generic convolutional decoder.
 
     When instanciating an encoder-decoder architechure, ``filters`` should be
-    the same for `pysegcnn.core.layers.Encoder` and
-    `pysegcnn.core.layers.Decoder`.
+    the same for :py:class:`pysegcnn.core.layers.Encoder` and
+    :py:class:`pysegcnn.core.layers.Decoder`.
 
-    See `pysegcnn.core.models.UNet` for an example implementation.
+    See :py:class:`pysegcnn.core.models.UNet` for an example implementation.
 
-    Parameters
+    Attributes
     ----------
-    filters : `list` [`int`]
-        List of input channels to each convolutional block. The length of
-        ``filters`` determines the depth of the decoder. The first element of
-        ``filters`` has to be the number of channels of the input images.
-    block : `pysegcnn.core.layers.DecoderBlock`
+    features : :py:class:`numpy.ndarray`
+        Input channels to each convolutional block, i.e. ``filters``.
+    block : :py:class:`pysegcnn.core.layers.EncoderBlock`
         The convolutional block defining a layer in the decoder.
-        A subclass of `pysegcnn.core.layers.DecoderBlock`, e.g.
-        `pysegcnn.core.layers.ConvBnReluMaxUnpool`.
+        A subclass of :py:class:`pysegcnn.core.layers.EncoderBlock`, e.g.
+        :py:class:`pysegcnn.core.layers.ConvBnReluMaxPool`.
     skip : `bool`
         Whether to apply skip connections from the encoder to the decoder.
-    **kwargs: 'dict' [`str`]
-        Additional arguments passed to `pysegcnn.core.layers.Conv2dSame`.
-
-    Returns
-    -------
-    None.
+    layers : :py:class:`torch.nn.ModuleList`
+        List of blocks in the decoder.
 
     """
 
     def __init__(self, filters, block, skip=True, **kwargs):
+        """Initialize.
+
+        Parameters
+        ----------
+        filters : `list` [`int`]
+            List of input channels to each convolutional block. The length of
+            ``filters`` determines the depth of the decoder. The first element
+            of ``filters`` has to be the number of channels of the input
+            images.
+        block : :py:class:`pysegcnn.core.layers.DecoderBlock`
+            The convolutional block defining a layer in the decoder.
+            A subclass of :py:class:`pysegcnn.core.layers.DecoderBlock`, e.g.
+            :py:class:`pysegcnn.core.layers.ConvBnReluMaxUnpool`.
+        skip : `bool`, optional
+            Whether to apply skip connections from the encoder to the decoder.
+        **kwargs: `dict` [`str`]
+            Additional arguments passed to
+            :py:class:`pysegcnn.core.layers.Conv2dSame`.
+
+        """
         super().__init__()
 
         # the block of operations defining a layer in the decoder
@@ -520,20 +533,22 @@ class Decoder(nn.Module):
 
         Parameters
         ----------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Output of the encoder.
         enc_cache : `dict` [`dict`]
             Cache dictionary. The keys of the dictionary are the number of the
             network layers and the values are dictionaries with the following
             (key, value) pairs:
-                ``"feature"``
-                    The intermediate encoder outputs (`torch.Tensor`).
-                ``"indices"``
-                    The indices of the max pooling layer (`torch.Tensor`).
+                ``'feature'``
+                    The intermediate encoder outputs
+                    (:py:class:`torch.Tensor`).
+                ``'indices'``
+                    The indices of the max pooling layer
+                    (:py:class:`torch.Tensor`).
 
         Returns
         -------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Output of the decoder.
 
         """
@@ -552,23 +567,7 @@ class Decoder(nn.Module):
 
 
 class ConvBnReluMaxPool(EncoderBlock):
-    """Block of convolution, batchnorm, relu and 2x2 max pool.
-
-    Parameters
-    ----------
-    in_channels : `int`
-        Number of input channels.
-    out_channels : `int`
-        Number of output channels.
-    **kwargs: 'dict' [`str`]
-        Additional keyword arguments passed to
-        `pysegcnn.core.layers.Conv2dSame`.
-
-    Returns
-    -------
-    None.
-
-    """
+    """Block of convolution, batchnorm, relu and 2x2 max pool."""
 
     def __init__(self, in_channels, out_channels, **kwargs):
         super().__init__(in_channels, out_channels, **kwargs)
@@ -578,29 +577,30 @@ class ConvBnReluMaxPool(EncoderBlock):
 
         Returns
         -------
-        layers : `torch.nn.Sequential` [`torch.nn.Module`]
-            An instance of `torch.nn.Sequential` containing the sequence
-            of convolution, batchnorm and relu layer (`torch.nn.Module`)
-            instances.
+        layers : :py:class:`torch.nn.Sequential` [:py:class:`torch.nn.Module`]
+            An instance of :py:class:`torch.nn.Sequential` containing the
+            sequence of convolution, batchnorm and relu layer
+            (:py:class:`torch.nn.Module`) instances.
 
         """
         return conv_bn_relu(self.in_channels, self.out_channels, **self.kwargs)
 
     def downsample(self, x):
-        """2x2 max pooling layer, `torch.nn.functional.max_pool2d`.
+        """2x2 max pooling layer.
 
         Parameters
         ----------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Input tensor.
 
         Returns
         -------
-        x : `torch.Tensor`, shape=(batch, channel, height // 2, width // 2)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h // 2, w // 2)
             The 2x2 max pooled tensor.
-        indices : `torch.Tensor` or `None`
+        indices : :py:class:`torch.Tensor` or `None`
             The indices of the maxima. Useful for upsampling with
-            `torch.nn.functional.max_unpool2d`.
+            :py:func:`torch.nn.functional.max_unpool2d`.
+
         """
         x, indices = F.max_pool2d(x, kernel_size=2, return_indices=True)
         return x, indices
@@ -618,23 +618,7 @@ class ConvBnReluMaxPool(EncoderBlock):
 
 
 class ConvBnReluMaxUnpool(DecoderBlock):
-    """Block of convolution, batchnorm, relu and 2x2 max unpool.
-
-    Parameters
-    ----------
-    in_channels : `int`
-        Number of input channels.
-    out_channels : `int`
-        Number of output channels
-    **kwargs: 'dict' [`str`]
-        Additional keyword arguments passed to
-        `pysegcnn.core.layers.Conv2dSame`.
-
-    Returns
-    -------
-    None.
-
-    """
+    """Block of convolution, batchnorm, relu and 2x2 max unpool."""
 
     def __init__(self, in_channels, out_channels, **kwargs):
         super().__init__(in_channels, out_channels, **kwargs)
@@ -644,10 +628,10 @@ class ConvBnReluMaxUnpool(DecoderBlock):
 
         Returns
         -------
-        layers : `torch.nn.Sequential` [`torch.nn.Module`]
-            An instance of `torch.nn.Sequential` containing the sequence
-            of convolution, batchnorm and relu layer (`torch.nn.Module`)
-            instances.
+        layers : :py:class:`torch.nn.Sequential` [:py:class:`torch.nn.Module`]
+            An instance of :py:class:`torch.nn.Sequential` containing the
+            sequence of convolution, batchnorm and relu layer
+            (:py:class:`torch.nn.Module`) instances.
 
         """
         return conv_bn_relu(self.in_channels, self.out_channels, **self.kwargs)
@@ -657,18 +641,18 @@ class ConvBnReluMaxUnpool(DecoderBlock):
 
         Parameters
         ----------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Input tensor.
-        feature : `torch.Tensor`, shape=(batch, channel, height, width)
+        feature : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Intermediate output of a layer in the encoder. Used to determine
             the output shape of the upsampling operation.
-        indices : `torch.Tensor`
+        indices : :py:class:`torch.Tensor`
             The indices of the maxima of the max pooling operation
-            (as returned by `torch.nn.functional.max_pool2d`).
+            (as returned by :py:func:`torch.nn.functional.max_pool2d`).
 
         Returns
         -------
-        x : `torch.Tensor`, shape=(batch, channel, height * 2, width * 2)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h * 2, w * 2)
             The 2x2 max unpooled tensor.
 
         """
@@ -688,22 +672,7 @@ class ConvBnReluMaxUnpool(DecoderBlock):
 
 
 class ConvBnReluUpsample(DecoderBlock):
-    """Block of convolution, batchnorm, relu and nearest neighbor upsampling.
-
-    Parameters
-    ----------
-    in_channels : `int`
-        Number of input channels.
-    out_channels : `int`
-        Number of output channels
-    **kwargs: 'dict' [`str`]
-        Additional arguments passed to `pysegcnn.core.layers.Conv2dSame`.
-
-    Returns
-    -------
-    None.
-
-    """
+    """Block of convolution, batchnorm, relu and nearest neighbor upsample."""
 
     def __init__(self, in_channels, out_channels, **kwargs):
         super().__init__(in_channels, out_channels, **kwargs)
@@ -713,10 +682,10 @@ class ConvBnReluUpsample(DecoderBlock):
 
         Returns
         -------
-        layers : `torch.nn.Sequential` [`torch.nn.Module`]
-            An instance of `torch.nn.Sequential` containing the sequence
-            of convolution, batchnorm and relu layer (`torch.nn.Module`)
-            instances.
+        layers : :py:class:`torch.nn.Sequential` [:py:class:`torch.nn.Module`]
+            An instance of :py:class:`torch.nn.Sequential` containing the
+            sequence of convolution, batchnorm and relu layer
+            (:py:class:`torch.nn.Module`) instances.
 
         """
         return conv_bn_relu(self.in_channels, self.out_channels, **self.kwargs)
@@ -726,19 +695,19 @@ class ConvBnReluUpsample(DecoderBlock):
 
         Parameters
         ----------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Input tensor.
-        feature : `torch.Tensor`, shape=(batch, channel, height, width)
+        feature : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             Intermediate output of a layer in the encoder. Used to determine
             the output shape of the upsampling operation.
         indices : `None`, optional
             The indices of the maxima of the max pooling operation
-            (as returned by `torch.nn.functional.max_pool2d`). Not required by
-            this upsampling method.
+            (as returned by :py:func:`torch.nn.functional.max_pool2d`).
+            Not required by this upsampling method.
 
         Returns
         -------
-        x : `torch.Tensor`, shape=(batch, channel, height, width)
+        x : :py:class:`torch.Tensor`, shape=(b, c, h, w)
             The 2x2 upsampled tensor.
 
         """
diff --git a/pysegcnn/core/models.py b/pysegcnn/core/models.py
index 39ba1a1c4d6247e67aa0ef7a028e992ff53584c9..e24c76c8d1ce528fc8ea2348a63471d2ae0ff07b 100644
--- a/pysegcnn/core/models.py
+++ b/pysegcnn/core/models.py
@@ -37,15 +37,17 @@ class Network(nn.Module):
     """Generic Network class.
 
     The base class for each model. If you want to implement a new model,
-    inherit the ``~pysegcnn.core.models.Network`` class.
+    inherit the :py:class:`pysegcnn.core.models.Network` class.
 
-    Returns
-    -------
-    None.
+    Attributes
+    ----------
+    state_file : `str` or `None` or :py:class:`pathlib.Path`
+        The model state file, where the model parameters are saved.
 
     """
 
     def __init__(self):
+        """Initialize."""
         super().__init__()
 
         # initialize state file
@@ -89,9 +91,9 @@ class Network(nn.Module):
 
         Parameters
         ----------
-        state_file : `str` or `pathlib.Path`
+        state_file : `str` or :py:class:`pathlib.Path`
             Path to save the model state.
-        optimizer : `torch.optim.Optimizer`
+        optimizer : :py:class:`torch.optim.Optimizer`
             The optimizer used to train the model.
         bands : `list` [`str`] or `None`, optional
             List of bands the model is trained with. The default is None.
@@ -102,7 +104,7 @@ class Network(nn.Module):
         Returns
         -------
         model_state : `dict`
-            A dictionary containing the model and optimizer state
+            A dictionary containing the model and optimizer state.
 
         """
         # check if the output path exists and if not, create it
@@ -156,7 +158,7 @@ class Network(nn.Module):
 
         Parameters
         ----------
-        state_file : `str` or `pathlib.Path`
+        state_file : `str` or :py:class:`pathlib.Path`
            The model state file. Model state files are stored in
            pysegcnn/main/_models.
 
@@ -167,13 +169,13 @@ class Network(nn.Module):
 
         Returns
         -------
-        model : `pysegcnn.core.models.Network`
+        model : :py:class:`pysegcnn.core.models.Network`
             The pretrained model.
-        optimizer : `torch.optim.Optimizer`
+        optimizer : :py:class:`torch.optim.Optimizer`
            The optimizer used to train the model.
-        model_state : '`dict`
+        model_state : `dict`
             A dictionary containing the model and optimizer state, as
-            constructed by `~pysegcnn.core.Network.save`.
+            constructed by :py:meth:`~pysegcnn.core.Network.save`.
 
         """
         # load the pretrained model
@@ -216,7 +218,7 @@ class Network(nn.Module):
 
         Returns
         -------
-        state_file : `pathlib.Path` or `None`
+        state_file : :py:class:`pathlib.Path` or `None`
             The model state file.
 
         """
@@ -224,36 +226,58 @@ class Network(nn.Module):
 
 
 class UNet(Network):
-    """A PyTorch implementation of `U-Net`_.
+    """A slightly modified implementation of `U-Net`_ in PyTorch.
+
+    .. important::
 
-    Slightly modified version of U-Net:
-        - each convolution is followed by a batch normalization layer
-        - the upsampling is implemented by a 2x2 max unpooling operation
+        - Each convolution is followed by a batch normalization layer
+        - Upsampling is implemented by a 2x2 max unpooling operation
 
     .. _U-Net:
         https://arxiv.org/abs/1505.04597
 
-    Parameters
+    Attributes
     ----------
     in_channels : `int`
         Number of channels of the input images.
     nclasses : `int`
         Number of classes.
-    filters : `list` [`int`]
+    kwargs : `dict` [`str`]
+        Additional keyword arguments passed to
+        :py:class:`pysegcnn.core.layers.Conv2dSame`.
+    nfilters : `list` [`int`]
         List of input channels to each convolutional block.
     skip : `bool`
         Whether to apply skip connections from the encoder to the decoder.
-    **kwargs: 'dict' [`str`]
-        Additional keyword arguments passed to
-        `pysegcnn.core.layers.Conv2dSame`.
-
-    Returns
-    -------
-    None.
+    epoch : `int`
+        Number of epochs the model was trained.
+    encoder : :py:class:`pysegcnn.core.layers.Encoder`
+        The convolutional encoder.
+    decoder : :py:class:`pysegcnn.core.layers.Decoder`
+        The convolutional decoder.
+    classifier : :py:class:`pysegcnn.core.layers.Conv2dSame`
+        The classification layer, a 1x1 convolution.
 
     """
 
     def __init__(self, in_channels, nclasses, filters, skip, **kwargs):
+        """Initialize.
+
+        Parameters
+        ----------
+        in_channels : `int`
+            Number of channels of the input images.
+        nclasses : `int`
+            Number of classes.
+        filters : `list` [`int`]
+            List of input channels to each convolutional block.
+        skip : `bool`
+            Whether to apply skip connections from the encoder to the decoder.
+        **kwargs: `dict` [`str`]
+            Additional keyword arguments passed to
+            :py:class:`pysegcnn.core.layers.Conv2dSame`.
+
+        """
         super().__init__()
 
         # number of input channels