diff --git a/bob/pad/base/tools/algorithm.py b/bob/pad/base/tools/algorithm.py index 6a52b9ba51b9ab202034d004aea6bd164050f59c..f8ee01bf90f60801ad7dc69a96f1f7ff92f2f9d4 100644 --- a/bob/pad/base/tools/algorithm.py +++ b/bob/pad/base/tools/algorithm.py @@ -115,13 +115,31 @@ def project(algorithm, extractor, groups=None, indices=None, allow_missing_files feature_file = str(feature_files[i]) projected_file = str(projected_files[i]) + if not os.path.exists(feature_file): + if allow_missing_files: + logger.debug("... Cannot find extracted feature file %s; skipping", feature_file) + continue + else: + logger.error("Cannot find extracted feature file %s", feature_file) + if not utils.check_file(projected_file, force, 1000): - logger.info("- Projection: projecting file: %s", feature_file) + logger.debug("... Projecting features for file '%s'", feature_file) + # load feature feature = extractor.read_feature(feature_file) # project feature projected = algorithm.project(feature) + + if projected is None: + if allow_missing_files: + logger.debug("... Projection for extracted file %s failed; skipping", feature_file) + continue + else: + raise RuntimeError("Projection of file '%s' was not successful" % feature_file) # write it bob.io.base.create_directories_safe(os.path.dirname(projected_file)) algorithm.write_feature(projected, projected_file) + else: + logger.debug("... Skipping feature file '%s' since projected file '%s' exists", feature_file, projected_file) + diff --git a/bob/pad/base/tools/scoring.py b/bob/pad/base/tools/scoring.py index 7c5639a74d149bc0139d233be247bb2439619039..119477389e1e0008ffcb702f4709ba1e89d7d695 100644 --- a/bob/pad/base/tools/scoring.py +++ b/bob/pad/base/tools/scoring.py @@ -22,13 +22,19 @@ from .FileSelector import FileSelector from bob.bio.base import utils -def _compute_scores(algorithm, toscore_objects): - """Compute scores for the given list of objectis using provided algorithm. +def _compute_scores(algorithm, toscore_objects, allow_missing_files): + """Compute scores for the given list of objects using provided algorithm. """ # the scores to be computed scores = [] + # Loops over the toscore sets for i, toscore_element in enumerate(toscore_objects): + # filter missing files + if allow_missing_files and not os.path.exists(toscore_element): + # we keep NaN score for such elements + scores.insert(i, [numpy.nan]) + continue # read toscore toscore = algorithm.read_toscore_object(toscore_element) # compute score @@ -100,8 +106,11 @@ def _save_scores(score_file, scores, toscore_objects, write_compressed=False): for i, toscore_object in enumerate(toscore_objects): id_str = (str(toscore_object.client_id)).zfill(3) sample_name = str(toscore_object.make_path()) + + # scores[i] is a list, so + # each sample is allowed to have multiple scores for score in scores[i]: - if not toscore_object.attack_type or toscore_object.attack_type=="None": + if not toscore_object.attack_type or toscore_object.attack_type == "None": _write(f, "%s %s %s %.12f\n" % (id_str, id_str, sample_name, score), write_compressed) else: attackname = toscore_object.attack_type @@ -110,7 +119,7 @@ def _save_scores(score_file, scores, toscore_objects, write_compressed=False): _close_written(score_file, f, write_compressed) -def _scores_all(algorithm, group, force, write_compressed=False): +def _scores_all(algorithm, group, force, allow_missing_files=False, write_compressed=False): """Computes scores for all (real, attack) files in a given group using the provided algorithm.""" # the file selector object fs = FileSelector.instance() @@ -122,6 +131,7 @@ def _scores_all(algorithm, group, force, write_compressed=False): type_objects = ['real', 'attack'] total_scores = [] + one_score_file_exists = False for i in range(0, 2): current_objects = current_toscore_objects[i] obj_type = type_objects[i] @@ -132,19 +142,25 @@ def _scores_all(algorithm, group, force, write_compressed=False): if utils.check_file(score_file, force): logger.warn("Score file '%s' already exists.", score_file) total_scores = [] + one_score_file_exists = True else: # get the attack files current_files = fs.get_paths(current_objects, 'projected' if algorithm.performs_projection else 'extracted') # compute scores for the list of File objects - cur_scores = _compute_scores(algorithm, current_files) + cur_scores = _compute_scores(algorithm, current_files, allow_missing_files) total_scores += cur_scores # Save scores to text file _save_scores(score_file, cur_scores, current_objects, write_compressed) if total_scores != [] and not utils.check_file(fs.score_file_combined(group), force): # save all scores together in one file - _save_scores(fs.score_file_combined(group), total_scores, - current_toscore_objects[0]+current_toscore_objects[1], write_compressed) + if one_score_file_exists: + logger.warn("Since at least one score file already pre-existed, " + "we skip combining individual score files together. " + "You can do it manually, using 'cat' or similar utilities.") + else: + _save_scores(fs.score_file_combined(group), total_scores, + current_toscore_objects[0]+current_toscore_objects[1], write_compressed) def compute_scores(algorithm, force=False, groups=['dev', 'eval'], allow_missing_files=False, write_compressed=False): @@ -175,4 +191,4 @@ def compute_scores(algorithm, force=False, groups=['dev', 'eval'], allow_missing algorithm.load_projector(fs.projector_file) for group in groups: - _scores_all(algorithm, group, force, write_compressed) + _scores_all(algorithm, group, force, allow_missing_files, write_compressed)