Commit ·
d2c3c35
1
Parent(s): 97f7eaf
docs: document the rewritten ROOT-GNN stack
Browse files- README.md +233 -25
- docs/architecture.md +154 -1
- docs/migration.md +137 -11
README.md
CHANGED
|
@@ -1,41 +1,249 @@
|
|
| 1 |
# GNN4Colliders
|
| 2 |
|
| 3 |
-
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
```bash
|
| 14 |
-
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
-
|
| 18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
uv run pytest
|
|
|
|
| 20 |
uv run ruff check .
|
| 21 |
uv run ruff format --check .
|
|
|
|
|
|
|
| 22 |
```
|
| 23 |
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
|
|
|
| 28 |
|
| 29 |
-
|
| 30 |
-
uv sync --extra ml
|
| 31 |
-
```
|
| 32 |
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
installable on this Linux host without a site-provided or source-built DGL.
|
| 38 |
-
Training and inference workflows are not yet implemented.
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
|
|
|
|
|
|
|
|
| 1 |
# GNN4Colliders
|
| 2 |
|
| 3 |
+
GNN4Colliders is a collider-machine-learning toolkit. The repository name
|
| 4 |
+
reflects its first production model family, ROOT-GNN; the Python package is
|
| 5 |
+
`gnn4colliders`, and the configuration identifier is `root_gnn`. Shared ROOT
|
| 6 |
+
ingestion, collider features, metadata, tasks, training, inference, and
|
| 7 |
+
distributed utilities are designed so that a future sequence model can reuse
|
| 8 |
+
them without requiring every event to be a graph.
|
| 9 |
|
| 10 |
+
```text
|
| 11 |
+
ROOT files -> EventSample -> shared collider features
|
| 12 |
+
├── GraphSample -> ROOT-GNN
|
| 13 |
+
└── future SequenceSample -> ROOT-Transformer
|
| 14 |
+
```
|
| 15 |
+
|
| 16 |
+
The new implementation lives under [`src/gnn4colliders`](src/gnn4colliders/).
|
| 17 |
+
[`legacy/`](legacy/) is a frozen behavioral reference for parity work and
|
| 18 |
+
historical checkpoint investigation, not a supported runtime backend.
|
| 19 |
+
|
| 20 |
+
## Installation
|
| 21 |
+
|
| 22 |
+
The supported development environment is Python 3.12 (`>=3.12,<3.13`), with
|
| 23 |
+
PyTorch 2.2.2 and the optional ROOT-GNN stack DGL 2.4.0. The canonical setup
|
| 24 |
+
is:
|
| 25 |
+
|
| 26 |
+
```bash
|
| 27 |
+
uv sync --dev --extra root-gnn
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
The core package can be installed without DGL when only shared data or task
|
| 31 |
+
code is needed. ROOT-GNN models, graph construction, and ROOT-GNN parity tests
|
| 32 |
+
require the `root-gnn` extra. The DGL extra uses the validated CUDA 12.1 wheel
|
| 33 |
+
source configured in `pyproject.toml`; a compatible NVIDIA driver is still
|
| 34 |
+
required. Do not add site-specific CUDA, Slurm, or filesystem paths to model
|
| 35 |
+
or task configuration.
|
| 36 |
+
|
| 37 |
+
## Quick start
|
| 38 |
|
| 39 |
+
Prepare a graph cache from a ROOT tree. The feature specifications below are
|
| 40 |
+
illustrative placeholders; replace them with the branches in the input tree.
|
| 41 |
+
The full preparation interface is documented in
|
| 42 |
+
[`docs/configuration.md`](docs/configuration.md).
|
| 43 |
|
| 44 |
```bash
|
| 45 |
+
uv run gnn4colliders prepare \
|
| 46 |
+
data.files=[data/events.root] \
|
| 47 |
+
data.tree_name=Events \
|
| 48 |
+
data.cache.path=cache/events.pt \
|
| 49 |
+
'data.feature_branches=[["jet_pt"],["jet_eta"],["jet_phi"],CALC_E,[1.0],[0.0],NODE_TYPE]' \
|
| 50 |
+
data.object_types=[vector] \
|
| 51 |
+
data.scales=[1,1,1,1,1,1,1]
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
Train, evaluate, and predict from that cache:
|
| 55 |
+
|
| 56 |
+
```bash
|
| 57 |
+
uv run gnn4colliders train \
|
| 58 |
+
data.cache.path=cache/events.pt \
|
| 59 |
+
trainer.max_epochs=1 \
|
| 60 |
+
environment.output_root=outputs/pretraining_multiclass
|
| 61 |
+
|
| 62 |
+
uv run gnn4colliders evaluate \
|
| 63 |
+
data.cache.path=cache/events.pt \
|
| 64 |
+
inference.checkpoint=outputs/pretraining_multiclass/checkpoints/epoch_0000.pt
|
| 65 |
+
|
| 66 |
+
uv run gnn4colliders predict \
|
| 67 |
+
data.cache.path=cache/events.pt \
|
| 68 |
+
inference.checkpoint=outputs/pretraining_multiclass/checkpoints/epoch_0000.pt \
|
| 69 |
+
inference.output=outputs/pretraining_multiclass/predictions.npz
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
For a dependency-complete, temporary-data version of this flow, run
|
| 73 |
+
`uv run python scripts/dev/smoke_end_to_end.py`.
|
| 74 |
+
|
| 75 |
+
## Core concepts
|
| 76 |
+
|
| 77 |
+
`EventSample` is the architecture-neutral event boundary. It contains the
|
| 78 |
+
selected `objects`, `label`, `global_features`, and named `EventMetadata`.
|
| 79 |
+
Metadata includes `fold`, `weight`, and stable `sample_id`; callers should not
|
| 80 |
+
interpret public `tracking[:, N]` columns. Legacy tracking mappings exist only
|
| 81 |
+
at compatibility boundaries.
|
| 82 |
+
|
| 83 |
+
The ROOT-GNN adapter converts shared features to a directed, fully connected
|
| 84 |
+
graph with no self-loops: an event with `N` nodes has `N * (N - 1)` edges.
|
| 85 |
+
Node columns are, in order, `pt`, `eta`, `phi`, `energy`, `btag`, `charge`,
|
| 86 |
+
and `node_type`. Edge columns are `deta`, wrapped `dphi`, and `dR`.
|
| 87 |
+
Object collections are concatenated in configured object-type order. The
|
| 88 |
+
compatibility energy is `pt * cosh(eta)` before per-column scaling.
|
| 89 |
+
|
| 90 |
+
`GraphSampleCache` stores processed graph samples and schema metadata. It is a
|
| 91 |
+
Level-2 graph cache, not the universal event cache. Feature, graph, and cache
|
| 92 |
+
schema versions are checked when loading; incompatible versions fail before
|
| 93 |
+
training.
|
| 94 |
+
|
| 95 |
+
## ROOT-GNN training and transfer
|
| 96 |
+
|
| 97 |
+
`EdgeNetwork` encodes node, edge, and global features, performs iterative
|
| 98 |
+
edge/node/global message passing, decodes a graph representation, and applies
|
| 99 |
+
the classifier. Its output is raw logits; sigmoid or softmax is task-owned.
|
| 100 |
+
|
| 101 |
+
Multiclass pretraining uses the semantic `model=root_gnn/edge_network` and
|
| 102 |
+
`task=pretraining_multiclass` groups:
|
| 103 |
+
|
| 104 |
+
```bash
|
| 105 |
+
uv run gnn4colliders train \
|
| 106 |
+
data.cache.path=cache/events.pt \
|
| 107 |
+
model=root_gnn/edge_network task=pretraining_multiclass \
|
| 108 |
+
trainer.max_epochs=20 data.batch_size=64 \
|
| 109 |
+
environment.output_root=outputs/pretraining_multiclass
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
Fine-tuning is a separate workflow. It loads a pretrained backbone, replaces
|
| 113 |
+
the classifier, and creates a new task/head optimizer:
|
| 114 |
+
|
| 115 |
+
```bash
|
| 116 |
+
uv run gnn4colliders train \
|
| 117 |
+
data.cache.path=cache/target.pt \
|
| 118 |
+
model=root_gnn/fine_tuned_edge_network \
|
| 119 |
+
task=binary_classification \
|
| 120 |
+
checkpoint.pretrained=/path/to/pretrained.pt \
|
| 121 |
+
model.freeze_backbone=true \
|
| 122 |
+
trainer.max_epochs=10
|
| 123 |
+
```
|
| 124 |
+
|
| 125 |
+
Set `model.freeze_backbone=false` to train the reused backbone as well.
|
| 126 |
+
Transfer learning is not resume training:
|
| 127 |
+
|
| 128 |
+
| Workflow | Meaning | Restored state |
|
| 129 |
+
| --- | --- | --- |
|
| 130 |
+
| Resume | Continue the same task/run | model, optimizer, scheduler, trainer, early stopping, and RNG state when present |
|
| 131 |
+
| Transfer | Start a new task from a pretrained backbone | model weights only; new classifier and optimizer |
|
| 132 |
|
| 133 |
+
Resume example:
|
| 134 |
|
| 135 |
+
```bash
|
| 136 |
+
uv run gnn4colliders train \
|
| 137 |
+
data.cache.path=cache/events.pt \
|
| 138 |
+
checkpoint.resume=outputs/pretraining_multiclass/checkpoints/epoch_0000.pt \
|
| 139 |
+
trainer.max_epochs=20
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
Validation is evaluated each epoch and drives scheduling/early stopping;
|
| 143 |
+
`test` remains held out. Evaluation computes task metrics over the complete
|
| 144 |
+
selected split, including weighted ROC AUC where defined:
|
| 145 |
+
|
| 146 |
+
```bash
|
| 147 |
+
uv run gnn4colliders evaluate \
|
| 148 |
+
data.cache.path=cache/events.pt \
|
| 149 |
+
inference.split=test \
|
| 150 |
+
inference.checkpoint=/path/to/checkpoint.pt
|
| 151 |
+
```
|
| 152 |
+
|
| 153 |
+
Prediction writes a named compressed NPZ. Labeled data includes `labels`;
|
| 154 |
+
`fold` and `weight` are included when available. Every result includes
|
| 155 |
+
`sample_id`, `logits`, `scores`, and `predictions`:
|
| 156 |
+
|
| 157 |
+
```bash
|
| 158 |
+
uv run gnn4colliders predict \
|
| 159 |
+
data.cache.path=cache/events.pt \
|
| 160 |
+
inference.checkpoint=/path/to/checkpoint.pt \
|
| 161 |
+
inference.output=outputs/predictions.npz
|
| 162 |
+
```
|
| 163 |
+
|
| 164 |
+
Optional Python-level ROOT writing is provided by
|
| 165 |
+
`gnn4colliders.inference.write_root_scores`. It clones the selected tree,
|
| 166 |
+
adds `score` (or `score_class_N`), and writes `selection_pass`; IDs ending in
|
| 167 |
+
`:<entry>` preserve alignment and unselected entries receive NaN scores. The
|
| 168 |
+
CLI currently exposes NPZ output only.
|
| 169 |
+
|
| 170 |
+
The supported legacy checkpoint, metadata, and output boundary is documented
|
| 171 |
+
in [`docs/compatibility.md`](docs/compatibility.md). New code should use named
|
| 172 |
+
metadata fields; positional tracking is accepted only by the explicit
|
| 173 |
+
compatibility adapter.
|
| 174 |
+
|
| 175 |
+
### ONNX export
|
| 176 |
+
|
| 177 |
+
Install the optional export dependencies and export a prepared graph-cache
|
| 178 |
+
checkpoint with numerical ONNX validation:
|
| 179 |
+
|
| 180 |
+
```bash
|
| 181 |
+
uv sync --extra root-gnn --extra onnx
|
| 182 |
+
uv run gnn4colliders export \
|
| 183 |
+
export.checkpoint=/path/to/checkpoint.pt \
|
| 184 |
+
export.output=model.onnx \
|
| 185 |
+
data.cache.path=/path/to/graph-cache.pt
|
| 186 |
+
```
|
| 187 |
+
|
| 188 |
+
The model accepts processed graph tensors and returns raw logits. See
|
| 189 |
+
[`docs/export.md`](docs/export.md) for the tensor contract and limitations.
|
| 190 |
+
|
| 191 |
+
## Configuration and environments
|
| 192 |
+
|
| 193 |
+
Hydra groups are `data`, `model`, `task`, `trainer`, `checkpoint`,
|
| 194 |
+
`inference`, `environment`, and `distributed`. Use configuration for a new
|
| 195 |
+
experiment and Python for new behavior. Examples:
|
| 196 |
+
|
| 197 |
+
```bash
|
| 198 |
+
uv run gnn4colliders train trainer.max_epochs=50 data.batch_size=64
|
| 199 |
+
uv run gnn4colliders train environment=perlmutter environment.device=cuda
|
| 200 |
+
uv run gnn4colliders train distributed=ddp environment=perlmutter
|
| 201 |
+
```
|
| 202 |
+
|
| 203 |
+
Each run writes a resolved configuration to
|
| 204 |
+
`<environment.output_root>/resolved_config.yaml`. See
|
| 205 |
+
[`docs/configuration.md`](docs/configuration.md) for the group reference and
|
| 206 |
+
[`docs/perlmutter.md`](docs/perlmutter.md) for launch examples.
|
| 207 |
+
|
| 208 |
+
## Distributed execution and reproducibility
|
| 209 |
+
|
| 210 |
+
Launch DDP with `torchrun` or the provided Slurm wrappers. `data.batch_size`
|
| 211 |
+
and `data.num_workers` are per process, so the ordinary effective batch size
|
| 212 |
+
is `batch_size * world_size`. Training shards may be padded for equal steps;
|
| 213 |
+
validation and prediction are unpadded. Rank 0 writes shared checkpoints,
|
| 214 |
+
configs, and predictions, and metrics/results are gathered across ranks.
|
| 215 |
+
|
| 216 |
+
The configured seed controls initialization and deterministic local loader
|
| 217 |
+
ordering; distributed process seeds are rank-offset and samplers use
|
| 218 |
+
`set_epoch`. CPU runs are reproducible for fixed inputs and environment. GPU
|
| 219 |
+
kernels, DGL, and distributed scheduling can remain nondeterministic, so the
|
| 220 |
+
project does not promise bitwise GPU reproducibility.
|
| 221 |
+
|
| 222 |
+
## Development and validation
|
| 223 |
+
|
| 224 |
+
```bash
|
| 225 |
uv run pytest
|
| 226 |
+
GNN4COLLIDERS_REQUIRE_ROOT_GNN=1 uv run pytest tests/parity -v
|
| 227 |
uv run ruff check .
|
| 228 |
uv run ruff format --check .
|
| 229 |
+
uv run python benchmarks/benchmark_preprocessing.py
|
| 230 |
+
uv run python benchmarks/benchmark_training.py --device cpu
|
| 231 |
```
|
| 232 |
|
| 233 |
+
Unit tests cover isolated components, integration tests cover small workflows,
|
| 234 |
+
and parity tests compare deterministic behavior with the frozen legacy
|
| 235 |
+
reference. Performance guidance and measured caveats are in
|
| 236 |
+
[`docs/performance.md`](docs/performance.md) and
|
| 237 |
+
[`benchmarks/README.md`](benchmarks/README.md).
|
| 238 |
|
| 239 |
+
## Architecture and migration status
|
|
|
|
|
|
|
| 240 |
|
| 241 |
+
See [`docs/architecture.md`](docs/architecture.md) for responsibility
|
| 242 |
+
boundaries and the future sequence-model extension point. See
|
| 243 |
+
[`docs/migration.md`](docs/migration.md) for the migration matrix,
|
| 244 |
+
intentional redesigns, compatibility limits, and deferred work.
|
|
|
|
|
|
|
| 245 |
|
| 246 |
+
ROOT-GNN v1 covers ROOT preparation, validated feature/graph/model/task
|
| 247 |
+
behavior, training, fine-tuning, checkpoint resume, evaluation, prediction,
|
| 248 |
+
single-process/DDP execution, and validated ONNX export. Streaming distributed
|
| 249 |
+
output, legacy cleanup, and ROOT-Transformer remain follow-up work.
|
docs/architecture.md
CHANGED
|
@@ -1,4 +1,79 @@
|
|
| 1 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
This document covers the target system in `legacy/root_gnn_dgl/`. The sibling
|
| 4 |
`legacy/physicsnemo/` tree is a prior rewrite attempt and is not a behavioral
|
|
@@ -6,6 +81,12 @@ target.
|
|
| 6 |
|
| 7 |
## 1. High-level system description
|
| 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
`root_gnn_dgl` is a ROOT-to-DGL graph classification system. YAML selects
|
| 10 |
dataset, model, loss, and finish-function classes by import path. The dataset
|
| 11 |
reads ROOT trees, converts collider objects to fully connected DGL graphs, and
|
|
@@ -137,6 +218,55 @@ Keys strip `module.` and compiled models save the underlying `_orig_mod` state;
|
|
| 137 |
to a cloned ROOT tree ([`training_script.py:57-140`](../legacy/root_gnn_dgl/scripts/training_script.py),
|
| 138 |
[`inference.py:328-385`](../legacy/root_gnn_dgl/scripts/inference.py)).
|
| 139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
## Randomness, external services, and coupling
|
| 141 |
|
| 142 |
The CLI exposes `--seed`, but `main` passes it to model construction rather
|
|
@@ -187,11 +317,34 @@ when a config has a validation fold ([`training_script.py:682-747`](../legacy/ro
|
|
| 187 |
|
| 188 |
## 3. De facto interfaces to preserve
|
| 189 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
The rewrite's shared data boundary is `gnn4colliders.data`: it reads selected
|
| 191 |
ROOT/Awkward branches and returns architecture-neutral event samples. Feature
|
| 192 |
construction and graph building remain separate downstream boundaries, so the
|
| 193 |
same samples can be reused by non-graph model families.
|
| 194 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
1. YAML `module`, `class`, `args`, plus runtime `sample_graph` and
|
| 196 |
`sample_global` injection.
|
| 197 |
2. Dataset items `(DGLGraph, label, tracking, global_features)`.
|
|
|
|
| 1 |
+
# GNN4Colliders architecture
|
| 2 |
+
|
| 3 |
+
## Current v1 architecture
|
| 4 |
+
|
| 5 |
+
The supported rewrite is layered around an architecture-neutral event boundary:
|
| 6 |
+
|
| 7 |
+
```text
|
| 8 |
+
ROOT/Awkward
|
| 9 |
+
↓
|
| 10 |
+
EventSample + EventMetadata
|
| 11 |
+
↓
|
| 12 |
+
shared collider feature construction
|
| 13 |
+
├── GraphSample -> versioned graph cache -> GraphBatch
|
| 14 |
+
└── future SequenceSample -> ROOT-Transformer (not implemented)
|
| 15 |
+
↓
|
| 16 |
+
ROOT-GNN EdgeNetwork
|
| 17 |
+
↓
|
| 18 |
+
raw logits -> Task
|
| 19 |
+
├── loss
|
| 20 |
+
├── predictions
|
| 21 |
+
└── full-split metrics
|
| 22 |
+
↓
|
| 23 |
+
Trainer / Predictor / outputs
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
| Layer | Responsibility |
|
| 27 |
+
| --- | --- |
|
| 28 |
+
| `data` | ROOT/Awkward ingestion, event samples, metadata, graph caches, folds, and batching |
|
| 29 |
+
| `features` | Shared collider-object features and derived physics quantities |
|
| 30 |
+
| `graphs` | Topology, edge features, and the DGL representation adapter |
|
| 31 |
+
| `models/root_gnn` | ROOT-GNN encoders, message passing, classifier, and transfer boundary |
|
| 32 |
+
| `tasks` | Loss, score/prediction, labels, weights, and metrics |
|
| 33 |
+
| `training` | Optimizer lifecycle, validation, early stopping, checkpointing, and reproducibility |
|
| 34 |
+
| `inference` | Ordered prediction/evaluation and NPZ/ROOT output adapters |
|
| 35 |
+
| `distributed` | Rank-local devices, sharding, DDP, and cross-rank collection |
|
| 36 |
+
| `config` / `cli` | Semantic Hydra composition and thin user-facing commands |
|
| 37 |
+
|
| 38 |
+
`EventSample` is shared infrastructure, not a ROOT-GNN object. `GraphSample`
|
| 39 |
+
is the current representation-specific adapter. This separation is the
|
| 40 |
+
extension point for a future sequence/token representation.
|
| 41 |
+
|
| 42 |
+
The new public metadata contract is named `EventMetadata(fold, weight,
|
| 43 |
+
sample_id, extra)`. The legacy positional tracking tensor is accepted only by
|
| 44 |
+
compatibility-facing ingestion code. A `GraphSampleCache` is deliberately a
|
| 45 |
+
Level-2 graph cache; replacing it with a universal cache would couple future
|
| 46 |
+
model families to DGL.
|
| 47 |
+
|
| 48 |
+
For deployment, a prepared `GraphBatch` can pass through the isolated
|
| 49 |
+
`RootGNNExportAdapter` into an ONNX model. This is an inference boundary only;
|
| 50 |
+
the native model continues to consume DGL graphs and ONNX does not read ROOT
|
| 51 |
+
or construct collider features.
|
| 52 |
+
|
| 53 |
+
## Current public workflow
|
| 54 |
+
|
| 55 |
+
`prepare` reads ROOT through `RootEventDataset`, builds shared features and
|
| 56 |
+
DGL graphs, and saves a schema-checked cache. `train` creates a model/task and
|
| 57 |
+
`Trainer`; validation is the model-selection split and test is held out.
|
| 58 |
+
`evaluate` computes metrics after collecting the complete split. `predict`
|
| 59 |
+
returns detached CPU tensors in loader order and writes named NPZ fields.
|
| 60 |
+
`write_root_scores` is an optional Python adapter with explicit entry alignment;
|
| 61 |
+
the CLI currently exposes NPZ output.
|
| 62 |
+
|
| 63 |
+
Compatibility responsibilities are isolated in `gnn4colliders.compat`.
|
| 64 |
+
Supported historical checkpoint prefixes, classifier names, and the two-column
|
| 65 |
+
tracking conversion are listed in [`compatibility.md`](compatibility.md).
|
| 66 |
+
The modern pipeline does not propagate positional tracking or historical NPZ
|
| 67 |
+
fields.
|
| 68 |
+
|
| 69 |
+
Checkpoints are independent of the model implementation: they carry model and
|
| 70 |
+
task metadata, lifecycle state, schema versions, and optional RNG state.
|
| 71 |
+
Prefix normalization supports DDP `module.` and compiled `_orig_mod.` weights,
|
| 72 |
+
plus the active ROOT-GNN historical classifier-name compatibility path.
|
| 73 |
+
|
| 74 |
+
---
|
| 75 |
+
|
| 76 |
+
## Historical behavioral reference
|
| 77 |
|
| 78 |
This document covers the target system in `legacy/root_gnn_dgl/`. The sibling
|
| 79 |
`legacy/physicsnemo/` tree is a prior rewrite attempt and is not a behavioral
|
|
|
|
| 81 |
|
| 82 |
## 1. High-level system description
|
| 83 |
|
| 84 |
+
The active rewrite exposes `gnn4colliders.models.root_gnn.EdgeNetwork`. Its
|
| 85 |
+
encoders and message-passing blocks form a reusable backbone whose decoded
|
| 86 |
+
graph representation is passed to an explicit classifier. `FineTunedEdgeNetwork`
|
| 87 |
+
reuses that backbone and replaces only the task-specific classifier, with
|
| 88 |
+
explicit frozen or trainable-backbone control.
|
| 89 |
+
|
| 90 |
`root_gnn_dgl` is a ROOT-to-DGL graph classification system. YAML selects
|
| 91 |
dataset, model, loss, and finish-function classes by import path. The dataset
|
| 92 |
reads ROOT trees, converts collider objects to fully connected DGL graphs, and
|
|
|
|
| 218 |
to a cloned ROOT tree ([`training_script.py:57-140`](../legacy/root_gnn_dgl/scripts/training_script.py),
|
| 219 |
[`inference.py:328-385`](../legacy/root_gnn_dgl/scripts/inference.py)).
|
| 220 |
|
| 221 |
+
### Training lifecycle boundary
|
| 222 |
+
|
| 223 |
+
The active rewrite keeps lifecycle orchestration architecture-independent:
|
| 224 |
+
|
| 225 |
+
```text
|
| 226 |
+
GraphDataLoader -> GraphBatch -> Model -> Task -> Trainer
|
| 227 |
+
loss/metrics
|
| 228 |
+
```
|
| 229 |
+
|
| 230 |
+
`gnn4colliders.training.Trainer` owns device placement, train/evaluation mode,
|
| 231 |
+
gradient and optimizer steps, epoch aggregation, optional scheduler stepping,
|
| 232 |
+
early stopping, and in-memory history. Tasks own loss and metric semantics;
|
| 233 |
+
the trainer does not inspect positional tracking columns or collider-specific
|
| 234 |
+
features. Evaluation concatenates detached outputs across the complete split
|
| 235 |
+
before calling task metrics, so ROC AUC is not computed per mini-batch.
|
| 236 |
+
|
| 237 |
+
Checkpoint persistence and the Python inference/output layer are implemented
|
| 238 |
+
as separate adapters. The semantic CLI and distributed application boundary
|
| 239 |
+
are implemented in the current stack. `gnn4colliders.inference.Predictor` accumulates detached CPU
|
| 240 |
+
logits, task-defined scores/predictions, labels, and named event metadata in
|
| 241 |
+
loader order; `write_npz` is the primary named-field format and ROOT score
|
| 242 |
+
writing is an optional alignment-aware adapter.
|
| 243 |
+
|
| 244 |
+
The new lifecycle uses conventional split semantics. `train` updates model
|
| 245 |
+
parameters, `validation` is evaluated after every epoch and drives scheduler,
|
| 246 |
+
early-stopping, and later model selection, and `test` is held out. The trainer
|
| 247 |
+
does not accept a test loader in `fit`; callers evaluate the held-out test set
|
| 248 |
+
separately after training. This deliberately corrects the legacy convention
|
| 249 |
+
where a loader named `test` was used for model selection and `val` represented
|
| 250 |
+
held-out testing.
|
| 251 |
+
|
| 252 |
+
## Distributed execution
|
| 253 |
+
|
| 254 |
+
`gnn4colliders.distributed` contains the small DDP boundary used by the
|
| 255 |
+
application layer. `DistributedContext` reads the standard `torchrun`
|
| 256 |
+
environment (`RANK`, `LOCAL_RANK`, and `WORLD_SIZE`), selects the rank-local
|
| 257 |
+
device, and owns process-group cleanup. Graph samples are sharded before
|
| 258 |
+
batching; training may pad rank shards for equal step counts, while validation
|
| 259 |
+
and prediction use unpadded shards so events are not counted twice.
|
| 260 |
+
|
| 261 |
+
The configured graph `batch_size` is per process. DDP wraps an otherwise
|
| 262 |
+
ordinary model after device placement, and checkpoint state is normalized to
|
| 263 |
+
the underlying model keys. Loss gradients are synchronized by DDP; epoch
|
| 264 |
+
metrics and evaluation outputs are gathered across ranks. Rank 0 writes
|
| 265 |
+
resolved configuration, checkpoints, and NPZ predictions. Moderate-size
|
| 266 |
+
prediction gathering is in-memory; streaming/sharded output is a future
|
| 267 |
+
extension.
|
| 268 |
+
|
| 269 |
+
|
| 270 |
## Randomness, external services, and coupling
|
| 271 |
|
| 272 |
The CLI exposes `--seed`, but `main` passes it to model construction rather
|
|
|
|
| 317 |
|
| 318 |
## 3. De facto interfaces to preserve
|
| 319 |
|
| 320 |
+
### Metadata-aware dataset boundary
|
| 321 |
+
|
| 322 |
+
The rewrite uses named `EventMetadata` (`fold`, `weight`, and stable
|
| 323 |
+
`sample_id`) instead of exposing the legacy positional tracking tensor.
|
| 324 |
+
`GraphSample`, `GraphBatch`, `SplitDefinition`, and `GraphDataLoader` form the
|
| 325 |
+
ROOT-GNN orchestration boundary. Graph caches carry feature, graph, and cache
|
| 326 |
+
schema versions and reject incompatible artifacts before loading.
|
| 327 |
+
|
| 328 |
+
The current cache implementation stores processed `GraphSample` values (the
|
| 329 |
+
Level-2 cache). The separation from `RootEventDataset` is intentional: a
|
| 330 |
+
future Level-1 cache can store normalized `EventSample`/feature data for
|
| 331 |
+
sequence or transformer representations without requiring DGL graph caches.
|
| 332 |
+
|
| 333 |
The rewrite's shared data boundary is `gnn4colliders.data`: it reads selected
|
| 334 |
ROOT/Awkward branches and returns architecture-neutral event samples. Feature
|
| 335 |
construction and graph building remain separate downstream boundaries, so the
|
| 336 |
same samples can be reused by non-graph model families.
|
| 337 |
|
| 338 |
+
### Configuration and CLI boundary
|
| 339 |
+
|
| 340 |
+
Hydra composes semantic YAML groups under `configs/` and passes the resolved
|
| 341 |
+
configuration to explicit application factories in `gnn4colliders.config`.
|
| 342 |
+
Those factories allow-list supported models, tasks, and trainer components;
|
| 343 |
+
YAML is never treated as an arbitrary Python import specification. The thin
|
| 344 |
+
`gnn4colliders` CLI selects `prepare`, `train`, `evaluate`, or `predict` and
|
| 345 |
+
delegates to the stable data, training, checkpoint, and inference APIs. A new
|
| 346 |
+
experiment should generally be a YAML change; new behavior belongs in Python.
|
| 347 |
+
|
| 348 |
1. YAML `module`, `class`, `args`, plus runtime `sample_graph` and
|
| 349 |
`sample_global` injection.
|
| 350 |
2. Dataset items `(DGLGraph, label, tracking, global_features)`.
|
docs/migration.md
CHANGED
|
@@ -86,8 +86,24 @@ padding. Compare against `RootDataset.save/load`, `LazyDataset`, and
|
|
| 86 |
Treat `NONE`, `STEPS`, `FIXED`, and `NODE` as explicit features; do not hide
|
| 87 |
the hardcoded fixed padding sizes.
|
| 88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
## Phase 4 — active model parity
|
| 90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
Port `models.GCN.Edge_Network` first. Preserve constructor parameters,
|
| 92 |
`forward(graph, global_feats)`, feature keys, processor order, MLP LayerNorm
|
| 93 |
placement, and logits shape. Compare intermediate and final tensors on fixed
|
|
@@ -117,6 +133,19 @@ classes only with dedicated tests; do not substitute their reductions.
|
|
| 117 |
|
| 118 |
## Phase 6 — checkpoint and lifecycle
|
| 119 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
Create a checkpoint adapter preserving `model_epoch_<epoch>.pt` and keys
|
| 121 |
`epoch`, `model_state_dict`, `optimizer_state_dict`, and `early_stop`
|
| 122 |
([`training_script.py:565-604`](../legacy/root_gnn_dgl/scripts/training_script.py)).
|
|
@@ -130,12 +159,22 @@ resume, restart, early termination, and `.npz` fields before distributed work.
|
|
| 130 |
|
| 131 |
## Phase 7 — CLI, inference, and export
|
| 132 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
Build thin new applications around tested library interfaces in this order:
|
| 134 |
|
| 135 |
1. preprocessing/cache generation (`scripts/prep_data.py`);
|
| 136 |
2. training/evaluation (`scripts/training_script.py`);
|
| 137 |
3. inference to `.npz` and ROOT (`scripts/inference.py`);
|
| 138 |
-
4. ONNX export after PyTorch parity (`
|
| 139 |
|
| 140 |
Use subprocess integration tests with tiny fixtures. Preserve CLI options only
|
| 141 |
where they serve an active workflow; document removed diagnostic/cluster-only
|
|
@@ -143,20 +182,107 @@ options.
|
|
| 143 |
|
| 144 |
## Phase 8 — reproducibility and deployment
|
| 145 |
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
|
| 151 |
## Checkpoint compatibility checklist
|
| 152 |
|
| 153 |
-
- [
|
| 154 |
-
- [
|
| 155 |
-
- [
|
| 156 |
-
- [
|
| 157 |
-
- [
|
| 158 |
-
- [
|
| 159 |
|
| 160 |
Known risks are documented in [`architecture.md`](architecture.md): edge order,
|
| 161 |
self-loops, weight semantics, validation/test naming, padding, dynamic
|
| 162 |
selection evaluation, reproducibility, and the experimental model/loss surface.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
Treat `NONE`, `STEPS`, `FIXED`, and `NODE` as explicit features; do not hide
|
| 87 |
the hardcoded fixed padding sizes.
|
| 88 |
|
| 89 |
+
Task 7 establishes the metadata-aware orchestration boundary around this
|
| 90 |
+
phase: `EventMetadata`, `GraphSample`, `GraphBatch`, fold-based split
|
| 91 |
+
selection, deterministic batching, and a version-checked graph-sample cache.
|
| 92 |
+
The cache is deliberately Level 2; normalized event caching remains a future
|
| 93 |
+
extension so non-graph model families can reuse ROOT preprocessing.
|
| 94 |
+
|
| 95 |
## Phase 4 — active model parity
|
| 96 |
|
| 97 |
+
Task 8 adds the active `EdgeNetwork` and `FineTunedEdgeNetwork` under
|
| 98 |
+
`gnn4colliders.models.root_gnn`. The update order and MLP ordering follow the
|
| 99 |
+
legacy active path. The rewrite uses an explicit backbone/classifier boundary,
|
| 100 |
+
local DGL graph scope, and does not mutate global RNG state in constructors.
|
| 101 |
+
Model parity now covers fixed-weight pretraining and transfer paths, including
|
| 102 |
+
historical checkpoint prefixes. The legacy transfer implementation has an
|
| 103 |
+
active bug when nonempty globals are supplied (`Pretrained_Output` ignores its
|
| 104 |
+
argument); parity therefore characterizes its supported no-global path, while
|
| 105 |
+
the rewritten model supports both global and fallback modes.
|
| 106 |
+
|
| 107 |
Port `models.GCN.Edge_Network` first. Preserve constructor parameters,
|
| 108 |
`forward(graph, global_feats)`, feature keys, processor order, MLP LayerNorm
|
| 109 |
placement, and logits shape. Compare intermediate and final tensors on fixed
|
|
|
|
| 133 |
|
| 134 |
## Phase 6 — checkpoint and lifecycle
|
| 135 |
|
| 136 |
+
Task 10 implemented the in-memory single-process training lifecycle before the
|
| 137 |
+
checkpoint portion of this phase: `Trainer`, explicit optimizer/scheduler
|
| 138 |
+
builders, `EarlyStopping`, reproducibility seeding, `GraphBatch.to`, and
|
| 139 |
+
epoch/history result types. Checkpoint persistence/resume and the Python
|
| 140 |
+
inference/evaluation and named NPZ/ROOT output layers are now implemented.
|
| 141 |
+
Distributed execution and CLI wiring were completed in the later phases.
|
| 142 |
+
|
| 143 |
+
Task 10 also establishes corrected split semantics: validation is evaluated
|
| 144 |
+
every epoch and is the only split used for model selection or early stopping;
|
| 145 |
+
the test split remains held out and is evaluated separately after fitting. The
|
| 146 |
+
legacy loader naming inversion (`test` used for selection and `val` held out)
|
| 147 |
+
is not carried into the rewrite.
|
| 148 |
+
|
| 149 |
Create a checkpoint adapter preserving `model_epoch_<epoch>.pt` and keys
|
| 150 |
`epoch`, `model_state_dict`, `optimizer_state_dict`, and `early_stop`
|
| 151 |
([`training_script.py:565-604`](../legacy/root_gnn_dgl/scripts/training_script.py)).
|
|
|
|
| 159 |
|
| 160 |
## Phase 7 — CLI, inference, and export
|
| 161 |
|
| 162 |
+
Task 12 implemented ordered prediction/evaluation, task-owned score
|
| 163 |
+
semantics, checkpoint weight-only loading, named metadata retention, NPZ
|
| 164 |
+
output, and explicit ROOT entry alignment. The semantic CLI and the validated
|
| 165 |
+
ROOT-GNN ONNX export adapter are implemented.
|
| 166 |
+
|
| 167 |
+
Task 13 adds Hydra composition and a single-process CLI around those existing
|
| 168 |
+
APIs. The current application data boundary is a versioned
|
| 169 |
+
`GraphSampleCache`; ROOT preparation converts events through the shared
|
| 170 |
+
feature and graph builders before writing that cache.
|
| 171 |
+
|
| 172 |
Build thin new applications around tested library interfaces in this order:
|
| 173 |
|
| 174 |
1. preprocessing/cache generation (`scripts/prep_data.py`);
|
| 175 |
2. training/evaluation (`scripts/training_script.py`);
|
| 176 |
3. inference to `.npz` and ROOT (`scripts/inference.py`);
|
| 177 |
+
4. ONNX export after PyTorch parity (`gnn4colliders export`).
|
| 178 |
|
| 179 |
Use subprocess integration tests with tiny fixtures. Preserve CLI options only
|
| 180 |
where they serve an active workflow; document removed diagnostic/cluster-only
|
|
|
|
| 182 |
|
| 183 |
## Phase 8 — reproducibility and deployment
|
| 184 |
|
| 185 |
+
Task 14 adds the initial deployment boundary: CPU/GPU DDP through standard
|
| 186 |
+
`torchrun` variables, rank-local graph-sample sharding, global metric/output
|
| 187 |
+
gathering, rank-0 checkpoint/config writing, and Perlmutter-oriented Slurm
|
| 188 |
+
examples. Evaluation deliberately avoids sampler padding duplicates. The
|
| 189 |
+
remaining follow-up is a streaming or sharded output path for very large
|
| 190 |
+
distributed inference jobs.
|
| 191 |
+
|
| 192 |
+
The seed policy remains explicit: the configured seed is offset by rank for
|
| 193 |
+
process-local randomness, while distributed sample assignment is derived from
|
| 194 |
+
the configured seed, world size, and epoch. GPU kernel nondeterminism and
|
| 195 |
+
exact per-rank RNG checkpoint replay remain environment-dependent. Slurm/NCCL,
|
| 196 |
+
Podman-HPC, ROOT, and Hugging Face integrations stay in launcher/adapters
|
| 197 |
+
rather than package code.
|
| 198 |
|
| 199 |
## Checkpoint compatibility checklist
|
| 200 |
|
| 201 |
+
- [x] Load a checked-in or generated multiclass pretrained checkpoint.
|
| 202 |
+
- [x] Load a legacy fine-tuning checkpoint after prefix normalization.
|
| 203 |
+
- [x] Resume optimizer and early-stop state.
|
| 204 |
+
- [x] Produce equivalent logits on a deterministic graph fixture.
|
| 205 |
+
- [x] Produce equivalent `.npz` score, label, and metadata fields.
|
| 206 |
+
- [x] Preserve ROOT scalar/vector score branch conventions in the Python adapter.
|
| 207 |
|
| 208 |
Known risks are documented in [`architecture.md`](architecture.md): edge order,
|
| 209 |
self-loops, weight semantics, validation/test naming, padding, dynamic
|
| 210 |
selection evaluation, reproducibility, and the experimental model/loss surface.
|
| 211 |
+
|
| 212 |
+
## Migration closure status
|
| 213 |
+
|
| 214 |
+
### Task 18 compatibility closure
|
| 215 |
+
|
| 216 |
+
The compatibility boundary is now explicit in `gnn4colliders.compat`.
|
| 217 |
+
Production ingestion stores named `EventMetadata`; legacy two-column tracking
|
| 218 |
+
is converted only at the compatibility boundary. Checkpoint prefix cleanup and
|
| 219 |
+
the historical ROOT-GNN `classify` to `classifier` mapping have one canonical
|
| 220 |
+
implementation. The new checkpoint schema and named NPZ output remain
|
| 221 |
+
canonical. See [`compatibility.md`](compatibility.md) for the supported and
|
| 222 |
+
intentionally unsupported historical artifacts.
|
| 223 |
+
|
| 224 |
+
The following matrix describes the supported new stack, rather than every
|
| 225 |
+
class that exists in `legacy/`:
|
| 226 |
+
|
| 227 |
+
| Legacy area | New-stack status | Notes |
|
| 228 |
+
| --- | --- | --- |
|
| 229 |
+
| ROOT/Awkward ingestion | migrated | `RootEventDataset` returns `EventSample` in file/event order |
|
| 230 |
+
| node features | migrated + parity-tested | seven-column schema, `CALC_E`, ordering, scales, float32 |
|
| 231 |
+
| edge construction | migrated + parity-tested | directed source-major topology and `[deta,dphi,dR]` |
|
| 232 |
+
| graph cache | migrated | versioned `GraphSampleCache`; graph-level cache only |
|
| 233 |
+
| folds and weights | migrated | named `EventMetadata.fold` and `.weight` |
|
| 234 |
+
| batching | migrated | deterministic local loader and DDP sharding |
|
| 235 |
+
| legacy padding modes | deferred | no active new-stack consumer |
|
| 236 |
+
| `Edge_Network` | migrated + parity-tested | `EdgeNetwork`, raw logits |
|
| 237 |
+
| transfer/fine-tuning | migrated + parity-tested | frozen or trainable backbone |
|
| 238 |
+
| loss and metrics | migrated + parity-tested | task-owned weighted reductions and full-split AUC |
|
| 239 |
+
| training lifecycle | migrated | `Trainer`, validation semantics, scheduler, early stopping |
|
| 240 |
+
| checkpoints/resume | migrated | schema v1; historical weight/prefix adapter |
|
| 241 |
+
| inference/NPZ | migrated | named output fields and ordered accumulation |
|
| 242 |
+
| ROOT score output | compatibility adapter | Python API supported; CLI currently NPZ-only |
|
| 243 |
+
| DDP | migrated | torchrun boundary, rank-0 artifacts, gathered metrics |
|
| 244 |
+
| Slurm/Perlmutter | launcher examples | site policy remains outside package code |
|
| 245 |
+
| ONNX export | migrated for ROOT-GNN | tensor-only adapter, ONNX Runtime validation, and `export` CLI; raw graph tensors are the input contract |
|
| 246 |
+
|
| 247 |
+
### Intentional redesigns
|
| 248 |
+
|
| 249 |
+
These are deliberate new-stack contracts, not accidental parity failures:
|
| 250 |
+
|
| 251 |
+
* `tracking[:, 0]` and `tracking[:, 1]` become named `metadata.fold` and
|
| 252 |
+
`metadata.weight`; public consumers do not depend on positional columns.
|
| 253 |
+
* Dynamic legacy YAML `module`/`class` construction becomes allow-listed
|
| 254 |
+
semantic Hydra configuration.
|
| 255 |
+
* The monolithic training script becomes `Task` + `Trainer` + checkpoint and
|
| 256 |
+
inference adapters.
|
| 257 |
+
* Graph state is scoped to the forward pass rather than relying on persistent
|
| 258 |
+
mutation of shared graph state.
|
| 259 |
+
* Model constructors do not mutate global RNG state; seeding is explicit in
|
| 260 |
+
the training/application boundary.
|
| 261 |
+
* Validation is the selection/early-stopping split and test is held out. This
|
| 262 |
+
corrects the legacy loader-name inversion.
|
| 263 |
+
|
| 264 |
+
Compatibility preserves externally observable scientific behavior where it is
|
| 265 |
+
validated; it does not promise to preserve every legacy implementation bug.
|
| 266 |
+
The characterized legacy transfer path had a nonempty-global handling bug;
|
| 267 |
+
the rewrite supports named globals. Negative weights, rare empty graphs,
|
| 268 |
+
historical checkpoint variants, and legacy padding edge cases remain areas to
|
| 269 |
+
audit when a supported consumer requires them.
|
| 270 |
+
|
| 271 |
+
## ROOT-GNN v1 completion checklist
|
| 272 |
+
|
| 273 |
+
- [x] active ROOT data path and graph cache
|
| 274 |
+
- [x] validated feature, graph, model, task, and metric behavior
|
| 275 |
+
- [x] train from scratch and fine-tune a pretrained backbone
|
| 276 |
+
- [x] resume new-stack checkpoints and load supported historical weights
|
| 277 |
+
- [x] evaluate and predict named outputs
|
| 278 |
+
- [x] single-process and DDP application boundaries
|
| 279 |
+
- [x] Perlmutter/Slurm launcher examples and profiling guidance
|
| 280 |
+
- [x] ROOT-GNN ONNX export and CPU Runtime parity
|
| 281 |
+
- [ ] streaming/sharded large-scale prediction output
|
| 282 |
+
- [ ] removal of frozen legacy reference
|
| 283 |
+
- [ ] ROOT-Transformer representation/model
|
| 284 |
+
|
| 285 |
+
ROOT-GNN v1 is complete when the checked-in new stack can prepare active data,
|
| 286 |
+
reproduce validated legacy behavior, train, transfer, resume, evaluate,
|
| 287 |
+
predict, and run single-process or DDP workflows. The remaining unchecked
|
| 288 |
+
items are intentionally deferred rather than undocumented promises.
|