Skip to content

Commit 05115ba

Browse files
Feature/eval (#145)
* (wip) start on result database * fix context manager behavior * (wip) start sketching executable infrastructure * switch to roslaunch for exec * log error code and set ros output * add ability to skip scenes that are already present * add ability to drop results * fix typo * add quick draft of export command * preserve directory structure when exporting * drop spark config * fix formatting
1 parent e9c2c41 commit 05115ba

5 files changed

Lines changed: 386 additions & 36 deletions

File tree

eval/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ dependencies = [
99
"click",
1010
"matplotlib",
1111
"pandas",
12+
"pyyaml",
1213
"rich",
1314
"seaborn",
1415
"tqdm",

eval/python/hydra_eval/__main__.py

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,9 @@
44

55
import click
66

7+
import hydra_eval.commands.collect as collect
78
import hydra_eval.commands.timing as timing
8-
9-
10-
class ClickHandler(logging.Handler):
11-
"""Logging handler to color output using click."""
12-
13-
def emit(self, record):
14-
"""Send log record to console with appropriate coloring."""
15-
msg = self.format(record)
16-
17-
if record.levelno <= logging.DEBUG:
18-
click.secho(msg, fg="green")
19-
return
20-
21-
if record.levelno <= logging.INFO:
22-
click.echo(msg)
23-
return
24-
25-
if record.levelno <= logging.WARNING:
26-
click.secho(msg, fg="yellow", err=True)
27-
return
28-
29-
click.secho(msg, fg="red", err=True)
30-
31-
32-
def setup_log_file(result_dir):
33-
"""Set logging to also use log file."""
34-
handler = logging.FileHandler(result_dir / "odsg_eval.log", mode="w")
35-
handler.setLevel(logging.DEBUG)
36-
formatter = logging.Formatter(
37-
"[%(levelname)s] %(asctime)s @ %(filename)s:%(lineno)s: %(message)s"
38-
)
39-
handler.setFormatter(formatter)
40-
logger = logging.getLogger()
41-
logger.addHandler(handler)
9+
from hydra_eval.utils import ClickHandler
4210

4311

4412
@click.group()
@@ -47,7 +15,6 @@ def cli():
4715
logger = logging.getLogger()
4816
logger.setLevel(logging.DEBUG)
4917

50-
# TODO(nathan) pass config from commands
5118
handler = ClickHandler()
5219
handler.setLevel(logging.INFO)
5320
formatter = logging.Formatter("%(message)s")
@@ -58,7 +25,7 @@ def cli():
5825

5926

6027
cli.add_command(timing.cli)
61-
28+
cli.add_command(collect.cli)
6229

6330
if __name__ == "__main__":
6431
cli()
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""Command to run hydra and collect results."""
2+
3+
import pathlib
4+
import pprint
5+
import shutil
6+
7+
import click
8+
9+
from hydra_eval.result_collection import ExperimentManager, ResultManager
10+
11+
12+
@click.group(name="collect")
13+
def cli():
14+
"""Run and manage experimental results."""
15+
pass
16+
17+
18+
@cli.command(name="run")
19+
@click.argument("output_path", type=click.Path())
20+
@click.argument("experiments", type=click.Path(exists=True), nargs=-1)
21+
@click.option("--skip-existing", "-s", is_flag=True)
22+
def run(output_path, experiments, skip_existing):
23+
"""Collect a new set of Hydra results."""
24+
with ResultManager(output_path) as manager:
25+
for experiment_path in experiments:
26+
experiment = ExperimentManager.from_file(manager, experiment_path)
27+
if manager is None:
28+
continue
29+
30+
experiment.run(skip_existing)
31+
32+
33+
@cli.command(name="list")
34+
@click.argument("result_path", type=click.Path(exists=True))
35+
def list(result_path):
36+
"""List all results in the result collection."""
37+
with ResultManager(result_path) as manager:
38+
for result in manager.results:
39+
pprint.pprint(result)
40+
41+
42+
@cli.command(name="find")
43+
@click.argument("result_path", type=click.Path(exists=True))
44+
@click.argument("experiment_name", type=str)
45+
@click.argument("trial_name", type=str)
46+
def find(result_path, experiment_name, trial_name):
47+
"""Find all matching results for a given trial."""
48+
with ResultManager(result_path) as manager:
49+
header = f"Results for {trial_name}:{experiment_name}:"
50+
print(header)
51+
print("-" * len(header))
52+
results = manager.find_trials(experiment_name, trial_name)
53+
for result in results:
54+
pprint.pprint(result)
55+
56+
57+
@cli.command(name="drop")
58+
@click.argument("result_path", type=click.Path(exists=True))
59+
@click.argument("condition", type=str)
60+
def drop(result_path, condition):
61+
"""Drop all results matching condition from collection."""
62+
with ResultManager(result_path) as manager:
63+
print("Would drop:")
64+
print("-----------")
65+
for result in manager.find(condition):
66+
pprint.pprint(result)
67+
68+
click.confirm("Drop results?", abort=True)
69+
manager.drop(condition)
70+
71+
72+
@cli.command(name="export")
73+
@click.argument("result_path", type=click.Path(exists=True))
74+
@click.argument("output_path", type=click.Path())
75+
@click.argument("condition", type=str)
76+
def export(result_path, output_path, condition):
77+
"""Save results matching condition to a directory."""
78+
output_path = pathlib.Path(output_path).expanduser().absolute()
79+
if output_path.exists():
80+
click.confirm(f"Remove existing '{output_path}'?", abort=True)
81+
shutil.rmtree(output_path)
82+
83+
output_path.mkdir(parents=True)
84+
with ResultManager(result_path) as manager:
85+
for result in manager.find(condition):
86+
hydra_path = result.path / "hydra"
87+
required = [
88+
"hydra_config.yaml",
89+
"frontend/dsg_with_mesh.json",
90+
"backend/deformation_graph.dgrf",
91+
]
92+
required = [hydra_path / x for x in required]
93+
missing = [str(x) for x in required if not x.exists()]
94+
if len(missing) > 0:
95+
result_name = f"{result.name}:{result.trial_name}"
96+
missing_str = pprint.pformat(missing)
97+
click.secho(
98+
f"Missing files for {result_name}:\n{missing_str}",
99+
fg="yellow",
100+
)
101+
continue
102+
103+
exp_path = output_path / result.name / result.trial_name
104+
exp_path.mkdir(parents=True)
105+
dest_paths = [exp_path / x.relative_to(hydra_path) for x in required]
106+
for src, dest in zip(required, dest_paths):
107+
dest.parent.mkdir(exist_ok=True, parents=True)
108+
shutil.copy2(src, dest)

0 commit comments

Comments
 (0)