如何在不使用 @hydra.main() 的情况下获取 Hydra 配置
How to get a Hydra config without using @hydra.main()
假设我们有以下设置(从 Hydra docs 复制和缩短):
配置文件:config.yaml
db:
driver: mysql
user: omry
pass: secret
Python 文件:my_app.py
import hydra
@hydra.main(config_path="config.yaml")
def my_app(cfg):
print(cfg.pretty())
if __name__ == "__main__":
my_app()
当我们可以在函数 my_app
上使用装饰器时,这很有效。现在我想(为了小脚本和测试目的,但这并不重要)在任何函数之外获取这个 cfg
对象,只是在一个普通的 python 脚本中。据我了解装饰器的工作原理,应该可以调用
import hydra
cfg = hydra.main(config_path="config.yaml")(lambda x: x)()
print(cfg.pretty())
但是 cfg
只是 None
而不是所需的配置对象。所以看起来装饰器没有传递返回值。还有其他方法可以达到 cfg
吗?
我找到了一个相当丑陋的答案,但它有效 - 如果有人找到更优雅的解决方案,请告诉我们!
我们可以使用闭包或一些可变对象。在这个例子中,我们在外部定义了一个列表并附加了配置对象:
对于 hydra >= 1.0.0
,您必须改用 config_name
,请参阅 documentation。
import hydra
c = []
hydra.main(config_name="config.yaml")(lambda x:c.append(x))()
cfg = c[0]
print(cfg)
旧版本:
import hydra
c = []
hydra.main(config_path="config.yaml")(c.append)()
cfg = c[0]
print(cfg.pretty())
使用 Compose API:
from hydra import compose, initialize
from omegaconf import OmegaConf
initialize(config_path="conf", job_name="test_app")
cfg = compose(config_name="config", overrides=["db=mysql", "db.user=me"])
print(OmegaConf.to_yaml(cfg))
这只会构成配置,不会产生副作用,例如更改工作目录或配置 Python 日志系统。
另一个丑陋的答案,但作者说这可能会在下一个版本中被粉碎
Blockquote
from omegaconf import DictConfig
from hydra.utils import instantiate
from hydra._internal.utils import _strict_mode_strategy, split_config_path, create_automatic_config_search_path
from hydra._internal.hydra import Hydra
from hydra.utils import get_class
class SomeThing:
...
def load_from_yaml(self, config_path, strict=True):
config_dir, config_file = split_config_path(config_path)
strict = _strict_mode_strategy(strict, config_file)
search_path = create_automatic_config_search_path(
config_file, None, config_dir
)
hydra = Hydra.create_main_hydra2(
task_name='sdfs', config_search_path=search_path, strict=strict
)
config = hydra.compose_config(config_file, [])
config.pop('hydra')
self.config = config
print(self.config.pretty())
None 以上解决方案对我有用。他们给出了错误:
'builtin_function_or_method' object has no attribute 'code'
和
GlobalHydra is already initialized, call
Globalhydra.instance().clear() if you want to re-initialize
我深入研究了 hydra 并意识到我可以只使用 OmegaConf 直接加载文件。你不会得到覆盖,但我对此并不担心。
import omegaconf
cfg = omegaconf.OmegaConf.load(path)
这是我的解决方案
from omegaconf import OmegaConf
class MakeObj(object):
""" dictionary to object.
Thanks to
Args:
object ([type]): [description]
"""
def __init__(self, d):
for a, b in d.items():
if isinstance(b, (list, tuple)):
setattr(self, a, [MakeObj(x) if isinstance(x, dict) else x for x in b])
else:
setattr(self, a, MakeObj(b) if isinstance(b, dict) else b)
def read_yaml(path):
x_dict = OmegaConf.load(path)
x_yamlstr = OmegaConf.to_yaml(x_dict)
x_obj = MakeObj(x_dict)
return x_yamlstr, x_dict, x_obj
x_yamlstr, x_dict, x_obj = read_yaml('config/train.yaml')
print(x_yamlstr)
print(x_dict)
print(x_obj)
print(dir(x_obj))
假设我们有以下设置(从 Hydra docs 复制和缩短):
配置文件:config.yaml
db:
driver: mysql
user: omry
pass: secret
Python 文件:my_app.py
import hydra
@hydra.main(config_path="config.yaml")
def my_app(cfg):
print(cfg.pretty())
if __name__ == "__main__":
my_app()
当我们可以在函数 my_app
上使用装饰器时,这很有效。现在我想(为了小脚本和测试目的,但这并不重要)在任何函数之外获取这个 cfg
对象,只是在一个普通的 python 脚本中。据我了解装饰器的工作原理,应该可以调用
import hydra
cfg = hydra.main(config_path="config.yaml")(lambda x: x)()
print(cfg.pretty())
但是 cfg
只是 None
而不是所需的配置对象。所以看起来装饰器没有传递返回值。还有其他方法可以达到 cfg
吗?
我找到了一个相当丑陋的答案,但它有效 - 如果有人找到更优雅的解决方案,请告诉我们!
我们可以使用闭包或一些可变对象。在这个例子中,我们在外部定义了一个列表并附加了配置对象:
对于 hydra >= 1.0.0
,您必须改用 config_name
,请参阅 documentation。
import hydra
c = []
hydra.main(config_name="config.yaml")(lambda x:c.append(x))()
cfg = c[0]
print(cfg)
旧版本:
import hydra
c = []
hydra.main(config_path="config.yaml")(c.append)()
cfg = c[0]
print(cfg.pretty())
使用 Compose API:
from hydra import compose, initialize
from omegaconf import OmegaConf
initialize(config_path="conf", job_name="test_app")
cfg = compose(config_name="config", overrides=["db=mysql", "db.user=me"])
print(OmegaConf.to_yaml(cfg))
这只会构成配置,不会产生副作用,例如更改工作目录或配置 Python 日志系统。
另一个丑陋的答案,但作者说这可能会在下一个版本中被粉碎
Blockquote
from omegaconf import DictConfig
from hydra.utils import instantiate
from hydra._internal.utils import _strict_mode_strategy, split_config_path, create_automatic_config_search_path
from hydra._internal.hydra import Hydra
from hydra.utils import get_class
class SomeThing:
...
def load_from_yaml(self, config_path, strict=True):
config_dir, config_file = split_config_path(config_path)
strict = _strict_mode_strategy(strict, config_file)
search_path = create_automatic_config_search_path(
config_file, None, config_dir
)
hydra = Hydra.create_main_hydra2(
task_name='sdfs', config_search_path=search_path, strict=strict
)
config = hydra.compose_config(config_file, [])
config.pop('hydra')
self.config = config
print(self.config.pretty())
None 以上解决方案对我有用。他们给出了错误:
'builtin_function_or_method' object has no attribute 'code'
和
GlobalHydra is already initialized, call Globalhydra.instance().clear() if you want to re-initialize
我深入研究了 hydra 并意识到我可以只使用 OmegaConf 直接加载文件。你不会得到覆盖,但我对此并不担心。
import omegaconf
cfg = omegaconf.OmegaConf.load(path)
这是我的解决方案
from omegaconf import OmegaConf
class MakeObj(object):
""" dictionary to object.
Thanks to
Args:
object ([type]): [description]
"""
def __init__(self, d):
for a, b in d.items():
if isinstance(b, (list, tuple)):
setattr(self, a, [MakeObj(x) if isinstance(x, dict) else x for x in b])
else:
setattr(self, a, MakeObj(b) if isinstance(b, dict) else b)
def read_yaml(path):
x_dict = OmegaConf.load(path)
x_yamlstr = OmegaConf.to_yaml(x_dict)
x_obj = MakeObj(x_dict)
return x_yamlstr, x_dict, x_obj
x_yamlstr, x_dict, x_obj = read_yaml('config/train.yaml')
print(x_yamlstr)
print(x_dict)
print(x_obj)
print(dir(x_obj))