ho22joshua commited on
Commit
cbbff50
Β·
1 Parent(s): 9dcd2b7

feat: make Hydra configs installable

Browse files
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 pathlib import Path
8
 
9
  from hydra import compose, initialize_config_dir
10
  from omegaconf import OmegaConf
11
 
12
- from gnn4colliders.config.application import predict_or_evaluate, prepare, train
 
 
 
 
 
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("Usage: gnn4colliders <prepare|train|evaluate|predict> [key=value ...]")
 
 
 
23
  print("Use gnn4colliders <command> --help for command help.")
24
 
25
 
26
  def _config(overrides: list[str]):
27
- config_dir = Path(__file__).resolve().parents[3] / "configs"
28
- with initialize_config_dir(version_base=None, config_dir=str(config_dir)):
29
- return compose(config_name="config", overrides=overrides)
 
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
- print(f"saved checkpoint: {train(config)}")
 
 
 
 
56
  elif command == "evaluate":
57
  result = predict_or_evaluate(config, evaluate=True)
58
- print(OmegaConf.to_yaml(result.metrics))
 
59
  else:
60
  result = predict_or_evaluate(config)
61
- print(
62
- f"wrote predictions: {config.inference.output} "
63
- f"({len(result.sample_ids)} events)"
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
- - /task/binary_classification
3
  - _self_
 
1
  defaults:
2
+ - binary_classification
3
  - _self_
{configs β†’ src/gnn4colliders/configs}/trainer/debug.yaml RENAMED
@@ -1,4 +1,4 @@
1
  defaults:
2
- - /trainer/default
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