From d5d1d787ca8c014edc48a64f14b0e40ce11dea73 Mon Sep 17 00:00:00 2001 From: Amir MOHAMMADI <amir.mohammadi@idiap.ch> Date: Thu, 6 Jun 2019 15:24:45 +0200 Subject: [PATCH] Adds a sort command and small fixes --- bob/bio/base/annotator/FailSafe.py | 2 ++ bob/bio/base/grid.py | 3 +- bob/bio/base/script/sort.py | 36 +++++++++++++++++++++++ bob/bio/base/test/test_commands.py | 46 +++++++++++++++++++++++------- bob/bio/base/utils/io.py | 5 +++- conda/meta.yaml | 1 + setup.py | 1 + 7 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 bob/bio/base/script/sort.py diff --git a/bob/bio/base/annotator/FailSafe.py b/bob/bio/base/annotator/FailSafe.py index bfad2513..b690f243 100644 --- a/bob/bio/base/annotator/FailSafe.py +++ b/bob/bio/base/annotator/FailSafe.py @@ -48,6 +48,8 @@ class FailSafe(Annotator): if not annotations: logger.debug( "Annotator `%s' returned empty annotations.", annotator) + else: + logger.debug("Annotator `%s' succeeded!", annotator) kwargs['annotations'].update(annotations or {}) # check if we have all the required annotations if all(key in kwargs['annotations'] for key in self.required_keys): diff --git a/bob/bio/base/grid.py b/bob/bio/base/grid.py index 60aa0125..791604d0 100644 --- a/bob/bio/base/grid.py +++ b/bob/bio/base/grid.py @@ -8,13 +8,14 @@ PREDEFINED_QUEUES = { 'default' : {}, '2G' : {'queue' : 'all.q', 'memfree' : '2G'}, '4G' : {'queue' : 'all.q', 'memfree' : '4G'}, + '4G-q1d' : {'queue' : 'q1d', 'memfree' : '4G'}, '4G-io-big' : {'queue' : 'q1d', 'memfree' : '4G', 'io_big' : True}, '8G' : {'queue' : 'q1d', 'memfree' : '8G'}, '8G-io-big' : {'queue' : 'q1d', 'memfree' : '8G', 'io_big' : True}, '16G' : {'queue' : 'q1dm', 'memfree' : '16G', 'pe_opt' : 'pe_mth 2', 'hvmem' : '8G'}, '16G-io-big' : {'queue' : 'q1dm', 'memfree' : '16G', 'pe_opt' : 'pe_mth 2', 'hvmem' : '8G', 'io_big' : True}, '32G' : {'queue' : 'q1dm', 'memfree' : '32G', 'pe_opt' : 'pe_mth 4', 'hvmem' : '8G', 'io_big' : True}, - '64G' : {'queue' : 'q1dm', 'memfree' : '64G', 'pe_opt' : 'pe_mth 8', 'hvmem' : '8G', 'io_big' : True}, + '64G' : {'queue' : 'q1dm', 'memfree' : '56G', 'pe_opt' : 'pe_mth 8', 'hvmem' : '7G', 'io_big' : True}, 'Week' : {'queue' : 'q1wm', 'memfree' : '32G', 'pe_opt' : 'pe_mth 4', 'hvmem' : '8G'}, 'GPU' : {'queue' : 'gpu'} } diff --git a/bob/bio/base/script/sort.py b/bob/bio/base/script/sort.py new file mode 100644 index 00000000..74691263 --- /dev/null +++ b/bob/bio/base/script/sort.py @@ -0,0 +1,36 @@ +"""Sorts score files based on their score value +""" +import click +import logging +import numpy +from bob.bio.base.score.load import load_score, dump_score +from bob.extension.scripts.click_helper import verbosity_option, log_parameters + +logger = logging.getLogger(__name__) + + +@click.command( + epilog="""\b +Examples: + + $ bob bio sort -vvv /path/to/scores +""" +) +@click.argument( + "score_paths", + type=click.Path(exists=True, file_okay=True, dir_okay=False, writable=True), + nargs=-1, +) +@verbosity_option() +def sort(score_paths, **kwargs): + """Sorts score files based on their score values + + The conversion happens in-place; backup your scores before using this script + """ + log_parameters(logger) + + for path in score_paths: + logger.info("Sorting: %s", path) + scores = load_score(path) + scores = scores[numpy.argsort(scores["score"])] + dump_score(path, scores) diff --git a/bob/bio/base/test/test_commands.py b/bob/bio/base/test/test_commands.py index 8a92e486..dbe1ace1 100644 --- a/bob/bio/base/test/test_commands.py +++ b/bob/bio/base/test/test_commands.py @@ -1,12 +1,14 @@ '''Tests for bob.measure scripts''' -import sys -import filecmp import click from click.testing import CliRunner +import shutil import pkg_resources -from ..script import commands +import numpy +import nose from bob.extension.scripts.click_helper import assert_click_runner_result +from ..script import commands, sort +from ..score import scores def test_metrics(): dev1 = pkg_resources.resource_filename('bob.bio.base.test', @@ -87,7 +89,6 @@ def test_metrics(): assert_click_runner_result(result) - def test_roc(): dev1 = pkg_resources.resource_filename('bob.bio.base.test', 'data/dev-4col.txt') @@ -138,7 +139,6 @@ def test_roc(): assert_click_runner_result(result) - def test_det(): dev1 = pkg_resources.resource_filename('bob.bio.base.test', 'data/dev-4col.txt') @@ -170,7 +170,6 @@ def test_det(): click.echo(result.output) assert_click_runner_result(result) - dev_nonorm = pkg_resources.resource_filename('bob.bio.base.test', 'data/scores-nonorm-dev') dev_ztnorm = pkg_resources.resource_filename('bob.bio.base.test', @@ -225,7 +224,6 @@ def test_epc(): assert_click_runner_result(result) - def test_hist(): dev1 = pkg_resources.resource_filename('bob.bio.base.test', 'data/dev-4col.txt') @@ -260,7 +258,6 @@ def test_hist(): assert_click_runner_result(result) - def test_cmc(): dev1 = pkg_resources.resource_filename('bob.bio.base.test', 'data/scores-cmc-5col.txt') @@ -296,8 +293,6 @@ def test_cmc(): assert_click_runner_result(result) - - def test_dir(): dev1 = pkg_resources.resource_filename('bob.bio.base.test', 'data/scores-nonorm-openset-dev') @@ -317,3 +312,34 @@ def test_dir(): if result.output: click.echo(result.output) assert_click_runner_result(result) + + +def test_sort(): + + def sorted_scores(score_lines): + lines = [] + floats = [] + for line in score_lines: + lines.append(line) + floats.append(line[-1]) + sort_idx = numpy.argsort(floats) + lines = [lines[i] for i in sort_idx] + return lines + + dev1 = pkg_resources.resource_filename('bob.bio.base.test', + 'data/scores-nonorm-dev') + runner = CliRunner() + with runner.isolated_filesystem(): + # create a temporary sort file and sort it and check if it is sorted! + + path = "scores.txt" + shutil.copy(dev1, path) + + result = runner.invoke(sort.sort, [path]) + assert_click_runner_result(result, exit_code=0) + + # load dev1 and sort it and compare to path + dev1_sorted = sorted_scores(scores(dev1)) + path_scores = list(scores(path)) + + nose.tools.assert_list_equal(dev1_sorted, path_scores) diff --git a/bob/bio/base/utils/io.py b/bob/bio/base/utils/io.py index e9f6424f..d69fece9 100644 --- a/bob/bio/base/utils/io.py +++ b/bob/bio/base/utils/io.py @@ -306,7 +306,10 @@ def vstack_features(reader, paths, same_size=False, allow_missing_files=False): raise ValueError("Both same_size and allow_missing_files cannot be True at" " the same time.") iterable = _generate_features(reader, paths, same_size, allow_missing_files) - dtype, shape = next(iterable) + try: + dtype, shape = next(iterable) + except StopIteration: + return numpy.array([]) if same_size: total_size = int(len(paths) * numpy.prod(shape)) all_features = numpy.fromiter(iterable, dtype, total_size) diff --git a/conda/meta.yaml b/conda/meta.yaml index 1287a68b..ecea2f8f 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -75,6 +75,7 @@ test: - bob bio dir --help - bob bio gen --help - bob bio evaluate --help + - bob bio sort --help - nosetests --with-coverage --cover-package={{ name }} -sv {{ name }} - sphinx-build -aEW {{ project_dir }}/doc {{ project_dir }}/sphinx - sphinx-build -aEb doctest {{ project_dir }}/doc sphinx diff --git a/setup.py b/setup.py index 0fb586ed..d8d2797c 100644 --- a/setup.py +++ b/setup.py @@ -149,6 +149,7 @@ setup( 'gen = bob.bio.base.script.gen:gen', 'evaluate = bob.bio.base.script.commands:evaluate', 'baseline = bob.bio.base.script.baseline:baseline', + 'sort = bob.bio.base.script.sort:sort', ], # annotators -- GitLab