mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-01 23:08:43 +01:00
exp: add support for --no-hydra flag (#10866)
This commit is contained in:
@@ -20,6 +20,7 @@ class CmdExperimentsRun(CmdRepro):
|
|||||||
tmp_dir=self.args.tmp_dir,
|
tmp_dir=self.args.tmp_dir,
|
||||||
copy_paths=self.args.copy_paths,
|
copy_paths=self.args.copy_paths,
|
||||||
message=self.args.message,
|
message=self.args.message,
|
||||||
|
no_hydra=self.args.no_hydra,
|
||||||
**self._common_kwargs,
|
**self._common_kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -107,4 +108,14 @@ def _add_run_common(parser):
|
|||||||
default=None,
|
default=None,
|
||||||
help="Custom commit message to use when committing the experiment.",
|
help="Custom commit message to use when committing the experiment.",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-hydra",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help=(
|
||||||
|
"Disables automatically updating `params.yaml` with Hydra configuration. "
|
||||||
|
" You can still use `--set-param` to update individual params if needed."
|
||||||
|
" Default is False."
|
||||||
|
),
|
||||||
|
)
|
||||||
parser.add_argument("-M", dest="message", help=argparse.SUPPRESS) # obsolete
|
parser.add_argument("-M", dest="message", help=argparse.SUPPRESS) # obsolete
|
||||||
|
|||||||
@@ -287,6 +287,7 @@ class BaseStashQueue(ABC):
|
|||||||
baseline_rev: Optional[str] = None,
|
baseline_rev: Optional[str] = None,
|
||||||
branch: Optional[str] = None,
|
branch: Optional[str] = None,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
|
no_hydra: bool = False,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> QueueEntry:
|
) -> QueueEntry:
|
||||||
"""Stash changes from the workspace as an experiment.
|
"""Stash changes from the workspace as an experiment.
|
||||||
@@ -302,6 +303,7 @@ class BaseStashQueue(ABC):
|
|||||||
name: Optional experiment name. If specified this will be used as
|
name: Optional experiment name. If specified this will be used as
|
||||||
the human-readable name in the experiment branch ref. Has no
|
the human-readable name in the experiment branch ref. Has no
|
||||||
effect of branch is specified.
|
effect of branch is specified.
|
||||||
|
no_hydra: Disable Hydra from automatically overwriting all params.
|
||||||
|
|
||||||
.. _Hydra Override:
|
.. _Hydra Override:
|
||||||
https://hydra.cc/docs/next/advanced/override_grammar/basic/
|
https://hydra.cc/docs/next/advanced/override_grammar/basic/
|
||||||
@@ -318,7 +320,7 @@ class BaseStashQueue(ABC):
|
|||||||
|
|
||||||
# update experiment params from command line
|
# update experiment params from command line
|
||||||
if params:
|
if params:
|
||||||
self._update_params(params)
|
self._update_params(params, no_hydra=no_hydra)
|
||||||
|
|
||||||
# DVC commit data deps to preserve state across workspace
|
# DVC commit data deps to preserve state across workspace
|
||||||
# & tempdir runs
|
# & tempdir runs
|
||||||
@@ -441,12 +443,13 @@ class BaseStashQueue(ABC):
|
|||||||
f"from '{config_path}': {param_list}"
|
f"from '{config_path}': {param_list}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def _update_params(self, params: dict[str, list[str]]):
|
def _update_params(self, params: dict[str, list[str]], no_hydra: bool = False):
|
||||||
"""Update param files with the provided `Hydra Override`_ patterns.
|
"""Update param files with the provided `Hydra Override`_ patterns.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
params: Dict mapping paths to `Hydra Override`_ patterns,
|
params: Dict mapping paths to `Hydra Override`_ patterns,
|
||||||
provided via `exp run --set-param`.
|
provided via `exp run --set-param`.
|
||||||
|
no_hydra: Disable Hydra from automatically overwriting all params.
|
||||||
|
|
||||||
.. _Hydra Override:
|
.. _Hydra Override:
|
||||||
https://hydra.cc/docs/advanced/override_grammar/basic/
|
https://hydra.cc/docs/advanced/override_grammar/basic/
|
||||||
@@ -456,7 +459,7 @@ class BaseStashQueue(ABC):
|
|||||||
logger.debug("Using experiment params '%s'", params)
|
logger.debug("Using experiment params '%s'", params)
|
||||||
|
|
||||||
hydra_config = self.repo.config.get("hydra", {})
|
hydra_config = self.repo.config.get("hydra", {})
|
||||||
hydra_enabled = hydra_config.get("enabled", False)
|
hydra_enabled = hydra_config.get("enabled", False) and not no_hydra
|
||||||
hydra_output_file = ParamsDependency.DEFAULT_PARAMS_FILE
|
hydra_output_file = ParamsDependency.DEFAULT_PARAMS_FILE
|
||||||
for path, overrides in params.items():
|
for path, overrides in params.items():
|
||||||
if hydra_enabled and path == hydra_output_file:
|
if hydra_enabled and path == hydra_output_file:
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ def run( # noqa: C901, PLR0912
|
|||||||
queue: bool = False,
|
queue: bool = False,
|
||||||
copy_paths: Optional[Iterable[str]] = None,
|
copy_paths: Optional[Iterable[str]] = None,
|
||||||
message: Optional[str] = None,
|
message: Optional[str] = None,
|
||||||
|
no_hydra: bool = False,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> dict[str, str]:
|
) -> dict[str, str]:
|
||||||
"""Reproduce the specified targets as an experiment.
|
"""Reproduce the specified targets as an experiment.
|
||||||
@@ -67,7 +68,7 @@ def run( # noqa: C901, PLR0912
|
|||||||
else:
|
else:
|
||||||
path_overrides = {}
|
path_overrides = {}
|
||||||
|
|
||||||
hydra_enabled = repo.config.get("hydra", {}).get("enabled", False)
|
hydra_enabled = repo.config.get("hydra", {}).get("enabled", False) and not no_hydra
|
||||||
hydra_output_file = ParamsDependency.DEFAULT_PARAMS_FILE
|
hydra_output_file = ParamsDependency.DEFAULT_PARAMS_FILE
|
||||||
if hydra_enabled and hydra_output_file not in path_overrides:
|
if hydra_enabled and hydra_output_file not in path_overrides:
|
||||||
# Force `_update_params` even if `--set-param` was not used
|
# Force `_update_params` even if `--set-param` was not used
|
||||||
@@ -80,6 +81,7 @@ def run( # noqa: C901, PLR0912
|
|||||||
tmp_dir=tmp_dir,
|
tmp_dir=tmp_dir,
|
||||||
copy_paths=copy_paths,
|
copy_paths=copy_paths,
|
||||||
message=message,
|
message=message,
|
||||||
|
no_hydra=no_hydra,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -100,6 +102,7 @@ def run( # noqa: C901, PLR0912
|
|||||||
params=sweep_overrides,
|
params=sweep_overrides,
|
||||||
copy_paths=copy_paths,
|
copy_paths=copy_paths,
|
||||||
message=message,
|
message=message,
|
||||||
|
no_hydra=no_hydra,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
if sweep_overrides:
|
if sweep_overrides:
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ def test_modify_params(params_repo, dvc, changes, expected):
|
|||||||
("conf", "bar"),
|
("conf", "bar"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@pytest.mark.parametrize("no_hydra", [True, False])
|
||||||
def test_hydra_compose_and_dump(
|
def test_hydra_compose_and_dump(
|
||||||
tmp_dir, params_repo, dvc, hydra_enabled, config_dir, config_name
|
tmp_dir, params_repo, dvc, hydra_enabled, config_dir, config_name, no_hydra
|
||||||
):
|
):
|
||||||
hydra_setup(
|
hydra_setup(
|
||||||
tmp_dir,
|
tmp_dir,
|
||||||
@@ -50,14 +51,14 @@ def test_hydra_compose_and_dump(
|
|||||||
if config_name is not None:
|
if config_name is not None:
|
||||||
conf["hydra"]["config_name"] = config_name
|
conf["hydra"]["config_name"] = config_name
|
||||||
|
|
||||||
dvc.experiments.run()
|
dvc.experiments.run(no_hydra=no_hydra)
|
||||||
|
|
||||||
if hydra_enabled:
|
if hydra_enabled and not no_hydra:
|
||||||
assert (tmp_dir / "params.yaml").parse() == {
|
assert (tmp_dir / "params.yaml").parse() == {
|
||||||
"db": {"driver": "mysql", "user": "omry", "pass": "secret"},
|
"db": {"driver": "mysql", "user": "omry", "pass": "secret"},
|
||||||
}
|
}
|
||||||
|
|
||||||
dvc.experiments.run(params=["db=postgresql"])
|
dvc.experiments.run(params=["db=postgresql"], no_hydra=no_hydra)
|
||||||
assert (tmp_dir / "params.yaml").parse() == {
|
assert (tmp_dir / "params.yaml").parse() == {
|
||||||
"db": {
|
"db": {
|
||||||
"driver": "postgresql",
|
"driver": "postgresql",
|
||||||
@@ -117,6 +118,7 @@ def test_hydra_sweep(
|
|||||||
targets=None,
|
targets=None,
|
||||||
copy_paths=None,
|
copy_paths=None,
|
||||||
message=None,
|
message=None,
|
||||||
|
no_hydra=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -137,3 +139,76 @@ def test_hydra_sweep_prefix_name(tmp_dir, params_repo, dvc):
|
|||||||
exp_names = [entry.name for entry in dvc.experiments.celery_queue.iter_queued()]
|
exp_names = [entry.name for entry in dvc.experiments.celery_queue.iter_queued()]
|
||||||
for name, expected in zip(exp_names, expected_names):
|
for name, expected in zip(exp_names, expected_names):
|
||||||
assert name == expected
|
assert name == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_mixing_no_hydra_and_params_flags(tmp_dir, params_repo, dvc):
|
||||||
|
# Passing no_hydra should not prevent user from
|
||||||
|
# using --set-param on unmodified params.yaml
|
||||||
|
hydra_setup(
|
||||||
|
tmp_dir,
|
||||||
|
config_dir="conf",
|
||||||
|
config_name="config",
|
||||||
|
)
|
||||||
|
|
||||||
|
with dvc.config.edit() as conf:
|
||||||
|
conf["hydra"]["enabled"] = True
|
||||||
|
conf["hydra"]["config_dir"] = "conf"
|
||||||
|
conf["hydra"]["config_name"] = "config"
|
||||||
|
|
||||||
|
dvc.experiments.run(no_hydra=True, params=["goo.bag=10.0"])
|
||||||
|
|
||||||
|
assert (tmp_dir / "params.yaml").parse() == {
|
||||||
|
"foo": [{"bar": 1}, {"baz": 2}],
|
||||||
|
"goo": {"bag": 10.0},
|
||||||
|
"lorem": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"hydra_enabled,overrides,expected",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
True,
|
||||||
|
["db=mysql,postgresql"],
|
||||||
|
[
|
||||||
|
{"params.yaml": ["db=mysql"]},
|
||||||
|
{"params.yaml": ["db=postgresql"]},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
False,
|
||||||
|
["foo=bar,baz"],
|
||||||
|
[{"params.yaml": ["foo=bar"]}, {"params.yaml": ["foo=baz"]}],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
False,
|
||||||
|
[],
|
||||||
|
[{}],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize("no_hydra", [True, False])
|
||||||
|
def test_mixing_no_hydra_and_sweeps(
|
||||||
|
tmp_dir, params_repo, dvc, mocker, hydra_enabled, overrides, expected, no_hydra
|
||||||
|
):
|
||||||
|
# Passing no_hydra should not prevent user from
|
||||||
|
# queuing sweeps with --set-param and --queue
|
||||||
|
patched = mocker.patch.object(dvc.experiments, "queue_one")
|
||||||
|
|
||||||
|
if hydra_enabled:
|
||||||
|
hydra_setup(tmp_dir, config_dir="conf", config_name="config")
|
||||||
|
with dvc.config.edit() as conf:
|
||||||
|
conf["hydra"]["enabled"] = True
|
||||||
|
|
||||||
|
dvc.experiments.run(params=overrides, queue=True, no_hydra=no_hydra)
|
||||||
|
|
||||||
|
assert patched.call_count == len(expected)
|
||||||
|
for e in expected:
|
||||||
|
patched.assert_any_call(
|
||||||
|
mocker.ANY,
|
||||||
|
params=e,
|
||||||
|
targets=None,
|
||||||
|
copy_paths=None,
|
||||||
|
message=None,
|
||||||
|
no_hydra=no_hydra,
|
||||||
|
)
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ def test_experiments_run(dvc, scm, mocker):
|
|||||||
"tmp_dir": False,
|
"tmp_dir": False,
|
||||||
"copy_paths": [],
|
"copy_paths": [],
|
||||||
"message": None,
|
"message": None,
|
||||||
|
"no_hydra": False,
|
||||||
}
|
}
|
||||||
default_arguments.update(repro_arguments)
|
default_arguments.update(repro_arguments)
|
||||||
|
|
||||||
@@ -151,6 +152,7 @@ def test_experiments_run_message(dvc, scm, mocker, flag):
|
|||||||
"tmp_dir": False,
|
"tmp_dir": False,
|
||||||
"copy_paths": [],
|
"copy_paths": [],
|
||||||
"message": "mymessage",
|
"message": "mymessage",
|
||||||
|
"no_hydra": False,
|
||||||
}
|
}
|
||||||
default_arguments.update(repro_arguments)
|
default_arguments.update(repro_arguments)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user