hydra-zen について
hydra-zen Fluency は、hydra-zen と Hydra で設定システムを構築する開発者向けのスキルです。Python の呼び出し可能オブジェクトから型付き dataclass 設定を生成する方法と、ビルダー、継承、defaults リストのよくある問題を解説します。
主な機能
- 01呼び出し可能オブジェクトから dataclass 設定を生成
- 02シグネチャに基づく設定引数の検証
- 03ビルダーと設定パターンの解説
- 04defaults リストとグループ移動の説明
- 05補間と継承の問題点を特定
活用シーン
- 01手書き YAML のターゲット設定を置き換え
- 02設定引数のスペルミスを早期検出
- 03コマンドラインで上書き可能な設定を構築
- 04defaults リストの接続問題を診断
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ d-laub/ dlaub-togo --skill hydra-zenインストール後、Claude Code で/hydra-zenを入力して読み込まれたか確認します。
詳細
hydra-zen の使いこなし
概要
hydra-zen は素の Hydra ではありません。 Hydra/OmegaConf の上に構築された薄いレイヤーで、実際の Python 呼び出し可能オブジェクトから構造化設定を生成することで、手書きの YAML と _target_ 文字列をなくす役割を果たします。その代わりに得られるものは、次の 2 つです。
- 型安全性:設定は呼び出し可能オブジェクトのシグネチャから派生したデータクラスです。フィールドの不足やスペルミスは実行時ではなく、設定のビルド時に失敗します(
builds(Foo, momtum=0.9)は、Fooにmomtumキーワード引数がなければ直ちにTypeErrorを送出します)。 - 定型コードの削減(DRY):
conf/の YAML ツリーも、_target_: pkg.mod.Class文字列も不要です。クラスや関数自体をbuilds(...)に渡せば、hydra-zen がそのシグネチャを反映します。ターゲットをリファクタリングすれば、設定も自動的に追従します。
hydra-zen が呼び出し可能オブジェクトやビルダーを受け付ける場面で、Hydra 形式の文字列を書いているなら、それは hydra-zen を使うのではなく、回避していることになります。
使用する場面
次のいずれかが見られる場合に、このスキルを使用してください。
hydra_zenからのインポート(builds、make_custom_builds_fn、store、just、MISSING、hydrated_dataclass、kwargs_of、make_config、instantiate、to_yaml、zen、ZenStore、BuildsFn)。defaults:の YAML ブロックではなく、store(...)の呼び出しに渡されるhydra_defaults=[...]リスト。- hydra-zen を使用するプロジェクト内の
_target_文字列、${interpolations}、またはMISSINGセンチネル。 - 設定の継承に使う
builds_bases=(Parent,)、またはmake_configのbases=(Cfg,)。 - Hydra YAML を Python のキーワード引数に変換したような、LLM が記述した設定。
- 「部分関数の部分関数」パターン、つまり
functools.partial(builds_fn, target, ...)。通常、これは誰かがpopulate_full_signatureに手こずっていた兆候です。
次の用途では、このスキルを使用しないでください。
hydra_zenをインポートしない、純粋な Hydra/OmegaConf プロジェクト。これらには異なるルールがあり、YAML が信頼できる情報源です。- 実行時やトレーニングのロジック。このスキルの対象は設定の構築であり、インスタンス化されたオブジェクトを使用するコードではありません。
仕組み(型付けの観点)
Hydra: YAML files → OmegaConf DictConfig → hydra.utils.instantiate
hydra-zen: Python → dataclass (via builds) → hydra_zen.instantiate
↑
this is the part you write
builds(Foo, **kwargs) は、インポート時におおよそ次の処理を行います。
inspect.signature(Foo)を呼び出して、パラメーター、デフォルト値、アノテーションを読み取ります。- 渡された各キーワード引数をシグネチャと照合して検証します。タイプミスは実行時ではなく、その場で
TypeErrorになります。 - 各アノテーションを Hydra/OmegaConf が受け入れられる形式に調整します(下記の「型の調整」を参照)。
- (調整済み)シグネチャを反映するフィールドを備えた
@dataclassを生成し、_target_ = "pkg.mod.Foo"を組み込みます。 - そのデータクラスの型を返します。
instantiate(Cls(**overrides))はFoo(**overrides)を構築します。
静的型付けについて:builds のオーバーロードは型付けされているため、返されるデータクラスは BuildsWithSig[type[Foo], P] を示します。ここで P は Foo の ParamSpec です。そのため、Pyright/mypy は、設定クラスに渡すキーワード引数を Foo のシグネチャと照合して検査できます。@hydrated_dataclass では、デコレーターが dataclass_transform を使用するため、生成されたクラスは静的チェッカーに対して @dataclass のように振る舞います。属性アクセス、イミュータブル性、フィールドの型がすべて認識されます。
型の絞り込み — 気づきにくい型の拡大
Hydra が受け入れるのは、注釈のうち限られたサブセットのみです。Any、プリミティブ型、Enum、ネストされた構造化設定、これらの List/Dict、Optional、およびネストされたコンテナ(OmegaConf ≥ 2.2)が対象です。それ以外(Literal、プリミティブ型以外の Union[X, Y]、カスタムプロトコル、TypedDict、Annotated など)は、通常の Hydra ではインスタンス化時にエラーになります。
hydra-zen は、サポートされていない注釈を自動的に拡大します。
Literal[1, 2]→AnyList[Literal[1, 2]]→List[Any](コンテナは維持し、内部の型を削除)tuple[int, ...]→ OmegaConf がサポートしていればそのまま維持し、サポートしていなければTuple[Any, ...]。
その結果:
- 設定はインスタンス化できますが、OmegaConf は実行時に
Literalのメンバーシップを強制しません。これが必要な場合は、zen_wrappers=経由でpydantic/beartypeを適用するか、ターゲットを@pydantic.dataclasses.dataclassでデコレートしてください。 - 静的チェッカーには、hydra-zen がメタデータに元の型を付与するため、元の型が認識されます。IDE のサポートは失われず、絞り込まれたフィールドに対する Hydra 側の実行時検証のみが失われます。
ビルダー
| ビルダー | 戻り値 | 用途 |
|---|---|---|
builds(Foo, **kwargs) | データクラス型。instantiate は Foo(**kwargs) を返す | 具体的な設定 |
builds(Foo, zen_partial=True, ...) | データクラス。instantiate は functools.partial(Foo, **kwargs) を返す | オプティマイザー、スケジューラー、ロガーなど、フレームワークが後でインスタンス化するもの |
builds(Foo, populate_full_signature=True) | __init__ のすべてのパラメーターを反映したデータクラス | ユーザーが CLI で任意のフィールドをオーバーライドできるようにする場合 |
make_custom_builds_fn(**defaults) | デフォルトがあらかじめ適用された builds | プロジェクト全体の規約(例:常に populate_full_signature=True を設定) |
hydrated_dataclass(target=...) | デコレーター。フィールドはクラス本体で定義 | 静的型付きの設定(pyright はフィールドの型と frozen=True を認識) |
kwargs_of(fn, **overrides) | fn のシグネチャに一致する dict にインスタンス化されるデータクラス | 「これらのキーだけを持つ dict がほしい」場合。ターゲットではないものに **kwargs を渡すのに便利 |
make_config(*fields, bases=(...)) | 名前付きフィールドを持つ、ターゲットなしのデータクラス | トップレベルの「タスク」設定や実験用のオーバーレイ。詳しくは以下を参照 |
just(value) | value そのものに解決されるデータクラス | 構築済み設定のリスト、クラスオブジェクト、または functools.partial(...) インスタンスを埋め込む |
MISSING | OmegaConf のセンチネル | 必須フィールド。デフォルト値リストまたは CLI で値を指定する必要がある |
このリポジトリで定義されている pbuilds は、make_custom_builds_fn(populate_full_signature=True, zen_partial=True) にすぎません。「シグネチャ全体を指定した partial ビルド」と読み替えてください。
シグネチャの自動反映に関する落とし穴
populate_full_signature=True は、ターゲットの __init__ のデフォルト値からすべてのフィールドを再導出します。builds_bases=(Parent,) と組み合わせると、親クラスにのみ設定されたフィールドは、ターゲット自身の __init__ のデフォルト値で暗黙に上書きされます。
# Parent sets val_splits=["train-val"]
MMDataCfg = pbuilds(CisGeneRegData, val_splits=["train-val"], ..., builds_bases=(DataCfg,))
# WRONG: populate_full_signature on the child re-derives val_splits from
# CisGeneRegData.__init__, blanking what MMDataCfg set.
MMTuneDataCfg = pbuilds(CisGeneRegData, limit_regions=TUNING_CHROM,
builds_bases=(MMDataCfg,))
# RIGHT: restate inherited fields explicitly when you need full-signature population.
MMTuneDataCfg = pbuilds(CisGeneRegData, limit_regions=TUNING_CHROM,
val_splits=["train-val"], test_splits=["train-test"],
builds_bases=(MMDataCfg,))
# ALSO RIGHT (idiomatic — see "Hacking" section): drop full-signature on the child.
size_builds = make_custom_builds_fn(zen_partial=True) # no populate_full_signature
MMTuneDataCfg = size_builds(CisGeneRegData, limit_regions=TUNING_CHROM,
builds_bases=(MMDataCfg,))
経験則:populate_full_signature=True と builds_bases は、期待するようには組み合わせて使えません。フィールドを再指定するか、子バリアントにはシグネチャ全体を自動反映しないビルダーを使ってください。
補間とビルダーとデフォルトリストによる再配置の違い
"${name}" は、インスタンス化時に合成済みの設定ツリーを基準に解決される OmegaConf の補間です。これは、別の型が注釈されたフィールドに格納される str であるため、hydra-zen の型の絞り込みでは見抜けない型システムの抜け穴になります。正当な用途は 2 つあります。それ以外の場合には、より適した方法があります。
正当な用途 1:遅延値/導出値
これらには型安全な代替手段がありません。補間が適切な方法です。
run_dir = "${data.dir}/${run.name}" # compose from other tree paths
git_sha = "${oc.env:GIT_SHA}" # resolve env at runtime
timestamp = "${now:%Y-%m-%d}" # built-in resolvers
正当な使用例 2:グループ選択をネストされたフィールドに接続する(ただし、group@pkg を優先)
これは "${...}" を使って次のように記述します。
# Works, but not the most idiomatic — loss_fn is annotated nn.Module and
# gets a "${loss}" str at config-build time. Wiring is scattered across nested
# builders instead of collocated.
ModelCfg = pbuilds(CisGeneReg, loss_fn="${loss}", scheduler="${scheduler}", flags="${flags}", ...)
store(name="train", loss=MISSING, scheduler=MISSING, flags=MISSING, model=ModelCfg, ...,
hydra_defaults=["_self_",
{"loss": "pairwise_mse"},
{"scheduler": "cosine"},
{"flags": "multi_baseline"}])(train)
defaults リストでパッケージを移動する [email protected] を優先してください。 選択したグループ設定が補間文字列なしで型付きフィールドの宛先に直接配置され、接続設定も一か所にまとまります。
# Idiomatic — no "${...}" in any nested builder; ModelCfg has no top-level
# `loss` / `scheduler` / `flags` mirror fields at all.
ModelCfg = pbuilds(CisGeneReg, optimizer=OptimCfg, ...) # no loss_fn= line
store(name="train", model=ModelCfg, ...,
hydra_defaults=["_self_",
{"[email protected]_fn": "pairwise_mse"},
{"[email protected]": "cosine"},
{"[email protected]": "multi_baseline"}])(train)
# CLI: python train.py [email protected]_fn=gar
トレードオフ:
- 補間形式では、
${loss}の解決先となるように、トップレベルにミラーフィールド(loss=MISSINGなど)が必要です。移動形式では不要で、トップレベルにlossフィールドはありません。 - 補間形式では、1つのグループ選択を複数の宛先に配布できます(複数の場所で
${loss}を使用)。移動形式では、宛先ごとに defaults リストのエントリーが必要です。複数箇所への配布には補間を、すっきりとした接続には移動を選んでください。 - CLI のオーバーライド構文が異なります。補間形式は
loss=pairwise_mse、移動形式は[email protected]_fn=pairwise_mseです。後者は冗長ですが、より明示的です。
ヒューリスティック:Hydra グループに紐付いた対応するトップレベルフィールドがない場合、"${...}" は誤りです。 補間は汎用変数ではなく、合成された設定内のパスを参照します。対応するフィールドがある場合でも、group@pkg のほうがすっきりするか検討してください。
MISSING と defaults リスト — 明示的な選択パターン
MISSING が必要なのは、設定内にフィールドがあり、データクラスのデフォルト値以外のもので埋める必要がある場合だけです。補間形式のグループ接続では、MISSING と defaults エントリーの両方が必要です。一方、group@pkg による移動では、defaults リスト自体が宛先フィールドを配置するため、通常はどちらも必要ありません。
# Interpolation form: requires the MISSING field + defaults entry pair.
store(name="train",
loss=MISSING, # required field
scheduler=MISSING, # required field
hydra_defaults=["_self_",
{"loss": "pairwise_mse"},
{"scheduler": "cosine"}])(train)
# Relocation form: no top-level loss/scheduler fields at all; the defaults
# list installs the chosen configs directly at model.loss_fn / model.scheduler.
store(name="train",
hydra_defaults=["_self_",
{"[email protected]_fn": "pairwise_mse"},
{"[email protected]": "cosine"}])(train)
補間形式で MISSING が重要な理由は、このフィールドを「必ず設定する必要がある」と示すためです。defaults リストのエントリーを省略すると、実行のたびに CLI で loss=... を渡さなければなりません。MISSING を省略すると、タイプミスがあってもフィールドはデータクラスのデフォルト値のままになり、気づけません。
ZenStore — グループ、パッケージ、「Python の None は使えない」というルール
store(group="scheduler")(SomeCfg, name="cosine") は SomeCfg をグループ scheduler に登録します。CLI では scheduler=cosine と指定します。
ドキュメントにある便利なパターン:
# Pre-curry a group for repeated entries
db_store = store(group="db")
db_store(Database(name="mysql"))
db_store(Database(name="sqlite"))
# Auto-name from a config attribute (lambda receives the cfg)
auto_name = store(name=lambda cfg: cfg.name)
auto_name(group="server")(Server(name="apache", port=80))
# Push everything into Hydra's global store at app startup
if __name__ == "__main__":
store.add_to_hydra_store()
zen(task).hydra_main(config_path=None, config_name="train", version_base="1.2")
生の None をグループオプションとして登録することはできません。
# WRONG — hydra-zen rejects None as a config:
scheduler_store(None, name="none")
# Also wrong on CLI: `scheduler=null`. Hydra parses YAML null as Python None
# *before* the group lookup, raising ValueError.
# RIGHT: wrap None in a builds() of a sentinel function.
def _null_scheduler(*a, **kw): return None
scheduler_store(builds(_null_scheduler), name="none") # CLI: scheduler=none
make_config と _global_ パッケージを使った実験用オーバーレイ
「実験 X = ベース設定 + いくつかのオーバーライド」を表す標準的な方法:
from hydra_zen import make_config
experiment_store = store(group="experiment", package="_global_")
experiment_store(
make_config(
hydra_defaults=["_self_", {"override /db": "sqlite"}],
server=dict(port=8080),
bases=(Config,), # inherit from the top-level config
),
name="aplite",
)
# CLI: python app.py +experiment=aplite
package="_global_" は、実験設定をトップレベル設定の下にネストするのではなく、置き換えることを意味します。bases=(Config,) は「すべてのフィールドを継承してから、これらをオーバーライドする」という意味です。Hydra の YAML 検索パスを使っていないため、"override /db"(絶対パス)が必要です。
just() — Python オブジェクトをそのまま埋め込む
just(x) は、instantiate(...) が変更せずに x を返す設定を生成します。直接ターゲットとして呼び出せないものの、別の builds(...) の中に置く必要があるものに使います。
# A list of already-built callback configs, embedded into the Trainer config.
TrainerCfg = pbuilds(L.Trainer,
callbacks=just([builds(RichProgressBar)]),
...)
# Embedding a functools.partial as an alternative to zen_partial=True:
LogConf = just(functools.partial(logger, format_spec='{0:>8s}'))
just を使わないと、hydra-zen はその値をターゲットとして解釈しようとして失敗します。
hydrated_dataclass — 静的型付けが必要な場合
builds(...) はクラスを返しますが、オーバーロードの工夫なしでは pyright/mypy からフィールド名を認識できません。@hydrated_dataclass では逆の方法を取ります。データクラスの本体を記述すると、デコレーターが _target_、_partial_、バリデーション、型の絞り込みを組み込みます。
from hydra_zen import hydrated_dataclass
from torch.optim import Adam
@hydrated_dataclass(target=Adam, zen_partial=True, frozen=True)
class BuildsAdam:
lr: float = 0.01
momentum: float = 0.9
# pyright now flags both of these:
BuildsAdam(lr="a string") # bad type
conf = BuildsAdam(); conf.lr = 10.0 # frozen
フィールド名の誤記があると、builds() と同様にデコレーション時に TypeError が発生します。IDE の属性補完や frozen=True の静的チェックを重視する場合に使用してください。
kwargs_of —「このシグネチャに一致する辞書をください」
ターゲットそのものではなく、キーとデフォルト値が関数のものと一致する dict をインスタンス化する設定が必要な場合:
from hydra_zen import kwargs_of
DataLoaderKwargs = kwargs_of(DataLoader, zen_exclude=("dataset",), batch_size=32)
# instantiate(DataLoaderKwargs(num_workers=4))
# → {"batch_size": 32, "num_workers": 4, ...}
自分が所有していないコンストラクターに **kwargs の一式を渡す場合や、dataclasses.replace のようなオーバーレイに渡す設定に便利です。
BuildsFn サブクラス — プロジェクト全体で使うビルダーのデフォルト設定
make_custom_builds_fn より強い規約(たとえば、常に beartype ラッパーを付与する、常に hydra_convert="object" を設定する、未知の kwargs を常に拒否する)が必要な場合は、BuildsFn をサブクラス化します。
from hydra_zen import BuildsFn
class MyBuilds(BuildsFn):
_default_dataclass_options_for_builds = {"frozen": True}
# ... override class methods to inject zen_wrappers, etc.
builds = MyBuilds.builds
pbuilds = MyBuilds.builds # with zen_partial=True via your own wrapper
本当にプロジェクト全体に適用する方針に限って使用してください。ほとんどのプロジェクトでは、make_custom_builds_fn で十分です。
例外的なケースのハック
「partial の partial」パターン(通常は不適切な理由)
次のようなコードは避けるべきです。
# This repo's cfg.py:
PartialModelCfg = partial(
pbuilds,
CisGeneReg,
loss_fn="${loss}", optimizer=OptimCfg, scheduler="${scheduler}",
grad_clip_val=1.0, flags="${flags}", device="cuda", compile_arch=True,
builds_bases=(ModelCfg,),
)
model_store(PartialModelCfg(d_model=32, nhead=2, n_layers=2), name="tiny")
model_store(PartialModelCfg(d_model=64, nhead=4, n_layers=4), name="small")
実際に起きていること:作成者は、サイズごとの小さなバリアントを4つ用意しようとしています。functools.partial で pbuilds をラップし、各呼び出しで必要なのが d_model/nhead/n_layers だけになるようにしています。また、builds_bases=(ModelCfg,) を設定し、共有 kwargs もすべて再指定しています。builds_bases が機能するならこれは冗長ですが、ここでは pbuilds に populate_full_signature=True が設定されており、親だけにあるフィールドが空になるため必要です(上記の「シグネチャーの展開に関する落とし穴」を参照)。
慣用的なリファクタリング — バリアント用に、フルシグネチャーを展開しないビルダーをもう1つ使います。
builds_kw = make_custom_builds_fn() # for required configs
pbuilds = make_custom_builds_fn(populate_full_signature=True,
zen_partial=True) # full sig + partial
variant = make_custom_builds_fn(zen_partial=True) # partial, no full sig
# Base carries every shared kwarg (and full signature → CLI overrideable):
ModelCfg = pbuilds(
CisGeneReg,
loss_fn="${loss}", optimizer=OptimCfg, scheduler="${scheduler}",
grad_clip_val=1.0, flags="${flags}", device="cuda", compile_arch=True,
)
# Variants inherit cleanly; only the differing kwargs are listed.
model_store(variant(CisGeneReg, d_model=32, nhead=2, n_layers=2, builds_bases=(ModelCfg,)), name="tiny")
model_store(variant(CisGeneReg, d_model=64, nhead=4, n_layers=4, builds_bases=(ModelCfg,)), name="small")
変更点:variant では populate_full_signature=True を省略しているため、builds_bases=(ModelCfg,) が適切に合成されます。親のフィールドは保持され、子にはサイズを表す3つのフィールドだけが追加されます。functools.partial による間接処理もありません。(トレードオフ:バリアントの設定では、CLI にすべての CisGeneReg.__init__ フィールドが表示されなくなります。pbuilds はフルシグネチャーなので、ベースには引き続き表示され、CLI のオーバーライドは継承を通じて反映されます。)
代替案:make_config オーバーレイ
バリアントが別個のターゲット設定ではなく、CLI のオーバーレイだけである場合は、make_config(..., bases=(ModelCfg,)) が使えます(上記の「実験用オーバーレイ」を参照)。合成可能な実験にはこちらを、単一ターゲットの型付きバリアントには builds(... builds_bases=...) を使用してください。
functools.partial を直接埋め込む
functools.partial のインスタンスがあり、それを設定として登録したい場合(たとえば、デコレートできないサードパーティーのファクトリーなど)は、just でラップします。
LogConf = just(functools.partial(logger, format_spec='{0:>8s}'))
builds(logger, format_spec='{0:>8s}', zen_partial=True) と同等ですが、hydra-zen の外部で partial を作成できます。
実行時の型バリデーションを追加する
zen_wrappers=(validates_with_beartype,) または (validates_with_pydantic,) を指定すると、未絞り込みの型がインスタンス化時に再検証されます。
from hydra_zen.third_party.beartype import validates_with_beartype
ModelCfg = pbuilds(CisGeneReg, ..., zen_wrappers=validates_with_beartype)
これにより、hydra-zen が Hydra 向けに型の許容範囲を広げていても、instantiate の実行時に Literal[...]、カスタムプロトコル、ユニオン型が強制されます。
zen_meta — 設定には存在するがターゲットには渡さないフィールド
実験タグや git SHA などのメタデータを、ダンプした設定には含めつつ、ターゲットの __init__ には渡したくない場合:
ModelCfg = pbuilds(CisGeneReg, ..., zen_meta={"git_sha": "${oc.env:GIT_SHA}"})
git_sha は to_yaml(ModelCfg) に表示されますが、CisGeneReg(**kwargs) の呼び出し前に取り除かれます。
zen_exclude — シグネチャーのパラメーターを除外する
populate_full_signature=True を指定したビルドで、設定可能にしたくない kwargs がある場合:
builds(DataLoader, populate_full_signature=True, zen_exclude=("dataset", "collate_fn"))
実行時にパラメーターを設定する場合(dataset はトレーナーから渡されます)に便利です。他のパラメーターについては、フルシグネチャーを維持できます。
クイックリファレンス
| 用途 | パターン |
|---|---|
| クラスの具体的な設定 | builds(Cls, **kwargs) |
| ファクトリー/部分適用 | builds(Cls, zen_partial=True, ...) |
| プロジェクト全体のビルダーのデフォルト | make_custom_builds_fn(populate_full_signature=True, ...) |
| 静的型付きの設定(pyright) | @hydrated_dataclass(target=Cls) クラス本体 |
| 対象なしのトップレベル設定/実験 | make_config(*fields, bases=(...)) |
| シグネチャに一致する辞書 | kwargs_of(fn, **overrides) |
| 必須フィールド。デフォルト値はグループから取得 | field=MISSING + hydra_defaults=[{"group": "name"}, ...] |
| グループの選択肢をネストしたフィールドに紐付ける(慣用的) | hydra_defaults=[{"[email protected]": "default_name"}, ...] — 選択した設定を dest.path に直接設定します |
| グループの選択肢をネストしたフィールドに紐付ける(複数箇所への展開) | nested_field="${group_name}" + トップレベルの group_name=MISSING + defaults エントリー。1 つのグループ選択を複数の出力先に反映する場合に使用します |
| 遅延評価/派生値/環境変数から解決する値 | field="${other.path}"、"${oc.env:VAR}"、"${now:...}" — 型安全な代替手段はありません |
| グループの選択肢を登録 | store(group="g")(SomeCfg, name="opt") |
None に解決されるグループの選択肢 | _null_fn をグループに登録した builds(_null_fn) |
| 実験用のオーバーレイ | package="_global_" を指定して登録した make_config(hydra_defaults=[...], bases=(Config,)) |
Python リテラル/functools.partial を埋め込む | just(value) |
| 継承して上書き | builds(Cls, **overrides, builds_bases=(ParentCfg,)) — populate_full_signature=True の場合、親にのみ存在するフィールドも再指定します |
| 基底のバリエーション | builds_bases が適切に合成されるよう、フルシグネチャを使わないビルダーを使用します |
| フルシグネチャからフィールドを除外 | zen_exclude=("name1", "name2") |
| 実行時の型チェックを追加 | zen_wrappers=validates_with_beartype |
| 設定専用のメタデータ | zen_meta={"key": value} |
要注意事項 — 作業を止めて再検討してください
- hydra-zen ファイル内のどこかに
_target_が文字列として現れる →builds(...)を使用します。 - 同じストアのトップレベルフィールドではない
somethingを参照する"${something}"→ ビルダーをインライン化するか、不足しているグループ/フィールドを追加するか、(推奨)hydra_defaultsの{"[email protected]": "..."}エントリーに置き換えます。 - 対応する
group_name=MISSINGミラーフィールドがある"${group_name}"→ 動作しますが、[email protected]による配置の方がすっきりしないか検討してください。同じ選択肢を複数の出力先で本当に使う場合にのみ、補間を使用します。 - 子の
builds_bases=(Parent,)設定から親のフィールドが「謎に」消える →populate_full_signatureによる再導出が原因です。フィールドを再指定するか、フルシグネチャを使わないビルダーを使用します。 - hydra-zen ビルダーをラップする
functools.partial(some_builds_fn, target, ...)→ ほぼ確実に(2)への回避策です。builds_basesとフルシグネチャを使わないバリアントを使ってリファクタリングします。 store(group="g")(None, name="off")または CLI のg=nullが失敗する →Noneをセンチネルbuilds()でラップします。- hydra-zen プロジェクトに新しい YAML ファイルが現れる → ほぼ確実に誤りです。データクラスが信頼できる唯一の情報源です。
instantiate(cfg)が予期しないfunctools.partialを返す → ビルダーにzen_partial=Trueが指定されています。これを呼び出すか、zen_partialなしで再構築します。Literal/Unionフィールドで実行時にValidationErrorが発生する → hydra-zen によってAnyに絞り込まれています。型の適用が必要な場合は、zen_wrappers=validates_with_beartypeを追加するか、対象を@pydantic.dataclasses.dataclassでデコレートします。
LLM によくある間違い(および修正方法)
| 間違い | 間違っている理由 | 修正方法 |
|---|---|---|
OptimCfg を optimizer="${optimizer}" に置き換える | optimizer グループは登録されていないため、補間しても何も解決されません | ビルダーを渡します:optimizer=OptimCfg |
builds に _target_="pkg.Foo" のキーワード引数を書く | hydra-zen は最初の位置引数から _target_ を設定します | builds(Foo, ...) |
「無効化」するために scheduler=None を設定する | hydra-zen と Hydra のどちらも、グループオプションとしての null の解析を拒否します | builds(_null_scheduler) でラップし、"none" として登録します |
populate_full_signature=True と builds_bases を併用し、ディープマージを期待する | 子が __init__ からすべてのフィールドを再導出するため、親だけにあるフィールドが空になります | 継承したフィールドを再指定するか、子には完全なシグネチャを使わないビルダーを使用します |
バリアント間でキーワード引数を共有するために pbuilds を functools.partial でラップする | builds_bases がすでにこれを行います。このラッパーは、完全なシグネチャによる空欄化を回避するために存在します | バリアントには populate_full_signature を指定せず、2 つ目の make_custom_builds_fn を使用します |
defaults: YAML ブロックを書く | hydra-zen では store(...) の hydra_defaults=[...] キーワード引数を使います | リストを store の呼び出しに移します |
Python 定数のパラメーター化に ${oc.env:VAR} を使う | hydra-zen では通常の Python デフォルト値を記述できます | 通常のキーワード引数/ファクトリーパラメーターを使用します |
Literal[...] が実行時に強制されると考える | 型の絞り込みでは、Hydra との互換性のために Any に広げられます | zen_wrappers=validates_with_beartype を追加するか、pydantic データクラスのターゲットを使用します |
関連項目
- hydra-zen ドキュメント:https://mit-ll-responsible-ai.github.io/hydra-zen/
- DRY の根拠:上流リポジトリの
docs/source/explanation/dont_repeat_yourself.rst - 型の絞り込み:
docs/source/explanation/type_refinement.rst - 静的型付き設定:
docs/source/explanation/hydrated_dataclass.rst - 実験オーバーレイ:
docs/source/how_to/configuring_experiments.rst - 部分設定:
docs/source/how_to/partial_config.rst - Pydantic/beartype による実行時チェック:
docs/source/how_to/pydantic_guide.rst、beartype.rst - Hydra の defaults リストのセマンティクスも引き続き適用されます:https://hydra.cc/docs/advanced/defaults_list/
- このリポジトリでは、
src/gvf_germ_som/train/multigene/cfg.pyが標準的なローカルの例です。そこにあるコメントには、上記の注意点のいくつかが記載されています。