Last Updated on 2023-02-01 by Clay
Introduction
Hydra是一個開源的 Python 框架,它被設計用來簡化研發佈署的流程(尤其是在複雜的應用上)。Hydra 能夠在佈署時動態地建立階層式的設定檔案、也透過命令列(command line)來繼承(複寫)設定檔。
官方紀錄的主要功能如下:
- 複數來源的階層式設定部屬
- 可以透過命令列指定、複寫設定
- 動態命令列補完
- 可以在本地端或遠端運行應用程式
- 可以用單行指令執行多個任務
現在的 Hydra 是 1.2 穩定版本,支援 Linux、MacOS、Windows。(2022-12-09)
Quick start
Installation
我們可以透過 pip
套件管理工具進行安裝。
pip3 install hydra-core --upgrade
Basic example
以下是一個基本的 hydra 使用範例,我們真正要執行的程式是 app.py
,而 conf 則是我們設定檔所存放的資料夾(後面的範例中,我們會有很多的設定檔)。
資料夾結構
hydra_sample/
├── app.py
└── conf
└── config.yaml
如果要測試 hydra,你可以製作一個一模一樣的架構。
conf/config.yaml
這是一個 YAML 的設定檔,裡面有一些關於網站的設定。
web:
web_name: clay-atlas.com
account: clay
password: secret
app.py
而我們要執行的程式中,主要執行邏輯必須包含在一個函式中,函式的上方需要添加 hydra 的修飾符 @hydra.main()
,裡面則必須傳入必須的參數。
import hydra
from omegaconf import DictConfig, OmegaConf
@hydra.main(version_base=None, config_path="conf", config_name="config")
def my_app(cfg: DictConfig) -> None:
print(OmegaConf.to_yaml(cfg))
if __name__ == "__main__":
my_app()
執行效果
$ python3 app.py
web:
web_name: clay-atlas.com
account: clay
password: secret
如果我們要修改設定檔的參數,我們可以直接在命令列中指令參數的傳入值。例如我在這裡就修改了 account
和 password
。
python3 app.py web.account=test web.password=1234
web:
web_name: clay-atlas.com
account: test
password: 1234
多個不同的設定檔案
(可以看到,架構變得更複雜了!)
hydra_sample/
├── app.py
└── conf
├── config.yaml
└── db
├── web1.yaml
└── web2.yaml
conf/config.yaml
首先,最上層的設定檔只指定了一個參數:它要讀取 db
底下哪個設定檔。
在這裡,我們預設是 web1
。
defaults:
- db: web1
conf/db/web1.yaml
在 web1 中,我們設定了 google 的網站、帳號與密碼。
web_name: www.google.com
account: google
password: 1234
conf/db/web2.yaml
在 web2 中,我們做了跟 web1 相似的事情,只不過改成了我的個人網站、帳號與密碼。
web_name: clay-atlas.com
account: clay
password: secret
RUN
接下來就是執行的部份了。app.py 仍然沒有任何改動,唯一做的事情就是把參數打印出來。
$ python3 app.py
db:
web_name: www.google.com
account: google
password: 1234
可以看到,我們預設的參數就是 google 那一組參數設定!如果我們想要改成另外一組參數設定,我們就直接把 db=web2
寫在執行檔案的命令列中。
$ python3 app.py db=web2
Output:
db:
web_name: clay-atlas.com
account: clay
password: secret
除了設定 db
要吃哪個設定檔外,我們也可以直接指定 db 底下的參數哦。
$ python3 app.py db=web2 db.password=9999
Outputs:
db:
web_name: clay-atlas.com
account: clay
password: 9999
以上是一些 Hydra 的基本用法。包含如何寫設定檔、如何在命令列中改動參數。
我們可以使用 "+" 在命令列執行過程中添加參數
以下的程式,Hydra預設建立一個空的 cfg
物件並傳遞給 @hydra.main()
裝飾的函式。
我們可以在命令列執行程式時,動態地使用 +
來添加參數。
這跟在命令列中指定參數不同,我們添加的參數可以是從未在設定檔中出現的參數。
from omegaconf import DictConfig, OmegaConf
import hydra
@hydra.main(version_base=None)
def my_app(cfg: DictConfig) -> None:
print(OmegaConf.to_yaml(cfg))
if __name__ == "__main__":
my_app()
執行:
python3 app.py +arg1=111 +arg2=222
Outputs:
arg1: 111
arg2: 222
指定一個設定檔(config file)
我們可以透過在 hydra.main()
中傳遞 config_path
和 config_name
來指定要讀取的設定檔路徑。
config_path
: 設定檔所在的位置(通常為設定檔所在的資料夾位置)config_name
: 設定檔的名稱
from omegaconf import DictConfig, OmegaConf
import hydra
@hydra.main(version_base=None, config_path=".", config_name="config")
def my_app(cfg: DictConfig) -> None:
print(OmegaConf.to_yaml(cfg))
if __name__ == "__main__":
my_app()
像以上的範例程式,讀取的設定檔就是在當前目錄底下,名為 config.yaml 的檔案。
當然,我們同樣可以使用 +
來添加參數
python3 app.py +arg3=333
如果參數已經存在於設定檔中,我們可以直接覆寫該參數
python3 app.py arg2=333
如果參數存在於設定檔中則覆寫,如不存在則直接新增。此功能可以使用 ++
來做到
python3 app.py ++arg4=444
我們可以使用屬性(attribute)和字典(dictionary)的方式來存取變數
from omegaconf import DictConfig, OmegaConf
import hydra
@hydra.main(version_base=None, config_path="conf", config_name="config")
def my_app(cfg: DictConfig) -> None:
print(cfg.node.arg1)
print(cfg["node"]["arg1"])
if __name__ == "__main__":
my_app()
我們可以設定預設配置組合
原本直接執行的結果會是以下的參數被打印出。
python3 app.py
Output:
db:
web_name: www.google.com
account: google
password: 1234
當然,如果我們不再需要使用這個參數,也可以透過命令列移除預設配置組合。
python3 app.py ~db
Output:
{}
如果我們的預設配置中,包含著固定的配置組合、以及我們想預設的非配置組合參數
比方說我們知道我們的 db
需要使用幾乎所有的 web1
固定配置組合。
然而,account
我們也知道需要更改成 **BERT**
。
這種時候,我們要為了僅僅一個參數另外新增一個固定的組合配置 web3
嗎?
實際上,我們可以設定 _self_
在 defaults 底下,然後另外配置我們所需要的客製化參數。
config.yaml
defaults:
- db: web1
- _self_
db:
account: BERT
然後執行:
python3 app.py
Output:
db:
web_name: www.google.com
account: BERT
password: 1234
到這裡,常用的 Hydra 功能應該已經介紹完畢了。如果還有待挖掘的好用功能,或許只要在我遇過實際案例後才會明白了。