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