Commit Β·
cbbff50
1
Parent(s): 9dcd2b7
feat: make Hydra configs installable
Browse files- docs/configuration.md +94 -0
- src/gnn4colliders/cli/__init__.py +33 -13
- src/gnn4colliders/configs/__init__.py +1 -0
- {configs β src/gnn4colliders/configs}/checkpoint/default.yaml +0 -0
- {configs β src/gnn4colliders/configs}/config.yaml +2 -0
- {configs β src/gnn4colliders/configs}/data/delphes.yaml +0 -0
- {configs β src/gnn4colliders/configs}/data/local_test.yaml +6 -0
- src/gnn4colliders/configs/distributed/ddp.yaml +2 -0
- src/gnn4colliders/configs/distributed/single.yaml +2 -0
- {configs β src/gnn4colliders/configs}/environment/local.yaml +0 -0
- {configs β src/gnn4colliders/configs}/environment/perlmutter.yaml +0 -0
- src/gnn4colliders/configs/export/onnx.yaml +6 -0
- {configs β src/gnn4colliders/configs}/inference/default.yaml +0 -0
- {configs β src/gnn4colliders/configs}/model/root_gnn/edge_network.yaml +0 -0
- {configs β src/gnn4colliders/configs}/model/root_gnn/fine_tuned_edge_network.yaml +0 -0
- {configs β src/gnn4colliders/configs}/task/binary_classification.yaml +0 -0
- {configs β src/gnn4colliders/configs}/task/pretraining_multiclass.yaml +0 -0
- {configs β src/gnn4colliders/configs}/task/tth_cp_finetune.yaml +1 -1
- {configs β src/gnn4colliders/configs}/trainer/debug.yaml +1 -1
- {configs β src/gnn4colliders/configs}/trainer/default.yaml +0 -0
docs/configuration.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Configuration guide
|
| 2 |
+
|
| 3 |
+
The CLI composes the installed `gnn4colliders.configs/config.yaml` with semantic
|
| 4 |
+
Hydra groups. A config
|
| 5 |
+
describes experiment intent; it does not contain arbitrary Python module or
|
| 6 |
+
class import paths.
|
| 7 |
+
|
| 8 |
+
## Groups
|
| 9 |
+
|
| 10 |
+
| Group | Purpose |
|
| 11 |
+
| --- | --- |
|
| 12 |
+
| `data` | ROOT source or graph-cache path, batch settings, and fold splits |
|
| 13 |
+
| `model` | Model family and supported ROOT-GNN constructor settings |
|
| 14 |
+
| `task` | Binary or multiclass loss, score, and metric semantics |
|
| 15 |
+
| `trainer` | Device, seed, epochs, optimizer, scheduler, and early stopping |
|
| 16 |
+
| `checkpoint` | Output directory, resume checkpoint, or pretrained checkpoint |
|
| 17 |
+
| `inference` | Checkpoint, split, output path, and output format |
|
| 18 |
+
| `environment` | Device and experiment output root |
|
| 19 |
+
| `distributed` | Single-process/DDP selection and process-group backend |
|
| 20 |
+
|
| 21 |
+
The active model groups are `root_gnn/edge_network` and
|
| 22 |
+
`root_gnn/fine_tuned_edge_network`. The active task groups are
|
| 23 |
+
`pretraining_multiclass`, `binary_classification`, and `tth_cp_finetune`.
|
| 24 |
+
|
| 25 |
+
## Preparation
|
| 26 |
+
|
| 27 |
+
`prepare` requires `data.files`, `data.cache.path`, `data.feature_branches`,
|
| 28 |
+
`data.object_types`, and `data.scales`. `feature_branches` follows the shared
|
| 29 |
+
seven-column feature contract: one branch/constant specification per output
|
| 30 |
+
column and one entry per configured object type. `CALC_E` and `NODE_TYPE` are
|
| 31 |
+
reserved derived specifications. `object_types` entries are `vector` or
|
| 32 |
+
`single`. Preparation reads the configured tree in file order and writes a
|
| 33 |
+
versioned `GraphSampleCache`.
|
| 34 |
+
|
| 35 |
+
Example overrides are easiest to maintain in a YAML file for real datasets:
|
| 36 |
+
|
| 37 |
+
```yaml
|
| 38 |
+
# project-local example: data/my_events.yaml
|
| 39 |
+
files: [data/events.root]
|
| 40 |
+
tree_name: Events
|
| 41 |
+
cache:
|
| 42 |
+
path: cache/events.pt
|
| 43 |
+
feature_branches:
|
| 44 |
+
- [jet_pt]
|
| 45 |
+
- [jet_eta]
|
| 46 |
+
- [jet_phi]
|
| 47 |
+
- CALC_E
|
| 48 |
+
- [1.0]
|
| 49 |
+
- [0.0]
|
| 50 |
+
- NODE_TYPE
|
| 51 |
+
object_types: [vector]
|
| 52 |
+
scales: [1, 1, 1, 1, 1, 1, 1]
|
| 53 |
+
fold_var: eventNumber
|
| 54 |
+
weight_var: weight
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
Then compose it with `data=my_events`. The cache stores processed graph
|
| 58 |
+
samples, labels, globals, named metadata, and feature/graph/cache schema
|
| 59 |
+
versions. Changing the feature or graph schema requires a new compatible cache;
|
| 60 |
+
loading a mismatched schema raises an error.
|
| 61 |
+
|
| 62 |
+
## Common overrides
|
| 63 |
+
|
| 64 |
+
```bash
|
| 65 |
+
uv run gnn4colliders train \
|
| 66 |
+
data.cache.path=cache/events.pt \
|
| 67 |
+
data.batch_size=64 \
|
| 68 |
+
trainer.max_epochs=50 \
|
| 69 |
+
trainer.seed=123 \
|
| 70 |
+
environment.output_root=outputs/my_run
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
`data.batch_size` is per process. `data.splits.train_folds`,
|
| 74 |
+
`validation_folds`, and `test_folds` define conventional train/validation/test
|
| 75 |
+
selection and must be disjoint. Model/task mismatches are rejected during
|
| 76 |
+
config validation; binary tasks require `model.out_size=1`, while multiclass
|
| 77 |
+
tasks require `model.out_size=task.num_classes`.
|
| 78 |
+
|
| 79 |
+
## Checkpoints and resolved configuration
|
| 80 |
+
|
| 81 |
+
Training writes `epoch_####.pt` and the fully resolved configuration at
|
| 82 |
+
`<environment.output_root>/resolved_config.yaml`. A checkpoint includes schema
|
| 83 |
+
version, model weights/config, task config, trainer/optimizer/scheduler state,
|
| 84 |
+
early stopping state, metadata, and optional RNG state. Set
|
| 85 |
+
`checkpoint.resume=/path/to/epoch_####.pt` to continue a run. Set
|
| 86 |
+
`checkpoint.pretrained=/path/to/epoch_####.pt` with the fine-tuned model group
|
| 87 |
+
to load weights into a new task head; these options are mutually exclusive.
|
| 88 |
+
|
| 89 |
+
## Environment profiles
|
| 90 |
+
|
| 91 |
+
`environment=local` selects CPU by default. `environment=perlmutter` selects
|
| 92 |
+
the CUDA device and a conventional output-root pattern. Profiles should hold
|
| 93 |
+
device/output policy only; site-specific module loads and filesystem paths
|
| 94 |
+
belong in a launcher or shell environment.
|
src/gnn4colliders/cli/__init__.py
CHANGED
|
@@ -3,15 +3,25 @@
|
|
| 3 |
from __future__ import annotations
|
| 4 |
|
| 5 |
import logging
|
|
|
|
| 6 |
import sys
|
| 7 |
-
from
|
| 8 |
|
| 9 |
from hydra import compose, initialize_config_dir
|
| 10 |
from omegaconf import OmegaConf
|
| 11 |
|
| 12 |
-
from gnn4colliders.config.application import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
-
_COMMANDS = {"prepare", "train", "evaluate", "predict"}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
|
| 17 |
def _help(command: str | None = None) -> None:
|
|
@@ -19,14 +29,18 @@ def _help(command: str | None = None) -> None:
|
|
| 19 |
print(f"Usage: gnn4colliders {command} [key=value ...]")
|
| 20 |
print("Compose Hydra configuration with semantic overrides.")
|
| 21 |
else:
|
| 22 |
-
print(
|
|
|
|
|
|
|
|
|
|
| 23 |
print("Use gnn4colliders <command> --help for command help.")
|
| 24 |
|
| 25 |
|
| 26 |
def _config(overrides: list[str]):
|
| 27 |
-
|
| 28 |
-
with
|
| 29 |
-
|
|
|
|
| 30 |
|
| 31 |
|
| 32 |
def main(argv: list[str] | None = None) -> int:
|
|
@@ -52,16 +66,22 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 52 |
if command == "prepare":
|
| 53 |
print(f"prepared cache: {prepare(config)}")
|
| 54 |
elif command == "train":
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
elif command == "evaluate":
|
| 57 |
result = predict_or_evaluate(config, evaluate=True)
|
| 58 |
-
|
|
|
|
| 59 |
else:
|
| 60 |
result = predict_or_evaluate(config)
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
|
|
|
| 65 |
return 0
|
| 66 |
except (ValueError, FileNotFoundError, KeyError, ImportError) as error:
|
| 67 |
print(f"gnn4colliders: {error}", file=sys.stderr)
|
|
|
|
| 3 |
from __future__ import annotations
|
| 4 |
|
| 5 |
import logging
|
| 6 |
+
import os
|
| 7 |
import sys
|
| 8 |
+
from importlib import resources
|
| 9 |
|
| 10 |
from hydra import compose, initialize_config_dir
|
| 11 |
from omegaconf import OmegaConf
|
| 12 |
|
| 13 |
+
from gnn4colliders.config.application import (
|
| 14 |
+
export_onnx,
|
| 15 |
+
predict_or_evaluate,
|
| 16 |
+
prepare,
|
| 17 |
+
train,
|
| 18 |
+
)
|
| 19 |
|
| 20 |
+
_COMMANDS = {"prepare", "train", "evaluate", "predict", "export"}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def _is_main_process() -> bool:
|
| 24 |
+
return int(os.environ.get("RANK", "0")) == 0
|
| 25 |
|
| 26 |
|
| 27 |
def _help(command: str | None = None) -> None:
|
|
|
|
| 29 |
print(f"Usage: gnn4colliders {command} [key=value ...]")
|
| 30 |
print("Compose Hydra configuration with semantic overrides.")
|
| 31 |
else:
|
| 32 |
+
print(
|
| 33 |
+
"Usage: gnn4colliders <prepare|train|evaluate|predict|export> "
|
| 34 |
+
"[key=value ...]"
|
| 35 |
+
)
|
| 36 |
print("Use gnn4colliders <command> --help for command help.")
|
| 37 |
|
| 38 |
|
| 39 |
def _config(overrides: list[str]):
|
| 40 |
+
config_resource = resources.files("gnn4colliders.configs")
|
| 41 |
+
with resources.as_file(config_resource) as config_dir:
|
| 42 |
+
with initialize_config_dir(version_base=None, config_dir=str(config_dir)):
|
| 43 |
+
return compose(config_name="config", overrides=overrides)
|
| 44 |
|
| 45 |
|
| 46 |
def main(argv: list[str] | None = None) -> int:
|
|
|
|
| 66 |
if command == "prepare":
|
| 67 |
print(f"prepared cache: {prepare(config)}")
|
| 68 |
elif command == "train":
|
| 69 |
+
if _is_main_process():
|
| 70 |
+
print(f"saved checkpoint: {train(config)}")
|
| 71 |
+
elif command == "export":
|
| 72 |
+
if _is_main_process():
|
| 73 |
+
print(f"wrote ONNX model: {export_onnx(config)}")
|
| 74 |
elif command == "evaluate":
|
| 75 |
result = predict_or_evaluate(config, evaluate=True)
|
| 76 |
+
if _is_main_process():
|
| 77 |
+
print(OmegaConf.to_yaml(result.metrics))
|
| 78 |
else:
|
| 79 |
result = predict_or_evaluate(config)
|
| 80 |
+
if _is_main_process():
|
| 81 |
+
print(
|
| 82 |
+
f"wrote predictions: {config.inference.output} "
|
| 83 |
+
f"({len(result.sample_ids)} events)"
|
| 84 |
+
)
|
| 85 |
return 0
|
| 86 |
except (ValueError, FileNotFoundError, KeyError, ImportError) as error:
|
| 87 |
print(f"gnn4colliders: {error}", file=sys.stderr)
|
src/gnn4colliders/configs/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
"""Canonical Hydra configuration tree shipped with the package."""
|
{configs β src/gnn4colliders/configs}/checkpoint/default.yaml
RENAMED
|
File without changes
|
{configs β src/gnn4colliders/configs}/config.yaml
RENAMED
|
@@ -6,6 +6,8 @@ defaults:
|
|
| 6 |
- checkpoint: default
|
| 7 |
- inference: default
|
| 8 |
- environment: local
|
|
|
|
|
|
|
| 9 |
- _self_
|
| 10 |
experiment:
|
| 11 |
name: pretraining_multiclass
|
|
|
|
| 6 |
- checkpoint: default
|
| 7 |
- inference: default
|
| 8 |
- environment: local
|
| 9 |
+
- distributed: single
|
| 10 |
+
- export: onnx
|
| 11 |
- _self_
|
| 12 |
experiment:
|
| 13 |
name: pretraining_multiclass
|
{configs β src/gnn4colliders/configs}/data/delphes.yaml
RENAMED
|
File without changes
|
{configs β src/gnn4colliders/configs}/data/local_test.yaml
RENAMED
|
@@ -1,5 +1,11 @@
|
|
| 1 |
files: []
|
| 2 |
tree_name: Events
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
batch_size: 32
|
| 4 |
num_workers: 0
|
| 5 |
shuffle: true
|
|
|
|
| 1 |
files: []
|
| 2 |
tree_name: Events
|
| 3 |
+
feature_branches: null
|
| 4 |
+
object_types: null
|
| 5 |
+
scales: null
|
| 6 |
+
global_features: []
|
| 7 |
+
fold_var: eventNumber
|
| 8 |
+
weight_var: null
|
| 9 |
batch_size: 32
|
| 10 |
num_workers: 0
|
| 11 |
shuffle: true
|
src/gnn4colliders/configs/distributed/ddp.yaml
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
enabled: true
|
| 2 |
+
backend: null
|
src/gnn4colliders/configs/distributed/single.yaml
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
enabled: false
|
| 2 |
+
backend: null
|
{configs β src/gnn4colliders/configs}/environment/local.yaml
RENAMED
|
File without changes
|
{configs β src/gnn4colliders/configs}/environment/perlmutter.yaml
RENAMED
|
File without changes
|
src/gnn4colliders/configs/export/onnx.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
format: onnx
|
| 2 |
+
checkpoint: null
|
| 3 |
+
output: ${environment.output_root}/export/model.onnx
|
| 4 |
+
opset: 17
|
| 5 |
+
split: train
|
| 6 |
+
overwrite: false
|
{configs β src/gnn4colliders/configs}/inference/default.yaml
RENAMED
|
File without changes
|
{configs β src/gnn4colliders/configs}/model/root_gnn/edge_network.yaml
RENAMED
|
File without changes
|
{configs β src/gnn4colliders/configs}/model/root_gnn/fine_tuned_edge_network.yaml
RENAMED
|
File without changes
|
{configs β src/gnn4colliders/configs}/task/binary_classification.yaml
RENAMED
|
File without changes
|
{configs β src/gnn4colliders/configs}/task/pretraining_multiclass.yaml
RENAMED
|
File without changes
|
{configs β src/gnn4colliders/configs}/task/tth_cp_finetune.yaml
RENAMED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
defaults:
|
| 2 |
-
-
|
| 3 |
- _self_
|
|
|
|
| 1 |
defaults:
|
| 2 |
+
- binary_classification
|
| 3 |
- _self_
|
{configs β src/gnn4colliders/configs}/trainer/debug.yaml
RENAMED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
defaults:
|
| 2 |
-
-
|
| 3 |
- _self_
|
| 4 |
max_epochs: 1
|
|
|
|
| 1 |
defaults:
|
| 2 |
+
- default
|
| 3 |
- _self_
|
| 4 |
max_epochs: 1
|
{configs β src/gnn4colliders/configs}/trainer/default.yaml
RENAMED
|
File without changes
|