| |
|
|
| |
| |
| |
|
|
| |
|
|
| |
| |
| |
| |
| |
| |
| r"""Evaluate the frame interpolation model from a tfrecord and store results. |
| |
| This script runs the inference on examples in a tfrecord and generates images |
| and numeric results according to the gin config. For details, see the |
| run_evaluation() function below. |
| |
| Usage example: |
| python3 -m frame_interpolation.eval.eval_cli -- \ |
| --gin_config <path to eval_dataset.gin> \ |
| --base_folder <the root directory to all training sessions> \ |
| --label < the foldername of the training session> |
| |
| or |
| |
| python3 -m frame_interpolation.eval.eval_cli -- \ |
| --gin_config <path to eval_dataset.gin> \ |
| --model_path <The filepath of the TF2 saved model> |
| |
| The output is saved at the parent directory of the `model_path`: |
| <parent directory of model_path>/batch_eval. |
| |
| The evaluation is run on a GPU by default. Add the `--mode` argument for others. |
| """ |
| import collections |
| import os |
| from typing import Any, Dict |
|
|
| from . import util |
| from absl import app |
| from absl import flags |
| from absl import logging |
| import gin.tf |
| from ..losses import losses |
| import numpy as np |
| import tensorflow as tf |
| from ..training import data_lib |
|
|
|
|
| _GIN_CONFIG = flags.DEFINE_string('gin_config', None, 'Gin config file.') |
| _LABEL = flags.DEFINE_string( |
| 'label', None, 'Descriptive label for the training session to eval.') |
| _BASE_FOLDER = flags.DEFINE_string('base_folder', None, |
| 'Root folder of training sessions.') |
| _MODEL_PATH = flags.DEFINE_string( |
| name='model_path', |
| default=None, |
| help='The path of the TF2 saved model to use. If _MODEL_PATH argument is ' |
| 'directly specified, _LABEL and _BASE_FOLDER arguments will be ignored.') |
| _OUTPUT_FRAMES = flags.DEFINE_boolean( |
| name='output_frames', |
| default=False, |
| help='If true, saves the the inputs, groud-truth and interpolated frames.') |
| _MODE = flags.DEFINE_enum('mode', 'gpu', ['cpu', 'gpu'], |
| 'Device to run evaluations.') |
|
|
|
|
| @gin.configurable('experiment') |
| def _get_experiment_config(name) -> Dict[str, Any]: |
| """Fetches the gin config.""" |
| return { |
| 'name': name, |
| } |
|
|
|
|
| def _set_visible_devices(): |
| """Set the visible devices according to running mode.""" |
| mode_devices = tf.config.list_physical_devices(_MODE.value.upper()) |
| tf.config.set_visible_devices([], 'GPU') |
| tf.config.set_visible_devices([], 'TPU') |
| tf.config.set_visible_devices(mode_devices, _MODE.value.upper()) |
| return |
|
|
|
|
| @gin.configurable('evaluation') |
| def run_evaluation(model_path, tfrecord, output_dir, max_examples, metrics): |
| """Runs the eval loop for examples in the tfrecord. |
| |
| The evaluation is run for the first 'max_examples' number of examples, and |
| resulting images are stored into the given output_dir. Any tensor that |
| appears like an image is stored with its name -- this may include intermediate |
| results, depending on what the model outputs. |
| |
| Additionally, numeric results are stored into results.csv file within the same |
| directory. This includes per-example metrics and the mean across the whole |
| dataset. |
| |
| Args: |
| model_path: Directory TF2 saved model. |
| tfrecord: Directory to the tfrecord eval data. |
| output_dir: Directory to store the results into. |
| max_examples: Maximum examples to evaluate. |
| metrics: The names of loss functions to use. |
| """ |
| model = tf.saved_model.load(model_path) |
|
|
| |
| with tf.io.gfile.GFile(os.path.join(output_dir, 'readme.txt'), mode='w') as f: |
| print('Results for:', file=f) |
| print(f' model: {model_path}', file=f) |
| print(f' tfrecord: {tfrecord}', file=f) |
|
|
| with tf.io.gfile.GFile( |
| os.path.join(output_dir, 'results.csv'), mode='w') as csv_file: |
| test_losses = losses.test_losses(metrics, [ |
| 1.0, |
| ] * len(metrics)) |
| title_row = ['key'] + list(test_losses) |
| print(', '.join(title_row), file=csv_file) |
|
|
| datasets = data_lib.create_eval_datasets( |
| batch_size=1, |
| files=[tfrecord], |
| names=[os.path.basename(output_dir)], |
| max_examples=max_examples) |
| dataset = datasets[os.path.basename(output_dir)] |
|
|
| all_losses = collections.defaultdict(list) |
| for example in dataset: |
| inputs = { |
| 'x0': example['x0'], |
| 'x1': example['x1'], |
| 'time': example['time'][..., tf.newaxis], |
| } |
| prediction = model(inputs, training=False) |
|
|
| |
| path = example['path'][0].numpy().decode('utf-8') |
| key = path.rsplit('.', 1)[0].rsplit(os.sep)[-1] |
|
|
| |
| combined = {**prediction, **example} if _OUTPUT_FRAMES.value else {} |
| for name in combined: |
| image = combined[name] |
| if isinstance(image, tf.Tensor): |
| |
| |
| |
| |
| if len(image.shape) == 4 and (image.shape[-1] == 1 or |
| image.shape[-1] == 3): |
| util.write_image( |
| os.path.join(output_dir, f'{key}_{name}.png'), image[0].numpy()) |
|
|
| |
| |
| if 'y' in example: |
| loss_values = [] |
| |
| |
| |
| prediction['image'] = tf.clip_by_value(prediction['image'], 0., 1.) |
| for loss_name, (loss_value_fn, loss_weight_fn) in test_losses.items(): |
| loss_value = loss_value_fn(example, prediction) * loss_weight_fn(0) |
| loss_values.append(loss_value.numpy()) |
| all_losses[loss_name].append(loss_value.numpy()) |
| print(f'{key}, {str(loss_values)[1:-1]}', file=csv_file) |
|
|
| if all_losses: |
| totals = [np.mean(all_losses[loss_name]) for loss_name in test_losses] |
| print(f'mean, {str(totals)[1:-1]}', file=csv_file) |
| totals_dict = { |
| loss_name: np.mean(all_losses[loss_name]) for loss_name in test_losses |
| } |
| logging.info('mean, %s', totals_dict) |
|
|
|
|
| def main(argv): |
| if len(argv) > 1: |
| raise app.UsageError('Too many command-line arguments.') |
|
|
| if _MODEL_PATH.value is not None: |
| model_path = _MODEL_PATH.value |
| else: |
| model_path = os.path.join(_BASE_FOLDER.value, _LABEL.value, 'saved_model') |
|
|
| gin.parse_config_files_and_bindings( |
| config_files=[_GIN_CONFIG.value], |
| bindings=None, |
| skip_unknown=True) |
|
|
| config = _get_experiment_config() |
| eval_name = config['name'] |
| output_dir = os.path.join( |
| os.path.dirname(model_path), 'batch_eval', eval_name) |
| logging.info('Creating output_dir @ %s ...', output_dir) |
|
|
| |
| tf.io.gfile.makedirs(output_dir) |
| tf.io.gfile.copy( |
| _GIN_CONFIG.value, os.path.join(output_dir, 'config.gin'), overwrite=True) |
|
|
| _set_visible_devices() |
| logging.info('Evaluating %s on %s ...', eval_name, [ |
| el.name.split('/physical_device:')[-1] |
| for el in tf.config.get_visible_devices() |
| ]) |
| run_evaluation(model_path=model_path, output_dir=output_dir) |
|
|
| logging.info('Done. Evaluations saved @ %s.', output_dir) |
|
|
| if __name__ == '__main__': |
| app.run(main) |
|
|