|
import argparse |
|
import re |
|
from os import path as osp |
|
|
|
|
|
def parse_args(): |
|
parser = argparse.ArgumentParser( |
|
description='Generate benchmark training/testing scripts') |
|
parser.add_argument( |
|
'--input_file', |
|
required=False, |
|
type=str, |
|
help='Input file containing the paths ' |
|
'of configs to be trained/tested.') |
|
parser.add_argument( |
|
'--output_file', |
|
required=True, |
|
type=str, |
|
help='Output file containing the ' |
|
'commands to train/test selected models.') |
|
parser.add_argument( |
|
'--gpus_per_node', |
|
type=int, |
|
default=8, |
|
help='GPUs per node config for slurm, ' |
|
'should be set according to your slurm environment') |
|
parser.add_argument( |
|
'--cpus_per_task', |
|
type=int, |
|
default=5, |
|
help='CPUs per task config for slurm, ' |
|
'should be set according to your slurm environment') |
|
parser.add_argument( |
|
'--gpus', |
|
type=int, |
|
default=8, |
|
help='Totally used num of GPUs config for slurm (in testing), ' |
|
'should be set according to your slurm environment') |
|
parser.add_argument( |
|
'--mode', type=str, default='train', help='Train or test') |
|
parser.add_argument( |
|
'--long_work_dir', |
|
action='store_true', |
|
help='Whether use full relative path of config as work dir') |
|
parser.add_argument( |
|
'--max_keep_ckpts', |
|
type=int, |
|
default=1, |
|
help='The max number of checkpoints saved in training') |
|
parser.add_argument( |
|
'--full_log', |
|
action='store_true', |
|
help='Whether save full log in a file') |
|
|
|
args = parser.parse_args() |
|
return args |
|
|
|
|
|
args = parse_args() |
|
assert args.mode in ['train', 'test'], 'Currently we only support ' \ |
|
'automatically generating training or testing scripts.' |
|
|
|
config_paths = [] |
|
|
|
if args.input_file is not None: |
|
with open(args.input_file, 'r') as fi: |
|
config_paths = fi.read().strip().split('\n') |
|
else: |
|
while True: |
|
print('Please type a config path and ' |
|
'press enter (press enter directly to exit):') |
|
config_path = input() |
|
if config_path != '': |
|
config_paths.append(config_path) |
|
else: |
|
break |
|
|
|
script = '''PARTITION=$1 |
|
CHECKPOINT_DIR=$2 |
|
|
|
''' |
|
|
|
if args.mode == 'train': |
|
for i, config_path in enumerate(config_paths): |
|
root_dir = osp.dirname(osp.dirname(osp.abspath(__file__))) |
|
if not osp.exists(osp.join(root_dir, config_path)): |
|
print(f'Invalid config path (does not exist):\n{config_path}') |
|
continue |
|
|
|
config_name = config_path.split('/')[-1][:-3] |
|
match_obj = re.match(r'^.*_[0-9]+x([0-9]+)_.*$', config_name) |
|
if match_obj is None: |
|
print(f'Invalid config path (no GPU num in ' |
|
f'config name):\n{config_path}') |
|
continue |
|
|
|
gpu_num = int(match_obj.group(1)) |
|
work_dir_name = config_path if args.long_work_dir else config_name |
|
|
|
script += f"echo '{config_path}' &\n" |
|
if args.full_log: |
|
script += f'mkdir -p $CHECKPOINT_DIR/{work_dir_name}\n' |
|
|
|
|
|
script += f'GPUS={gpu_num} GPUS_PER_NODE={args.gpus_per_node} ' \ |
|
f'CPUS_PER_TASK={args.cpus_per_task} ' \ |
|
f'./tools/slurm_train.sh $PARTITION {config_name} ' \ |
|
f'{config_path} \\\n' |
|
script += f'$CHECKPOINT_DIR/{work_dir_name} --cfg-options ' \ |
|
f'checkpoint_config.max_keep_ckpts=' \ |
|
f'{args.max_keep_ckpts} \\\n' \ |
|
|
|
|
|
|
|
if args.full_log: |
|
script += f'2>&1|tee $CHECKPOINT_DIR/{work_dir_name}' \ |
|
f'/FULL_LOG.txt &\n' |
|
else: |
|
script += '>/dev/null &\n' |
|
|
|
if i != len(config_paths) - 1: |
|
script += '\n' |
|
|
|
print(f'Successfully generated script for {config_name}') |
|
|
|
with open(args.output_file, 'w') as fo: |
|
fo.write(script) |
|
|
|
elif args.mode == 'test': |
|
for i, config_path in enumerate(config_paths): |
|
root_dir = osp.dirname(osp.dirname(osp.abspath(__file__))) |
|
if not osp.exists(osp.join(root_dir, config_path)): |
|
print(f'Invalid config path (does not exist):\n{config_path}') |
|
continue |
|
|
|
config_name = config_path.split('/')[-1][:-3] |
|
|
|
tasks = { |
|
'scannet_seg', 'scannet', 's3dis_seg', 'sunrgbd', 'kitti', 'nus', |
|
'lyft', 'waymo' |
|
} |
|
eval_option = None |
|
for task in tasks: |
|
if task in config_name: |
|
eval_option = task |
|
break |
|
if eval_option is None: |
|
print(f'Invalid config path (invalid task):\n{config_path}') |
|
continue |
|
|
|
work_dir_name = config_path if args.long_work_dir else config_name |
|
|
|
script += f"echo '{config_path}' &\n" |
|
if args.full_log: |
|
script += f'mkdir -p $CHECKPOINT_DIR/{work_dir_name}\n' |
|
|
|
|
|
script += f'GPUS={args.gpus} GPUS_PER_NODE={args.gpus_per_node} ' \ |
|
f'CPUS_PER_TASK={args.cpus_per_task} ' \ |
|
f'./tools/slurm_test.sh $PARTITION {config_name} ' \ |
|
f'{config_path} \\\n' |
|
script += f'$CHECKPOINT_DIR/{work_dir_name}/latest.pth ' \ |
|
|
|
if eval_option in ['scannet_seg', 's3dis_seg']: |
|
script += '--eval mIoU \\\n' |
|
elif eval_option in ['scannet', 'sunrgbd', 'kitti', 'nus']: |
|
script += '--eval map \\\n' |
|
elif eval_option in ['lyft']: |
|
script += f'--format-only --eval-options jsonfile_prefix=' \ |
|
f'$CHECKPOINT_DIR/{work_dir_name}/results_challenge ' \ |
|
f'csv_savepath=$CHECKPOINT_DIR/{work_dir_name}/' \ |
|
f'results_challenge.csv \\\n' |
|
elif eval_option in ['waymo']: |
|
script += f'--eval waymo --eval-options pklfile_prefix=' \ |
|
f'$CHECKPOINT_DIR/{work_dir_name}/kitti_results ' \ |
|
f'submission_prefix=$CHECKPOINT_DIR/{work_dir_name}/' \ |
|
f'kitti_results \\\n' |
|
|
|
|
|
|
|
if args.full_log: |
|
script += f'2>&1|tee $CHECKPOINT_DIR/{work_dir_name}' \ |
|
f'/FULL_LOG.txt &\n' |
|
else: |
|
script += '>/dev/null &\n' |
|
|
|
if i != len(config_paths) - 1: |
|
script += '\n' |
|
|
|
print(f'Successfully generated script for {config_name}') |
|
|
|
with open(args.output_file, 'w') as fo: |
|
fo.write(script) |
|
|