From fcb5475675d4353c5eb46586bcd357ba4a5fb551 Mon Sep 17 00:00:00 2001 From: Andre Anjos <andre.anjos@idiap.ch> Date: Tue, 7 Apr 2020 13:14:31 +0200 Subject: [PATCH] [predictor] Multiple fixes so it works confortably --- bob/ip/binseg/engine/predictor.py | 22 ++++++++++++++++------ bob/ip/binseg/script/predict.py | 20 +++++++++++++------- doc/evaluation.rst | 28 +++++++++++++++++++--------- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/bob/ip/binseg/engine/predictor.py b/bob/ip/binseg/engine/predictor.py index 016ce0bc..093c6c67 100644 --- a/bob/ip/binseg/engine/predictor.py +++ b/bob/ip/binseg/engine/predictor.py @@ -4,10 +4,13 @@ import os import time import datetime -import numpy as np + +import numpy import torch from tqdm import tqdm +import bob.io.base + import logging logger = logging.getLogger(__name__) @@ -35,9 +38,11 @@ def save_hdf5(predictions, names, output_folder): img = predictions.cpu().data[j].squeeze(0).numpy() filename = "{}.hdf5".format(names[j].split(".")[0]) fullpath = os.path.join(output_folder, filename) - logger.info(f"saving {filename}") + tqdm.write(f"Saving {fullpath}...") fulldir = os.path.dirname(fullpath) if not os.path.exists(fulldir): + tqdm.write(f"Creating directory {fulldir}...") + # protect against concurrent access - exist_ok=True os.makedirs(fulldir, exist_ok=True) bob.io.base.save(img, fullpath) @@ -62,8 +67,13 @@ def run(model, data_loader, device, output_folder): """ logger.info("Start prediction") - logger.info(f"Output folder: {output_folder}, Device: {device}") - os.makedirs(output_folder, exist_ok=True) + logger.info(f"Output folder: {output_folder}") + logger.info(f"Device: {device}") + + if not os.path.exists(output_folder): + logger.debug(f"Creating output directory '{output_folder}'...") + # protect against concurrent access - exist_ok=True + os.makedirs(output_folder, exist_ok=True) model.eval().to(device) # Sigmoid for probabilities @@ -105,8 +115,8 @@ def run(model, data_loader, device, output_folder): total_time = datetime.timedelta(seconds=int(time.time() - start_total_time)) logger.info(f"Total time: {total_time}") - average_batch_time = np.mean(times) + average_batch_time = numpy.mean(times) logger.info(f"Average batch time: {average_batch_time:g}s\n") - average_image_time = np.sum(times * len_samples) / float(sum(len_samples)) + average_image_time = numpy.sum(numpy.array(times) * len_samples) / float(sum(len_samples)) logger.info(f"Average image time: {average_image_time:g}s\n") diff --git a/bob/ip/binseg/script/predict.py b/bob/ip/binseg/script/predict.py index 8fe08c40..560a8a19 100644 --- a/bob/ip/binseg/script/predict.py +++ b/bob/ip/binseg/script/predict.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # coding=utf-8 +import os + import click from click_plugins import with_plugins @@ -15,6 +17,7 @@ from bob.extension.scripts.click_helper import ( ) from ..engine.predictor import run +from ..utils.checkpointer import DetectronCheckpointer import logging logger = logging.getLogger(__name__) @@ -27,7 +30,7 @@ logger = logging.getLogger(__name__) \b 1. Runs prediction on an existing dataset configuration: - +\b $ bob binseg predict -vv m2unet drive-test --weight=path/to/model_final.pth --output-path=path/to/predictions \b 2. To run prediction on a folder with your own images, you must first @@ -36,10 +39,10 @@ logger = logging.getLogger(__name__) performance. To figure out such specifications, you must consult the dataset configuration used for **training** the provided model. Once you figured this out, do the following: - - $ bob binseg config copy image-folder myfolder.py - # modify "myfolder.py" to include the base path and required transforms - $ bob binseg predict -vv m2unet myfolder.py --weight=path/to/model_final.pth --output-path=path/to/predictions +\b + $ bob binseg config copy folder-dataset-example mydataset.py + # modify "mydataset.py" to include the base path and required transforms + $ bob binseg predict -vv m2unet mydataset.py --weight=path/to/model_final.pth --output-path=path/to/predictions """, ) @click.option( @@ -102,8 +105,11 @@ def predict(output_path, model, dataset, batch_size, device, weight, **kwargs): ) # checkpointer, loads pre-fit model - checkpointer = DetectronCheckpointer(model, save_dir=output_path, + weight_fullpath = os.path.abspath(weight) + weight_path = os.path.dirname(weight_fullpath) + weight_name = os.path.basename(weight_fullpath) + checkpointer = DetectronCheckpointer(model, save_dir=weight_path, save_to_disk=False) - checkpointer.load(weight) + checkpointer.load(weight_name) run(model, data_loader, device, output_path) diff --git a/doc/evaluation.rst b/doc/evaluation.rst index 3b0f758d..0329dabd 100644 --- a/doc/evaluation.rst +++ b/doc/evaluation.rst @@ -6,13 +6,22 @@ Inference and Evaluation ========================== +This guides explains how to run inference or a complete evaluation using +command-line tools. Inference produces probability maps for input images, +while evaluation will analyze such output against existing annotations and +produce performance figures. + Inference --------- You may use one of your trained models (or :ref:`one of ours <bob.ip.binseg.models>` to run inference on existing datasets or your own -dataset. +dataset. In inference (or prediction) mode, we input data, the trained model, +and output HDF5 files containing the prediction outputs for every input image. +Each HDF5 file contains a single object with a 2-dimensional matrix of floating +point numbers indicating the vessel probability (``[0.0,1.0]``) for each pixel +in the input image. Inference on an existing datasets @@ -43,7 +52,6 @@ you need to instantiate one of: Read the appropriate module documentation for details. - .. code-block:: bash $ bob binseg config copy folder-dataset-example mydataset.py @@ -53,16 +61,18 @@ Read the appropriate module documentation for details. $ bob binseg predict -vv <model> -w <path/to/model.pth> ./mydataset.py +Inference typically consumes less resources than training, but you may speed +things up using ``--device='cuda:0'`` in case you have a GPU. + + Evaluation ---------- -To evaluate trained models use our CLI interface. ``bob binseg evaluate`` -followed by the model and the dataset configuration, and the path to the -pretrained model via the argument ``--weight``. - -Alternatively point to the output folder used during training via the -``--output-path`` argument. The Checkpointer will load the model as indicated -in the file: ``last_checkpoint``. +In evaluation we input an **annotated** dataset and a pre-trained model to +output a complete set of performance figures that can help analysis of model +performance. Evaluation is done using ``bob binseg evaluate`` followed by the +model and the dataset configuration, and the path to the pretrained model via +the ``--weight`` argument. Use ``bob binseg evaluate --help`` for more information. -- GitLab