【问题标题】:How to override hydra working dir from within a script?如何从脚本中覆盖 hydra 工作目录?
【发布时间】:2021-02-14 09:20:52
【问题描述】:

我知道我可以通过在命令行中设置hydra.run.dir=XXX 来更改配置中的工作目录。 但是如何在不使用 CLI 参数的情况下从脚本中正确执行此操作,甚至将日志保存在我设置的目录中?

此代码不起作用,因为:

  1. 当我尝试更改目录时,hydra 及其记录器已经初始化,并且
  2. 没有这样的属性cfg.hydra

UPD:我在 cmets 中有一个指针。我可以在调用 hydra 之前更改块 if __name__ == 'main': 中的 hydra 参数。但是如何从脚本中获取和修改hydra.run.dir呢?

    @hydra.main(config_path="conf", config_name="config")
    def main(cfg):
        cfg.hydra.run.dir = "./c_out/cached_loss"  # no such attribute
        logger.info('I log something')

我的 hydra 配置如下所示:

defaults:                     
  - hydra/job_logging: custom_logging 
# hydra/custom_logging.yaml
# python logging configuration for tasks                           
version: 1                                                         
formatters:                                                        
  simple:                                                          
    format: '[%(asctime)s][%(name)s][%(levelname)s] - %(message)s' 
handlers:                                                          
  console:                                                         
    class: logging.StreamHandler                                   
    formatter: simple                                              
    stream: ext://sys.stdout                                       
  file:                                                            
    class: logging.FileHandler                                     
    formatter: simple                                              
    # relative to the job log directory                            
    filename: ${hydra.job.name}.log                                
root:                                                              
  level: INFO                                                      
  handlers: [console, file]                                        
                                                                   
disable_existing_loggers: false                                    

【问题讨论】:

  • 我不认识九头蛇。主要的 Python 入口点是在您的代码中还是在 Hydra 库中?如果它在您的代码中,那么您必须能够在 Hydra 初始化之前进行更改。如果不是,那么您是在谈论让 Hydra 根据新位置重新初始化自身,对吗?这似乎是一个长镜头。我很好奇为什么您需要动态地执行此操作。如果你真的这样做,那么使用命令行参数的包装启动脚本怎么样,但对你隐藏它并根据你将在主程序中使用的任何方法设置目录。
  • 谢谢,@史蒂夫。这就说得通了。如果if __name__ == 'main': 阻塞,我的入口点,我假设它在 hydra 之前被调用。我可以尝试在那里更改参数,但是没有明显的方法,因为 hydra 在脚本启动后对用户隐藏其内部配置。

标签: python fb-hydra hydra-python


【解决方案1】:

这可以通过omegaconf interpolation来实现
例如,我创建以 uuid
命名的目录时的用例 首先我们用我们需要的函数而不是 lambda 注册解析器

from omegaconf import OmegaConf

OmegaConf.register_resolver("uuid", lambda : "fdjsfas-3213-kjfdsf")

在 hydra 配置中

hydra:
  run:
    dir: ./outputs/training/${uuid:}

这仍然不是真正从脚本访问,但它允许 python 代码生成配置变量。我真的不认为有一种正常的方法可以在初始化后更改 hydra 配置。

附:我使用结构化配置并且不得不更改代码,因此它可能无法实际工作,但我希望你明白了

【讨论】:

    【解决方案2】:

    @hydra.main 装饰器从sys.argv 读取命令行参数,并在执行装饰函数之前创建输出目录并根据参数设置日志记录。在进入函数之前你没有配置,但是你可以在使用这种 hack 调用函数之前添加hydra.run.dir=XXX 命令行参数:

    @hydra.main(config_path="conf", config_name="config")
    def main(cfg):
        logger.info('I log something')
    
    if __name__ == 'main':
        sys.argv.append('hydra.run.dir=c_out/cached_loss')
        main()
    

    【讨论】:

    • 说得好! (这对于 OP 的问题是完全正确的,但是对于将这个想法应用于--multirun 的任何人,请注意相关参数是不同的:hydra.sweep.dir and hydra.sweep.subdir。)
    【解决方案3】:

    您可以在脚本开始之前通过覆盖该参数来更改它。

    python foo.py hydra.run.dir=something
    

    您也可以在配置中更改它: config.yaml

    hydra:
      run:
        dir: whatever
    

    这也可以使用配置中的环境变量OmegaConf env resolver

    hydra:
      run:
        dir: ${env:HYDRA_OUTPUT_DIR,default_output_dir}
    

    如果您只想在运行时更改工作目录,您可以使用 os.chdir()

    【讨论】:

    • 但问题是如何在不使用命令行参数的情况下做到这一点......
    • 更改工作目录不会改变日志文件路径,该路径由 hydra 在初始化期间配置(它会在我更改工作目录之前创建日志处理程序)。
    • 对此我很抱歉。我已经再次澄清了这个问题。当你编辑你的答案时,我会改变我的投票。
    猜你喜欢
    • 1970-01-01
    • 2023-01-21
    • 2018-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-06
    • 2013-09-05
    • 2013-01-18
    相关资源
    最近更新 更多