lm_human_preferences/utils/launch.py (55 lines of code) (raw):

import concurrent.futures import os import subprocess from functools import partial import cloudpickle import fire def launch(name, f, *, namespace='safety', mode='local', mpi=1) -> None: if mode == 'local': with open('/tmp/pickle_fn', 'wb') as file: cloudpickle.dump(f, file) subprocess.check_call(['mpiexec', '-n', str(mpi), 'python', '-c', 'import sys; import pickle; pickle.loads(open("/tmp/pickle_fn", "rb").read())()']) return raise Exception('Other modes unimplemented!') def parallel(jobs, mode): if mode == 'local': assert len(jobs) == 1, "Cannot run jobs in parallel locally" for job in jobs: job() else: with concurrent.futures.ThreadPoolExecutor() as executor: futures = [executor.submit(job) for job in jobs] for f in futures: f.result() def launch_trials(name, fn, trials, hparam_class, extra_hparams=None, dry_run=False, mpi=1, mode='local', save_dir=None): jobs = [] for trial in trials: descriptors = [] kwargs = {} for k, v, s in trial: if k is not None: if k in kwargs: print(f'WARNING: overriding key {k} from {kwargs[k]} to {v}') kwargs[k] = v if s.get('descriptor'): descriptors.append(str(s['descriptor'])) hparams = hparam_class() hparams.override_from_dict(kwargs) if extra_hparams: hparams.override_from_str_dict(extra_hparams) job_name = (name + '/' + '-'.join(descriptors)).rstrip('/') hparams.validate() if dry_run: print(f"{job_name}: {kwargs}") else: if save_dir: hparams.run.save_dir = os.path.join(save_dir, job_name) trial_fn = partial(fn, hparams) jobs.append(partial(launch, job_name, trial_fn, mpi=mpi, mode=mode)) parallel(jobs, mode=mode) def main(commands_dict): """Similar to fire.Fire, but with support for multiple commands without having a class.""" class _Commands: def __init__(self): for name, cmd in commands_dict.items(): setattr(self, name, cmd) fire.Fire(_Commands)