"""Default engine activities.
Adapted from Facebook's detectron2.
https://github.com/facebookresearch/detectron2
"""
import argparse
import os
import warnings
import keras.backend as K
import tensorflow as tf
from fvcore.common.file_io import PathManager
from medsegpy import glob_constants
from medsegpy.utils import dl_utils, env
from medsegpy.utils.collect_env import collect_env_info
from medsegpy.utils.io_utils import format_exp_version
from medsegpy.utils.logger import setup_logger
def config_exists(experiment_dir: str):
return (
os.path.isfile(os.path.join(experiment_dir, "config.ini"))
or os.path.isfile(os.path.join(experiment_dir, "config.yaml"))
or os.path.isfile(os.path.join(experiment_dir, "config.yml"))
)
[docs]def default_argument_parser():
"""
Create a parser with some common arguments used by detectron2 users.
Returns:
argparse.ArgumentParser:
"""
parser = argparse.ArgumentParser(description="MedSegPy Training")
parser.add_argument("--config-file", default="", metavar="FILE", help="path to config file")
parser.add_argument("--eval-only", action="store_true", help="perform evaluation only")
parser.add_argument("--num-gpus", type=int, default=1, help="number of gpus")
# parser.add_argument(
# "--overwrite", action="store_true", help="overwrite previous experiment"
# )
parser.add_argument("--debug", action="store_true", help="run in debug mode")
# Add option to execute non-eagerly in tensorflow 2
if env.is_tf2():
parser.add_argument("--non-eagerly", action="store_true", help="run tensorflow non-eagerly")
parser.add_argument(
"opts",
help="Modify config options using the command-line",
default=None,
nargs=argparse.REMAINDER,
)
return parser
[docs]def default_setup(cfg, args):
"""
Perform some basic common setups at the beginning of a job, including:
1. Set up the medsegpy logger
2. Log basic information about environment, cmdline arguments, and config
3. Backup the config to the output directory
4. Version experiments
Args:
cfg (CfgNode): the full config to be used
args (argparse.NameSpace): the command line arguments to be logged
"""
# Make new experiment version if not evaluating
# TODO: Add support to evaluate latest version (if found) when eval_only specified.
cfg.OUTPUT_DIR = PathManager.get_local_path(cfg.OUTPUT_DIR)
make_new_version = not (hasattr(args, "eval_only") and args.eval_only)
if not make_new_version and not config_exists(cfg.OUTPUT_DIR):
raise ValueError(
f"Tried to evaluate on empty experiment directory. " f"{cfg.OUTPUT_DIR} does not exist."
)
if args.eval_only and config_exists(cfg.OUTPUT_DIR):
pass
elif args.debug:
os.environ["MEDSEGPY_RUN_MODE"] = "debug"
cfg.OUTPUT_DIR = (
os.path.join(cfg.OUTPUT_DIR, "debug")
if os.path.basename(cfg.OUTPUT_DIR).lower() != "debug"
else cfg.OUTPUT_DIR
)
else:
cfg.OUTPUT_DIR = format_exp_version(cfg.OUTPUT_DIR, new_version=make_new_version)
# Setup cuda visible devices.
num_gpus = args.num_gpus
if num_gpus > 0:
gpu_ids = dl_utils.get_available_gpus(num_gpus)
gpu_ids_tf_str = ",".join([str(g_id) for g_id in gpu_ids])
os.environ["CUDA_VISIBLE_DEVICES"] = gpu_ids_tf_str
else:
os.environ["CUDA_VISIBLE_DEVICES"] = ""
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
# Set seed.
if cfg.SEED == -1:
cfg.SEED = env.generate_seed()
# Set experiment name.
if not cfg.EXP_NAME:
cfg.EXP_NAME = default_exp_name(cfg)
output_dir = cfg.OUTPUT_DIR
PathManager.mkdirs(output_dir)
setup_logger(output_dir, name="fvcore")
logger = setup_logger(output_dir)
logger.info("Environment info:\n" + collect_env_info())
logger.info("Command line arguments: " + str(args))
if hasattr(args, "config_file") and args.config_file != "":
logger.info(
"Contents of args.config_file={}:\n{}".format(
args.config_file, PathManager.open(args.config_file, "r").read()
)
)
logger.info("Running with full config:\n")
cfg.summary()
cfg.save_config()
if cfg.SEED is not None:
logger.info("Using seed {}".format(cfg.SEED))
glob_constants.SEED = cfg.SEED
# Set image format to be (N, dim1, dim2, dim3, channel).
K.set_image_data_format("channels_last")
# Non-eager execution in tf2
if env.is_tf2() and args.non_eagerly:
if env.tf_version() >= (2, 3):
tf.config.run_functions_eagerly(False)
logger.info("Disabling eager execution...")
else:
logger.warning(
"Eager mode has not been disabled. May have to disable manually in the model"
)
[docs]def default_exp_name(cfg):
"""Extracts default experiment name from the config.
`cfg.EXP_NAME` if exists. If basename starts with "version" or "debug",
take both parent directory name and version name to make experiment name
(e.g. "my_exp/version_001").
Returns:
exp_name (str): The default convention for naming experiments.
"""
exp_name = cfg.get("EXP_NAME")
if not exp_name:
warnings.warn("EXP_NAME not specified. Defaulting to basename...")
basename = os.path.basename(cfg.OUTPUT_DIR)
if basename.startswith("version") or basename.startswith("debug"):
exp_name = f"{os.path.basename(os.path.dirname(cfg.OUTPUT_DIR))}/{basename}"
else:
exp_name = basename
return exp_name