diff --git a/AGENTS.md b/AGENTS.md index 9182e1d7d3304edd3c50f247a381bcde1ebb66a8..a79b6287885e190b2df736816843cee4469c3b8d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,13 +31,12 @@ docs/migration.md and the relevant existing source and tests. -The `legacy/` tree is a behavioral reference for the rewrite. +The `root-gnn-parity-baseline` tag and committed reference fixtures preserve +the behavioral baseline for the rewrite. Historical implementation code is +not part of the active source tree. -Unless explicitly instructed otherwise: - -* do not modify legacy code -* do not reorganize legacy code -* do not mechanically copy legacy architecture into the new package +Do not reintroduce historical implementation code or imports into the active +package. Preserve compatibility through explicit fixtures and adapters. When legacy behavior and documentation disagree, identify the discrepancy rather than silently choosing one. @@ -195,7 +194,7 @@ Do not attempt to rewrite the entire legacy repository in one task. For substantial migrations: -1. inspect the relevant legacy implementation +1. inspect the relevant reference fixture and compatibility contract 2. identify externally observable behavior 3. inspect existing characterization/parity tests 4. state or infer the intended new interface diff --git a/README_PROJECT.md b/README_PROJECT.md index b37f9c8c9be992a45ae9a58d4afb6dc528c773cd..69fbee39331c910702663a6a4e885bcc5d3f7235 100644 --- a/README_PROJECT.md +++ b/README_PROJECT.md @@ -14,8 +14,10 @@ ROOT files -> EventSample -> shared collider features ``` The new implementation lives under [`src/gnn4colliders`](src/gnn4colliders/). -[`legacy/`](legacy/) is a frozen behavioral reference for parity work and -historical checkpoint investigation, not a supported runtime backend. +Historical behavior is preserved by the +[`root-gnn-parity-baseline`](https://huggingface.co/HWresearch/GNN4Colliders/tree/root-gnn-parity-baseline) +tag and committed reference fixtures, not by a supported historical runtime +backend. ## Installation @@ -31,13 +33,13 @@ uv sync --dev --extra root-gnn ``` The core package can be installed without DGL when only shared data or task -code is needed. ROOT-GNN models, graph construction, and ROOT-GNN parity tests +code is needed. ROOT-GNN models, graph construction, and ROOT-GNN reference tests require the `root-gnn` extra. On Linux x86_64, it uses the validated CUDA 12.1 wheels configured in `pyproject.toml`; a compatible NVIDIA driver is still required. On Apple Silicon macOS, it installs the CPU DGL wheel, supporting local graph/cache development. The default ROOT-GNN backend performs training with native PyTorch graph tensors, so it runs on Apple MPS, NVIDIA CUDA, and -CPU; DGL remains a cache and legacy-compatibility adapter. Do not add +CPU; DGL remains a cache and graph compatibility adapter. Do not add site-specific CUDA, Slurm, or filesystem paths to model or task configuration. Use the MPS profile on an Apple Silicon Mac: diff --git a/docs/agent-workflows/gnn4colliders-workflow.md b/docs/agent-workflows/gnn4colliders-workflow.md index bd756a8365eae6c6a5345fb9e0448404714fa8ba..5e005bc4b39295c76eada63ef4f87712abe057bb 100644 --- a/docs/agent-workflows/gnn4colliders-workflow.md +++ b/docs/agent-workflows/gnn4colliders-workflow.md @@ -15,8 +15,9 @@ docs/migration.md Production Python belongs under `src/gnn4colliders/`. Keep collider physics features in `features/`, graph topology in `graphs/`, architecture code in -`models/`, and lifecycle code in `training/`. Do not modify `legacy/`; use it -as a behavioral reference for parity work. +`models/`, and lifecycle code in `training/`. Use the frozen parity fixtures +and compatibility adapters for historical behavior; do not add historical +implementation imports. ## Environment diff --git a/docs/architecture.md b/docs/architecture.md index b88fc7902824c7e1a11ca1d45eca7ac25f81a50e..32871b9e7e88f5e08b8c8080f8aa2736306a2197 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,378 +1,86 @@ # GNN4Colliders architecture -## Current v1 architecture +## Current architecture -The supported rewrite is layered around an architecture-neutral event boundary: +GNN4Colliders is organized around an architecture-neutral event boundary: ```text ROOT/Awkward ↓ EventSample + EventMetadata ↓ -shared collider feature construction - ├── GraphSample -> versioned graph cache -> GraphBatch - └── future SequenceSample -> ROOT-Transformer (not implemented) - ↓ - ROOT-GNN EdgeNetwork - ↓ - raw logits -> Task - ├── loss - ├── predictions - └── full-split metrics - ↓ - Trainer / Predictor / outputs +shared features and representation adapters + ├── GraphSample -> GraphSampleCache -> GraphBatch + └── future SequenceSample -> transformer/token models + ↓ +model family + ↓ +Task -> Trainer/Predictor -> named outputs ``` | Layer | Responsibility | -| --- | --- | -| `data` | ROOT/Awkward ingestion, event samples, metadata, graph caches, folds, and batching | -| `features` | Shared collider-object features and derived physics quantities | -| `graphs` | Topology, edge features, and the DGL representation adapter | -| `models/root_gnn` | ROOT-GNN encoders, portable tensor message passing, classifier, and transfer boundary | -| `tasks` | Loss, score/prediction, labels, weights, and metrics | -| `training` | Optimizer lifecycle, validation, early stopping, checkpointing, and reproducibility | -| `inference` | Ordered prediction/evaluation and NPZ/ROOT output adapters | -| `distributed` | Rank-local devices, sharding, DDP, and cross-rank collection | -| `config` / `cli` | Semantic Hydra composition and thin user-facing commands | - -`EventSample` is shared infrastructure, not a ROOT-GNN object. `GraphSample` -is the current representation-specific adapter. At batching, the default -ROOT-GNN backend converts cached DGL graphs into `TensorGraph` values with -explicit node/edge indices and graph membership. Native message passing then -uses only PyTorch tensor operations, allowing the same model to train on CPU, -CUDA, and Apple MPS. This separation is the extension point for a future -sequence/token representation. - -The new public metadata contract is named `EventMetadata(fold, weight, -sample_id, extra)`. The legacy positional tracking tensor is accepted only by -compatibility-facing ingestion code. A `GraphSampleCache` is deliberately a -Level-2 graph cache; replacing it with a universal cache would couple future -model families to DGL. - -For deployment, a prepared `GraphBatch` can pass through the isolated -`RootGNNExportAdapter` into an ONNX model. ONNX is still an inference boundary: -it does not read ROOT or construct collider features. - -## Current public workflow - -`prepare` reads ROOT through `RootEventDataset`, builds shared features and -DGL graphs, and saves a schema-checked cache. `train` creates a model/task and -`Trainer`; validation is the model-selection split and test is held out. -`evaluate` computes metrics after collecting the complete split. `predict` -returns detached CPU tensors in loader order and writes named NPZ fields. -`write_root_scores` is an optional Python adapter with explicit entry alignment; -the CLI currently exposes NPZ output. - -Compatibility responsibilities are isolated in `gnn4colliders.compat`. -Supported historical checkpoint prefixes, classifier names, and the two-column -tracking conversion are listed in [`compatibility.md`](compatibility.md). -The modern pipeline does not propagate positional tracking or historical NPZ -fields. - -Checkpoints are independent of the model implementation: they carry model and -task metadata, lifecycle state, schema versions, and optional RNG state. -Prefix normalization supports DDP `module.` and compiled `_orig_mod.` weights, -plus the active ROOT-GNN historical classifier-name compatibility path. - ---- - -## Historical behavioral reference - -This document covers the target system in `legacy/root_gnn_dgl/`. The sibling -`legacy/physicsnemo/` tree is a prior rewrite attempt and is not a behavioral -target. - -## 1. High-level system description - -The active rewrite exposes `gnn4colliders.models.root_gnn.EdgeNetwork`. Its -encoders and message-passing blocks form a reusable backbone whose decoded -graph representation is passed to an explicit classifier. `FineTunedEdgeNetwork` -reuses that backbone and replaces only the task-specific classifier, with -explicit frozen or trainable-backbone control. - -`root_gnn_dgl` is a ROOT-to-DGL graph classification system. YAML selects -dataset, model, loss, and finish-function classes by import path. The dataset -reads ROOT trees, converts collider objects to fully connected DGL graphs, and -saves graph chunks. Training loads those chunks, applies fold selection and -optional pre-batching/padding, trains a graph network, writes one PyTorch -checkpoint per epoch, and reports weighted loss, accuracy, and ROC AUC. - -The primary model is `models.GCN.Edge_Network` ([`GCN.py:182-251`](../legacy/root_gnn_dgl/models/GCN.py)). -It encodes node, edge, and global features, repeats edge -> node -> global -message passing `n_proc_steps` times, decodes the global state, and applies -`classify`. Fine-tuning uses `models.GCN.Transferred_Learning_Finetuning` -([`GCN.py:884-997`](../legacy/root_gnn_dgl/models/GCN.py)), which loads a -pretrained `Edge_Network`, removes its final classifier, and applies a new one. -The active configs use output size 12 for multiclass pretraining and output -size 1 for binary tasks ([`configs/stats_100K/pretraining_multiclass.yaml:1-45`](../legacy/root_gnn_dgl/configs/stats_100K/pretraining_multiclass.yaml), -[`configs/stats_100K/finetuning_ttH_CP_even_vs_odd.yaml:1-45`](../legacy/root_gnn_dgl/configs/stats_100K/finetuning_ttH_CP_even_vs_odd.yaml)). - -### Entry points and flows - -- `scripts/training_script.py:main` and its CLI parser load YAML, create - loaders, construct the model, and call `train`; `--evaluate` calls - `evaluate` ([`training_script.py:638-843`](../legacy/root_gnn_dgl/scripts/training_script.py)). -- `scripts/prep_data.py:main` creates configured graph caches - ([`prep_data.py:68-110`](../legacy/root_gnn_dgl/scripts/prep_data.py)). -- `scripts/inference.py:main` reconstructs an unlazy dataset, loads one or - more checkpoints, and writes `.npz` or ROOT scores - ([`inference.py:163-387`](../legacy/root_gnn_dgl/scripts/inference.py)). -- `scripts/export_onnx.py:main` exports an ONNX-friendly model - ([`export_onnx.py:979-1035`](../legacy/root_gnn_dgl/scripts/export_onnx.py)). -- `selections.py:main`, `check_dataset_files.py:main`, and - `plot_config_distributions.py:main` are diagnostic entry points. `run_demo.sh` - sequences pretraining, binary training, fine-tuning, and inference - ([`run_demo.sh:3-59`](../legacy/root_gnn_dgl/run_demo.sh)). - -The training flow is: - -```text -YAML -> load_config/buildFromConfig -> RootDataset/LazyDataset - -> ROOT/Awkward -> DGL graph + labels/tracking/globals -> .bin cache - -> fold_selection -> prebatch/padding -> GraphDataLoader - -> Edge_Network or transfer model -> weighted loss/metrics - -> model_epoch_N.pt, logs, evaluation/inference output -``` - -`training_script.train` is the lifecycle implementation -([`training_script.py:143-614`](../legacy/root_gnn_dgl/scripts/training_script.py)); -distributed paths use NCCL/DDP ([`training_script.py:616-839`](../legacy/root_gnn_dgl/scripts/training_script.py)). -Inference uses `CustomPreBatchedDataset`, applies a configured finish function, -and collects `scores`, `labels`, and `tracking_info` -([`inference.py:20-76`](../legacy/root_gnn_dgl/scripts/inference.py), -[`inference.py:223-325`](../legacy/root_gnn_dgl/scripts/inference.py)). - -## 2. Dependency and data-flow map +|---|---| +| `data` | ROOT/Awkward ingestion, metadata, datasets, folds, batching, and caches | +| `features` | Collider-object features and derived physics quantities | +| `graphs` | Topology, edge construction, and graph-specific adapters | +| `models` | Architecture-specific neural networks | +| `tasks` | Labels, weights, losses, scores, predictions, and metrics | +| `training` | Optimizers, lifecycle, reproducibility, checkpointing, and distributed utilities | +| `inference` | Ordered prediction, evaluation, and named output writing | +| `cli` / `config` | Thin semantic entry points and configuration composition | + +Production code must depend on these package boundaries rather than on +historical implementation paths. The canonical ROOT-GNN implementation is +`gnn4colliders.models.root_gnn.EdgeNetwork` with +`FineTunedEdgeNetwork` as its transfer boundary. New architecture families +must reuse shared data, feature, task, training, and inference interfaces where +their representation permits it. + +## Data and representation boundaries + +`EventSample` and named `EventMetadata(fold, weight, sample_id, extra)` are +representation-independent. `GraphSample` and `GraphBatch` are the current +graph representation boundary. `TensorGraph` provides a native tensor path +for ROOT-GNN execution on CPU, CUDA, and MPS; DGL remains an optional graph +adapter and cache dependency. + +The active collider node schema has seven columns: +`[pt, eta, phi, energy, btag, charge, node_type]`. Graph edges are directed, +source-major, fully connected without self-loops except for the one-node +case, and carry `[deta, dphi, dR]` features. These are compatibility contracts +captured by deterministic tests and the frozen `root-gnn-parity-baseline` +reference fixture. + +## Configuration and lifecycle + +Experiments use semantic configuration such as `model.type: root_gnn`; model +module paths are not part of the new public configuration contract. The CLI +delegates to tested application factories and does not contain model or data +processing logic. + +Checkpoints carry model/task metadata, lifecycle state, schema versions, and +optional RNG state. The compatibility package accepts historical checkpoint +prefixes and classifier names as a one-way input adapter. No executable +historical model code is required at runtime. + +## Extending the model families + +The next model family should introduce only its representation-specific +boundary and model implementation, for example: ```text -ROOT files (raw_dir/file_names, tree_name) - -> gnn4colliders.data.RootEventDataset (Uproot/Awkward) - -> node feature construction (dataset.py:15-50) - -> full_connected_graph (dataset.py:52-59) - -> EdgeDataset.make_graph: [deta, dphi, dR] (dataset.py:471-482) - -> DGL .bin cache / LazyDataset / PreBatchedDataset - -> GraphDataLoader -> models.GCN -> loss/metrics -> outputs +data.EventSample -> features -> SequenceSample -> models.root_transformer ``` -`RootDataset` provides `process`, `save`, `load`, `__getitem__`, and `__len__` -([`dataset.py:160-469`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)); -`LazyDataset` loads one chunk through a ring buffer -([`dataset.py:525-578`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)); -`PreBatchedDataset.process` selects, shuffles, batches, pads, and caches -([`batched_dataset.py:34-146`](../legacy/root_gnn_dgl/root_gnn_base/batched_dataset.py)). - -`load_config` uses PyYAML `FullLoader` and shallow `include` merging, while -`buildFromConfig` dynamically imports `module`, resolves `class`, merges extra -keys into `args`, converts list-valued weights to tensors, and injects runtime -arguments ([`utils.py:10-43`](../legacy/root_gnn_dgl/root_gnn_base/utils.py)). -This reflection shape is a de facto interface for configured components. - -### Data and preprocessing - -The active node schema is seven columns: `pt`, `eta`, `phi`, `energy`, `btag`, -`charge`, and `node_type`. `CALC_E` is `pt*cosh(eta)`, constants are broadcast -per object type, `NODE_TYPE` is an integer type code, and feature scales are -applied columnwise ([`dataset.py:15-50`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)). -`full_connected_graph` makes directed all-pairs edges; `EdgeDataset` requests -no self-loops and stores `[deta, dphi, dR]` -([`dataset.py:52-59`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py), -[`dataset.py:471-482`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)). - -Selections are strings evaluated with builtins disabled or -`(variable, cut, operator)` triples (`check_selection`, `selection_mask`; -[`dataset.py:75-145`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)). Fold -selection uses `tracking[:,0] % n_folds`; tracking column 0 is fold and column 1 -is weight ([`utils.py:121-143`](../legacy/root_gnn_dgl/root_gnn_base/utils.py), -[`dataset.py:176-182`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)). -`hash_partition` and a seeded Torch generator control pre-batch order -([`batched_dataset.py:27-99`](../legacy/root_gnn_dgl/root_gnn_base/batched_dataset.py)). -Padding modes are `NONE`, `STEPS`, `FIXED`, and `NODE`; `FIXED` is hardcoded to -16,000 nodes and 104,000 edges ([`batched_dataset.py:100-125`](../legacy/root_gnn_dgl/root_gnn_base/batched_dataset.py)). - -### Model, losses, and metrics - -`Make_MLP` builds linear/ReLU/dropout blocks followed by LayerNorm -([`GCN.py:18-35`](../legacy/root_gnn_dgl/models/GCN.py)). Each `Edge_Network` -step encodes inputs, copies source/destination states to edges, updates edges, -sums edge messages into nodes, updates nodes, then mean-pools nodes/edges to -update globals ([`GCN.py:195-249`](../legacy/root_gnn_dgl/models/GCN.py)). It -returns logits `[graphs, out_size]` without sigmoid/softmax. - -The default objective is elementwise `BCEWithLogitsLoss`, multiplied by -`tracking[:,1]`, averaged separately per unique label, then averaged across -labels ([`training_script.py:143-185`](../legacy/root_gnn_dgl/scripts/training_script.py), -[`training_script.py:320-359`](../legacy/root_gnn_dgl/scripts/training_script.py)). -`--abs` makes weights positive. Binary metrics use sigmoid threshold 0.5 and -weighted ROC AUC; multiclass metrics use argmax and one-vs-rest ROC AUC -([`training_script.py:438-510`](../legacy/root_gnn_dgl/scripts/training_script.py)). -Additional configurable losses/finishers live in `models/loss.py` -([`loss.py:6-310`](../legacy/root_gnn_dgl/models/loss.py)). - -### Checkpoints and outputs - -Training writes `Training_Directory/model_epoch_.pt` containing `epoch`, -`model_state_dict`, `optimizer_state_dict`, and serialized `early_stop` -([`training_script.py:565-604`](../legacy/root_gnn_dgl/scripts/training_script.py)). -Keys strip `module.` and compiled models save the underlying `_orig_mod` state; -`get_last_epoch`, `get_specific_epoch`, and `get_best_epoch` load the files -([`utils.py:145-248`](../legacy/root_gnn_dgl/root_gnn_base/utils.py)). -`evaluate` writes `evaluation_.npz`; inference writes `.npz` fields -`scores`, `labels`, `tracking_info`, or adds score branches and `selection_pass` -to a cloned ROOT tree ([`training_script.py:57-140`](../legacy/root_gnn_dgl/scripts/training_script.py), -[`inference.py:328-385`](../legacy/root_gnn_dgl/scripts/inference.py)). - -### Training lifecycle boundary - -The active rewrite keeps lifecycle orchestration architecture-independent: - -```text -GraphDataLoader -> GraphBatch -> Model -> Task -> Trainer - loss/metrics -``` - -`gnn4colliders.training.Trainer` owns device placement, train/evaluation mode, -gradient and optimizer steps, epoch aggregation, optional scheduler stepping, -early stopping, and in-memory history. Tasks own loss and metric semantics; -the trainer does not inspect positional tracking columns or collider-specific -features. Evaluation concatenates detached outputs across the complete split -before calling task metrics, so ROC AUC is not computed per mini-batch. - -Checkpoint persistence and the Python inference/output layer are implemented -as separate adapters. The semantic CLI and distributed application boundary -are implemented in the current stack. `gnn4colliders.inference.Predictor` accumulates detached CPU -logits, task-defined scores/predictions, labels, and named event metadata in -loader order; `write_npz` is the primary named-field format and ROOT score -writing is an optional alignment-aware adapter. - -The new lifecycle uses conventional split semantics. `train` updates model -parameters, `validation` is evaluated after every epoch and drives scheduler, -early-stopping, and later model selection, and `test` is held out. The trainer -does not accept a test loader in `fit`; callers evaluate the held-out test set -separately after training. This deliberately corrects the legacy convention -where a loader named `test` was used for model selection and `val` represented -held-out testing. - -## Distributed execution - -`gnn4colliders.distributed` contains the small DDP boundary used by the -application layer. `DistributedContext` reads the standard `torchrun` -environment (`RANK`, `LOCAL_RANK`, and `WORLD_SIZE`), selects the rank-local -device, and owns process-group cleanup. Graph samples are sharded before -batching; training may pad rank shards for equal step counts, while validation -and prediction use unpadded shards so events are not counted twice. - -The configured graph `batch_size` is per process. DDP wraps an otherwise -ordinary model after device placement, and checkpoint state is normalized to -the underlying model keys. Loss gradients are synchronized by DDP; epoch -metrics and evaluation outputs are gathered across ranks. Rank 0 writes -resolved configuration, checkpoints, and NPZ predictions. Moderate-size -prediction gathering is in-memory; streaming/sharded output is a future -extension. - - -## Randomness, external services, and coupling - -The CLI exposes `--seed`, but `main` passes it to model construction rather -than globally seeding Python, NumPy, or Torch -([`training_script.py:638-753`](../legacy/root_gnn_dgl/scripts/training_script.py)). -Pre-batching has explicit seeds, but `AugmentedDataset` mutates the process-wide -NumPy seed ([`dataset.py:716-827`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)), -clustering uses unseeded `torch.randperm`/`randint` (`loss.py:259-295`), and -model reset/fine-tuning hardcodes `torch.manual_seed(2)` -([`GCN.py:58-65`](../legacy/root_gnn_dgl/models/GCN.py), -[`GCN.py:900-915`](../legacy/root_gnn_dgl/models/GCN.py)). CUDA kernels, DDP, -and DataLoader behavior are not made deterministic. - -Implicit coupling includes repository-relative `sys.path` insertion -([`training_script.py:14-20`](../legacy/root_gnn_dgl/scripts/training_script.py)), -dynamic imports, mutable default lists/dicts, global `FEATURE_DTYPE` -([`dataset.py:13`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)), -in-place `tracking_info` mutation ([`dataset.py:176-181`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)), -and in-place DGL graph mutation during forward. - -The legacy environment assumes Python 3.8, PyTorch 2.0.1, CUDA 11.8, DGL -1.1.1, ROOT, Awkward, Uproot, PyYAML, and scikit-learn -([`setup/environment.yml:1-10`](../legacy/root_gnn_dgl/setup/environment.yml), -[`setup/environment.yml:240-295`](../legacy/root_gnn_dgl/setup/environment.yml)). -The active Linux development environment is intentionally separate: Python -3.12, PyTorch 2.2.2/CUDA 12.1, and DGL 2.4.0 from the official DGL wheel -repository. CUDA runtime wheels do not replace the compatible host NVIDIA -driver and do not encode Perlmutter module settings. -Standard configs assume `/global/cfs/` and `/pscratch/` paths, CUDA/NCCL, -Slurm, and optionally Podman-HPC. `setup/download_data.sh` downloads the -external Hugging Face dataset `HWresearch/Delphes` -([`download_data.sh:13-67`](../legacy/root_gnn_dgl/setup/download_data.sh)). - -## Apparent unused or secondary code - -Not selected by the standard stats/Delphes configs, or only reachable from -optional workflows, are `GCN_global`, `GCN_global_2way`, most transfer variants, -attention models, `MultiModel`, and `Clustering` -([`GCN.py:122-1933`](../legacy/root_gnn_dgl/models/GCN.py)); `UprootDataset`, -`tHbbEdgeDataset`, `AugmentedDataset`, and photon-ID paths -([`uproot_dataset.py:10-31`](../legacy/root_gnn_dgl/root_gnn_base/uproot_dataset.py), -[`dataset.py:484-827`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py), -[`photon_ID_dataset.py:1-33`](../legacy/root_gnn_dgl/root_gnn_base/photon_ID_dataset.py)); -optional loss and similarity utilities; and the no-op -`root_gnn_base.utils.graph_augmentation` ([`utils.py:393-395`](../legacy/root_gnn_dgl/root_gnn_base/utils.py)). -The main path evaluates `test_loaders`; validation loaders are only assembled -when a config has a validation fold ([`training_script.py:682-747`](../legacy/root_gnn_dgl/scripts/training_script.py)). - -## 3. De facto interfaces to preserve - -### Metadata-aware dataset boundary - -The rewrite uses named `EventMetadata` (`fold`, `weight`, and stable -`sample_id`) instead of exposing the legacy positional tracking tensor. -`GraphSample`, `GraphBatch`, `SplitDefinition`, and `GraphDataLoader` form the -ROOT-GNN orchestration boundary. Graph caches carry feature, graph, and cache -schema versions and reject incompatible artifacts before loading. - -The current cache implementation stores processed `GraphSample` values (the -Level-2 cache). The separation from `RootEventDataset` is intentional: a -future Level-1 cache can store normalized `EventSample`/feature data for -sequence or transformer representations without requiring DGL graph caches. - -The rewrite's shared data boundary is `gnn4colliders.data`: it reads selected -ROOT/Awkward branches and returns architecture-neutral event samples. Feature -construction and graph building remain separate downstream boundaries, so the -same samples can be reused by non-graph model families. - -### Configuration and CLI boundary - -Hydra composes semantic YAML groups under `configs/` and passes the resolved -configuration to explicit application factories in `gnn4colliders.config`. -Those factories allow-list supported models, tasks, and trainer components; -YAML is never treated as an arbitrary Python import specification. The thin -`gnn4colliders` CLI selects `prepare`, `train`, `evaluate`, or `predict` and -delegates to the stable data, training, checkpoint, and inference APIs. A new -experiment should generally be a YAML change; new behavior belongs in Python. - -1. YAML `module`, `class`, `args`, plus runtime `sample_graph` and - `sample_global` injection. -2. Dataset items `(DGLGraph, label, tracking, global_features)`. -3. `ndata['features']`, `edata['features']`, seven node columns, and three edge - columns in `[deta, dphi, dR]` order. -4. Tracking column 0 fold and column 1 weight semantics. -5. `model(graph, global_feats)`, logits shape `[batch, out_size]`, and - `representation` where used. -6. Weighted per-label loss, metric thresholds, checkpoint keys/prefix cleanup, - epoch filenames, and `.npz`/ROOT output fields. - -## 4. Ambiguous behavior - -- Historical edge order/self-loop expectations; empty and padding graph inputs. -- Whether negative weights are meaningful or should always be absolute. -- Whether “validation” is intended to differ from the active test-loader path. -- Shape semantics of multi-label finishers and experimental transfer classes. -- Whether chunk IDs must match historical `np.array_split` boundaries. -- Required behavior for missing branches and dynamic selection expressions. +It should include a deterministic fixture, unit tests for the representation, +an integration path through the shared task/trainer interfaces, and explicit +checkpoint/inference behavior. Shared infrastructure should be generalized +only when the second model demonstrates a real common use case. -## 5. Recommended rewrite boundaries +## Frozen baseline -Separate typed configuration; ROOT/Awkward I/O; selections/folds/features/ -edges; DGL cache/lazy loading/batching; active models and checkpoint adapters; -objectives/metrics; training lifecycle; and inference/ONNX applications. -Establish parity for the active `LazyDataset -> PreBatchedDataset -> -Edge_Network` binary/multiclass path first. Add experimental classes only when -a config or consumer proves they are required. +The complete ROOT-GNN parity campaign is recorded by the +`root-gnn-parity-baseline` tag. The historical implementation is no longer +part of the active source tree. Reference data and compatibility adapters are +kept so existing checkpoints and scientific observations remain usable while +development moves to new architectures. diff --git a/docs/compatibility.md b/docs/compatibility.md index d56c12e798248a17666e4528c5de08003eae4ba2..6848cb4e6312d0e4a8aa2d18329b132c79a4288f 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -18,5 +18,6 @@ adapted into the new representation and are never rewritten implicitly. | Historical `tracking_info` NPZ output | no | — | No active consumer remains; positional output is intentionally unsupported | | Legacy YAML `module`/`class`/`args` | compatibility only | configuration boundary | Accepted only where the semantic factory can safely interpret it; new configs use semantic model names | -The frozen `legacy/` tree remains available to parity tests and historical -investigation. Production modules do not import executable code from it. +The frozen parity fixtures and `root-gnn-parity-baseline` tag preserve the +historical observations for parity tests and investigation. Production modules +do not import executable historical model code. diff --git a/docs/end_to_end_validation.md b/docs/end_to_end_validation.md index 2b07297b087bafe5bf3fffc42e9357c8851c4d10..ef6ad17064569ae00d438d1868e059622b188e70 100644 --- a/docs/end_to_end_validation.md +++ b/docs/end_to_end_validation.md @@ -1,4 +1,4 @@ -# End-to-end legacy/rewrite validation +# End-to-end reference validation Task 21 compares staged event identity, labels, folds, weights, globals, node features, topology, edge features, batching, fixed-weight forward, loss and diff --git a/docs/migration.md b/docs/migration.md index 2d75c2751a875f86d73f2b35c504f3631aa768ce..3cacb78af9bca602f9d9e6c6c1f222f31cb096b5 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -1,312 +1,49 @@ -# Incremental migration plan: `root_gnn_dgl` - -The target is `legacy/root_gnn_dgl/`. `legacy/physicsnemo/` is a prior rewrite -attempt and may inspire abstractions, but it is not a parity target. Neither -legacy tree should be modified during migration. - -Each phase should add focused unit tests, a deterministic fixture in -`data/fixtures/`, and parity tests under `tests/parity/` before moving upward. -Record intentional differences and checkpoint consequences here. +# Migration and model-family roadmap ## Frozen ROOT-GNN baseline -The active ROOT-GNN rewrite and the legacy implementation are frozen at the -`root-gnn-parity-baseline` tag. The legacy tree is now a read-only behavioral -reference; new model development must not add production dependencies on it. -The completed no-selection ttH CP-even versus CP-odd campaign covered full -event preprocessing and graph parity, binary losses and metrics, one-step and -multi-epoch fine-tuning, full-split training, checkpoint reload and resume, -reproducibility, and chunked legacy `.bin` serialization. - -The next migration boundary is to replace live legacy imports in validation -workflows with frozen reference fixtures. Until that boundary is complete, -`legacy/` remains in the repository so the strict parity gate and historical -checkpoint investigations remain reproducible. New architecture families may -reuse shared data, features, tasks, training, and inference interfaces without -depending on ROOT-GNN or the legacy tree. - -## Phase 0 — freeze observations and fixtures - -Capture a small representative ROOT-equivalent fixture containing the seven -active node features, three edge features, labels, fold values, weights, and -globals. Record outputs of `node_features_from_tree`, `full_connected_graph`, -`EdgeDataset.make_graph`, and `fold_selection` -([`dataset.py:15-59`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py), -[`dataset.py:471-482`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py), -[`utils.py:121-143`](../legacy/root_gnn_dgl/root_gnn_base/utils.py)). Preserve -one `.bin`, one `model_epoch_N.pt`, one evaluation `.npz`, and one inference -`.npz` fixture if available. - -Task 3 characterization records the active-path observations. Node rows are -concatenated by object type in the configured order (jets, electrons, muons, -photons, MET), and the seven columns are `[pt, eta, phi, energy, btag, charge, -node_type]`. `CALC_E` is `pt*cosh(eta)` before the configured column scale is -applied. The graph is directed and uses all ordered pairs except self-loops -for graphs with more than one node; edge order is source-major. A one-node -graph is a special case: the no-self-loop branch retains its sole self-loop. -Edge columns are `[deta, dphi, dR]`, with `dphi` wrapped into `[-pi, pi]`. -Dataset items expose `(graph, label, tracking, global_features)`; tracking -column 0 is the fold identifier and column 1 is the event weight. These are -compatibility observations, not proposed fixes. - -## Phase 1 — configuration boundary - -Implement a typed configuration layer that reads `Training`, `Model`, -optional `Loss`, and `Datasets`. Initially retain a compatibility adapter for -`module`/`class`/`args` and runtime injection of `sample_graph` and -`sample_global`, matching `buildFromConfig` -([`utils.py:10-43`](../legacy/root_gnn_dgl/root_gnn_base/utils.py)). Keep -dynamic imports isolated at this boundary rather than spreading reflection -through new code. - -## Phase 2 — pure preprocessing parity - -Port and test, in isolation: - -- branch-to-node conversion, `CALC_E`, `NODE_TYPE`, constants, scaling, empty - objects, and dtypes (`node_features_from_tree`, - [`dataset.py:15-50`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)); -- string/tuple selections and cutflow (`check_selection`, `selection_mask`, - `compute_cutflow`, [`dataset.py:75-158`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)); -- fold masks and cache suffixes (`fold_selection`, `fold_selection_name`, - [`utils.py:121-143`](../legacy/root_gnn_dgl/root_gnn_base/utils.py)); -- deterministic chunk partitioning (`hash_partition`, - [`batched_dataset.py:27-31`](../legacy/root_gnn_dgl/root_gnn_base/batched_dataset.py)). - -This is the highest-value parity layer: model parity is invalid if graph inputs -differ. - -Task 4 implements the shared branch-to-node feature builder under -`gnn4colliders.features`. It preserves the active seven-column schema, -object-type ordering, explicit scales, derived `CALC_E`, node-type codes, -float32 output, and supported empty vector collections. Selection, fold, and -chunk helpers remain deferred to later data-infrastructure work. - -Task 6 implements the shared ROOT/Awkward ingestion boundary under -`gnn4colliders.data`. `RootEventDataset` returns immutable, architecture-neutral -`EventSample` values with selected branch data, labels, tracking, and globals; -events are ordered by input file order with a global zero-based index. Fold -filtering, caching, batching, and model-specific conversion remain deferred. - -## Phase 3 — graph construction and cache format - -Implement graph construction with tests for node/edge counts, directed edge -ordering, self-loop policy, `[deta, dphi, dR]` order, metadata, and empty graphs. -Preserve the dataset item contract `(graph, label, tracking, global_features)` -from `RootDataset.__getitem__` -([`dataset.py:465-469`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py)). - -Then implement DGL `.bin` serialization, lazy chunk loading, pre-batching, and -padding. Compare against `RootDataset.save/load`, `LazyDataset`, and -`PreBatchedDataset` ([`dataset.py:396-469`](../legacy/root_gnn_dgl/root_gnn_base/dataset.py), -[`batched_dataset.py:129-174`](../legacy/root_gnn_dgl/root_gnn_base/batched_dataset.py)). -Treat `NONE`, `STEPS`, `FIXED`, and `NODE` as explicit features; do not hide -the hardcoded fixed padding sizes. - -Task 7 establishes the metadata-aware orchestration boundary around this -phase: `EventMetadata`, `GraphSample`, `GraphBatch`, fold-based split -selection, deterministic batching, and a version-checked graph-sample cache. -The cache is deliberately Level 2; normalized event caching remains a future -extension so non-graph model families can reuse ROOT preprocessing. - -## Phase 4 — active model parity - -Task 8 adds the active `EdgeNetwork` and `FineTunedEdgeNetwork` under -`gnn4colliders.models.root_gnn`. The update order and MLP ordering follow the -legacy active path. The rewrite uses an explicit backbone/classifier boundary, -local DGL graph scope, and does not mutate global RNG state in constructors. -Model parity now covers fixed-weight pretraining and transfer paths, including -historical checkpoint prefixes. The legacy transfer implementation has an -active bug when nonempty globals are supplied (`Pretrained_Output` ignores its -argument); parity therefore characterizes its supported no-global path, while -the rewritten model supports both global and fallback modes. - -Task 22 adds `TensorEdgeNetwork`, a native PyTorch realization of the same -message-passing equations. It receives explicit node/edge index tensors from -the batching boundary, retains parameter names for legacy checkpoint loading, -and has fixed-weight CPU parity coverage against the DGL backend. It is the -default training backend for CPU, CUDA, and Apple MPS; DGL remains available as -a cache and compatibility adapter during the transition. - -Port `models.GCN.Edge_Network` first. Preserve constructor parameters, -`forward(graph, global_feats)`, feature keys, processor order, MLP LayerNorm -placement, and logits shape. Compare intermediate and final tensors on fixed -graphs using the legacy architecture -([`GCN.py:18-35`](../legacy/root_gnn_dgl/models/GCN.py), -[`GCN.py:182-251`](../legacy/root_gnn_dgl/models/GCN.py)). - -Next port `Transferred_Learning_Finetuning`, including pretrained -`model_state_dict` loading, removal of the final classifier, and new classifier -initialization ([`GCN.py:884-997`](../legacy/root_gnn_dgl/models/GCN.py)). Test -both frozen and unfrozen modes. Defer other model classes until an active -config or consumer proves they are needed. - -## Phase 5 — objectives and metrics - -Implement the default objective exactly: elementwise configured loss, -tracking-column weights, per-unique-label normalization, and averaging across -labels ([`training_script.py:320-359`](../legacy/root_gnn_dgl/scripts/training_script.py)). -Add parity cases for positive, zero, and negative weights and binary versus -multiclass shapes. - -Port metric behavior from -[`training_script.py:438-510`](../legacy/root_gnn_dgl/scripts/training_script.py): -sigmoid threshold 0.5, argmax, weight masking, weighted ROC AUC, one-vs-rest -multiclass AUC, and NaN behavior when AUC is undefined. Add `models/loss.py` -classes only with dedicated tests; do not substitute their reductions. - -## Phase 6 — checkpoint and lifecycle - -Task 10 implemented the in-memory single-process training lifecycle before the -checkpoint portion of this phase: `Trainer`, explicit optimizer/scheduler -builders, `EarlyStopping`, reproducibility seeding, `GraphBatch.to`, and -epoch/history result types. Checkpoint persistence/resume and the Python -inference/evaluation and named NPZ/ROOT output layers are now implemented. -Distributed execution and CLI wiring were completed in the later phases. - -Task 10 also establishes corrected split semantics: validation is evaluated -every epoch and is the only split used for model selection or early stopping; -the test split remains held out and is evaluated separately after fitting. The -legacy loader naming inversion (`test` used for selection and `val` held out) -is not carried into the rewrite. - -Create a checkpoint adapter preserving `model_epoch_.pt` and keys -`epoch`, `model_state_dict`, `optimizer_state_dict`, and `early_stop` -([`training_script.py:565-604`](../legacy/root_gnn_dgl/scripts/training_script.py)). -Support legacy DDP/compiled prefixes (`module.` and `_orig_mod.`) as exercised -by checkpoint lookup and inference -([`utils.py:145-248`](../legacy/root_gnn_dgl/root_gnn_base/utils.py), -[`inference.py:274-290`](../legacy/root_gnn_dgl/scripts/inference.py)). Port -`EarlyStop` state and log parsing separately -([`utils.py:325-390`](../legacy/root_gnn_dgl/root_gnn_base/utils.py)). Verify -resume, restart, early termination, and `.npz` fields before distributed work. - -## Phase 7 — CLI, inference, and export - -Task 12 implemented ordered prediction/evaluation, task-owned score -semantics, checkpoint weight-only loading, named metadata retention, NPZ -output, and explicit ROOT entry alignment. The semantic CLI and the validated -ROOT-GNN ONNX export adapter are implemented. - -Task 13 adds Hydra composition and a single-process CLI around those existing -APIs. The current application data boundary is a versioned -`GraphSampleCache`; ROOT preparation converts events through the shared -feature and graph builders before writing that cache. - -Build thin new applications around tested library interfaces in this order: - -1. preprocessing/cache generation (`scripts/prep_data.py`); -2. training/evaluation (`scripts/training_script.py`); -3. inference to `.npz` and ROOT (`scripts/inference.py`); -4. ONNX export after PyTorch parity (`gnn4colliders export`). - -Use subprocess integration tests with tiny fixtures. Preserve CLI options only -where they serve an active workflow; document removed diagnostic/cluster-only -options. - -## Phase 8 — reproducibility and deployment - -Task 14 adds the initial deployment boundary: CPU/GPU DDP through standard -`torchrun` variables, rank-local graph-sample sharding, global metric/output -gathering, rank-0 checkpoint/config writing, and Perlmutter-oriented Slurm -examples. Evaluation deliberately avoids sampler padding duplicates. The -remaining follow-up is a streaming or sharded output path for very large -distributed inference jobs. - -The seed policy remains explicit: the configured seed is offset by rank for -process-local randomness, while distributed sample assignment is derived from -the configured seed, world size, and epoch. GPU kernel nondeterminism and -exact per-rank RNG checkpoint replay remain environment-dependent. Slurm/NCCL, -Podman-HPC, ROOT, and Hugging Face integrations stay in launcher/adapters -rather than package code. - -## Checkpoint compatibility checklist - -- [x] Load a checked-in or generated multiclass pretrained checkpoint. -- [x] Load a legacy fine-tuning checkpoint after prefix normalization. -- [x] Resume optimizer and early-stop state. -- [x] Produce equivalent logits on a deterministic graph fixture. -- [x] Produce equivalent `.npz` score, label, and metadata fields. -- [x] Preserve ROOT scalar/vector score branch conventions in the Python adapter. - -Known risks are documented in [`architecture.md`](architecture.md): edge order, -self-loops, weight semantics, validation/test naming, padding, dynamic -selection evaluation, reproducibility, and the experimental model/loss surface. - -## Migration closure status +The `root-gnn-parity-baseline` tag records the completed migration of the +active ROOT-GNN behavior into `src/gnn4colliders.models.root_gnn`. The +campaign covered full event preprocessing and graph parity, binary objectives +and metrics, deterministic fine-tuning, full-split training, checkpoint reload +and resume, reproducibility, and serialized graph-cache checks. -### Task 18 compatibility closure +The historical implementation is no longer in the active source tree. Its +observable behavior is represented by committed fixtures, tests, and the +one-way checkpoint/metadata compatibility adapters. New work must not add +imports from historical implementation paths. -The compatibility boundary is now explicit in `gnn4colliders.compat`. -Production ingestion stores named `EventMetadata`; legacy two-column tracking -is converted only at the compatibility boundary. Checkpoint prefix cleanup and -the historical ROOT-GNN `classify` to `classifier` mapping have one canonical -implementation. The new checkpoint schema and named NPZ output remain -canonical. See [`compatibility.md`](compatibility.md) for the supported and -intentionally unsupported historical artifacts. +## Shared contracts -The following matrix describes the supported new stack, rather than every -class that exists in `legacy/`: +New model families should consume these boundaries: -| Legacy area | New-stack status | Notes | -| --- | --- | --- | -| ROOT/Awkward ingestion | migrated | `RootEventDataset` returns `EventSample` in file/event order | -| node features | migrated + parity-tested | seven-column schema, `CALC_E`, ordering, scales, float32 | -| edge construction | migrated + parity-tested | directed source-major topology and `[deta,dphi,dR]` | -| graph cache | migrated | versioned `GraphSampleCache`; graph-level cache only | -| folds and weights | migrated | named `EventMetadata.fold` and `.weight` | -| batching | migrated | deterministic local loader and DDP sharding | -| legacy padding modes | deferred | no active new-stack consumer | -| `Edge_Network` | migrated + parity-tested | `EdgeNetwork`, raw logits | -| transfer/fine-tuning | migrated + parity-tested | frozen or trainable backbone | -| loss and metrics | migrated + parity-tested | task-owned weighted reductions and full-split AUC | -| training lifecycle | migrated | `Trainer`, validation semantics, scheduler, early stopping | -| checkpoints/resume | migrated | schema v1; historical weight/prefix adapter | -| inference/NPZ | migrated | named output fields and ordered accumulation | -| ROOT score output | compatibility adapter | Python API supported; CLI currently NPZ-only | -| DDP | migrated | torchrun boundary, rank-0 artifacts, gathered metrics | -| Slurm/Perlmutter | launcher examples | site policy remains outside package code | -| ONNX export | migrated for ROOT-GNN | tensor-only adapter, ONNX Runtime validation, and `export` CLI; raw graph tensors are the input contract | +- `EventSample` and named `EventMetadata` from `data`; +- shared collider feature builders from `features`; +- a representation-specific sample/batch type from the relevant adapter; +- task-owned loss, score, prediction, and metric semantics; +- the shared `Trainer`, checkpoint, reproducibility, and inference APIs. -### Intentional redesigns +The graph path is the current ROOT-GNN representation. A sequence or token +model should add a separate representation boundary rather than placing +sequence behavior in graph modules or generic data code. -These are deliberate new-stack contracts, not accidental parity failures: +## Next model-family milestone -* `tracking[:, 0]` and `tracking[:, 1]` become named `metadata.fold` and - `metadata.weight`; public consumers do not depend on positional columns. -* Dynamic legacy YAML `module`/`class` construction becomes allow-listed - semantic Hydra configuration. -* The monolithic training script becomes `Task` + `Trainer` + checkpoint and - inference adapters. -* Graph state is scoped to the forward pass rather than relying on persistent - mutation of shared graph state. -* Model constructors do not mutate global RNG state; seeding is explicit in - the training/application boundary. -* Validation is the selection/early-stopping split and test is held out. This - corrects the legacy loader-name inversion. +The next vertical slice is a minimal `root_transformer` implementation: -Compatibility preserves externally observable scientific behavior where it is -validated; it does not promise to preserve every legacy implementation bug. -The characterized legacy transfer path had a nonempty-global handling bug; -the rewrite supports named globals. Negative weights, rare empty graphs, -historical checkpoint variants, and legacy padding edge cases remain areas to -audit when a supported consumer requires them. +1. Define a small `SequenceSample` contract and deterministic fixture. +2. Implement token construction using shared event/features infrastructure. +3. Add the transformer model under `models/root_transformer/`. +4. Connect it to the existing binary task and trainer on a tiny fixture. +5. Add checkpoint, prediction, and reproducibility tests. -## ROOT-GNN v1 completion checklist +Do not generalize shared interfaces until this second representation exercises +the proposed common behavior. -- [x] active ROOT data path and graph cache -- [x] validated feature, graph, model, task, and metric behavior -- [x] train from scratch and fine-tune a pretrained backbone -- [x] resume new-stack checkpoints and load supported historical weights -- [x] evaluate and predict named outputs -- [x] single-process and DDP application boundaries -- [x] Perlmutter/Slurm launcher examples and profiling guidance -- [x] ROOT-GNN ONNX export and CPU Runtime parity -- [ ] streaming/sharded large-scale prediction output -- [ ] removal of frozen legacy reference -- [ ] ROOT-Transformer representation/model +## Validation requirements -ROOT-GNN v1 is complete when the checked-in new stack can prepare active data, -reproduce validated legacy behavior, train, transfer, resume, evaluate, -predict, and run single-process or DDP workflows. The remaining unchecked -items are intentionally deferred rather than undocumented promises. +Every new model family must provide unit tests for its representation and +model, a small end-to-end integration test, checkpoint reload coverage, and a +deterministic repeatability check. Scientific behavior that is intentionally +shared with ROOT-GNN should be compared against the frozen reference fixture; +architecture-specific behavior should have its own reference outputs. diff --git a/legacy/LICENSE b/legacy/LICENSE deleted file mode 100644 index f8bc5304ced57d6e9da89cdf00995433e2c3b716..0000000000000000000000000000000000000000 --- a/legacy/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 LBL ATLAS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/legacy/README.md b/legacy/README.md deleted file mode 100644 index e5e004a4ae410d57a4be172387fa1036ff0f142b..0000000000000000000000000000000000000000 --- a/legacy/README.md +++ /dev/null @@ -1,358 +0,0 @@ ---- -license: mit -tags: -- arXiv:2412.10665 ---- - -This is a demo is of the approach described in the paper, ["Pretrained Event Classification Model for High Energy Physics Analysis"](https://arxiv.org/abs/2412.10665) -``` -@misc{ho2024pretrained, - title={Pretrained Event Classification Model for High Energy Physics Analysis}, - author={Joshua Ho, Benjamin Ryan Roberts, Shuo Han, Haichen Wang}, - year={2024}, - eprint={2412.10665}, - archivePrefix={arXiv} -} -``` - -## Abstract - -We introduce a foundation model for event classification in high-energy physics, built on a **Graph Neural Network** architecture and trained on **120 million simulated proton-proton collision events** spanning 12 distinct physics processes. The model is *pretrained* to learn a general and robust representation of collision data using challenging multiclass and multilabel classification tasks. - -Its performance is evaluated across five event classification tasks, which include both physics processes used during pretraining and new processes not encountered during pretraining. Fine-tuning the pretrained model significantly improves classification performance, particularly in scenarios with limited training data, demonstrating gains in both accuracy and computational efficiency. - -To investigate the underlying mechanisms behind these performance improvements, we employ a representational similarity evaluation framework based on *Centered Kernel Alignment*. This analysis reveals notable differences in the learned representations of fine-tuned pretrained models compared to baseline models trained from scratch. - -## Introduction - -Machine learning has become a ubiquitous tool in particle physics, employed in a variety of tasks including triggering, simulation, reconstruction, and offline analysis. While its utility spans classification, regression, and generative tasks, the current paradigm of developing machine learning models from scratch for each specific application presents several challenges. This approach not only demands specialized expertise and substantial computing resources but can also result in suboptimal performance due to limited training data. The from-scratch development of models necessitates individual validation studies to ensure that neural networks utilize well-modeled information from training samples, whether derived from Monte Carlo simulations or control samples from experimental data. - -Foundation models offer a promising direction to address these limitations. These models, pre-trained on large, diverse datasets across various tasks, provide robust and general representations of underlying data structures. Notable examples in other fields include GPT-4 [OpenAI et al., 2024](#ref-openai-2024-gpt4) and BERT [Devlin et al., 2018](#ref-devlin-2018-bert) in natural language processing, Stable Diffusion [Rombach et al., 2021](#ref-rombach-2021-latentdiffusion) in image processing, and AlphaFold [Jumper et al., 2021](#ref-jumper-2021-alphafold) in structural biology. The foundation model approach offers several advantages for particle physics applications: reduced computing resources for fine-tuning [Yosinski et al., 2014](#ref-yosinski-2014-transfer) compared to training from scratch, superior performance on specific tasks (particularly with limited training data), and potentially simplified validation procedures as downstream tasks inherit verified representations from the pre-trained model. - -Current literature on pretrained models for particle physics can be categorized based on the data representation they handle. Models operating on particle- or event-level numerical data use features like particle four momenta or jets, leveraging self-supervised or generative methods to learn versatile representations. Detector-focused models operate on high-dimensional responses such as calorimeter deposits or pixel hits, employing geometry-aware techniques for accurate simulation and analysis. Finally, models using textual or code representations apply large language model architectures to integrate domain knowledge, enabling tasks like question answering and code generation. - -Recent studies have begun exploring foundation models tailored to particle physics data, which has a variety of distinct structures and properties across many experiments and data processing stages, including: - -- particle-level & event-level numeric data [Wildridge et al., 2024](#ref-wildridge-2024-bumblebee), [Katel et al., 2024](#ref-katel-2024-jet), [Golling et al., 2024](#ref-golling-2024-maskedset), [Mikuni & Nachman, 2024](#ref-mikuni-2024-omnilearn), [Harris et al., 2024](#ref-harris-2024-resimulation), [Birk et al., 2024](#ref-birk-2024-omnijet), [Vigl et al., 2024](#ref-vigl-2024-finetune), -- detector-level & geometry-aware data [Araz et al., 2024](#ref-araz-2024-pointcloud), [Liu et al., 2023](#ref-liu-2023-gaam), [Hashemi et al., 2024](#ref-hashemi-2024-gen), [Huang et al., 2024](#ref-huang-2024-lmtracking), -- textual or code data [Zhang et al., 2024](#ref-zhang-2024-xiwu). - -This paper presents a foundation model designed specifically for collider event-level data. In modern collider experiments, final-stage analysis processes information from reconstructed objects that either directly correspond to particles in collision final states (such as leptons and photons) or serve as proxies (such as jets and missing transverse energy). While traditional approaches often relied on "high-level" variables calculated from object features, recent trends favor direct input of event objects and their features into neural networks for analysis tasks. A notable example is [ATLAS Collaboration, 2023](#ref-atlas-2023-4top), which established the observation of simultaneous production of four top quarks with the ATLAS experiment by employing a graph neural network (GNN) architecture to process event-level object information. - -We present foundation models that adopt an architecture similar to that used for [ATLAS Collaboration, 2023](#ref-atlas-2023-4top). Our models are pre-trained using either multiclass classification or multi-label learning tasks across 12 distinct physics processes. We evaluate these models through fine-tuning and testing on five classification tasks, including both familiar and novel processes not seen during pre-training. Our analysis benchmarks the models' performance improvements, their scaling behavior with training sample size, and computational efficiency, representing the first prototype of a foundation model operating on collider final-state object data. - -## Data Samples - -To provide a diverse set of physics processes for the pretraining, we use Madgraph@NLO 2.7.3 [Alwall et al., 2014](#ref-alwall-2014hca) to generate proton-proton collision events at next-to-leading order (NLO) in Quantum Chromodynamics (QCD). We generate 12 distinct Standard Model (SM) physics processes, including six major Higgs boson production mechanisms: gluon fusion production \\(ggF\\), vector boson fusion \\(VBF\\), associated production of the Higgs boson with a W boson \\(WH\\) or a Z boson \\(ZH\\), associated production of the Higgs boson with a top-quark pair \\(t\bar{t}H\\), and associated production of the Higgs boson with a single top quark and a forward quark \\(tHq\\). Additionally, we simulate six top quark production processes: single top production, top-quark pair production \\(t\bar{t}\\), top quark pair production in association with a pair of photons \\(t\bar{t}\gamma\gamma\\), associated production of a top-quark pair with a W boson \\(t\bar{t}W\\), simultaneous production of three top quarks \\(t\bar{t}t\\), and simultaneous production of four top quarks \\(t\bar{t}t\bar{t}\\). In these samples, the Higgs boson and top quarks decay inclusively. These 12 Higgs and top quark production processes constitute the pretraining dataset. - -To test the pretrained model, we further generated four processes including three beyond Standard Model (SM) processes: a SM \\(t\bar{t}H\\) production where the Higgs boson decays exclusively to a pair of photons, a \\(t\bar{t}H\\) production with the Higgs boson decaying to a pair of photons, where the top-Yukawa coupling is CP-odd, implemented using the Higgs Characterization model [Artoisenet et al., 2013](#ref-artoisinet-2013puc), the production of a pair of superpartners of the top quark (s-top) using the Minimal Supersymmetric Standard Model (MSSM) [Rosiek, 1990](#ref-rosiek-1990), [Allanach et al., 2009](#ref-allanach-2009), and flavor changing neutral current (FCNC) processes [Degrande et al., 2015](#ref-degrande-2015), [Durieux et al., 2015](#ref-durieux-2015). For the s-top process, we simulate the production of heavier s-top pairs \\(t_2\bar{t_2}\\), where each heavier s-top (mass 582 GeV) decays into a lighter s-top \\(t_1\\) or \\(\bar{t_1}\\), mass 400 GeV) and a Higgs boson. The FCNC process involves \\(t\bar{t}\\) production where one top quark decays to a Higgs boson and a light quark. We generate 10 million events for each process, except for \\(tHq\\) and \\(t\bar{t}t\bar{t}\\), where 5 million events were produced. - -In all simulation samples, the center of mass energy of the proton-proton collision is set to 13 TeV. The Higgs boson, top quarks, and vector bosons are set to decay inclusively (except the \\(t\bar{t}H \rightarrow \gamma\gamma\\) samples), with MadSpin [Artoisenet et al., 2012](#ref-artoisinet-2012st) handling the decays of top quarks and W bosons. The generated events are processed through Pythia 8.235 [Sjostrand et al., 2015](#ref-sjostrand-2015) for parton showering and heavy particle decays, followed by Delphes 3.4.2 [de Favereau et al., 2014](#ref-defavereau-2014) configured to emulate the ATLAS detector [ATLAS Collaboration, 2008](#ref-atlas-2008) for fast detector simulation. - -The detector-level object selection criteria are defined to align with typical experimental conditions. Photons are required to have transverse momentum \\(p_T \geq 20~\mathrm{GeV}\\) and pseudorapidity \\(|\eta| \leq 2.37\\), excluding the electromagnetic calorimeter crack region \\(1.37 < |\eta| < 1.52\\). Electrons must have \\(p_T \geq 10~\mathrm{GeV}\\) and \\(|\eta| \leq 2.47\\) (excluding the same crack region), while muons are selected with \\(p_T \geq 10~\mathrm{GeV}\\) and \\(|\eta| \leq 2.7\\). Jets are reconstructed using the anti-\\(k_t\\) algorithm [Cacciari et al., 2008](#ref-cacciari-2008gp) with radius parameter \\(\Delta R=0.4\\), where \\(\Delta R\\) is defined as \\(\sqrt{\Delta\eta ^2 + \Delta\phi^2}\\), with \\(\Delta\eta\\) being the difference in pseudorapidity and \\(\Delta\phi\\) the difference in azimuthal angle. Jets must satisfy \\(p_T \geq 25~\mathrm{GeV}\\) and \\(|\eta| \leq 2.5\\). To avoid double-counting, jets are removed if they are within \\(\Delta R < 0.4\\) of a photon or lepton. The identification of jets originating from b-quark decays (b-tagging) is performed by matching jets within \\(\Delta R = 0.4\\) of a b-quark, with efficiency corrections applied to match the performance of the ATLAS experiment's b-tagging algorithm [ATLAS Collaboration, 2019](#ref-atlas-2019bwq). - -## Methods - -### Overview - -We present a methodology for developing and evaluating a foundation model for particle collision event analysis. The approach centers on pretraining a Graph Neural Network (GNN) architecture using a comprehensive dataset that spans multiple physics tasks, enabling the model to learn robust and transferable features. For task-specific applications, we employ a fine-tuning strategy that combines output layer adaptation with carefully calibrated learning rates for updating the pretrained parameters. - -Given the prevalence of classification problems in particle physics data analysis, we evaluate the model's efficacy through a systematic assessment across five binary classification tasks: - -- \\(t\bar{t}H(\rightarrow \gamma\gamma)\\) with CP-even versus CP-odd t-H interaction -- \\(t\bar{t}\\) with FCNC top quark decays versus $tHq$ processes -- \\(t\bar{t}W\\) versus $ttt$ processes -- Stop pair production with Higgs bosons in the decay chain versus \\(t\bar{t}H\\) processes -- \\(WH\\) versus \\(ZH\\) production modes - -Our evaluation metrics encompass classification performance, computational efficiency, and model interpretability. The investigation extends to analyzing the model's scaling behavior with respect to training dataset size, benchmarked against models trained without pretraining. Although we explored transfer learning through parameter freezing of pretrained layers, this approach did not yield performance improvements, leading us to focus our detailed analysis on fine-tuning strategies. - -This methodological framework demonstrates the potential of foundation models to enhance the efficiency of particle physics analyses while improving task-specific performance, offering a promising direction for future high-energy physics research. - ---- - -### GNN Architecture - -We implement a Graph Neural Network (GNN) architecture that naturally accommodates the point-cloud structure of particle physics data, employing the DGL framework with a PyTorch backend [Wang et al., 2019][ref-dgl-2019], [Paszke et al., 2019][ref-pytorch-2019]. A fully connected graph is constructed for each event, with nodes corresponding to reconstructed jets, electrons, muons, photons, and \\(\vec{E}_T^{\text{miss}}\\). The features of each node include the four-momentum \\((p_T, \eta, \phi, E)\\) of the object with a massless assumption (\\(E = p_T \cosh \eta\\)), the b-tagging label (for jets), the charge (for leptons), and an integer labeling the type of object represented by the node. We use a placeholder value of 0 for features which are not defined for every node type such as the b-jet tag, lepton charge, or the pseudorapidity of \\(\vec{E}_T^{\text{miss}}\\). We assign the angular distances (\\(\Delta \eta, \Delta \phi, \Delta R\\)) as edge features and the number of nodes $N$ in the graph as a global feature. We denote the node features \\(\{\vec x_i\}\\), edge features \\(\{\vec y_{ij}\}\\), and global features \\(\{\vec z\}\\). - -The GNN model is based on the graph network architecture described in [Battaglia et al., 2018][ref-graphnets-2018] using simple multilayer perceptron (MLP) feature functions and summation aggregation. The model is comprised of three primary components: an encoder, the graph network, and a decoder. In the encoder, three MLPs embed the nodes, edges, and global features into a latent space of dimension 64. The graph network block, which is designed to facilitate message passing between different domains of the graph, performs an edge update $f_e$, followed by a node update $f_n$, and finally a global update $f_g$, all defined below. The inputs to each update MLP are concatenated. - -$$ -\vec {y'}_{ij} = f_e\left(\{\vec x_k\},\vec y_{ij},\vec z\right) = \mathrm{MLP}\left(\vec x_i,\vec x_j,\vec y_{ij},\vec z\right) -$$ - -$$ -\vec{x'}_{i} = f_n\left(\vec x_i,\{\vec{y'}_{jk}\},\vec z\right) = \mathrm{MLP}\left(\vec x_i,\sum_j\vec{y'}_{ij},\vec z\right) -$$ - -$$ -\vec{z'} = f_g\left(\{\vec{x'}_i\},\{\vec{y'}_{ij}\},\vec z\right) = \mathrm{MLP}\left(\sum_i\vec{x'}_i,\sum_{i,j}\vec{y'}_{ij},\vec z\right) -$$ - -This graph block is iterated four times with the same update MLPs. Finally, the global features are passed through a decoder MLP and a final layer linear to produce the desired model outputs. Each MLP consists of 4 linear layers, each with an output width of 64, with the `ReLU` activation function. The output of the MLP is then passed through a `LayerNorm` layer [Ba et al., 2016][ref-layernorm-2016]. The total number of trainable parameters in this model is about 400,000. - -As a performance benchmark, a baseline GNN model is trained from scratch for each classification task. The initial learning rate is set to \\(10^{-4}\\) with an exponential decay following \\(LR(x) = LR_{\text{initial}}\cdot(0.99)^x\\), where \\(x\\) represents the epoch number. - ---- - -### Pretraining Strategy - -We explore two complementary pretraining approaches to develop robust representations of collision events: (1) multi-class classification, which trains the model to distinguish between different physics processes, and (2) multi-label classification, which predicts the existence and kinematics of heavy particles with prompt decays. The pretraining dataset consists of approximately 120 million events, evenly distributed across 12 distinct physics processes, including all major Higgs boson production mechanisms and top quark processes as described in [Data Samples](#sec-data). This large-scale pretraining effort was conducted on the Perlmutter supercomputer at NERSC. - -#### Multi-class Classification - -For Monte Carlo simulated events, the underlying physics process that generated each event is known precisely, providing natural labels for supervised learning. However, the challenge lies in the complexity of collision events: different physics processes can produce similar kinematics and event topologies, particularly in certain regions of phase space. No single observable can unambiguously identify the underlying process. By training the model to distinguish between 12 different processes simultaneously, we challenge it to learn subtle differences in kinematics and topology that collectively characterize each process. The model is trained using categorical cross entropy as the loss function. The output layer of the multiclass classification model has 832 trainable parameters. - -#### Multi-label Classification - -This approach combines both classification and regression tasks to characterize collision events. For discrete properties like particle presence in specific kinematic regions, we employ classification labels with binary cross-entropy loss. For continuous quantities like particle multiplicities, we use regression labels with mean-squared error loss. This hybrid approach enables the model to learn both categorical and continuous aspects of the physics processes simultaneously. - -We develop a comprehensive set of 41 labels that capture both particle multiplicities and kinematic properties. This approach increases prediction granularity and enhances model interpretability. By training the model to predict event kinematics rather than event identification, we create a task-independent framework that can potentially generalize better to novel scenarios not seen during pretraining. - -The particle multiplicity labels count the number of Higgs bosons (\\(n_{\text{higgs}}\\)), top quarks (\\(n_{\text{tops}}\\)), vector bosons (\\(n_V\\)), \\(W\\) bosons (\\(n_W\\)), and \\(Z\\) bosons (\\(n_Z\\)). The kinematic labels characterize the transverse momentum (\\(p_T\\)), pseudorapidity (\\(\eta\\)), and azimuthal angle (\\(\phi\\)) of Higgs bosons and top quarks through binned classifications. - -For Higgs bosons, $p_T$ is categorized into three ranges: (0, 30) GeV, (30, 200) GeV, and (200, \\(\infty\\)) GeV, with the upper range particularly sensitive to potential BSM effects. Similarly, both leading and subleading top quarks have $p_T$ classifications spanning (0, 30) GeV, (30, 300) GeV, and (300, \\(\infty\\)) GeV. When no particle exists within a specific \\(p_T\\) range, the corresponding label is set to \\([0, 0, 0]\\). For all particles, \\(\eta\\) measurements are divided into 4 bins with boundaries at \\([-1.5, 0, 1.5]\\), while \\(\phi\\) measurements use 4 bins with boundaries at \\([-\frac{\pi}{2}, 0, \frac{\pi}{2}]\\). As with \\(p_T\\), both \\(\eta\\) and \\(\phi\\) labels default to \\([0, 0, 0, 0]\\) in the absence of a particle. This comprehensive labeling schema enables fine-grained learning of kinematic distributions and particle multiplicities, essential for characterizing complex collision events. - -The loss function combines individual losses from all 41 labels through weighted averaging. Binary cross-entropy is applied to classification labels, while mean-squared error is used for regression labels. The model generates predictions for all labels simultaneously, with individual losses calculated according to their respective types. The final loss is computed as an equally-weighted average across all labels, with weights set to 1 to ensure uniform contribution to the optimization process. The output layer of the multilabel model has 2,688 trainable parameters. - -#### Pretraining - -During pre-training, the initial learning rate is \\(10^{-4}\\), and the learning rate decays by 1% each epoch following the power law function \\(LR(x) = 10^{-4}\cdot(0.99)^x\\), where \\(x\\) is the number of epochs. Both pre-trained models reach a plateau in loss by epoch 50, at which point the training is stopped. - ---- -### Fine-tuning Methodology - -For downstream tasks, we adjust the model architecture for fine-tuning by replacing the original output layer (final linear layer) with a newly initialized linear layer while retaining the pre-trained weights for all other layers. This modification allows the model to specialize in the specific downstream task while leveraging the general features learned during pretraining. - -The fine-tuning process begins with distinct learning rate setups for different parts of the model. The newly initialized linear layer is trained with an initial learning rate of \\(10^{-4}\\), matching the rate used for models trained from scratch. Meanwhile, the pre-trained layers are fine-tuned more cautiously with a lower initial learning rate of \\(10^{-5}\\). This approach ensures that the pre-trained layers adapt gradually without losing their general features, while the new layer learns effectively from scratch. Both learning rates decay over time following the same power law function, \\(LR(x) = LR_{initial} \cdot (0.99)^x\\), to promote stable convergence as training progresses. - -We also evaluated a transfer learning setup in which either the decoder MLP or the final linear layer was replaced with a newly initialized component. During this process, all other model parameters remained frozen, leveraging the pre-trained features without further updating them. However, we did not observe performance improvements using the transfer learning setup. Consequently, we focus on reporting results obtained with the fine-tuning approach. - ---- - -### Performance Evaluation - -We assess model performance using two figures of merit: the classification accuracy and the Area Under the Curve (AUC) of the Receiver Operating Characteristic (ROC) curve. The accuracy is defined as the fraction of correctly classified events when applying a threshold of 0.5 to the neural network output score. Both metrics demonstrate consistent trends in our analysis. - -To obtain reliable performance estimates and uncertainties, we employ an ensemble training approach where 5 independent models are trained for each configuration with random weight initialization and random subsets of the training dataset. This enables us to evaluate both the models' sensitivity to initial parameters and to quantify uncertainties in their performance. - -To investigate how model performance scales with training data, we conducted training runs using sample sizes ranging from \\(10^3\\) to \\(10^7\\) events per class (\\(10^3\\), \\(10^4\\), \\(10^5\\), \\(10^6\\), and \\(10^7\\)) for each model setup: the from-scratch baseline and models fine-tuned from multi-class or multi-label pretrained models. For the \\(10^7\\) case, only the initialization was randomized due to dataset size limitations. All models were evaluated on the same testing dataset, consisting of 2 million events per class, which remained separate from the training process. - -| **Name of Task** | **Pretraining Task** | \\(10^3\\) | \\(10^4\\) | \\(10^5\\) | \\(10^6\\) | \\(10^7\\) | -|----------------------|----------------------|--------------------|--------------------|--------------------|--------------------|--------------------| -| **ttH CP Even vs Odd** | Baseline Accuracy | 56.5 ± 1.1 | 62.2 ± 0.1 | 64.3 ± 0.0 | 65.7 ± 0.0 | 66.2 ± 0.0 | -| | Multiclass (%) | +4.8 ± 1.1 | +3.4 ± 0.1 | +1.3 ± 0.0 | +0.2 ± 0.0 | −0.0 ± 0.0 | -| | Multilabel (%) | +2.1 ± 1.2 | +1.9 ± 0.1 | +0.8 ± 0.1 | +0.0 ± 0.0 | −0.1 ± 0.0 | -| **FCNC vs tHq** | Baseline Accuracy | 63.6 ± 0.7 | 67.8 ± 0.4 | 68.4 ± 0.3 | 69.3 ± 0.3 | 67.9 ± 0.0 | -| | Multiclass (%) | +5.8 ± 0.8 | +1.2 ± 0.4 | +1.4 ± 0.3 | +0.5 ± 0.3 | −0.0 ± 0.0 | -| | Multilabel (%) | −5.3 ± 0.8 | −1.3 ± 0.4 | +0.9 ± 0.4 | +0.3 ± 0.3 | +0.4 ± 0.1 | -| **ttW vs ttt** | Baseline Accuracy | 75.8 ± 0.1 | 77.6 ± 0.1 | 78.9 ± 0.0 | 79.8 ± 0.0 | 80.3 ± 0.0 | -| | Multiclass (%) | +3.7 ± 0.1 | +2.7 ± 0.1 | +1.3 ± 0.0 | +0.4 ± 0.0 | +0.0 ± 0.0 | -| | Multilabel (%) | +2.2 ± 0.1 | +1.1 ± 0.1 | +0.5 ± 0.0 | +0.0 ± 0.0 | −0.1 ± 0.0 | -| **stop vs ttH** | Baseline Accuracy | 83.0 ± 0.2 | 86.3 ± 0.1 | 87.6 ± 0.0 | 88.5 ± 0.0 | 88.8 ± 0.0 | -| | Multiclass (%) | +0.4 ± 0.2 | +1.9 ± 0.1 | +1.0 ± 0.0 | +0.3 ± 0.0 | +0.0 ± 0.0 | -| | Multilabel (%) | +2.8 ± 0.2 | +1.0 ± 0.1 | +0.5 ± 0.0 | +0.0 ± 0.0 | −0.0 ± 0.0 | -| **WH vs ZH** | Baseline Accuracy | 51.4 ± 0.1 | 53.9 ± 0.1 | 55.8 ± 0.0 | 57.5 ± 0.0 | 58.0 ± 0.0 | -| | Multiclass (%) | +5.2 ± 0.1 | +5.3 ± 0.1 | +3.1 ± 0.0 | +0.6 ± 0.0 | +0.1 ± 0.0 | -| | Multilabel (%) | −1.1 ± 0.1 | −0.9 ± 0.2 | +0.5 ± 0.1 | +0.1 ± 0.0 | −0.1 ± 0.0 | - -> **Table 1**: Accuracy of the traditional model versus the accuracy increase due to fine-tuning from various pretraining tasks. -> The accuracies are averaged over 5 independently trained models with randomly initialized weights and trained on a random subset of the data. One exception is the \\(10^7\\) training where all models use the same dataset due to limitations on our dataset size. The random subsets are allowed to overlap, but this overlap should be very minimal because all models take an independent random subset of \\(10^7\\) events. The testing accuracy is calculated from the same testing set of 2 million events per class across all models for a specific training task. The errors are the propagated errors (root sum of squares) of the standard deviation of accuracies for each model. - -## Results - -### Classification Performance - -Since the observations of AUC and accuracy show similar trends, we focus the presentation of the results using accuracy here for conciseness in Table 1. - -In general, the fine-tuned pretrained model achieves at least the same level of classification performance as the baseline model. Notably, there are significant improvements, particularly when the sample size is small, ranging from \\(10^3\\) to \\(10^4\\) events. In some cases, the accuracy improvements exceed five percentage points, demonstrating that pretrained models provide a strong initial representation that compensates for limited data. The numerical values of the improvements in accuracy may not fully capture the impact on the sensitivity of the measurements for which the neural network classifier is used, and the final sensitivity improvement is likely to be greater. - -As the training sample size grows to \\(10^5\\), \\(10^6\\), and eventually \\(10^7\\) events, the added benefit of pretraining diminishes. With abundant data, models trained from scratch approach or even match the accuracy of fine-tuned pretrained models. This suggests that large datasets enable effective learning from scratch, rendering the advantage of pretraining negligible in such scenarios. - -Although both pretraining approaches offer benefits, multiclass pretraining tends to provide more consistent improvements across tasks, especially in the low-data regime. In contrast, multilabel pretraining can sometimes lead to neutral or even slightly negative effects for certain tasks and data sizes. This highlights the importance of the pretraining task design, as the similarity between pretraining and fine-tuning tasks in the multiclass approach appears to yield better-aligned representations. - -Finally, the spread of accuracy across the five tasks for the baseline model is quite large, offering a robust test of fine-tuning across tasks of varying difficulty. The consistent observation of these trends across tasks confirms the reliability and robustness of the findings. - ---- - -### Model Interpretability - -We aim to understand whether pretrained and baseline models learn the same underlying representations. If the two models exhibit high similarity, a plausible interpretation is that pretraining provides the pretrained model with an advantageous initialization, allowing it to converge to a similar state as the baseline model more efficiently. Conversely, significant differences between the models would indicate that pretraining facilitates the development of a more general and robust latent space, which serves as a foundation for fine-tuning to effectively adapt to the downstream task. To investigate this, we analyzed the representational similarity between a pretrained model fine-tuned for the downstream task and a baseline model trained directly on the downstream task without pretraining. - -We use Centered Kernel Alignment (CKA) [Kornblith et al., 2019][ref-kornblith-2019-cka] to analyze model similarity and interpretability. CKA is a robust metric that quantifies the similarity between the internal representations of neural networks by comparing their feature matrices in a manner that is invariant to scaling, rotation, and alignment. This invariance makes CKA particularly effective for studying relationships between network layers, even across networks of different sizes or those trained from varying initializations. - -The similarity is evaluated using a 64-dimensional latent representation after the decoder stage of the GNN model. This choice allows us to compare the internal states of the models at a fine-grained level and understand how training strategies impact the representations directly used for the output task. - -To provide an intuitive understanding of CKA values, we construct a table of the CKA scores for various transformations performed on a set of dummy data. - -- **A:** randomly initialized matrix with shape (1000, 64), following a normal distribution (\\(\sigma = 1, \mu = 0\\)) -- **B:** matrix with shape (1000, 64) constructed via various transformations performed on \\(A\\) -- **Noise:** randomly initialized noise matrix with shape (1000, 64), following a normal distribution (\\(\sigma = 1, \mu = 0\\)) - -| Dataset | CKA Score | -|---------|-----------| -| \\(A, B = A\\) | 1.00 | -| \\(A, B =\\) permutation on columns of \\(A\\) | 1.00 | -| \\(A, B = A + \mathrm{Noise}(0.1)\\) | 0.99 | -| \\(A, B = A + \mathrm{Noise}(0.5)\\) | 0.80 | -| \\(A, B = A + \mathrm{Noise}(0.75)\\) | 0.77 | -| \\(A, B = A \cdot \mathrm{Noise}(1)\\) (Linear Transformation) | 0.76 | -| \\(A, B = A + \mathrm{Noise}(1)\\) | 0.69 | -| \\(A, B = A + \mathrm{Noise}(2)\\) | 0.51 | -| \\(A, B = A + \mathrm{Noise}(5)\\) | 0.39 | - -**Table 2:** CKA scores for a dummy dataset \\(A\\) and \\(B\\), where \\(B\\) is created via various transformations performed on \\(A\\). - -As seen in Table 2 and in the definition of the CKA, the CKA score is permutation-invariant. We will use the CKA score to evaluate the similarity between various models and gain insight into the learned representation of detector events in each model (i.e., the information that each model learns). - -We train ensembles of models for each training task to observe how the CKA score changes due to the random initialization of our models. The CKA score between two models is then defined to be: - -\\[ -CKA(A, B) = \frac{1}{n^2} \sum_i^n \sum_j^n CKA(A_i, B_j) -\\] - -where \\(A_i\\) is the representation learned by the \\(i^{\text{th}}\\) model in an ensemble with \\(n\\) total models. The error in CKA is the standard deviation of \\(CKA(A_i, B_j)\\). - -Here we present results for the CKA similarity between the final model in each setup with the final model in the baseline, shown in Table 3. - -| Training Task | Baseline | Multiclass | Multilabel | -|-----------------------|------------------|-----------------|-----------------| -| ttH CP Even vs Odd | 0.94 ± 0.05 | 0.82 ± 0.01 | 0.77 ± 0.06 | -| FCNC vs tHq | 0.96 ± 0.03 | 0.76 ± 0.01 | 0.81 ± 0.01 | -| ttW vs ttt | 0.91 ± 0.08 | 0.75 ± 0.10 | 0.72 ± 0.05 | -| stop vs ttH | 0.87 ± 0.11 | 0.79 ± 0.12 | 0.71 ± 0.08 | -| WH vs ZH | 0.90 ± 0.07 | 0.53 ± 0.03 | 0.44 ± 0.06 | - -**Table 3:** CKA Similarity of the latent representation before the decoder with the baseline model, averaged over 3 models per training setup, and all models trained with the full dataset (\\(10^7\\)). The baseline column is not guaranteed to be 1.0 because of the random initialization of the model. Each baseline model converges to a slightly different representation as seen in the CKA values in that column. - -The baseline models with different initializations exhibit high similarity values, ranging from approximately 0.87 to 0.96, which indicates that independently trained baseline models tend to converge on similar internal representations despite random initialization. Across the considered tasks, models trained as multi-class or multi-label classifiers exhibit noticeably lower CKA similarity scores when compared to the baseline model. For example, in the WH vs ZH task, the baseline model and another baseline trained model have a high similarity of 0.90, whereas the multi-class and multi-label models show significantly reduced similarities (0.53 and 0.44, respectively). This pattern suggests that the representational spaces developed by multi-class or multi-label models differ substantially from those learned by the baseline model that was trained directly on the downstream classification task. - -### Computational Efficiency - -To estimate the computational resources required for each approach, we measured the wall time needed for a model to reach its final performance. For baseline models, this is defined as the wall time from the start of training until the loss of the model plateaus. For the foundation model approach, the estimate includes both the pretraining time and the fine-tuning time, each measured from the start of training until the loss plateaus. This approach ensures a consistent and comprehensive evaluation of the computational demands. - -![The ratio of the fine-tuning time required to achieve 99% of the baseline model's final classification accuracy to the total time spent training the baseline model.](training_time.png) -*Fig. 1: The ratio of the fine-tuning time required to achieve 99% of the baseline model's final classification accuracy to the total time spent training the baseline model.* - -Figure 1 shows the fine-tuning time for the model pretrained with multiclass classification, relative to the time required for the baseline model, as a function of training sample size. In general, the fine-tuning time is significantly shorter than the training time required by the baseline model approach. For smaller training sets, on the order of \\(10^5\\) events, tasks such as FCNC vs. tHq and ttW vs. ttt benefit substantially from the pretrained model’s “head start,” achieving their final performance in only about 1% of the baseline time. For large training datasets, the fine-tuning time relative to the baseline training time becomes larger; however, given that the large training sample typically requires longer training time, fine-tuning still yields much faster training convergence. The ttH CP-even vs. ttH CP-odd task, with a training sample size of \\(10^7\\) events, is an exception where the fine-tuning time exceeds the training time required for the baseline model. This is likely because the processes involved in this task include photon objects in the final states, which are absent from the events used during pretraining. - -To accurately evaluate the total time consumption, it is necessary to include the pretraining time required for the foundation model approach. The pretraining times are as follows: - -- **Multi-class pretraining:** 45.5 GPU hours -- **Multi-label pretraining:** 60.0 GPU hours - -The GPU hours recorded for the multi-label model represent the total time required when training the model in parallel on 16 GPUs. This includes a model synchronization step, which results in higher GPU hours compared to the multi-class pretraining model. - -The foundation model approach becomes increasingly efficient when a large number of tasks are fine-tuned using the same pretrained model, compared to training each task independently from scratch. To illustrate this, we evaluate the computational time required for a scenario where the training sample contains \\(10^7\\) events. For the five tasks tested in this study, the baseline training time (training from scratch) ranges from 1.68 GPU hours (WH vs. ZH) to 5.30 GPU hours (ttW vs. ttt), with an average baseline training time of 2.94 GPU hours. In contrast, the average fine-tuning time for the foundation model approach, relative to the baseline, is 38% of the baseline training time for \\(10^7\\) events. Based on these averages, we estimate that the foundation model approach becomes more computationally efficient than the baseline approach when fine-tuning is performed for more than 41 tasks. - -As a practical example, the ATLAS measurement of Higgs boson couplings using the \\(H \rightarrow \gamma\gamma\\) decay channel [ATLAS Collaboration, 2023][ref-atlas-2023-higg] involved training 42 classifiers for event categorization. This coincides with our estimate, suggesting that the foundation model approach can reduce computational costs even for a single high-energy physics measurement. - -## Conclusions - -We presented an in-depth study of a particle physics foundation model designed to operate on the four-momentum and identification properties of event final-state objects. This model is built on a Graph Neural Network (GNN) architecture and trained on a dataset comprising 120 million simulated proton-proton collision events across 12 distinct physics processes. The pretraining phase explored both multiclass and multilabel classification tasks, providing a robust foundation for downstream applications. Notably, the pretrained models demonstrated significant improvements in event classification performance when fine-tuned, particularly for tasks with limited training samples. - -The foundation model approach also offers substantial computational advantages. By leveraging fine-tuning, this methodology reduces the computational resources required for large-scale applications across multiple tasks. Our estimates indicate that significant resource savings can be achieved even for single particle physics measurements, making this approach both scalable and efficient. - -To better understand the learned representations of the pretrained model and guide future optimization efforts, we employed a representational similarity evaluation framework using Centered Kernel Alignment (CKA). This metric allowed us to investigate the source of the performance gains observed in the foundation model. Our analysis revealed notable differences in the learned representations between the fine-tuned pretrained model and a baseline model trained from scratch. In deep learning, it is well-established that multiple equally valid solutions can exist. Future studies are necessary to determine whether the low similarity in latent representations reflects complementary information uniquely captured by the foundation and baseline models, or if it can simply be attributed to connected local minima in the loss landscape. - -## Acknowledgments - -This work is supported by the U.S. National Science Foundation under the Award No. 2046280, and by U.S. Department of Energy, Office of Science under contract DE-AC02-05CH11231. - -## References - -- **OpenAI et al.** GPT-4 Technical Report. arXiv:2303.08774 (2024). [https://arxiv.org/abs/2303.08774](https://arxiv.org/abs/2303.08774) - -- **Jason Yosinski, Jeff Clune, Yoshua Bengio, Hod Lipson.** How transferable are features in deep neural networks? CoRR abs/1411.1792 (2014). [http://arxiv.org/abs/1411.1792](http://arxiv.org/abs/1411.1792) - -- **Robin Rombach, Andreas Blattmann, Dominik Lorenz, Patrick Esser, Björn Ommer.** High-Resolution Image Synthesis with Latent Diffusion Models. CoRR abs/2112.10752 (2021). [https://arxiv.org/abs/2112.10752](https://arxiv.org/abs/2112.10752) - -- **Dustin Podell, Zion English, Kyle Lacey et al.** SDXL: Improving Latent Diffusion Models for High-Resolution Image Synthesis. arXiv:2307.01952 (2023). [https://arxiv.org/abs/2307.01952](https://arxiv.org/abs/2307.01952) - -- **John Jumper, Richard Evans, Alexander Pritzel et al.** Highly accurate protein structure prediction with AlphaFold. Nature 596, 583-589 (2021). [https://doi.org/10.1038/s41586-021-03819-2](https://doi.org/10.1038/s41586-021-03819-2) - -- **Jacob Devlin, Ming-Wei Chang, Kenton Lee, Kristina Toutanova.** BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. CoRR abs/1810.04805 (2018). [http://arxiv.org/abs/1810.04805](http://arxiv.org/abs/1810.04805) - -- **ATLAS Collaboration.** Measurement of the properties of Higgs boson production at \\(\sqrt{s} = 13\,\text{TeV}\\) in the \\(H \to \gamma\gamma\\) channel using \\(139\,\text{fb}^{-1}\\) of \\(pp\\) collision data with the ATLAS experiment. JHEP 07 (2023) 088. [arXiv:2207.00348](https://arxiv.org/abs/2207.00348), [https://doi.org/10.1007/JHEP07(2023)088](https://doi.org/10.1007/JHEP07(2023)088) - -- **ATLAS Collaboration.** Observation of four-top-quark production in the multilepton final state with the ATLAS detector. Eur. Phys. J. C 83 (2023) 496. [arXiv:2303.15061](https://arxiv.org/abs/2303.15061), [https://doi.org/10.1140/epjc/s10052-023-11573-0](https://doi.org/10.1140/epjc/s10052-023-11573-0) - -- **Simon Kornblith, Mohammad Norouzi, Honglak Lee, Geoffrey Hinton.** Similarity of Neural Network Representations Revisited. CoRR abs/1905.00414 (2019). [http://arxiv.org/abs/1905.00414](http://arxiv.org/abs/1905.00414) - ---- - - - -- **N. D. Birell, P. C. W. Davies.** Quantum Fields in Curved Space. Cambridge Univ. Press (1982). - -- **R. P. Feynman.** Phys. Rev. 94, 262 (1954). - -- **A. Einstein, Yu. Podolsky, N. Rosen.** Phys. Rev. 47, 777 (1935). - -- **G. P. Berman, Jr., F. M. Izrailev, Jr.** Stability of nonlinear modes. Physica D 88, 445 (1983). - -- **E. B. Davies, L. Parns.** Trapped modes in acoustic waveguides. Q. J. Mech. Appl. Math. 51, 477–492 (1988). - -- **Edward Witten.** hep-th/0106109 (2001). [https://arxiv.org/abs/hep-th/0106109](https://arxiv.org/abs/hep-th/0106109) - ---- - - - -- **E. Beutler.** Williams Hematology, 5th Edition, Chapter 7, pp. 654–662. McGraw-Hill, New York (1994). - -- **Donald E. Knuth.** The Art of Computer Programming vol. 1: Fundamental Algorithms, 2nd Ed., Addison-Wesley (1973). - -- **J. S. Smith, G. W. Johnson.** Philos. Trans. R. Soc. London, Ser. B 777, 1395 (2005). - -- **W. J. Smith, T. J. Johnson, B. G. Miller.** Surface chemistry and preferential crystal orientation on a silicon surface. J. Appl. Phys. (unpublished, 2010). - -- **V. K. Smith, K. Johnson, M. O. Klein.** Surface chemistry and preferential crystal orientation on a silicon surface. J. Appl. Phys. (submitted, 2010). - -- **Ulrich Underwood, Ned Net, Paul Pot.** Lower Bounds for Wishful Research Results. Talk at Fanstord University (1988). - -- **M. P. Johnson, K. L. Miller, K. Smith.** Personal communication (Jan-May 2007). - ---- - - - -- **Adam Paszke et al.** PyTorch: An Imperative Style, High-Performance Deep Learning Library. arXiv:1912.01703 (2019). [http://arxiv.org/abs/1912.01703](http://arxiv.org/abs/1912.01703) - -- **Minjie Wang et al.** Deep Graph Library: Towards Efficient and Scalable Deep Learning on Graphs. arXiv:1909.01315 (2019). [http://arxiv.org/abs/1909.01315](http://arxiv.org/abs/1909.01315) - -- **Peter W. Battaglia et al.** Relational inductive biases, deep learning, and graph networks. arXiv:1806.01261 (2018). [http://arxiv.org/abs/1806.01261](http://arxiv.org/abs/1806.01261) - -- **Jimmy Lei Ba, Jamie Ryan Kiros, Geoffrey E. Hinton.** Layer Normalization. arXiv:1607.06450 (2016). [https://arxiv.org/abs/1607.06450](https://arxiv.org/abs/1607.06450) - ---- - - - -- **Andrew J. Wildridge et al.** Bumblebee: Foundation Model for Particle Physics Discovery. arXiv:2412.07867 (2024). [https://arxiv.org/abs/2412.07867](https://arxiv.org/abs/2412.07867) - -- **Subash Katel et al.** Learning Symmetry-Independent Jet Representations via Jet-Based Joint Embedding Predictive Architecture. arXiv:2412.05333 (2024). [https://arxiv.org/abs/2412.05333](https://arxiv.org/abs/2412.05333) - -- **Jack Y. Araz et al.** Point cloud-based diffusion models for the Electron-Ion Collider. arXiv:2410.22421 (2024). [https://arxiv.org/abs/2410.22421](https://arxiv.org/abs/2410.22421) - -- **Matthew Leigh et al.** Is Tokenization Needed for Masked Particle Modelling? arXiv:2409.12589 (2024). [https://arxiv.org/abs/2409.12589](https://arxiv.org/abs/2409.12589) - -- **Vinicius Mikuni, Benjamin Nachman.** OmniLearn: A Method to Simultaneously Facilitate All Jet Physics Tasks. arXiv:2404.16091 (2024). [https://arxiv.org/abs/2404.16091](https://arxiv.org/abs/2404.16091) - -- **Zhengde Zhang et al.** Xiwu: A Basis Flexible and Learnable LLM for High Energy Physics. arXiv:2404.08001 (2024). [https://arxiv.org/abs/2404.08001](https://arxiv.org/abs/2404.08001) - -- **Philip Harris et al.** Re-Simulation-based Self-Supervised Learning for Pre-Training Foundation Models. arXiv:2403.07066 (2024). [https://arxiv.org/abs/2403.07066](https://arxiv.org/abs/2403.07066) - -- **Joschka Birk, Anna Hallin, Gregor Kasieczka.** OmniJet-$\alpha$: the first cross-task foundation model for particle physics. Machine Learning: Science and Technology. 5(3), 035031 (Aug 2024). [https://doi.org/10.1088/2632-2153/ad66ad](https://doi.org/10.1088/2632-2153/ad66ad) - -- **Andris Huang et al.** A Language Model for Particle Tracking. arXiv:2402.10239 (2024). [https://arxiv.org/abs/2402.10239](https://arxiv.org/abs/2402.10239) - -- **Tobias Golling et al.** Masked Particle Modeling on Sets: Towards Self-Supervised High Energy Physics Foundation Models. arXiv:2401.13537 (2024). [https://arxiv.org/abs/2401.13537](https://arxiv.org/abs/2401.13537) - -- **Junze Liu et al.** Generalizing to new geometries with Geometry-Aware Autoregressive Models (GAAMs) for fast calorimeter simulation. Journal of Instrumentation 18(11), P11003 (Nov 2023). [https://doi.org/10.1088/1748-0221/18/11/p11003](https://doi.org/10.1088/1748-0221/18/11/p11003) - -- **Baran Hashemi et al.** Ultra-high-granularity detector simulation with intra-event aware generative adversarial network and self-supervised relational reasoning. Nature Communications 15(1) (June 2024). [https://doi.org/10.1038/s41467-024-49104-4](https://doi.org/10.1038/s41467-024-49104-4) - -- **Matthias Vigl et al.** Finetuning Foundation Models for Joint Analysis Optimization. arXiv:2401.13536 (2024). [https://arxiv.org/abs/2401.13536](https://arxiv.org/abs/2401.13536) - -- **Chen Li, Hao Cai, Xianyang Jiang.** Refine neutrino events reconstruction with BEiT-3. Journal of Instrumentation 19(6), T06003 (Jun 2024). [https://doi.org/10.1088/1748-0221/19/06/t06003](https://doi.org/10.1088/1748-0221/19/06/t06003) \ No newline at end of file diff --git a/legacy/physicsnemo/configs/config.yaml b/legacy/physicsnemo/configs/config.yaml deleted file mode 100644 index f4ba528f692c8cde29bfb3cad5560510b408f134..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/configs/config.yaml +++ /dev/null @@ -1,64 +0,0 @@ -# ignore_header_test -# Copyright 2023 Stanford University -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -random_seed: 2 - -scheduler: - lr: 1.E-3 - lr_decay: 1.E-3 - -training: - epochs: 100 - -checkpoints: - ckpt_path: "checkpoints" - ckpt_name: "config" - -performance: - amp: False - jit: False - -architecture: - processor_size: 8 - hidden_dim_node_encoder: 128 - hidden_dim_edge_encoder: 128 - hidden_dim_processor: 128 - hidden_dim_node_decoder: 128 - out_dim: 1 - -paths: - data_dir: /global/cfs/projectdirs/atlas/joshua/hackathon_data/stats_100K - save_dir: /pscratch/sd/j/joshuaho/physicsnemo/graphs/stats_100K - training_dir: ./training_stats_100K/ - -datasets: - - name: ttH_cp_even - load_path: ${paths.data_dir}/ttH_NLO.root - label: 0 - - name: ttH_cp_odd - load_path: ${paths.data_dir}/ttH_CPodd.root - label: 1 - -root_dataset: - ttree: output - type: torch.bfloat16 - particles: ["jet", "ele", "mu", "ph", "MET"] - features: ["pt", "eta", "phi", "energy", "btag", "charge", "node_type"] - globals: [] - weights: "" - tracking: [] - step_size: 8192 - batch_size: 8192 - train_val_test_split: [0.75, 0.24, 0.01] \ No newline at end of file diff --git a/legacy/physicsnemo/configs/config_stats_all.yaml b/legacy/physicsnemo/configs/config_stats_all.yaml deleted file mode 100644 index bf7ac89fb86304cf48071dc7856db3da1e4bc057..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/configs/config_stats_all.yaml +++ /dev/null @@ -1,65 +0,0 @@ -# ignore_header_test -# Copyright 2023 Stanford University -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -random_seed: 2 - -scheduler: - lr: 1.E-4 - lr_decay: 1.E-3 - -training: - epochs: 100 - -checkpoints: - ckpt_path: "checkpoints" - ckpt_name: "config_stats_all" - -performance: - amp: False - jit: False - -architecture: - processor_size: 5 - hidden_dim_node_encoder: 64 - hidden_dim_edge_encoder: 64 - hidden_dim_processor: 64 - hidden_dim_node_decoder: 64 - out_dim: 1 - -paths: - data_dir: /global/cfs/projectdirs/atlas/joshua/hackathon_data/stats_all - save_dir: /pscratch/sd/j/joshuaho/physicsnemo/graphs/stats_all - training_dir: ./training_stats_all/ - -datasets: - - name: ttH_cp_even - load_path: ${paths.data_dir}/ttH_NLO.root - label: 0 - - name: ttH_cp_odd - load_path: ${paths.data_dir}/ttH_CPodd.root - label: 1 - -root_dataset: - ttree: output - type: torch.bfloat16 - particles: ["jet", "ele", "mu", "ph", "MET"] - features: ["pt", "eta", "phi", "energy", "btag", "charge", "node_type"] - globals: [] - weights: "" - tracking: [] - step_size: 81920 - batch_size: 8192 - train_val_test_split: [0.75, 0.24, 0.01] - prebatch: True \ No newline at end of file diff --git a/legacy/physicsnemo/configs/tHjb_CP_0_vs_45.yaml b/legacy/physicsnemo/configs/tHjb_CP_0_vs_45.yaml deleted file mode 100644 index 2bc0cfd298a5da976ae5c93b80f99e091b7f0a6c..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/configs/tHjb_CP_0_vs_45.yaml +++ /dev/null @@ -1,79 +0,0 @@ -# ignore_header_test -# Copyright 2023 Stanford University -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -random_seed: 2 - -scheduler: - lr: 1.E-3 - lr_decay: 1.E-3 - -training: - epochs: 100 - -checkpoints: - ckpt_path: "checkpoints" - ckpt_name: "config" - -performance: - amp: False - jit: False - -architecture: - processor_size: 8 - hidden_dim_node_encoder: 128 - hidden_dim_edge_encoder: 128 - hidden_dim_processor: 128 - hidden_dim_node_decoder: 128 - global_emb_dim: 128 - out_dim: 1 - -paths: - data_dir: /global/cfs/projectdirs/atlas/joshua/ttHCP/ntuples/v02/preselection/merged_fixed/train/ - save_dir: /pscratch/sd/j/joshuaho/physicsnemo/ttHCP/graphs/tHjb_CP_0_vs_45/ - training_dir: ./training_tHjb_CP_0_vs_45/ - -datasets: - - name: tHjb_cp_0_had - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_0_AF3_had_scaled.root - label: 0 - - name: tHjb_cp_0_lep - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_0_AF3_lep_scaled.root - label: 0 - - name: tHjb_cp_45_had - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_45_AF3_had_scaled.root - label: 1 - - name: tHjb_cp_45_lep - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_45_AF3_lep_scaled.root - label: 1 - -root_dataset: - ttree: output - dtype: torch.bfloat16 - features: - # pt, eta, phi, energy, btag, charge, node_type - jet: [m_jet_pt, m_jet_eta, m_jet_phi, CALC_E, m_jet_PCbtag, 0, 0] - electron: [m_el_pt, m_el_eta, m_el_phi, CALC_E, 0, m_el_charge, 1] - muon: [m_mu_pt, m_mu_eta, m_mu_phi, CALC_E, 0, m_mu_charge, 2] - photon: [ph_pt_myy, ph_eta, ph_phi, CALC_E, 0, 0, 3] - met: [m_met, 0, m_met_phi, CALC_E, 0, 0, 4] - globals: [NUM_NODES] - weights: m_weightXlumi - tracking: [] - step_size: 16384 - batch_size: 16384 - train_val_test_split: [0.5, 0.25, 0.25] - prebatch: - enabled: True - chunk_size: 512 \ No newline at end of file diff --git a/legacy/physicsnemo/configs/tHjb_CP_0_vs_90.yaml b/legacy/physicsnemo/configs/tHjb_CP_0_vs_90.yaml deleted file mode 100644 index 55737ff7b99cbd5b8fcceb41cc94e2e115e63333..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/configs/tHjb_CP_0_vs_90.yaml +++ /dev/null @@ -1,87 +0,0 @@ -# ignore_header_test -# Copyright 2023 Stanford University -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -random_seed: 2 - -scheduler: - lr: 1.E-3 - lr_decay: 1.E-3 - -training: - epochs: 100 - -checkpoints: - ckpt_path: "checkpoints" - ckpt_name: "tHjb_CP_0_vs_90" - -performance: - amp: False - jit: False - -architecture: - module: models.MeshGraphNet - class: MeshGraphNet - args: - base_gnn: - input_dim_nodes: 7 - input_dim_edges: 3 - output_dim: 128 - processor_size: 8 - hidden_dim_node_encoder: 128 - hidden_dim_edge_encoder: 128 - hidden_dim_processor: 128 - hidden_dim_node_decoder: 128 - global_emb_dim: 128 - global_feat_dim: 1 - out_dim: 1 - -paths: - data_dir: /global/cfs/projectdirs/atlas/joshua/ttHCP/ntuples/v02/preselection/merged_fixed/train/ - save_dir: /pscratch/sd/j/joshuaho/physicsnemo/ttHCP/graphs/tHjb_CP_0_vs_90/ - training_dir: ./tHjb_CP_0_vs_90/ - -datasets: - - name: tHjb_cp_0_had - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_0_AF3_had_scaled.root - label: 0 - - name: tHjb_cp_0_lep - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_0_AF3_lep_scaled.root - label: 0 - - name: tHjb_cp_90_had - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_90_AF3_had_scaled.root - label: 1 - - name: tHjb_cp_90_lep - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_90_AF3_lep_scaled.root - label: 1 - -root_dataset: - ttree: output - dtype: torch.bfloat16 - features: - # pt, eta, phi, energy, btag, charge, node_type - jet: [m_jet_pt, m_jet_eta, m_jet_phi, CALC_E, m_jet_PCbtag, 0, 0] - electron: [m_el_pt, m_el_eta, m_el_phi, CALC_E, 0, m_el_charge, 1] - muon: [m_mu_pt, m_mu_eta, m_mu_phi, CALC_E, 0, m_mu_charge, 2] - photon: [ph_pt_myy, ph_eta, ph_phi, CALC_E, 0, 0, 3] - met: [m_met, 0, m_met_phi, CALC_E, 0, 0, 4] - globals: [NUM_NODES] - weights: 1 - tracking: [] - step_size: 16384 - batch_size: 16384 - train_val_test_split: [0.5, 0.25, 0.25] - prebatch: - enabled: True - chunk_size: 512 \ No newline at end of file diff --git a/legacy/physicsnemo/configs/tHjb_CP_0_vs_90_edge_network.yaml b/legacy/physicsnemo/configs/tHjb_CP_0_vs_90_edge_network.yaml deleted file mode 100644 index 1fd6cfa0078254c3f817aad2736b0cd864fb672a..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/configs/tHjb_CP_0_vs_90_edge_network.yaml +++ /dev/null @@ -1,82 +0,0 @@ -# ignore_header_test -# Copyright 2023 Stanford University -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -random_seed: 2 - -scheduler: - lr: 1.E-3 - lr_decay: 1.E-3 - -training: - epochs: 100 - -checkpoints: - ckpt_path: "checkpoints" - ckpt_name: "tHjb_CP_0_vs_90_edge_network" - -performance: - amp: False - jit: False - -architecture: - module: models.Edge_Network - class: Edge_Network - args: - input_dim_nodes: 7 - input_dim_edges: 3 - input_dim_globals: 1 - hid_size: 64 - n_layers: 4 - n_proc_steps: 4 - out_dim: 1 - -paths: - data_dir: /global/cfs/projectdirs/atlas/joshua/ttHCP/ntuples/v02/preselection/merged_fixed/train/ - save_dir: /pscratch/sd/j/joshuaho/physicsnemo/ttHCP/graphs/tHjb_CP_0_vs_90/ - training_dir: ./tHjb_CP_0_vs_90_edge_network/ - -datasets: - - name: tHjb_cp_0_had - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_0_AF3_had_scaled.root - label: 0 - - name: tHjb_cp_0_lep - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_0_AF3_lep_scaled.root - label: 0 - - name: tHjb_cp_90_had - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_90_AF3_had_scaled.root - label: 1 - - name: tHjb_cp_90_lep - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_90_AF3_lep_scaled.root - label: 1 - -root_dataset: - ttree: output - dtype: torch.bfloat16 - features: - # pt, eta, phi, energy, btag, charge, node_type - jet: [m_jet_pt, m_jet_eta, m_jet_phi, CALC_E, m_jet_PCbtag, 0, 0] - electron: [m_el_pt, m_el_eta, m_el_phi, CALC_E, 0, m_el_charge, 1] - muon: [m_mu_pt, m_mu_eta, m_mu_phi, CALC_E, 0, m_mu_charge, 2] - photon: [ph_pt_myy, ph_eta, ph_phi, CALC_E, 0, 0, 3] - met: [m_met, 0, m_met_phi, CALC_E, 0, 0, 4] - globals: [NUM_NODES] - weights: 1 - tracking: [] - step_size: 16384 - batch_size: 16384 - train_val_test_split: [0.5, 0.25, 0.25] - prebatch: - enabled: True - chunk_size: 512 \ No newline at end of file diff --git a/legacy/physicsnemo/configs/tHjb_CP_0_vs_90_globals.yaml b/legacy/physicsnemo/configs/tHjb_CP_0_vs_90_globals.yaml deleted file mode 100644 index 546a69e7209db96d5b783eb60d09a0612b13b483..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/configs/tHjb_CP_0_vs_90_globals.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# ignore_header_test -# Copyright 2023 Stanford University -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -random_seed: 2 - -scheduler: - lr: 1.E-3 - lr_decay: 1.E-3 - -training: - epochs: 100 - -checkpoints: - ckpt_path: "checkpoints" - ckpt_name: "tHjb_CP_0_vs_90_globals" - -performance: - amp: False - jit: False - -architecture: - base_gnn: - input_dim_nodes: 7 - input_dim_edges: 3 - output_dim: 128 - processor_size: 8 - hidden_dim_node_encoder: 128 - hidden_dim_edge_encoder: 128 - hidden_dim_processor: 128 - hidden_dim_node_decoder: 128 - global_emb_dim: 128 - global_feat_dim: 5 - out_dim: 1 - -paths: - data_dir: /global/cfs/projectdirs/atlas/joshua/ttHCP/ntuples/v02/preselection/merged_fixed/train/ - save_dir: /pscratch/sd/j/joshuaho/physicsnemo/ttHCP/graphs/tHjb_CP_0_vs_90_globals/ - training_dir: ./tHjb_CP_0_vs_90_globals/ - -datasets: - - name: tHjb_cp_0_had - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_0_AF3_had_scaled.root - label: 0 - - name: tHjb_cp_0_lep - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_0_AF3_lep_scaled.root - label: 0 - - name: tHjb_cp_90_had - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_90_AF3_had_scaled.root - label: 1 - - name: tHjb_cp_90_lep - load_path: ${paths.data_dir}/merged_aMCPy8_tHjb125_CP_90_AF3_lep_scaled.root - label: 1 - -root_dataset: - ttree: output - dtype: torch.bfloat16 - features: - # pt, eta, phi, energy, btag, charge, node_type - jet: [m_jet_pt, m_jet_eta, m_jet_phi, CALC_E, m_jet_PCbtag, 0, 0] - electron: [m_el_pt, m_el_eta, m_el_phi, CALC_E, 0, m_el_charge, 1] - muon: [m_mu_pt, m_mu_eta, m_mu_phi, CALC_E, 0, m_mu_charge, 2] - photon: [ph_pt_myy, ph_eta, ph_phi, CALC_E, 0, 0, 3] - met: [m_met, 0, m_met_phi, CALC_E, 0, 0, 4] - globals: [NUM_NODES, eta_H, pt_H, eta_recotop1, pT_recotop1] - weights: 1 - tracking: [] - step_size: 16384 - batch_size: 16384 - train_val_test_split: [0.5, 0.25, 0.25] - prebatch: - enabled: True - chunk_size: 512 \ No newline at end of file diff --git a/legacy/physicsnemo/dataset/Dataset.py b/legacy/physicsnemo/dataset/Dataset.py deleted file mode 100644 index 107f83e80091a2133ef32f8f8c0b20af1096cd94..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/dataset/Dataset.py +++ /dev/null @@ -1,243 +0,0 @@ -import os -import uproot -import dgl -import torch -import numpy as np -from omegaconf import DictConfig -from typing import List -from concurrent.futures import ProcessPoolExecutor, as_completed -from tqdm import tqdm - -from dataset import GraphBuilder -from dataset import Graphs -from dataset import Normalization - -from dgl.dataloading import GraphDataLoader - -class Dataset: - def __init__( - self, - name: str, - label: int, - load_path: str, - save_path: str, - dtype: torch.dtype, - device: str, - cfg: DictConfig - ): - self.name = name - self.label = label - self.load_path = load_path - self.save_path = save_path - self.dtype = dtype - self.data = None - self.device = device - - self.ttree = cfg.ttree - self.features = cfg.features - self.weights = cfg.weights - self.globals = cfg.globals - self.tracking = cfg.tracking - self.step_size = cfg.step_size - self.batch_size = cfg.batch_size - - self.prebatch = cfg.get('prebatch', {'enabled': False}) - - self.train_val_test_split = cfg.train_val_test_split - assert np.sum(self.train_val_test_split) == 1, "train_val_test_split must sum to 1" - - print(f"initializing dataset {name} with dtype {self.dtype}") - - def get_branches(self) -> List[str]: - node_branches = [ - branches - for particle in self.features.values() - for branches in particle - if isinstance(branches, str) and (branches != "CALC_E" or branches != "NUM_NODES") - ] - global_branches = [x for x in self.globals if isinstance(x, str)] - weight_branch = [self.weights] if isinstance(self.weights, str) else [] - tracking_branches = [x for x in self.tracking if isinstance(x, str)] - label_branch = [self.label] if isinstance(self.label, str) else [] - - return node_branches + global_branches + weight_branch + tracking_branches + label_branch - - def process(self): - branches = self.get_branches() - with uproot.open(f"{self.load_path}:{self.ttree}") as tree: - available_branches = set(tree.keys()) - num_entries = tree.num_entries - - print(f"getting branches: {branches}") - - num_cpus = os.cpu_count() - total_chunks = np.ceil(num_entries / self.step_size) - - with ProcessPoolExecutor(max_workers=num_cpus) as executor: - futures = [] - - with tqdm( - uproot.iterate( - f"{self.load_path}:{self.ttree}", - expressions=[b for b in branches if b in available_branches], - step_size=self.step_size, - library="ak" - ), - desc="loading root file", - total=total_chunks, - position=0, - leave=True - ) as pbar: - - for chunk_id, arrays in enumerate(pbar): - - cfg = GraphBuilder.ChunkConfig( - name=self.name, - label=self.label, - chunk_id=chunk_id, - batch_size=self.batch_size, - arrays=arrays, - features=self.features, - globals=self.globals, - tracking=self.tracking, - weights=self.weights, - branches=branches, - dtype=self.dtype, - save_path=self.save_path, - prebatch = self.prebatch, - ) - - futures.append(executor.submit(GraphBuilder.process_chunk, cfg)) - - for idx, future in enumerate(as_completed(futures)): - try: - future.result() - except Exception as e: - import traceback - print(f"exception in chunk: {idx}") - traceback.print_exception(type(e), e, e.__traceback__) - return - - def load(self): - with uproot.open(f"{self.load_path}:{self.ttree}") as tree: - num_entries = tree.num_entries - total_chunks = int(np.ceil(num_entries / self.step_size)) - - chunk_files = [f"{self.save_path}/{self.name}_{chunk_id:04d}.bin" for chunk_id in range(total_chunks)] - if not all(os.path.exists(f) for f in chunk_files): - print("graphs not found. processing root file...") - self.process() - - graph_tuple_list = [] - - for chunk_id, f in enumerate(chunk_files): - if chunk_id < total_chunks - 1: - if (self.prebatch.enabled): - n_graphs = self.step_size // self.prebatch.chunk_size - else: - n_graphs = self.step_size - else: - if (self.prebatch.enabled): - n_graphs = (num_entries - self.step_size * (total_chunks - 1)) // self.prebatch.chunk_size + 1 - else: - n_graphs = num_entries - self.step_size * (total_chunks - 1) - graph_tuple_list.extend((f, idx) for idx in range(n_graphs)) - - split = self.train_val_test_split - n_total = len(graph_tuple_list) - n_train = int(split[0] * n_total) - n_val = int(split[1] * n_total) - - train_tuples = graph_tuple_list[:n_train] - val_tuples = graph_tuple_list[n_train:n_train + n_val] - test_tuples = graph_tuple_list[n_train + n_val:] - return train_tuples, val_tuples, test_tuples - -class GraphTupleDataset: - def __init__(self, tuple_list, stats): - self.tuple_list = tuple_list - self.stats = stats - self.cache = {} - - def __len__(self): - return len(self.tuple_list) - - def __getitem__(self, idx): - f, graph_idx = self.tuple_list[idx] - if f in self.cache: - g = self.cache[f] - else: - g = Graphs.load_graphs(f) - g.normalize(self.stats) - self.cache[f] = g - return g[graph_idx] - - @staticmethod - def collate_fn(samples): - all_graphs = [] - all_metadata = {} - - # Initialize keys in all_metadata from the first sample - for k in samples[0][1]: - all_metadata[k] = [] - - for graph, metadata in samples: - all_graphs.append(graph) - for k, v in metadata.items(): - all_metadata[k].append(v) - - # Stack or concatenate metadata for each key - for k in all_metadata: - # If v is a tensor, stack or cat as appropriate - # Use torch.cat if v is already [N, ...] (e.g. labels, features) - # Use torch.stack if v is scalar or needs new dimension - try: - all_metadata[k] = torch.cat(all_metadata[k], dim=0) - except Exception: - all_metadata[k] = torch.stack(all_metadata[k], dim=0) - - batched_graph = dgl.batch(all_graphs) - return batched_graph, all_metadata - -def get_dataset(cfg: DictConfig, device): - - all_train = [] - all_val = [] - all_test = [] - - dtype_str = getattr(cfg.root_dataset, "dtype", "torch.float32") - if isinstance(dtype_str, str) and dtype_str.startswith("torch."): - dtype = getattr(torch, dtype_str.split(".")[-1], torch.float32) - else: - dtype = torch.float32 - - for ds in cfg.datasets: - name = ds['name'] - load_path = ds.get('load_path', f"{cfg.paths.data_dir}/{name}.root") - save_path = ds.get('save_path', f"{cfg.paths.save_dir}/") - datastet = Dataset(name, ds.get('label'), load_path, save_path, dtype, device, cfg.root_dataset) - train, val, test = datastet.load() - all_train.extend(train) - all_val.extend(val) - all_test.extend(test) - - stats = Normalization.global_stats(f"{cfg.paths.save_dir}/stats/", dtype=dtype) - - train_dataset = GraphTupleDataset(all_train, stats) - val_dataset = GraphTupleDataset(all_val, stats) - test_dataset = GraphTupleDataset(all_test, stats) - - if (cfg.root_dataset.get('prebatch', False)): - batch_size = cfg.root_dataset.batch_size // cfg.root_dataset.prebatch.chunk_size - collate_fn = GraphTupleDataset.collate_fn - else: - batch_size = cfg.root_dataset.batch_size - collate_fn = None - - train_loader = GraphDataLoader(train_dataset, batch_size=batch_size, shuffle=True, pin_memory=True, num_workers=5, drop_last=False, collate_fn=collate_fn) - val_loader = GraphDataLoader(val_dataset, batch_size=batch_size, shuffle=False, pin_memory=True, num_workers=5, drop_last=False, collate_fn=collate_fn) - test_loader = GraphDataLoader(test_dataset, batch_size=batch_size, shuffle=False, pin_memory=True, num_workers=0, drop_last=False, collate_fn=collate_fn) - - print("all data loaded successfully") - print(f"train: {len(train_dataset)}, val: {len(val_dataset)}, test: {len(test_dataset)}") - return train_loader, val_loader, test_loader \ No newline at end of file diff --git a/legacy/physicsnemo/dataset/GraphBuilder.py b/legacy/physicsnemo/dataset/GraphBuilder.py deleted file mode 100644 index 2a21f04e58203177d680a9259af19086f28c9489..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/dataset/GraphBuilder.py +++ /dev/null @@ -1,162 +0,0 @@ -import dgl -import torch -import numpy as np -import awkward as ak -from dataclasses import dataclass -from typing import List, Any, Union - -from dataset.Graphs import Graphs, save_graphs -from dataset import Normalization - -@dataclass -class ChunkConfig: - name: str - label: Union[str, int] - chunk_id: int - batch_size: int - arrays: List[Any] - features: List[Any] - globals: List[Any] - weights: Union[str, float] - tracking: List[Any] - branches: List[Any] - dtype: torch.dtype - save_path: str - prebatch: dict - -def process_chunk(cfg: ChunkConfig): - # Collect everything as lists first - graph_list = [] - meta_dict = { - 'globals': [], - 'label': [], - 'weight': [], - 'tracking': [], - 'batch_num_nodes': [], - 'batch_num_edges': [], - } - - for i in range(len(cfg.arrays)): - g, meta = process_single_entry(cfg, i) - graph_list.append(g) - for k in meta_dict: - meta_dict[k].append(meta[k]) - - # Stack all metadata fields into tensors - for k in meta_dict: - meta_dict[k] = torch.stack(meta_dict[k]) - - graphs = Graphs(graphs=graph_list, metadata=meta_dict) - Normalization.save_stats(graphs, f"{cfg.save_path}/stats/{cfg.name}_{cfg.chunk_id:04d}.json") - - if getattr(cfg.prebatch, "enabled", False): - graphs.shuffle() - graphs.batch(cfg.prebatch["chunk_size"]) - - save_graphs(graphs, f"{cfg.save_path}/{cfg.name}_{cfg.chunk_id:04d}.bin") - -def process_single_entry(cfg, i): - # 1) node features - node_features: List[torch.Tensor] = [] - - for particle, branch_list in cfg.features.items(): - feature_tensors: List[torch.Tensor] = [] - for branch in branch_list: - if branch == "CALC_E": - pT = feature_tensors[0] - eta = feature_tensors[1] - val = pT * torch.cosh(eta) - elif isinstance(branch, str): - arr = cfg.arrays[branch][i] - val = torch.from_numpy(ak.to_numpy(arr)).to(cfg.dtype) - else: - length = feature_tensors[0].shape[0] - val = torch.full((length,), float(branch), dtype=cfg.dtype) - feature_tensors.append(val) - - if feature_tensors and feature_tensors[0].numel() > 0: - block = torch.stack(feature_tensors, dim=1) - node_features.append(block) - - node_features = torch.cat(node_features, dim=0) if node_features else torch.empty((0, len(cfg.features)), dtype=cfg.dtype) - - # 2) global features - global_feat_list: List[torch.Tensor] = [] - for b in cfg.globals: - if b == "NUM_NODES": - global_feat_list.append(torch.tensor([len(node_features)], dtype=cfg.dtype)) - else: - arr = cfg.arrays[b][i] - global_feat_list.append(torch.from_numpy(ak.to_numpy(arr)).to(cfg.dtype)) - global_feat = torch.cat(global_feat_list, dim=0) if global_feat_list else torch.zeros((1,), dtype=cfg.dtype) - - # 3) tracking - tracking_list: List[torch.Tensor] = [] - for b in cfg.tracking: - arr = cfg.arrays[b][i] - tracking_list.append(torch.from_numpy(ak.to_numpy(arr)).to(cfg.dtype)) - tracking = torch.cat(tracking_list, dim=0) if tracking_list else torch.zeros((1,), dtype=cfg.dtype) - - # 4) weight - weight = float(cfg.arrays[cfg.weights][i]) if isinstance(cfg.weights, str) else cfg.weights - weight = torch.tensor(weight, dtype=cfg.dtype) - - # 5) label - label = float(cfg.arrays[cfg.label][i]) if isinstance(cfg.label, str) else cfg.label - label = torch.tensor(label, dtype=cfg.dtype) - - # 6) make the DGLGraph - g = make_graph(node_features, dtype=cfg.dtype) - - # 7) batch_num_nodes and batch_num_edges - batch_num_nodes = g.batch_num_nodes() - batch_num_edges = g.batch_num_edges() - - meta = { - 'globals': global_feat, - 'label': label, - 'weight': weight, - 'tracking': tracking, - 'batch_num_nodes': batch_num_nodes, - 'batch_num_edges': batch_num_edges, - } - return g, meta - -src_dst_cache = {} -def get_src_dst(num_nodes): - if num_nodes not in src_dst_cache: - src, dst = torch.meshgrid(torch.arange(num_nodes), torch.arange(num_nodes), indexing='ij') - src_dst_cache[num_nodes] = (src.flatten(), dst.flatten()) - return src_dst_cache[num_nodes] - -@torch.jit.script -def compute_edge_features(eta, phi, src, dst): - deta = eta[src] - eta[dst] - dphi = phi[src] - phi[dst] - dphi = torch.remainder(dphi + np.pi, 2 * np.pi) - np.pi - dR = torch.sqrt(deta ** 2 + dphi ** 2) - edge_features = torch.stack([dR, deta, dphi], dim=1) - return edge_features - -def make_graph(node_features: torch.tensor, dtype=torch.float32): - - num_nodes = node_features.shape[0] - if num_nodes == 0: - g = dgl.graph(([], [])) - g.ndata['features'] = node_features - g.edata['features'] = torch.empty((0, 3), dtype=dtype) - g.globals = torch.tensor([0], dtype=dtype) - return g - - src, dst = get_src_dst(num_nodes) - src = src.flatten() - dst = dst.flatten() - g = dgl.graph((src, dst)) - g.ndata['features'] = node_features - - eta = node_features[:, 1] - phi = node_features[:, 2] - edge_features = compute_edge_features(eta, phi, src, dst) - g.edata['features'] = edge_features - - return g \ No newline at end of file diff --git a/legacy/physicsnemo/dataset/Graphs.py b/legacy/physicsnemo/dataset/Graphs.py deleted file mode 100644 index bcbd359e240e2a7778581cf7e3c9af3f5b70ab4d..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/dataset/Graphs.py +++ /dev/null @@ -1,88 +0,0 @@ -import dgl -import torch -from dataclasses import dataclass, field -from typing import List, Dict - -@dataclass -class Graphs: - graphs: List[dgl.DGLGraph] - metadata: Dict[str, torch.Tensor] - - def __len__(self): - return len(self.graphs) - - def __getitem__(self, idx): - meta = {k: v[idx] for k, v in self.metadata.items()} - return self.graphs[idx], meta - - def shuffle(self): - idx = torch.randperm(len(self.graphs)) - self.graphs = [self.graphs[i] for i in idx] - for k in self.metadata: - self.metadata[k] = self.metadata[k][idx] - - def batch(self, batch_size, node_feature_dim=None, dtype=None): - """ - In-place batching: after this, self.graphs is a list of batched DGLGraphs, - and self.metadata[k] is a tensor of shape [num_batches, batch_size, ...]. - """ - batched_graphs = [] - batched_meta = {k: [] for k in self.metadata} - N = len(self.graphs) - - # Infer node_feature_dim and dtype if not specified - if node_feature_dim is None and N > 0: - feats = self.graphs[0].ndata['features'] - node_feature_dim = feats.shape[1] if feats.ndim > 1 else 1 - if dtype is None and N > 0: - dtype = self.graphs[0].ndata['features'].dtype - - for start in range(0, N, batch_size): - end = start + batch_size - batch_graphs = self.graphs[start:end] - batch_meta = {k: v[start:end] for k, v in self.metadata.items()} - - # Padding if needed - pad_count = batch_size - len(batch_graphs) - if pad_count > 0: - dummy_graph = dgl.graph(([], [])) - dummy_graph.ndata['features'] = torch.empty((0, node_feature_dim), dtype=dtype) - dummy_graph.edata['features'] = torch.empty((0, 3), dtype=dtype) # assuming 3 edge features - batch_graphs += [dummy_graph] * pad_count - - # Pad metadata with zeros - for k, v in batch_meta.items(): - shape = list(v[0].shape) if len(v) > 0 else [] - pad_tensor = torch.zeros([pad_count] + shape, dtype=v.dtype, device=v.device) - batch_meta[k] = torch.cat([v, pad_tensor], dim=0) - else: - for k, v in batch_meta.items(): - batch_meta[k] = torch.stack(v, dim=0) if isinstance(v, list) else v - - batched_graphs.append(dgl.batch(batch_graphs)) - for k in batched_meta: - batched_meta[k].append(batch_meta[k]) - - # Now stack along a new axis: [num_batches, batch_size, ...] - for k in batched_meta: - self.metadata[k] = torch.stack(batched_meta[k], dim=0) - - self.graphs = batched_graphs - - def normalize(self, stats): - node_mean, node_std, _ = stats['node'] - edge_mean, edge_std, _ = stats['edge'] - for g in self.graphs: - g.ndata['features'] = (g.ndata['features'] - node_mean) / node_std - g.edata['features'] = (g.edata['features'] - edge_mean) / edge_std - -def save_graphs(graphs: Graphs, f: str): - meta_to_save = {k: v for k, v in graphs.metadata.items()} - dgl.save_graphs(f, graphs.graphs, meta_to_save) - -def load_graphs(f: str) -> Graphs: - g, meta = dgl.load_graphs(f) - for k in meta: - if not isinstance(meta[k], torch.Tensor): - meta[k] = torch.stack(meta[k]) - return Graphs(graphs=g, metadata=meta) \ No newline at end of file diff --git a/legacy/physicsnemo/dataset/Normalization.py b/legacy/physicsnemo/dataset/Normalization.py deleted file mode 100644 index ac168f5f41242af21c1018fc71051cd43f7ba643..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/dataset/Normalization.py +++ /dev/null @@ -1,144 +0,0 @@ -import torch -import json -import os -from dataset.Graphs import Graphs -from typing import List, Dict, Tuple - -def combine_feature_stats(chunks: List[Dict]) -> Tuple[torch.Tensor, torch.Tensor, int]: - """ - Combine mean/std/count from multiple chunks using Welford's algorithm. - Returns combined mean, std, and total count. - """ - n_total = 0 - mean_total = None - M2_total = None - - for chunk in chunks: - n_k = chunk['count'] - if n_k == 0: - continue - - mean_k = torch.tensor(chunk['mean']) - std_k = torch.tensor(chunk['std']) - M2_k = (std_k ** 2) * n_k - - if n_total == 0: - mean_total = mean_k - M2_total = M2_k - n_total = n_k - else: - delta = mean_k - mean_total - N = n_total + n_k - mean_total += delta * (n_k / N) - M2_total += M2_k + (delta ** 2) * (n_total * n_k / N) - n_total = N - - if n_total == 0: - return torch.tensor([]), torch.tensor([]), 0 - - std_total = torch.sqrt(M2_total / n_total) - return mean_total, std_total, n_total - -def global_stats(dirpath: str, dtype: torch.dtype) -> Dict[str, Tuple[torch.Tensor, torch.Tensor, int]]: - """ - Load all JSON stats files in a directory, combine node, edge, and global stats, - and optionally save the combined stats as JSON to `save_path`. - """ - - combined_stats_path = os.path.join(dirpath, "global_stats.json") - - if not os.path.exists(combined_stats_path): - stats_list = [] - for fname in os.listdir(dirpath): - if fname.endswith('.json'): - with open(os.path.join(dirpath, fname), 'r') as f: - stats_list.append(json.load(f)) - - node_stats = [s['node'] for s in stats_list] - edge_stats = [s['edge'] for s in stats_list] - - combined = { - 'node': combine_feature_stats(node_stats), - 'edge': combine_feature_stats(edge_stats), - } - - combined_json = {} - for key, (mean, std, count) in combined.items(): - combined_json[key] = { - 'mean': mean.tolist() if mean.numel() > 0 else [], - 'std': std.tolist() if std.numel() > 0 else [], - 'count': count, - } - - with open(combined_stats_path, 'w') as f: - json.dump(combined_json, f, indent=4) - - with open(combined_stats_path, 'r') as f: - combined_json = json.load(f) - - def to_tensor(d): - mean = torch.tensor(d['mean'], dtype=dtype) if d['mean'] else torch.tensor([], dtype=dtype) - std = torch.tensor(d['std'], dtype=dtype) if d['std'] else torch.tensor([], dtype=dtype) - count = d['count'] - return mean, std, count - - return { - 'node': to_tensor(combined_json['node']), - 'edge': to_tensor(combined_json['edge']), - } - -def compute_stats(feats, eps=1e-6): - mean = feats.mean(dim=0) - if feats.size(0) > 1: - var = ((feats - mean) ** 2).mean(dim=0) - else: - var = torch.zeros_like(mean) - std = torch.sqrt(var) - std = torch.where(std < eps, torch.full_like(std, eps), std) - - return mean, std - -def save_stats(graphs: 'Graphs', filepath: str, categorical_unique_threshold=50): - """ - Compute and save normalization stats (mean, std, counts) for node and edge features. - Categorical features (few unique values) have normalization disabled (mean=0, std=1). - """ - if len(graphs) == 0: - raise ValueError("No graphs to compute stats from.") - - # Node and edge features - all_node_feats = torch.cat([g.ndata['features'] for g, _ in graphs], dim=0) - all_edge_feats = torch.cat([g.edata['features'] for g, _ in graphs], dim=0) - - counts = { - 'node': all_node_feats.size(0), - 'edge': all_edge_feats.size(0), - } - - node_mean, node_std = compute_stats(all_node_feats) - edge_mean, edge_std = compute_stats(all_edge_feats) - - categorical_mask = torch.tensor([ - torch.unique(all_node_feats[:, i]).numel() < categorical_unique_threshold - for i in range(node_mean.size(0)) - ], dtype=torch.bool) - node_mean[categorical_mask] = 0.0 - node_std[categorical_mask] = 1.0 - - stats = { - 'node': { - 'mean': node_mean.tolist(), - 'std': node_std.tolist(), - 'count': counts['node'], - }, - 'edge': { - 'mean': edge_mean.tolist(), - 'std': edge_std.tolist(), - 'count': counts['edge'], - }, - } - - os.makedirs(os.path.dirname(filepath), exist_ok=True) - - with open(filepath, 'w') as f: - json.dump(stats, f, indent=4) \ No newline at end of file diff --git a/legacy/physicsnemo/metrics.py b/legacy/physicsnemo/metrics.py deleted file mode 100644 index 5393c7a78e4ac9b90580901d2b1ba4a46924277f..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/metrics.py +++ /dev/null @@ -1,110 +0,0 @@ -import torch -import numpy as np -import torch.nn.functional as F - -def bce(input, target, weights=None): - - if input.shape != target.shape: - if input.shape[-1] == 1 and input.shape[:-1] == target.shape: - input = input.squeeze(-1) - elif target.shape[-1] == 1 and target.shape[:-1] == input.shape: - target = target.squeeze(-1) - - loss = F.binary_cross_entropy_with_logits(input, target, reduction='none') - return torch.mean(loss) - -def weighted_bce(input, target, weights=None): - """ - Compute a weighted and label-normalized binary cross entropy (BCE) loss. - - For each unique label in the target tensor, the BCE loss is computed and weighted, - then normalized by the sum of weights for that label. The final loss is the mean - of these per-label normalized losses. - - Args: - input (Tensor): Predicted logits of shape (N, ...). - target (Tensor): Ground truth labels of shape (N, ...), with discrete label values. - weights (Tensor or None): Optional tensor of per-sample weights, same shape as input/target. - - Returns: - Tensor: Scalar tensor representing the normalized weighted BCE loss. - """ - - if input.shape != target.shape: - if input.shape[-1] == 1 and input.shape[:-1] == target.shape: - input = input.squeeze(-1) - elif target.shape[-1] == 1 and target.shape[:-1] == input.shape: - target = target.squeeze(-1) - - # Compute per-element BCE loss (no reduction) - loss = F.binary_cross_entropy_with_logits(input, target, reduction='none') - - # If weights not provided, use ones - if weights is None: - weights = torch.ones_like(loss) - - unique_labels = torch.unique(target) - normalized_losses = [] - for label in unique_labels: - label_mask = (target == label) # This will be a bool tensor - # Defensive: make sure mask is bool - if label_mask.dtype != torch.bool: - label_mask = label_mask.bool() - label_weights = weights[label_mask] - label_losses = loss[label_mask] - weight_sum = label_weights.sum() - if weight_sum > 0: - label_loss = (label_weights * label_losses).sum() / weight_sum - normalized_losses.append(label_loss) - - if normalized_losses: - return torch.stack(normalized_losses).mean() - else: - return torch.tensor(0.0, device=input.device) - - -def roc_auc_score(classes : np.ndarray, - predictions : np.ndarray, - weights : np.ndarray = None) -> float: - """ - Calculating ROC AUC score as the probability of correct ordering - """ - - if weights is None: - weights = np.ones_like(predictions) - - assert len(classes) == len(predictions) == len(weights) - assert classes.ndim == predictions.ndim == weights.ndim == 1 - class0, class1 = sorted(np.unique(classes)) - - data = np.empty( - shape=len(classes), - dtype=[('c', classes.dtype), - ('p', predictions.dtype), - ('w', weights.dtype)] - ) - data['c'], data['p'], data['w'] = classes, predictions, weights - - data = data[np.argsort(data['c'])] - data = data[np.argsort(data['p'], kind='mergesort')] # here we're relying on stability as we need class orders preserved - - correction = 0. - # mask1 - bool mask to highlight collision areas - # mask2 - bool mask with collision areas' start points - mask1 = np.empty(len(data), dtype=bool) - mask2 = np.empty(len(data), dtype=bool) - mask1[0] = mask2[-1] = False - mask1[1:] = data['p'][1:] == data['p'][:-1] - if mask1.any(): - mask2[:-1] = ~mask1[:-1] & mask1[1:] - mask1[:-1] |= mask1[1:] - ids, = mask2.nonzero() - correction = sum([((dsplit['c'] == class0) * dsplit['w'] * msplit).sum() * - ((dsplit['c'] == class1) * dsplit['w'] * msplit).sum() - for dsplit, msplit in zip(np.split(data, ids), np.split(mask1, ids))]) * 0.5 - - weights_0 = data['w'] * (data['c'] == class0) - weights_1 = data['w'] * (data['c'] == class1) - cumsum_0 = weights_0.cumsum() - - return ((cumsum_0 * weights_1).sum() - correction) / (weights_1.sum() * cumsum_0[-1]) diff --git a/legacy/physicsnemo/models/Edge_Network.py b/legacy/physicsnemo/models/Edge_Network.py deleted file mode 100644 index e7cf7591fa03375552f31a3978c2fa91cf1780e7..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/models/Edge_Network.py +++ /dev/null @@ -1,72 +0,0 @@ -import torch -import torch.nn as nn -import dgl - -from models import utils - -class Edge_Network(nn.Module): - def __init__(self, cfg): - super().__init__() - hid_size = cfg.hid_size - n_layers = cfg.n_layers - self.n_proc_steps = cfg.n_proc_steps - - #encoder - self.node_encoder = utils.Make_MLP(cfg.input_dim_nodes, hid_size, hid_size, n_layers) - self.edge_encoder = utils.Make_MLP(cfg.input_dim_edges, hid_size, hid_size, n_layers) - self.global_encoder = utils.Make_MLP(cfg.input_dim_globals, hid_size, hid_size, n_layers) - - #GNN - self.node_update = utils.Make_MLP(3*hid_size, hid_size, hid_size, n_layers) - self.edge_update = utils.Make_MLP(4*hid_size, hid_size, hid_size, n_layers) - self.global_update = utils.Make_MLP(3*hid_size, hid_size, hid_size, n_layers) - - #decoder - self.global_decoder = utils.Make_MLP(hid_size, hid_size, hid_size, n_layers) - self.classify = nn.Linear(hid_size, cfg.out_dim) - - def forward(self, node_feats, edge_feats, global_feats, batched_graph, metadata={}): - # encoders - batched_graph.ndata['h'] = self.node_encoder(node_feats) - batched_graph.edata['e'] = self.edge_encoder(edge_feats) - - if global_feats.ndim == 3: - global_feats = global_feats.view(-1, global_feats.shape[-1]) - h_global = self.global_encoder(global_feats) - - # message passing - for _ in range(self.n_proc_steps): - batched_graph.apply_edges(dgl.function.copy_u('h', 'm_u')) - batched_graph.apply_edges(utils.copy_v) - - # edge update - edge_inputs = torch.cat([ - batched_graph.edata['e'], - batched_graph.edata['m_u'], - batched_graph.edata['m_v'], - utils.broadcast_global_to_edges(h_global, edge_split=metadata.get("batch_num_edges", None)) - ], dim=1) - batched_graph.edata['e'] = self.edge_update(edge_inputs) - - # node update - batched_graph.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - node_inputs = torch.cat([ - batched_graph.ndata['h'], - batched_graph.ndata['h_e'], - utils.broadcast_global_to_nodes(h_global, node_split=metadata.get("batch_num_nodes", None)) - ], dim=1) - batched_graph.ndata['h'] = self.node_update(node_inputs) - - # global update - graph_node_feat = utils.mean_nodes( - batched_graph, 'h', node_split=metadata.get("batch_num_nodes", None) - ) - graph_edge_feat = utils.mean_edges( - batched_graph, 'e', edge_split=metadata.get("batch_num_edges", None) - ) - h_global = self.global_update(torch.cat([h_global, graph_node_feat, graph_edge_feat], dim=1)) - - h_global = self.global_decoder(h_global) - out = self.classify(h_global) - return out - diff --git a/legacy/physicsnemo/models/MeshGraphNet.py b/legacy/physicsnemo/models/MeshGraphNet.py deleted file mode 100644 index c20cd3813f1373900f4fdaab25e6b0964a678daf..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/models/MeshGraphNet.py +++ /dev/null @@ -1,51 +0,0 @@ -import torch -import torch.nn as nn -import dgl - -from models import utils - -# Import the PhysicsNemo MeshGraphNet model -from physicsnemo.models.meshgraphnet import MeshGraphNet as PhysicsNemoMeshGraphNet - -class MeshGraphNet(nn.Module): - def __init__(self, cfg): - super().__init__() - base_gnn_cfg = cfg.base_gnn - self.base_gnn = PhysicsNemoMeshGraphNet(**base_gnn_cfg) - - self.global_mlp = nn.Sequential( - nn.Linear(cfg.global_feat_dim, cfg.global_emb_dim), - nn.ReLU(), - ) - - self.mlp = nn.Linear( - base_gnn_cfg['output_dim'] + base_gnn_cfg['input_dim_edges'] + cfg.global_emb_dim, - cfg.out_dim - ) - - def forward(self, node_feats, edge_feats, global_feats, batched_graph, metadata={}): - """ - node_feats: [total_num_nodes, node_feat_dim] - edge_feats: [total_num_edges, edge_feat_dim] - global_feats: [num_graphs, global_feat_dim] - batched_graph: DGLGraph, representing the collection of graphs in a batch - metadata: dict, may contain 'batch_num_nodes', 'batch_num_edges', etc. - Returns: - graph_pred: [num_graphs, out_dim] - """ - node_pred = self.base_gnn(node_feats, edge_feats, batched_graph) - batched_graph.ndata['h'] = node_pred - batched_graph.edata['e'] = edge_feats - - graph_node_feat = utils.mean_nodes(batched_graph, 'h', node_split=metadata.get("batch_num_nodes", None)) - graph_edge_feat = utils.mean_edges(batched_graph, 'e', edge_split=metadata.get("batch_num_edges", None)) - - # Flatten global_feats if needed - if global_feats.ndim == 3: - global_feats = global_feats.view(-1, global_feats.shape[-1]) - global_emb = self.global_mlp(global_feats) # [num_graphs, global_emb_dim] - - combined_feat = torch.cat([graph_node_feat, graph_edge_feat, global_emb], dim=-1) - graph_pred = self.mlp(combined_feat) - return graph_pred - diff --git a/legacy/physicsnemo/models/utils.py b/legacy/physicsnemo/models/utils.py deleted file mode 100644 index 2823e5397f5a518836351106cbbc9fa884338d4e..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/models/utils.py +++ /dev/null @@ -1,135 +0,0 @@ -import torch -import torch.nn as nn -import dgl - -def mean_nodes(batched_graph, feat_key='h', op='mean', node_split=None): - """ - Aggregates node features per disjoint graph in a batched DGLGraph. - - Args: - batched_graph: DGLGraph - feat_key: str, node feature key - op: 'mean', 'sum', or 'max' - node_split: 1D tensor or list of ints (num nodes per graph) - - Returns: - Tensor of shape [num_graphs, node_feat_dim] - """ - h = batched_graph.ndata[feat_key] - if node_split is None or len(node_split) == 0: - if op == 'mean': - return dgl.mean_nodes(batched_graph, feat_key) - elif op == 'sum': - return dgl.sum_nodes(batched_graph, feat_key) - elif op == 'max': - return dgl.max_nodes(batched_graph, feat_key) - else: - raise ValueError(f"Unknown op: {op}") - else: - # Ensure node_split is a flat list of ints - if isinstance(node_split, torch.Tensor): - splits = node_split.view(-1).tolist() - else: - splits = [int(x) for x in node_split] - chunks = torch.split(h, splits, dim=0) - if op == 'mean': - out = torch.stack([chunk.mean(0) if chunk.shape[0] > 0 else torch.zeros_like(h[0]) for chunk in chunks]) - elif op == 'sum': - out = torch.stack([chunk.sum(0) if chunk.shape[0] > 0 else torch.zeros_like(h[0]) for chunk in chunks]) - elif op == 'max': - out = torch.stack([chunk.max(0).values if chunk.shape[0] > 0 else torch.zeros_like(h[0]) for chunk in chunks]) - else: - raise ValueError(f"Unknown op: {op}") - return out - -def mean_edges(batched_graph, feat_key='e', op='mean', edge_split=None): - """ - Aggregates edge features per disjoint graph in a batched DGLGraph. - - Args: - batched_graph: DGLGraph - feat_key: str, edge feature key - op: 'mean', 'sum', or 'max' - edge_split: 1D tensor or list of ints (num edges per graph) - - Returns: - Tensor of shape [num_graphs, edge_feat_dim] - """ - e = batched_graph.edata[feat_key] - if edge_split is None or len(edge_split) == 0: - if op == 'mean': - return dgl.mean_edges(batched_graph, feat_key) - elif op == 'sum': - return dgl.sum_edges(batched_graph, feat_key) - elif op == 'max': - return dgl.max_edges(batched_graph, feat_key) - else: - raise ValueError(f"Unknown op: {op}") - else: - # Ensure edge_split is a flat list of ints - if isinstance(edge_split, torch.Tensor): - splits = edge_split.view(-1).tolist() - else: - splits = [int(x) for x in edge_split] - chunks = torch.split(e, splits, dim=0) - if op == 'mean': - out = torch.stack([chunk.mean(0) if chunk.shape[0] > 0 else torch.zeros_like(e[0]) for chunk in chunks]) - elif op == 'sum': - out = torch.stack([chunk.sum(0) if chunk.shape[0] > 0 else torch.zeros_like(e[0]) for chunk in chunks]) - elif op == 'max': - out = torch.stack([chunk.max(0).values if chunk.shape[0] > 0 else torch.zeros_like(e[0]) for chunk in chunks]) - else: - raise ValueError(f"Unknown op: {op}") - return out - -def Make_SLP(in_size, out_size, activation = nn.ReLU, dropout = 0): - layers = [] - layers.append(nn.Linear(in_size, out_size)) - layers.append(activation()) - layers.append(nn.Dropout(dropout)) - return layers - -def Make_MLP(in_size, hid_size, out_size, n_layers, activation = nn.ReLU, dropout = 0): - layers = [] - if n_layers > 1: - layers += Make_SLP(in_size, hid_size, activation, dropout) - for i in range(n_layers-2): - layers += Make_SLP(hid_size, hid_size, activation, dropout) - layers += Make_SLP(hid_size, out_size, activation, dropout) - else: - layers += Make_SLP(in_size, out_size, activation, dropout) - layers.append(torch.nn.LayerNorm(out_size)) - return nn.Sequential(*layers) - -def broadcast_global_to_nodes(globals, node_split): - """ - globals: [num_graphs, global_dim] - node_split: list/1D tensor of length num_graphs, number of nodes per graph - Returns: [total_num_nodes, global_dim] - """ - if node_split is None: - raise ValueError("node_split must be provided") - if not torch.is_tensor(node_split): - node_split = torch.tensor(node_split, dtype=torch.long, device=globals.device) - else: - node_split = node_split.to(device=globals.device, dtype=torch.long) - node_split = node_split.flatten() - return torch.repeat_interleave(globals, node_split, dim=0) - -def broadcast_global_to_edges(globals, edge_split): - """ - globals: [num_graphs, global_dim] (on CUDA or CPU) - edge_split: list/1D tensor of length num_graphs, number of edges per graph (CPU or CUDA) - Returns: [total_num_edges, global_dim] - """ - if edge_split is None: - raise ValueError("edge_split must be provided") - if not torch.is_tensor(edge_split): - edge_split = torch.tensor(edge_split, dtype=torch.long, device=globals.device) - else: - edge_split = edge_split.to(device=globals.device, dtype=torch.long) - edge_split = edge_split.flatten() - return torch.repeat_interleave(globals, edge_split, dim=0) - -def copy_v(edges): - return {'m_v': edges.dst['h']} \ No newline at end of file diff --git a/legacy/physicsnemo/setup/Dockerfile b/legacy/physicsnemo/setup/Dockerfile deleted file mode 100755 index 89cf6d2f530e3a8c186e82c43f22e3f428f4a65f..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/setup/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM nvcr.io/nvidia/physicsnemo/physicsnemo:25.06 - -WORKDIR /global/cfs/projectdirs/atlas/joshua/GNN4Colliders - -LABEL maintainer.name="Joshua Ho" -LABEL maintainer.email="ho22joshua@berkeley.edu" - -ENV LANG=C.UTF-8 - -# Install system dependencies: vim, OpenMPI, and build tools -RUN apt-get update -qq \ - && apt-get install -y --no-install-recommends \ - wget lsb-release gnupg software-properties-common \ - vim \ - g++-11 gcc-11 libstdc++-11-dev \ - openmpi-bin openmpi-common libopenmpi-dev \ - && rm -rf /var/lib/apt/lists/* - -# Install Python packages: mpi4py and jupyter -RUN pip install --no-cache-dir mpi4py jupyter uproot - -# (Optional) Expose Jupyter port -EXPOSE 8888 diff --git a/legacy/physicsnemo/setup/build_image.sh b/legacy/physicsnemo/setup/build_image.sh deleted file mode 100755 index f9d1ecbb9bda5da752e97ed025f51d454ea6566b..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/setup/build_image.sh +++ /dev/null @@ -1,4 +0,0 @@ -tag=$1 -echo $tag -podman-hpc build -t joshuaho/nemo:$tag --platform linux/amd64 . -podman-hpc migrate joshuaho/nemo:$tag diff --git a/legacy/physicsnemo/train.py b/legacy/physicsnemo/train.py deleted file mode 100644 index 0801dd4bff1b49aa0fa2561ea9187f8d096495bd..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/train.py +++ /dev/null @@ -1,246 +0,0 @@ -import time, os - -start = time.time() -import torch -from torch.nn.parallel import DistributedDataParallel -from dgl.dataloading import GraphDataLoader -from torch.amp import GradScaler -import numpy as np -import hydra -from omegaconf import DictConfig -from physicsnemo.launch.logging import ( - PythonLogger, - RankZeroLoggingWrapper, -) -from physicsnemo.launch.utils import load_checkpoint, save_checkpoint -from physicsnemo.distributed.manager import DistributedManager - -import json -from tqdm import tqdm -import random - -import models.MeshGraphNet as MeshGraphNet -from dataset.Dataset import get_dataset -import metrics - -import utils - -class MGNTrainer: - def __init__(self, logger, cfg, dist): - # set device - self.device = dist.device - logger.info(f"Using {self.device} device") - - start = time.time() - self.trainloader, self.valloader, self.testloader = get_dataset(cfg, self.device) - print(f"total time loading dataset: {time.time() - start:.2f} seconds") - - dtype_str = getattr(cfg.root_dataset, "dtype", "torch.float32") - if isinstance(dtype_str, str) and dtype_str.startswith("torch."): - self.dtype = getattr(torch, dtype_str.split(".")[-1], torch.float32) - else: - self.dtype = torch.float32 - - self.model = utils.build_from_module(cfg.architecture) - self.model = self.model.to(dtype=self.dtype, device=self.device) - # num_params = sum(p.numel() for p in self.model.parameters() if p.requires_grad) - # print(f"Number of trainable parameters: {num_params}") - - if cfg.performance.jit: - self.model = torch.jit.script(self.model).to(self.device) - else: - self.model = self.model.to(self.device) - - # instantiate loss, optimizer, and scheduler - self.optimizer = torch.optim.Adam(self.model.parameters(), lr=cfg.scheduler.lr) - self.scheduler = torch.optim.lr_scheduler.CosineAnnealingLR( - self.optimizer, - T_max=cfg.training.epochs, - eta_min=cfg.scheduler.lr * cfg.scheduler.lr_decay, - ) - self.scaler = GradScaler('cuda') - - # load checkpoint - self.epoch_init = load_checkpoint( - os.path.join(cfg.checkpoints.ckpt_path, cfg.checkpoints.ckpt_name), - models=self.model, - optimizer=self.optimizer, - scheduler=self.scheduler, - scaler=self.scaler, - device=self.device, - ) - - self.cfg = cfg - - def backward(self, loss): - """ - Perform backward pass. - - Arguments: - loss: loss value. - - """ - # backward pass - if self.cfg.performance.amp: - self.scaler.scale(loss).backward() - self.scaler.step(self.optimizer) - self.scaler.update() - else: - loss.backward() - self.optimizer.step() - - def train(self, graph, metadata): - """ - Perform one training iteration over one graph. The training is performed - over multiple timesteps, where the number of timesteps is specified in - the 'stride' parameter. - - Arguments: - graph: the desired graph. - - Returns: - loss: loss value. - - """ - graph = graph.to(self.device, non_blocking=True) - globals = metadata['globals'].to(self.device, non_blocking=True) - label = metadata['label'].to(self.device, non_blocking=True) - weight = metadata['weight'].to(self.device, non_blocking=True) - - self.optimizer.zero_grad() - pred = self.model(graph.ndata["features"], graph.edata["features"], globals, graph, metadata) - loss = metrics.weighted_bce(pred, label, weights=weight) - self.backward(loss) - return loss.detach() - - @torch.no_grad() - def eval(self): - """ - Evaluate the model on one batch. - - Args: - graph (DGLGraph): The input graph. - label (Tensor): The target labels. - - Returns: - loss (Tensor): The computed loss value (scalar). - """ - predictions = [] - labels = [] - weights = [] - - for graph, metadata in self.valloader: - - graph = graph.to(self.device, non_blocking=True) - globals = metadata['globals'].to(self.device, non_blocking=True) - label = metadata['label'].to(self.device, non_blocking=True) - weight = metadata['weight'].to(self.device, non_blocking=True) - - pred = self.model(graph.ndata["features"], graph.edata["features"], globals, graph, metadata) - predictions.append(pred) - labels.append(label) - weights.append(weight) - - predictions = torch.cat(predictions, dim=0) - labels = torch.cat(labels, dim=0) - weights = torch.cat(weights, dim=0) - - loss = metrics.weighted_bce(predictions, labels, weights=weights) - - # Convert logits to probabilities - prob = torch.sigmoid(predictions) - - # Flatten to 1D arrays - prob_flat = prob.detach().to(torch.float32).cpu().numpy().flatten() - labels_flat = labels.detach().to(torch.float32).cpu().numpy().flatten() - - # Calculate AUC - try: - auc = metrics.roc_auc_score(labels_flat, prob_flat) - except ValueError: - auc = float('nan') # Not enough classes present for AUC - - return loss, auc - -@hydra.main(version_base=None, config_path="./configs/", config_name="tHjb_CP_0_vs_45") -def do_training(cfg: DictConfig): - """ - Perform training over all graphs in the dataset. - - Arguments: - cfg: Dictionary of parameters. - - """ - random.seed(cfg.random_seed) - np.random.seed(cfg.random_seed) - torch.manual_seed(cfg.random_seed) - - # initialize distributed manager - DistributedManager.initialize() - dist = DistributedManager() - - # initialize loggers - os.makedirs(cfg.checkpoints.ckpt_path, exist_ok=True) - logger = PythonLogger("main") - logger.file_logging(os.path.join(cfg.checkpoints.ckpt_path, "train.log")) - - # initialize trainer - trainer = MGNTrainer(logger, cfg, dist) - - if dist.distributed: - ddps = torch.cuda.Stream() - with torch.cuda.stream(ddps): - trainer.model = DistributedDataParallel( - trainer.model, - device_ids=[dist.local_rank], # Set the device_id to be - # the local rank of this process on - # this node - output_device=dist.device, - broadcast_buffers=dist.broadcast_buffers, - find_unused_parameters=dist.find_unused_parameters, - ) - torch.cuda.current_stream().wait_stream(ddps) - - # training loop - start = time.time() - logger.info("Training started...") - for epoch in range(trainer.epoch_init, cfg.training.epochs): - - # Training - train_loss = [] - for graph, metadata in tqdm(trainer.trainloader, desc=f"epoch {epoch} trianing"): - trainer.model.train() - loss = trainer.train(graph, metadata) - train_loss.append(loss.item()) - - val_loss, val_auc = trainer.eval() - - train_loss = torch.tensor(train_loss).mean() - - logger.info( - f"epoch: {epoch}, loss: {train_loss:10.3e}, val_loss: {val_loss:10.3e}, val_auc = {val_auc:10.3e}, time per epoch: {(time.time()-start):10.3e}" - ) - - # save checkpoint - save_checkpoint( - os.path.join(cfg.checkpoints.ckpt_path, cfg.checkpoints.ckpt_name), - models=trainer.model, - optimizer=trainer.optimizer, - scheduler=trainer.scheduler, - scaler=trainer.scaler, - epoch=epoch, - ) - start = time.time() - trainer.scheduler.step() - logger.info("Training completed!") - - -""" - Perform training over all graphs in the dataset. - - Arguments: - cfg: Dictionary of parameters. - - """ -if __name__ == "__main__": - do_training() \ No newline at end of file diff --git a/legacy/physicsnemo/utils.py b/legacy/physicsnemo/utils.py deleted file mode 100644 index bbbdb423dd993b19ca69a3f5c648ad2bd49b46c9..0000000000000000000000000000000000000000 --- a/legacy/physicsnemo/utils.py +++ /dev/null @@ -1,11 +0,0 @@ -import importlib -from types import SimpleNamespace - -def build_from_module(cfg): - modname = cfg['module'] - classname = cfg['class'] - args = cfg['args'] - module = importlib.import_module(modname) - model_cls = getattr(module, classname) - cfg_obj = SimpleNamespace(**args) - return model_cls(cfg_obj) \ No newline at end of file diff --git a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-data-preparation/SKILL.md b/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-data-preparation/SKILL.md deleted file mode 100644 index dcd60838fae35053959274e20fd2b6ba344f6e00..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-data-preparation/SKILL.md +++ /dev/null @@ -1,202 +0,0 @@ ---- -name: root-gnn-dgl-data-preparation -description: Use when the user asks to build graphs or prebatched .bin files, rerun failed data prep, verify missing graph chunks, or use scripts/prep_data.py, scripts/check_dataset_files.py, or jobs/prep_data/prep_data.sh before training in root_gnn_dgl. ---- - -# root-gnn-dgl-data-preparation - -Use this skill for graph creation and graph-readiness checks before training. - -## Fast parallel graph creation - -For the Delphes baseline configs, use the bounded launcher rather than -`jobs/prep_data/run_processing.py` or a hand-written unbounded process loop: - -```bash -python jobs/prep_data/parallel_prep.py \ - configs/delphes/*_baseline.yaml \ - --phase raw \ - --workers 8 -``` - -The launcher runs one subprocess per graph chunk, with a bounded worker pool. -The graph-building path streams ROOT entries for the requested chunk, so -parallel workers do not each materialize the complete input ROOT file. -Start with 8 workers per CPU session; 16 is reasonable when memory and I/O -are healthy. Do not equate the number of workers with all available CPUs: -filesystem contention and per-process graph memory generally become the -bottleneck first. Set numerical-library thread counts to one before launch: - -```bash -export OMP_NUM_THREADS=1 -export MKL_NUM_THREADS=1 -export OPENBLAS_NUM_THREADS=1 -export NUMEXPR_NUM_THREADS=1 -``` - -For two independent CPU sessions, split the task list without overlap: - -```bash -# Session 1 -python jobs/prep_data/parallel_prep.py configs/delphes/*_baseline.yaml \ - --phase raw --split 1/2 --workers 16 - -# Session 2 -python jobs/prep_data/parallel_prep.py configs/delphes/*_baseline.yaml \ - --phase raw --split 2/2 --workers 16 -``` - -Run prebatching only after both raw phases finish: - -```bash -python jobs/prep_data/parallel_prep.py configs/delphes/*_baseline.yaml \ - --phase shuffle --split 1/2 --workers 8 --buffer-size 1 -python jobs/prep_data/parallel_prep.py configs/delphes/*_baseline.yaml \ - --phase shuffle --split 2/2 --workers 8 --buffer-size 1 -``` - -`--split PART/TOTAL` partitions dataset tasks, not events. Use the same -config glob and split value in both sessions. Run only baseline configs for -graph creation; finetuning configs share the same processed data directories. - -## Primary entry point - -Run from the repo root: - -```bash -python scripts/prep_data.py --config --dataset --chunk -``` - -Use `--shuffle_mode` when you want preshuffled, prebatched graph files for training: - -```bash -python scripts/prep_data.py --config --dataset --shuffle_mode --chunk -``` - -## Chunk and memory semantics - -- `args.chunks` is the number of ordinary raw graph `.bin` files. It controls - the size of each graph-creation task and must match the configs used later - by training. -- `shuffle_chunks` is the number of shuffled/prebatched output partitions. -- `buffer_size` is the number of raw graph `.bin` chunks cached in memory by a - lazy dataset during shuffling. It does not need to be less than `chunks`, - but use `1` (or `2`) for memory-constrained runs. -- Reducing `chunks` makes each raw task larger; it usually increases, rather - than reduces, per-worker memory. Change it consistently in baseline and - finetuning configs, and do not mix old cache files from a different chunk - layout. -- For Delphes configs, the repository currently uses `chunks: 10` and - `shuffle_chunks: 10`. - -The old `jobs/prep_data/prep_data.sh` wrapper is sequential and previously -ran chunk 0 twice. Prefer `parallel_prep.py`; if the wrapper is needed, it -now runs each requested chunk once. - -## Recommended single-dataset run pattern - -- Read dataset names from `config["Datasets"]`. -- Read the chunk count from each dataset's `args.chunks`. -- For a single raw chunk, run the command without `--shuffle_mode`. -- Add `--shuffle_mode` only after the ordinary graph chunks exist. - -Example pattern: - -```bash -python scripts/prep_data.py --config --dataset --chunk 0 -python scripts/prep_data.py --config --dataset \ - --shuffle_mode --chunk 0 --buffer_size 1 -``` - -Use the repo wrapper when you want the standard loop: - -```bash -bash jobs/prep_data/prep_data.sh [extra_args] -``` - -## Important flags and caveats - -- `--shuffle_mode` creates the prebatched artifacts consumed by `scripts/training_script.py --preshuffle`. -- `scripts/prep_data.py` accepts `--buffer_size` and `--shuffle_chunks` as - runtime overrides; changing `--shuffle_chunks` changes output filenames, - so update training configs before using that override for production. -- `--drop_last` is inverted by the CLI definition: passing the flag sets `drop_last=False`. -- Dataset configs can override training batch size during prebatching with a dataset-level `batch_size`. -- The README says a `list index out of range` after graph saving is currently expected in some prep runs. Treat it as non-fatal if the output `.bin` files were written successfully. - -## Dataset selections - -Datasets may define event selections at the dataset level: - -```yaml -Datasets: - signal: - args: - ... - selections: - - [n_jets, 4, ">="] - - "met_met_NOSYS > 30000" -``` - -Selection behavior: - -- Selections are applied during data prep before graph chunking. -- `scripts/prep_data.py` prints a cutflow for each dataset before processing. -- The streaming optimization applies to the no-selection Delphes path. Configs - with selections still use the legacy full-array selection path and should - be tested with one worker before parallelizing. -- Tuple/list selections use `[branch, cut, op]`, where `op` can be `>`, `>=`, `<`, `<=`, `==`, or `!=`. -- String selections are evaluated against loaded ROOT branches, so referenced branch names must exist. -- Selection branches are added automatically to the branch list through `selection_branches()`. -- Empty or omitted `selections` means all events pass. -- If a selection references vector branches, verify the result is one boolean per event; jagged per-object masks will not index event arrays correctly. - -## Audit the outputs - -Run from the repo root: - -```bash -python scripts/check_dataset_files.py --configs stats_100K/pretraining_multiclass.yaml -``` - -The `--configs` argument must be a comma-separated list of paths relative to `configs/`. - -This checker validates: - -- chunk files named `${dataset}_${chunk}.bin` -- prebatched fold files named `${dataset}_prebatched_padded_${i}_n_${n_folds}_f_${foldlist}.bin` - -Use rerun mode to repair missing artifacts: - -```bash -python scripts/check_dataset_files.py --configs stats_100K/pretraining_multiclass.yaml --rerun -``` - -For bulk prep over every dataset in one or more configs, use the bounded -launcher above. Avoid the legacy bulk helper for large Delphes files because -it can start too many full-file readers. - -The legacy helper is: - -```bash -python jobs/prep_data/run_processing.py configs/run_3_ttH/scratch.yaml configs/run_3_ttH/finetuning.yaml -``` - -This calls `jobs/prep_data/prep_data.sh` for each dataset using the dataset-level `shuffle_chunks` value. - -Treat data prep as ready only if: - -- every required chunk file exists -- every required prebatched fold file exists when training will use `--preshuffle` -- save paths match the config -- any post-save `IndexError` did not prevent the files from being written - -If stopping a Slurm run, prefer cancelling the whole allocation: - -```bash -scancel "$SLURM_JOB_ID" -``` - -Completed `.bin` files remain on disk, but inspect files being written at the -time of cancellation before restarting; a partially written file may exist -and be mistaken for a valid cache. diff --git a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-env-setup/SKILL.md b/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-env-setup/SKILL.md deleted file mode 100644 index 019d6834098b8dd05141b02591c50dac6f017d84..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-env-setup/SKILL.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -name: root-gnn-dgl-env-setup -description: Use when the user asks to set up or validate the root_gnn_dgl runtime, such as running conda setup from setup/environment.yml, setup/test_setup.py, import ROOT checks, podman-hpc image setup, or the interactive allocation scripts in jobs/ before data prep, training, or inference. ---- - -# root-gnn-dgl-env-setup - -Use this skill from the repo root before any stage run. - -## Choose the runtime - -- Use the conda environment in `setup/environment.yml` for `scripts/inference.py`. The repo README says inference needs PyROOT, and the podman image does not include ROOT. -- Use the `podman-hpc` image `joshuaho/pytorch:1.0` for training on Perlmutter when you want the containerized path. -- For parallel inference, make sure `mpi4py` is available. The README notes it is not listed in the conda environment requirements; `setup/Dockerfile` installs it in the container image. - -## Conda path - -```bash -cd setup -conda env create -f environment.yml -conda activate pytorch -cd .. -python setup/test_setup.py -python -c "import ROOT" -``` - -Run `setup/test_setup.py` from the repo root. It appends the current working directory to `sys.path` and checks imports in `scripts`, `root_gnn_base`, and `models`. - -## Podman path - -```bash -podman-hpc pull docker.io/joshuaho/pytorch:1.0 -``` - -Or build locally: - -```bash -cd setup -source build_image.sh -``` - -The helper `setup/launch_image.sh` mounts `/pscratch/sd/j/joshuaho/` and `/global/cfs/projectdirs/atlas/joshua/` into the container and then runs the given entrypoint. - -## Interactive allocations - -- `source jobs/interactive.sh` for one shared interactive GPU node. -- `source jobs/cpu.sh` for a CPU allocation that suits large prep loops. -- `source jobs/salloc.sh` for a multi-node GPU allocation. - -## Runtime audit - -- Use `nvidia-smi` before training on login or interactive nodes to confirm memory availability. -- Validate the basic repo imports with `python setup/test_setup.py`. -- Validate PyROOT explicitly with `python -c "import ROOT"`. -- For parallel inference, also validate `python -c "from mpi4py import MPI"`. -- Some repo scripts hard-code NERSC-style paths under `/global/cfs/projectdirs/atlas/joshua/...`. If running elsewhere, fix those paths before assuming the environment is valid. - -Treat environment setup as passing only if: - -- imports succeed -- the chosen runtime matches the stage you plan to run -- required site-specific paths exist -- GPU or CPU resources are actually available for the intended stage diff --git a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-inference/SKILL.md b/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-inference/SKILL.md deleted file mode 100644 index 42705440485124252f0ad018356abd9399c546db..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-inference/SKILL.md +++ /dev/null @@ -1,133 +0,0 @@ ---- -name: root-gnn-dgl-inference -description: Use when the user asks to score ROOT files, add GNN score branches, launch MPI inference, or verify inference outputs in root_gnn_dgl, including scripts/inference.py, jobs/inference/run_inference.py, ROOT branch checks, and NPZ or ROOT output audits. ---- - -# root-gnn-dgl-inference - -Use this skill to score ntuples with trained models and verify the outputs. - -## Environment - -- Run inference in an environment with PyROOT available. -- The repo README says the conda environment is required for inference because the podman training image does not include ROOT. - -## Entry point - -Run from the repo root: - -```bash -python scripts/inference.py \ - --target \ - --destination \ - --config \ - --branch_name \ - --chunks 1 \ - --chunkno 0 \ - --write -``` - -## Multi-model inference - -The script accepts multiple configs and multiple branch names in one run: - -```bash -python scripts/inference.py \ - --target \ - --destination \ - --config config_a.yaml config_b.yaml \ - --branch_name score_a score_b \ - --chunks 1 \ - --chunkno 0 \ - --write -``` - -The number of configs and branch names must match. - -## Checkpoint selection - -- With the default `--ckpt -1`, the script selects the best epoch from `training.log` using `--var` and `--mode`. -- Use `--ckpt ` to force a specific checkpoint. -- If `--destination` is omitted, the script writes under `/inference/`. - -## Output modes - -- `--write` creates a new ROOT file and adds score branches. -- Without `--write`, the script saves an `.npz` bundle containing scores, labels, and tracking info. -- Use `--clobber` when reusing an existing destination path. - -## Parallel inference - -Use the generic MPI/local wrapper for many files or many models: - -```bash -mpirun -np python jobs/inference/run_inference.py \ - --sample-config \ - --config-dir \ - --output-dir \ - --write -``` - -Useful variants: - -```bash -python jobs/inference/run_inference.py --target '' --config model.yaml --output-dir scores --write -python jobs/inference/run_inference.py --sample-config samples.yaml --config model_a.yaml model_b.yaml --branch-name score_a score_b --output-dir scores --write -python jobs/inference/run_inference.py --sample-config samples.yaml --config-dir configs/run_3_ttH --output-dir scores --write --test -``` - -Wrapper behavior: - -- `--sample-config` discovers target ROOT files from every dataset's `args.raw_dir` and `args.file_names`. -- `--target` accepts explicit files or glob patterns. -- `--config-dir` discovers model configs from `*.yaml`; `--config` accepts explicit config files. -- Branch names default to each model config's `Training_Name` plus `_score`. -- `--branch-name` may override branch names, but the count must match the config count. -- `--test` prints the planned `scripts/inference.py` commands without running them. -- With MPI, tasks are split by target file across ranks; without MPI it runs serially. -- GPU assignment is local rank modulo 4 through `CUDA_VISIBLE_DEVICES`. - -## Repo-specific behavior - -- The first config's first dataset is used as the template dataset. The script rewrites `raw_dir`, `file_names`, `save_dir`, `chunks`, `process_chunks`, and optionally `tree_name` at runtime. -- Pass `--tree ` if the ROOT tree name differs from the config default. -- Chunked inference writes per-chunk outputs; merging those outputs is a separate step. -- Job wrappers should derive the repo root from their own path; avoid adding hard-coded checkout paths. - -## Audit the outputs - -Start with basic runtime evidence if you have a log: - -- `Writing to file` -- `Input entries:` -- `Output entries:` -- `Wrote scores to` -- absence of `Traceback` - -For ROOT outputs, prefer `uproot`: - -```bash -python - <<'PY' -import numpy as np -import uproot -path = "" -branches = [""] -tree = uproot.open(path)["output"] -print("entries", tree.num_entries) -for branch in branches: - arr = tree[branch].array(library="np") - print(branch, len(arr), np.isnan(arr).sum(), float(np.nanmin(arr)), float(np.nanmax(arr)), float(np.nanmean(arr))) -PY -``` - -Treat inference as valid only if: - -- the destination file exists -- every requested score branch exists -- output entry count matches the input tree -- score arrays contain no NaNs -- score arrays are not constant - -For multi-model inference, every branch must exist and branch statistics should usually differ unless the models are intentionally identical. - -Without `--write`, inspect the `.npz` keys `scores`, `labels`, and `tracking_info` and verify array lengths and NaN counts. diff --git a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-plotting/SKILL.md b/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-plotting/SKILL.md deleted file mode 100644 index de2c79e2e5a0b919d0f4df2f6bb12d53a9183a43..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-plotting/SKILL.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -name: root-gnn-dgl-plotting -description: Use when the user asks to plot training curves, regenerate training.png, build the sweep PDF from plotting/training_performance.py, compare training runs, or extract Loss, Accuracy, Test_Loss, Test_AUC, and timing information from training.log files in root_gnn_dgl. ---- - -# root-gnn-dgl-plotting - -Use this skill when the task is about plots or metrics derived from `training.log`. - -## Single-run plot regeneration - -The training script can regenerate the per-run PNG directly: - -```bash -python scripts/training_script.py --config --plot -``` - -That uses `root_gnn_base.utils.read_log()` and `root_gnn_base.utils.plot_log()` to rebuild `training.png` from `Training_Directory/training.log`. - -`plot_log()` produces a 2x2 figure with: - -- cumulative time in seconds -- train and test loss -- accuracy -- test AUC - -Be aware that `plot_log()` fixes the accuracy axis to `(0.44, 0.56)`, which may be too narrow for some runs. - -## Sweep-level plotting - -Use the dedicated plotting script when the user wants a PDF comparing shipped sweeps: - -```bash -python plotting/training_performance.py -python plotting/training_performance.py --output -``` - -The script currently plots two config groups: - -- `pretraining` -- `higgs_production` - -It writes one PDF page per group and resolves each run's `Training_Directory` from its config. - -## What the plotting script reads from training.log - -`plotting/training_performance.py` parses rows that start with `Epoch` and extracts: - -- `Epoch` -- `Loss` -- `Accuracy` -- `Test_Loss` -- `Test_AUC` -- `Time` - -It also computes cumulative time in hours. - -Baseline runs are drawn as lines. Non-baseline sweep variants are drawn as point clouds and labeled by the parameter change relative to the baseline. - -## Audit the log before plotting - -Treat plotting input as valid only if: - -- `training.log` exists -- it contains at least one valid `Epoch ...` row -- parsed metric arrays are finite -- the referenced `Training_Directory` actually exists - -If the plotting script fails, inspect the log directly: - -```bash -sed -n '1,40p' /training.log -tail -n 25 /training.log -``` - -## When to use which plot path - -- Use `--plot` on `scripts/training_script.py` when the user wants the repo's standard per-run `training.png`. -- Use `plotting/training_performance.py` when the user wants a cross-run PDF for the built-in sweep groups. -- If the user wants custom comparisons outside the built-in groups, start from the parsing logic in `plotting/training_performance.py` and the metric schema in `training.log`. diff --git a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-training/SKILL.md b/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-training/SKILL.md deleted file mode 100644 index 167ef8626ae125136731463b028554c2f73812e7..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-training/SKILL.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -name: root-gnn-dgl-training -description: Use when the user asks to train, finetune, resume, submit, queue-check, log-check, or validate training runs in root_gnn_dgl, including scripts/training_script.py, sqs, jobs/slurm/.out, training.log, checkpoints, and scripts/generate_multiclass_finetuning_configs.py. ---- - -# root-gnn-dgl-training - -Use this skill for any training stage in the repo, from launch through monitoring and artifact review. - -## Run locally - -Run from the repo root: - -```bash -python scripts/training_script.py --config --preshuffle --nocompile --lazy -``` - -This matches the README, `run_demo.sh`, and the podman job wrappers. - -## Why these defaults - -- `--preshuffle` uses the saved prebatched graph files created during data prep. -- `--nocompile` is recommended by the README because compiled mode requires padded graphs at prep time. -- `--lazy` matches the common dataset classes used by the shipped configs. - -## Common runtime modes - -- `--restart` starts from scratch instead of resuming from the last checkpoint. -- Without `--restart`, the script resumes from the last `model_epoch_.pt` it finds in `Training_Directory`. -- `--evaluate ` skips training and evaluates a specific checkpoint. -- `--plot` regenerates `training.png` from `training.log`. -- `--directory ` appends a suffix to `Training_Directory`. -- `--cpu`, `--multigpu`, `--multinode`, `--statistics`, `--seed`, and `--abs` are available when needed. - -## Run multiple local trainings - -Use the single-node launcher when queueing many config files on the current node: - -```bash -python jobs/training/run_parallel_trainings.py --split -``` - -Useful examples: - -```bash -python jobs/training/run_parallel_trainings.py configs/run_3_ttH --split 2/2 -python jobs/training/run_parallel_trainings.py configs/run_3_ttH --split 2/2 --test -``` - -Launcher behavior: - -- Discovers `.yaml` files from each target directory, or accepts explicit config files. -- Uses fixed local GPU slots `0,1,2,3` via `CUDA_VISIBLE_DEVICES`. -- Runs `scripts/training_script.py --config --preshuffle --nocompile --lazy`. -- Forwards unknown args to `training_script.py`, such as `--restart` or `--seed 7`. -- Rejects configs with duplicate `Training_Directory` values. -- `--split K/N` selects configs by deterministic index modulo `N`; use `--split 1/2` and `--split 2/2` for two complementary halves. -- `--test` prints the launch plan without starting training. -- Logs go under `jobs/slurm/parallel_training_logs//`. - -## Submit on Perlmutter - -Prefer the podman path: - -```bash -sbatch jobs/training/podman/run_job.sh -``` - -The job wrappers derive the repo root from their own location. `jobs/training/podman/submit.sh` and `jobs/training/conda/submit.sh` accept config paths as arguments; without arguments they run their built-in default sweeps. Set `SLURM_ACCOUNT` when the cluster requires an account: - -```bash -SLURM_ACCOUNT=atlas sbatch jobs/training/podman/run_job.sh configs/run_3_ttH/scratch.yaml -bash jobs/training/podman/submit.sh configs/run_3_ttH/scratch.yaml configs/run_3_ttH/finetuning.yaml -``` - -For the conda wrapper, set `ROOT_GNN_CONDA_ENV` if the environment is not named `dgl`. - -For distributed training, pass `--multinode` and launch under an environment that sets `RANK`, `LOCAL_RANK`, and `WORLD_SIZE`. - -## Preconditions - -- If you use `--preshuffle`, run data preparation first and confirm the graph artifacts exist. -- For finetuning configs, verify that `Model.args.pretraining_path` points to an existing checkpoint before launching training. -- For multinode runs, pass `--multinode` and launch under the relevant distributed job environment. - -## Monitor queue and logs - -Check queue state: - -```bash -sqs -u "$USER" -sqs -u "$USER" | rg "" -``` - -Useful interpretations: - -- `PD` means pending -- `R` means running -- `START_TIME N/A` with reason `Priority` means queued normally, not broken - -Once a job has a `JOBID`, inspect: - -```bash -sed -n '1,80p' jobs/slurm/.out -tail -n 80 jobs/slurm/.out -rg -n "Traceback|Error|Exception|Epoch|Epoch Done|Early Termination|Done" jobs/slurm/.out -``` - -Healthy training logs usually show: - -- the `Executing: python -u ... scripts/training_script.py ...` line -- dataset cache loads -- repeated `Epoch ... | LR ... | Loss ... | Accuracy ... | Test_Loss ... | Test_AUC ... | Time ... s` -- `Epoch Done.` -- `Num batches trained = ...` -- valid completion via `Done`, sometimes after `Early Termination at Epoch ...` - -Early stopping is a normal completion mode in this repo. - -## Audit training artifacts - -Training writes into `Training_Directory`: - -- `config.yaml` -- `model_epoch_.pt` -- `model_epoch_.npz` -- `training.log` -- `training.png` - -Primary checks: - -```bash -sed -n '1,40p' /training.log -tail -n 25 /training.log -``` - -Treat the run as healthy only if: - -- epoch numbers increase monotonically -- `Loss`, `Test_Loss`, and `Test_AUC` stay finite -- the latest logged epoch has a matching `model_epoch_.pt` -- the run produced real epoch rows rather than stopping before training started - -If `training.log` grows but checkpoints stop appearing, suspect a save-path or filesystem issue. - -Use `python plotting/training_performance.py` or the `root-gnn-dgl-plotting` skill when you want consolidated sweep-level PDFs instead of a single-run `training.png`. - -## Generate finetuning configs - -Use this when you want to derive `configs/higgs_production/multiclass_finetuning/*.yaml` from completed multiclass pretraining runs: - -```bash -python scripts/generate_multiclass_finetuning_configs.py -``` - -Before using the generated configs, verify that the chosen best-epoch checkpoint paths still exist. diff --git a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-workflow/SKILL.md b/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-workflow/SKILL.md deleted file mode 100644 index 26d40bebf5c1751025c8ad421883e70a6a892b16..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/.codex/skills/root-gnn-dgl-workflow/SKILL.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -name: root-gnn-dgl-workflow -description: Use when the user asks to run or review the full root_gnn_dgl workflow, such as run_demo.sh, a full pretraining-to-finetuning-to-inference campaign, or a stage-by-stage pass, warning, fail audit across environment setup, data preparation, training, inference, and outputs. ---- - -# root-gnn-dgl-workflow - -Use this skill when the user wants an end-to-end workflow rather than a single isolated stage. - -## Shipped demo - -Run from the repo root: - -```bash -source run_demo.sh -``` - -The demo does: - -1. graph prep for multiclass pretraining -2. multiclass pretraining -3. graph prep for binary classification -4. from-scratch binary training -5. finetuned binary training -6. inference with two output score branches - -## Before running the workflow - -- Check GPU availability with `nvidia-smi` or request an interactive node with `jobs/interactive.sh`. -- Confirm the target data and output directories in `run_demo.sh` exist and are writable. -- Confirm `configs/stats_100K/finetuning_ttH_CP_even_vs_odd.yaml` points at the checkpoint you actually want to finetune from. - -## Workflow audit order - -When reviewing a campaign, check stages in this order: - -1. environment readiness -2. data-prep outputs -3. training submission and queue state -4. training logs and checkpoints -5. inference outputs - -Use the retained stage skills for each check: - -- `root-gnn-dgl-env-setup` -- `root-gnn-dgl-data-preparation` -- `root-gnn-dgl-training` -- `root-gnn-dgl-inference` - -## Output style - -Return a short status for each stage: - -- `pass`: evidence is consistent with a healthy stage -- `warning`: stage likely worked but still needs a follow-up check -- `fail`: concrete blocker or corrupted or missing artifact found - -Repo-specific workflow blockers: - -- pending jobs in `sqs` with `Priority` are waiting, not failed -- missing prebatched `.bin` files block `--preshuffle` training -- missing `pretraining_path` blocks finetuning -- ROOT outputs without the requested score branches are inference failures even if the file exists - -## When to adapt instead of sourcing the demo - -- If you only want one stage, call the underlying prep, training, or inference script directly. -- If dataset paths, branch names, or chunk counts differ, copy the command pattern from `run_demo.sh` and adjust the values instead of editing the demo in place. diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/config.yaml b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/config.yaml deleted file mode 100755 index 1370d23875c785ac41bafb8011bb4324f761cca7..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/config.yaml +++ /dev/null @@ -1,319 +0,0 @@ -Datasets: - SingleT_schan: - args: - buffer_size: 11 - chunks: 100 - file_names: SingleT_schan.root - fold_var: Number - label: 8 - name: SingleT_schan - node_branch_names: &id001 - - - jet_pt - - ele_pt - - mu_pt - - ph_pt - - MET_met - - - jet_eta - - ele_eta - - mu_eta - - ph_eta - - 0 - - - jet_phi - - ele_phi - - mu_phi - - ph_phi - - MET_phi - - CALC_E - - - jet_btag - - 0 - - 0 - - 0 - - 0 - - - 0 - - ele_charge - - mu_charge - - 0 - - 0 - - NODE_TYPE - node_branch_types: &id002 - - vector - - vector - - vector - - vector - - single - node_feature_scales: &id003 - - 1e-1 - - 1 - - 1 - - 1e-1 - - 1 - - 1 - - 1 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: &id004 - n_folds: 10 - test: - - 0 - - 1 - train: - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - VBF: - args: - buffer_size: 11 - chunks: 100 - file_names: VBF_NLO_inc.root - fold_var: Number - label: 3 - name: VBF - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - WH: - args: - buffer_size: 11 - chunks: 100 - file_names: WH_NLO_inc.root - fold_var: Number - label: 4 - name: WH - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ZH: - args: - buffer_size: 11 - chunks: 100 - file_names: ZH_NLO_inc.root - fold_var: Number - label: 5 - name: ZH - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ggF: - args: - buffer_size: 11 - chunks: 100 - file_names: ggF_NLO_inc.root - fold_var: Number - label: 2 - name: ggF - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - tHjb: - args: - buffer_size: 11 - chunks: 100 - file_names: tHjb_NLO_inc.root - fold_var: Number - label: 1 - name: tHjb - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ttH: - args: - buffer_size: 11 - chunks: 100 - file_names: ttH_NLO_inc.root - fold_var: Number - label: 0 - name: ttH - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ttW: - args: - buffer_size: 11 - chunks: 100 - file_names: ttW.root - fold_var: Number - label: 10 - name: ttW - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ttbar: - args: - buffer_size: 11 - chunks: 100 - file_names: ttbar.root - fold_var: Number - label: 9 - name: ttbar - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ttt: - args: - buffer_size: 11 - chunks: 100 - file_names: ttt.root - fold_var: Number - label: 11 - name: ttt - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - tttt: - args: - buffer_size: 11 - chunks: 100 - file_names: tttt.root - fold_var: Number - label: 7 - name: tttt - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ttyy: - args: - buffer_size: 11 - chunks: 100 - file_names: ttyy.root - fold_var: Number - label: 6 - name: ttyy_ch - node_branch_names: *id001 - node_branch_types: *id002 - node_feature_scales: *id003 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_pretraining_multiclass_12_process/ - tree_name: output - weight_var: weight - class: LazyDataset - folding: *id004 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 -Loss: - args: {} - class: CrossEntropyLoss - finish: - args: - dim: 1 - class: Softmax - module: torch.nn - module: torch.nn -Model: - args: - dropout: 0 - hid_size: 64 - in_size: 7 - n_layers: 4 - n_proc_steps: 4 - out_size: 12 - class: Edge_Network - module: models.GCN -Training: - batch_size: 1024 - epochs: 100 - gamma: 0.99 - learning_rate: 0.0001 -Training_Directory: trainings/pretraining_multiclass/multiclass_12_process/ -Training_Name: multiclass_12_process diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_0.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_0.pt deleted file mode 100755 index 1cccd0def27edb421627fa33e0311c070fa159b7..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_0.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f13357759bae5ee14a4dd682fe867c09381aed0842ed712b0c12770aa621dd44 -size 1707210 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_1.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_1.pt deleted file mode 100755 index 5befaa60c0dd42423084cb15dadaeca4bea39806..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_1.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9617167a01ee1d11ba2ec03f71440bd4fa25f4fa5f32e72bd9d71f5d10cd11b2 -size 1707210 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_10.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_10.pt deleted file mode 100755 index d0915d92261895dd0d872199028d63b81828fad5..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_10.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5224b15282d60c8f09724904e5a665f27426d81ff577b234d901260050cb97e7 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_11.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_11.pt deleted file mode 100755 index 02fa7cc4dca6658e91b43121c5c635f2af496c1c..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_11.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a2fd4704348456e2a6c9655ee3aa2a9143df3f8394ba0d745207d46af139b558 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_12.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_12.pt deleted file mode 100755 index 4412f37037acc10ce2677203010ea18146926d77..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_12.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6960240dabb5128be0a501077ff952a985295885fbcece663282df40bb8d4584 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_13.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_13.pt deleted file mode 100755 index c20dbd992938bb377fbbe8210b0a76e4ff7d7395..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_13.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c11d6492d985d8f46b3476ed13671a3f9295269c0108dc55f491d7ef8270b901 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_14.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_14.pt deleted file mode 100755 index c654dbaf948b3ce058e44fde00cbaaa5a8ce9aeb..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_14.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:15bfd6edcb5cb2d9176683d13c546cdd2115eda320ddbc9a04b23dba8936d989 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_15.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_15.pt deleted file mode 100755 index 91c377c6afa675b4943a102c1c78ff9172600118..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_15.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5697fbccabb743b9c900a9e7f1e432077879fa4f83db42385e8ad1f597844195 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_16.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_16.pt deleted file mode 100755 index 3a90f37534199dcf5163ebaec6b5abcfea5eae2a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_16.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dc1818c04ee5d17f5cf05e985e69dbabf55e0c1c4c4b7c2cd29939b766350b39 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_17.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_17.pt deleted file mode 100755 index 4e2c83c6b0607758f3281f156cb5fffb172a5082..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_17.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:945575404de1372332c67423b1ea681edd4445e5445a21774d517dec45341c34 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_18.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_18.pt deleted file mode 100755 index 0079811bb18009af693cfd0b3887620cd3e5b2f3..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_18.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7f8e9f611bba22ad5682c44d158de95f76c3dfc2223654a64540f91972c12ed7 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_19.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_19.pt deleted file mode 100755 index b346ae37a0e99786a31bf92e1d057f71cddffe37..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_19.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b1957ba99bf8b1aeb6b5a19a6867433aa86e5658c3abfdb737bc16489ce3d83b -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_2.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_2.pt deleted file mode 100755 index 847b939168c63092237162cab6be265611909ef9..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_2.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:67b72a00c515215745d693f7f62d3a02274c8b702f53d7e68c1b162b0eee44ec -size 1707210 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_20.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_20.pt deleted file mode 100755 index 8a1b493b3d8c0f5058c931fe1935df05d00d5fba..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_20.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:38bd863cfeeb558c586b3c90686de8faf33f08b2675ca93edd4bf8ce63ba62ee -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_21.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_21.pt deleted file mode 100755 index 8d28bfeed081ab54902a1963d5d434d2a00e5511..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_21.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7e90498dffe402581e1e554870b10369c05b45aba7b98a3480422512fbd9832e -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_22.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_22.pt deleted file mode 100755 index c3ee0db50eb8739fc7ea9859c6eaa2ae52d40245..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_22.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a0ea74fb7cfbfa3ebf6908f75fd6d5e018ee307801f608ecdde228d29e666f81 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_23.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_23.pt deleted file mode 100755 index 813ba04d7ff30e13dd9d3bd2a679d697dfd1864f..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_23.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:01d1edadaa1b2ee1a7e7dea46f34c47992c625dac5aa592ce607a75a4aa89170 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_24.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_24.pt deleted file mode 100755 index 42804a503aae74bad3ac797811892b277af5fd0b..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_24.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d8ba9057ffc46f012d10ab5c09c16a441ec4681bff005e61bef33ac928298a0e -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_25.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_25.pt deleted file mode 100755 index 6a4cf8f09e5be383e9be3e61f31495e105a25410..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_25.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1c0b6074ff2fd237eb73612f94b0e9fe4e6ed74522b409cfc326a262edb81739 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_26.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_26.pt deleted file mode 100755 index 57edc95af62a66dc9dc01b6564a819df3090efa9..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_26.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:08c7620306f80b16df74051430adaa6fc4757e15a314eac46a71cf7c8b9f393e -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_27.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_27.pt deleted file mode 100755 index 9e874482a07f16e3ca295e66c5ca7e69b7620d78..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_27.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bd00777e30f340d99367804c520a0a432792cc149fb21299e86c9b9900e4e4de -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_28.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_28.pt deleted file mode 100755 index c5d30bc62a5b16700d34891e63a943cc663ef43b..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_28.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4179f61fcb98c60fd2712cb2e6a1467fc83ddc70331b19b9c720ba81b790dbde -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_29.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_29.pt deleted file mode 100755 index 7a6fcd4c11cb8805aa2f588b4da58c11db637b1f..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_29.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a82de1d53ad4dcde09215da9d94a278d484f58e9ae179c3c12379992ecfc5d86 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_3.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_3.pt deleted file mode 100755 index 4499bf2518ec45be8851885fd1db0d72d653cd40..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_3.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:824dda23baf611b3de75eabf3e85cc09f324957bbc8e5399c8a2f309730557c3 -size 1707210 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_30.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_30.pt deleted file mode 100755 index 52d7a1692695c00be40f2a92a82512d8d51333c2..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_30.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dd872b572b793a5e21c59206c25d655db4784eca3343130f39a6aae729272f3e -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_31.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_31.pt deleted file mode 100755 index 0cfd9fce09e74dd448c160c7160b45adf6896401..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_31.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3b8c20ece0701e7e3a90bb32ab2af634143444662298fdfcc0d3bff5e416320e -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_32.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_32.pt deleted file mode 100755 index cd0d114eab4723e4cff351f7e1a128e710ac4f76..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_32.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2f455a58bfb5a2e4ee9ffeff26b82d88f90ff17d96ee477bbd0870a991cd94a4 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_33.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_33.pt deleted file mode 100755 index fc3050bbeefee6f5fe655c3c5b544e2a6015597a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_33.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d60d6d9d14dac0b18cb5e360d392e5275eb2ae62879aa153b988372548a739f7 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_34.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_34.pt deleted file mode 100755 index fe6a92f0f81e83ca2ab0202fc0864d0db819654b..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_34.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:180c776909a07ea261e5ee287bb0397a73f3b706622f24b3fc2d7799d118b2d9 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_35.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_35.pt deleted file mode 100755 index 3492a170b324282a80bc7b770effa90f420954c0..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_35.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0526e9b114d77695d87c998cdb296b9ba092562bda1203937b9797c0bfd3f4a0 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_36.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_36.pt deleted file mode 100755 index ef277c920b22722e6142646540a5de83ab16e829..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_36.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2a048e5467642275af1d31472202dafa0fb1d76b9d31dbabf3350594ea6638c5 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_37.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_37.pt deleted file mode 100755 index 82984fc806765a50bd2d69d26b45ce9804bc9c1a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_37.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:64753f005246efaa7703a3c42dd41af20360290c6964287a804b48263060fb68 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_38.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_38.pt deleted file mode 100755 index 2d309dd0bdc07a3dca23fd2379424779593f06b7..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_38.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:51a5e7081a9794ca9a30d31a3e4d115790f3c002c76d4ec9b6c9151ee30e1959 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_39.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_39.pt deleted file mode 100755 index f7059b32b05acce91f28266e792a3fafebe21325..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_39.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0de00211875e257b7d5fc84eb05bc7d7811fa342127769d8b7b39262cca0efbc -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_4.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_4.pt deleted file mode 100755 index 6d8f3db11967fe0f93539265258666f414d03b38..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_4.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f800d37e79e3d9bd22ae47efb5f3089c55fc82f84e2503e5fccd163fd072d2f0 -size 1707210 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_40.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_40.pt deleted file mode 100755 index 1f7b8d2ff2d6d95382fda9365912c63c1782bb60..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_40.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:51be6db1707e8d49ea6df923b5ac7f6ffbaa4e2a228f2fc3c54624f2eb74136a -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_41.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_41.pt deleted file mode 100755 index 18b25e2b154b75173ca89c546c27a72bc4f94a61..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_41.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3d21965ac3908046a8af6f5032c20ffd8e33b22442ae05f6ce1e9d592fdb035e -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_42.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_42.pt deleted file mode 100755 index 28c8bcede6442031b2da105d0cd1472161255e4f..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_42.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:964eb93aaa7a05490d1f31a7e70d8514091a555822cee24bd1657ff4f52fc796 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_43.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_43.pt deleted file mode 100755 index 405d6d3a82d801c49885e6a9befe9b1aab397fa9..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_43.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3c4a379e4f5b55c3b1bbeda41c006cce7da055dab4b48d1f97faf835cd495370 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_44.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_44.pt deleted file mode 100755 index ed1a55f2b16b47b586827272669c9966de5ff99d..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_44.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:81b685db8579014076f38a3dbb0ec89c042c697fcd3b3d008994e4fcb13b4528 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_45.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_45.pt deleted file mode 100755 index 8e18f365ad825661fd694c4000ac21537f979302..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_45.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8a5e945caca75699fae347e22164537bf1af73c668f44b9d5001be9a45434d30 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_46.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_46.pt deleted file mode 100755 index de292f4bf482ac352cd034af80e975f6212f8881..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_46.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ddbe65014209fa0a71b55f28bae90da42d36ecf3145ca074daa3f5b30443441e -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_47.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_47.pt deleted file mode 100755 index 55e29d4f873b5b48ae65ae79bbf72646a55a9528..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_47.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:89deaa3de5cc05b87eac0fbfb94a6f34765e56c282ab6ba6e9b635e057cf1afe -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_48.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_48.pt deleted file mode 100755 index bf20f68a3dd537c331e79ee192959a3c30eb6f0d..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_48.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6f6f776731bd62504a2da894a6e628552b714c8d6433e9714868782167327a8c -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_49.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_49.pt deleted file mode 100755 index 49775f1a19b6ebffd01471edb9f17907f7cd03c1..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_49.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d39185a4ae0527343f7a7c41655b8dfebf2cfd5fb05c3fede3513baf3ba656c4 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_5.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_5.pt deleted file mode 100755 index 4c37752abb81fffd02663e790e6801ef7302df74..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_5.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:feff3fb319b0c403dc9fc49d7a58ba3a2fd02441cfd9fe5576925f558389fa00 -size 1707210 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_50.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_50.pt deleted file mode 100755 index b102f7b9707340bcdf93dfd165816310d2e67b25..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_50.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8414856c68ff2505a132993c4a6821893a371b240500eef03a4ae5e96738d4e4 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_51.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_51.pt deleted file mode 100755 index ac888bbf9a4979373ff257a60213842560e67c37..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_51.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:298ee4c7ad2f2c3551d575311ed2843adbc319a5d42662f8a52d7980005c08f2 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_52.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_52.pt deleted file mode 100755 index ad5b2177811130bf6378bb6dc5fd2b3bb57da913..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_52.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b0c6171f4ccd9130879bdd9c0029aa6ad57f160ed4fc79900cfae7853a1cf487 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_53.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_53.pt deleted file mode 100755 index 7c22531fa1d729739b1ea63150fcc88e7dc510b8..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_53.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1ad6ddfbedcf332a87ac87b1def7d37b3de0247e0863d61c615615e2b227a75e -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_54.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_54.pt deleted file mode 100755 index 024baddaa388f1e8a4df4626001036ac5ad1dd23..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_54.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ae3b5fe0a6a0a5c289c0a122f5a68c79862535b8f1ca366c1116436c7915db5c -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_55.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_55.pt deleted file mode 100755 index 294aaba4ee9ee1593827f07a93ee186aed8ff3c4..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_55.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:20688eb442db6737cc37318c76a7128ae4fd79505a470ba36c09bdaffe573c83 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_56.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_56.pt deleted file mode 100755 index eeb79093c131eaa46dc1fbe70839955b0191f54a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_56.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9e3889c446789d532bcc9936232026c5f7c8a3f624ceea4cdda3132389bdc5d2 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_57.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_57.pt deleted file mode 100755 index 8691fe8d9c276b2d825b9cf96dbd92e6ac753c39..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_57.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:89cd230b025bea3c77fa984cea8df8aed91e72ce974bf2e85e8a097cb76c07f0 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_58.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_58.pt deleted file mode 100755 index b270bb3e633eecdb684d24a0209a38c530a276a0..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_58.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:46b69748fbce6aed56e13e9142c3d30f632a4572da19f33b89a7f16d43105e5b -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_59.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_59.pt deleted file mode 100755 index 761410e34ebede1d1b3c8b5cb81f188dcba213b6..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_59.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dd0d983094ffdd377339c1786d042e4f79449f0124ba95c6f1041265bd40d54f -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_6.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_6.pt deleted file mode 100755 index 1fe5e30bca258703dc092187480eedd402128efb..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_6.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4877113b9a0dda418705feb99e0668c488da9118b6d2cad2ddbe212c5c1d0797 -size 1707210 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_60.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_60.pt deleted file mode 100755 index 8ea7bbcc2f856d528d57a4c9cd9d57011205623b..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_60.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:13464c40181b7daf5251a84e38a14474c03135558561ffe677092dfbe7ec8387 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_61.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_61.pt deleted file mode 100755 index 7e088d2e031604043370836bab4f792d24b48383..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_61.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c49038389ce16f886aeec01296aca1a62e1c08fbf7b1e88d2063e08b3d62237b -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_62.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_62.pt deleted file mode 100755 index 594f0efcb4b76ba7504cd6dfd597200f2c758b0d..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_62.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:222ffeb7f9466325f330492bc768e6a3202e26c0f3aa04738600e93d3b4a0392 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_63.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_63.pt deleted file mode 100755 index 888827971352b376ff3c3add47928e3a303c6361..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_63.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9f13a872904cf664c5ad81ab4fadad26c5c51b716385c9742a1c52268c8ae118 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_64.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_64.pt deleted file mode 100755 index 26267f88ac8e3ba1d5b628beaea78d1c42442d8b..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_64.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5d213c0b475bd54aa8e3714ef6a15a8d2768239bb8531824c95939bf8825b18a -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_65.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_65.pt deleted file mode 100755 index 7bf2363326cda4e1bdef4ca8a542f49b3433c3f0..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_65.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:172f4ce8a4f794ed2c4e6b80ea69d32436f7b263cc0ab090bb1dfdebe1b22b18 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_66.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_66.pt deleted file mode 100755 index 547bb0c251e49633f87d2b8891bbc156b4628d6c..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_66.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:50a3f94d433cef8ad9624e0af89b6bb8869ddf7af61e86b00231065c49d19322 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_67.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_67.pt deleted file mode 100755 index 1c9b25c8a07fb32a4462625af5999d87a1221ec4..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_67.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1e01c366ea60ff5b91e24ba82f1fb91f04f2b6741468a78eabb1b08fa30e1b74 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_68.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_68.pt deleted file mode 100755 index c0e3054373b76e9b283e846680bef385d3e4b014..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_68.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8955dbd9032aa10679c2182892bc6377ea52bfef5951ab569e67d57b2226c126 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_69.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_69.pt deleted file mode 100755 index 149615e138ad25b50cc20a782e058458047167b2..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_69.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7cd88340b42715aa31ec38774e0d1a8c96c68a8854b11e093dac619ea7423db7 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_7.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_7.pt deleted file mode 100755 index 592ff0544d7d1e2d50bf198989bec2958287177a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_7.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:811001ddeb217631289f7093d87a8600066a01d9b5cc9bfdf004d978a9a17fd7 -size 1707210 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_70.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_70.pt deleted file mode 100755 index dd40b8c5c2c3f7cc3a706f98bf6f2353c3bfea75..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_70.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6c24753f14abefaf1062084242a0ae6dc74a2541dd4bca8ad6acd7f018536dfa -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_71.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_71.pt deleted file mode 100755 index 4c2025ee7cbd748ae0080a2b5648c4b1e17c9f3d..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_71.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f382f9f8b2d8c09b896657d397985f9149f018fcf3aa6d6f56ce3e51cf8a6351 -size 1707502 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_8.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_8.pt deleted file mode 100755 index 1c99e3aa04602616da6dea5f2f924aa647f2b6ac..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_8.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7f96ccbbe7194fc54dbadda7a1cb6a7c7a1389678142c0b5c915270549b955c8 -size 1707210 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_9.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_9.pt deleted file mode 100755 index 47da8b5df4f3b2dcac3115cc3dcdad203f96f1e1..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_9.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9d21ef077a1cd3e46fc94e0c80105bcf2246c70d9811027a666c28ff21cb4c7f -size 1707210 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/training.log b/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/training.log deleted file mode 100755 index 9412d7e31a69685e670faaa0eb986a936784b103..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/training.log +++ /dev/null @@ -1,74 +0,0 @@ -Training multiclass_12_process 2024-09-06 23:50:52.835697 -Epoch 00000 | LR 1.0000e-04 | Loss 1.6853 | Accuracy 0.3672 | Test_Loss 1.6844 | Test_AUC 0.8323 | Time 2406.1502 s -Epoch 00001 | LR 9.9000e-05 | Loss 1.6216 | Accuracy 0.3743 | Test_Loss 1.6660 | Test_AUC 0.8344 | Time 2406.9453 s -Epoch 00002 | LR 9.8010e-05 | Loss 1.6066 | Accuracy 0.3769 | Test_Loss 1.6656 | Test_AUC 0.8389 | Time 2355.3162 s -Epoch 00003 | LR 9.7030e-05 | Loss 1.5989 | Accuracy 0.3752 | Test_Loss 1.6700 | Test_AUC 0.8379 | Time 2351.9926 s -Epoch 00004 | LR 9.6060e-05 | Loss 1.5936 | Accuracy 0.3809 | Test_Loss 1.6568 | Test_AUC 0.8435 | Time 2323.1655 s -Epoch 00005 | LR 9.5099e-05 | Loss 1.5898 | Accuracy 0.3784 | Test_Loss 1.6613 | Test_AUC 0.8405 | Time 2293.3972 s -Epoch 00006 | LR 9.4148e-05 | Loss 1.5869 | Accuracy 0.3832 | Test_Loss 1.6416 | Test_AUC 0.8416 | Time 2297.7492 s -Epoch 00007 | LR 9.3207e-05 | Loss 1.5844 | Accuracy 0.3917 | Test_Loss 1.6090 | Test_AUC 0.8455 | Time 2296.5126 s -Epoch 00008 | LR 9.2274e-05 | Loss 1.5822 | Accuracy 0.3895 | Test_Loss 1.6174 | Test_AUC 0.8429 | Time 2372.6853 s -Epoch 00009 | LR 9.1352e-05 | Loss 1.5810 | Accuracy 0.3965 | Test_Loss 1.6079 | Test_AUC 0.8453 | Time 2455.0305 s -Epoch 00010 | LR 9.0438e-05 | Loss 1.5795 | Accuracy 0.3966 | Test_Loss 1.6067 | Test_AUC 0.8468 | Time 2459.9180 s -Epoch 00011 | LR 8.9534e-05 | Loss 1.5782 | Accuracy 0.3943 | Test_Loss 1.6117 | Test_AUC 0.8465 | Time 2444.6930 s -Epoch 00012 | LR 8.8638e-05 | Loss 1.5770 | Accuracy 0.3973 | Test_Loss 1.6081 | Test_AUC 0.8471 | Time 2475.8966 s -Epoch 00013 | LR 8.7752e-05 | Loss 1.5759 | Accuracy 0.3973 | Test_Loss 1.6037 | Test_AUC 0.8486 | Time 2330.9825 s -Epoch 00014 | LR 8.6875e-05 | Loss 1.5749 | Accuracy 0.3974 | Test_Loss 1.6066 | Test_AUC 0.8491 | Time 2276.6652 s -Epoch 00015 | LR 8.6006e-05 | Loss 1.5741 | Accuracy 0.3981 | Test_Loss 1.6070 | Test_AUC 0.8475 | Time 2278.0207 s -Epoch 00016 | LR 8.5146e-05 | Loss 1.5733 | Accuracy 0.3958 | Test_Loss 1.6089 | Test_AUC 0.8471 | Time 2296.7680 s -Epoch 00017 | LR 8.4294e-05 | Loss 1.5726 | Accuracy 0.3978 | Test_Loss 1.6004 | Test_AUC 0.8491 | Time 2273.7842 s -Epoch 00018 | LR 8.3451e-05 | Loss 1.5718 | Accuracy 0.3847 | Test_Loss 1.6652 | Test_AUC 0.8448 | Time 2265.8179 s -Epoch 00019 | LR 8.2617e-05 | Loss 1.5713 | Accuracy 0.3858 | Test_Loss 1.6495 | Test_AUC 0.8434 | Time 2271.3266 s -Epoch 00020 | LR 8.1791e-05 | Loss 1.5708 | Accuracy 0.3842 | Test_Loss 1.6602 | Test_AUC 0.8431 | Time 2263.7548 s -Epoch 00021 | LR 8.0973e-05 | Loss 1.5703 | Accuracy 0.3829 | Test_Loss 1.6628 | Test_AUC 0.8439 | Time 2277.5963 s -Epoch 00022 | LR 8.0163e-05 | Loss 1.5699 | Accuracy 0.3873 | Test_Loss 1.6452 | Test_AUC 0.8436 | Time 2381.2508 s -Epoch 00023 | LR 7.9361e-05 | Loss 1.5694 | Accuracy 0.3841 | Test_Loss 1.6477 | Test_AUC 0.8446 | Time 2371.5616 s -Epoch 00024 | LR 7.8568e-05 | Loss 1.5690 | Accuracy 0.3917 | Test_Loss 1.6253 | Test_AUC 0.8448 | Time 2412.1963 s -Epoch 00025 | LR 7.7782e-05 | Loss 1.5685 | Accuracy 0.3997 | Test_Loss 1.5952 | Test_AUC 0.8483 | Time 2361.6398 s -Epoch 00026 | LR 7.7004e-05 | Loss 1.5680 | Accuracy 0.3975 | Test_Loss 1.6004 | Test_AUC 0.8491 | Time 2370.2956 s -Epoch 00027 | LR 7.6234e-05 | Loss 1.5679 | Accuracy 0.4008 | Test_Loss 1.6004 | Test_AUC 0.8496 | Time 2401.6121 s -Epoch 00028 | LR 7.5472e-05 | Loss 1.5678 | Accuracy 0.3993 | Test_Loss 1.6004 | Test_AUC 0.8492 | Time 2403.7899 s -Epoch 00029 | LR 7.4717e-05 | Loss 1.5676 | Accuracy 0.3993 | Test_Loss 1.5997 | Test_AUC 0.8497 | Time 2407.6645 s -Epoch 00030 | LR 7.3970e-05 | Loss 1.5672 | Accuracy 0.4022 | Test_Loss 1.5928 | Test_AUC 0.8498 | Time 2401.9651 s -Epoch 00031 | LR 7.3230e-05 | Loss 1.5669 | Accuracy 0.3991 | Test_Loss 1.6006 | Test_AUC 0.8475 | Time 2397.6024 s -Epoch 00032 | LR 7.2498e-05 | Loss 1.5667 | Accuracy 0.4011 | Test_Loss 1.5956 | Test_AUC 0.8483 | Time 2404.3273 s -Epoch 00033 | LR 7.1773e-05 | Loss 1.5664 | Accuracy 0.3999 | Test_Loss 1.5982 | Test_AUC 0.8468 | Time 2397.5160 s -Epoch 00034 | LR 7.1055e-05 | Loss 1.5662 | Accuracy 0.4012 | Test_Loss 1.5956 | Test_AUC 0.8491 | Time 2396.6267 s -Epoch 00035 | LR 7.0345e-05 | Loss 1.5659 | Accuracy 0.4003 | Test_Loss 1.5962 | Test_AUC 0.8473 | Time 2393.2753 s -Training multiclass_12_process 2024-09-08 07:29:43.909566 -Epoch 00036 | LR 7.0345e-05 | Loss 1.5654 | Accuracy 0.3859 | Test_Loss 1.6487 | Test_AUC 0.8440 | Time 2350.2070 s -Epoch 00037 | LR 6.9641e-05 | Loss 1.5654 | Accuracy 0.3855 | Test_Loss 1.6569 | Test_AUC 0.8450 | Time 2376.8111 s -Epoch 00038 | LR 6.8945e-05 | Loss 1.5652 | Accuracy 0.3876 | Test_Loss 1.6477 | Test_AUC 0.8444 | Time 2388.1118 s -Epoch 00039 | LR 6.8255e-05 | Loss 1.5650 | Accuracy 0.3856 | Test_Loss 1.6473 | Test_AUC 0.8441 | Time 2367.7247 s -Epoch 00040 | LR 6.7573e-05 | Loss 1.5648 | Accuracy 0.3893 | Test_Loss 1.6384 | Test_AUC 0.8448 | Time 2354.1136 s -Epoch 00041 | LR 6.6897e-05 | Loss 1.5646 | Accuracy 0.3861 | Test_Loss 1.6461 | Test_AUC 0.8458 | Time 2340.8834 s -Epoch 00042 | LR 6.6228e-05 | Loss 1.5644 | Accuracy 0.3932 | Test_Loss 1.6217 | Test_AUC 0.8482 | Time 2349.6574 s -Epoch 00043 | LR 6.5566e-05 | Loss 1.5641 | Accuracy 0.4010 | Test_Loss 1.5895 | Test_AUC 0.8484 | Time 2360.5786 s -Epoch 00044 | LR 6.4910e-05 | Loss 1.5638 | Accuracy 0.4019 | Test_Loss 1.5900 | Test_AUC 0.8483 | Time 2468.9202 s -Epoch 00045 | LR 6.4261e-05 | Loss 1.5640 | Accuracy 0.4008 | Test_Loss 1.5990 | Test_AUC 0.8481 | Time 2473.0072 s -Epoch 00046 | LR 6.3619e-05 | Loss 1.5639 | Accuracy 0.4011 | Test_Loss 1.5962 | Test_AUC 0.8498 | Time 2448.4408 s -Epoch 00047 | LR 6.2982e-05 | Loss 1.5638 | Accuracy 0.4017 | Test_Loss 1.5946 | Test_AUC 0.8485 | Time 2381.1478 s -Epoch 00048 | LR 6.2353e-05 | Loss 1.5636 | Accuracy 0.4011 | Test_Loss 1.5942 | Test_AUC 0.8480 | Time 2393.2382 s -Epoch 00049 | LR 6.1729e-05 | Loss 1.5635 | Accuracy 0.4022 | Test_Loss 1.5950 | Test_AUC 0.8482 | Time 2350.8688 s -Epoch 00050 | LR 6.1112e-05 | Loss 1.5634 | Accuracy 0.4007 | Test_Loss 1.5968 | Test_AUC 0.8500 | Time 2334.9762 s -Epoch 00051 | LR 6.0501e-05 | Loss 1.5632 | Accuracy 0.4026 | Test_Loss 1.5919 | Test_AUC 0.8487 | Time 2269.9354 s -Epoch 00052 | LR 5.9896e-05 | Loss 1.5631 | Accuracy 0.4018 | Test_Loss 1.5961 | Test_AUC 0.8493 | Time 2303.6344 s -Epoch 00053 | LR 5.9297e-05 | Loss 1.5630 | Accuracy 0.4022 | Test_Loss 1.5928 | Test_AUC 0.8501 | Time 2275.7180 s -Epoch 00054 | LR 5.8704e-05 | Loss 1.5626 | Accuracy 0.3868 | Test_Loss 1.6539 | Test_AUC 0.8439 | Time 2282.3519 s -Epoch 00055 | LR 5.8117e-05 | Loss 1.5626 | Accuracy 0.3848 | Test_Loss 1.6525 | Test_AUC 0.8449 | Time 2338.0367 s -Epoch 00056 | LR 5.7535e-05 | Loss 1.5625 | Accuracy 0.3861 | Test_Loss 1.6500 | Test_AUC 0.8444 | Time 2349.1735 s -Epoch 00057 | LR 5.6960e-05 | Loss 1.5624 | Accuracy 0.3883 | Test_Loss 1.6474 | Test_AUC 0.8438 | Time 2352.2581 s -Epoch 00058 | LR 5.6391e-05 | Loss 1.5623 | Accuracy 0.3869 | Test_Loss 1.6484 | Test_AUC 0.8453 | Time 2300.8949 s -Epoch 00059 | LR 5.5827e-05 | Loss 1.5621 | Accuracy 0.3885 | Test_Loss 1.6456 | Test_AUC 0.8452 | Time 2296.1956 s -Epoch 00060 | LR 5.5268e-05 | Loss 1.5620 | Accuracy 0.3891 | Test_Loss 1.6347 | Test_AUC 0.8457 | Time 2311.4265 s -Epoch 00061 | LR 5.4716e-05 | Loss 1.5618 | Accuracy 0.4018 | Test_Loss 1.5879 | Test_AUC 0.8495 | Time 2307.2661 s -Epoch 00062 | LR 5.4169e-05 | Loss 1.5615 | Accuracy 0.4029 | Test_Loss 1.5857 | Test_AUC 0.8507 | Time 2356.9390 s -Epoch 00063 | LR 5.3627e-05 | Loss 1.5617 | Accuracy 0.4008 | Test_Loss 1.5969 | Test_AUC 0.8497 | Time 2315.4540 s -Epoch 00064 | LR 5.3091e-05 | Loss 1.5618 | Accuracy 0.4014 | Test_Loss 1.5944 | Test_AUC 0.8490 | Time 2322.3426 s -Epoch 00065 | LR 5.2560e-05 | Loss 1.5618 | Accuracy 0.4013 | Test_Loss 1.5960 | Test_AUC 0.8498 | Time 2337.3654 s -Epoch 00066 | LR 5.2034e-05 | Loss 1.5616 | Accuracy 0.4038 | Test_Loss 1.5905 | Test_AUC 0.8505 | Time 2354.6974 s -Epoch 00067 | LR 5.1514e-05 | Loss 1.5615 | Accuracy 0.4028 | Test_Loss 1.5932 | Test_AUC 0.8491 | Time 2346.2346 s -Epoch 00068 | LR 5.0999e-05 | Loss 1.5615 | Accuracy 0.4026 | Test_Loss 1.5919 | Test_AUC 0.8492 | Time 2364.3581 s -Epoch 00069 | LR 5.0489e-05 | Loss 1.5614 | Accuracy 0.4014 | Test_Loss 1.5947 | Test_AUC 0.8485 | Time 2321.0254 s -Epoch 00070 | LR 4.9984e-05 | Loss 1.5613 | Accuracy 0.4018 | Test_Loss 1.5942 | Test_AUC 0.8504 | Time 2360.4706 s -Epoch 00071 | LR 4.9484e-05 | Loss 1.5612 | Accuracy 0.4016 | Test_Loss 1.5946 | Test_AUC 0.8487 | Time 2348.2632 s diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/config.yaml b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/config.yaml deleted file mode 100644 index d5c63f0079c57faf98f9371a339639e66300e5e1..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/config.yaml +++ /dev/null @@ -1,569 +0,0 @@ -Datasets: - SingleT_schan: - args: - buffer_size: 11 - chunks: 100 - file_names: SingleT_schan_multilabel.root - fold_var: Number - label: &id001 - - n_higgs - - n_top - - n_V - - n_W - - n_Z - - higgs_exists - - higgs_pt_low - - higgs_pt_med - - higgs_pt_high - - higgs_eta_0 - - higgs_eta_1 - - higgs_eta_2 - - higgs_eta_3 - - higgs_phi_0 - - higgs_phi_1 - - higgs_phi_2 - - higgs_phi_3 - - top0_exists - - top0_pt_low - - top0_pt_med - - top0_pt_high - - top0_eta_0 - - top0_eta_1 - - top0_eta_2 - - top0_eta_3 - - top0_phi_0 - - top0_phi_1 - - top0_phi_2 - - top0_phi_3 - - top1_exists - - top1_pt_low - - top1_pt_med - - top1_pt_high - - top1_eta_0 - - top1_eta_1 - - top1_eta_2 - - top1_eta_3 - - top1_phi_0 - - top1_phi_1 - - top1_phi_2 - - top1_phi_3 - name: SingleT_schan - node_branch_names: &id002 - - - jet_pt - - ele_pt - - mu_pt - - ph_pt - - MET_met - - - jet_eta - - ele_eta - - mu_eta - - ph_eta - - 0 - - - jet_phi - - ele_phi - - mu_phi - - ph_phi - - MET_phi - - CALC_E - - - jet_btag - - 0 - - 0 - - 0 - - 0 - - - 0 - - ele_charge - - mu_charge - - 0 - - 0 - - NODE_TYPE - node_branch_types: &id003 - - vector - - vector - - vector - - vector - - single - node_feature_scales: &id004 - - 1e-1 - - 1 - - 1 - - 1e-1 - - 1 - - 1 - - 1 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: &id005 - n_folds: 10 - test: - - 0 - - 1 - train: - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - VBF: - args: - buffer_size: 11 - chunks: 100 - file_names: VBF_NLO_inc_multilabel.root - fold_var: Number - label: *id001 - name: VBF - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - WH: - args: - buffer_size: 11 - chunks: 100 - file_names: WH_NLO_inc_multilabel.root - fold_var: Number - label: *id001 - name: WH - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ZH: - args: - buffer_size: 11 - chunks: 100 - file_names: ZH_NLO_inc_multilabel.root - fold_var: Number - label: *id001 - name: ZH - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ggF: - args: - buffer_size: 11 - chunks: 100 - file_names: ggF_NLO_inc_multilabel.root - fold_var: Number - label: *id001 - name: ggF - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - tHjb: - args: - buffer_size: 11 - chunks: 100 - file_names: tHjb_NLO_inc_multilabel.root - fold_var: Number - label: *id001 - name: tHjb - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ttH: - args: - buffer_size: 11 - chunks: 100 - file_names: ttH_NLO_inc_multilabel.root - fold_var: Number - label: *id001 - name: ttH - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ttW: - args: - buffer_size: 11 - chunks: 100 - file_names: ttW_multilabel.root - fold_var: Number - label: *id001 - name: ttW - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ttbar: - args: - buffer_size: 11 - chunks: 100 - file_names: ttbar_multilabel.root - fold_var: Number - label: *id001 - name: ttbar - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ttt: - args: - buffer_size: 11 - chunks: 100 - file_names: ttt_multilabel.root - fold_var: Number - label: *id001 - name: ttt - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - tttt: - args: - buffer_size: 11 - chunks: 100 - file_names: tttt_multilabel.root - fold_var: Number - label: *id001 - name: tttt - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 - ttyy: - args: - buffer_size: 11 - chunks: 100 - file_names: ttyy_multilabel.root - fold_var: Number - label: *id001 - name: ttyy - node_branch_names: *id002 - node_branch_types: *id003 - node_feature_scales: *id004 - raw_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/ntuples/Hyy_pretraining/multilabel/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_diverse_multilabel/ - tree_name: output - weight_var: weight - class: LazyMultiLabelDataset - folding: *id005 - module: root_gnn_base.dataset - padding_mode: NONE - shuffle_chunks: 10 -Loss: - args: - label_names: - - n_higgs - - n_top - - n_V - - n_W - - n_Z - - higgs_exists - - higgs_pt_low - - higgs_pt_med - - higgs_pt_high - - higgs_eta_0 - - higgs_eta_1 - - higgs_eta_2 - - higgs_eta_3 - - higgs_phi_0 - - higgs_phi_1 - - higgs_phi_2 - - higgs_phi_3 - - top0_exists - - top0_pt_low - - top0_pt_med - - top0_pt_high - - top0_eta_0 - - top0_eta_1 - - top0_eta_2 - - top0_eta_3 - - top0_phi_0 - - top0_phi_1 - - top0_phi_2 - - top0_phi_3 - - top1_exists - - top1_pt_low - - top1_pt_med - - top1_pt_high - - top1_eta_0 - - top1_eta_1 - - top1_eta_2 - - top1_eta_3 - - top1_phi_0 - - top1_phi_1 - - top1_phi_2 - - top1_phi_3 - label_types: - - r - - r - - r - - r - - r - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - label_weights: - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - - 1 - class: MultiLabelLoss - finish: - args: - label_names: - - n_higgs - - n_top - - n_V - - n_W - - n_Z - - higgs_exists - - higgs_pt_low - - higgs_pt_med - - higgs_pt_high - - higgs_eta_0 - - higgs_eta_1 - - higgs_eta_2 - - higgs_eta_3 - - higgs_phi_0 - - higgs_phi_1 - - higgs_phi_2 - - higgs_phi_3 - - top0_exists - - top0_pt_low - - top0_pt_med - - top0_pt_high - - top0_eta_0 - - top0_eta_1 - - top0_eta_2 - - top0_eta_3 - - top0_phi_0 - - top0_phi_1 - - top0_phi_2 - - top0_phi_3 - - top1_exists - - top1_pt_low - - top1_pt_med - - top1_pt_high - - top1_eta_0 - - top1_eta_1 - - top1_eta_2 - - top1_eta_3 - - top1_phi_0 - - top1_phi_1 - - top1_phi_2 - - top1_phi_3 - label_types: - - r - - r - - r - - r - - r - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - - c - class: MultiLabelFinish - module: models.loss - module: models.loss -Model: - args: - dropout: 0.1 - hid_size: 64 - in_size: 7 - n_layers: 4 - n_proc_steps: 4 - out_size: 41 - class: Edge_Network - module: models.GCN -Training: - batch_size: 1024 - epochs: 100 - gamma: 0.99 - learning_rate: 0.0001 -Training_Directory: trainings/pretraining_multilabel/multilabel_41_higgs_tops_all_kinematics/ -Training_Name: multilabel_41_higgs_tops_all_kinematics diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_0.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_0.pt deleted file mode 100644 index a80a85ba71aef8120e6009860cd989b33d008527..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_0.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b35623bd73f89904024b44144c408ba430b232bae49c021e1b1ae4690246acc0 -size 1729866 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_1.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_1.pt deleted file mode 100644 index 8f5c489b77eacd547f8015f12464223e9a1c5c1e..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_1.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5293c53130fa58787b931037204ebc9d4d15edd38b40da70dccae94c047207db -size 1729866 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_10.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_10.pt deleted file mode 100644 index 581699a9cf69eac09be882d0e6a61b771f130af0..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_10.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4f34ff45f81b7b78bbce4c73cd05f90c92012593362ac1ab3cc1f06dfc09502b -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_11.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_11.pt deleted file mode 100644 index 0e14b48c0240f97a6c9854eb558de0d3b30cfa5f..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_11.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ce76ad96336b5d0535b94e673da5ce0adf01d786840721bf10fbf3eb4022ab2f -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_12.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_12.pt deleted file mode 100644 index 3f8c53122a82b2265c84e7aafaaa45f11fe24608..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_12.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8fb13df39d81627b366ca3af476a4dd871d6a4428ac313ce424c7f6d36fa3f2b -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_13.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_13.pt deleted file mode 100644 index 138700d0842953066dbcbfeea1956d550b011199..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_13.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d5425e2e7dca48fb8e9d736e4c925b020b84c97cad3b89951c27b7676921aa7a -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_14.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_14.pt deleted file mode 100644 index 482023b9a1f1bc034f8fdf8b254f239db4c5bdc7..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_14.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:310b9d646f4cca3efd1a026ccd6612fdc594834ec4a1c5d6bc40995b334ed458 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_15.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_15.pt deleted file mode 100644 index a8cfb97c9a8ada4a4917128c85f89b3a5b426312..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_15.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3f692534bb4e64302551cdd1c20bea8355a0d93c6929f53510264f00e9510d06 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_16.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_16.pt deleted file mode 100644 index b7c47248e805166ab1b61ab2176f11ade6e8427e..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_16.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c2552ddea648c9dd7589555e6a38beed6e2a8a12440da626d221bdab38d11803 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_17.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_17.pt deleted file mode 100644 index a8113c66ed5c1a5e01c5a6dd4d719368181c97a3..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_17.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:474e09077dcf1f213ba06f114845f02dfd3ed4873c1521efe01de0f225d57820 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_18.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_18.pt deleted file mode 100644 index 7ff91ca2554c1bc887b6ef24912b81ea0b8c1406..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_18.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:436c7a943101c56d536347868339c32abd92b54c08f9d8d2034ee82b80afc71e -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_19.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_19.pt deleted file mode 100644 index 578e495780f1e89b427626fe2ead95d960c179cf..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_19.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e924597baddcbf074ff39019a6419d799d5c5668f00a06c04a75676fc3d2c03d -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_2.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_2.pt deleted file mode 100644 index be82305f0089c113db87269aa91d8285de6aab5f..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_2.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ccba8d6f3b5a7b86079672b1aca6ccc798b12f824e140aaa04a6b1b017ac13fd -size 1729866 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_20.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_20.pt deleted file mode 100644 index c80752bea2bd1516c587138522b32a53e07073bf..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_20.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc717315297f2f372ea1f164f9b7e2bf2eb7a6cabe74cb2ebd7eff2f724ad8c6 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_21.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_21.pt deleted file mode 100644 index 59c2fb55de4b42c97018da6fa8c906ead8907a37..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_21.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:72496310cee6b6126fa08f243cfb04b8cf4c783b1892d4cb0a3a181a9fc88578 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_22.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_22.pt deleted file mode 100644 index 216d755690230dd6b0ceac3bc0e705e6f4fc95c6..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_22.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:92772d751a7fb9251a877568acec015b0ebe67e69f24c12843a9c409c661f5a9 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_23.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_23.pt deleted file mode 100644 index 140582bc537487dad5a88a55f1dd047025fd555c..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_23.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:82a01009af57e3e6bd4f8730d30813431b3b7cd343844656709fe11eda25e308 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_24.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_24.pt deleted file mode 100644 index 4916e26d382640499c8e4a2b9363d854fdbb4c6e..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_24.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:061c3c1c1b9728084f2ece3de5369d5d6039fdea0063e02297d571eb6b432117 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_25.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_25.pt deleted file mode 100644 index 22948601725565894574c6b9920c39d1744d8c81..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_25.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d426b047c06e1ac1630f23bb8e80b16dc6aab8f896c355d15b7e548bbc05b3f1 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_26.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_26.pt deleted file mode 100644 index 3787bd8d6201582730d9e8872ec4aee98f8e7490..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_26.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc9971d60afb5880cfb87c3e78a74b073c00edf5c91135b9870fddeca141c402 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_27.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_27.pt deleted file mode 100644 index 546495f1ebb52434a502348afa0f6b3555db5736..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_27.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bf62c53a2b5eaac01a9ab535216d3fb4ac029bd9453f129ced4bc2d44cf49121 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_28.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_28.pt deleted file mode 100644 index 8d21ca2a91c3a3ebae5d4d3ccfdf0cb7c882e37a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_28.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3497558df8f8c07697b26c3bcb35c46945ac883397fb349e002aefb29691a537 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_29.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_29.pt deleted file mode 100644 index df631a0002ff06c626294bb88c18fa322e87a7bb..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_29.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8f94b2f41319aa802a477df80ca575c766426e7a2121a1f3607088fa1a2d6f88 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_3.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_3.pt deleted file mode 100644 index 5f8555ca98676f331d2aeb8d8e7fbd1a1abc1bfc..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_3.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a3b2c405a7eae365a2606fcf090511a3a8b479f2208cda6eb9f73d6eaf8ad059 -size 1729866 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_30.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_30.pt deleted file mode 100644 index 63f2762b8189ced83cf2999452b3be4d78fd8e43..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_30.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c0721c85c33101cb00d620d4efe1eb8aade168beb459f86b73b483eafd7f40e5 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_31.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_31.pt deleted file mode 100644 index 870624f1cf90667ab2ef432147047cccc95e9767..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_31.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d95c167b1ac6ebc812aa0c6e56a6c9747adecafc7415841d7ab7d5c55f204fa7 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_32.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_32.pt deleted file mode 100644 index 95fecbb1c9c9c018ab136e2bbaac1b433ebff608..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_32.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1bb0c0af5c2057c399ff55e2603381fc4f084a726b2e9be6165bbdb74269f323 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_33.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_33.pt deleted file mode 100644 index 1af63dea4b8cad5e5bbc614805b13e53ebee78dc..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_33.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5a0db77643694bf14f3667d3ac2aa302fa44b50d5c875648311ccdb13f2cd5fe -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_34.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_34.pt deleted file mode 100644 index e1376e107c16d72c05888750679f591d7744898f..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_34.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:658fda7ee7e94d3ae98ec009fd5af58f1128ed055072b1bd409334f1a6f85305 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_35.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_35.pt deleted file mode 100644 index 1e5224ad64560d2cd686b057c3b99852d4938db9..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_35.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6d5b2cf087fa1b5ef133bec889efb45ef7f11a01406f539589ce6b11657dfc39 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_36.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_36.pt deleted file mode 100644 index 77967fb0999c4ee80cfc97ca0339aa5705d63cc9..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_36.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:91fad1e952b404228dc087a33ea8fa088903a2b0775c50d93a31f38a48b2247d -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_37.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_37.pt deleted file mode 100644 index 5e0f105416e6fdc8093c2cf3086b694827de0953..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_37.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1b38716c720979473fc5a7827808293ce957555c173e1d887e8e80b2b2a14398 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_38.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_38.pt deleted file mode 100644 index 3bad774c4d2a1206a27882b2831e53ea39fbbcd8..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_38.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ada2b582fd615a424bfc9baef046007d4fa85b648921ccb8357904dd47b81c75 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_39.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_39.pt deleted file mode 100644 index 576992afa5dde0e346b8b1110e243c529e9ee80b..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_39.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d08ca41bff2f5ff1319238f61dd9f33c6bf3d9726d2c228e2ea7d35df8ba63a5 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_4.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_4.pt deleted file mode 100644 index 9fcae154a0ad4c293c0a573ee897347efedc20e1..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_4.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4ac15ebdb013c36716b2bcf8057aa6d90a18f3a90844ee18c5a815722dee0747 -size 1729866 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_40.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_40.pt deleted file mode 100644 index f194bc415ddd3e1fcc94186c61b6466064f1d6d1..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_40.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fdb09ffba7ae76974829bc48759c24fe4e404a5011e36d09c3b46ed33a29dd9c -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_41.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_41.pt deleted file mode 100644 index a7fd9fca93e31f109725bb800e075273e2177cc4..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_41.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e93badb54b0b77040382628b20d1003fda3bceeffef88bd6b41b181698744f88 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_42.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_42.pt deleted file mode 100644 index 0e429db7c5f5783688b6585477bdacfa61081be5..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_42.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5b32dde2d38d6d1ad8351fd111278069a21602b28f18e934b124bfda8ab2a7c8 -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_43.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_43.pt deleted file mode 100644 index 23f476e1623f64ce6ccfd56c0db00e7e67b62c49..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_43.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc8b90ac18e70c00b08888ab85f31807372eac8f584537c1617d81790e41ee1a -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_44.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_44.pt deleted file mode 100644 index 3eb94c98a2f4e4d31ea9d256e140a21a594f94c3..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_44.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c3fdf8d12e9c1bece6e22a91b10a6ede5e7ce8103e247b912fbfda580461446b -size 1730158 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_5.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_5.pt deleted file mode 100644 index 6a65eb589f3afcfb5c42330a6d15b90e2c15d28a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_5.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:000181566cca68ee73f02fb124f02c3e524fe52505bb98e1046d0a72b5da45c4 -size 1729866 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_6.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_6.pt deleted file mode 100644 index e1886e553407e2d18466beb238bbf91ca3c36638..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_6.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:af83359d847957c65837afc7549760f78b4d6069193b705b2350daf097ec04f2 -size 1729866 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_7.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_7.pt deleted file mode 100644 index 439794c6ee68792bb98f10d8b5337e9d51f66366..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_7.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e78a651aacf2e5a007898758ae1539d0bf94a35c10adf5bd10d4262a948e46ce -size 1729866 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_8.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_8.pt deleted file mode 100644 index 4975391148741aca11748d9388c9afbc3c2824bf..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_8.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:41dc6355004cca5dc103587f48d7358a1b579bdadc99c97d490e24518e2d27b0 -size 1729866 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_9.pt b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_9.pt deleted file mode 100644 index e71c3664d9c5d8fefed62d82467fc45f1b622022..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/model_epoch_9.pt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b3ab110d102c9b16bcd58874d606750ae5ee853d5ea97240911ed1956c1f7e23 -size 1729866 diff --git a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/training.log b/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/training.log deleted file mode 100644 index ee51d69c2134cc11052c7292eff01c421b771b3a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/Pretrained_GNN/multilabel_pretrained_model_41/training.log +++ /dev/null @@ -1,91 +0,0 @@ -Training multilabel_41_higgs_tops_all_kinematics 2024-08-23 19:20:10.496271 -MultiLabel_Accuracy | 0.7455 | 0.5281 | 0.3708 | 0.3795 | 0.9044 | 0.4787 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.7644 | 0.9852 | 0.5181 | 0.8782 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.7744 | 0.9731 | 0.5523 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00000 | LR 1.0000e-04 | Loss 21.5584 | Accuracy 0.8039 | Test_Loss 29.8678 | Test_AUC 0.0000 | Time 352.4659 s -MultiLabel_Accuracy | 0.7517 | 0.5461 | 0.4684 | 0.4625 | 0.9044 | 0.7094 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8195 | 0.9852 | 0.6451 | 0.8782 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8309 | 0.9731 | 0.7521 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00001 | LR 9.9000e-05 | Loss 16.0182 | Accuracy 0.8252 | Test_Loss 28.8779 | Test_AUC 0.0000 | Time 303.0560 s -MultiLabel_Accuracy | 0.7517 | 0.5593 | 0.4727 | 0.4625 | 0.9044 | 0.7153 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8259 | 0.9852 | 0.7177 | 0.8782 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8330 | 0.9731 | 0.7826 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00002 | LR 9.8010e-05 | Loss 15.3191 | Accuracy 0.8285 | Test_Loss 28.6484 | Test_AUC 0.0000 | Time 288.8502 s -MultiLabel_Accuracy | 0.7560 | 0.5629 | 0.4914 | 0.4665 | 0.9044 | 0.7099 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8284 | 0.9852 | 0.7207 | 0.9055 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8376 | 0.9731 | 0.7980 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00003 | LR 9.7030e-05 | Loss 15.0311 | Accuracy 0.8304 | Test_Loss 28.5576 | Test_AUC 0.0000 | Time 286.0547 s -MultiLabel_Accuracy | 0.7625 | 0.5731 | 0.5011 | 0.4725 | 0.9044 | 0.7103 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8325 | 0.9852 | 0.7283 | 0.9086 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8426 | 0.9731 | 0.8055 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00004 | LR 9.6060e-05 | Loss 14.8461 | Accuracy 0.8319 | Test_Loss 28.4603 | Test_AUC 0.0000 | Time 284.5482 s -MultiLabel_Accuracy | 0.7645 | 0.5736 | 0.5196 | 0.5005 | 0.9044 | 0.7025 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8364 | 0.9852 | 0.7657 | 0.9338 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8469 | 0.9731 | 0.8034 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00005 | LR 9.5099e-05 | Loss 14.7059 | Accuracy 0.8346 | Test_Loss 28.4169 | Test_AUC 0.0000 | Time 281.6354 s -MultiLabel_Accuracy | 0.7648 | 0.5748 | 0.5223 | 0.5069 | 0.9044 | 0.7103 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8350 | 0.9852 | 0.7655 | 0.9281 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8430 | 0.9731 | 0.8036 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00006 | LR 9.4148e-05 | Loss 14.6290 | Accuracy 0.8347 | Test_Loss 28.3604 | Test_AUC 0.0000 | Time 281.7016 s -MultiLabel_Accuracy | 0.7626 | 0.5821 | 0.5289 | 0.5139 | 0.9044 | 0.7184 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8283 | 0.9852 | 0.7678 | 0.9335 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8344 | 0.9731 | 0.7900 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00007 | LR 9.3207e-05 | Loss 14.5512 | Accuracy 0.8349 | Test_Loss 28.3178 | Test_AUC 0.0000 | Time 283.5411 s -MultiLabel_Accuracy | 0.7629 | 0.5778 | 0.5311 | 0.5153 | 0.9044 | 0.7141 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8294 | 0.9852 | 0.7725 | 0.9309 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8272 | 0.9731 | 0.7831 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00008 | LR 9.2274e-05 | Loss 14.4881 | Accuracy 0.8345 | Test_Loss 28.3158 | Test_AUC 0.0000 | Time 301.1452 s -MultiLabel_Accuracy | 0.7641 | 0.5809 | 0.5265 | 0.5111 | 0.9044 | 0.7141 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8289 | 0.9852 | 0.7678 | 0.9249 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8278 | 0.9731 | 0.7936 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00009 | LR 9.1352e-05 | Loss 14.4349 | Accuracy 0.8344 | Test_Loss 28.2953 | Test_AUC 0.0000 | Time 290.1668 s -MultiLabel_Accuracy | 0.7630 | 0.5775 | 0.5313 | 0.5147 | 0.9044 | 0.7133 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8268 | 0.9852 | 0.7712 | 0.9161 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8224 | 0.9731 | 0.7899 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00010 | LR 9.0438e-05 | Loss 14.3933 | Accuracy 0.8341 | Test_Loss 28.2877 | Test_AUC 0.0000 | Time 282.7054 s -MultiLabel_Accuracy | 0.7631 | 0.5796 | 0.5274 | 0.5106 | 0.9044 | 0.7121 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8272 | 0.9852 | 0.7771 | 0.9241 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8227 | 0.9731 | 0.7846 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00011 | LR 8.9534e-05 | Loss 14.3596 | Accuracy 0.8341 | Test_Loss 28.2753 | Test_AUC 0.0000 | Time 281.5382 s -MultiLabel_Accuracy | 0.7640 | 0.5816 | 0.5218 | 0.5071 | 0.9044 | 0.7125 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8278 | 0.9852 | 0.7836 | 0.9215 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8261 | 0.9731 | 0.7864 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00012 | LR 8.8638e-05 | Loss 14.3304 | Accuracy 0.8342 | Test_Loss 28.2619 | Test_AUC 0.0000 | Time 356.4046 s -MultiLabel_Accuracy | 0.7643 | 0.5823 | 0.5164 | 0.5030 | 0.9044 | 0.7158 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8284 | 0.9852 | 0.7898 | 0.9320 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8290 | 0.9731 | 0.7799 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00013 | LR 8.7752e-05 | Loss 14.3099 | Accuracy 0.8344 | Test_Loss 28.2455 | Test_AUC 0.0000 | Time 319.6655 s -MultiLabel_Accuracy | 0.7639 | 0.5792 | 0.5255 | 0.5108 | 0.9044 | 0.7151 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8270 | 0.9852 | 0.7780 | 0.9251 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8258 | 0.9731 | 0.7858 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00014 | LR 8.6875e-05 | Loss 14.2862 | Accuracy 0.8343 | Test_Loss 28.2518 | Test_AUC 0.0000 | Time 285.1502 s -MultiLabel_Accuracy | 0.7647 | 0.5830 | 0.5255 | 0.5100 | 0.9044 | 0.7184 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8260 | 0.9852 | 0.7850 | 0.9223 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8261 | 0.9731 | 0.7829 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00015 | LR 8.6006e-05 | Loss 14.2648 | Accuracy 0.8345 | Test_Loss 28.2293 | Test_AUC 0.0000 | Time 284.2648 s -MultiLabel_Accuracy | 0.7655 | 0.5830 | 0.5284 | 0.5133 | 0.9044 | 0.7184 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8285 | 0.9852 | 0.7904 | 0.9221 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8304 | 0.9731 | 0.7856 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00016 | LR 8.5146e-05 | Loss 14.2550 | Accuracy 0.8350 | Test_Loss 28.2367 | Test_AUC 0.0000 | Time 285.0594 s -MultiLabel_Accuracy | 0.7646 | 0.5796 | 0.5293 | 0.5135 | 0.9044 | 0.7168 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8288 | 0.9852 | 0.7897 | 0.9253 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8290 | 0.9731 | 0.7913 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00017 | LR 8.4294e-05 | Loss 14.2427 | Accuracy 0.8351 | Test_Loss 28.2483 | Test_AUC 0.0000 | Time 285.6626 s -MultiLabel_Accuracy | 0.7650 | 0.5815 | 0.5352 | 0.5199 | 0.9044 | 0.7206 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8246 | 0.9852 | 0.7882 | 0.9255 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8242 | 0.9731 | 0.7825 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00018 | LR 8.3451e-05 | Loss 14.2201 | Accuracy 0.8351 | Test_Loss 28.2372 | Test_AUC 0.0000 | Time 281.2534 s -MultiLabel_Accuracy | 0.7651 | 0.5869 | 0.5295 | 0.5168 | 0.9044 | 0.7228 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8277 | 0.9852 | 0.7926 | 0.9242 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8306 | 0.9731 | 0.7825 | 0.9525 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00019 | LR 8.2617e-05 | Loss 14.2050 | Accuracy 0.8353 | Test_Loss 28.2081 | Test_AUC 0.0000 | Time 280.0656 s -MultiLabel_Accuracy | 0.7646 | 0.5755 | 0.5386 | 0.5236 | 0.9044 | 0.7172 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8265 | 0.9852 | 0.7885 | 0.9215 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8277 | 0.9731 | 0.7928 | 0.9599 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00020 | LR 8.1791e-05 | Loss 14.1920 | Accuracy 0.8355 | Test_Loss 28.2547 | Test_AUC 0.0000 | Time 281.6702 s -MultiLabel_Accuracy | 0.7666 | 0.5848 | 0.5371 | 0.5224 | 0.9044 | 0.7205 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8267 | 0.9852 | 0.7904 | 0.9215 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8255 | 0.9731 | 0.7858 | 0.9597 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00021 | LR 8.0973e-05 | Loss 14.1798 | Accuracy 0.8356 | Test_Loss 28.2137 | Test_AUC 0.0000 | Time 283.8978 s -MultiLabel_Accuracy | 0.7645 | 0.5835 | 0.5386 | 0.5260 | 0.9044 | 0.7215 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8252 | 0.9852 | 0.7857 | 0.9235 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8265 | 0.9731 | 0.7921 | 0.9599 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00022 | LR 8.0163e-05 | Loss 14.1698 | Accuracy 0.8357 | Test_Loss 28.2437 | Test_AUC 0.0000 | Time 284.9271 s -MultiLabel_Accuracy | 0.7659 | 0.5885 | 0.5385 | 0.5258 | 0.9044 | 0.7210 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8287 | 0.9852 | 0.7920 | 0.9255 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8275 | 0.9731 | 0.7913 | 0.9594 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00023 | LR 7.9361e-05 | Loss 14.1528 | Accuracy 0.8361 | Test_Loss 28.1935 | Test_AUC 0.0000 | Time 282.3253 s -MultiLabel_Accuracy | 0.7656 | 0.5849 | 0.5377 | 0.5230 | 0.9044 | 0.7188 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8275 | 0.9852 | 0.7909 | 0.9259 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8289 | 0.9731 | 0.7928 | 0.9598 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00024 | LR 7.8568e-05 | Loss 14.1443 | Accuracy 0.8359 | Test_Loss 28.2195 | Test_AUC 0.0000 | Time 295.7619 s -MultiLabel_Accuracy | 0.7652 | 0.5848 | 0.5384 | 0.5230 | 0.9044 | 0.7158 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8280 | 0.9852 | 0.7879 | 0.9215 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8293 | 0.9731 | 0.7947 | 0.9594 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00025 | LR 7.7782e-05 | Loss 14.1351 | Accuracy 0.8357 | Test_Loss 28.2209 | Test_AUC 0.0000 | Time 305.7035 s -MultiLabel_Accuracy | 0.7657 | 0.5860 | 0.5367 | 0.5201 | 0.9044 | 0.7158 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8297 | 0.9852 | 0.7926 | 0.9228 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8298 | 0.9731 | 0.7950 | 0.9594 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00026 | LR 7.7004e-05 | Loss 14.1285 | Accuracy 0.8359 | Test_Loss 28.2225 | Test_AUC 0.0000 | Time 294.8985 s -MultiLabel_Accuracy | 0.7661 | 0.5872 | 0.5370 | 0.5208 | 0.9044 | 0.7178 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8288 | 0.9852 | 0.7931 | 0.9269 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8294 | 0.9731 | 0.7926 | 0.9601 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00027 | LR 7.6234e-05 | Loss 14.1134 | Accuracy 0.8360 | Test_Loss 28.1849 | Test_AUC 0.0000 | Time 282.3505 s -MultiLabel_Accuracy | 0.7663 | 0.5863 | 0.5395 | 0.5243 | 0.9044 | 0.7188 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8283 | 0.9852 | 0.7875 | 0.9197 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8304 | 0.9731 | 0.7959 | 0.9589 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00028 | LR 7.5472e-05 | Loss 14.1056 | Accuracy 0.8359 | Test_Loss 28.2178 | Test_AUC 0.0000 | Time 286.5912 s -MultiLabel_Accuracy | 0.7660 | 0.5886 | 0.5383 | 0.5231 | 0.9044 | 0.7219 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8268 | 0.9852 | 0.7913 | 0.9258 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8262 | 0.9731 | 0.7927 | 0.9599 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00029 | LR 7.4717e-05 | Loss 14.0994 | Accuracy 0.8361 | Test_Loss 28.2007 | Test_AUC 0.0000 | Time 281.7022 s -MultiLabel_Accuracy | 0.7675 | 0.5887 | 0.5363 | 0.5219 | 0.9044 | 0.7175 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8311 | 0.9852 | 0.7943 | 0.9255 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8295 | 0.9731 | 0.7942 | 0.9597 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00030 | LR 7.3970e-05 | Loss 14.0880 | Accuracy 0.8362 | Test_Loss 28.1905 | Test_AUC 0.0000 | Time 279.7372 s -MultiLabel_Accuracy | 0.7677 | 0.5906 | 0.5366 | 0.5232 | 0.9044 | 0.7194 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8312 | 0.9852 | 0.7940 | 0.9255 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8308 | 0.9731 | 0.7967 | 0.9594 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00031 | LR 7.3230e-05 | Loss 14.0795 | Accuracy 0.8364 | Test_Loss 28.1945 | Test_AUC 0.0000 | Time 285.0377 s -MultiLabel_Accuracy | 0.7687 | 0.5940 | 0.5357 | 0.5232 | 0.9044 | 0.7206 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8299 | 0.9852 | 0.7924 | 0.9242 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8324 | 0.9731 | 0.7960 | 0.9596 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00032 | LR 7.2498e-05 | Loss 14.0707 | Accuracy 0.8364 | Test_Loss 28.1790 | Test_AUC 0.0000 | Time 282.6988 s -MultiLabel_Accuracy | 0.7673 | 0.5884 | 0.5350 | 0.5214 | 0.9044 | 0.7151 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8321 | 0.9852 | 0.7913 | 0.9197 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8279 | 0.9731 | 0.7922 | 0.9590 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00033 | LR 7.1773e-05 | Loss 14.0643 | Accuracy 0.8358 | Test_Loss 28.1895 | Test_AUC 0.0000 | Time 278.8458 s -MultiLabel_Accuracy | 0.7681 | 0.5947 | 0.5338 | 0.5211 | 0.9044 | 0.7213 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8298 | 0.9852 | 0.7941 | 0.9262 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8269 | 0.9731 | 0.7919 | 0.9600 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00034 | LR 7.1055e-05 | Loss 14.0574 | Accuracy 0.8362 | Test_Loss 28.1609 | Test_AUC 0.0000 | Time 283.4880 s -MultiLabel_Accuracy | 0.7690 | 0.5982 | 0.5342 | 0.5229 | 0.9044 | 0.7235 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8299 | 0.9852 | 0.7948 | 0.9273 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8274 | 0.9731 | 0.7912 | 0.9601 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00035 | LR 7.0345e-05 | Loss 14.0464 | Accuracy 0.8365 | Test_Loss 28.1496 | Test_AUC 0.0000 | Time 285.9291 s -MultiLabel_Accuracy | 0.7684 | 0.5962 | 0.5339 | 0.5212 | 0.9044 | 0.7213 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8349 | 0.9852 | 0.7960 | 0.9255 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8302 | 0.9731 | 0.7935 | 0.9597 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00036 | LR 6.9641e-05 | Loss 14.0393 | Accuracy 0.8365 | Test_Loss 28.1716 | Test_AUC 0.0000 | Time 284.9658 s -MultiLabel_Accuracy | 0.7686 | 0.5963 | 0.5337 | 0.5208 | 0.9044 | 0.7184 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8339 | 0.9852 | 0.7956 | 0.9259 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8305 | 0.9731 | 0.7932 | 0.9596 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00037 | LR 6.8945e-05 | Loss 14.0344 | Accuracy 0.8364 | Test_Loss 28.1794 | Test_AUC 0.0000 | Time 289.9682 s -MultiLabel_Accuracy | 0.7692 | 0.5996 | 0.5330 | 0.5190 | 0.9044 | 0.7203 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8346 | 0.9852 | 0.7971 | 0.9260 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8321 | 0.9731 | 0.7949 | 0.9598 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00038 | LR 6.8255e-05 | Loss 14.0218 | Accuracy 0.8367 | Test_Loss 28.1637 | Test_AUC 0.0000 | Time 287.4777 s -MultiLabel_Accuracy | 0.7691 | 0.5970 | 0.5330 | 0.5201 | 0.9044 | 0.7190 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8345 | 0.9852 | 0.7968 | 0.9276 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8342 | 0.9731 | 0.7962 | 0.9601 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00039 | LR 6.7573e-05 | Loss 14.0097 | Accuracy 0.8367 | Test_Loss 28.1543 | Test_AUC 0.0000 | Time 290.9069 s -MultiLabel_Accuracy | 0.7694 | 0.5998 | 0.5333 | 0.5203 | 0.9044 | 0.7209 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8350 | 0.9852 | 0.7975 | 0.9277 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8353 | 0.9731 | 0.7976 | 0.9601 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00040 | LR 6.6897e-05 | Loss 13.9961 | Accuracy 0.8369 | Test_Loss 28.1429 | Test_AUC 0.0000 | Time 284.9635 s -MultiLabel_Accuracy | 0.7692 | 0.5994 | 0.5328 | 0.5191 | 0.9044 | 0.7226 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8346 | 0.9852 | 0.7977 | 0.9274 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8365 | 0.9731 | 0.7987 | 0.9602 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00041 | LR 6.6228e-05 | Loss 13.9844 | Accuracy 0.8370 | Test_Loss 28.1354 | Test_AUC 0.0000 | Time 283.8730 s -MultiLabel_Accuracy | 0.7694 | 0.6001 | 0.5347 | 0.5204 | 0.9044 | 0.7256 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8345 | 0.9852 | 0.7974 | 0.9282 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8360 | 0.9731 | 0.7990 | 0.9599 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00042 | LR 6.5566e-05 | Loss 13.9704 | Accuracy 0.8371 | Test_Loss 28.1307 | Test_AUC 0.0000 | Time 284.3014 s -MultiLabel_Accuracy | 0.7695 | 0.5988 | 0.5348 | 0.5199 | 0.9044 | 0.7225 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8366 | 0.9852 | 0.7988 | 0.9278 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8378 | 0.9731 | 0.8020 | 0.9602 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00043 | LR 6.4910e-05 | Loss 13.9571 | Accuracy 0.8372 | Test_Loss 28.1316 | Test_AUC 0.0000 | Time 282.0029 s -MultiLabel_Accuracy | 0.7695 | 0.5994 | 0.5348 | 0.5192 | 0.9044 | 0.7233 | 0.8561 | 0.6573 | 0.9652 | 0.8321 | 0.9076 | 0.9074 | 0.8316 | 0.8933 | 0.8935 | 0.7987 | 0.8932 | 0.8354 | 0.9852 | 0.7979 | 0.9274 | 0.8829 | 0.8077 | 0.8077 | 0.8832 | 0.8453 | 0.8454 | 0.8456 | 0.8453 | 0.8359 | 0.9731 | 0.8007 | 0.9602 | 0.8843 | 0.8548 | 0.8545 | 0.8843 | 0.8695 | 0.8695 | 0.8696 | 0.8693 -Epoch 00044 | LR 6.4261e-05 | Loss 13.9445 | Accuracy 0.8371 | Test_Loss 28.1224 | Test_AUC 0.0000 | Time 282.0396 s diff --git a/legacy/root_gnn_dgl/README.md b/legacy/root_gnn_dgl/README.md deleted file mode 100644 index 25c82ab0cf6bd50c79e770d66ac2962613990ea2..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/README.md +++ /dev/null @@ -1,239 +0,0 @@ - -# root_gnn_dgl - -Pretrained DGL-based ROOT graph neural network. - -Pretrained model location: `/global/cfs/projectdirs/atlas/joshua/Pretrained_GNN/multiclass_pretrained_model_12/` -To use the pretrained model, take a look at a finetuning config in `configs`. -Replace `pretraining_path:` with `/global/cfs/projectdirs/atlas/joshua/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_71.pt`. - -## Overview -- Stable release with pretrained model weights. - -## Conda setup - -The conda environment is required for the inference step: applying the GNN onto root files and saving GNN scores as an additional branch. This is because the infereces script uses pyROOT. - -```bash -cd setup -conda env create -f environment.yml -conda activate pytorch -cd .. -python setup/test_setup.py -``` - -## Container Setup (Podman-HPC) - -- NERSC Perlmutter environment with `podman-hpc` available. -- Access to `joshuaho/pytorch:1.0` on Docker Hub [https://hub.docker.com/r/joshuaho/pytorch](https://hub.docker.com/r/joshuaho/pytorch) - -The inference step requires the conda environment, since the container does not contain ROOT. - -### Pull the Prebuilt Image - -```bash -podman-hpc pull docker.io/joshuaho/pytorch:1.0 -``` - -Or, you can build your own container here: - -```bash -cd setup -source build_image.sh -``` - -Run the image and mount the paths you need, replaceing `` with source directory path and `` with the path for when you are inside the container. -```bash - -podman-hpc run \ - -it \ - --mount type=bind,source=,target= \ - --rm \ - --network host \ - --gpu \ - --userns keep-id \ - --shm-size=32g \ - joshuaho/pytorch:1.0 - ``` - -### Test the Environment -Run the `setup/test_setup.py` script to confirm that all packages needed for training are properly set up. -```bash -python setup/test_setup.py -``` - - -## Running the Demo -The demo training is an example of our ML workflow, consisting of training a pretrained model, then finetuning it for an analysis task, while also training a model for the analysis task from scratch. The config files for the demo are located in the directory `configs/stats_100K/`. The demo can be run on a login node on Perlmutter (if enough GPU memory is availble). - -To check login node GPU memory availability, use the command `nvidia-smi`. If there is not enough memory available, you can switch to another login node with the command `ssh login**`, where `**` is a number between 0 and 39. - -For better performance, it is recommended to run the training and inference of the demo on a shared interactive node, where you have access to one exclusive GPU. An interactive node can be requested using the shell script in `jobs/interactive.sh`. - -The pretraining for the demo is a multiclass classification training on 12 datasets corresponding to 12 distinct physics processes, containing 100,000 simulated collision events each. The pretraining is then fintuned on a binary classification task between two datasets containing 100,000 simulated collision events each for two different processes, called ttH CP Even and ttH CP Odd. - -The entire demo can be ran with the command -```bash -source run_demo.sh -``` - -This shell script can also be used as an example to run the entire workflow. - -## Data Preparation -The first step in the process is to convert the events stored in ROOT files into DGL graph objects. This conversion is handled automatically by the Dataset objects during their creation, provided the graph data has not already been saved to disk. To accomplish this, a simple script is used to initialize the relevant Dataset object and then exit. This script needs to be executed for each data chunk in each dataset being used for training. - -Below is an example of how to use the `scripts/prep_data.py` script: - -```bash -datasets=("ttH" "tHjb" "ggF" "VBF" "WH" "ZH" "ttyy" "tttt" "SingleT_schan" "ttbar" "ttW" "ttt") -chunks=3 - -for data in "${datasets[@]}"; do - python scripts/prep_data.py --config configs/demo/pretraining_multiclass.yaml --dataset "$data" --shuffle_mode --chunk 0 - for ((i=0; i= 5" - - "(123 < higgs_m) & (higgs_m < 127)" - folding: - n_folds: 4 - test: [0] - train: [1, 2, 3] -``` - -Supported selection syntax: -- Simple comparisons like `"N_jet >= 5"`, `"higgs_m < 200"`, or `"MET_met == 0"` -- Multiple conditions combined with `&` and parentheses, for example `"(123 < higgs_m) & (higgs_m < 127)"` - -To quickly test that the selections in a config are valid and to print a fast cutflow for every dataset, run: -```bash -python scripts/selections.py --config configs/stats_100K/ttH_CP_even_vs_odd.yaml -``` - -This script reads only the branches needed for the selections and prints: -- the status of each selection expression -- the yield after each cut -- the individual efficiency of each cut -- the total efficiency relative to the uncut sample - -## Training -Training is run by `scripts/training_script`. `--preshuffle` tells it to use the preshuffled and batched graphs rather than shuffling and batching on the fly, and `--restart` can be used to force the training to start from the beginning rather than from the last available checkpoint. - -Using the `--nocompile` arguement is also recommended, as using `torch.compile()` requires padding the graphs beforehand during data processing. - -```bash -python scripts/training_script.py --config configs/stats_100K/pretraining_multiclass.yaml --preshuffle --nocompile --lazy -``` - -This step should produce the training directory `trainings/stats_100K/pretraining_multiclass/` containing a copy of the config file, checkpoints (`model_epoch_*.pt`) with the model weights after each epoch of training, npz files with the GNN outputs for each event after each epoch of training, and two files `training.log` and `training.png` which summarize the model performance and convergence. - -## Inference -Inference is done by `scripts/inference.py`. This script applies the model defined by `--config` onto the samples located at `--target`. A new set of samples with the GNN scores saved as the `--branch` in the ntuples will be created at `--destination`. The `--chunks` arguement will handel the inference in specified chunks. - -```bash -python scripts/inference.py \ - --target "/global/cfs/projectdirs/atlas/joshua/gnn_data/stats_100K/ttH_NLO.root" \ - --destination "/global/cfs/projectdirs/atlas/joshua/gnn_data/scores/stats_100K/ttH_NLO.root" \ - --config "configs/stats_100K/finetuning_ttH_CP_even_vs_odd.yaml" \ - --branch_name "GNN_Score" \ - --chunks 1 \ - --chunkno 0 \ - --write -``` - -You can also input a list as the `--config` and the `--branch_name` to simultaneously apply multiple models onto the same set of samples. An example on how to do this in shell script is in the `run_demo.sh` file. - -## ONNX Export -The `scripts/onnx_export.py` script exports a trained model to ONNX and validates the exported model against PyTorch on a real batch from the processed dataset. - -Example: -```bash -python scripts/onnx_export.py --config configs/stats_100K/ttH_CP_even_vs_odd.yaml --name ttH.onnx -``` - -To export a specific checkpoint instead of the best `Test_AUC` epoch, pass `--epoch`: -```bash -python scripts/onnx_export.py --config configs/stats_100K/ttH_CP_even_vs_odd.yaml --name ttH_epoch68.onnx --epoch 68 -``` - -What it does: -- Reads the model definition from the provided config -- Automatically chooses the matching model class from the config, including the finetuning or from-scratch path -- Loads the first prebatched chunk from the dataset save directory -- Uses the graph node count per event as `global_features` -- Exports an ONNX model with inputs in this order: - 1. `node_features` - 2. `edge_features` - 3. `global_features` - 4. `edge_index` - 5. `node_batch` -- Checks the ONNX graph with `onnx.checker` -- Runs ONNX Runtime and compares the output to PyTorch - -If `--epoch` is omitted, the script loads the checkpoint from the best `Test_AUC` entry in `training.log`, which matches the previous behavior. - -The validation is a three-way comparison: -1. The original DGL model from training -2. The tensor-based PyTorch translation of the same GNN -3. The exported ONNX model - -The script compares both logits and final sigmoid scores across all three models. It also produces a diagnostic plot showing: -- score distributions for the DGL, tensor, and ONNX models -- residual distributions for tensor - DGL and ONNX - DGL - -The plot is saved automatically next to the ONNX file using the same stem, with `_onnx.png` appended. - -Input shapes follow the notebook convention: -- `node_features`: `[num_nodes, node_feature_dim]` -- `edge_features`: `[num_edges, edge_feature_dim]` -- `global_features`: `[batch_size, 1]` -- `edge_index`: `[2, num_edges]` -- `node_batch`: `[num_nodes]` - -The validation prints the max and mean absolute differences for both logits and sigmoid probabilities. For a healthy export, those differences should be very small, typically around `1e-5` or better for logits. - -## Running Jobs + Parallelization - -Perlmutter job scripts are located in `jobs/`. Job scripts are separated into 3 categories: `prep_data`, `training`, and `inference`. - -The different shell scripts show how to request GPU or CPU nodes from Perlmutter, which are reqired for running jobs. - -### Data Prep Parallelization - -The preparation of data can be parallelized across several threads on a CPU. The parallelization is handled by python's `concurrent.futures.ThreadPoolExecutor`. - -### Training Parallelization - -Parallelization of GNN training is implemented with `torch.DistributedDataParallel`. The job submission script is in `jobs/training/multinode/submit.sh`. - -When running a multinode training, remember to use the `--multinode` run-time arguement for the training script. - -### Inference Parallelization - -Model inference parallelization is done with `mpi4py` (currently not listed in the conda environment requirements). You can run the parallel inference script with `mpirun -np python jobs/inference/run_inference.py`. diff --git a/legacy/root_gnn_dgl/configs/delphes/FCNC_vs_tHjb_baseline.yaml b/legacy/root_gnn_dgl/configs/delphes/FCNC_vs_tHjb_baseline.yaml deleted file mode 100755 index 151e73693498b7a0dc31d0d125fd46d9dcd5ab72..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/FCNC_vs_tHjb_baseline.yaml +++ /dev/null @@ -1,56 +0,0 @@ -Training_Name: FCNC_vs_tHjb_baseline -Training_Directory: trainings/ensemble/FCNC_vs_ttH/FCNC_vs_tHjb_baseline/ -Model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - FCNC: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: FCNC - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: FCNC_NLO_inc.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_FCNC_vs_tHjb - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - tHjb: - <<: *dataset_defn - args: - <<: *dataset_args - name: tHjb - label: 1 - file_names: tHjb_NLO_inc.root diff --git a/legacy/root_gnn_dgl/configs/delphes/FCNC_vs_tHjb_finetuning_multiclass_12_process.yaml b/legacy/root_gnn_dgl/configs/delphes/FCNC_vs_tHjb_finetuning_multiclass_12_process.yaml deleted file mode 100755 index 71a41c0f212a705e8245b1717200c5d282cc0a36..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/FCNC_vs_tHjb_finetuning_multiclass_12_process.yaml +++ /dev/null @@ -1,66 +0,0 @@ -Training_Name: FCNC_vs_tHjb_finetuning_multiclass_12_process -Training_Directory: trainings/ensemble/FCNC_vs_ttH/FCNC_vs_tHjb_finetuning_multiclass_12_process/ -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: trainings/pretraining_multiclass/multiclass_12_process/model_epoch_71.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 12 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.00001 - gamma: 0.99 -Datasets: - FCNC: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: FCNC - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: FCNC_NLO_inc.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /global/cfs/projectdirs/atlas/joshua/root_gnn/root_gnn_dgl/data/processed_FCNC_vs_tHjb/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - tHjb: - <<: *dataset_defn - args: - <<: *dataset_args - name: tHjb - label: 1 - file_names: tHjb_NLO_inc.root diff --git a/legacy/root_gnn_dgl/configs/delphes/FCNC_vs_tHjb_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml b/legacy/root_gnn_dgl/configs/delphes/FCNC_vs_tHjb_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml deleted file mode 100755 index 4653ac36f2d7686edf699114a74be83f5b3e9c1c..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/FCNC_vs_tHjb_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml +++ /dev/null @@ -1,66 +0,0 @@ -Training_Name: FCNC_vs_tHjb_finetuning_multilabel_41_higgs_tops_all_kinematics -Training_Directory: trainings/ensemble/FCNC_vs_ttH/FCNC_vs_tHjb_finetuning_multilabel_41_higgs_tops_all_kinematics/ -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: trainings/pretraining_multilabel/multilabel_41_higgs_tops_all_kinematics/model_epoch_44.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 41 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - FCNC: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: FCNC - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: FCNC_NLO_inc.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_FCNC_vs_tHjb - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - tHjb: - <<: *dataset_defn - args: - <<: *dataset_args - name: tHjb - label: 1 - file_names: tHjb_NLO_inc.root diff --git a/legacy/root_gnn_dgl/configs/delphes/WH_vs_ZH_inc_baseline.yaml b/legacy/root_gnn_dgl/configs/delphes/WH_vs_ZH_inc_baseline.yaml deleted file mode 100755 index d2da16e221f79767d7f250e0617c6051a630310e..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/WH_vs_ZH_inc_baseline.yaml +++ /dev/null @@ -1,56 +0,0 @@ -Training_Name: WH_vs_ZH_inc_baseline -Training_Directory: trainings/ensemble/WH_vs_ZH/WH_vs_ZH_inc_baseline/ -Model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - ZH: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ZH - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: ZH_NLO_inc.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_ZH_vs_WH_full_higgs_inc/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0,1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - WH: - <<: *dataset_defn - args: - <<: *dataset_args - name: WH - label: 1 - file_names: WH_NLO_inc.root diff --git a/legacy/root_gnn_dgl/configs/delphes/WH_vs_ZH_inc_finetuning_multiclass_12_process.yaml b/legacy/root_gnn_dgl/configs/delphes/WH_vs_ZH_inc_finetuning_multiclass_12_process.yaml deleted file mode 100755 index 174b91b03499418ab79115316ac34eefd3136e23..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/WH_vs_ZH_inc_finetuning_multiclass_12_process.yaml +++ /dev/null @@ -1,66 +0,0 @@ -Training_Name: WH_vs_ZH_inc_finetuning_multiclass_12_process -Training_Directory: trainings/ensemble/WH_vs_ZH/WH_vs_ZH_inc_finetuning_multiclass_12_process/ -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: trainings/pretraining_multiclass/multiclass_12_process/model_epoch_71.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 12 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.00001 - gamma: 0.99 -Datasets: - ZH: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ZH - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: ZH_NLO_inc.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_ZH_vs_WH_full_higgs_inc/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0,1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - WH: - <<: *dataset_defn - args: - <<: *dataset_args - name: WH - label: 1 - file_names: WH_NLO_inc.root diff --git a/legacy/root_gnn_dgl/configs/delphes/WH_vs_ZH_inc_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml b/legacy/root_gnn_dgl/configs/delphes/WH_vs_ZH_inc_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml deleted file mode 100755 index dd5c91f847cbcdd89a22c6c67f2f6bc8e4a3ba08..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/WH_vs_ZH_inc_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml +++ /dev/null @@ -1,66 +0,0 @@ -Training_Name: WH_vs_ZH_inc_finetuning_multilabel_41_higgs_tops_all_kinematics -Training_Directory: trainings/ensemble/WH_vs_ZH/WH_vs_ZH_inc_finetuning_multilabel_41_higgs_tops_all_kinematics/ -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: trainings/pretraining_multilabel/multilabel_41_higgs_tops_all_kinematics/model_epoch_44.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 41 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - ZH: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ZH - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: ZH_NLO_inc.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_ZH_vs_WH_full_higgs_inc/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0,1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - WH: - <<: *dataset_defn - args: - <<: *dataset_args - name: WH - label: 1 - file_names: WH_NLO_inc.root diff --git a/legacy/root_gnn_dgl/configs/delphes/stop_vs_ttH_inc_baseline.yaml b/legacy/root_gnn_dgl/configs/delphes/stop_vs_ttH_inc_baseline.yaml deleted file mode 100755 index 567eeddf01552cbe76c3c1f483382c6bd8d0002a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/stop_vs_ttH_inc_baseline.yaml +++ /dev/null @@ -1,57 +0,0 @@ -Training_Name: stop_vs_ttH_inc_baseline -Training_Directory: trainings/ensemble/stop_vs_ttH_inc/stop_vs_ttH_inc_baseline/ -Model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - STOP: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1028 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: STOP - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: STOP_LO_inc.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_stop_vs_ttH_inc/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - ttH_inc: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttH_inc - label: 1 - file_names: ttH_NLO_inc.root diff --git a/legacy/root_gnn_dgl/configs/delphes/stop_vs_ttH_inc_finetuning_multiclass_12_process.yaml b/legacy/root_gnn_dgl/configs/delphes/stop_vs_ttH_inc_finetuning_multiclass_12_process.yaml deleted file mode 100755 index 2664c31dae4eb95399263dd4e5d3895948161f22..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/stop_vs_ttH_inc_finetuning_multiclass_12_process.yaml +++ /dev/null @@ -1,67 +0,0 @@ -Training_Name: stop_vs_ttH_inc_finetuning_multiclass_12_process -Training_Directory: trainings/ensemble/stop_vs_ttH_inc/stop_vs_ttH_inc_finetuning_multiclass_12_process/ -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: trainings/pretraining_multiclass/multiclass_12_process/model_epoch_71.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 12 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.00001 - gamma: 0.99 -Datasets: - STOP: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1028 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: STOP - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: STOP_LO_inc.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_stop_vs_ttH_inc/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - ttH_inc: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttH_inc - label: 1 - file_names: ttH_NLO_inc.root diff --git a/legacy/root_gnn_dgl/configs/delphes/stop_vs_ttH_inc_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml b/legacy/root_gnn_dgl/configs/delphes/stop_vs_ttH_inc_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml deleted file mode 100755 index cf07626960e5f0e95e095a6a00b8bc1abea25db3..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/stop_vs_ttH_inc_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml +++ /dev/null @@ -1,67 +0,0 @@ -Training_Name: stop_vs_ttH_inc_finetuning_multilabel_41_higgs_tops_all_kinematics -Training_Directory: trainings/ensemble/stop_vs_ttH_inc/stop_vs_ttH_inc_finetuning_multilabel_41_higgs_tops_all_kinematics/ -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: trainings/pretraining_multilabel/multilabel_41_higgs_tops_all_kinematics/model_epoch_44.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 41 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - STOP: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1028 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: STOP - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: STOP_LO_inc.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_stop_vs_ttH_inc/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - ttH_inc: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttH_inc - label: 1 - file_names: ttH_NLO_inc.root diff --git a/legacy/root_gnn_dgl/configs/delphes/ttH_CP_even_vs_odd_baseline.yaml b/legacy/root_gnn_dgl/configs/delphes/ttH_CP_even_vs_odd_baseline.yaml deleted file mode 100755 index bd38e1f14cf93c6ccb01ca853bb455f6ea3977c9..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/ttH_CP_even_vs_odd_baseline.yaml +++ /dev/null @@ -1,57 +0,0 @@ -Training_Name: ttH_CP_even_vs_odd_baseline -Training_Directory: trainings/ensemble/ttH_vs_ttH_CPodd/ttH_CP_even_vs_odd_baseline/ -Model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - ttH: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1024 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttH - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: ttH_NLO.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_ttH_vs_ttH_CPOdd - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1, 2] - # validation: 1 - train: [3,4,5,6,7,8,9] - ttH_CPodd: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttH_CPodd - label: 1 - file_names: ttH_CPodd.root diff --git a/legacy/root_gnn_dgl/configs/delphes/ttH_CP_even_vs_odd_finetuning_multiclass_12_process.yaml b/legacy/root_gnn_dgl/configs/delphes/ttH_CP_even_vs_odd_finetuning_multiclass_12_process.yaml deleted file mode 100755 index 847d11346f9489d4ab9d3228751ef64f3da3bf73..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/ttH_CP_even_vs_odd_finetuning_multiclass_12_process.yaml +++ /dev/null @@ -1,67 +0,0 @@ -Training_Name: ttH_CP_even_vs_odd_finetuning_multiclass_12_process -Training_Directory: trainings/ensemble/ttH_vs_ttH_CPodd/ttH_CP_even_vs_odd_finetuning_multiclass_12_process/ -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: trainings/pretraining_multiclass/multiclass_12_process/model_epoch_71.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 12 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.00001 - gamma: 0.99 -Datasets: - ttH: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1024 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttH - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: ttH_NLO.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_ttH_vs_ttH_CPOdd - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1, 2] - # validation: 1 - train: [3,4,5,6,7,8,9] - ttH_CPodd: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttH_CPodd - label: 1 - file_names: ttH_CPodd.root diff --git a/legacy/root_gnn_dgl/configs/delphes/ttH_CP_even_vs_odd_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml b/legacy/root_gnn_dgl/configs/delphes/ttH_CP_even_vs_odd_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml deleted file mode 100755 index 49acccb092bb852925ce7b7190379da18d122b05..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/ttH_CP_even_vs_odd_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml +++ /dev/null @@ -1,67 +0,0 @@ -Training_Name: ttH_CP_even_vs_odd_finetuning_multilabel_41_higgs_tops_all_kinematics -Training_Directory: trainings/ensemble/ttH_vs_ttH_CPodd/ttH_CP_even_vs_odd_finetuning_multilabel_41_higgs_tops_all_kinematics/ -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: trainings/pretraining_multilabel/multilabel_41_higgs_tops_all_kinematics/model_epoch_44.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 41 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - ttH: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1024 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttH - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: ttH_NLO.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_ttH_vs_ttH_CPOdd - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1, 2] - # validation: 1 - train: [3,4,5,6,7,8,9] - ttH_CPodd: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttH_CPodd - label: 1 - file_names: ttH_CPodd.root diff --git a/legacy/root_gnn_dgl/configs/delphes/ttW_vs_ttt_baseline.yaml b/legacy/root_gnn_dgl/configs/delphes/ttW_vs_ttt_baseline.yaml deleted file mode 100755 index 7583fc4037ee8628fd1c02e4df4792e31ac941aa..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/ttW_vs_ttt_baseline.yaml +++ /dev/null @@ -1,57 +0,0 @@ -Training_Name: ttW_vs_ttt_baseline -Training_Directory: trainings/ensemble/ttW_vs_ttt/ttW_vs_ttt_baseline/ -Model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - ttW: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1024 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttW - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: ttW.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_ttW_vs_ttt - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - ttt: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttt - label: 1 - file_names: ttt.root diff --git a/legacy/root_gnn_dgl/configs/delphes/ttW_vs_ttt_finetuning_multiclass_12_process.yaml b/legacy/root_gnn_dgl/configs/delphes/ttW_vs_ttt_finetuning_multiclass_12_process.yaml deleted file mode 100755 index dff19eb59f228314705f421099beb26813f48ff6..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/ttW_vs_ttt_finetuning_multiclass_12_process.yaml +++ /dev/null @@ -1,67 +0,0 @@ -Training_Name: ttW_vs_ttt_finetuning_multiclass_12_process -Training_Directory: trainings/ensemble/ttW_vs_ttt/ttW_vs_ttt_finetuning_multiclass_12_process/ -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: trainings/pretraining_multiclass/multiclass_12_process/model_epoch_71.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 12 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.00001 - gamma: 0.99 -Datasets: - ttW: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1024 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttW - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: ttW.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_ttW_vs_ttt - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - ttt: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttt - label: 1 - file_names: ttt.root diff --git a/legacy/root_gnn_dgl/configs/delphes/ttW_vs_ttt_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml b/legacy/root_gnn_dgl/configs/delphes/ttW_vs_ttt_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml deleted file mode 100755 index b6b13d2e12aa909c5c1aede362f9e01477392a7d..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/delphes/ttW_vs_ttt_finetuning_multilabel_41_higgs_tops_all_kinematics.yaml +++ /dev/null @@ -1,67 +0,0 @@ -Training_Name: ttW_vs_ttt_finetuning_multilabel_41_higgs_tops_all_kinematics -Training_Directory: trainings/ensemble/ttW_vs_ttt/ttW_vs_ttt_finetuning_multilabel_41_higgs_tops_all_kinematics/ -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: trainings/pretraining_multilabel/multilabel_41_higgs_tops_all_kinematics/model_epoch_44.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 41 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0.0 -Training: - epochs: 100 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - ttW: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1024 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttW - label: 0 - weight_var: weight - chunks: 10 - buffer_size: 11 - file_names: ttW.root - tree_name: output - fold_var: Number - raw_dir: delphes/ - save_dir: /pscratch/sd/j/joshuaho/root_gnn/root_gnn_dgl/data/processed_ttW_vs_ttt - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 10 - test: [0, 1] - # validation: 1 - train: [2,3,4,5,6,7,8,9] - ttt: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttt - label: 1 - file_names: ttt.root diff --git a/legacy/root_gnn_dgl/configs/stats_100K/finetuning_ttH_CP_even_vs_odd.yaml b/legacy/root_gnn_dgl/configs/stats_100K/finetuning_ttH_CP_even_vs_odd.yaml deleted file mode 100755 index 33c62c3d4cab69684e191d46b7c5e325c0f032cd..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/stats_100K/finetuning_ttH_CP_even_vs_odd.yaml +++ /dev/null @@ -1,70 +0,0 @@ -Training_Name: finetuning_ttH_CP_even_vs_odd -Training_Directory: trainings/stats_100K/finetuning_ttH_CP_even_vs_odd -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_71.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 12 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0 -Training: - epochs: 500 - batch_size: 1024 - learning_rate: 0.00001 - gamma: 0.99 -Datasets: - ttH_CP_even: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 3 - batch_size: 1024 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttH_CP_even - label: 0 - # weight_var: weight - chunks: 3 - buffer_size: 2 - file_names: ttH_NLO.root - tree_name: output - fold_var: Number - raw_dir: /global/cfs/projectdirs/atlas/joshua/gnn_data/stats_100K/ - save_dir: /pscratch/sd/j/joshuaho/gnn/stats_100K/ttH_CP_even_vs_odd/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - selections: - - "N_jet >= 5" - - "(123 < higgs_m) & (higgs_m < 127)" - folding: - n_folds: 4 - test: [0] - # validation: 1 - train: [1, 2, 3] - ttH_CP_odd: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttH_CP_odd - label: 1 - file_names: ttH_CPodd.root diff --git a/legacy/root_gnn_dgl/configs/stats_100K/pretraining_multiclass.yaml b/legacy/root_gnn_dgl/configs/stats_100K/pretraining_multiclass.yaml deleted file mode 100644 index d3c1cdbd9015bbf2d85aa0c571f156ba69953cf4..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/stats_100K/pretraining_multiclass.yaml +++ /dev/null @@ -1,134 +0,0 @@ -Training_Name: pretraining_multiclass -Training_Directory: trainings/stats_100K/pretraining_multiclass/ -Model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 12 - n_layers: 4 - n_proc_steps: 4 - dropout: 0 -Loss: - module: torch.nn - class: CrossEntropyLoss - args: {} - finish: - module: torch.nn - class: Softmax - args: {dim: 1} -Training: - epochs: 500 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - ttH: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 3 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttH - label: 0 - # weight_var: weight - chunks: 3 - buffer_size: 2 - file_names: ttH_NLO_inc.root - tree_name: output - fold_var: Number - raw_dir: /global/cfs/projectdirs/atlas/joshua/gnn_data/stats_100K/ - save_dir: /pscratch/sd/j/joshuaho/gnn/stats_100K/pretraining_multiclass/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 4 - test: [0] - # validation: [1] - train: [1, 2, 3] - tHjb: - <<: *dataset_defn - args: - <<: *dataset_args - name: tHjb - label: 1 - file_names: tHjb_NLO_inc.root - ggF: - <<: *dataset_defn - args: - <<: *dataset_args - name: ggF - label: 2 - file_names: ggF_NLO_inc.root - VBF: - <<: *dataset_defn - args: - <<: *dataset_args - name: VBF - label: 3 - file_names: VBF_NLO_inc.root - WH: - <<: *dataset_defn - args: - <<: *dataset_args - name: WH - label: 4 - file_names: WH_NLO_inc.root - ZH: - <<: *dataset_defn - args: - <<: *dataset_args - name: ZH - label: 5 - file_names: ZH_NLO_inc.root - ttyy: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttyy - label: 6 - file_names: 'ttyy.root' - tttt: - <<: *dataset_defn - args: - <<: *dataset_args - name: tttt - label: 7 - file_names: 'tttt.root' - SingleT_schan: - <<: *dataset_defn - args: - <<: *dataset_args - name: SingleT_schan - label: 8 - file_names: 'SingleT_schan.root' - ttbar: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttbar - label: 9 - file_names: 'ttbar.root' - ttW: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttW - label: 10 - file_names: 'ttW.root' - ttt: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttt - label: 11 - file_names: 'ttt.root' \ No newline at end of file diff --git a/legacy/root_gnn_dgl/configs/stats_100K/ttH_CP_even_vs_odd.yaml b/legacy/root_gnn_dgl/configs/stats_100K/ttH_CP_even_vs_odd.yaml deleted file mode 100755 index 44999846ead6ff5066b53287c012ce7fde0ce182..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/stats_100K/ttH_CP_even_vs_odd.yaml +++ /dev/null @@ -1,60 +0,0 @@ -Training_Name: ttH_CP_even_vs_odd -Training_Directory: trainings/stats_100K/ttH_CP_even_vs_odd -Model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0 -Training: - epochs: 500 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - ttH_CP_even: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 3 - batch_size: 1024 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttH_CP_even - label: 0 - # weight_var: weight - chunks: 3 - buffer_size: 2 - file_names: ttH_NLO.root - tree_name: output - fold_var: Number - raw_dir: /global/cfs/projectdirs/atlas/joshua/gnn_data/stats_100K/ - save_dir: /pscratch/sd/j/joshuaho/gnn/stats_100K/ttH_CP_even_vs_odd/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - selections: - - "N_jet >= 5" - - "(123 < higgs_m) & (higgs_m < 127)" - folding: - n_folds: 4 - test: [0] - # validation: 1 - train: [1, 2, 3] - ttH_CP_odd: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttH_CP_odd - label: 1 - file_names: ttH_CPodd.root diff --git a/legacy/root_gnn_dgl/configs/stats_all/finetuning_ttH_CP_even_vs_odd.yaml b/legacy/root_gnn_dgl/configs/stats_all/finetuning_ttH_CP_even_vs_odd.yaml deleted file mode 100755 index eefb5d82e72a6b4cb93ff859c37892867897ed9b..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/stats_all/finetuning_ttH_CP_even_vs_odd.yaml +++ /dev/null @@ -1,67 +0,0 @@ -Training_Name: finetuning_ttH_CP_even_vs_odd -Training_Directory: trainings/stats_all/finetuning_ttH_CP_even_vs_odd -Model: - module: models.GCN - class: Transferred_Learning_Finetuning - args: - pretraining_path: Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_71.pt - pretraining_model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 12 - n_layers: 4 - n_proc_steps: 4 - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0 -Training: - epochs: 500 - batch_size: 1024 - learning_rate: 0.00001 - gamma: 0.99 -Datasets: - ttH_CP_even: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1024 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttH_CP_even - label: 0 - # weight_var: weight - chunks: 10 - buffer_size: 3 - file_names: ttH_NLO.root - tree_name: output - fold_var: Number - raw_dir: /global/cfs/projectdirs/atlas/joshua/gnn_data/stats_all/ - save_dir: /pscratch/sd/j/joshuaho/gnn/stats_all/ttH_CP_even_vs_odd/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 4 - test: [0] - # validation: 1 - train: [1, 2, 3] - ttH_CP_odd: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttH_CP_odd - label: 1 - file_names: ttH_CPodd.root diff --git a/legacy/root_gnn_dgl/configs/stats_all/pretraining_multiclass.yaml b/legacy/root_gnn_dgl/configs/stats_all/pretraining_multiclass.yaml deleted file mode 100644 index de99ab56f6f824b98cf1aace37488e67b880c04d..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/stats_all/pretraining_multiclass.yaml +++ /dev/null @@ -1,134 +0,0 @@ -Training_Name: pretraining_multiclass -Training_Directory: trainings/stats_all/pretraining_multiclass/ -Model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 12 - n_layers: 4 - n_proc_steps: 4 - dropout: 0 -Loss: - module: torch.nn - class: CrossEntropyLoss - args: {} - finish: - module: torch.nn - class: Softmax - args: {dim: 1} -Training: - epochs: 500 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - ttH: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttH - label: 0 - # weight_var: weight - chunks: 10 - buffer_size: 3 - file_names: ttH_NLO_inc.root - tree_name: output - fold_var: Number - raw_dir: /global/cfs/projectdirs/atlas/joshua/gnn_data/stats_all/ - save_dir: /pscratch/sd/j/joshuaho/gnn/stats_all/pretraining_multiclass/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 4 - test: [0] - # validation: [1] - train: [1, 2, 3] - tHjb: - <<: *dataset_defn - args: - <<: *dataset_args - name: tHjb - label: 1 - file_names: tHjb_NLO_inc.root - ggF: - <<: *dataset_defn - args: - <<: *dataset_args - name: ggF - label: 2 - file_names: ggF_NLO_inc.root - VBF: - <<: *dataset_defn - args: - <<: *dataset_args - name: VBF - label: 3 - file_names: VBF_NLO_inc.root - WH: - <<: *dataset_defn - args: - <<: *dataset_args - name: WH - label: 4 - file_names: WH_NLO_inc.root - ZH: - <<: *dataset_defn - args: - <<: *dataset_args - name: ZH - label: 5 - file_names: ZH_NLO_inc.root - ttyy: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttyy_ch - label: 6 - file_names: 'ttyy.root' - tttt: - <<: *dataset_defn - args: - <<: *dataset_args - name: tttt - label: 7 - file_names: 'tttt.root' - SingleT_schan: - <<: *dataset_defn - args: - <<: *dataset_args - name: SingleT_schan - label: 8 - file_names: 'SingleT_schan.root' - ttbar: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttbar - label: 9 - file_names: 'ttbar.root' - ttW: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttW - label: 10 - file_names: 'ttW.root' - ttt: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttt - label: 11 - file_names: 'ttt.root' \ No newline at end of file diff --git a/legacy/root_gnn_dgl/configs/stats_all/ttH_CP_even_vs_odd.yaml b/legacy/root_gnn_dgl/configs/stats_all/ttH_CP_even_vs_odd.yaml deleted file mode 100755 index 6aaa14e9bc08a6989a247e82456413467c9e99bd..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/configs/stats_all/ttH_CP_even_vs_odd.yaml +++ /dev/null @@ -1,57 +0,0 @@ -Training_Name: ttH_CP_even_vs_odd -Training_Directory: trainings/stats_all/ttH_CP_even_vs_odd -Model: - module: models.GCN - class: Edge_Network - args: - hid_size: 64 - in_size: 7 - out_size: 1 - n_layers: 4 - n_proc_steps: 4 - dropout: 0 -Training: - epochs: 500 - batch_size: 1024 - learning_rate: 0.0001 - gamma: 0.99 -Datasets: - ttH_CP_even: &dataset_defn - module: root_gnn_base.dataset - class: LazyDataset - shuffle_chunks: 10 - batch_size: 1024 - padding_mode: NONE #one of STEPS, FIXED, or NONE - args: &dataset_args - name: ttH_CP_even - label: 0 - # weight_var: weight - chunks: 10 - buffer_size: 3 - file_names: ttH_NLO.root - tree_name: output - fold_var: Number - raw_dir: /global/cfs/projectdirs/atlas/joshua/gnn_data/stats_all/ - save_dir: /pscratch/sd/j/joshuaho/gnn/stats_all/ttH_CP_even_vs_odd/ - node_branch_names: - - [jet_pt, ele_pt, mu_pt, ph_pt, MET_met] - - [jet_eta, ele_eta, mu_eta, ph_eta, 0] - - [jet_phi, ele_phi, mu_phi, ph_phi, MET_phi] - - CALC_E - - [jet_btag, 0, 0, 0, 0] - - [0, ele_charge, mu_charge, 0, 0] - - NODE_TYPE - node_branch_types: [vector, vector, vector, vector, single] - node_feature_scales: [1e-1, 1, 1, 1e-1, 1, 1, 1] - folding: - n_folds: 4 - test: [0] - # validation: 1 - train: [1, 2, 3] - ttH_CP_odd: - <<: *dataset_defn - args: - <<: *dataset_args - name: ttH_CP_odd - label: 1 - file_names: ttH_CPodd.root diff --git a/legacy/root_gnn_dgl/jobs/cpu.sh b/legacy/root_gnn_dgl/jobs/cpu.sh deleted file mode 100644 index b9dabeb9f8cc1cf2f887bde1bf81bde74af204f4..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/cpu.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -ACCOUNT="${SLURM_ACCOUNT:-atlas}" - -salloc --nodes=1 --ntasks=64 --cpus-per-task=1 --qos=interactive --time=04:00:00 --constraint=cpu --account="$ACCOUNT" diff --git a/legacy/root_gnn_dgl/jobs/inference/run_inference.py b/legacy/root_gnn_dgl/jobs/inference/run_inference.py deleted file mode 100644 index 014a5bb1079a1bfe4567ef653c5034f64e83c153..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/inference/run_inference.py +++ /dev/null @@ -1,277 +0,0 @@ -#!/usr/bin/env python3 - -from __future__ import annotations - -import argparse -import glob -import os -import re -import subprocess -import sys -from dataclasses import dataclass -from pathlib import Path - -import yaml - -try: - from mpi4py import MPI -except ImportError: - MPI = None - - -REPO_ROOT = Path(__file__).resolve().parents[2] -GPUS_PER_NODE = 4 - - -@dataclass(frozen=True) -class InferenceTask: - target: Path - destination: Path - - -def load_config(path: Path) -> dict: - with path.open("r", encoding="utf-8") as handle: - return yaml.safe_load(handle) - - -def repo_relative(path: Path) -> str: - try: - return str(path.resolve().relative_to(REPO_ROOT)) - except ValueError: - return str(path) - - -def resolve_path(raw_path: str) -> Path: - path = Path(raw_path).expanduser() - if path.is_absolute(): - return path.resolve() - - repo_path = (REPO_ROOT / path).resolve() - if repo_path.exists() or str(raw_path).startswith(("configs/", "jobs/", "scripts/")): - return repo_path - - return (Path.cwd() / path).resolve() - - -def sanitize_branch_name(name: str) -> str: - cleaned = re.sub(r"\W+", "_", name).strip("_") - if not cleaned: - cleaned = "gnn" - if cleaned[0].isdigit(): - cleaned = f"gnn_{cleaned}" - return f"{cleaned}_score" - - -def discover_model_configs(raw_configs: list[str], raw_config_dirs: list[str]) -> list[Path]: - configs = [] - for raw_config in raw_configs: - config = resolve_path(raw_config) - if not config.is_file(): - raise FileNotFoundError(f"Config file does not exist: {config}") - configs.append(config) - - for raw_dir in raw_config_dirs: - config_dir = resolve_path(raw_dir) - if not config_dir.is_dir(): - raise NotADirectoryError(f"Config directory does not exist: {config_dir}") - configs.extend(sorted(path.resolve() for path in config_dir.glob("*.yaml"))) - - unique_configs = [] - seen = set() - for config in configs: - if config not in seen: - unique_configs.append(config) - seen.add(config) - if not unique_configs: - raise ValueError("No model configs were provided.") - return unique_configs - - -def default_branch_names(config_paths: list[Path]) -> list[str]: - branch_names = [] - for config_path in config_paths: - config = load_config(config_path) - training_name = config.get("Training_Name") or config_path.stem - branch_names.append(sanitize_branch_name(str(training_name))) - return branch_names - - -def discover_targets_from_config(sample_config_path: Path) -> list[Path]: - config = load_config(sample_config_path) - targets = [] - - for dataset_name, dataset_config in config.get("Datasets", {}).items(): - args = dataset_config.get("args", {}) - raw_dir = args.get("raw_dir") - file_names = args.get("file_names") - if not raw_dir or not file_names: - raise ValueError(f"Dataset {dataset_name} is missing raw_dir or file_names.") - - patterns = file_names if isinstance(file_names, list) else [file_names] - for pattern in patterns: - matches = sorted(Path(path).resolve() for path in glob.glob(os.path.join(raw_dir, pattern))) - if not matches: - raise FileNotFoundError(f"No files matched {os.path.join(raw_dir, pattern)}") - targets.extend(matches) - - unique_targets = [] - seen = set() - for target in targets: - if target not in seen: - unique_targets.append(target) - seen.add(target) - return unique_targets - - -def discover_targets(raw_targets: list[str], sample_config: str | None) -> list[Path]: - targets = [] - if sample_config: - targets.extend(discover_targets_from_config(resolve_path(sample_config))) - - for raw_target in raw_targets: - matches = sorted(Path(path).resolve() for path in glob.glob(str(resolve_path(raw_target)))) - if matches: - targets.extend(matches) - else: - target = resolve_path(raw_target) - if not target.exists(): - raise FileNotFoundError(f"Target does not exist: {target}") - targets.append(target) - - unique_targets = [] - seen = set() - for target in targets: - if target not in seen: - unique_targets.append(target) - seen.add(target) - if not unique_targets: - raise ValueError("No inference targets were provided.") - return unique_targets - - -def build_tasks(targets: list[Path], output_dir: Path) -> list[InferenceTask]: - output_dir.mkdir(parents=True, exist_ok=True) - return [InferenceTask(target=target, destination=(output_dir / target.name).resolve()) for target in targets] - - -def build_command( - task: InferenceTask, - config_paths: list[Path], - branch_names: list[str], - args: argparse.Namespace, -) -> list[str]: - command = [ - sys.executable, - "scripts/inference.py", - "--target", - str(task.target), - "--destination", - str(task.destination), - "--config", - *[str(path) for path in config_paths], - "--branch_name", - *branch_names, - "--chunks", - str(args.chunks), - "--chunkno", - str(args.chunkno), - ] - - if args.write: - command.append("--write") - if args.clobber: - command.append("--clobber") - if args.ckpt is not None: - command.extend(["--ckpt", str(args.ckpt)]) - if args.var: - command.extend(["--var", args.var]) - if args.mode: - command.extend(["--mode", args.mode]) - if args.tree: - command.extend(["--tree", args.tree]) - return command - - -def run_task( - task: InferenceTask, - config_paths: list[Path], - branch_names: list[str], - args: argparse.Namespace, - rank: int, -) -> int: - gpu_id = rank % GPUS_PER_NODE - env = os.environ.copy() - env["CUDA_VISIBLE_DEVICES"] = str(gpu_id) - command = build_command(task, config_paths, branch_names, args) - - print( - f"[rank {rank}] target={task.target} destination={task.destination} gpu={gpu_id}", - flush=True, - ) - print(f"[rank {rank}] command={' '.join(command)}", flush=True) - if args.test: - return 0 - return subprocess.run(command, cwd=REPO_ROOT, env=env).returncode - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser( - description="Run scripts/inference.py over many ROOT files with many model configs." - ) - parser.add_argument("--sample-config", help="Config whose dataset file_names define inference targets.") - parser.add_argument("--target", nargs="*", default=[], help="Target ROOT files or glob patterns.") - parser.add_argument("--config", nargs="*", default=[], help="Model config files to score.") - parser.add_argument("--config-dir", nargs="*", default=[], help="Directories containing model YAML configs.") - parser.add_argument("--branch-name", nargs="*", default=[], help="Score branch names. Defaults to Training_Name_score.") - parser.add_argument("--output-dir", required=True, help="Directory for output ROOT/NPZ files.") - parser.add_argument("--chunks", type=int, default=1) - parser.add_argument("--chunkno", type=int, default=0) - parser.add_argument("--write", action="store_true", help="Write ROOT files with score branches.") - parser.add_argument("--clobber", action="store_true") - parser.add_argument("--ckpt", type=int, default=None, help="Checkpoint epoch. Omit to let scripts/inference.py choose best epoch.") - parser.add_argument("--var", default="Test_AUC") - parser.add_argument("--mode", default="max") - parser.add_argument("--tree", default="") - parser.add_argument("--test", action="store_true", help="Print planned commands without running inference.") - return parser.parse_args() - - -def main() -> int: - args = parse_args() - config_paths = discover_model_configs(args.config, args.config_dir) - branch_names = args.branch_name or default_branch_names(config_paths) - if len(branch_names) != len(config_paths): - raise ValueError("--branch-name count must match the number of model configs.") - - targets = discover_targets(args.target, args.sample_config) - tasks = build_tasks(targets, resolve_path(args.output_dir)) - - print(f"Repo root: {REPO_ROOT}", flush=True) - print(f"Targets: {len(tasks)}", flush=True) - print(f"Model configs: {len(config_paths)}", flush=True) - print("Branches:", " ".join(branch_names), flush=True) - - if MPI is None: - failures = 0 - for task in tasks: - failures += int(run_task(task, config_paths, branch_names, args, rank=0) != 0) - return 1 if failures else 0 - - comm = MPI.COMM_WORLD - rank = comm.Get_rank() - size = comm.Get_size() - - failures = 0 - for index, task in enumerate(tasks): - if index % size != rank: - continue - failures += int(run_task(task, config_paths, branch_names, args, rank=rank) != 0) - - total_failures = comm.allreduce(failures, op=MPI.SUM) - if rank == 0: - print(f"Completed {len(tasks) - total_failures} task(s); failed {total_failures}.", flush=True) - return 1 if total_failures else 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/legacy/root_gnn_dgl/jobs/interactive.sh b/legacy/root_gnn_dgl/jobs/interactive.sh deleted file mode 100644 index 0920e5c02f41e85c7588d6fd8d8908c88887507b..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/interactive.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -ACCOUNT="${SLURM_ACCOUNT:-atlas}" - -salloc --nodes 1 --qos shared_interactive --time 04:00:00 --constraint gpu --account="$ACCOUNT" --gres=gpu:1 diff --git a/legacy/root_gnn_dgl/jobs/prep_data/parallel_prep.py b/legacy/root_gnn_dgl/jobs/prep_data/parallel_prep.py deleted file mode 100644 index 43821fe7fb6ed14f690ab8ea33e16c079a55511d..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/prep_data/parallel_prep.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python3 -"""Bounded, two-phase graph preparation for chunked ROOT datasets. - -Phase 1 creates ordinary graph chunks. Phase 2 creates shuffled/prebatched -files from those chunks. Keeping the phases separate prevents every shuffle -worker from also trying to build the same raw graph cache. -""" - -from __future__ import annotations - -import argparse -import subprocess -from concurrent.futures import ThreadPoolExecutor, as_completed -from pathlib import Path - -import yaml - - -REPO_ROOT = Path(__file__).resolve().parents[2] -PREP = REPO_ROOT / "scripts" / "prep_data.py" - - -def parse_split(value: str): - try: - part_text, total_text = value.split("/", 1) - part, total = int(part_text), int(total_text) - except ValueError as exc: - raise argparse.ArgumentTypeError("split must have the form PART/TOTAL, e.g. 1/2") from exc - if total < 1 or part < 1 or part > total: - raise argparse.ArgumentTypeError("split must satisfy 1 <= PART <= TOTAL") - return part, total - - -def load_tasks(config_path: Path): - config = yaml.safe_load(config_path.read_text()) - for dataset, dataset_config in config["Datasets"].items(): - chunks = int(dataset_config["args"].get("chunks", 1)) - shuffle_chunks = int(dataset_config.get("shuffle_chunks", 10)) - yield config_path, dataset, chunks, shuffle_chunks - - -def run(command): - print("+", " ".join(map(str, command)), flush=True) - subprocess.run(command, cwd=REPO_ROOT, check=True) - - -def run_bounded(commands, workers): - with ThreadPoolExecutor(max_workers=workers) as pool: - futures = [pool.submit(run, command) for command in commands] - for future in as_completed(futures): - future.result() - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("configs", nargs="+", type=Path) - parser.add_argument("--phase", choices=("raw", "shuffle", "all"), default="all") - parser.add_argument("--workers", type=int, default=8) - parser.add_argument("--buffer-size", type=int, default=1) - parser.add_argument( - "--split", - type=parse_split, - default=None, - help="Process one partition of the dataset task list, e.g. 1/2 or 2/2.", - ) - parser.add_argument( - "--shuffle-chunks", - type=int, - default=None, - help="Override config shuffle_chunks; use a larger value to reduce per-worker memory.", - ) - args = parser.parse_args() - - if ( - args.workers < 1 - or args.buffer_size < 1 - or (args.shuffle_chunks is not None and args.shuffle_chunks < 1) - ): - parser.error("workers, buffer-size, and shuffle-chunks must be positive") - - tasks = [] - for config in args.configs: - config_path = config if config.is_absolute() else REPO_ROOT / config - tasks.extend(load_tasks(config_path)) - - if args.split is not None: - part, total = args.split - start = (len(tasks) * (part - 1)) // total - stop = (len(tasks) * part) // total - tasks = tasks[start:stop] - print(f"Running split {part}/{total}: tasks {start}:{stop}", flush=True) - for config, dataset, chunks, shuffle_chunks in tasks: - print( - f" {config.name}:{dataset} raw_chunks={chunks} shuffle_chunks={shuffle_chunks}", - flush=True, - ) - - if args.phase in ("raw", "all"): - raw_commands = [] - for config, dataset, chunks, _ in tasks: - for chunk in range(chunks): - raw_commands.append([ - "python", str(PREP), "--config", str(config), - "--dataset", dataset, "--chunk", str(chunk), - ]) - run_bounded(raw_commands, args.workers) - - if args.phase in ("shuffle", "all"): - shuffle_commands = [] - for config, dataset, _, config_shuffle_chunks in tasks: - shuffle_chunks = args.shuffle_chunks or config_shuffle_chunks - for chunk in range(shuffle_chunks): - command = [ - "python", str(PREP), "--config", str(config), - "--dataset", dataset, "--shuffle_mode", "--chunk", str(chunk), - "--buffer_size", str(args.buffer_size), - ] - if args.shuffle_chunks is not None: - command.extend(["--shuffle_chunks", str(shuffle_chunks)]) - shuffle_commands.append(command) - run_bounded(shuffle_commands, args.workers) - - -if __name__ == "__main__": - main() diff --git a/legacy/root_gnn_dgl/jobs/prep_data/prep_data.sh b/legacy/root_gnn_dgl/jobs/prep_data/prep_data.sh deleted file mode 100755 index a473dd38bb01f42f33abb571c6e9165bb99eecaa..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/prep_data/prep_data.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -# Arguments -config=$1 # YAML configuration file -dataset=$2 # Dataset name -CHUNKS=$3 # Number of chunks - -shift 3 -args=("$@") # Additional arguments to pass to prep_data.py - -# Loop through all chunks -for ((i=0; i<$CHUNKS; i++)); do - command=(python scripts/prep_data.py --dataset "$dataset" --shuffle_mode --chunk "$i" --config "$config" "${args[@]}") - printf '+ ' - printf '%q ' "${command[@]}" - printf '\n' - "${command[@]}" -done diff --git a/legacy/root_gnn_dgl/jobs/prep_data/run_processing.py b/legacy/root_gnn_dgl/jobs/prep_data/run_processing.py deleted file mode 100644 index 7ae76366d7bae354fb731cc9608c13f6aa6e8039..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/prep_data/run_processing.py +++ /dev/null @@ -1,110 +0,0 @@ -from concurrent.futures import ThreadPoolExecutor, as_completed -import argparse -import yaml -import os -import subprocess -from pathlib import Path - -def extract_dataset_keys_and_chunks(yaml_file): - """ - Extract keys and shuffle_chunks under the 'Datasets' section from a YAML file. - """ - try: - # Open and parse the YAML file - with open(yaml_file, 'r') as file: - config = yaml.safe_load(file) - - # Check if 'Datasets' exists in the YAML file - if 'Datasets' in config: - datasets = config['Datasets'] - results = [] - for key, value in datasets.items(): - # Extract shuffle_chunks if available - shuffle_chunks = value.get('shuffle_chunks', None) - results.append((key, shuffle_chunks)) - return results - else: - print(f"No 'Datasets' section found in {yaml_file}.") - return [] - except Exception as e: - print(f"Error reading {yaml_file}: {e}") - return [] - -def call_bash_script(config, dataset_key, shuffle_chunks, bash_script): - """ - Call a bash script with dataset_key and shuffle_chunks as arguments. - """ - try: - # Construct the command to call the bash script - command = [bash_script, config, dataset_key, str(shuffle_chunks)] - - print(f"Executing command: {' '.join(command)}") - - result = subprocess.run(command, check=True, capture_output=True, text=True) - if result.stdout: - print(result.stdout, end="") - if result.stderr: - print(result.stderr, end="") - return f"Success: {dataset_key}" - except subprocess.CalledProcessError as e: - stderr = e.stderr if isinstance(e.stderr, str) else (e.stderr.decode() if e.stderr else "") - stdout = e.stdout if isinstance(e.stdout, str) else (e.stdout.decode() if e.stdout else "") - message = f"Error executing bash script for dataset {dataset_key}: {stderr or stdout or str(e)}" - return message - -def process_yaml_file(config, base_directory, bash_script): - """ - Process a single YAML file by extracting datasets and calling the bash script in parallel. - """ - yaml_file = os.path.join(base_directory, config) - if os.path.exists(yaml_file): - print(f"Processing file: {config}") - datasets = extract_dataset_keys_and_chunks(yaml_file) - - # Use ThreadPoolExecutor to parallelize bash script calls for datasets - max_workers = min(len(datasets), os.cpu_count()) # Limit workers to number of datasets or CPU cores - with ThreadPoolExecutor(max_workers=max_workers) as executor: - futures = [ - executor.submit(call_bash_script, config, key, shuffle_chunks, bash_script) - for key, shuffle_chunks in datasets - ] - - # Collect and print results as they complete - results = [] - for future in as_completed(futures): - results.append(future.result()) - return results - else: - return [f"File not found: {yaml_file}"] - -def main(): - parser = argparse.ArgumentParser(description="Run prep_data.sh for every dataset in one or more configs.") - parser.add_argument("configs", nargs="+", help="YAML config files, relative to the repo root or absolute.") - parser.add_argument( - "--bash-script", - default=None, - help="Path to prep_data.sh. Defaults to jobs/prep_data/prep_data.sh under the repo root.", - ) - args = parser.parse_args() - - repo_root = Path(__file__).resolve().parents[2] - base_directory = str(repo_root) + "/" - configs = [str(Path(config).resolve()) if Path(config).is_absolute() else config for config in args.configs] - bash_script = args.bash_script or str(repo_root / "jobs/prep_data/prep_data.sh") - - # Use ThreadPoolExecutor to process YAML files concurrently - max_workers = os.cpu_count() # Use all available CPU cores - with ThreadPoolExecutor(max_workers=max_workers) as executor: - futures = [ - executor.submit(process_yaml_file, config, base_directory, bash_script) - for config in configs - ] - - # Collect and print results as they complete - for future in as_completed(futures): - results = future.result() - for result in results: - print(result) - -if __name__ == "__main__": - main() diff --git a/legacy/root_gnn_dgl/jobs/salloc.sh b/legacy/root_gnn_dgl/jobs/salloc.sh deleted file mode 100644 index 132cfc83c1b0477af0050a94115ee7c8c55e2355..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/salloc.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -ACCOUNT="${SLURM_ACCOUNT:-atlas}" - -salloc --nodes 4 --qos interactive --time 04:00:00 --constraint gpu --account="$ACCOUNT" --gres=gpu:4 diff --git a/legacy/root_gnn_dgl/jobs/training/conda/run_job.sh b/legacy/root_gnn_dgl/jobs/training/conda/run_job.sh deleted file mode 100755 index 7315469900a963352a719e739172a9daa9a42c8a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/training/conda/run_job.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -#SBATCH -N 1 -#SBATCH -C gpu -#SBATCH -q shared -#SBATCH -t 15:00:00 -#SBATCH -o jobs/slurm/%j.out # STDOUT - -CONFIG=$1 -shift -ARGUMENTS=("$@") - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" - -cd "$REPO_ROOT" -mkdir -p jobs/slurm - -eval "$(conda shell.bash hook)" -conda activate "${ROOT_GNN_CONDA_ENV:-dgl}" - -COMMAND=( - "$REPO_ROOT/scripts/training_script.py" - "${ARGUMENTS[@]}" - "--preshuffle" - "--nocompile" - "--lazy" - "--config" - "$CONFIG" -) - -echo "Running my script now" -echo "Executing: python -u ${COMMAND[*]}" -python -u "${COMMAND[@]}" -echo "Done" diff --git a/legacy/root_gnn_dgl/jobs/training/conda/submit.sh b/legacy/root_gnn_dgl/jobs/training/conda/submit.sh deleted file mode 100644 index a0b85c7cc2c807f8ab40388e9d0990e74f414147..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/training/conda/submit.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -date - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" -RUN_JOB="$REPO_ROOT/jobs/training/conda/run_job.sh" -SBATCH_ACCOUNT_ARGS=() -if [ -n "${SLURM_ACCOUNT:-}" ]; then - SBATCH_ACCOUNT_ARGS=(--account "$SLURM_ACCOUNT") -fi - -default_configs=( - "configs/stats_all/ttH_CP_even_vs_odd.yaml" - "configs/stats_all/ttH_CP_even_vs_odd_batch_size_2048.yaml" - "configs/stats_all/ttH_CP_even_vs_odd_batch_size_4096.yaml" - "configs/stats_all/ttH_CP_even_vs_odd_batch_size_8192.yaml" -) - -if [ "$#" -gt 0 ]; then - configs=("$@") -else - configs=("${default_configs[@]}") -fi - -counter=0 - -hours=12 -time="${hours}:00:00" - -for job in "${configs[@]}" -do - sbatch "${SBATCH_ACCOUNT_ARGS[@]}" --job-name="$job" --time="$time" "$RUN_JOB" "$job" - ((counter++)) -done - -echo "Total jobs submitted: $counter" diff --git a/legacy/root_gnn_dgl/jobs/training/podman/run_job.sh b/legacy/root_gnn_dgl/jobs/training/podman/run_job.sh deleted file mode 100755 index a6219c9f5031ed644c061ba8cf8f48905d9bcc6e..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/training/podman/run_job.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -#SBATCH -N 1 -#SBATCH -C "gpu&hbm80g" -#SBATCH -q shared -#SBATCH -t 24:00:00 -#SBATCH -o jobs/slurm/%j.out # STDOUT - -ARGUMENTS=("$@") - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" - -cd "$REPO_ROOT" -mkdir -p jobs/slurm - -echo "Arguments: ${ARGUMENTS[*]}" - -source "$REPO_ROOT/setup/launch_image.sh" "$REPO_ROOT/jobs/training/podman/run_job_image.sh" "${ARGUMENTS[@]}" diff --git a/legacy/root_gnn_dgl/jobs/training/podman/run_job_image.sh b/legacy/root_gnn_dgl/jobs/training/podman/run_job_image.sh deleted file mode 100755 index 46c22e4265047f441e763c256b1acba9cf5773a1..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/training/podman/run_job_image.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -CONFIG=$1 -shift -# Store any other potential arguments safely -OTHER_ARGUEMENTS=("$@") - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" - -cd "$REPO_ROOT" - -# Use a bash array to build the command and its arguments -# Each element in the () is a separate argument. -COMMAND_ARGS=( - "$REPO_ROOT/scripts/training_script.py" - "${OTHER_ARGUEMENTS[@]}" - "--preshuffle" - "--nocompile" - "--lazy" - "--config" - "$CONFIG" -) - -echo "Running my script now" -# Using "@" in quotes expands the array correctly -echo "Executing: python -u ${COMMAND_ARGS[@]}" - -# The "${COMMAND_ARGS[@]}" syntax ensures each element is passed as a distinct argument -python -u "${COMMAND_ARGS[@]}" - -echo "Done" diff --git a/legacy/root_gnn_dgl/jobs/training/podman/submit.sh b/legacy/root_gnn_dgl/jobs/training/podman/submit.sh deleted file mode 100644 index ee19d1b9464c82f5b01003b6db5eafccbbf3dd9a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/training/podman/submit.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash - -date - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" -RUN_JOB="$REPO_ROOT/jobs/training/podman/run_job.sh" -SBATCH_ACCOUNT_ARGS=() -if [ -n "${SLURM_ACCOUNT:-}" ]; then - SBATCH_ACCOUNT_ARGS=(--account "$SLURM_ACCOUNT") -fi - -default_configs=( - # "configs/multiclass_pretraining/baseline.yaml" - # "configs/multiclass_pretraining/pretraining_batch_size/multiclass_bs_4096.yaml" - # "configs/multiclass_pretraining/pretraining_hid_size/multiclass_hid_256.yaml" - # "configs/multiclass_pretraining/pretraining_lr/multiclass_lr_1e2.yaml" - # "configs/multiclass_pretraining/pretraining_n_layers/multiclass_layers_6.yaml" - - # "configs/multiclass_pretraining/pretraining_batch_size/multiclass_bs_2048.yaml" - # "configs/multiclass_pretraining/pretraining_hid_size/multiclass_hid_128.yaml" - # "configs/multiclass_pretraining/pretraining_lr/multiclass_lr_1e3.yaml" - # "configs/multiclass_pretraining/pretraining_n_layers/multiclass_layers_5.yaml" - - # "configs/higgs_production/baseline.yaml" - # "configs/higgs_production/higgs_production_batch_size/higgs_production_bs_4096.yaml" - # "configs/higgs_production/higgs_production_hid_size/higgs_production_hid_256.yaml" - # "configs/higgs_production/higgs_production_lr/higgs_production_lr_1e2.yaml" - # "configs/higgs_production/higgs_production_n_layers/higgs_production_layers_6.yaml" - - # "configs/higgs_production/higgs_production_batch_size/higgs_production_bs_2048.yaml" - # "configs/higgs_production/higgs_production_hid_size/higgs_production_hid_128.yaml" - # "configs/higgs_production/higgs_production_lr/higgs_production_lr_1e3.yaml" - # "configs/higgs_production/higgs_production_n_layers/higgs_production_layers_5.yaml" - # "configs/higgs_production/baseline2.yaml" - # "configs/higgs_production/baseline3.yaml" - # "configs/higgs_production/baseline4.yaml" - # "configs/higgs_production/baseline5.yaml" - "configs/higgs_production/multiclass_finetuning/baseline.yaml" - "configs/higgs_production/multiclass_finetuning/baseline_lr_1e4.yaml" - "configs/higgs_production/multiclass_finetuning/baseline_lr_1e6.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_hid_128.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_hid_128_lr_1e4.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_hid_128_lr_1e6.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_hid_256.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_hid_256_lr_1e4.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_hid_256_lr_1e6.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_layers_6.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_layers_6_lr_1e4.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_layers_6_lr_1e6.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_lr_1e3.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_lr_1e3_lr_1e4.yaml" - "configs/higgs_production/multiclass_finetuning/multiclass_lr_1e3_lr_1e6.yaml" - - -) - -if [ "$#" -gt 0 ]; then - configs=("$@") -else - configs=("${default_configs[@]}") -fi - -counter=0 - -hours=24 -time="${hours}:00:00" - -for job in "${configs[@]}" -do - sbatch "${SBATCH_ACCOUNT_ARGS[@]}" --job-name="$job" --time="$time" "$RUN_JOB" "$job" - ((counter++)) -done - -echo "Total jobs submitted: $counter" diff --git a/legacy/root_gnn_dgl/jobs/training/run_parallel_trainings.py b/legacy/root_gnn_dgl/jobs/training/run_parallel_trainings.py deleted file mode 100644 index 15c663f79e3ab21dd6fb44fb61007e9a2510c265..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/jobs/training/run_parallel_trainings.py +++ /dev/null @@ -1,509 +0,0 @@ -#!/usr/bin/env python3 - -from __future__ import annotations - -import argparse -import os -import re -import shlex -import subprocess -import sys -import time -from collections import deque -from dataclasses import dataclass -from pathlib import Path -import socket - -import yaml - - -REPO_ROOT = Path(__file__).resolve().parents[2] -DEFAULT_TARGETS = ( - REPO_ROOT / "configs/higgs_production_updated_leptons", - REPO_ROOT / "configs/triboson", -) -FIXED_GPU_TOKENS = ("0", "1", "2", "3") -DEFAULT_TRAINING_ARGS = ("--preshuffle", "--nocompile", "--lazy") -FORBIDDEN_TRAINING_ARGS = {"--config", "--multigpu", "--multinode"} - - -@dataclass(frozen=True) -class ExecutionSlot: - gpu_token: str - - -@dataclass -class TrainingJob: - config_path: Path - training_directory: str - pretraining_path: Path | None - - -@dataclass -class ActiveProcess: - job: TrainingJob - slot: ExecutionSlot - log_path: Path - log_handle: object - process: subprocess.Popen - - -def parse_args() -> tuple[argparse.Namespace, list[str]]: - parser = argparse.ArgumentParser( - description=( - "Queue local single-GPU trainings on the current node only. This launcher " - "is intentionally hard-coded to use GPUs 0,1,2,3 with no srun or multi-node logic." - ), - epilog=( - "Unknown arguments are forwarded to scripts/training_script.py. " - "Example: python jobs/training/run_parallel_trainings.py --split 1/2 --restart --seed 7" - ), - ) - parser.add_argument( - "targets", - nargs="*", - help=( - "Config files or directories. Defaults to " - "configs/higgs_production_updated_leptons and configs/triboson." - ), - ) - parser.add_argument( - "--split", - type=str, - help=( - "Run only one deterministic slice of the config queue, formatted as K/N. " - "Example: --split 1/2 for the first half and --split 2/2 for the second." - ), - ) - parser.add_argument( - "--logs-root", - type=str, - default="jobs/slurm/parallel_training_logs", - help="Directory where launcher stdout/stderr logs should be written.", - ) - parser.add_argument( - "--stop-on-failure", - action="store_true", - help="Stop launching new trainings after the first failure.", - ) - parser.add_argument( - "--ignore-missing-pretraining", - action="store_true", - help="Launch even if a finetuning config points to a missing pretraining checkpoint.", - ) - parser.add_argument( - "--test", - action="store_true", - help="Run preflight checks and print the launch plan without starting trainings.", - ) - parser.add_argument( - "--poll-seconds", - type=float, - default=10.0, - help="Seconds between checks for finished trainings.", - ) - - # Accepted only so older commands do not fail; these are ignored in the - # single-node hard-coded launcher. - parser.add_argument("--gpus", type=str, help=argparse.SUPPRESS) - parser.add_argument("--nodelist", type=str, help=argparse.SUPPRESS) - parser.add_argument("--local-only", action="store_true", help=argparse.SUPPRESS) - parser.add_argument("--srun-binary", type=str, help=argparse.SUPPRESS) - parser.add_argument("--scontrol-binary", type=str, help=argparse.SUPPRESS) - parser.add_argument("--max-parallel", type=int, help=argparse.SUPPRESS) - parser.add_argument("--dry-run", action="store_true", help=argparse.SUPPRESS) - - args, forwarded_args = parser.parse_known_args() - return args, forwarded_args - - -def repo_relative(path: Path) -> str: - try: - return str(path.resolve().relative_to(REPO_ROOT)) - except ValueError: - return str(path.resolve()) - - -def resolve_target(raw_target: str) -> Path: - raw_path = Path(raw_target).expanduser() - if raw_path.is_absolute(): - return raw_path.resolve() - - repo_candidate = (REPO_ROOT / raw_path).resolve() - if repo_candidate.exists(): - return repo_candidate - - return (Path.cwd() / raw_path).resolve() - - -def discover_configs(raw_targets: list[str]) -> list[Path]: - targets = [resolve_target(raw_target) for raw_target in raw_targets] if raw_targets else list(DEFAULT_TARGETS) - configs: list[Path] = [] - - for target in targets: - if target.is_file(): - if target.suffix != ".yaml": - raise FileNotFoundError(f"Expected a .yaml config file, got {target}") - configs.append(target) - continue - - if not target.is_dir(): - raise FileNotFoundError(f"Config target does not exist: {target}") - - configs.extend(sorted(path.resolve() for path in target.glob("*.yaml"))) - - unique_configs = [] - seen = set() - for config in configs: - if config not in seen: - unique_configs.append(config) - seen.add(config) - return unique_configs - - -def resolve_checkpoint_path(raw_path: str) -> Path: - candidate = Path(raw_path).expanduser() - if candidate.is_absolute(): - return candidate.resolve() - return (REPO_ROOT / candidate).resolve() - - -def load_job(config_path: Path) -> TrainingJob: - with config_path.open("r", encoding="utf-8") as handle: - config = yaml.safe_load(handle) - - if not isinstance(config, dict): - raise ValueError(f"Config is not a YAML mapping: {config_path}") - - training_directory = config.get("Training_Directory") - if not training_directory: - raise ValueError(f"Config is missing Training_Directory: {config_path}") - - pretraining_path = None - model_args = config.get("Model", {}).get("args", {}) - if isinstance(model_args, dict) and model_args.get("pretraining_path"): - pretraining_path = resolve_checkpoint_path(model_args["pretraining_path"]) - - return TrainingJob( - config_path=config_path.resolve(), - training_directory=str(training_directory), - pretraining_path=pretraining_path, - ) - - -def parse_split_spec(raw_split: str | None) -> tuple[int, int] | None: - if raw_split is None: - return None - - match = re.fullmatch(r"\s*(\d+)\s*/\s*(\d+)\s*", raw_split) - if not match: - raise ValueError( - f"Invalid --split value {raw_split!r}. Use the format K/N, for example 1/2." - ) - - split_index = int(match.group(1)) - split_count = int(match.group(2)) - - if split_count <= 0: - raise ValueError("--split requires N > 0.") - if split_index <= 0: - raise ValueError("--split requires K >= 1.") - if split_index > split_count: - raise ValueError("--split requires K <= N.") - - return split_index, split_count - - -def select_jobs_for_split( - jobs: list[TrainingJob], - split_spec: tuple[int, int] | None, -) -> tuple[list[TrainingJob], str | None]: - if split_spec is None: - return jobs, None - - split_index, split_count = split_spec - selected_jobs = [ - job for index, job in enumerate(jobs) - if index % split_count == (split_index - 1) - ] - return selected_jobs, f"{split_index}/{split_count}" - - -def validate_forwarded_args(forwarded_args: list[str]) -> None: - normalized_args = [arg.split("=", 1)[0] for arg in forwarded_args] - forbidden = sorted(arg for arg in normalized_args if arg in FORBIDDEN_TRAINING_ARGS) - if forbidden: - joined = ", ".join(forbidden) - raise ValueError( - f"These training arguments are controlled by the launcher and cannot be forwarded: {joined}" - ) - - -def warn_about_ignored_args(args: argparse.Namespace) -> None: - ignored = [] - - if args.gpus: - ignored.append("--gpus") - if args.nodelist: - ignored.append("--nodelist") - if args.local_only: - ignored.append("--local-only") - if args.srun_binary: - ignored.append("--srun-binary") - if args.scontrol_binary: - ignored.append("--scontrol-binary") - if args.max_parallel is not None: - ignored.append("--max-parallel") - if args.dry_run: - ignored.append("--dry-run") - - if ignored: - print( - "Ignoring launcher options not used by the single-node version: " - + ", ".join(ignored), - flush=True, - ) - - -def format_slot(slot: ExecutionSlot, hostname: str) -> str: - return f"{hostname}:gpu{slot.gpu_token}" - - -def sanitize_log_name(config_path: Path) -> str: - try: - relative = config_path.resolve().relative_to(REPO_ROOT) - name = "__".join(relative.parts) - except ValueError: - name = config_path.name - return f"{name}.log" - - -def terminate_active_processes(active_processes: list[ActiveProcess]) -> None: - for active in active_processes: - if active.process.poll() is None: - active.process.terminate() - - deadline = time.time() + 10 - while time.time() < deadline: - if all(active.process.poll() is not None for active in active_processes): - break - time.sleep(0.5) - - for active in active_processes: - if active.process.poll() is None: - active.process.kill() - - for active in active_processes: - if not active.log_handle.closed: - active.log_handle.close() - - -def build_training_command(job: TrainingJob, forwarded_args: list[str]) -> list[str]: - return [ - sys.executable, - "scripts/training_script.py", - "--config", - str(job.config_path), - *DEFAULT_TRAINING_ARGS, - *forwarded_args, - ] - - -def launch_job( - job: TrainingJob, - slot: ExecutionSlot, - forwarded_args: list[str], - log_dir: Path, - hostname: str, -) -> ActiveProcess: - log_path = log_dir / sanitize_log_name(job.config_path) - log_path.parent.mkdir(parents=True, exist_ok=True) - log_handle = log_path.open("w", encoding="utf-8") - - command = build_training_command(job, forwarded_args) - - env = os.environ.copy() - env["CUDA_VISIBLE_DEVICES"] = slot.gpu_token - - process = subprocess.Popen( - command, - cwd=REPO_ROOT, - env=env, - stdout=log_handle, - stderr=subprocess.STDOUT, - ) - - print( - f"[launch] slot={format_slot(slot, hostname)} config={repo_relative(job.config_path)} " - f"log={repo_relative(log_path)}", - flush=True, - ) - - return ActiveProcess( - job=job, - slot=slot, - log_path=log_path, - log_handle=log_handle, - process=process, - ) - - -def main() -> int: - args, forwarded_args = parse_args() - validate_forwarded_args(forwarded_args) - warn_about_ignored_args(args) - split_spec = parse_split_spec(args.split) - - config_paths = discover_configs(args.targets) - if not config_paths: - raise RuntimeError("No YAML configs were found for the requested targets.") - - all_jobs = [load_job(config_path) for config_path in config_paths] - jobs, split_label = select_jobs_for_split(all_jobs, split_spec) - if not jobs: - raise RuntimeError("No configs were selected for this split.") - - duplicated_training_dirs: dict[str, Path] = {} - duplicate_messages = [] - missing_pretraining = [] - for job in jobs: - if job.training_directory in duplicated_training_dirs: - duplicate_messages.append( - f"{repo_relative(job.config_path)} conflicts with " - f"{repo_relative(duplicated_training_dirs[job.training_directory])} " - f"on Training_Directory={job.training_directory}" - ) - else: - duplicated_training_dirs[job.training_directory] = job.config_path - - if job.pretraining_path is not None and not job.pretraining_path.exists(): - missing_pretraining.append( - f"{repo_relative(job.config_path)} -> missing {job.pretraining_path}" - ) - - if duplicate_messages: - raise RuntimeError( - "Refusing to launch configs with overlapping Training_Directory values:\n" - + "\n".join(duplicate_messages) - ) - - if missing_pretraining and not args.ignore_missing_pretraining: - raise RuntimeError( - "Missing pretraining checkpoints were found:\n" - + "\n".join(missing_pretraining) - + "\nRe-run with --ignore-missing-pretraining to launch anyway." - ) - - if missing_pretraining: - print("Pretraining checkpoint warnings:", flush=True) - for message in missing_pretraining: - print(f" {message}", flush=True) - - hostname = socket.gethostname().split(".", 1)[0] - execution_slots = [ExecutionSlot(gpu_token=gpu_token) for gpu_token in FIXED_GPU_TOKENS] - max_parallel = len(execution_slots) - - timestamp = time.strftime("%Y%m%d_%H%M%S") - log_dir = (REPO_ROOT / args.logs_root / timestamp).resolve() - - print(f"Repo root: {REPO_ROOT}", flush=True) - print(f"Configs discovered: {len(all_jobs)}", flush=True) - if split_label: - print(f"Configs selected for split {split_label}: {len(jobs)}", flush=True) - else: - print(f"Configs selected: {len(jobs)}", flush=True) - print(f"Node selected: {hostname}", flush=True) - print(f"GPUs selected: {', '.join(FIXED_GPU_TOKENS)}", flush=True) - print(f"Max parallel trainings: {max_parallel}", flush=True) - print(f"Training args: {' '.join(DEFAULT_TRAINING_ARGS + tuple(forwarded_args))}", flush=True) - print(f"Launcher logs: {repo_relative(log_dir)}", flush=True) - print("Launch mode: local queued trainings only", flush=True) - - if args.test or args.dry_run: - print("Running launcher self-test; no trainings will be started.", flush=True) - for index, job in enumerate(jobs, start=1): - slot = execution_slots[(index - 1) % len(execution_slots)] - command = build_training_command(job, forwarded_args) - print( - f"[dry-run {index:02d}] slot={format_slot(slot, hostname)} " - f"dir={job.training_directory} cmd={shlex.join(command)}", - flush=True, - ) - return 0 - - log_dir.mkdir(parents=True, exist_ok=True) - - pending_jobs = deque(jobs) - free_slots = deque(execution_slots) - active_processes: list[ActiveProcess] = [] - failed_jobs: list[tuple[TrainingJob, int, Path]] = [] - completed_jobs = 0 - - try: - while pending_jobs or active_processes: - while pending_jobs and free_slots: - job = pending_jobs.popleft() - slot = free_slots.popleft() - active_processes.append(launch_job(job, slot, forwarded_args, log_dir, hostname)) - - if not active_processes: - break - - time.sleep(args.poll_seconds) - - still_active: list[ActiveProcess] = [] - for active in active_processes: - return_code = active.process.poll() - if return_code is None: - still_active.append(active) - continue - - active.log_handle.close() - free_slots.append(active.slot) - - if return_code == 0: - completed_jobs += 1 - print( - f"[done] slot={format_slot(active.slot, hostname)} " - f"config={repo_relative(active.job.config_path)} " - f"completed={completed_jobs}/{len(jobs)}", - flush=True, - ) - else: - failed_jobs.append((active.job, return_code, active.log_path)) - print( - f"[fail] slot={format_slot(active.slot, hostname)} " - f"config={repo_relative(active.job.config_path)} " - f"exit={return_code} log={repo_relative(active.log_path)}", - flush=True, - ) - if args.stop_on_failure: - pending_jobs.clear() - - active_processes = still_active - - if failed_jobs and args.stop_on_failure: - terminate_active_processes(active_processes) - active_processes = [] - break - - except KeyboardInterrupt: - print("\nInterrupted. Terminating active trainings...", flush=True) - terminate_active_processes(active_processes) - return 130 - - print(f"Completed {completed_jobs} training(s); failed {len(failed_jobs)}.", flush=True) - if failed_jobs: - for job, return_code, log_path in failed_jobs: - print( - f" {repo_relative(job.config_path)} exit={return_code} " - f"log={repo_relative(log_path)}", - flush=True, - ) - return 1 - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/legacy/root_gnn_dgl/models/GCN.py b/legacy/root_gnn_dgl/models/GCN.py deleted file mode 100755 index 35b09bf1259a80b03db873ffc824f982ce435ded..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/models/GCN.py +++ /dev/null @@ -1,1948 +0,0 @@ -import dgl -import dgl.nn as dglnn - -import torch -import torch.nn as nn -import torch.nn.functional as F - -import sys -import os -file_path = os.getcwd() -sys.path.append(file_path) - -import root_gnn_base.dataset as datasets -from root_gnn_base import utils - -import gc - -def Make_SLP(in_size, out_size, activation = nn.ReLU, dropout = 0): - layers = [] - layers.append(nn.Linear(in_size, out_size)) - layers.append(activation()) - layers.append(nn.Dropout(dropout)) - return layers - -def Make_MLP(in_size, hid_size, out_size, n_layers, activation = nn.ReLU, dropout = 0): - layers = [] - if n_layers > 1: - layers += Make_SLP(in_size, hid_size, activation, dropout) - for i in range(n_layers-2): - layers += Make_SLP(hid_size, hid_size, activation, dropout) - layers += Make_SLP(hid_size, out_size, activation, dropout) - else: - layers += Make_SLP(in_size, out_size, activation, dropout) - layers.append(torch.nn.LayerNorm(out_size)) - return nn.Sequential(*layers) - -class MLP(nn.Module): - def __init__(self, in_size, hid_size, out_size, n_layers, activation = nn.ReLU, dropout = 0, **kwargs): - super().__init__() - print(f'Unused args while creating MLP: {kwargs}') - self.layers = Make_MLP(in_size, hid_size, hid_size, n_layers-1, activation, dropout) - self.linear = nn.Linear(hid_size, out_size) - - def forward(self, x): - return self.linear(self.layers(x)) - -def broadcast_global_to_nodes(g, globals): - boundaries = g.batch_num_nodes() - return torch.repeat_interleave(globals, boundaries, dim=0) - -def broadcast_global_to_edges(g, globals): - boundaries = g.batch_num_edges() - return torch.repeat_interleave(globals, boundaries, dim=0) - -def copy_v(edges): - return {'m_v': edges.dst['h']} - -def partial_reset(model : nn.Module): - in_size = len(model.classify.weight[0]) - out_size = len(model.classify.weight) - device = next(model.classify.parameters()).device - torch.manual_seed(2) - model.classify = nn.Linear(in_size, out_size) - model.classify.to(device) - print(model.classify.weight) - -def print_model(model: nn.Module): - print(model) - -def print_mlp(layer): - for l in layer.children(): - if isinstance(l, nn.Linear): - print(l.state_dict()) - else: - print(l) - - -# This function returns a model with the whole GNN completely reset -def full_reset(model : nn.Module): - mlp_list = [model.node_encoder, model.edge_encoder, model.global_encoder, - model.node_update, model.edge_update, model.global_update, - model.global_decoder] - - for mlp in mlp_list: - for layer in mlp.children(): - if hasattr(layer, 'reset_parameters'): - layer.reset_parameters() - partial_reset(model) - - -class GCN(nn.Module): - def __init__(self, in_size, hid_size, out_size, n_layers, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.layers = nn.ModuleList() - - # two-layer GCN - self.layers.extend( - [nn.Linear(in_size, hid_size),] + - [nn.Linear(hid_size, hid_size) for i in range(n_layers)] + - [dglnn.GraphConv(hid_size, hid_size) for i in range(n_layers)] + - [nn.Linear(hid_size, hid_size) for i in range(n_layers)] - ) - self.classify = nn.Linear(hid_size, out_size) - #self.dropout = nn.Dropout(0.05) - - def forward(self, g): - h = g.ndata['features'] - for i, layer in enumerate(self.layers): - if i >= self.n_layers + 1 and i < self.n_layers * 2 + 1: - h = layer(g, h) - else: - h = layer(h) - h = F.relu(h) - with g.local_scope(): - g.ndata['h'] = h - # Calculate graph representation by average readout. - hg = dgl.mean_nodes(g, 'h') - return self.classify(hg) - -class GCN_global(nn.Module): - def __init__(self, in_size, hid_size=4, out_size=1, n_layers=1, dropout=0, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - - #encoder - self.node_encoder = Make_MLP(in_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(1, hid_size, hid_size, n_layers, dropout=dropout) - - #GCN - self.node_update = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(2*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.conv = dglnn.GraphConv(hid_size, hid_size) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - def forward(self, g): - h = self.node_encoder(g.ndata['features']) - h_global = self.global_encoder(g.batch_num_nodes()[:, None].to(torch.float)) - for i in range(self.n_layers): - h = self.node_update(h) - h = self.conv(g, h) - g.ndata['h'] = h - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h')), dim = 1)) - h_global = self.global_decoder(h_global) - return self.classify(h_global) - -class GCN_global_2way(nn.Module): - def __init__(self, in_size, hid_size=4, out_size=1, n_layers=1, dropout=0, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - - #encoder - self.node_encoder = Make_MLP(in_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(1, hid_size, hid_size, n_layers, dropout=dropout) - - #GCN - self.node_update = Make_MLP(2*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(2*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.conv = dglnn.GraphConv(hid_size, hid_size) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - def forward(self, g): - h = self.node_encoder(g.ndata['features']) - h_global = self.global_encoder(g.batch_num_nodes()[:, None].to(torch.float)) - for i in range(self.n_layers): - h = self.node_update(torch.cat((h, broadcast_global_to_nodes(g, h_global)), dim = 1)) - h = self.conv(g, h) - g.ndata['h'] = h - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h')), dim = 1)) - h_global = self.global_decoder(h_global) - return self.classify(h_global) - -class Edge_Network(nn.Module): - def __init__(self, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - if (len(sample_global) == 0): - self.has_global = False - else: - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - #encoder - self.node_encoder = Make_MLP(sample_graph.ndata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.edge_encoder = Make_MLP(sample_graph.edata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(gl_size, hid_size, hid_size, n_layers, dropout=dropout) - - #GNN - self.node_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_update = Make_MLP(4*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - def forward(self, g, global_feats): - h = self.node_encoder(g.ndata['features']) - e = self.edge_encoder(g.edata['features']) - - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - - batch_num_nodes = None - sum_weights = None - if "w" in g.ndata: - batch_indices = g.batch_num_nodes() - # Find non-zero rows (non-padded nodes) - non_padded_nodes_mask = torch.any(g.ndata['features'] != 0, dim=1) - # Split the mask according to the batch indices - batch_num_nodes = [] - start_idx = 0 - for num_nodes in batch_indices: - end_idx = start_idx + num_nodes - non_padded_count = non_padded_nodes_mask[start_idx:end_idx].sum().item() - batch_num_nodes.append(non_padded_count) - start_idx = end_idx - batch_num_nodes = torch.tensor(batch_num_nodes, device = g.ndata['features'].device) - sum_weights = batch_num_nodes[:, None].repeat(1, 64) - global_feats = batch_num_nodes[:, None].to(torch.float) - - h_global = self.global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - if "w" in g.ndata: - mean_nodes = dgl.sum_nodes(g, 'h', 'w') / sum_weights - h_global = self.global_update(torch.cat((h_global, mean_nodes, dgl.mean_edges(g, 'e')), dim = 1)) - else: - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.global_decoder(h_global) - return self.classify(h_global) - - def representation(self, g, global_feats): - h = self.node_encoder(g.ndata['features']) - e = self.edge_encoder(g.edata['features']) - - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - - batch_num_nodes = None - sum_weights = None - if "w" in g.ndata: - batch_indices = g.batch_num_nodes() - # Find non-zero rows (non-padded nodes) - non_padded_nodes_mask = torch.any(g.ndata['features'] != 0, dim=1) - # Split the mask according to the batch indices - batch_num_nodes = [] - start_idx = 0 - for num_nodes in batch_indices: - end_idx = start_idx + num_nodes - non_padded_count = non_padded_nodes_mask[start_idx:end_idx].sum().item() - batch_num_nodes.append(non_padded_count) - start_idx = end_idx - batch_num_nodes = torch.tensor(batch_num_nodes, device = g.ndata['features'].device) - sum_weights = batch_num_nodes[:, None].repeat(1, 64) - global_feats = batch_num_nodes[:, None].to(torch.float) - - h_global = self.global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - if "w" in g.ndata: - mean_nodes = dgl.sum_nodes(g, 'h', 'w') / sum_weights - h_global = self.global_update(torch.cat((h_global, mean_nodes, dgl.mean_edges(g, 'e')), dim = 1)) - else: - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - before_global_decoder = h_global - after_global_decoder = self.global_decoder(before_global_decoder) - after_classify = self.classify(after_global_decoder) - return before_global_decoder, after_global_decoder, after_classify - - def __str__(self): - layer_names = ["node_encoder", "edge_encoder", "global_encoder", - "node_update", "edge_update", "global_update", "global_decoder"] - - layers = [self.node_encoder, self.edge_encoder, self.global_encoder, - self.node_update, self.edge_update, self.global_update, self.global_decoder] - - for i in range(len(layers)): - print(layer_names[i]) - for layer in layers[i].children(): - if isinstance(layer, nn.Linear): - print(layer.state_dict()) - - print("classify") - print(self.classify.weight) - return "" - -class Transferred_Learning(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - - if (len(sample_global) == 0): - self.has_global = False - else: - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.pretrained_model = utils.buildFromConfig(pretraining_model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - - checkpoint = torch.load(pretraining_path) - self.pretrained_model.load_state_dict(checkpoint['model_state_dict']) - pretrained_layers = list(self.pretrained_model.children()) - pretrained_layers = pretrained_layers[:-1] - self.pretrained_model = nn.Sequential(*pretrained_layers) - - # Freeze Weights - for param in self.pretrained_model.parameters(): - param.requires_grad = False # Freeze all layers - - self.global_decoder = Make_MLP(pretraining_model['args']['hid_size'], hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - def TL_node_encoder(self, x): - for layer in self.pretrained_model[1]: - x = layer(x) - return x - - def TL_edge_encoder(self, x): - for layer in self.pretrained_model[2]: - x = layer(x) - return x - - def TL_global_encoder(self, x): - for layer in self.pretrained_model[3]: - x = layer(x) - return x - - def TL_node_update(self, x): - for layer in self.pretrained_model[4]: - x = layer(x) - return x - - def TL_edge_update(self, x): - for layer in self.pretrained_model[5]: - x = layer(x) - return x - - def TL_global_update(self, x): - for layer in self.pretrained_model[6]: - x = layer(x) - return x - - def TL_global_decoder(self, x): - for layer in self.pretrained_model[7]: - x = layer(x) - return x - - def forward(self, g, global_feats): - h = self.TL_node_encoder(g.ndata['features']) - e = self.TL_edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.TL_global_decoder(h_global) - return self.classify(self.global_decoder(h_global)) - -class Transferred_Learning_Graph(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, additional_proc_steps=1, dropout=0, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - - if (len(sample_global) == 0): - self.has_global = False - else: - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.pretrained_model = utils.buildFromConfig(pretraining_model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - - checkpoint = torch.load(pretraining_path) - self.pretrained_model.load_state_dict(checkpoint['model_state_dict']) - pretrained_layers = list(self.pretrained_model.children()) - pretrained_layers = pretrained_layers[:-1] - self.pretrained_model = nn.Sequential(*pretrained_layers) - - self.additional_proc_steps = additional_proc_steps - - # Freeze Weights - for param in self.pretrained_model.parameters(): - param.requires_grad = False # Freeze all layers - - #GNN - self.node_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_update = Make_MLP(4*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - def TL_node_encoder(self, x): - for layer in self.pretrained_model[1]: - x = layer(x) - return x - - def TL_edge_encoder(self, x): - for layer in self.pretrained_model[2]: - x = layer(x) - return x - - def TL_global_encoder(self, x): - for layer in self.pretrained_model[3]: - x = layer(x) - return x - - def TL_node_update(self, x): - for layer in self.pretrained_model[4]: - x = layer(x) - return x - - def TL_edge_update(self, x): - for layer in self.pretrained_model[5]: - x = layer(x) - return x - - def TL_global_update(self, x): - for layer in self.pretrained_model[6]: - x = layer(x) - return x - - def forward(self, g, global_feats): - h = self.TL_node_encoder(g.ndata['features']) - e = self.TL_edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - for j in range(self.additional_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - - h_global = self.global_decoder(h_global) - return self.classify(h_global) - -class Transferred_Learning_Parallel(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.pretrained_model = utils.buildFromConfig(pretraining_model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - checkpoint = torch.load(pretraining_path) - self.pretrained_model.load_state_dict(checkpoint['model_state_dict']) - pretrained_layers = list(self.pretrained_model.children()) - pretrained_layers = pretrained_layers[:-1] - self.pretrained_model = nn.Sequential(*pretrained_layers) - - # Freeze Weights - for param in self.pretrained_model.parameters(): - param.requires_grad = False # Freeze all layers - - #encoder - self.node_encoder = Make_MLP(sample_graph.ndata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.edge_encoder = Make_MLP(sample_graph.edata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(gl_size, hid_size, hid_size, n_layers, dropout=dropout) - - #GNN - self.node_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_update = Make_MLP(4*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size + pretraining_model['args']['hid_size'], out_size) - - def TL_node_encoder(self, x): - for layer in self.pretrained_model[1]: - x = layer(x) - return x - - def TL_edge_encoder(self, x): - for layer in self.pretrained_model[2]: - x = layer(x) - return x - - def TL_global_encoder(self, x): - for layer in self.pretrained_model[3]: - x = layer(x) - return x - - def TL_node_update(self, x): - for layer in self.pretrained_model[4]: - x = layer(x) - return x - - def TL_edge_update(self, x): - for layer in self.pretrained_model[5]: - x = layer(x) - return x - - def TL_global_update(self, x): - for layer in self.pretrained_model[6]: - x = layer(x) - return x - - def TL_global_decoder(self, x): - for layer in self.pretrained_model[7]: - x = layer(x) - return x - - def Pretrained_Output(self, g): - h = self.TL_node_encoder(g.ndata['features']) - e = self.TL_edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.TL_global_decoder(h_global) - return h_global - - def forward(self, g, global_feats): - pretrained_global = self.Pretrained_Output(g.clone()) - h = self.node_encoder(g.ndata['features']) - e = self.edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.global_decoder(h_global) - - return self.classify(torch.cat((pretrained_global, h_global), dim = 1)) - -class Transferred_Learning_Sequential(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.pretrained_model = utils.buildFromConfig(pretraining_model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - checkpoint = torch.load(pretraining_path) - self.pretrained_model.load_state_dict(checkpoint['model_state_dict']) - pretrained_layers = list(self.pretrained_model.children()) - pretrained_layers = pretrained_layers[:-1] - self.pretrained_model = nn.Sequential(*pretrained_layers) - - # Freeze Weights - for param in self.pretrained_model.parameters(): - param.requires_grad = False # Freeze all layers - - #encoder - self.mlp = Make_MLP(pretraining_model['args']['hid_size'], hid_size, hid_size, n_layers, dropout=dropout) - - self.classify = nn.Linear(hid_size, out_size) - - def TL_node_encoder(self, x): - for layer in self.pretrained_model[1]: - x = layer(x) - return x - - def TL_edge_encoder(self, x): - for layer in self.pretrained_model[2]: - x = layer(x) - return x - - def TL_global_encoder(self, x): - for layer in self.pretrained_model[3]: - x = layer(x) - return x - - def TL_node_update(self, x): - for layer in self.pretrained_model[4]: - x = layer(x) - return x - - def TL_edge_update(self, x): - for layer in self.pretrained_model[5]: - x = layer(x) - return x - - def TL_global_update(self, x): - for layer in self.pretrained_model[6]: - x = layer(x) - return x - - def TL_global_decoder(self, x): - for layer in self.pretrained_model[7]: - x = layer(x) - return x - - def Pretrained_Output(self, g): - h = self.TL_node_encoder(g.ndata['features']) - e = self.TL_edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.TL_global_decoder(h_global) - return h_global - - def forward(self, g, global_feats): - pretrained_global = self.Pretrained_Output(g.clone()) - global_features = self.mlp(pretrained_global) - return self.classify(global_features) - - -class Transferred_Learning_Message_Passing(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.pretrained_model = utils.buildFromConfig(pretraining_model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - checkpoint = torch.load(pretraining_path) - self.pretrained_model.load_state_dict(checkpoint['model_state_dict']) - pretrained_layers = list(self.pretrained_model.children()) - pretrained_layers = pretrained_layers[:-1] - self.pretrained_model = nn.Sequential(*pretrained_layers) - - # Freeze Weights - for param in self.pretrained_model.parameters(): - param.requires_grad = False # Freeze all layers - - #encoder - self.mlp = Make_MLP(pretraining_model['args']['hid_size']*pretraining_model['args']['n_proc_steps'], hid_size, hid_size, n_layers, dropout=dropout) - - self.classify = nn.Linear(hid_size, out_size) - - def TL_node_encoder(self, x): - for layer in self.pretrained_model[1]: - x = layer(x) - return x - - def TL_edge_encoder(self, x): - for layer in self.pretrained_model[2]: - x = layer(x) - return x - - def TL_global_encoder(self, x): - for layer in self.pretrained_model[3]: - x = layer(x) - return x - - def TL_node_update(self, x): - for layer in self.pretrained_model[4]: - x = layer(x) - return x - - def TL_edge_update(self, x): - for layer in self.pretrained_model[5]: - x = layer(x) - return x - - def TL_global_update(self, x): - for layer in self.pretrained_model[6]: - x = layer(x) - return x - - def TL_global_decoder(self, x): - for layer in self.pretrained_model[7]: - x = layer(x) - return x - - def Pretrained_Output(self, g): - message_passing = None - h = self.TL_node_encoder(g.ndata['features']) - e = self.TL_edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - if (message_passing is None): - message_passing = h_global.clone() - else: - message_passing = torch.cat((message_passing, h_global.clone()), dim=1) - h_global = self.TL_global_decoder(h_global) - return message_passing - - def forward(self, g, global_feats): - pretrained_global = self.Pretrained_Output(g.clone()) - #print(f"message_passing layers have size = {pretrained_global.shape}") - #print(pretrained_global) - global_features = self.mlp(pretrained_global) - return self.classify(global_features) - -class Transferred_Learning_Message_Passing_Parallel(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.pretrained_model = utils.buildFromConfig(pretraining_model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - checkpoint = torch.load(pretraining_path) - self.pretrained_model.load_state_dict(checkpoint['model_state_dict']) - pretrained_layers = list(self.pretrained_model.children()) - pretrained_layers = pretrained_layers[:-1] - self.pretrained_model = nn.Sequential(*pretrained_layers) - - #encoder - self.node_encoder = Make_MLP(sample_graph.ndata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.edge_encoder = Make_MLP(sample_graph.edata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(gl_size, hid_size, hid_size, n_layers, dropout=dropout) - - #GNN - self.node_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_update = Make_MLP(4*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - # Freeze Weights - for param in self.pretrained_model.parameters(): - param.requires_grad = False # Freeze all layers - - self.classify = nn.Linear(pretraining_model['args']['hid_size']*pretraining_model['args']['n_proc_steps'] + hid_size, out_size) - - def TL_node_encoder(self, x): - for layer in self.pretrained_model[1]: - x = layer(x) - return x - - def TL_edge_encoder(self, x): - for layer in self.pretrained_model[2]: - x = layer(x) - return x - - def TL_global_encoder(self, x): - for layer in self.pretrained_model[3]: - x = layer(x) - return x - - def TL_node_update(self, x): - for layer in self.pretrained_model[4]: - x = layer(x) - return x - - def TL_edge_update(self, x): - for layer in self.pretrained_model[5]: - x = layer(x) - return x - - def TL_global_update(self, x): - for layer in self.pretrained_model[6]: - x = layer(x) - return x - - def TL_global_decoder(self, x): - for layer in self.pretrained_model[7]: - x = layer(x) - return x - - def Pretrained_Output(self, g): - message_passing = None - h = self.TL_node_encoder(g.ndata['features']) - e = self.TL_edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - if (message_passing is None): - message_passing = h_global.clone() - else: - message_passing = torch.cat((message_passing, h_global.clone()), dim=1) - h_global = self.TL_global_decoder(h_global) - return message_passing - - def forward(self, g, global_feats): - pretrained_message = self.Pretrained_Output(g.clone()) - h = self.node_encoder(g.ndata['features']) - e = self.edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.global_decoder(h_global) - return self.classify(torch.cat((pretrained_message, h_global), dim = 1)) - -class Transferred_Learning_Finetuning(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, frozen_pretraining=False, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - - if (len(sample_global) == 0): - self.has_global = False - else: - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.pretrained_model = utils.buildFromConfig(pretraining_model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - - checkpoint = torch.load(pretraining_path) - self.pretrained_model.load_state_dict(checkpoint['model_state_dict']) - pretrained_layers = list(self.pretrained_model.children()) - pretrained_layers = pretrained_layers[:-1] - self.pretrained_model = nn.Sequential(*pretrained_layers) - - print(f"Freeze Pretraining = {frozen_pretraining}") - if (frozen_pretraining): - for param in self.pretrained_model.parameters(): - param.requires_grad = False # Freeze all layers - for param in self.pretrained_model[7]: - param.requires_grad = True - - torch.manual_seed(2) - self.classify = nn.Linear(pretraining_model['args']['hid_size'], out_size) - - def TL_node_encoder(self, x): - for layer in self.pretrained_model[1]: - x = layer(x) - return x - - def TL_edge_encoder(self, x): - for layer in self.pretrained_model[2]: - x = layer(x) - return x - - def TL_global_encoder(self, x): - for layer in self.pretrained_model[3]: - x = layer(x) - return x - - def TL_node_update(self, x): - for layer in self.pretrained_model[4]: - x = layer(x) - return x - - def TL_edge_update(self, x): - for layer in self.pretrained_model[5]: - x = layer(x) - return x - - def TL_global_update(self, x): - for layer in self.pretrained_model[6]: - x = layer(x) - return x - - def TL_global_decoder(self, x): - for layer in self.pretrained_model[7]: - x = layer(x) - return x - - def Pretrained_Output(self, g): - h = self.TL_node_encoder(g.ndata['features']) - e = self.TL_edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.TL_global_decoder(h_global) - return h_global - - def forward(self, g, global_feats): - h_global = self.Pretrained_Output(g.clone()) - return self.classify(h_global) - - def representation(self, g, global_feats): - h = self.TL_node_encoder(g.ndata['features']) - e = self.TL_edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - - before_global_decoder = h_global - after_global_decoder = self.TL_global_decoder(before_global_decoder) - after_classify = self.classify(after_global_decoder) - return before_global_decoder, after_global_decoder, after_classify - - def __str__(self): - layer_names = ["node_encoder", "edge_encoder", "global_encoder", - "node_update", "edge_update", "global_update", "global_decoder"] - - layers = [self.pretrained_model[1], self.pretrained_model[2], self.pretrained_model[3], - self.pretrained_model[4], self.pretrained_model[5], self.pretrained_model[6], - self.pretrained_model[7]] - - for i in range(len(layers)): - print(layer_names[i]) - for layer in layers[i].children(): - if isinstance(layer, nn.Linear): - print(layer.state_dict()) - - print("classify") - print(self.classify.weight) - return "" - - -class Transferred_Learning_Parallel_Finetuning(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, learning_rate=0.0001, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - - self.learning_rate = learning_rate - - self.parallel_params = [] - self.finetuning_params = [] - - - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.pretrained_model = utils.buildFromConfig(pretraining_model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - checkpoint = torch.load(pretraining_path) - self.pretrained_model.load_state_dict(checkpoint['model_state_dict']) - pretrained_layers = list(self.pretrained_model.children()) - pretrained_layers = pretrained_layers[:-1] - self.pretrained_model = nn.Sequential(*pretrained_layers) - - self.finetuning_params.append(self.pretrained_model) - - #encoder - self.node_encoder = Make_MLP(sample_graph.ndata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.edge_encoder = Make_MLP(sample_graph.edata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(gl_size, hid_size, hid_size, n_layers, dropout=dropout) - - #GNN - self.node_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_update = Make_MLP(4*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size + pretraining_model['args']['hid_size'], out_size) - - self.parallel_params.append(self.node_encoder) - self.parallel_params.append(self.edge_encoder) - self.parallel_params.append(self.global_encoder) - self.parallel_params.append(self.node_update) - self.parallel_params.append(self.edge_update) - self.parallel_params.append(self.global_update) - self.parallel_params.append(self.global_decoder) - self.parallel_params.append(self.classify) - - def TL_node_encoder(self, x): - for layer in self.pretrained_model[1]: - x = layer(x) - return x - - def TL_edge_encoder(self, x): - for layer in self.pretrained_model[2]: - x = layer(x) - return x - - def TL_global_encoder(self, x): - for layer in self.pretrained_model[3]: - x = layer(x) - return x - - def TL_node_update(self, x): - for layer in self.pretrained_model[4]: - x = layer(x) - return x - - def TL_edge_update(self, x): - for layer in self.pretrained_model[5]: - x = layer(x) - return x - - def TL_global_update(self, x): - for layer in self.pretrained_model[6]: - x = layer(x) - return x - - def TL_global_decoder(self, x): - for layer in self.pretrained_model[7]: - x = layer(x) - return x - - def Pretrained_Output(self, g): - h = self.TL_node_encoder(g.ndata['features']) - e = self.TL_edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.TL_global_decoder(h_global) - return h_global - - def forward(self, g, global_feats): - pretrained_global = self.Pretrained_Output(g.clone()) - h = self.node_encoder(g.ndata['features']) - e = self.edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.global_decoder(h_global) - - return self.classify(torch.cat((pretrained_global, h_global), dim = 1)) - - def parameters(self, recurse: bool = True): - params = [] - for model_section in self.parallel_params: - if (type(self.learning_rate) == dict and self.learning_rate["trainable_lr"]): - params.append({'params': model_section.parameters(), 'lr': self.learning_rate["trainable_lr"]}) - else: - params.append({'params': model_section.parameters(), 'lr': 0.0001}) - for model_section in self.finetuning_params: - if (type(self.learning_rate) == dict and self.learning_rate["finetuning_lr"]): - params.append({'params': model_section.parameters(), 'lr': self.learning_rate["finetuning_lr"]}) - else: - params.append({'params': model_section.parameters(), 'lr': 0.0001}) - return params - -class Attention(nn.Module): - def __init__(self, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, num_heads = 1, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - self.hid_size = hid_size - gl_size = sample_global.shape[1] if self.has_global else 1 - - #encoder - self.node_encoder = Make_MLP(sample_graph.ndata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(gl_size, hid_size, hid_size, n_layers, dropout=dropout) - - #GNN - self.node_update = Make_MLP(2*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(2*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - #attention - self.multihead_attn = nn.MultiheadAttention(hid_size, num_heads, dropout=dropout, batch_first=True) - self.queries = nn.Linear(hid_size, hid_size) - self.keys = nn.Linear(hid_size, hid_size) - self.values = nn.Linear(hid_size, hid_size) - - def forward(self, g, global_feats): - h = self.node_encoder(g.ndata['features']) - g.ndata['h'] = h - - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - - batch_num_nodes = None - sum_weights = None - if "w" in g.ndata: - batch_indices = g.batch_num_nodes() - # Find non-zero rows (non-padded nodes) - non_padded_nodes_mask = torch.any(g.ndata['features'] != 0, dim=1) - # Split the mask according to the batch indices - batch_num_nodes = [] - start_idx = 0 - for num_nodes in batch_indices: - end_idx = start_idx + num_nodes - non_padded_count = non_padded_nodes_mask[start_idx:end_idx].sum().item() - batch_num_nodes.append(non_padded_count) - start_idx = end_idx - batch_num_nodes = torch.tensor(batch_num_nodes, device = g.ndata['features'].device) - sum_weights = batch_num_nodes[:, None].repeat(1, self.hid_size) - global_feats = batch_num_nodes[:, None].to(torch.float) - - h_global = self.global_encoder(global_feats) - - h_original_shape = h.shape - num_graphs = len(dgl.unbatch(g)) - num_nodes = g.batch_num_nodes()[0].item() - padding_mask = g.ndata['padding_mask'] > 0 - padding_mask = torch.reshape(padding_mask, (num_graphs, num_nodes)) - - h = g.ndata['h'] - query = self.queries(h) - key = self.keys(h) - value = self.values(h) - query = torch.reshape(query, (num_graphs, num_nodes, h_original_shape[1])) - key = torch.reshape(key, (num_graphs, num_nodes, h_original_shape[1])) - value = torch.reshape(value, (num_graphs, num_nodes, h_original_shape[1])) - h, _ = self.multihead_attn(query, key, value, key_padding_mask=padding_mask) - h = torch.reshape(h, h_original_shape) - - h = self.node_update(torch.cat((h, broadcast_global_to_nodes(g, h_global)), dim = 1)) - g.ndata['h'] = h - mean_nodes = dgl.sum_nodes(g, 'h', 'w') / sum_weights - h_global = self.global_update(torch.cat((h_global, mean_nodes), dim = 1)) - h_global = self.global_decoder(h_global) - return self.classify(h_global) - -class Attention_Edge_Network(nn.Module): - def __init__(self, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, num_heads = 1, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - #encoder - self.node_encoder = Make_MLP(sample_graph.ndata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.edge_encoder = Make_MLP(sample_graph.edata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(gl_size, hid_size, hid_size, n_layers, dropout=dropout) - - #GNN - self.node_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_update = Make_MLP(4*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - - #attention - self.multihead_attn = nn.MultiheadAttention(hid_size, num_heads, dropout=dropout, batch_first=True) - self.queries = nn.Linear(hid_size, hid_size) - self.keys = nn.Linear(hid_size, hid_size) - self.values = nn.Linear(hid_size, hid_size) - - def forward(self, g, global_feats): - h = self.node_encoder(g.ndata['features']) - e = self.edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.global_encoder(global_feats) - - h = g.ndata['h'] - h_original_shape = h.shape - num_graphs = len(dgl.unbatch(g)) - num_nodes = g.batch_num_nodes()[0].item() - padding_mask = g.ndata['padding_mask'].bool() - - padding_mask = torch.reshape(padding_mask, (num_graphs, num_nodes)) - - for i in range(self.n_proc_steps): - - h = g.ndata['h'] - query = self.queries(h) - key = self.keys(h) - value = self.values(h) - query = torch.reshape(query, (num_graphs, num_nodes, h_original_shape[1])) - key = torch.reshape(key, (num_graphs, num_nodes, h_original_shape[1])) - value = torch.reshape(value, (num_graphs, num_nodes, h_original_shape[1])) - h, _ = self.multihead_attn(query, key, value, key_padding_mask=padding_mask) - h = torch.reshape(h, h_original_shape) - - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h', 'w'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.global_decoder(h_global) - return self.classify(h_global) - -class Attention_Unbatched(nn.Module): - def __init__(self, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, num_heads = 1, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - #encoder - self.node_encoder = Make_MLP(sample_graph.ndata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.edge_encoder = Make_MLP(sample_graph.edata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(gl_size, hid_size, hid_size, n_layers, dropout=dropout) - - #GNN - self.node_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_update = Make_MLP(4*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - - #attention - self.multihead_attn = nn.MultiheadAttention(hid_size, 1, dropout=dropout) - self.queries = nn.Linear(hid_size, hid_size) - self.keys = nn.Linear(hid_size, hid_size) - self.values = nn.Linear(hid_size, hid_size) - - - - def forward(self, g, global_feats): - - h = self.node_encoder(g.ndata['features']) - e = self.edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.global_encoder(global_feats) - - for i in range(self.n_proc_steps): - - unbatched_g = dgl.unbatch(g) - for graph in unbatched_g: - h = graph.ndata['h'] - h, _ = self.multihead_attn(self.queries(h), self.keys(h), self.values(h)) - graph.ndata['h'] = h - g = dgl.batch(unbatched_g) - - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.global_decoder(h_global) - return self.classify(h_global) - -class Transferred_Learning_Attention(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, num_heads, dropout=0, learning_rate=0.0001, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - self.hid_size = hid_size - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.learning_rate = learning_rate - - self.pretraining_params = [] - self.attention_params = [] - - self.pretrained_model = utils.buildFromConfig(pretraining_model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - - checkpoint = torch.load(pretraining_path) - self.pretrained_model.load_state_dict(checkpoint['model_state_dict']) - pretrained_layers = list(self.pretrained_model.children()) - pretrained_layers = pretrained_layers[:-1] - self.pretrained_model = nn.Sequential(*pretrained_layers) - - self.pretraining_params.append(self.pretrained_model[1]) - self.pretraining_params.append(self.pretrained_model[3]) - self.pretraining_params.append(self.pretrained_model[7]) - - #attention - self.multihead_attn = nn.MultiheadAttention(hid_size, num_heads, dropout=dropout, batch_first=True) - self.queries = nn.Linear(hid_size, hid_size) - self.keys = nn.Linear(hid_size, hid_size) - self.values = nn.Linear(hid_size, hid_size) - - self.node_update = Make_MLP(2*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(2*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - self.classify = nn.Linear(pretraining_model['args']['hid_size'], out_size) - - self.attention_params.append(self.multihead_attn) - - self.attention_params.append(self.queries) - self.attention_params.append(self.keys) - self.attention_params.append(self.values) - self.attention_params.append(self.classify) - self.attention_params.append(self.node_update) - self.attention_params.append(self.global_update) - - def TL_node_encoder(self, x): - for layer in self.pretrained_model[1]: - x = layer(x) - return x - - def TL_global_encoder(self, x): - for layer in self.pretrained_model[3]: - x = layer(x) - return x - - def TL_global_decoder(self, x): - for layer in self.pretrained_model[7]: - x = layer(x) - return x - - def forward(self, g, global_feats): - h = self.TL_node_encoder(g.ndata['features']) - g.ndata['h'] = h - - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - - batch_num_nodes = None - sum_weights = None - if "w" in g.ndata: - batch_indices = g.batch_num_nodes() - # Find non-zero rows (non-padded nodes) - non_padded_nodes_mask = torch.any(g.ndata['features'] != 0, dim=1) - # Split the mask according to the batch indices - batch_num_nodes = [] - start_idx = 0 - for num_nodes in batch_indices: - end_idx = start_idx + num_nodes - non_padded_count = non_padded_nodes_mask[start_idx:end_idx].sum().item() - batch_num_nodes.append(non_padded_count) - start_idx = end_idx - batch_num_nodes = torch.tensor(batch_num_nodes, device = g.ndata['features'].device) - sum_weights = batch_num_nodes[:, None].repeat(1, self.hid_size) - global_feats = batch_num_nodes[:, None].to(torch.float) - - h_global = self.TL_global_encoder(global_feats) - - h_original_shape = h.shape - num_graphs = len(dgl.unbatch(g)) - num_nodes = g.batch_num_nodes()[0].item() - padding_mask = g.ndata['padding_mask'] > 0 - padding_mask = torch.reshape(padding_mask, (num_graphs, num_nodes)) - - h = g.ndata['h'] - query = self.queries(h) - key = self.keys(h) - value = self.values(h) - query = torch.reshape(query, (num_graphs, num_nodes, h_original_shape[1])) - key = torch.reshape(key, (num_graphs, num_nodes, h_original_shape[1])) - value = torch.reshape(value, (num_graphs, num_nodes, h_original_shape[1])) - h, _ = self.multihead_attn(query, key, value, key_padding_mask=padding_mask) - h = torch.reshape(h, h_original_shape) - - h = self.node_update(torch.cat((h, broadcast_global_to_nodes(g, h_global)), dim = 1)) - g.ndata['h'] = h - mean_nodes = dgl.sum_nodes(g, 'h', 'w') / sum_weights - h_global = self.global_update(torch.cat((h_global, mean_nodes), dim = 1)) - h_global = self.TL_global_decoder(h_global) - return self.classify(h_global) - - def parameters(self, recurse: bool = True): - params = [] - for model_section in self.pretraining_params: - if (type(self.learning_rate) == dict and self.learning_rate["pretraining_lr"]): - params.append({'params': model_section.parameters(), 'lr': self.learning_rate["pretraining_lr"]}) - else: - params.append({'params': model_section.parameters(), 'lr': 0.0001}) - for model_section in self.attention_params: - if (type(self.learning_rate) == dict and self.learning_rate["attention_lr"]): - params.append({'params': model_section.parameters(), 'lr': self.learning_rate["attention_lr"]}) - else: - params.append({'params': model_section.parameters(), 'lr': 0.0001}) - return params - -class Multimodel_Transferred_Learning(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, frozen_pretraining=True, learning_rate=None, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.learning_rate = learning_rate - input_size = 0 - - self.pretraining_params = [] - self.model_params = [] - - self.pretrained_models = [] - for model, path in zip(pretraining_model, pretraining_path): - input_size += model['args']['hid_size'] - model = utils.buildFromConfig(model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - - checkpoint = torch.load(path)['model_state_dict'] - new_state_dict = {} - for k, v in checkpoint.items(): - new_key = k.replace('module.', '') - new_state_dict[new_key] = v - model.load_state_dict(new_state_dict) - pretrained_layers = list(model.children()) - pretrained_layers = pretrained_layers[:-1] - - model = nn.Sequential(*pretrained_layers) - - # Freeze Weights - print(f"Freeze Pretraining = {frozen_pretraining}") - if (frozen_pretraining): - for param in model.parameters(): - param.requires_grad = False # Freeze all layers - self.pretraining_params.append(model) - self.pretrained_models.append(model) - - print(f"len(pretrained_models) = {len(self.pretrained_models)}") - print(f"input size = {input_size}") - - self.final_mlp = Make_MLP(input_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - self.model_params.append(self.final_mlp) - self.model_params.append(self.classify) - - def TL_node_encoder(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][1]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][1]: - x = layer(x) - return x - - def TL_edge_encoder(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][2]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][2]: - x = layer(x) - return x - - def TL_global_encoder(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][3]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][3]: - x = layer(x) - return x - - def TL_node_update(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][4]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][4]: - x = layer(x) - return x - - def TL_edge_update(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][5]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][5]: - x = layer(x) - return x - - def TL_global_update(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][6]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][6]: - x = layer(x) - return x - - def TL_global_decoder(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][7]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][7]: - x = layer(x) - return x - - def Pretrained_Output(self, g, model_idx): - h = self.TL_node_encoder(g.ndata['features'], model_idx) - e = self.TL_edge_encoder(g.edata['features'], model_idx) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats, model_idx) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1), model_idx) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1), model_idx) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1), model_idx) - # h_global = self.TL_global_decoder(h_global, model_idx) - return h_global - - def forward(self, g, global_feats): - h_global = [] - for i in range(len(self.pretrained_models)): - h_global.append(self.Pretrained_Output(g.clone(), i)) - h_global = torch.concatenate(h_global, dim=1) - return self.classify(self.final_mlp(h_global)) - - def to(self, device): - for i in range(len(self.pretrained_models)): - self.pretrained_models[i].to(device) - self.classify.to(device) - self.final_mlp.to(device) - return self - - def parameters(self, recurse: bool = True): - params = [] - for model_section in self.pretraining_params: - if (type(self.learning_rate) == dict and self.learning_rate["pretraining_lr"]): - params.append({'params': model_section.parameters(), 'lr': self.learning_rate["pretraining_lr"]}) - else: - params.append({'params': model_section.parameters(), 'lr': 0.00001}) - for model_section in self.model_params: - if (type(self.learning_rate) == dict and self.learning_rate["model_lr"]): - params.append({'params': model_section.parameters(), 'lr': self.learning_rate["model_lr"]}) - else: - params.append({'params': model_section.parameters(), 'lr': 0.0001}) - return params - - -class MultiModel(nn.Module): - def __init__(self, pretraining_path, pretraining_model, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, frozen_pretraining=True, learning_rate=None, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - self.learning_rate = learning_rate - input_size = 0 - - self.model_params = [] - self.pretraining_params = [] - - self.pretrained_models = [] - for model, path in zip(pretraining_model, pretraining_path): - input_size += model['args']['hid_size'] - model = utils.buildFromConfig(model, {'sample_graph': sample_graph, 'sample_global': sample_global}) - - checkpoint = torch.load(path)['model_state_dict'] - new_state_dict = {} - for k, v in checkpoint.items(): - new_key = k.replace('module.', '') - new_state_dict[new_key] = v - model.load_state_dict(new_state_dict) - pretrained_layers = list(model.children()) - pretrained_layers = pretrained_layers[:-1] - - model = nn.Sequential(*pretrained_layers) - - # Freeze Weights - print(f"Freeze Pretraining = {frozen_pretraining}") - if (frozen_pretraining): - for param in model.parameters(): - param.requires_grad = False # Freeze all layers - self.pretraining_params.append(model) - self.pretrained_models.append(model) - - print(f"len(pretrained_models) = {len(self.pretrained_models)}") - print(f"input size = {input_size}") - - #encoder - self.node_encoder = Make_MLP(sample_graph.ndata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.edge_encoder = Make_MLP(sample_graph.edata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(gl_size, hid_size, hid_size, n_layers, dropout=dropout) - - #GNN - self.node_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_update = Make_MLP(4*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - self.final_mlp = Make_MLP(input_size + hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - self.model_params.append(self.final_mlp) - self.model_params.append(self.classify) - - def TL_node_encoder(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][1]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][1]: - x = layer(x) - return x - - def TL_edge_encoder(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][2]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][2]: - x = layer(x) - return x - - def TL_global_encoder(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][3]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][3]: - x = layer(x) - return x - - def TL_node_update(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][4]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][4]: - x = layer(x) - return x - - def TL_edge_update(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][5]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][5]: - x = layer(x) - return x - - def TL_global_update(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][6]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][6]: - x = layer(x) - return x - - def TL_global_decoder(self, x, model_idx): - try: - for layer in self.pretrained_models[model_idx][7]: - x = layer(x) - return x - except (NotImplementedError, IndexError): - for layer in self.pretrained_models[model_idx][1][7]: - x = layer(x) - return x - - def Pretrained_Output(self, g, model_idx): - h = self.TL_node_encoder(g.ndata['features'], model_idx) - e = self.TL_edge_encoder(g.edata['features'], model_idx) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.TL_global_encoder(global_feats, model_idx) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.TL_edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1), model_idx) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.TL_node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1), model_idx) - h_global = self.TL_global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1), model_idx) - # h_global = self.TL_global_decoder(h_global, model_idx) - return h_global - - def forward(self, g, global_feats): - h = self.node_encoder(g.ndata['features']) - e = self.edge_encoder(g.edata['features']) - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - h_global = self.global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = [h_global] - for i in range(len(self.pretrained_models)): - h_global.append(self.Pretrained_Output(g.clone(), i)) - h_global = torch.concatenate(h_global, dim=1) - return self.classify(self.final_mlp(h_global)) - - def to(self, device): - for i in range(len(self.pretrained_models)): - self.pretrained_models[i].to(device) - self.classify.to(device) - self.final_mlp.to(device) - self.node_encoder.to(device) - self.edge_encoder.to(device) - self.global_encoder.to(device) - - self.node_update.to(device) - self.edge_update.to(device) - self.global_update.to(device) - return self - - def parameters(self, recurse: bool = True): - params = [] - for i, model_section in enumerate(self.pretraining_params): - if (type(self.learning_rate) == dict and self.learning_rate["pretraining_lr"]): - print(f"Pretraining LR = {self.learning_rate['pretraining_lr'][i]}") - params.append({'params': model_section.parameters(), 'lr': self.learning_rate["pretraining_lr"][i]}) - else: - print(f"Pretraining LR = 0.00001") - params.append({'params': model_section.parameters(), 'lr': 0.00001}) - for model_section in self.model_params: - if (type(self.learning_rate) == dict and self.learning_rate["model_lr"]): - print(f"Model LR = {self.learning_rate['model_lr']}") - params.append({'params': model_section.parameters(), 'lr': self.learning_rate["model_lr"]}) - else: - print(f"Model LR = 0.0001") - params.append({'params': model_section.parameters(), 'lr': 0.0001}) - return params - - -class Clustering(nn.Module): - def __init__(self, sample_graph, sample_global, hid_size, out_size, n_layers, n_proc_steps, dropout=0, **kwargs): - super().__init__() - print(f'Unused args while creating GCN: {kwargs}') - self.n_layers = n_layers - self.n_proc_steps = n_proc_steps - self.layers = nn.ModuleList() - self.hid_size = hid_size - if (len(sample_global) == 0): - self.has_global = False - else: - self.has_global = sample_global.shape[1] != 0 - gl_size = sample_global.shape[1] if self.has_global else 1 - - #encoder - self.node_encoder = Make_MLP(sample_graph.ndata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.edge_encoder = Make_MLP(sample_graph.edata['features'].shape[1], hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = Make_MLP(gl_size, hid_size, hid_size, n_layers, dropout=dropout) - - #GNN - self.node_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_update = Make_MLP(4*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = Make_MLP(3*hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - #decoder - self.global_decoder = Make_MLP(hid_size, hid_size, out_size, n_layers, dropout=dropout) - - def model_forward(self, g, global_feats, features = 'features'): - h = self.node_encoder(g.ndata[features]) - e = self.edge_encoder(g.edata[features]) - - g.ndata['h'] = h - g.edata['e'] = e - if not self.has_global: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - - batch_num_nodes = None - sum_weights = None - if "w" in g.ndata: - batch_indices = g.batch_num_nodes() - # Find non-zero rows (non-padded nodes) - non_padded_nodes_mask = torch.any(g.ndata[features] != 0, dim=1) - # Split the mask according to the batch indices - batch_num_nodes = [] - start_idx = 0 - for num_nodes in batch_indices: - end_idx = start_idx + num_nodes - non_padded_count = non_padded_nodes_mask[start_idx:end_idx].sum().item() - batch_num_nodes.append(non_padded_count) - start_idx = end_idx - batch_num_nodes = torch.tensor(batch_num_nodes, device = g.ndata[features].device) - sum_weights = batch_num_nodes[:, None].repeat(1, self.hid_size) - global_feats = batch_num_nodes[:, None].to(torch.float) - - h_global = self.global_encoder(global_feats) - for i in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u('h', 'm_u')) - g.apply_edges(copy_v) - g.edata['e'] = self.edge_update(torch.cat((g.edata['e'], g.edata['m_u'], g.edata['m_v'], broadcast_global_to_edges(g, h_global)), dim = 1)) - g.update_all(dgl.function.copy_e('e', 'm'), dgl.function.sum('m', 'h_e')) - g.ndata['h'] = self.node_update(torch.cat((g.ndata['h'], g.ndata['h_e'], broadcast_global_to_nodes(g, h_global)), dim = 1)) - if "w" in g.ndata: - mean_nodes = dgl.sum_nodes(g, 'h', 'w') / sum_weights - h_global = self.global_update(torch.cat((h_global, mean_nodes, dgl.mean_edges(g, 'e')), dim = 1)) - else: - h_global = self.global_update(torch.cat((h_global, dgl.mean_nodes(g, 'h'), dgl.mean_edges(g, 'e')), dim = 1)) - h_global = self.global_decoder(h_global) - return h_global - - def forward(self, g, global_feats): - h_global = self.model_forward(g, global_feats, 'features') - h_global_augmented = self.model_forward(g, global_feats, 'augmented_features') - return torch.cat((h_global, h_global_augmented), dim=1) - - def representation(self, g, global_feats): - h_global = self.model_forward(g, global_feats, 'features') - h_global_augmented = self.model_forward(g, global_feats, 'augmented_features') - return h_global, h_global_augmented, torch.cat((h_global, h_global_augmented), dim=1) - - def __str__(self): - layer_names = ["node_encoder", "edge_encoder", "global_encoder", - "node_update", "edge_update", "global_update", "global_decoder"] - - layers = [self.node_encoder, self.edge_encoder, self.global_encoder, - self.node_update, self.edge_update, self.global_update, self.global_decoder] - - for i in range(len(layers)): - print(layer_names[i]) - for layer in layers[i].children(): - if isinstance(layer, nn.Linear): - print(layer.state_dict()) - - print("classify") - print(self.classify.weight) - return "" \ No newline at end of file diff --git a/legacy/root_gnn_dgl/models/loss.py b/legacy/root_gnn_dgl/models/loss.py deleted file mode 100755 index c846861ca33f1020a0e8099a7e432fd0ab3528df..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/models/loss.py +++ /dev/null @@ -1,311 +0,0 @@ -from torch import nn -import torch -from root_gnn_base import utils -import numpy as np - -class MaskedLoss(): - def __init__(self, mask = []): - self.mask = mask - - def make_mask(self, targets): - mask = torch.ones_like(targets[:,0]) - for m in self.mask: - if m['op'] == 'eq': - mask[targets[:,m['idx']] == m['val']] = 0 - elif m['op'] == 'gt': - mask[targets[:,m['idx']] > m['val']] = 0 - elif m['op'] == 'lt': - mask[targets[:,m['idx']] < m['val']] = 0 - elif m['op'] == 'ge': - mask[targets[:,m['idx']] >= m['val']] = 0 - elif m['op'] == 'le': - mask[targets[:,m['idx']] <= m['val']] = 0 - elif m['op'] == 'ne': - mask[targets[:,m['idx']] != m['val']] = 0 - else: - raise ValueError(f'Unknown mask op {m["op"]}') - return mask == 1 - -class MaskedL1Loss(MaskedLoss): - def __init__(self, mask = [], index = 0): - super().__init__(mask) - self.index = index - self.loss = nn.L1Loss() - - def __call__(self, logits, targets): - mask = self.make_mask(targets) - return self.loss(logits[mask], targets[mask][:,self.index]) - -class BCEWithLogitsLoss(): - def __init__(self, weight=None, reduction='mean'): - self.loss = nn.BCEWithLogitsLoss(weight=weight, reduction=reduction) - - def __call__(self, logits, targets): - return self.loss(logits[:,0], targets.float()) - -class MultiScore(): - def __init__(self, scores): - self. score_fcns = [] - self.start_idx = [] - self.end_idx = [] - for score in scores: - self.score_fcns.append(utils.buildFromConfig(score)) - self.start_idx.append(score['start_idx']) - self.end_idx.append(score['end_idx']) - - def __call__(self, last_layer): - scores = [] - for i in range(len(self.score_fcns)): - scores.append(self.score_fcns[i](last_layer[:, self.start_idx[i]:self.end_idx[i]])) - return torch.cat(scores, dim=1) - -class MultiLoss(): - def __init__(self, losses): - self.loss_fcns = [] - self.label_start_idx = [] - self.label_end_idx = [] - self.output_start_idx = [] - self.output_end_idx = [] - self.weights = [] - self.label_types = [] - for loss in losses: - self.loss_fcns.append(utils.buildFromConfig(loss)) - self.label_start_idx.append(loss['label_start_idx']) - self.label_end_idx.append(loss['label_end_idx']) - self.output_start_idx.append(loss['output_start_idx']) - self.output_end_idx.append(loss['output_end_idx']) - self.weights.append(loss.get('weight', 1.0)) - self.label_types.append(loss.get('label_type', 'float')) - - def __call__(self, logits, targets): - loss = 0 - # print(logits.shape, targets.shape) - for i in range(len(self.loss_fcns)): - if self.label_types[i] == 'int': - # print('loss', i, self.label_start_idx[i], self.label_end_idx[i], self.output_start_idx[i], self.output_end_idx[i]) - # print(logits[:, self.output_start_idx[i]:self.output_end_idx[i]].shape, targets[:, self.label_start_idx[i]].shape) - loss += self.weights[i] * self.loss_fcns[i](logits[:, self.output_start_idx[i]:self.output_end_idx[i]], targets[:, self.label_start_idx[i]].to(int)) - elif self.label_end_idx[i] - self.label_start_idx[i] == 1: - loss += self.weights[i] * self.loss_fcns[i](logits[:, self.output_start_idx[i]:self.output_end_idx[i]], targets[:, self.label_start_idx[i]]) - else: - # print('loos', i, self.label_start_idx[i], self.label_end_idx[i], self.output_start_idx[i], self.output_end_idx[i]) - # print(logits[:, self.output_start_idx[i]:self.output_end_idx[i]].shape, targets[:, self.label_start_idx[i]:self.label_end_idx[i]].shape) - loss += self.weights[i] * self.loss_fcns[i](logits[:, self.output_start_idx[i]:self.output_end_idx[i]], targets[:, self.label_start_idx[i]:self.label_end_idx[i]]) - return loss - -class AdvLoss(): - def __init__(self, loss, adv_loss, adv_weight=1.0): - self.loss_fcn = utils.buildFromConfig(loss) - self.adv_loss_fcn = utils.buildFromConfig(adv_loss) - self.adv_weight = adv_weight - - def __call__(self, logits, targets): - mask = targets[:,0] == 0 - loss = self.loss_fcn(logits[:,0], targets[:,0]) - adv_loss = self.adv_loss_fcn(logits[mask][:,1], targets[mask]) - return loss - self.adv_weight * adv_loss - -class MassWindowAdvLoss(AdvLoss): - def __call__(self, logits, targets): - mask = (targets[:,0] == 0) & (targets[:,1] > 5) & (targets[:,1] < 25) - print(mask, mask.shape, mask.sum()) - loss = self.loss_fcn(logits[:,0], targets[:,0]) - print(loss) - adv_loss = self.adv_loss_fcn(logits[mask][:,1], targets[mask][:,1]) - print(adv_loss) - return loss - self.adv_weight * adv_loss - -class KDELoss(MaskedLoss): - def __init__(self, mask = [], index = 0): - self.index = index - super().__init__(mask) - - def __call__(self, logits, targets): - mask = self.make_mask(targets) - logits = logits[mask] - targets = targets[mask][:,self.index] - N = logits.shape[0] - masses = targets / torch.sqrt(torch.mean(targets**2)) - scores = logits[:,0] / torch.sqrt(torch.mean(logits**2)) - - factor_2d = (1.0*N) ** (-2/6) - covs = (factor_2d * torch.var(masses), factor_2d * torch.var(scores)) - - m_diffs = torch.unsqueeze(masses, 1) - torch.unsqueeze(masses, 0) - s_diffs = torch.unsqueeze(scores, 1) - torch.unsqueeze(scores, 0) - - ymm = torch.exp(- (m_diffs**2) / (4 * covs[0])) - yss = torch.exp(- (s_diffs**2) / (4 * covs[1])) - - integral_rho_2d_rho_2d = torch.einsum('ij,ij->', ymm, yss) - integral_rho_1d_rho_1d = torch.einsum('ij,kl->', ymm, yss) - integral_rho_2d_rho_1d = torch.einsum('ij,ik->', ymm, yss) - raw_integral = integral_rho_2d_rho_2d - 2 * integral_rho_2d_rho_1d / N + integral_rho_1d_rho_1d / N**2 - return raw_integral / (4 * torch.pi * N**2) - -class MultiLabelLoss(): - def __init__(self, label_names, label_types, label_weights = None): - self.loss_fcn = [] - if (label_weights): - self.weights = torch.tensor(label_weights) - else: - self.weights = torch.ones(len(label_types)) - for type in label_types: - if (type == "r"): - self.loss_fcn.append(torch.nn.MSELoss(reduce=False)) - elif (type == "c"): - self.loss_fcn.append(torch.nn.BCEWithLogitsLoss()) - print(f"self.weights = {self.weights}") - - def __call__(self, logits, targets): - targets = targets.float() - loss = torch.zeros(len(logits[:, 0]), device = logits.get_device()) - for i in range(len(self.loss_fcn)): - loss += self.weights[i] * self.loss_fcn[i](logits[:, i], targets[:, i]) - return torch.mean(loss) - - -class MultiLabelFinish(): - def __init__(self, label_names, label_types): - self.finish_fcn = [] - for type in label_types: - if (type == "r"): - self.finish_fcn.append(None) - elif (type == "c"): - self.finish_fcn.append(torch.special.expit) - - def __call__(self, logits): - for i in range(len(self.finish_fcn)): - if (self.finish_fcn[i]): - logits[:, i] = self.finish_fcn[i](logits[:, i].to(torch.long)) - return logits - -class ContrastiveClusterLoss(): - def __init__(self, k=10, temperature=1, alpha=1): - self.k = k - self.temperature = temperature - self.alpha = alpha - - def __call__(self, logits, targets): - targets = targets.float() - logits_combined = logits.float() - - hid_size = int(len(logits[0]) / 2) - - logits = normalize_embeddings(logits_combined[:, :hid_size]) - logits_augmented = normalize_embeddings(logits_combined[:, hid_size:]) - - contrastive = contrastive_loss(logits, logits_augmented, self.temperature) - clustering, _ = clustering_loss(logits, self.k) - - variance_loss = variance_regularization(logits) + variance_regularization(logits_augmented) - - return torch.mean(contrastive + clustering + self.alpha * variance_loss) - -class ContrastiveClusterFinish(): - def __init__(self, k = 10, temperature = 1, max_cluster_iterations = 10): - self.k = k - self.temperature = temperature - self.max_cluster_iterations = max_cluster_iterations - - print(f"ContrastiveClusterFinish: k = {k}, temperature = {temperature}") - - def __call__(self, logits): - logits_combined = logits.float() - - hid_size = int(len(logits[0]) / 2) - - logits = logits_combined[:, :hid_size] - logits_augmented = logits_combined[:, hid_size:] - - contrastive = contrastive_loss(logits, logits_augmented, self.temperature) - clustering, _ = clustering_loss(logits, self.k, self.max_cluster_iterations) - variance = variance_regularization(logits) + variance_regularization(logits_augmented) - - return contrastive, clustering, variance - -def s(z_i, z_j): - z_i = torch.tensor(z_i) if not isinstance(z_i, torch.Tensor) else z_i - z_j = torch.tensor(z_j) if not isinstance(z_j, torch.Tensor) else z_j - - return torch.cdist(z_i, z_j, p=2) - # dot_product = torch.dot(z_i, z_j) - # norm_i = torch.linalg.norm(z_i) - # norm_j = torch.linalg.norm(z_j) - - # return dot_product / (norm_i * norm_j) - -def contrastive_loss(logits, logits_augmented, temperature=1, margin=1.0): - logits = torch.tensor(logits) if not isinstance(logits, torch.Tensor) else logits - logits_augmented = torch.tensor(logits_augmented) if not isinstance(logits_augmented, torch.Tensor) else logits_augmented - - z = torch.cat((logits, logits_augmented), dim=0) - similarity_matrix = torch.mm(z, z.t()) / temperature - norms = torch.linalg.norm(z, dim=1) - norm_matrix = torch.ger(norms, norms) - similarity_matrix = similarity_matrix / norm_matrix - mask = torch.eye(similarity_matrix.size(0), dtype=torch.bool) - - loss = 0 - for k in range(len(logits)): - numerator = torch.exp(similarity_matrix[k, k + len(logits)]) - denominator = torch.sum(torch.exp(similarity_matrix[k, ~mask[k]])) - - loss += -torch.log(numerator / denominator) - - return loss - - -def clustering_loss(logits, k=10, max_iterations=10): - # Step 1: Initialize cluster means - indices = torch.randperm(logits.size(0))[:k] - cluster_means = logits[indices] - - prev_assignments = None - assignment_history = [] - iteration = 0 - - while iteration < max_iterations: - iteration += 1 - - # Step 2: Assign each data point to the nearest cluster mean - distances = torch.cdist(logits, cluster_means, p=2) # Compute distances between logits and cluster means - cluster_assignments = torch.argmin(distances, dim=1) # Assign each point to the nearest cluster mean - - # Check for convergence: if assignments do not change, break the loop - if prev_assignments is not None and torch.equal(cluster_assignments, prev_assignments): - break - - # Check for cycles: if assignments have been seen before, break the loop - if any(torch.equal(cluster_assignments, prev) for prev in assignment_history): - break - - assignment_history.append(cluster_assignments.clone()) - prev_assignments = cluster_assignments.clone() - - # Step 3: Update cluster means based on assignments - new_cluster_means = torch.zeros_like(cluster_means) - for i in range(k): - assigned_points = logits[cluster_assignments == i] - if assigned_points.size(0) > 0: - new_cluster_means[i] = assigned_points.mean(dim=0) - else: - # If no points are assigned to the cluster, reinitialize the mean randomly - new_cluster_means[i] = logits[torch.randint(0, logits.size(0), (1,)).item()] - cluster_means = new_cluster_means - - # Step 4: Compute the clustering loss - distances = torch.cdist(logits, cluster_means, p=2) - min_distances = torch.min(distances, dim=1)[0] - loss = torch.sum(min_distances ** 2) - - return loss, cluster_means - -def normalize_embeddings(embeddings): - return embeddings / embeddings.norm(dim=1, keepdim=True) - -def variance_regularization(embeddings): - mean_embedding = embeddings.mean(dim=0) - variance = ((embeddings - mean_embedding) ** 2).mean() - return variance - diff --git a/legacy/root_gnn_dgl/profile.sh b/legacy/root_gnn_dgl/profile.sh deleted file mode 100644 index 9d3b20f528c749c34c3de3fa4389e95a16300967..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/profile.sh +++ /dev/null @@ -1,35 +0,0 @@ -nsys profile \ - -o /pscratch/sd/j/joshuaho/full_stats_profile_1_gpu_batch_size_1028 \ - --capture-range=cudaProfilerApi \ - --duration=100 \ - --force-overwrite true \ - --trace=nvtx \ - --cudabacktrace=all \ - python scripts/training_script.py --config configs/stats_all/ttH_CP_even_vs_odd.yaml --preshuffle --nocompile --lazy --restart --profile - -nsys profile \ - -o /pscratch/sd/j/joshuaho/full_stats_profile_1_gpu_batch_size_2048 \ - --capture-range=cudaProfilerApi \ - --duration=100 \ - --force-overwrite true \ - --trace=nvtx \ - --cudabacktrace=all \ - python scripts/training_script.py --config configs/stats_all/ttH_CP_even_vs_odd_batch_size_2048.yaml --preshuffle --nocompile --lazy --restart --profile - -nsys profile \ - -o /pscratch/sd/j/joshuaho/full_stats_profile_1_gpu_batch_size_4096 \ - --capture-range=cudaProfilerApi \ - --duration=100 \ - --force-overwrite=true \ - --trace=nvtx \ - --cudabacktrace=all \ - python scripts/training_script.py --config configs/stats_all/ttH_CP_even_vs_odd_batch_size_4096.yaml --preshuffle --nocompile --lazy --restart --profile - -nsys profile \ - -o /pscratch/sd/j/joshuaho/full_stats_profile_1_gpu_batch_size_8192 \ - --capture-range=cudaProfilerApi \ - --duration=100 \ - --force-overwrite true \ - --trace=nvtx \ - --cudabacktrace=all \ - python scripts/training_script.py --config configs/stats_all/ttH_CP_even_vs_odd_batch_size_8192.yaml --preshuffle --nocompile --lazy --restart --profile diff --git a/legacy/root_gnn_dgl/root_gnn_base/batched_dataset.py b/legacy/root_gnn_dgl/root_gnn_base/batched_dataset.py deleted file mode 100644 index 94bcc3109d7de02e3282d42d06d8fe21fdde8124..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/root_gnn_base/batched_dataset.py +++ /dev/null @@ -1,219 +0,0 @@ -from dgl.dataloading import GraphDataLoader -from torch.utils.data.sampler import SubsetRandomSampler -from torch.utils.data.sampler import SequentialSampler -from dgl.data import DGLDataset -import torch -import time -import os -import dgl -from root_gnn_base import utils - -def GetBatchedLoader(dataset, batch_size, mask_fn = None, drop_last=True, **kwargs): - if mask_fn == None: - mask_fn = lambda x: torch.ones(len(x), dtype=torch.bool) - dloader = GraphDataLoader(dataset, sampler=SubsetRandomSampler(torch.arange(len(dataset))[mask_fn(dataset)]), batch_size=batch_size, drop_last=drop_last, num_workers = 0) - return dloader - -class FixedOrderSampler: - def __init__(self, indices): - self.indices = indices - - def __iter__(self): - return iter(self.indices.tolist()) - - def __len__(self): - return len(self.indices) - -def hash_partition(indices, chunks, seed): - if chunks <= 1: - return torch.zeros(len(indices), dtype=torch.long) - hashed = (indices * 1103515245 + int(seed)) % 2147483647 - return hashed % chunks - -#Dataset which contains prebatched shuffled graphs. Cannot be saved to disk, else batching info is lost. -class PreBatchedDataset(DGLDataset): - def __init__(self, start_dataset, batch_size, mask_fn = None, drop_last=True, save_to_disk = True, suffix = '', chunks = 1, chunkno = -1, shuffle = True, padding_mode = 'NONE', hidden_size=64, shuffle_seed=12345, **kwargs): - print(f'Unused kwargs: {kwargs}') - self.start_dataset = start_dataset - self.start_dataset.load() - - self.batch_size = batch_size - self.chunks = chunks - self.chunkno = chunkno - self.mask_fn = mask_fn - if self.mask_fn == None: - self.mask_fn = lambda x: torch.ones(len(x), dtype=torch.bool) - self.drop_last = drop_last - self.graphs = [] - self.label = [] - self.padding_mode = padding_mode - self.save_to_disk = save_to_disk - self.shuffle = shuffle - self.shuffle_seed = shuffle_seed - self.suffix = suffix - self.current_chunk = None - self.current_chunk_idx = -1 - self.hid_size = hidden_size - super().__init__(name = start_dataset.name + '_prebatched_padded', save_dir=start_dataset.save_dir) - - def process(self): - dataset_indices = torch.arange(len(self.start_dataset)) - fold_indices = dataset_indices[self.mask_fn(self.start_dataset)] - if self.shuffle: - if self.chunks > 1 and self.chunkno >= 0: - partitions = hash_partition(fold_indices, self.chunks, self.shuffle_seed) - fold_indices = fold_indices[partitions == self.chunkno] - print(f'Processing shuffled chunk {self.chunkno} of {self.chunks} with {len(fold_indices)} events from {len(self.start_dataset)} total') - dloader = GraphDataLoader(self.start_dataset, sampler=FixedOrderSampler(fold_indices), batch_size=self.batch_size, drop_last=self.drop_last) - else: #Only don't shuffle if we're doing inference. Then we want all of the events anyways? - print(f'Processing sequential dataset with {len(self.start_dataset)} events') - dloader = GraphDataLoader(self.start_dataset, sampler=SequentialSampler(self.start_dataset), batch_size=self.batch_size, drop_last=self.drop_last) - self.graphs = [] - self.labels = [] - self.tracking = [] - self.globals = [] - self.batch_num_nodes = [] - self.batch_num_edges = [] - max_edges = 0 - max_nodes = 0 - load_batch_start = time.time() - for batch, label, tracking, global_feat in dloader: - if batch.num_edges() > max_edges: - max_edges = batch.num_edges() - if batch.num_nodes() > max_nodes: - max_nodes = batch.num_nodes() - self.graphs.append(batch) - self.labels.append(label) - self.tracking.append(tracking) - self.globals.append(global_feat) - load_batch_end = time.time() - print(f'Loaded {len(self.graphs)} batches in {load_batch_end - load_batch_start} seconds') - if self.shuffle and len(self.graphs) > 1: - generator = torch.Generator() - generator.manual_seed(self.shuffle_seed + 7919 * max(self.chunkno, 0)) - batch_order = torch.randperm(len(self.graphs), generator=generator).tolist() - self.graphs = [self.graphs[i] for i in batch_order] - self.labels = [self.labels[i] for i in batch_order] - self.tracking = [self.tracking[i] for i in batch_order] - self.globals = [self.globals[i] for i in batch_order] - print(f'Shuffled {len(self.graphs)} prebatched batches before padding') - if self.padding_mode == 'STEPS': - pad_node, pad_edge = utils.pad_size(self.batch_size, max_edges, max_nodes) - elif self.padding_mode == 'FIXED': - print('Padding to fixed size. This is currently hardcoded.') - pad_node = 16000 - pad_edge = 104000 - elif self.padding_mode == 'NONE': - pad_node = 0 - pad_edge = 0 - else: - pad_node = 0 - pad_edge = 0 - print(f'Max edges: {max_edges}, Max nodes: {max_nodes}, Padding to {pad_edge} edges and {pad_node} nodes') - pad_start = time.time() - if self.padding_mode == 'NODE': - for i in range(len(self.graphs)): - unbatched_g = dgl.unbatch(self.graphs[i]) - max_num_nodes = max(g.number_of_nodes() for g in unbatched_g) - self.graphs[i] = utils.pad_batch_num_nodes(self.graphs[i], max_num_nodes, hid_size=self.hid_size) - self.batch_num_nodes.append(self.graphs[i].batch_num_nodes()) - self.batch_num_edges.append(self.graphs[i].batch_num_edges()) - else: - for i in range(len(self.graphs)): - self.graphs[i] = utils.pad_batch(self.graphs[i], pad_edge, pad_node) - self.batch_num_nodes.append(self.graphs[i].batch_num_nodes()) - self.batch_num_edges.append(self.graphs[i].batch_num_edges()) - pad_end = time.time() - print(f'Padded {len(self.graphs)} batches in {pad_end - pad_start} seconds') - - def save(self): - if not self.save_to_disk: - return - graph_path = os.path.join(self.save_dir, f'{self.name}_{self.chunkno}_{self.suffix}.bin') - print(f'Saving dataset to {graph_path}') - if len(self.graphs) == 0: - return - dgl.save_graphs(str(graph_path), self.graphs, {'labels': torch.stack(self.labels), 'batch_num_nodes': torch.stack(self.batch_num_nodes), 'batch_num_edges': torch.stack(self.batch_num_edges), 'tracking': torch.stack(self.tracking), 'globals': torch.stack(self.globals)}) - - def has_cache(self): - if not self.save_to_disk: - return False - for ch in range(self.chunks): - graph_path = os.path.join(self.save_dir, f'{self.name}_{ch}_{self.suffix}.bin') - if not os.path.exists(graph_path): - print(f'Cache file {graph_path} does not exist, not loading from cache.') - return False - return True - - def load(self): - if not self.save_to_disk: - return - self.graphs = [] - label_chunks = [] - tracking_chunks = [] - global_chunks = [] - for ch in range(self.chunks): - graph_path = os.path.join(self.save_dir, f'{self.name}_{ch}_{self.suffix}.bin') - print(f'Loading dataset from {graph_path}') - graphs, label_dict = dgl.load_graphs(graph_path) - label_chunks.append(label_dict['labels']) - tracking_chunks.append(label_dict['tracking']) - global_chunks.append(label_dict['globals']) - for g, bnn, bne in zip(graphs, label_dict['batch_num_nodes'], label_dict['batch_num_edges']): - g.set_batch_num_nodes(bnn) - g.set_batch_num_edges(bne) - self.graphs.extend(graphs) - self.labels = torch.cat(label_chunks) - self.tracking = torch.cat(tracking_chunks) - self.globals = torch.cat(global_chunks) - - def __getitem__(self, idx): - return self.graphs[idx], self.labels[idx], self.tracking[idx], self.globals[idx] - - def __len__(self): - return len(self.graphs) - -#Dataset which contains prebatched shuffled graphs. Cannot be saved to disk, else batching info is lost. -class LazyPreBatchedDataset(PreBatchedDataset): - def __init__(self, **kwargs): - # print(f'Unused kwargs: {kwargs}') - self.current_chunk = None - self.current_chunk_idx = -10 - self.label_chunks = [] - super().__init__(**kwargs) - - def load(self): - if not self.save_to_disk: - return - self.label_chunks = [] - for ch in range(self.chunks): - graph_path = os.path.join(self.save_dir, f'{self.name}_{ch}_{self.suffix}.bin') - print(f'Loading dataset from {graph_path}') - label_dict = dgl.data.graph_serialize.load_labels_v2(graph_path) - self.label_chunks.append(label_dict) - - def __getitem__(self, idx): - chunk_idx = -1 - sum = 0 - ev_idx = -999 - for i in range(len(self.label_chunks)): - count = len(self.label_chunks[i]['labels']) - if idx < sum + count: - chunk_idx = i - ev_idx = idx - sum - break - sum += count - if chunk_idx != self.current_chunk_idx: - # print(f"rank {self.rank} getting data from {self.name}_{chunk_idx}_{self.suffix}.bin") - self.current_chunk, _ = dgl.load_graphs(os.path.join(self.save_dir, f'{self.name}_{chunk_idx}_{self.suffix}.bin')) - self.current_chunk_idx = chunk_idx - g = self.current_chunk[ev_idx] - g.set_batch_num_nodes(self.label_chunks[chunk_idx]['batch_num_nodes'][ev_idx]) - g.set_batch_num_edges(self.label_chunks[chunk_idx]['batch_num_edges'][ev_idx]) - return g, self.label_chunks[chunk_idx]['labels'][ev_idx], self.label_chunks[chunk_idx]['tracking'][ev_idx], self.label_chunks[chunk_idx]['globals'][ev_idx] - - def __len__(self): - l = 0 - for chunk in self.label_chunks: - l += len(chunk['labels']) - return l diff --git a/legacy/root_gnn_dgl/root_gnn_base/custom_scheduler.py b/legacy/root_gnn_dgl/root_gnn_base/custom_scheduler.py deleted file mode 100644 index b437115e0712665a6b8512e067a4a2df5d7be99a..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/root_gnn_base/custom_scheduler.py +++ /dev/null @@ -1,565 +0,0 @@ -import types -import math -import torch -from torch import inf -from functools import wraps, partial -import warnings -import weakref -from collections import Counter -from bisect import bisect_right - -from models import GCN - - - - -### Code from: https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html#ReduceLROnPlateau - -Optimizer = torch.optim.Optimizer - -__all__ = ['LambdaLR', 'MultiplicativeLR', 'StepLR', 'MultiStepLR', 'ConstantLR', 'LinearLR', - 'ExponentialLR', 'SequentialLR', 'CosineAnnealingLR', 'ChainedScheduler', 'ReduceLROnPlateau', - 'CyclicLR', 'CosineAnnealingWarmRestarts', 'OneCycleLR', 'PolynomialLR', 'LRScheduler'] - -EPOCH_DEPRECATION_WARNING = ( - "The epoch parameter in `scheduler.step()` was not necessary and is being " - "deprecated where possible. Please use `scheduler.step()` to step the " - "scheduler. During the deprecation, if epoch is different from None, the " - "closed form is used instead of the new chainable form, where available. " - "Please open an issue if you are unable to replicate your use case: " - "https://github.com/pytorch/pytorch/issues/new/choose." -) - - -def update_LR(opt, lr): - for param_group in opt.param_groups: - param_group['lr'] = lr - -def print_LR(opt): - for param_group in opt.param_groups: - print(f"LR = {param_group['lr']}") - -def _check_verbose_deprecated_warning(verbose): - """Raises a warning when verbose is not the default value.""" - if verbose != "deprecated": - warnings.warn("The verbose parameter is deprecated. Please use get_last_lr() " - "to access the learning rate.", UserWarning) - return verbose - return False - -class LRScheduler: - - def __init__(self, optimizer, last_epoch=-1, verbose="deprecated"): - - # Attach optimizer - if not isinstance(optimizer, Optimizer): - raise TypeError(f'{type(optimizer).__name__} is not an Optimizer') - self.optimizer = optimizer - - # Initialize epoch and base learning rates - if last_epoch == -1: - for group in optimizer.param_groups: - group.setdefault('initial_lr', group['lr']) - else: - for i, group in enumerate(optimizer.param_groups): - if 'initial_lr' not in group: - raise KeyError("param 'initial_lr' is not specified " - f"in param_groups[{i}] when resuming an optimizer") - self.base_lrs = [group['initial_lr'] for group in optimizer.param_groups] - self.last_epoch = last_epoch - - # Following https://github.com/pytorch/pytorch/issues/20124 - # We would like to ensure that `lr_scheduler.step()` is called after - # `optimizer.step()` - def with_counter(method): - if getattr(method, '_with_counter', False): - # `optimizer.step()` has already been replaced, return. - return method - - # Keep a weak reference to the optimizer instance to prevent - # cyclic references. - instance_ref = weakref.ref(method.__self__) - # Get the unbound method for the same purpose. - func = method.__func__ - cls = instance_ref().__class__ - del method - - @wraps(func) - def wrapper(*args, **kwargs): - instance = instance_ref() - instance._step_count += 1 - wrapped = func.__get__(instance, cls) - return wrapped(*args, **kwargs) - - # Note that the returned function here is no longer a bound method, - # so attributes like `__func__` and `__self__` no longer exist. - wrapper._with_counter = True - return wrapper - - self.optimizer.step = with_counter(self.optimizer.step) - self.verbose = _check_verbose_deprecated_warning(verbose) - - self._initial_step() - - def _initial_step(self): - """Initialize step counts and performs a step""" - self.optimizer._step_count = 0 - self._step_count = 0 - self.step() - - def state_dict(self): - """Returns the state of the scheduler as a :class:`dict`. - - It contains an entry for every variable in self.__dict__ which - is not the optimizer. - """ - return {key: value for key, value in self.__dict__.items() if key != 'optimizer'} - - def load_state_dict(self, state_dict): - """Loads the schedulers state. - - Args: - state_dict (dict): scheduler state. Should be an object returned - from a call to :meth:`state_dict`. - """ - self.__dict__.update(state_dict) - - def get_last_lr(self): - """ Return last computed learning rate by current scheduler. - """ - return self._last_lr - - def get_lr(self): - # Compute learning rate using chainable form of the scheduler - raise NotImplementedError - - def print_lr(self, is_verbose, group, lr, epoch=None): - """Display the current learning rate. - """ - if is_verbose: - if epoch is None: - print(f'Adjusting learning rate of group {group} to {lr:.4e}.') - else: - epoch_str = ("%.2f" if isinstance(epoch, float) else - "%.5d") % epoch - print(f'Epoch {epoch_str}: adjusting learning rate of group {group} to {lr:.4e}.') - - - def step(self, epoch=None): - # Raise a warning if old pattern is detected - # https://github.com/pytorch/pytorch/issues/20124 - if self._step_count == 1: - if not hasattr(self.optimizer.step, "_with_counter"): - warnings.warn("Seems like `optimizer.step()` has been overridden after learning rate scheduler " - "initialization. Please, make sure to call `optimizer.step()` before " - "`lr_scheduler.step()`. See more details at " - "https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate", UserWarning) - - # Just check if there were two first lr_scheduler.step() calls before optimizer.step() - elif self.optimizer._step_count < 1: - warnings.warn("Detected call of `lr_scheduler.step()` before `optimizer.step()`. " - "In PyTorch 1.1.0 and later, you should call them in the opposite order: " - "`optimizer.step()` before `lr_scheduler.step()`. Failure to do this " - "will result in PyTorch skipping the first value of the learning rate schedule. " - "See more details at " - "https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate", UserWarning) - self._step_count += 1 - - with _enable_get_lr_call(self): - if epoch is None: - self.last_epoch += 1 - values = self.get_lr() - else: - warnings.warn(EPOCH_DEPRECATION_WARNING, UserWarning) - self.last_epoch = epoch - if hasattr(self, "_get_closed_form_lr"): - values = self._get_closed_form_lr() - else: - values = self.get_lr() - - for i, data in enumerate(zip(self.optimizer.param_groups, values)): - param_group, lr = data - param_group['lr'] = lr - - self._last_lr = [group['lr'] for group in self.optimizer.param_groups] - - -# Including _LRScheduler for backwards compatibility -# Subclass instead of assign because we want __name__ of _LRScheduler to be _LRScheduler (assigning would make it LRScheduler). -class _LRScheduler(LRScheduler): - pass - - -class _enable_get_lr_call: - - def __init__(self, o): - self.o = o - - def __enter__(self): - self.o._get_lr_called_within_step = True - return self - - def __exit__(self, type, value, traceback): - self.o._get_lr_called_within_step = False - - -class Dynamic_LR(LRScheduler): - """Reduce learning rate when a metric has stopped improving. - Models often benefit from reducing the learning rate by a factor - of 2-10 once learning stagnates. This scheduler reads a metrics - quantity and if no improvement is seen for a 'patience' number - of epochs, the learning rate is reduced. - - Args: - optimizer (Optimizer): Wrapped optimizer. - mode (str): One of `min`, `max`. In `min` mode, lr will - be reduced when the quantity monitored has stopped - decreasing; in `max` mode it will be reduced when the - quantity monitored has stopped increasing. Default: 'min'. - factor (float): Factor by which the learning rate will be - reduced. new_lr = lr * factor. Default: 0.1. - patience (int): Number of epochs with no improvement after - which learning rate will be reduced. For example, if - `patience = 2`, then we will ignore the first 2 epochs - with no improvement, and will only decrease the LR after the - 3rd epoch if the loss still hasn't improved then. - Default: 10. - threshold (float): Threshold for measuring the new optimum, - to only focus on significant changes. Default: 1e-4. - threshold_mode (str): One of `rel`, `abs`. In `rel` mode, - dynamic_threshold = best * ( 1 + threshold ) in 'max' - mode or best * ( 1 - threshold ) in `min` mode. - In `abs` mode, dynamic_threshold = best + threshold in - `max` mode or best - threshold in `min` mode. Default: 'rel'. - cooldown (int): Number of epochs to wait before resuming - normal operation after lr has been reduced. Default: 0. - min_lr (float or list): A scalar or a list of scalars. A - lower bound on the learning rate of all param groups - or each group respectively. Default: 0. - eps (float): Minimal decay applied to lr. If the difference - between new and old lr is smaller than eps, the update is - ignored. Default: 1e-8. - verbose (bool): If ``True``, prints a message to stdout for - each update. Default: ``False``. - - .. deprecated:: 2.2 - ``verbose`` is deprecated. Please use ``get_last_lr()`` to access the - learning rate. - - Example: - >>> # xdoctest: +SKIP - >>> optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9) - >>> scheduler = ReduceLROnPlateau(optimizer, 'min') - >>> for epoch in range(10): - >>> train(...) - >>> val_loss = validate(...) - >>> # Note that step should be called after validate() - >>> scheduler.step(val_loss) - """ - - def __init__(self, optimizer, mode = 'max', factor=0.1, patience=10, - plateau_var = "test_auc", - threshold=1e-4, threshold_mode='rel', cooldown=0, - min_lr=0, max_lr=1e-4, eps=1e-8, verbose=False): - - """ - if factor >= 1.0: - raise ValueError('Factor should be < 1.0.') - """ - self.factor = factor - - # Attach optimizer - if not isinstance(optimizer, Optimizer): - raise TypeError(f'{type(optimizer).__name__} is not an Optimizer') - self.optimizer = optimizer - - if isinstance(min_lr, (list, tuple)): - if len(min_lr) != len(optimizer.param_groups): - raise ValueError(f"expected {len(optimizer.param_groups)} min_lrs, got {len(min_lr)}") - self.min_lrs = list(min_lr) - self.max_lrs = list(max_lr) - else: - self.min_lrs = [min_lr] * len(optimizer.param_groups) - self.max_lrs = [max_lr] * len(optimizer.param_groups) - - self.patience = patience - self.plateau_var = plateau_var - - self.verbose = verbose - self.cooldown = cooldown - self.cooldown_counter = 0 - self.mode = mode - self.threshold = threshold - self.threshold_mode = threshold_mode - self.best = None - self.num_bad_epochs = None - self.mode_worse = None # the worse value for the chosen mode - self.eps = eps - self.last_epoch = 0 - self._last_lr = [group['lr'] for group in self.optimizer.param_groups] - self._init_is_better(mode=mode, threshold=threshold, - threshold_mode=threshold_mode) - self._reset() - - def _reset(self): - """Resets num_bad_epochs counter and cooldown counter.""" - self.best = self.mode_worse - self.cooldown_counter = 0 - self.num_bad_epochs = 0 - - def step(self, model, metrics, epoch=None): - # convert `metrics` to float, in case it's a zero-dim Tensor - current = float(metrics[self.plateau_var]) - if epoch is None: - epoch = self.last_epoch + 1 - else: - warnings.warn(EPOCH_DEPRECATION_WARNING, UserWarning) - self.last_epoch = epoch - - if self.is_better(current, self.best): - if(self.verbose): - print("Model is improving!") - self.best = current - self.num_bad_epochs = 0 - else: - if(self.verbose): - print(f"Model is not improving :( best = {self.best}, current = {current}") - self.num_bad_epochs += 1 - - if self.in_cooldown: - self.cooldown_counter -= 1 - self.num_bad_epochs = 0 # ignore any bad epochs in cooldown - - if self.num_bad_epochs > self.patience: - self._reduce_lr(epoch) - self.cooldown_counter = self.cooldown - self.num_bad_epochs = 0 - - self._last_lr = [group['lr'] for group in self.optimizer.param_groups] - - def _reduce_lr(self, epoch): - print("Adjusting Learning Rate") - self._reset() - for i, param_group in enumerate(self.optimizer.param_groups): - old_lr = float(param_group['lr']) - new_lr = max(old_lr * self.factor, self.min_lrs[i]) - new_lr = min(new_lr, self.max_lrs[i]) - if abs(old_lr - new_lr) > self.eps: - param_group['lr'] = new_lr - - def get_last_lr(self): - return self._last_lr - @property - def in_cooldown(self): - return self.cooldown_counter > 0 - - def is_better(self, a, best): - if self.mode == 'min' and self.threshold_mode == 'rel': - rel_epsilon = 1. - self.threshold - return a < best * rel_epsilon - - elif self.mode == 'min' and self.threshold_mode == 'abs': - return a < best - self.threshold - - elif self.mode == 'max' and self.threshold_mode == 'rel': - rel_epsilon = self.threshold + 1. - return a > best * rel_epsilon - - else: # mode == 'max' and epsilon_mode == 'abs': - return a > best + self.threshold - - def _init_is_better(self, mode, threshold, threshold_mode): - if mode not in {'min', 'max'}: - raise ValueError('mode ' + mode + ' is unknown!') - if threshold_mode not in {'rel', 'abs'}: - raise ValueError('threshold mode ' + threshold_mode + ' is unknown!') - - if mode == 'min': - self.mode_worse = inf - else: # mode == 'max': - self.mode_worse = -inf - - self.mode = mode - self.threshold = threshold - self.threshold_mode = threshold_mode - - def state_dict(self): - return {key: value for key, value in self.__dict__.items() if key != 'optimizer'} - - def load_state_dict(self, state_dict): - self.__dict__.update(state_dict) - self._init_is_better(mode=self.mode, threshold=self.threshold, threshold_mode=self.threshold_mode) - -class Action_On_Plateau(): - - def __init__(self, mode = 'max', patience=10, - plateau_var = "test_auc", - threshold=1e-4, threshold_mode='rel', cooldown=0, - eps=1e-8, verbose=False): - - self.patience = patience - self.plateau_var = plateau_var - - self.verbose = verbose - self.cooldown = cooldown - self.cooldown_counter = 0 - self.mode = mode - self.threshold = threshold - self.threshold_mode = threshold_mode - self.best = None - self.num_bad_epochs = None - self.mode_worse = None # the worse value for the chosen mode - self.eps = eps - self.last_epoch = 0 - self._init_is_better(mode=mode, threshold=threshold, - threshold_mode=threshold_mode) - self._reset() - - def _reset(self): - """Resets num_bad_epochs counter and cooldown counter.""" - self.best = self.mode_worse - self.cooldown_counter = 0 - self.num_bad_epochs = 0 - - def step(self, model, metrics, epoch=None): - # convert `metrics` to float, in case it's a zero-dim Tensor - current = float(metrics[self.plateau_var]) - if epoch is None: - epoch = self.last_epoch + 1 - else: - warnings.warn(EPOCH_DEPRECATION_WARNING, UserWarning) - self.last_epoch = epoch - - if self.is_better(current, self.best): - if(self.verbose): - print("Model is improving!") - self.best = current - self.num_bad_epochs = 0 - else: - if(self.verbose): - print(f"Model is not improving :( best = {self.best}, current = {current}") - self.num_bad_epochs += 1 - - if self.in_cooldown: - self.cooldown_counter -= 1 - self.num_bad_epochs = 0 # ignore any bad epochs in cooldown - - if self.num_bad_epochs > self.patience: - self.action(model, metrics, epoch) - - def action(self, model, metrics, epoch=None): - if(self.verbose): - print("Doing my action") - - @property - def in_cooldown(self): - return self.cooldown_counter > 0 - - def is_better(self, a, best): - if self.mode == 'min' and self.threshold_mode == 'rel': - rel_epsilon = 1. - self.threshold - return a < best * rel_epsilon - - elif self.mode == 'min' and self.threshold_mode == 'abs': - return a < best - self.threshold - - elif self.mode == 'max' and self.threshold_mode == 'rel': - rel_epsilon = self.threshold + 1. - return a > best * rel_epsilon - - else: # mode == 'max' and epsilon_mode == 'abs': - return a > best + self.threshold - - def _init_is_better(self, mode, threshold, threshold_mode): - if mode not in {'min', 'max'}: - raise ValueError('mode ' + mode + ' is unknown!') - if threshold_mode not in {'rel', 'abs'}: - raise ValueError('threshold mode ' + threshold_mode + ' is unknown!') - - if mode == 'min': - self.mode_worse = inf - else: # mode == 'max': - self.mode_worse = -inf - - self.mode = mode - self.threshold = threshold - self.threshold_mode = threshold_mode - -class Partial_Reset(Action_On_Plateau): - - def __init__(self, mode='max', patience=10, plateau_var="test_auc", - threshold=0.0001, threshold_mode='rel', cooldown=0, - eps=1e-8, verbose=False): - - super().__init__(mode, patience, plateau_var, threshold, - threshold_mode, cooldown, eps, verbose) - - def action(self, model, metrics, epoch=None): - print("Partial Reset!!") - GCN.partial_reset(model) - self._reset() - self.cooldown_counter = self.cooldown - self.num_bad_epochs = 0 - - -class Full_Reset(Action_On_Plateau): - - def __init__(self, mode='max', patience=10, plateau_var="test_auc", - threshold=0.0001, threshold_mode='rel', cooldown=0, - eps=1e-8, verbose=False): - - super().__init__(mode, patience, plateau_var, threshold, - threshold_mode, cooldown, eps, verbose) - - def action(self, model, metrics, epoch=None): - print("Full Reset!!") - GCN.full_reset(model) - self._reset() - self.cooldown_counter = self.cooldown - self.num_bad_epochs = 0 - -class Dynamic_LR_AND_Partial_Reset(): - def __init__(self, optimizer, mode = 'max', factor=0.1, patience=10, - plateau_var = "test_auc", reset_patience=None, reset_plateau_var=None, - threshold=1e-4, threshold_mode='rel', cooldown=0, - min_lr=0, max_lr=1e-4, eps=1e-8, verbose=False): - - if (reset_patience == None): - reset_patience = patience - if(reset_plateau_var == None): - reset_plateau_var = plateau_var - - self.dynamic_lr = Dynamic_LR(optimizer, mode=mode, factor=factor, patience = patience, - plateau_var=plateau_var, threshold=threshold, threshold_mode =threshold_mode, - cooldown=cooldown, min_lr=min_lr, max_lr=max_lr, eps=eps, verbose=verbose) - - self.partial_reset = Partial_Reset(mode=mode, patience=reset_patience, plateau_var=reset_plateau_var, - threshold=threshold, threshold_mode=threshold_mode, cooldown=cooldown, - eps=eps) - - def step(self, model, metrics, epoch=None): - self.dynamic_lr.step(model=model, metrics=metrics, epoch=epoch) - self.partial_reset.step(model=model, metrics=metrics, epoch=epoch) - -class Dynamic_LR_AND_Full_Reset(): - def __init__(self, optimizer, mode = 'max', factor=0.1, patience=10, - plateau_var = "test_auc", reset_patience=None, reset_plateau_var=None, - threshold=1e-4, threshold_mode='rel', cooldown=0, - min_lr=0, max_lr=1e-4, eps=1e-8, verbose=False): - - if (reset_patience == None): - reset_patience = patience - if(reset_plateau_var == None): - reset_plateau_var = plateau_var - - self.dynamic_lr = Dynamic_LR(optimizer, mode=mode, factor=factor, patience = patience, - plateau_var=plateau_var, threshold=threshold, threshold_mode =threshold_mode, - cooldown=cooldown, min_lr=min_lr, max_lr=max_lr, eps=eps, verbose=verbose) - - self.full_reset = Full_Reset(mode=mode, patience=reset_patience, plateau_var=reset_plateau_var, - threshold=threshold, threshold_mode=threshold_mode, cooldown=cooldown, - eps=eps) - - def step(self, model, metrics, epoch=None): - self.dynamic_lr.step(model=model, metrics=metrics, epoch=epoch) - self.full_reset.step(model=model, metrics=metrics, epoch=epoch) \ No newline at end of file diff --git a/legacy/root_gnn_dgl/root_gnn_base/dataset.py b/legacy/root_gnn_dgl/root_gnn_base/dataset.py deleted file mode 100644 index f05c24b31996e5227ecbe644b8f43b78e0060e3b..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/root_gnn_base/dataset.py +++ /dev/null @@ -1,874 +0,0 @@ -from dgl.data import DGLDataset -import dgl -import uproot -import awkward as ak -import torch -import os -import glob -import time -import numpy as np -import re -from root_gnn_base import utils - -FEATURE_DTYPE = torch.float32 - -def node_features_from_tree(ch, node_branch_names, node_branch_types, node_feature_scales): - lengths = [] - for branch, node_type in zip(node_branch_names[0], node_branch_types): - if node_type == 'single': - lengths.append(1) - elif node_type == 'vector': - lengths.append(len(ch[branch])) - else: - print('Unknown node branch type: {}'.format(node_type)) - features = [] - for node_feat in node_branch_names: - if node_feat == 'CALC_E': - features.append(features[0]*torch.cosh(features[1])) - continue - elif node_feat == 'NODE_TYPE': - feat = [] - for i, length in enumerate(lengths): - feat.extend([i,]*length) - features.append(torch.tensor(feat, dtype=FEATURE_DTYPE)) - continue - feat = [] - itype = 0 - for length, branch, node_type in zip(lengths, node_feat, node_branch_types): - if isinstance(branch, (int, float, complex)): - feat.extend([branch,]*length) - elif branch == 'CALC_E': - this_type_starts_at = sum(lengths[:itype]) - this_type_ends_at = sum(lengths[:itype+1]) - feat.extend(features[0][this_type_starts_at:this_type_ends_at]*torch.cosh(features[1][this_type_starts_at:this_type_ends_at])) - elif node_type == 'single': - feat.append(ch[branch]) - elif node_type == 'vector': - feat.extend(ch[branch]) - itype += 1 - features.append(torch.as_tensor(np.asarray(feat, dtype=np.float32), dtype=FEATURE_DTYPE)) - return torch.stack(features, dim=1) * node_feature_scales, lengths - -def full_connected_graph(n_nodes, self_loops=True): - senders = np.arange(n_nodes*n_nodes) // n_nodes - receivers = np.arange(n_nodes*n_nodes) % n_nodes - if not self_loops and n_nodes > 1: - mask = senders != receivers - senders = senders[mask] - receivers = receivers[mask] - return dgl.graph((senders, receivers)) - -def _selection_context(ch): - if isinstance(ch, dict): - return ch - if hasattr(ch, 'GetListOfBranches'): - context = {} - for branch in ch.GetListOfBranches(): - branch_name = branch.GetName() - try: - context[branch_name] = getattr(ch, branch_name) - except Exception: - continue - return context - return vars(ch) - -def check_selection(ch, selection): - if isinstance(selection, str): - return bool(eval(selection, {"__builtins__": {}}, _selection_context(ch))) - var, cut, op = selection - if op == '>': - return ch[var] > cut - elif op == '>=': - return ch[var] >= cut - elif op == '<': - return ch[var] < cut - elif op == '<=': - return ch[var] <= cut - elif op == '==': - return ch[var] == cut - elif op == '!=': - return ch[var] != cut - raise ValueError(f'Unknown selection operator: {op}') - -def check_selections(ch, selections): - for selection in selections: - if not check_selection(ch, selection): - return False - return True - -def selection_branches(selection): - if isinstance(selection, str): - tokens = re.findall(r"\b[A-Za-z_][A-Za-z0-9_]*\b", selection) - keywords = {"and", "or", "not", "True", "False"} - return [tok for tok in tokens if tok not in keywords] - if isinstance(selection, (list, tuple)) and len(selection) > 0: - return [selection[0]] - return [] - -def init_cutflow(selections): - return {"selections": list(selections), "counts": [0] * len(selections), "total": 0} - -def update_cutflow(cutflow, ch): - cutflow["total"] += 1 - passed = True - for i, selection in enumerate(cutflow["selections"]): - if passed and check_selection(ch, selection): - cutflow["counts"][i] += 1 - else: - passed = False - -def print_cutflow(cutflow, title="Cutflow"): - total = cutflow["total"] - print(f"\n{title}") - print(f"{'Step':<6} {'Label':<30} {'Yield':>12} {'Ind. Eff.':>12} {'Tot. Eff.':>12}") - prev = total - current = total - print(f"{0:<6} {'all events':<30} {total:>12} {1.0:>12.4f} {1.0:>12.4f}") - for i, (selection, count) in enumerate(zip(cutflow["selections"], cutflow["counts"]), start=1): - current = count - ind_eff = current / prev if prev else 0.0 - tot_eff = current / total if total else 0.0 - print(f"{i:<6} {str(selection):<30} {current:>12} {ind_eff:>12.4f} {tot_eff:>12.4f}") - prev = current - -def selection_mask(data, selections): - if len(selections) == 0: - first_field = data.fields[0] if len(data.fields) > 0 else None - return np.ones(len(data[first_field]), dtype=bool) if first_field is not None else None - mask = None - for selection in selections: - current_mask = eval(selection, {"__builtins__": {}}, data) if isinstance(selection, str) else check_selection(data, selection) - if mask is None: - mask = current_mask - else: - mask = mask & current_mask - return mask - -def compute_cutflow(data, selections): - cutflow = init_cutflow(selections) - first_field = data.fields[0] if len(data.fields) > 0 else None - cutflow["total"] = len(data[first_field]) if first_field is not None else 0 - if first_field is None: - return cutflow - running_mask = np.ones(cutflow["total"], dtype=bool) - for i, selection in enumerate(selections): - current_mask = eval(selection, {"__builtins__": {}}, data) if isinstance(selection, str) else check_selection(data, selection) - running_mask = running_mask & current_mask - cutflow["counts"][i] = int(ak.sum(running_mask)) - return cutflow - -class RootDataset(DGLDataset): - def __init__(self, name=None, raw_dir=None, save_dir=None, label=1, file_names = '*.root', node_branch_names=None, node_branch_types=None, node_feature_scales=None, - selections=[], save=True, tree_name = 'nominal_Loose', fold_var = 'eventNumber', weight_var = None, chunks = 1, process_chunks = None, global_features = [], tracking_info = [], **kwargs): - ignored_keys = {'shuffle_chunks', 'shuffle_seed', 'batch_size', 'padding_mode', 'folding'} - unused_kwargs = {k: v for k, v in kwargs.items() if k not in ignored_keys} - if len(unused_kwargs) > 0: - print(f'Unused args while creating RootDataset: {unused_kwargs}') - self.label = label - self.counts = [] - self.selections = selections - self.save_to_disk = save - self.file_names = file_names - self.node_branch_names = node_branch_names - self.node_branch_types = node_branch_types - self.node_feature_scales = torch.tensor([float(sf) for sf in node_feature_scales], dtype=FEATURE_DTYPE) - self.tree_name = tree_name - self.fold_var = fold_var - self.tracking_info = tracking_info - self.tracking_info.insert(0, fold_var) - if weight_var is None: - weight_var = 1 - self.tracking_info.insert(1, weight_var) - self.global_features = global_features - self.chunks = chunks - self.process_chunks = process_chunks - if self.process_chunks is None: - self.process_chunks = [i for i in range(self.chunks)] - self.times = [0, 0] - super().__init__(name=name, raw_dir=raw_dir, save_dir=save_dir) - - def get_list_of_branches(self): - branches = [] - for feat in self.node_branch_names: - if isinstance(feat, list): - for branch in feat: - if branch == 'CALC_E': - continue - if isinstance(branch, str): - branches.append(branch) - for feat in self.global_features: - if isinstance(feat, str): - branches.append(feat) - for feat in self.tracking_info: - if isinstance(feat, str): - branches.append(feat) - for selection in self.selections: - branches.extend(selection_branches(selection)) - return list(set(branches)) # Remove duplicates - - def make_graph(self, ch): - t1 = time.time() - features, _ = node_features_from_tree(ch, self.node_branch_names, self.node_branch_types, self.node_feature_scales) - features = features[features[:,0] != 0] - t2 = time.time() - g = full_connected_graph(features.shape[0], self_loops=False) - g.ndata['features'] = features - t3 = time.time() - self.times[0] += t2 - t1 - self.times[1] += t3 - t2 - return g - - def process(self): - # When processing a single requested chunk without selections, stream - # only that entry range from ROOT. The previous implementation read - # and concatenated the complete file before splitting it, which made - # parallel chunk processing multiply the full expanded Awkward-array - # footprint by the number of workers. - if not self.selections and self.chunks > 1 and self.process_chunks is not None: - return self._process_streaming_chunks() - - times = [0, 0, 0] - oldtime = time.time() - if isinstance(self.file_names, str): - self.files = glob.glob(os.path.join(self.raw_dir, self.file_names)) - else: - self.files = [] - for file_name in self.file_names: - self.files.extend(glob.glob(os.path.join(self.raw_dir, file_name))) - branches = self.get_list_of_branches() - - # Read all files and concatenate arrays - arrays = [] - for file in self.files: - with uproot.open(file) as f: - arrays.append(f[self.tree_name].arrays(branches, library="ak")) - if len(arrays) == 0: - print('No files found in {}'.format(os.path.join(self.raw_dir, self.file_names))) - return - data = ak.concatenate(arrays, axis=0) - sel_mask = selection_mask(data, self.selections) - selected_indices = np.arange(len(data[branches[0]])) - if sel_mask is not None: - selected_indices = selected_indices[ak.to_numpy(sel_mask)] - n_entries = len(selected_indices) - newtime = time.time() - times[0] += newtime - oldtime - chunks = np.array_split(selected_indices, self.chunks) - chunks = [chunk for i, chunk in enumerate(chunks) if i in self.process_chunks] - - self.graph_chunks = [] - self.label_chunks = [] - self.tracking_chunks = [] - self.global_chunks = [] - cutflow = init_cutflow(self.selections) - chunk_id = -1 - for chunk in chunks: - print('Processing chunk {}/{}'.format(chunk_id + 1, len(chunks)), flush=True) - chunk_id += 1 - graphs = [] - labels = [] - tracking = [] - globals = [] - for ientry in chunk: - if (ientry % 10000 == 0): - print('Processing event {}/{}'.format(ientry, n_entries), flush=True) - ch = {b: data[b][ientry] for b in branches} - passed = True - for selection in self.selections: - if not check_selection(ch, selection): - passed = False - continue - oldtime = newtime - newtime = time.time() - times[1] += newtime - oldtime - if passed: - graphs.append(self.make_graph(ch)) - labels.append(self.label) - tracking.append(torch.zeros(len(self.tracking_info), dtype=FEATURE_DTYPE)) - globals.append(torch.zeros(len(self.global_features), dtype=FEATURE_DTYPE)) - for i_ti, tr_branch in enumerate(self.tracking_info): - if isinstance(tr_branch, str): - dtype = tracking[-1].dtype - tracking[-1][i_ti] = torch.as_tensor(ch[tr_branch], dtype=dtype) - # tracking[-1][i_ti] = ch[tr_branch] - else: - tracking[-1][i_ti] = tr_branch - for i_gl, gl_branch in enumerate(self.global_features): - globals[-1][i_gl] = ch[gl_branch] - oldtime = newtime - newtime = time.time() - times[2] += newtime - oldtime - - labels = torch.tensor(labels) - tracking = torch.stack(tracking) - globals = torch.stack(globals) - - # self.graph_chunks.append(graphs) - # self.label_chunks.append(labels) - # self.tracking_chunks.append(tracking) - # self.global_chunks.append(globals) - # self.counts.append(len(graphs)) - - if (self.chunks > 1): - self.save_chunk(chunk_id, graphs, labels, tracking, globals) - else: - self.labels = labels - self.tracking = tracking - self.global_features = globals - self.graphs = graphs - self.save() - return - - def _process_streaming_chunks(self): - """Create requested graph chunks without materializing the full ROOT file.""" - if isinstance(self.file_names, str): - files = glob.glob(os.path.join(self.raw_dir, self.file_names)) - else: - files = [] - for file_name in self.file_names: - files.extend(glob.glob(os.path.join(self.raw_dir, file_name))) - - if not files: - print('No files found in {}'.format(os.path.join(self.raw_dir, self.file_names))) - return - - branches = self.get_list_of_branches() - file_entries = [] - total_entries = 0 - for file in files: - with uproot.open(file) as root_file: - entries = root_file[self.tree_name].num_entries - file_entries.append((file, total_entries, total_entries + entries)) - total_entries += entries - - # Match the old np.array_split boundaries without allocating an array - # containing one integer per event. - boundaries = np.linspace(0, total_entries, self.chunks + 1, dtype=np.int64) - requested = set(self.process_chunks) - for chunk_id in sorted(requested): - if chunk_id < 0 or chunk_id >= self.chunks: - raise ValueError(f"Requested chunk {chunk_id} outside [0, {self.chunks})") - start, stop = int(boundaries[chunk_id]), int(boundaries[chunk_id + 1]) - graphs, labels, tracking, globals_ = [], [], [], [] - print(f'Processing streamed chunk {chunk_id}/{self.chunks} ' - f'(entries {start}:{stop})', flush=True) - - for file, file_start, file_stop in file_entries: - overlap_start = max(start, file_start) - overlap_stop = min(stop, file_stop) - if overlap_start >= overlap_stop: - continue - local_start = overlap_start - file_start - local_stop = overlap_stop - file_start - tree = uproot.open(file)[self.tree_name] - for data in tree.iterate( - expressions=branches, - entry_start=local_start, - entry_stop=local_stop, - step_size='256 MB', - library='ak', - ): - n_events = len(data[branches[0]]) - for ientry in range(n_events): - ch = {branch: data[branch][ientry] for branch in branches} - graphs.append(self.make_graph(ch)) - labels.append(self.label) - track = torch.zeros(len(self.tracking_info), dtype=FEATURE_DTYPE) - global_feat = torch.zeros(len(self.global_features), dtype=FEATURE_DTYPE) - for i_ti, tr_branch in enumerate(self.tracking_info): - track[i_ti] = torch.as_tensor(ch[tr_branch], dtype=track.dtype) if isinstance(tr_branch, str) else tr_branch - for i_gl, gl_branch in enumerate(self.global_features): - global_feat[i_gl] = ch[gl_branch] - tracking.append(track) - globals_.append(global_feat) - - if graphs: - self.save_chunk( - self.process_chunks.index(chunk_id), - graphs, - torch.tensor(labels), - torch.stack(tracking), - torch.stack(globals_), - ) - else: - print(f'No graphs created for chunk {chunk_id}.', flush=True) - - def save(self): - if not self.save_to_disk: - return - if self.chunks > 1 and (not hasattr(self, "graph_chunks") or len(self.graph_chunks) == 0): - print(f"Skipping save for {self.name}: no graphs were created.") - return - graph_path = os.path.join(self.save_dir, self.name + '.bin') - if self.chunks == 1: - print(f'Saving dataset to {os.path.join(self.save_dir, self.name + ".bin")}') - dgl.save_graphs(str(graph_path), self.graphs, {'labels': torch.tensor(self.labels), 'tracking': torch.tensor(self.tracking), 'global': torch.tensor(self.global_features)}) - else: - for i in range(len(self.process_chunks)): - print(f'Saving dataset to {os.path.join(self.save_dir, self.name + f"_{self.process_chunks[i]}.bin")}') - - dgl.save_graphs(str(graph_path).replace('.bin', f'_{self.process_chunks[i]}.bin'), self.graph_chunks[i], {'labels': self.label_chunks[i], 'tracking': self.tracking_chunks[i], 'global': self.global_chunks[i]}) - - def save_chunk(self, chunk_id, graphs, labels, tracking, globals): - if not self.save_to_disk: - return - if len(graphs) == 0: - print(f"Skipping save for chunk {chunk_id}: no graphs passed selections.") - return - graph_path = os.path.join(self.save_dir, self.name + '.bin') - print(f'Saving dataset to {os.path.join(self.save_dir, self.name + f"_{self.process_chunks[chunk_id]}.bin")}') - dgl.save_graphs(str(graph_path).replace('.bin', f'_{self.process_chunks[chunk_id]}.bin'), graphs, {'labels': labels, 'tracking': tracking, 'global': globals}) - - def has_cache(self): - print(f'Checking for cache of {self.name}') - if not self.save_to_disk: - print('Skipping load.') - return False - if self.chunks == 1: - graph_path = os.path.join(self.save_dir, self.name + '.bin') - return os.path.exists(graph_path) - else: - for i in range(len(self.process_chunks)): - graph_path = os.path.join(self.save_dir, self.name + f'_{self.process_chunks[i]}.bin') - if not os.path.exists(graph_path): - print(f'File {graph_path} does not exist, processing.') - return False - return True - - def load(self): - if self.chunks == 1: - print(f'Loading dataset from {os.path.join(self.save_dir, self.name + ".bin")}') - graphs, label_dict = dgl.load_graphs(os.path.join(self.save_dir, self.name + '.bin')) - self.graphs = graphs - self.labels = label_dict['labels'] - self.tracking = label_dict['tracking'] - self.global_features = label_dict['global'] - else: - self.graphs = [] - self.labels = [] - self.tracking = [] - self.global_features = [] - for i in range(self.chunks): - try: - print(f'Loading dataset from {os.path.join(self.save_dir, self.name + f"_{self.process_chunks[i]}.bin")}') - graphs, label = dgl.load_graphs(os.path.join(self.save_dir, self.name + f'_{self.process_chunks[i]}.bin')) - self.graphs.extend(graphs) - self.labels.append(label['labels']) - self.tracking.append(label['tracking']) - self.global_features.append(label['global']) - except Exception as e: - print(e) - self.labels = torch.cat(self.labels) - self.tracking = torch.cat(self.tracking) - self.global_features = torch.cat(self.global_features) - - def __getitem__(self, idx): - return self.graphs[idx], self.labels[idx], self.tracking[idx], self.global_features[idx] - - def __len__(self): - return len(self.graphs) - -#Dataset with edge features added (deta, dphi, dR) -class EdgeDataset(RootDataset): - def make_graph(self, ch): - g = super().make_graph(ch) - u, v = g.edges() - deta = g.ndata['features'][u, 1] - g.ndata['features'][v, 1] - dphi = g.ndata['features'][u, 2] - g.ndata['features'][v, 2] - dphi = torch.where(dphi > np.pi, dphi - 2*np.pi, dphi) - dphi = torch.where(dphi < -np.pi, dphi + 2*np.pi, dphi) - dR = torch.sqrt(deta**2 + dphi**2) - g.edata['features'] = torch.stack([deta, dphi, dR], dim=1) - return g - -class tHbbEdgeDataset(RootDataset): - def __init__(self, exclude_branches=None, **kwargs): - self.exclude_branches = exclude_branches - super().__init__(**kwargs) - - def get_list_of_branches(self): - br = super().get_list_of_branches() - for sector in self.exclude_branches: - if sector == None: - continue - for excl in sector: - if type(excl) == str: - br.append(excl) - return br - - def make_graph(self, ch): - features, lengths = node_features_from_tree(ch, self.node_branch_names, self.node_branch_types, self.node_feature_scales) - - include_mask = torch.ones(features.shape[0], dtype=torch.bool) - node_idx = 0 - for sector, length in zip(self.exclude_branches, lengths): - if sector == None: - node_idx += length - continue - for excl in sector: - if type(excl) == int: - include_mask[excl + node_idx] = False - elif type(excl) == str: - include_mask[getattr(self.chain, excl) + node_idx] = False - g = full_connected_graph(features[include_mask].shape[0], self_loops=False) - g.ndata['features'] = features[include_mask] - - u, v = g.edges() - deta = g.ndata['features'][u, 1] - g.ndata['features'][v, 1] - dphi = g.ndata['features'][u, 2] - g.ndata['features'][v, 2] - dphi = torch.where(dphi > np.pi, dphi - 2*np.pi, dphi) - dphi = torch.where(dphi < -np.pi, dphi + 2*np.pi, dphi) - dR = torch.sqrt(deta**2 + dphi**2) - g.edata['features'] = torch.stack([deta, dphi, dR], dim=1) - return g - -class LazyDataset(EdgeDataset): - def __init__(self, buffer_size = 2, **kwargs): - self.buffer = [None,] * buffer_size - self.buffer_ptr = 0 - self.get_item_calls = 0 - self.buffer_indices = [-1,] * buffer_size - super().__init__(**kwargs) - - def __getitem__(self, idx): - self.get_item_calls += 1 - chunk_idx = -1 - sum = 0 - ev_idx = -999 - for i, count in enumerate(self.counts): - sum += count - if idx < sum: - chunk_idx = i - ev_idx = idx - sum + count - break - buf_idx = self.buffer_get(chunk_idx) - if ev_idx >= len(self.buffer[buf_idx][0]): - print(f'Getting event {ev_idx} from chunk {chunk_idx} from buffer {buf_idx}. Calls: {self.get_item_calls}') - print(len(self.buffer)) - print(self.counts) - print(len(self.buffer[buf_idx][0])) - return self.buffer[buf_idx][0][ev_idx], self.buffer[buf_idx][1]['labels'][ev_idx], self.buffer[buf_idx][1]['tracking'][ev_idx], self.buffer[buf_idx][1]['global'][ev_idx] - - def buffer_get(self, buffer_idx): - if buffer_idx in self.buffer_indices: - for i in range(len(self.buffer)): - if self.buffer_indices[i] == buffer_idx: - return i - else: - print(f'Loading dataset from {os.path.join(self.save_dir, self.name + f"_{buffer_idx}.bin")}', flush=True) - self.buffer_ptr = (self.buffer_ptr + 1) % len(self.buffer) - self.buffer[self.buffer_ptr] = dgl.load_graphs(os.path.join(self.save_dir, self.name + f'_{buffer_idx}.bin')) - self.buffer_indices[self.buffer_ptr] = buffer_idx - return self.buffer_ptr - - def load(self): - self.counts = [] - self.tracking = [] - try: - for i in range(self.chunks): - print(f'Loading dataset from {os.path.join(self.save_dir, self.name + f"_{self.process_chunks[i]}.bin")}') - l = dgl.data.graph_serialize.load_labels_v2(os.path.join(self.save_dir, self.name + f'_{self.process_chunks[i]}.bin')) - self.counts.append(len(l['tracking'])) - self.tracking.append(l['tracking']) - self.tracking = torch.cat(self.tracking) - except Exception as e: - print(e) - - def __len__(self): - return sum(self.counts) - -class MultiLabelDataset(EdgeDataset): - def __init__(self, **kwargs): - super().__init__(**kwargs) - - def get_list_of_branches(self): - br = super().get_list_of_branches() - for l in self.label: - if isinstance(l, str): - br.append(l) - if isinstance(l, dict): - br.append(l['branch']) - return br - - def get_label(self, ch): - label = [] - for l in self.label: - if isinstance(l, str): - label.append((getattr(ch, l))) - if isinstance(l, dict): - label.append(getattr(ch, l['branch'])*float(l['scale'])) - if isinstance(l, float) or isinstance(l, int): - label.append(l) - - return torch.tensor(label) - - def process(self): - times = [0, 0, 0] - oldtime = time.time() - if isinstance(self.file_names, str): - self.files = glob.glob(os.path.join(self.raw_dir, self.file_names)) - else: - self.files = [] - for file_name in self.file_names: - self.files.extend(glob.glob(os.path.join(self.raw_dir, file_name))) - self.chain = ROOT.TChain(self.tree_name) - if len(self.files) == 0: - print('No files found in {}'.format(os.path.join(self.raw_dir, self.file_names))) - for file in self.files: - utils.set_timeout(60*2) - self.chain.Add(file) - utils.unset_timeout() - branches = self.get_list_of_branches() - self.chain.SetBranchStatus('*', 0) - for branch in branches: - self.chain.SetBranchStatus(branch, 1) - newtime = time.time() - times[0] += newtime - oldtime - all_indices = np.arange(self.chain.GetEntries()) - branches = self.get_list_of_branches() - data = {branch: [] for branch in branches} - for ientry in all_indices: - self.chain.GetEntry(ientry) - for branch in branches: - data[branch].append(getattr(self.chain, branch)) - data = {branch: ak.Array(values) for branch, values in data.items()} - sel_mask = selection_mask(data, self.selections) - selected_indices = all_indices[ak.to_numpy(sel_mask)] if sel_mask is not None else all_indices - chunks = np.array_split(selected_indices, self.chunks) - chunks = [chunk for i, chunk in enumerate(chunks) if i in self.process_chunks] - self.graph_chunks = [] - self.label_chunks = [] - self.tracking_chunks = [] - self.global_chunks = [] - chunk_id = -1 - for chunk in chunks: - chunk_id += 1 - graphs = [] - labels = [] - tracking = [] - globals = [] - for ientry in chunk: - if (ientry % 10000 == 0): - print('Processing event {}/{}'.format(ientry, self.chain.GetEntries()), flush=True) - self.chain.GetEntry(ientry) - ch = {b: getattr(self.chain, b) for b in branches} - passed = True - for selection in self.selections: - if not check_selection(self.chain, selection): - passed = False - continue - oldtime = newtime - newtime = time.time() - times[1] += newtime - oldtime - if passed: - graphs.append(self.make_graph(self.chain)) - labels.append(self.get_label(self.chain)) - tracking.append(torch.zeros(len(self.tracking_info), dtype=FEATURE_DTYPE)) - globals.append(torch.zeros(len(self.global_features), dtype=FEATURE_DTYPE)) - for i_ti, tr_branch in enumerate(self.tracking_info): - if isinstance(tr_branch, str): - tracking[-1][i_ti] = getattr(self.chain, tr_branch) - else: - tracking[-1][i_ti] = tr_branch - for i_gl, gl_branch in enumerate(self.global_features): - globals[-1][i_gl] = getattr(self.chain, gl_branch) - oldtime = newtime - newtime = time.time() - times[2] += newtime - oldtime - - labels = torch.stack(labels) - self.save_chunk(chunk_id, graphs, labels, torch.stack(tracking), torch.stack(globals)) - # self.graph_chunks.append(graphs) - # self.label_chunks.append(labels) - # self.tracking_chunks.append(torch.stack(tracking)) - # self.global_chunks.append(torch.stack(globals)) - # self.counts.append(len(graphs)) - return - self.graphs = self.graph_chunks[0] - for chunk in self.graph_chunks[1:]: - self.graphs += chunk - - self.labels = torch.cat(self.label_chunks) - self.tracking = torch.cat(self.tracking_chunks) - self.global_features = torch.cat(self.global_chunks) - print('Time spent: Creating TChain: {}s, Getting Entries and Selection: {}s, Graph Creation: {}s'.format(*times)) - print('Time spent in node_features_from_tree: {}s, full_connected_graph: {}s'.format(*self.times)) - -class LazyMultiLabelDataset(MultiLabelDataset, LazyDataset): - def __init__(self, buffer_size = 2, **kwargs): - LazyDataset.__init__(self, buffer_size=buffer_size, **kwargs) - -class MultiLabeltHbbDataset(MultiLabelDataset, tHbbEdgeDataset): - def __init__(self, **kwargs): - super().__init__(**kwargs) - - def get_list_of_branches(self): - br = super().get_list_of_branches() - for sector in self.exclude_branches: - if sector == None: - continue - for excl in sector: - if type(excl) == str: - br.append(excl) - return br - - -class AugmentedDataset(RootDataset): - - def __init__(self, seed = 2, feature_index = None, node_mapping = None, **kwargs): - self.seed = seed - np.random.seed(seed) - if(feature_index == None): - self.feature_index = {"pt": 0, "eta": 1, "phi": 2, "energy": 3, "btag": 4, "charge": 5, "node_type": 6} - if (node_mapping == None): - self.node_mapping = {"jet": 0, "ele": 1, "mu": 2, "ph": 3, "MET": 4} - super().__init__(**kwargs) - - def detector_noise(self, node_features): - noise = np.zeros_like(node_features) - - node_types = node_features[:, self.feature_index["node_type"]] - pts = node_features[:, self.feature_index["pt"]] - etas = node_features[:, self.feature_index["eta"]] - energies = node_features[:, self.feature_index["energy"]] - - # Noise calculation for jets - jet_mask = (node_types == self.node_mapping["jet"]) - jet_pts = pts[jet_mask] - jet_etas = etas[jet_mask] - - if (jet_mask.sum() > 0): - jet_resolutions = np.where( - jet_pts <= 0.1, 0.0, - np.where( - np.abs(jet_etas) <= 0.5, np.sqrt(0.06**2 + jet_pts**2 * 1.3e-3**2), - np.where( - np.abs(jet_etas) <= 1.5, np.sqrt(0.10**2 + jet_pts**2 * 1.7e-3**2), - np.where( - np.abs(jet_etas) <= 2.5, np.sqrt(0.25**2 + jet_pts**2 * 3.1e-3**2), - 0.0 - ) - ) - ) - ) - noise[jet_mask, self.feature_index["pt"]] = np.random.normal(loc=0.0, scale=jet_resolutions) - - # Noise calculation for electrons - ele_mask = (node_types == self.node_mapping["ele"]) - ele_pts = pts[ele_mask] - ele_etas = etas[ele_mask] - - if (ele_mask.sum() > 0): - ele_resolutions = np.where( - np.abs(ele_etas) <= 0.5, np.sqrt(0.03**2 + ele_pts**2 * 1.3e-3**2), - np.where( - np.abs(ele_etas) <= 1.5, np.sqrt(0.05**2 + ele_pts**2 * 1.7e-3**2), - np.where( - np.abs(ele_etas) <= 2.5, np.sqrt(0.15**2 + ele_pts**2 * 3.1e-3**2), - 0.0 - ) - ) - ) - noise[ele_mask, self.feature_index["pt"]] = np.random.normal(loc=0.0, scale=ele_resolutions) - - # Noise calculation for muons - mu_mask = (node_types == self.node_mapping["mu"]) - mu_pts = pts[mu_mask] - mu_etas = etas[mu_mask] - - if (mu_mask.sum() > 0): - mu_resolutions = np.where( - np.abs(mu_etas) <= 0.5, np.sqrt(0.01**2 + mu_pts**2 * 1.0e-4**2), - np.where( - np.abs(mu_etas) <= 1.5, np.sqrt(0.015**2 + mu_pts**2 * 1.5e-4**2), - np.where( - np.abs(mu_etas) <= 2.5, np.sqrt(0.025**2 + mu_pts**2 * 3.5e-4**2), - 0.0 - ) - ) - ) - noise[mu_mask, self.feature_index["pt"]] = np.random.normal(loc=0.0, scale=mu_resolutions) - - # Noise calculation for photons - ph_mask = (node_types == self.node_mapping["ph"]) - ph_etas = etas[ph_mask] - ph_energies = energies[ph_mask] - - if (ph_mask.sum() > 0): - ph_resolutions = np.where( - np.abs(ph_etas) <= 3.2, np.sqrt(ph_energies**2 * 0.0017**2 + ph_energies * 0.101**2), - np.where( - np.abs(ph_etas) <= 4.9, np.sqrt(ph_energies**2 * 0.0350**2 + ph_energies * 0.285**2), - 0.0 - ) - ) - noise[ph_mask, self.feature_index["energy"]] = np.random.normal(loc=0.0, scale=ph_resolutions) - return noise - - def make_graph(self, ch): - g = super().make_graph(ch) - - g.ndata['augmented_features'] = g.ndata['features'] - - num_nodes = len(g.ndata['features'][:, 0]) - - # Rotations: phi -> phi + delta_phi - phi_index = self.feature_index["phi"] - # Generate a single delta_phi for all nodes - delta_phi = np.random.uniform(low=-np.pi, high=np.pi) - - # Apply the same delta_phi to all nodes - g.ndata['augmented_features'][:, phi_index] = (g.ndata['augmented_features'][:, phi_index] + delta_phi + np.pi) % (2 * np.pi) - np.pi - - # Reflections: eta -> -1 * eta, phi -> -1 * phi - eta_index = self.feature_index["eta"] - - eta_reflection = np.random.choice([-1, 1]) - phi_reflection = np.random.choice([-1, 1]) - - g.ndata['augmented_features'][:, eta_index] = g.ndata['augmented_features'][:, eta_index] * eta_reflection - g.ndata['augmented_features'][:, phi_index] = g.ndata['augmented_features'][:, phi_index] * phi_reflection - - - # Detector Noise: pt -> pt + normal(pt, noise(pt)) - noise = self.detector_noise(g.ndata['augmented_features']) - g.ndata['augmented_features'] = g.ndata['augmented_features'] + noise - - pt_index = self.feature_index["pt"] - if (g.ndata['augmented_features'][-1][self.feature_index["node_type"]] == self.node_mapping["MET"]): - # Initialize sums of px and py - sum_px = 0 - sum_py = 0 - - # Loop over all nodes except the last one (MET node) - for i in range(len(g.ndata['augmented_features']) - 1): - pt = g.ndata['augmented_features'][i][pt_index] - phi = g.ndata['augmented_features'][i][phi_index] - - # Compute px and py - px = pt * np.cos(phi) - py = pt * np.sin(phi) - - # Sum px and py - sum_px += px - sum_py += py - - # Calculate MET - g.ndata['augmented_features'][-1][pt_index] = np.sqrt(sum_px**2 + sum_py**2) - - u, v = g.edges() - deta = g.ndata['features'][u, 1] - g.ndata['features'][v, 1] - dphi = g.ndata['features'][u, 2] - g.ndata['features'][v, 2] - dphi = torch.where(dphi > np.pi, dphi - 2*np.pi, dphi) - dphi = torch.where(dphi < -np.pi, dphi + 2*np.pi, dphi) - dR = torch.sqrt(deta**2 + dphi**2) - g.edata['features'] = torch.stack([deta, dphi, dR], dim=1) - - deta = g.ndata['augmented_features'][u, 1] - g.ndata['augmented_features'][v, 1] - dphi = g.ndata['augmented_features'][u, 2] - g.ndata['augmented_features'][v, 2] - dphi = torch.where(dphi > np.pi, dphi - 2*np.pi, dphi) - dphi = torch.where(dphi < -np.pi, dphi + 2*np.pi, dphi) - dR = torch.sqrt(deta**2 + dphi**2) - g.edata['augmented_features'] = torch.stack([deta, dphi, dR], dim=1) - - return g diff --git a/legacy/root_gnn_dgl/root_gnn_base/photon_ID_dataset.py b/legacy/root_gnn_dgl/root_gnn_base/photon_ID_dataset.py deleted file mode 100644 index 05c893bdfc423b6e95ef5c87a382b36c68e68a4e..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/root_gnn_base/photon_ID_dataset.py +++ /dev/null @@ -1,44 +0,0 @@ -from root_gnn_base import dataset -import dgl -import torch -import numpy as np - -def radius_graph(features, radii, self_loops=False): - senders = [] - receivers = [] - n_nodes = features.shape[0] - senders = np.arange(n_nodes*n_nodes) // n_nodes - receivers = np.arange(n_nodes*n_nodes) % n_nodes - if not self_loops and n_nodes > 1: - mask = senders != receivers - senders = senders[mask] - receivers = receivers[mask] - for k, r in radii.items(): - d = features[senders, k] - features[receivers, k] - mask = np.abs(d) < r - senders = senders[mask] - receivers = receivers[mask] - return dgl.graph((senders, receivers)) - -class PhotonIDDataset(dataset.LazyMultiLabelDataset): - def __init__(self, eta_radius, phi_radius, **kwargs): - self.eta_radius = eta_radius - self.phi_radius = phi_radius - super().__init__(**kwargs) - def make_graph(self, ch): - features, _ = dataset.node_features_from_tree(ch, self.node_branch_names, self.node_branch_types, self.node_feature_scales) - features = features[features[:,0] != 0] - #Delta Eta, Delta Phi, Adjacent Layer - g = radius_graph(features, {1: self.eta_radius, 2: self.phi_radius, 6: 1.1}, self_loops=True) #Self loops ensure last cell is included even if disconnected - g.ndata['features'] = features - u, v = g.edges() - deta = features[u, 1] - features[v, 1] - dphi = g.ndata['features'][u, 2] - g.ndata['features'][v, 2] - dphi = torch.where(dphi > np.pi, dphi - 2*np.pi, dphi) - dphi = torch.where(dphi < -np.pi, dphi + 2*np.pi, dphi) - dR = torch.sqrt(deta**2 + dphi**2) - dx = features[u, 3] - features[v, 3] - dy = features[u, 4] - features[v, 4] - dz = features[u, 5] - features[v, 5] - g.edata['features'] = torch.stack([deta, dphi, dR, dx, dy, dz], dim=1) - return g \ No newline at end of file diff --git a/legacy/root_gnn_dgl/root_gnn_base/similarity.py b/legacy/root_gnn_dgl/root_gnn_base/similarity.py deleted file mode 100644 index 9a6aaadc11ad929671e346acb794d7268fcb2468..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/root_gnn_base/similarity.py +++ /dev/null @@ -1,158 +0,0 @@ -import numpy as np -import scipy -from sklearn.decomposition import PCA -from sklearn.metrics.pairwise import cosine_similarity -from sklearn.metrics.pairwise import euclidean_distances -from sklearn.preprocessing import StandardScaler - -from scipy.stats import wasserstein_distance - -def cka(rep_a, rep_b, size=None): - """ - Computes the Centered Kernel Alignment (CKA) between two large representation matrices rep_a and rep_b. - If size is provided, it performs CKA on a randomly selected subset of the data. - - Parameters: - rep_a : np.ndarray - First representation matrix of size (n_samples, n_features_a). - rep_b : np.ndarray - Second representation matrix of size (n_samples, n_features_b). - size : int, optional - Number of samples to use for the CKA calculation. If None, use the full dataset. - - Returns: - float - CKA similarity between rep_a and rep_b. - """ - - def gram_linear(x): - """Compute the Gram (kernel) matrix using a linear kernel.""" - return x @ x.T - - def center_gram(gram): - """Center the Gram matrix.""" - n = gram.shape[0] - identity = np.eye(n) - ones = np.ones((n, n)) / n - return gram - ones @ gram - gram @ ones + ones @ gram @ ones - - # If sample_size is specified, randomly sample a subset of the data - if size is not None and size < rep_a.shape[0]: - indices = np.random.choice(rep_a.shape[0], size, replace=False) - rep_a = rep_a[indices] - rep_b = rep_b[indices] - - # Compute the Gram matrices - gram_a = gram_linear(rep_a) - gram_b = gram_linear(rep_b) - - # Center the Gram matrices - centered_gram_a = center_gram(gram_a) - centered_gram_b = center_gram(gram_b) - - # Compute the CKA similarity - numerator = np.sum(centered_gram_a * centered_gram_b) - denominator = np.sqrt(np.sum(centered_gram_a**2) * np.sum(centered_gram_b**2)) - - return numerator / denominator if denominator != 0 else 0 - -def cca(X, Y, size = None, num_components=10): - """ - Perform Canonical Correlation Analysis (CCA) between two datasets. - - Parameters: - X : np.ndarray - First dataset, shape (n_samples, n_features_X). - Y : np.ndarray - Second dataset, shape (n_samples, n_features_Y). - num_components : int - Number of CCA components to return. - - Returns: - w_X : np.ndarray - Canonical weights for the first dataset, shape (n_features_X, num_components). - w_Y : np.ndarray - Canonical weights for the second dataset, shape (n_features_Y, num_components). - corrs : np.ndarray - Array of canonical correlations for each component. - """ - - # If sample size is specified, randomly sample a subset of the data - if size is not None and size < X.shape[0]: - indices = np.random.choice(X.shape[0], size, replace=False) - X = X[indices] - Y = Y[indices] - - # Standardize both datasets (mean = 0, variance = 1) - scaler_X = StandardScaler() - scaler_Y = StandardScaler() - - X = scaler_X.fit_transform(X) - Y = scaler_Y.fit_transform(Y) - - # Covariance matrices - C_XX = np.cov(X, rowvar=False) # Covariance of X - C_YY = np.cov(Y, rowvar=False) # Covariance of Y - C_XY = np.cov(X, Y, rowvar=False)[:X.shape[1], X.shape[1]:] # Cross-covariance of X and Y - - # Regularization term to avoid singular matrices - reg = 1e-6 - inv_C_XX = np.linalg.inv(C_XX + reg * np.eye(C_XX.shape[0])) - inv_C_YY = np.linalg.inv(C_YY + reg * np.eye(C_YY.shape[0])) - - # Solve the generalized eigenvalue problem for CCA - # (inv_C_XX @ C_XY @ inv_C_YY @ C_XY.T) and vice versa for Y - A = inv_C_XX @ C_XY @ inv_C_YY @ C_XY.T - B = inv_C_YY @ C_XY.T @ inv_C_XX @ C_XY - - # Perform eigenvalue decomposition - eigvals_X, eigvecs_X = np.linalg.eigh(A) - eigvals_Y, eigvecs_Y = np.linalg.eigh(B) - - # Sort the eigenvalues and eigenvectors in descending order - idx_X = np.argsort(eigvals_X)[::-1] - idx_Y = np.argsort(eigvals_Y)[::-1] - - eigvecs_X = eigvecs_X[:, idx_X] - eigvecs_Y = eigvecs_Y[:, idx_Y] - - # Canonical weights (the first `num_components` components) - w_X = eigvecs_X[:, :num_components] - w_Y = eigvecs_Y[:, :num_components] - - # Canonical correlations (square root of the eigenvalues, constrained to [0,1]) - corrs = np.sqrt(np.clip(eigvals_X[:num_components], 0, 1)) - - return np.mean(corrs) - return w_X, w_Y, corrs - -def pca(X, Y, size=1000, n_components=3, bins=30): - - pca_X = PCA(n_components=n_components) - X_pca = pca_X.fit_transform(X) - - pca_Y = PCA(n_components=n_components) - Y_pca = pca_Y.fit_transform(Y) - - # Step 2: Determine common bin edges based on the range of PCA components - min_value = min(X_pca.min(), Y_pca.min()) - max_value = max(X_pca.max(), Y_pca.max()) - bin_edges = np.linspace(min_value, max_value, bins + 1) - - # Step 3: Calculate histograms for each PCA component using the same bins - histograms_X = [np.histogram(X_pca[:, i], bins=bin_edges, density=True)[0] for i in range(n_components)] - histograms_Y = [np.histogram(Y_pca[:, i], bins=bin_edges, density=True)[0] for i in range(n_components)] - - # Step 4: Calculate Wasserstein distance between corresponding histograms - total_distance = 0 - for i in range(n_components): - total_distance += wasserstein_distance(histograms_X[i], histograms_Y[i]) - - # Step 5: Normalize the total distance for a similarity score - # Calculate the maximum possible distance (theoretical max could be based on histogram size) - # This could be replaced with a more complex calculation if necessary. - max_distance = 1.0 # Replace this with a suitable maximum based on your dataset properties. - - similarity_score = 1 - (total_distance / max_distance) - - return max(0, min(1, similarity_score)) # Ensure the score stays in [0, 1] diff --git a/legacy/root_gnn_dgl/root_gnn_base/uproot_dataset.py b/legacy/root_gnn_dgl/root_gnn_base/uproot_dataset.py deleted file mode 100644 index 04f06f895ef15e713f85e46ab42c76f757aedd5e..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/root_gnn_base/uproot_dataset.py +++ /dev/null @@ -1,54 +0,0 @@ -from root_gnn_base import dataset -import torch -import uproot -import glob -import os -import awkward as ak -import numpy as np -import time - -def node_features_from_ak(ch, node_branch_names, node_branch_types, node_feature_scales): - node_types = [] - n_types = len(node_branch_names[0]) - for i in range(n_types): - features = [] - branch_type = node_branch_types[i] - for j in range(len(node_branch_names)): - if node_branch_names[j] == 'CALC_E': - features.append(features[0] * np.cosh(features[1])) - elif node_branch_names[j] == 'NODE_TYPE': - features.append(ak.full_like(features[0], i)) - elif isinstance(node_branch_names[j][i], str): - features.append(ch[node_branch_names[j][i]]) - elif isinstance(node_branch_names[j][i], (int, float)): - features.append(ak.full_like(features[0], node_branch_names[j][i])) - if branch_type == 'single': - features = [f[:,np.newaxis] for f in features] - node_types.append(ak.Array(features)) - node_features = ak.concatenate(node_types, axis=2) * node_feature_scales #axis order at this point is (feature, event, node) - return node_features - -class UprootDataset(dataset.RootDataset): - def process(self): - starttime = time.time() - self.files = glob.glob(os.path.join(self.raw_dir, self.file_names)) - branches = self.get_list_of_branches() - self.chain = uproot.concatenate([f + ':' + self.tree_name for f in self.files], branches, num_workers=4) - node_features = node_features_from_ak(self.chain, self.node_branch_names, self.node_branch_types, self.node_feature_scales) - loadtime = time.time() - n_nodes = ak.num(node_features[0], axis=1) #number of nodes for each event - ftime = time.time() - self.graphs = [dataset.full_connected_graph(n, False) for n in n_nodes] - itime = time.time() - for i in range(len(self.graphs)): - if i % 10000 == 0: - print(f'Processing event {i}/{len(self.graphs)}') - self.graphs[i].ndata['features'] = torch.transpose(torch.tensor(node_features[:,i,:]),0,1).to(torch.float) - self.label = torch.stack([torch.full((len(self.graphs),),torch.tensor(self.label)), torch.tensor(ak.values_astype(self.chain[self.fold_var], np.int64))], dim=1) - gtime = time.time() - print() - print(f'load time: {loadtime - starttime} s') - print(f'feature time: {ftime - loadtime} s') - print(f'graph time: {itime - ftime} s') - print(f'graph data time: {gtime - itime} s') - diff --git a/legacy/root_gnn_dgl/root_gnn_base/utils.py b/legacy/root_gnn_dgl/root_gnn_base/utils.py deleted file mode 100644 index 08c5a1a56ac6b11f11fc84ca344bb2ac2b70fdeb..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/root_gnn_base/utils.py +++ /dev/null @@ -1,395 +0,0 @@ -import importlib -import yaml -import os -import torch -import numpy as np -import matplotlib.pyplot as plt -import dgl -import signal - -def buildFromConfig(conf, run_time_args = {}): - device = run_time_args.get('device', 'cpu') - if 'module' in conf: - module = importlib.import_module(conf['module']) - cls = getattr(module, conf['class']) - args = conf['args'].copy() - extra_args = {k: v for k, v in conf.items() if k not in ['module', 'class', 'args']} - args.update(extra_args) - if 'weight' in args and isinstance(args['weight'], list): - args['weight'] = torch.tensor(args['weight'], dtype=torch.float, device=device) - # Remove device from run_time_args to not pass it to the class - run_time_args = {k: v for k, v in run_time_args.items() if k != 'device'} - return cls(**args, **run_time_args) - else: - print('No module specified in config. Returning None.') - -def cycler(iterable): - while True: - #print('Cycler is cycling...') - for i in iterable: - yield i - -def include_config(conf): - if 'include' in conf: - for i in conf['include']: - with open(i) as f: - conf.update(yaml.load(f, Loader=yaml.FullLoader)) - del conf['include'] - -def load_config(config_file): - with open(config_file) as f: - conf = yaml.load(f, Loader=yaml.FullLoader) - include_config(conf) - return conf - -#Timeout function from https://stackoverflow.com/questions/492519/timeout-on-a-function-call -class TimeoutException(Exception): - pass - -def timeout_handler(signum, frame): - raise TimeoutException() - -def set_timeout(timeout): - signal.signal(signal.SIGALRM, timeout_handler) - signal.alarm(timeout) - -def unset_timeout(): - signal.alarm(0) - signal.signal(signal.SIGALRM, signal.SIG_DFL) - -def make_padding_graph(batch, pad_nodes, pad_edges): - senders = [] - receivers = [] - senders = torch.arange(0,pad_edges) // pad_nodes - receivers = torch.arange(1,pad_edges+1) % pad_nodes - if pad_nodes < 0 or pad_edges < 0 or pad_edges > pad_nodes * pad_nodes / 2: - print('Batch is larger than padding size or e > n^2/2. Repeating edges as necessary.') - print(f'Batch nodes: {batch.num_nodes()}, Batch edges: {batch.num_edges()}, Padding nodes: {pad_nodes}, Padding edges: {pad_edges}') - senders = senders % pad_nodes - padg = dgl.graph((senders[:pad_edges], receivers[:pad_edges]), num_nodes = pad_nodes) - for k in batch.ndata.keys(): - padg.ndata[k] = torch.zeros( (pad_nodes, batch.ndata[k].shape[1]) ) - for k in batch.edata.keys(): - padg.edata[k] = torch.zeros( (pad_edges, batch.edata[k].shape[1]) ) - return dgl.batch([batch, padg.to(batch.device)]) - -def pad_size(graphs, edges, nodes, edge_per_graph=3, node_per_graph=14): - pad_nodes = ((nodes // (node_per_graph * graphs))+1) * graphs * node_per_graph - pad_edges = ((edges // (edge_per_graph * graphs))+1) * graphs * edge_per_graph - return pad_nodes, pad_edges - -def pad_batch_to_step_per_graph(batch, edge_per_graph=3, node_per_graph=14): - n_graphs = batch.batch_num_nodes().shape[0] - pad_nodes = (batch.num_nodes() + node_per_graph * n_graphs) % int(n_graphs * node_per_graph) - pad_edges = (batch.num_edges() + edge_per_graph * n_graphs) % int(n_graphs * edge_per_graph) - return make_padding_graph(batch, pad_nodes, pad_edges) - -def pad_batch(batch, edges = 104000, nodes = 16000): - if edges == 0 and nodes == 0: - return batch - pad_nodes = 0 - pad_edges = 0 - pad_nodes = nodes - batch.num_nodes() - pad_edges = edges - batch.num_edges() - return make_padding_graph(batch, pad_nodes, pad_edges) - -def pad_batch_num_nodes(batch, max_num_nodes, hid_size = 64): - print(f"Padding each graph to have {max_num_nodes} nodes. Using hidden size {hid_size}.") - - unbatched = dgl.unbatch(batch) - for g in unbatched: - num_nodes_to_add = max_num_nodes - g.number_of_nodes() - if num_nodes_to_add > 0: - g.add_nodes(num_nodes_to_add) # Add isolated nodes - - batch = dgl.batch(unbatched) - - padding_mask = torch.zeros((batch.ndata['features'].shape[0]), dtype=torch.bool) - global_update_weights = torch.ones((batch.ndata['features'].shape[0], hid_size)) - - for i in range(len(batch.ndata['features'])): - if (torch.count_nonzero(batch.ndata['features'][i]) == 0): - padding_mask[i] = True - global_update_weights[i] = 0 - - batch.ndata['w'] = global_update_weights - batch.ndata['padding_mask'] = padding_mask - - return batch - - -def fold_selection(fold_config, sample): - n_folds = fold_config['n_folds'] - folds_opt = fold_config[sample] - folds = [] - if type(folds_opt) == int: - return lambda x : x.tracking[:,0] % n_folds == folds_opt - elif type(folds_opt) == list: - print("fold type is list") - print(f"fold_config = {fold_config}") - print(f"folds_opt = {folds_opt}") - return lambda x : sum([x.tracking[:,0] % n_folds == f for f in folds_opt]) == 1 - else: - raise ValueError("Invalid fold selection option with type {}".format(type(folds_opt))) - -def fold_selection_name(fold_config, sample): - n_folds = fold_config['n_folds'] - folds_opt = fold_config[sample] - if type(folds_opt) == int: - return f'n_{n_folds}_f_{folds_opt}' - elif type(folds_opt) == list: - return f'n_{n_folds}_f_{"_".join([str(f) for f in folds_opt])}' - else: - raise ValueError("Invalid fold selection option with type {}".format(type(folds_opt))) - -#Return the index and checkpoint of the last epoch. -def get_last_epoch(config, max_ep = -1, device = None): - last_epoch = -1 - checkpoint = None - if max_ep < 0: - max_ep = config['Training']['epochs'] - for ep in range(max_ep): - if os.path.exists(os.path.join(config['Training_Directory'], f'model_epoch_{ep}.pt')): - last_epoch = ep - else: - print(f'Epoch {ep} not found. Stopping at epoch {last_epoch}') - print('File not found: ', os.path.join(config['Training_Directory'], f'model_epoch_{ep}.pt')) - break - if last_epoch >= 0: - checkpoint = torch.load(os.path.join(config['Training_Directory'], f'model_epoch_{last_epoch}.pt'), map_location=device) - return last_epoch, checkpoint - -#Return the index and checkpoint of the last epoch. -def get_specific_epoch(config, target_epoch, device = None, from_ryan = False): - last_epoch = -1 - checkpoint = None - for ep in range(target_epoch + 1): - if (from_ryan): - if os.path.exists(os.path.join('/global/cfs/cdirs/atlas/berobert/root_gnn_dgl/' + config['Training_Directory'], f'model_epoch_{ep}.pt')): - last_epoch = ep - else: - print(f'Epoch {ep} not found. Stopping at epoch {last_epoch}') - print('File not found: ', os.path.join('/global/cfs/cdirs/atlas/berobert/root_gnn_dgl/' + config['Training_Directory'], f'model_epoch_{ep}.pt')) - break - else: - if os.path.exists(os.path.join(config['Training_Directory'], f'model_epoch_{ep}.pt')): - last_epoch = ep - else: - print(f'Epoch {ep} not found. Stopping at epoch {last_epoch}') - print('File not found: ', os.path.join(config['Training_Directory'], f'model_epoch_{ep}.pt')) - break - if last_epoch >= 0: - if (from_ryan): - checkpoint = torch.load('/global/cfs/cdirs/atlas/berobert/root_gnn_dgl/' + os.path.join(config['Training_Directory'], f'model_epoch_{last_epoch}.pt'), map_location=device) - else: - checkpoint = torch.load(os.path.join(config['Training_Directory'], f'model_epoch_{last_epoch}.pt'), map_location=device) - return last_epoch, checkpoint - -#Return the index and checkpoint of the nest epoch. -def get_best_epoch(config, var='Test_AUC', mode='max', device=None, from_ryan=False): - # Read the training log - log = read_log(config) - - # Ensure the specified variable exists in the log - if var not in log: - raise ValueError(f"Variable '{var}' not found in the training log.") - - # Determine the target epoch based on the mode ('max' or 'min') - if mode == 'max': - target_epoch = int(np.argmax(log[var])) - print(f"Best epoch based on '{var}' (max): {target_epoch} with value: {log[var][target_epoch]}") - elif mode == 'min': - target_epoch = int(np.argmin(log[var])) - print(f"Best epoch based on '{var}' (min): {target_epoch} with value: {log[var][target_epoch]}") - else: - raise ValueError(f"Invalid mode '{mode}'. Expected 'max' or 'min'.") - - # Initialize checkpoint retrieval variables - last_epoch = -1 - checkpoint = None - - # Iterate through epochs up to the target epoch to find the corresponding checkpoint - for ep in range(target_epoch + 1): - if from_ryan: - checkpoint_path = os.path.join( - '/global/cfs/cdirs/atlas/berobert/root_gnn_dgl/', - config['Training_Directory'], - f'model_epoch_{ep}.pt' - ) - else: - checkpoint_path = os.path.join( - config['Training_Directory'], - f'model_epoch_{ep}.pt' - ) - - if os.path.exists(checkpoint_path): - last_epoch = ep - else: - print(f'Epoch {ep} not found. Stopping at epoch {last_epoch}') - print('File not found: ', checkpoint_path) - break - - # Load the checkpoint for the last valid epoch - if last_epoch >= 0: - if from_ryan: - checkpoint_path = os.path.join( - '/global/cfs/cdirs/atlas/berobert/root_gnn_dgl/', - config['Training_Directory'], - f'model_epoch_{last_epoch}.pt' - ) - else: - checkpoint_path = os.path.join( - config['Training_Directory'], - f'model_epoch_{last_epoch}.pt' - ) - - checkpoint = torch.load(checkpoint_path, map_location=device) - - return last_epoch, checkpoint - -def read_log(config): - lines = [] - with open(config['Training_Directory'] + '/training.log', 'r') as f: - lines = f.readlines() - lines = [l for l in lines if 'Epoch' in l] - - labels = [] - for field in lines[0].split('|'): - labels.append(field.split()[0]) - - # Initialize log as a dictionary with empty lists - log = {label: [] for label in labels} - - for line in lines: - valid_row = True # Flag to check if the row is valid - temp_row = {} # Temporary row to store values before adding to log - - for field in line.split('|'): - spl = field.split() - try: - temp_row[spl[0]] = float(spl[1]) - except (ValueError, IndexError): - valid_row = False # Mark row as invalid if conversion fails - break - - if valid_row: # Only add the row if all fields are valid - for label in labels: - log[label].append(temp_row.get(label, np.nan)) # Handle missing labels gracefully - - # Convert lists to numpy arrays for consistency - for label in labels: - log[label] = np.array(log[label]) - - return log - -#Plot training logs. -def plot_log(log, output_file): - fig, ax = plt.subplots(2, 2, figsize=(10,10)) - #Time - - ax[0][0].plot(log['Epoch'], np.cumsum(log['Time']), label='Time') - ax[0][0].set_xlabel('Epoch') - ax[0][0].set_ylabel('Time (s)') - ax[0][0].legend() - - """ - ax[0][0].plot(log['Epoch'], log['LR'], label='Learning Rate') - ax[0][0].set_xlabel('Epoch') - ax[0][0].set_ylabel('Learning Rate') - ax[0][0].set_yscale('log') - ax[0][0].legend() - """ - - #Loss - ax[0][1].plot(log['Epoch'], log['Loss'], label='Train Loss') - ax[0][1].plot(log['Epoch'], log['Test_Loss'], label='Test Loss') - ax[0][1].set_xlabel('Epoch') - ax[0][1].set_ylabel('Loss') - ax[0][1].legend() - - #Accuracy - ax[1][0].plot(log['Epoch'], log['Accuracy'], label='Test Accuracy') - ax[1][0].set_xlabel('Epoch') - ax[1][0].set_ylabel('Accuracy') - ax[1][0].set_ylim((0.44, 0.56)) - ax[1][0].legend() - - #AUC - ax[1][1].plot(log['Epoch'], log['Test_AUC'], label='Test AUC') - ax[1][1].set_xlabel('Epoch') - ax[1][1].set_ylabel('AUC') - ax[1][1].legend() - - fig.savefig(output_file) - -class EarlyStop(): - def __init__(self, patience=15, threshold=1e-8, mode='min'): - self.patience = patience - self.threshold = threshold - self.mode = mode - self.count = 0 - self.current_best = np.inf if mode == 'min' else -np.inf - self.should_stop = False - - def update(self, value): - if self.mode == 'min': # Minimizing loss - if value < self.current_best - self.threshold: - self.current_best = value - self.count = 0 - else: - self.count += 1 - elif self.mode == 'max': # Maximizing metric - if value > self.current_best + self.threshold: - self.current_best = value - self.count = 0 - else: - self.count += 1 - - # Check if patience is exceeded - if self.count >= self.patience: - self.should_stop = True - - def reset(self): - self.count = 0 - self.current_best = np.inf if self.mode == 'min' else -np.inf - self.should_stop = False - - def to_str(self): - status = ( - f"EarlyStop Status:\n" - f" Mode: {'Minimize' if self.mode == 'min' else 'Maximize'}\n" - f" Patience: {self.patience}\n" - f" Threshold: {self.threshold:.3e}\n" - f" Current Best: {self.current_best:.6f}\n" - f" Consecutive Epochs Without Improvement: {self.count}\n" - f" Stopping Triggered: {'Yes' if self.should_stop else 'No'}" - ) - return status - - def to_dict(self): - - return { - 'patience': self.patience, - 'threshold': self.threshold, - 'mode': self.mode, - 'count': self.count, - 'current_best': self.current_best, - 'should_stop': self.should_stop, - } - - @classmethod - def load_from_dict(cls, state_dict): - instance = cls( - patience=state_dict['patience'], - threshold=state_dict['threshold'], - mode=state_dict['mode'] - ) - instance.count = state_dict['count'] - instance.current_best = state_dict['current_best'] - instance.should_stop = state_dict['should_stop'] - return instance - - -def graph_augmentation(graph): - print("Augmenting Graph") - return diff --git a/legacy/root_gnn_dgl/run_demo.sh b/legacy/root_gnn_dgl/run_demo.sh deleted file mode 100644 index 71fc5f9514e5f8f53464d16a38f8e4a95ae832ef..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/run_demo.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash - -# Pretraining -datasets=("ttH" "tHjb" "ggF" "VBF" "WH" "ZH" "ttyy" "tttt" "SingleT_schan" "ttbar" "ttW" "ttt") -chunks=3 - -for data in "${datasets[@]}"; do - python scripts/prep_data.py --config configs/stats_100K/pretraining_multiclass.yaml --dataset "$data" --shuffle_mode --chunk 0 - for ((i=0; i tensor and tensor -> ONNX - - save diagnostic plot next to ONNX file -""" - -from __future__ import annotations - -import argparse -import inspect -import importlib -import os -import sys -from pathlib import Path -from types import MethodType, SimpleNamespace -from typing import Any, Dict, Iterator, Optional, Tuple - -REPO_ROOT = Path(__file__).resolve().parents[1] -sys.path.insert(0, str(REPO_ROOT)) - -import dgl -import matplotlib.pyplot as plt -import numpy as np -import onnxruntime as ort -import torch -import torch.nn as nn -import yaml -from dgl.dataloading import GraphDataLoader -from torch_scatter import scatter_mean, scatter_sum - -try: - from root_gnn_base import utils -except Exception as exc: - utils = None - _UTILS_IMPORT_ERROR = exc -else: - _UTILS_IMPORT_ERROR = None - - -# ------------------------- -# Config / checkpoint utils -# ------------------------- - - -def load_config(config_file: str | os.PathLike[str]) -> Dict[str, Any]: - config_path = Path(config_file) - with config_path.open() as f: - conf = yaml.load(f, Loader=yaml.FullLoader) - - if conf is None: - raise ValueError(f"Empty config: {config_file}") - - include_config(conf, config_path.parent) - return conf - - -def include_config(conf: Dict[str, Any], base_dir: Path) -> None: - includes = conf.pop("include", None) - if not includes: - return - - if isinstance(includes, (str, os.PathLike)): - includes = [includes] - - for inc in includes: - inc_path = Path(inc) - if not inc_path.is_absolute(): - inc_path = base_dir / inc_path - - with inc_path.open() as f: - included = yaml.load(f, Loader=yaml.FullLoader) or {} - - include_config(included, inc_path.parent) - conf.update(included) - - -def find_model_class(model_cfg: Dict[str, Any]) -> str: - return str(model_cfg.get("class", "")).split(".")[-1] - - -def infer_global_size(model_args: Dict[str, Any]) -> int: - for key in ("global_size", "global_in_size", "global_dim", "n_global", "sample_global"): - if key in model_args: - return int(model_args[key]) - return 1 - - -def load_best_checkpoint(conf: Dict[str, Any]) -> Tuple[int, Dict[str, Any]]: - if utils is None: - raise RuntimeError( - "Could not import root_gnn_base.utils, which is needed for utils.get_best_epoch. " - f"Original import error: {_UTILS_IMPORT_ERROR}" - ) - - try: - return utils.get_best_epoch(conf, mode="max") - except TypeError: - return utils.get_best_epoch(conf) - - -def load_checkpoint(conf: Dict[str, Any], epoch: Optional[int]) -> Tuple[int, Dict[str, Any]]: - if epoch is None: - return load_best_checkpoint(conf) - - training_dir = Path(conf["Training_Directory"]) - checkpoint_path = training_dir / f"model_epoch_{epoch}.pt" - - if not checkpoint_path.exists(): - raise FileNotFoundError(f"Could not find checkpoint: {checkpoint_path}") - - checkpoint = torch.load(checkpoint_path, map_location="cpu") - return epoch, checkpoint - - -# ------------------------- -# MLP helpers -# ------------------------- - - -def make_slp(in_size: int, out_size: int, activation=nn.ReLU, dropout: float = 0) -> list[nn.Module]: - return [nn.Linear(in_size, out_size), activation(), nn.Dropout(dropout)] - - -def make_mlp( - in_size: int, - hid_size: int, - out_size: int, - n_layers: int, - activation=nn.ReLU, - dropout: float = 0, -) -> nn.Sequential: - layers: list[nn.Module] = [] - - if n_layers > 1: - layers += make_slp(in_size, hid_size, activation, dropout) - for _ in range(n_layers - 2): - layers += make_slp(hid_size, hid_size, activation, dropout) - layers += make_slp(hid_size, out_size, activation, dropout) - else: - layers += make_slp(in_size, out_size, activation, dropout) - - layers.append(nn.LayerNorm(out_size)) - return nn.Sequential(*layers) - - -def broadcast_global_to_nodes(h_global: torch.Tensor, node_batch: torch.Tensor) -> torch.Tensor: - if h_global.dim() == 1: - h_global = h_global.unsqueeze(0) - return h_global[node_batch.to(torch.long)] - - -def broadcast_global_to_edges(h_global: torch.Tensor, edge_batch: torch.Tensor) -> torch.Tensor: - if h_global.dim() == 1: - h_global = h_global.unsqueeze(0) - return h_global[edge_batch.to(torch.long)] - - -def copy_v_udf(edges): - return {"m_v": edges.dst["h"]} - - -def make_node_batch_ids(batch_num_nodes: torch.Tensor) -> torch.Tensor: - return torch.repeat_interleave( - torch.arange(len(batch_num_nodes), device=batch_num_nodes.device, dtype=torch.long), - batch_num_nodes.to(torch.long), - ) - - -def make_edge_batch_ids(batch_num_edges: torch.Tensor) -> torch.Tensor: - return torch.repeat_interleave( - torch.arange(len(batch_num_edges), device=batch_num_edges.device, dtype=torch.long), - batch_num_edges.to(torch.long), - ) - - -# ------------------------- -# Tensor / ONNX model copies -# ------------------------- - - -class EdgeNetworkONNX(nn.Module): - """ONNX-friendly tensor implementation of the DGL Edge_Network.""" - - def __init__( - self, - sample_graph: Any, - sample_global: int, - hid_size: int, - out_size: int, - n_layers: int, - n_proc_steps: int, - dropout: float = 0, - **kwargs: Any, - ) -> None: - super().__init__() - - if kwargs: - print(f"Unused args while creating EdgeNetworkONNX: {kwargs}") - - self.n_proc_steps = n_proc_steps - - node_in = int(sample_graph.ndata["features"].shape[1]) - edge_in = int(sample_graph.edata["features"].shape[1]) - gl_size = int(sample_global) - - self.layers = nn.ModuleList() - self.node_encoder = make_mlp(node_in, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_encoder = make_mlp(edge_in, hid_size, hid_size, n_layers, dropout=dropout) - self.global_encoder = make_mlp(gl_size, hid_size, hid_size, n_layers, dropout=dropout) - - self.node_update = make_mlp(3 * hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.edge_update = make_mlp(4 * hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.global_update = make_mlp(3 * hid_size, hid_size, hid_size, n_layers, dropout=dropout) - - self.global_decoder = make_mlp(hid_size, hid_size, hid_size, n_layers, dropout=dropout) - self.classify = nn.Linear(hid_size, out_size) - - def forward( - self, - node_features: torch.Tensor, - edge_features: torch.Tensor, - global_feats: torch.Tensor, - edge_index: torch.Tensor, - node_batch: torch.Tensor, - ) -> torch.Tensor: - src = edge_index[0].to(torch.long) - dst = edge_index[1].to(torch.long) - node_batch = node_batch.to(torch.long) - - h = self.node_encoder(node_features) - e = self.edge_encoder(edge_features) - h_global = self.global_encoder(global_feats) - - num_graphs = global_feats.size(0) - - for _ in range(self.n_proc_steps): - edge_batch = node_batch[dst] - - e = self.edge_update( - torch.cat( - [ - e, - h[src], - h[dst], - broadcast_global_to_edges(h_global, edge_batch), - ], - dim=1, - ) - ) - - h_e = scatter_sum(e, dst, dim=0, dim_size=h.size(0)) - - h = self.node_update( - torch.cat( - [ - h, - h_e, - broadcast_global_to_nodes(h_global, node_batch), - ], - dim=1, - ) - ) - - mean_n = scatter_mean(h, node_batch, dim=0, dim_size=num_graphs) - mean_e = scatter_mean(e, edge_batch, dim=0, dim_size=num_graphs) - - h_global = self.global_update(torch.cat([h_global, mean_n, mean_e], dim=1)) - - return self.classify(self.global_decoder(h_global)) - - -class TransferredLearningFinetuningONNX(nn.Module): - """ONNX-friendly tensor implementation of Transferred_Learning_Finetuning.""" - - def __init__( - self, - pretraining_path: str, - pretraining_model_args: Dict[str, Any], - sample_graph: Any, - sample_global: int, - hid_size: int, - out_size: int, - n_layers: int, - n_proc_steps: int, - dropout: float = 0, - frozen_pretraining: bool = False, - **kwargs: Any, - ) -> None: - super().__init__() - - if kwargs: - print(f"Unused args while creating TransferredLearningFinetuningONNX: {kwargs}") - - self.n_proc_steps = n_proc_steps - - pre_args = dict(pretraining_model_args) - pre_args.setdefault("dropout", dropout) - - self.pretrained_model = EdgeNetworkONNX( - sample_graph=sample_graph, - sample_global=sample_global, - **pre_args, - ) - - checkpoint = torch.load(pretraining_path, map_location="cpu") - self.pretrained_model.load_state_dict(checkpoint["model_state_dict"]) - - self.pretrained_model = nn.Sequential(*list(self.pretrained_model.children())[:-1]) - - print(f"Freeze Pretraining = {frozen_pretraining}") - - if frozen_pretraining: - for param in self.pretrained_model.parameters(): - param.requires_grad = False - for param in self.pretrained_model[7].parameters(): - param.requires_grad = True - - torch.manual_seed(2) - self.classify = nn.Linear(hid_size, out_size) - - def _backbone_forward( - self, - node_features: torch.Tensor, - edge_features: torch.Tensor, - global_feats: torch.Tensor, - edge_index: torch.Tensor, - node_batch: torch.Tensor, - ) -> torch.Tensor: - src = edge_index[0].to(torch.long) - dst = edge_index[1].to(torch.long) - node_batch = node_batch.to(torch.long) - - node_enc = self.pretrained_model[1] - edge_enc = self.pretrained_model[2] - glob_enc = self.pretrained_model[3] - node_upd = self.pretrained_model[4] - edge_upd = self.pretrained_model[5] - glob_upd = self.pretrained_model[6] - glob_dec = self.pretrained_model[7] - - h = node_enc(node_features) - e = edge_enc(edge_features) - h_global = glob_enc(global_feats) - - num_graphs = global_feats.size(0) - - for _ in range(self.n_proc_steps): - edge_batch = node_batch[dst] - - e = edge_upd( - torch.cat( - [ - e, - h[src], - h[dst], - broadcast_global_to_edges(h_global, edge_batch), - ], - dim=1, - ) - ) - - h_e = scatter_sum(e, dst, dim=0, dim_size=h.size(0)) - - h = node_upd( - torch.cat( - [ - h, - h_e, - broadcast_global_to_nodes(h_global, node_batch), - ], - dim=1, - ) - ) - - mean_n = scatter_mean(h, node_batch, dim=0, dim_size=num_graphs) - mean_e = scatter_mean(e, edge_batch, dim=0, dim_size=num_graphs) - - h_global = glob_upd(torch.cat([h_global, mean_n, mean_e], dim=1)) - - return glob_dec(h_global) - - def forward( - self, - node_features: torch.Tensor, - edge_features: torch.Tensor, - global_feats: torch.Tensor, - edge_index: torch.Tensor, - node_batch: torch.Tensor, - ) -> torch.Tensor: - return self.classify( - self._backbone_forward( - node_features, - edge_features, - global_feats, - edge_index, - node_batch, - ) - ) - - -# ------------------------- -# Model construction -# ------------------------- - - -def make_sample_graph(node_features: int, edge_features: int) -> Any: - return SimpleNamespace( - ndata={"features": torch.zeros(2, node_features, dtype=torch.float32)}, - edata={"features": torch.zeros(2, edge_features, dtype=torch.float32)}, - ) - - -def build_tensor_model(conf: Dict[str, Any]) -> nn.Module: - model_cfg = conf["Model"] - model_args = dict(model_cfg.get("args", {})) - class_name = find_model_class(model_cfg) - - node_in = int(model_args.get("in_size", 7)) - edge_in = int(model_args.get("edge_in_size", 3)) - global_in = infer_global_size(model_args) - - sample_graph = make_sample_graph(node_in, edge_in) - - common = { - "sample_graph": sample_graph, - "sample_global": global_in, - "hid_size": int(model_args["hid_size"]), - "out_size": int(model_args["out_size"]), - "n_layers": int(model_args["n_layers"]), - "n_proc_steps": int(model_args["n_proc_steps"]), - "dropout": float(model_args.get("dropout", 0)), - } - - if class_name == "Edge_Network": - return EdgeNetworkONNX(**common) - - if class_name == "Transferred_Learning_Finetuning": - pretraining_model = model_args.get("pretraining_model", {}) - pre_args = dict(pretraining_model.get("args", {})) - - pre_args.pop("in_size", None) - pre_args.pop("edge_in_size", None) - - return TransferredLearningFinetuningONNX( - pretraining_path=model_args["pretraining_path"], - pretraining_model_args=pre_args, - frozen_pretraining=bool(model_args.get("frozen_pretraining", False)), - **common, - ) - - raise ValueError( - f"Unsupported Model.class={class_name!r}. " - "Expected Edge_Network or Transferred_Learning_Finetuning." - ) - - -def build_dgl_model(conf: Dict[str, Any], sample_graph: dgl.DGLGraph, sample_global: torch.Tensor) -> nn.Module: - if utils is None: - raise RuntimeError( - "Could not import root_gnn_base.utils, which is needed to build the DGL model. " - f"Original import error: {_UTILS_IMPORT_ERROR}" - ) - - return utils.buildFromConfig( - conf["Model"], - { - "sample_graph": sample_graph, - "sample_global": sample_global, - }, - ) - - -def patch_finetuning_pretrained_output(model: nn.Module) -> nn.Module: - """Patch older finetuning models so Pretrained_Output can accept explicit globals. - - The repo has moved through a few signatures for the finetuning DGL model. - Some checkpoints still load a class whose forward() calls Pretrained_Output(g.clone()) - while the body expects a global_feats tensor. This adapter preserves the original - module weights but makes the instance callable from the exporter in either style. - """ - - if not hasattr(model, "TL_node_encoder") or not hasattr(model, "TL_global_encoder"): - return model - - original = getattr(model, "Pretrained_Output", None) - if original is None: - return model - - try: - signature = inspect.signature(original) - # Bound methods exclude "self". - if len(signature.parameters) > 1: - return model - except (TypeError, ValueError): - pass - - def _patched_pretrained_output(self, g, global_feats=None): - h = self.TL_node_encoder(g.ndata["features"]) - e = self.TL_edge_encoder(g.edata["features"]) - g.ndata["h"] = h - g.edata["e"] = e - - if global_feats is None: - global_feats = g.batch_num_nodes()[:, None].to(torch.float) - - h_global = self.TL_global_encoder(global_feats) - node_batch = make_node_batch_ids(g.batch_num_nodes()) - edge_batch = make_edge_batch_ids(g.batch_num_edges()) - - for _ in range(self.n_proc_steps): - g.apply_edges(dgl.function.copy_u("h", "m_u")) - g.apply_edges(copy_v_udf) - g.edata["e"] = self.TL_edge_update( - torch.cat( - ( - g.edata["e"], - g.edata["m_u"], - g.edata["m_v"], - broadcast_global_to_edges(h_global, edge_batch), - ), - dim=1, - ) - ) - g.update_all(dgl.function.copy_e("e", "m"), dgl.function.sum("m", "h_e")) - g.ndata["h"] = self.TL_node_update( - torch.cat((g.ndata["h"], g.ndata["h_e"], broadcast_global_to_nodes(h_global, node_batch)), dim=1) - ) - h_global = self.TL_global_update( - torch.cat((h_global, dgl.mean_nodes(g, "h"), dgl.mean_edges(g, "e")), dim=1) - ) - - return self.TL_global_decoder(h_global) - - model.Pretrained_Output = MethodType(_patched_pretrained_output, model) - return model - - -# ------------------------- -# Dataset / graph utilities -# ------------------------- - - -def build_dataset_from_config(conf: Dict[str, Any]): - if utils is None: - raise RuntimeError( - "Could not import root_gnn_base.utils, which is needed to build the dataset. " - f"Original import error: {_UTILS_IMPORT_ERROR}" - ) - - dset_name = list(conf["Datasets"].keys())[0] - dset_conf = dict(conf["Datasets"][dset_name]) - dataset = utils.buildFromConfig(dset_conf) - return dset_name, dataset - - -def single_graph_loader(conf: Dict[str, Any]) -> Tuple[str, GraphDataLoader]: - dset_name, dataset = build_dataset_from_config(conf) - - loader = GraphDataLoader( - dataset, - batch_size=1, - shuffle=False, - drop_last=False, - num_workers=0, - ) - - return dset_name, loader - - -def get_global_features(batch: dgl.DGLGraph) -> torch.Tensor: - candidates = [] - - for attr in ("global_features", "global_feats", "globals"): - if hasattr(batch, attr): - candidates.append(getattr(batch, attr)) - - for key in ("global_features", "global_feats", "globals", "features"): - try: - if key in batch.ndata and False: - pass - except Exception: - pass - - for candidate in candidates: - if isinstance(candidate, torch.Tensor) and candidate.numel() > 0: - if candidate.dim() == 1: - candidate = candidate.unsqueeze(0) - return candidate.to(torch.float32) - - return batch.batch_num_nodes().to(torch.float32).unsqueeze(1) - - -def tensorize_single_graph(batch: dgl.DGLGraph) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: - if len(batch.batch_num_nodes()) != 1: - raise ValueError( - f"Expected a single graph/event, but got batched graph with {len(batch.batch_num_nodes())} graphs" - ) - - node_features = batch.ndata["features"].detach().cpu().to(torch.float32) - edge_features = batch.edata["features"].detach().cpu().to(torch.float32) - - src, dst = batch.edges() - edge_index = torch.stack([src.detach().cpu(), dst.detach().cpu()], dim=0).to(torch.long) - - node_batch = torch.zeros(node_features.shape[0], dtype=torch.long) - global_feats = get_global_features(batch).detach().cpu().to(torch.float32) - - if global_feats.dim() == 1: - global_feats = global_feats.unsqueeze(0) - - if global_feats.shape[0] != 1: - global_feats = global_feats.reshape(1, -1) - - return node_features, edge_features, global_feats, edge_index, node_batch - - -def first_real_event_inputs(conf: Dict[str, Any]) -> Tuple[str, dgl.DGLGraph, Tuple[torch.Tensor, ...]]: - dset_name, loader = single_graph_loader(conf) - - batch, labels, tracking, extra = next(iter(loader)) - _ = labels, tracking, extra - - inputs = tensorize_single_graph(batch) - return dset_name, batch, inputs - - -# ------------------------- -# ONNX export / runtime -# ------------------------- - - -def export_onnx(model: nn.Module, inputs: Tuple[torch.Tensor, ...], out_path: str) -> None: - output = Path(out_path) - - if output.parent and str(output.parent) != ".": - output.parent.mkdir(parents=True, exist_ok=True) - - torch.onnx.export( - model, - inputs, - str(output), - input_names=[ - "node_features", - "edge_features", - "global_features", - "edge_index", - "node_batch", - ], - output_names=["logits"], - dynamic_axes={ - "node_features": {0: "num_nodes"}, - "edge_features": {0: "num_edges"}, - "edge_index": {1: "num_edges"}, - "node_batch": {0: "num_nodes"}, - }, - opset_version=16, - ) - - -def make_onnx_session(onnx_path: str) -> ort.InferenceSession: - sess_options = ort.SessionOptions() - - # Avoid Perlmutter / CPU affinity warnings from ONNX Runtime. - sess_options.intra_op_num_threads = 1 - sess_options.inter_op_num_threads = 1 - - return ort.InferenceSession( - onnx_path, - sess_options=sess_options, - providers=["CPUExecutionProvider"], - ) - - -def run_onnx(sess: ort.InferenceSession, inputs: Tuple[torch.Tensor, ...]) -> np.ndarray: - node_features, edge_features, global_feats, edge_index, node_batch = inputs - - ort_inputs = { - "node_features": node_features.numpy().astype(np.float32), - "edge_features": edge_features.numpy().astype(np.float32), - "global_features": global_feats.numpy().astype(np.float32), - "edge_index": edge_index.numpy().astype(np.int64), - "node_batch": node_batch.numpy().astype(np.int64), - } - - ort_input_names = {inp.name for inp in sess.get_inputs()} - ort_inputs = {k: v for k, v in ort_inputs.items() if k in ort_input_names} - - return sess.run(None, ort_inputs)[0] - - -# ------------------------- -# Real-data validation loop -# ------------------------- - - -def sigmoid_np(x: np.ndarray) -> np.ndarray: - return 1.0 / (1.0 + np.exp(-x)) - - -def run_real_data_test( - conf: Dict[str, Any], - tensor_model: nn.Module, - onnx_path: str, - epoch: int, - checkpoint: Dict[str, Any], - max_events: int, - tol_dgl_tensor: float, - tol_tensor_onnx: float, -) -> None: - dset_name, loader = single_graph_loader(conf) - - first_batch, labels, tracking, extra = next(iter(loader)) - _ = labels, tracking, extra - - first_inputs = tensorize_single_graph(first_batch) - first_global = first_inputs[2] - - dgl_model = build_dgl_model(conf, first_batch, first_global) - dgl_model.load_state_dict(checkpoint["model_state_dict"]) - dgl_model = patch_finetuning_pretrained_output(dgl_model) - dgl_model.eval().cpu() - - tensor_model.eval().cpu() - - sess = make_onnx_session(onnx_path) - - all_dgl_logits = [] - all_tensor_logits = [] - all_onnx_logits = [] - - all_dgl_prob = [] - all_tensor_prob = [] - all_onnx_prob = [] - - dgl_tensor_max_diffs = [] - tensor_onnx_max_diffs = [] - - n_tested = 0 - - # Recreate loader so event 0 is included. - _, loader = single_graph_loader(conf) - - for item in loader: - batch, labels, tracking, extra = item - _ = labels, tracking, extra - - inputs = tensorize_single_graph(batch) - node_features, edge_features, global_feats, edge_index, node_batch = inputs - - with torch.no_grad(): - dgl_logits = dgl_model(batch, global_feats).detach().cpu().numpy() - tensor_logits = tensor_model(*inputs).detach().cpu().numpy() - - onnx_logits = run_onnx(sess, inputs) - - dgl_prob = sigmoid_np(dgl_logits) - tensor_prob = sigmoid_np(tensor_logits) - onnx_prob = sigmoid_np(onnx_logits) - - all_dgl_logits.append(dgl_logits.reshape(-1)) - all_tensor_logits.append(tensor_logits.reshape(-1)) - all_onnx_logits.append(onnx_logits.reshape(-1)) - - all_dgl_prob.append(dgl_prob.reshape(-1)) - all_tensor_prob.append(tensor_prob.reshape(-1)) - all_onnx_prob.append(onnx_prob.reshape(-1)) - - dgl_tensor_max_diffs.append(float(np.max(np.abs(dgl_logits - tensor_logits)))) - tensor_onnx_max_diffs.append(float(np.max(np.abs(tensor_logits - onnx_logits)))) - - n_tested += 1 - - if n_tested % 100 == 0: - print(f"Validated {n_tested} single-event graphs...") - - if max_events > 0 and n_tested >= max_events: - break - - if n_tested == 0: - raise RuntimeError("No events were available for validation.") - - dgl_logits_all = np.concatenate(all_dgl_logits) - tensor_logits_all = np.concatenate(all_tensor_logits) - onnx_logits_all = np.concatenate(all_onnx_logits) - - dgl_prob_all = np.concatenate(all_dgl_prob) - tensor_prob_all = np.concatenate(all_tensor_prob) - onnx_prob_all = np.concatenate(all_onnx_prob) - - dgl_vs_tensor = np.abs(dgl_logits_all - tensor_logits_all) - tensor_vs_onnx = np.abs(tensor_logits_all - onnx_logits_all) - - dgl_vs_tensor_prob = np.abs(dgl_prob_all - tensor_prob_all) - tensor_vs_onnx_prob = np.abs(tensor_prob_all - onnx_prob_all) - - print(f"\n== Real Data Test: {dset_name} ==") - print(f"Epoch : {epoch}") - print(f"Single-event graphs tested : {n_tested}") - print(f"DGL output shape : {dgl_logits_all.shape}") - print(f"Tensor output shape : {tensor_logits_all.shape}") - print(f"ONNX output shape : {onnx_logits_all.shape}") - - print("\nLogit comparisons") - print(f"max abs diff DGL->Tensor : {dgl_vs_tensor.max():.8g}") - print(f"mean abs diff DGL->Tensor : {dgl_vs_tensor.mean():.8g}") - print(f"max abs diff Tensor->ONNX : {tensor_vs_onnx.max():.8g}") - print(f"mean abs diff Tensor->ONNX : {tensor_vs_onnx.mean():.8g}") - - print("\nScore comparisons") - print(f"max abs diff DGL->Tensor : {dgl_vs_tensor_prob.max():.8g}") - print(f"mean abs diff DGL->Tensor : {dgl_vs_tensor_prob.mean():.8g}") - print(f"max abs diff Tensor->ONNX : {tensor_vs_onnx_prob.max():.8g}") - print(f"mean abs diff Tensor->ONNX : {tensor_vs_onnx_prob.mean():.8g}") - - print("\nPer-event max logit-diff summaries") - print(f"DGL->Tensor max over events : {np.max(dgl_tensor_max_diffs):.8g}") - print(f"DGL->Tensor mean over events : {np.mean(dgl_tensor_max_diffs):.8g}") - print(f"Tensor->ONNX max over events : {np.max(tensor_onnx_max_diffs):.8g}") - print(f"Tensor->ONNX mean over events : {np.mean(tensor_onnx_max_diffs):.8g}") - - save_comparison_plot( - onnx_path=onnx_path, - sample_name=dset_name, - dgl_prob=dgl_prob_all, - tensor_prob=tensor_prob_all, - onnx_prob=onnx_prob_all, - ) - - failed = False - - if dgl_vs_tensor.max() > tol_dgl_tensor: - failed = True - print( - f"\nFAIL: DGL->Tensor max diff {dgl_vs_tensor.max():.8g} " - f"> tolerance {tol_dgl_tensor:.8g}" - ) - - if tensor_vs_onnx.max() > tol_tensor_onnx: - failed = True - print( - f"\nFAIL: Tensor->ONNX max diff {tensor_vs_onnx.max():.8g} " - f"> tolerance {tol_tensor_onnx:.8g}" - ) - - if failed: - raise RuntimeError("Real-data validation failed.") - - print("\nReal-data validation passed") - - -def save_comparison_plot( - onnx_path: str, - sample_name: str, - dgl_prob: np.ndarray, - tensor_prob: np.ndarray, - onnx_prob: np.ndarray, -) -> None: - score_bins = np.linspace(0.0, 1.0, 41) - - residuals_onnx = onnx_prob.reshape(-1) - dgl_prob.reshape(-1) - residuals_tensor = tensor_prob.reshape(-1) - dgl_prob.reshape(-1) - - combined_residuals = np.concatenate([residuals_onnx, residuals_tensor]) - - if np.all(combined_residuals == combined_residuals[0]): - diff_bins = np.linspace(combined_residuals[0] - 1e-8, combined_residuals[0] + 1e-8, 80) - else: - diff_bins = np.histogram_bin_edges(combined_residuals, bins=80) - - fig, (ax_left, ax_right) = plt.subplots(1, 2, figsize=(12, 4)) - - ax_left.hist( - dgl_prob.reshape(-1), - bins=score_bins, - histtype="step", - linewidth=2.0, - label="DGL", - ) - ax_left.hist( - tensor_prob.reshape(-1), - bins=score_bins, - histtype="step", - linewidth=2.0, - label="Tensor", - ) - ax_left.hist( - onnx_prob.reshape(-1), - bins=score_bins, - histtype="step", - linewidth=2.0, - label="ONNX", - ) - ax_left.set_title(f"Score Distributions: {sample_name}") - ax_left.set_xlabel("Score") - ax_left.set_ylabel("Events / bin") - ax_left.legend() - - ax_right.hist( - residuals_onnx, - bins=diff_bins, - histtype="step", - linewidth=1.8, - label="ONNX - DGL", - ) - ax_right.hist( - residuals_tensor, - bins=diff_bins, - histtype="step", - linewidth=1.8, - label="Tensor - DGL", - ) - ax_right.set_title(f"Differences vs DGL: {sample_name}") - ax_right.set_xlabel("Score difference") - ax_right.set_ylabel("Events / bin") - ax_right.set_yscale("log") - ax_right.legend() - - plt.tight_layout() - - plot_path = os.path.splitext(onnx_path)[0] + "_onnx.png" - plt.savefig(plot_path, dpi=200, bbox_inches="tight") - plt.close(fig) - - print(f"Saved comparison plot to {plot_path}") - - -# ------------------------- -# CLI -# ------------------------- - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description="Export root_gnn_base GCN models to ONNX.") - - parser.add_argument("--config", required=True, help="YAML training config.") - parser.add_argument("--name", required=True, help='Output ONNX filename, e.g. "ttH.onnx".') - - parser.add_argument( - "--epoch", - type=int, - default=None, - help="Checkpoint epoch to export. Default: best Test_AUC epoch.", - ) - parser.add_argument( - "--no-test", - action="store_true", - help="Skip real-data validation and plotting.", - ) - parser.add_argument( - "--max-test-events", - type=int, - default=1000, - help="Number of single-event graphs to validate. Use 0 for all events. Default: 1000.", - ) - parser.add_argument( - "--tol-dgl-tensor", - type=float, - default=1e-8, - help="Max allowed logit difference for DGL vs tensor model.", - ) - parser.add_argument( - "--tol-tensor-onnx", - type=float, - default=5e-5, - help="Max allowed logit difference for tensor model vs ONNX.", - ) - - return parser.parse_args() - - -def main() -> None: - args = parse_args() - conf = load_config(args.config) - - tensor_model = build_tensor_model(conf) - epoch, checkpoint = load_checkpoint(conf, args.epoch) - - tensor_model.load_state_dict(checkpoint["model_state_dict"]) - tensor_model.eval().cpu() - - if args.no_test: - model_args = conf["Model"].get("args", {}) - - node_in = int(model_args.get("in_size", 7)) - edge_in = int(model_args.get("edge_in_size", 3)) - global_in = infer_global_size(model_args) - - node_features = torch.randn(4, node_in, dtype=torch.float32) - src = torch.tensor([0, 0, 1, 1, 2, 2, 3, 3], dtype=torch.long) - dst = torch.tensor([1, 2, 0, 3, 0, 3, 1, 2], dtype=torch.long) - edge_index = torch.stack([src, dst], dim=0) - edge_features = torch.randn(edge_index.shape[1], edge_in, dtype=torch.float32) - global_features = torch.ones(1, global_in, dtype=torch.float32) - node_batch = torch.zeros(node_features.shape[0], dtype=torch.long) - - export_inputs = ( - node_features, - edge_features, - global_features, - edge_index, - node_batch, - ) - else: - dset_name, first_batch, export_inputs = first_real_event_inputs(conf) - print(f"Using one real event from {dset_name} as the ONNX export example input.") - - with torch.no_grad(): - _ = tensor_model(*export_inputs) - - export_onnx(tensor_model, export_inputs, args.name) - - print(f"Exported epoch {epoch} to {args.name}") - - if not args.no_test: - run_real_data_test( - conf=conf, - tensor_model=tensor_model, - onnx_path=args.name, - epoch=epoch, - checkpoint=checkpoint, - max_events=args.max_test_events, - tol_dgl_tensor=args.tol_dgl_tensor, - tol_tensor_onnx=args.tol_tensor_onnx, - ) - - -if __name__ == "__main__": - main() diff --git a/legacy/root_gnn_dgl/scripts/find_free_port.py b/legacy/root_gnn_dgl/scripts/find_free_port.py deleted file mode 100644 index 0f3050ccc310c538ae69221a83186a1b2933f2bf..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/scripts/find_free_port.py +++ /dev/null @@ -1,12 +0,0 @@ -# find_free_port.py -def find_free_port(): - import socket - from contextlib import closing - - with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: - s.bind(('', 0)) - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - return str(s.getsockname()[1]) - -if __name__ == "__main__": - print(find_free_port()) diff --git a/legacy/root_gnn_dgl/scripts/inference.py b/legacy/root_gnn_dgl/scripts/inference.py deleted file mode 100644 index 0508835ca0265cf66c1c38e288c8f60bc2aed10b..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/scripts/inference.py +++ /dev/null @@ -1,388 +0,0 @@ -import sys -import os -import argparse -import yaml -import gc -from array import array -import fnmatch -import re -from pathlib import Path - -REPO_ROOT = Path(__file__).resolve().parents[1] -sys.path.insert(0, str(REPO_ROOT)) - -import torch -import dgl -from dgl.data import DGLDataset -from dgl.dataloading import GraphDataLoader -from torch.utils.data import SubsetRandomSampler, SequentialSampler - -class CustomPreBatchedDataset(DGLDataset): - def __init__(self, start_dataset, batch_size, chunkno=0, chunks=1, mask_fn=None, drop_last=False, shuffle=False, **kwargs): - self.start_dataset = start_dataset - self.batch_size = batch_size - self.mask_fn = mask_fn or (lambda x: torch.ones(len(x), dtype=torch.bool)) - self.drop_last = drop_last - self.shuffle = shuffle - self.chunkno = chunkno - self.chunks = chunks - super().__init__(name=start_dataset.name + '_custom_prebatched', save_dir=start_dataset.save_dir) - - def process(self): - mask = self.mask_fn(self.start_dataset) - indices = torch.arange(len(self.start_dataset))[mask] - print(f"Number of elements after masking: {len(indices)}") # Debugging print - - # --- CHUNK SPLITTING --- - total = len(indices) - if self.chunks == 1: - chunk_indices = indices - print(f"Chunks=1, using all {total} indices.") - else: - chunk_size = (total + self.chunks - 1) // self.chunks - start = self.chunkno * chunk_size - end = min((self.chunkno + 1) * chunk_size, total) - chunk_indices = indices[start:end] - print(f"Working on chunk {self.chunkno}/{self.chunks}: indices {start}:{end} (total {len(chunk_indices)})") - - if self.shuffle: - sampler = SubsetRandomSampler(chunk_indices) - else: - sampler = SequentialSampler(chunk_indices) - - self.dataloader = GraphDataLoader( - self.start_dataset, - sampler=sampler, - batch_size=self.batch_size, - drop_last=self.drop_last - ) - - def __getitem__(self, idx): - if isinstance(idx, int): - idx = [idx] - sampler = SequentialSampler(idx) - dloader = GraphDataLoader(self.start_dataset, sampler=sampler, batch_size=self.batch_size, drop_last=False) - return next(iter(dloader)) - - def __len__(self): - mask = self.mask_fn(self.start_dataset) - indices = torch.arange(len(self.start_dataset))[mask] - total = len(indices) - if self.chunks == 1: - return total - chunk_size = (total + self.chunks - 1) // self.chunks - start = self.chunkno * chunk_size - end = min((self.chunkno + 1) * chunk_size, total) - return end - start - -def include_config(conf): - if 'include' in conf: - for i in conf['include']: - with open(i) as f: - conf.update(yaml.load(f, Loader=yaml.FullLoader)) - del conf['include'] - -def load_config(config_file): - with open(config_file) as f: - conf = yaml.load(f, Loader=yaml.FullLoader) - include_config(conf) - return conf - -def _branch_names(tree): - return {branch.GetName() for branch in tree.GetListOfBranches()} - -def _compare(value, cut, op): - if op == '>': - return value > cut - if op == '>=': - return value >= cut - if op == '<': - return value < cut - if op == '<=': - return value <= cut - if op == '==': - return value == cut - if op == '!=': - return value != cut - raise ValueError(f'Unknown selection operator: {op}') - -def compute_selection_pass(tree, selections): - if not selections: - return 1 - - names = _branch_names(tree) - - for selection in selections: - if isinstance(selection, str): - tokens = set(re.findall(r'\b[A-Za-z_]\w*\b', selection)) - needed = tokens & names - - context = {} - for name in needed: - context[name] = getattr(tree, name) - - try: - passed = bool(eval(selection, {"__builtins__": {}}, context)) - except NameError as exc: - raise NameError( - f"Selection expression references an unknown name: {selection}" - ) from exc - - if not passed: - return 0 - else: - if not isinstance(selection, (tuple, list)) or len(selection) != 3: - raise ValueError( - f"Selection must be a string or a 3-item sequence " - f"(var, cut, op), got: {selection}" - ) - - var, cut, op = selection - - if var not in names: - raise KeyError(f"Selection references missing branch: {var}") - - value = getattr(tree, var) - - if not _compare(value, cut, op): - return 0 - - return 1 - -def select_dataset_config(configs, target_path): - target_name = os.path.basename(target_path) - for config in configs: - dset_config = config['Datasets'][list(config['Datasets'].keys())[0]] - file_names = dset_config['args'].get('file_names', '') - patterns = file_names if isinstance(file_names, list) else [file_names] - for pattern in patterns: - if fnmatch.fnmatch(target_name, os.path.basename(pattern)): - return dset_config - return configs[0]['Datasets'][list(configs[0]['Datasets'].keys())[0]] - -def main(): - - parser = argparse.ArgumentParser() - add_arg = parser.add_argument - add_arg('--config', type=str, nargs='+', required=True, help="List of config files") - add_arg('--target', type=str, required=True) - add_arg('--destination', type=str, default='') - add_arg('--chunkno', type=int, default=0) - add_arg('--chunks', type=int, default=1) - add_arg('--write', action='store_true') - add_arg('--ckpt', type=int, default=-1) - add_arg('--var', type=str, default='Test_AUC') - add_arg('--mode', type=str, default='max') - add_arg('--clobber', action='store_true') - add_arg('--tree', type=str, default='') - add_arg('--branch_name', type=str, nargs='+', required=True, help="List of branch names corresponding to configs") - args = parser.parse_args() - - if(len(args.config) != len(args.branch_name)): - print(f"configs and branch names do not match") - return - - config = load_config(args.config[0]) - - # --- OUTPUT DESTINATION LOGIC --- - if args.destination == '': - base_dest = os.path.join(config['Training_Directory'], 'inference/', os.path.split(args.target)[1]) - else: - base_dest = args.destination - - base_dest = base_dest.replace('.root', '').replace('.npz', '') - if args.chunks > 1: - chunked_dest = f"{base_dest}_chunk{args.chunkno}" - else: - chunked_dest = base_dest - chunked_dest += '.root' if args.write else '.npz' - args.destination = chunked_dest - - # --- FILE EXISTENCE CHECK --- - if os.path.exists(args.destination): - print(f'File {args.destination} already exists.') - if args.clobber: - print('Clobbering.') - else: - print('Exiting.') - return - else: - print(f'Writing to {args.destination}') - - import time - start = time.time() - import ROOT - import torch - from array import array - import numpy as np - from root_gnn_base import batched_dataset as dataset - from root_gnn_base import utils - end = time.time() - print('Imports finished in {:.2f} seconds'.format(end - start)) - - start = time.time() - dset_config = select_dataset_config([load_config(c) for c in args.config], args.target) - if dset_config['class'] == 'LazyDataset': - dset_config['class'] = 'EdgeDataset' - elif dset_config['class'] == 'LazyMultiLabelDataset': - dset_config['class'] = 'MultiLabelDataset' - elif dset_config['class'] == 'PhotonIDDataset': - dset_config['class'] = 'UnlazyPhotonIDDataset' - elif dset_config['class'] == 'kNNDataset': - dset_config['class'] = 'UnlazyKNNDataset' - dset_config['args']['raw_dir'] = os.path.split(args.target)[0] - dset_config['args']['file_names'] = os.path.split(args.target)[1] - dset_config['args']['save'] = False - dset_config['args']['chunks'] = args.chunks - dset_config['args']['process_chunks'] = [args.chunkno,] - dset_config['args']['selections'] = [] - - dset_config['args']['save_dir'] = os.path.dirname(args.destination) - - if args.tree != '': - dset_config['args']['tree_name'] = args.tree - - device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') - - dstart = time.time() - dset = utils.buildFromConfig(dset_config) - dend = time.time() - print('Dataset finished in {:.2f} seconds'.format(dend - dstart)) - - print(dset) - - batch_size = config['Training']['batch_size'] - lstart = time.time() - loader = CustomPreBatchedDataset( - dset, - batch_size, - chunkno=args.chunkno, - chunks=args.chunks - ) - loader.process() - lend = time.time() - print('Loader finished in {:.2f} seconds'.format(lend - lstart)) - sample_graph, _, _, global_sample = loader[0] - global_sample = [] - - print('dset length =', len(dset)) - print('loader length =', len(loader)) - - all_scores = {} - all_labels = {} - all_tracking = {} - with torch.no_grad(): - for config_file, branch in zip(args.config, args.branch_name): - config = load_config(config_file) - model = utils.buildFromConfig(config['Model'], {'sample_graph' : sample_graph, 'sample_global': global_sample}).to(device) - - if args.ckpt < 0: - ep, checkpoint = utils.get_best_epoch(config, var=args.var, mode='max', device=device) - else: - ep, checkpoint = utils.get_specific_epoch(config, args.ckpt, device=device) - # Remove distributed/compiled prefixes if present - mds_copy = {} - for key in checkpoint['model_state_dict'].keys(): - newkey = key.replace('module.', '') - newkey = newkey.replace('_orig_mod.', '') - mds_copy[newkey] = checkpoint['model_state_dict'][key] - model.load_state_dict(mds_copy) - model.eval() - - end = time.time() - print('Model and dataset finished in {:.2f} seconds'.format(end - start)) - print('Starting inference') - start = time.time() - - finish_fn = torch.nn.Sigmoid() - if 'Loss' in config: - finish_fn = utils.buildFromConfig(config['Loss']['finish']) - - scores = [] - labels = [] - tracking_info = [] - ibatch = 0 - - for batch, label, track, globals in loader.dataloader: - batch = batch.to(device) - pred = model(batch, globals.to(device)) - ibatch += 1 - if (finish_fn.__class__.__name__ == "ContrastiveClusterFinish"): - scores.append(pred.detach().cpu().numpy()) - else: - scores.append(finish_fn(pred).detach().cpu().numpy()) - labels.append(label.detach().cpu().numpy()) - tracking_info.append(track.detach().cpu().numpy()) - - score_size = scores[0].shape[1] if len(scores[0].shape) > 1 else 1 - scores = np.concatenate(scores) - labels = np.concatenate(labels) - tracking_info = np.concatenate(tracking_info) - end = time.time() - - print('Inference finished in {:.2f} seconds'.format(end - start)) - all_scores[branch] = scores - all_labels[branch] = labels - all_tracking[branch] = tracking_info - - if args.write: - from ROOT import std - write_config = select_dataset_config([load_config(c) for c in args.config], args.target) - # Open the original ROOT file - infile = ROOT.TFile.Open(args.target) - tree = infile.Get(write_config['args']['tree_name']) - selections = write_config.get('selections', []) - - # Create the destination directory if it doesn't exist - os.makedirs(os.path.split(args.destination)[0], exist_ok=True) - - # Create a new ROOT file to write the modified tree - outfile = ROOT.TFile.Open(args.destination, 'RECREATE') - - # Clone the original tree structure - outtree = tree.CloneTree(0) - - # Create branches for all scores - branch_vectors = {} - for branch, scores in all_scores.items(): - if isinstance(scores[0], (list, tuple, np.ndarray)) and len(scores[0]) > 1: - # Create a new branch for vectors - branch_vectors[branch] = std.vector('float')() - outtree.Branch(branch, branch_vectors[branch]) - else: - # Create a new branch for single floats - branch_vectors[branch] = array('f', [0]) - outtree.Branch(branch, branch_vectors[branch], f'{branch}/F') - - selection_pass = array('i', [1]) - outtree.Branch('selection_pass', selection_pass, 'selection_pass/I') - - # Fill the tree - for i in range(tree.GetEntries()): - tree.GetEntry(i) - selection_pass[0] = compute_selection_pass(tree, selections) - - for branch, scores in all_scores.items(): - branch_data = branch_vectors[branch] - if isinstance(branch_data, array): # Check if it's a single float array - branch_data[0] = float(scores[i]) - else: # Assume it's a std::vector - branch_data.clear() - for value in scores[i]: - branch_data.push_back(float(value)) - - outtree.Fill() - - # Write the modified tree to the new file - print(f'Writing to file {args.destination}') - print(f'Input entries: {tree.GetEntries()}, Output entries: {outtree.GetEntries()}') - print(f'Wrote scores to {args.branch_name} and selection_pass') - outtree.Write() - outfile.Close() - infile.Close() - else: - os.makedirs(os.path.split(args.destination)[0], exist_ok=True) - np.savez(args.destination, scores=all_scores, labels=all_labels, tracking_info=all_tracking) - -if __name__ == '__main__': - main() diff --git a/legacy/root_gnn_dgl/scripts/plot_config_distributions.py b/legacy/root_gnn_dgl/scripts/plot_config_distributions.py deleted file mode 100644 index 72cec8039651a0f35004f3786f324816ba146181..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/scripts/plot_config_distributions.py +++ /dev/null @@ -1,304 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import glob -import math -import os -import re -from pathlib import Path - -import awkward as ak -import matplotlib -matplotlib.use("Agg") -import matplotlib.pyplot as plt -from matplotlib.backends.backend_pdf import PdfPages -import numpy as np -import uproot -import yaml - - -OPERATORS = { - ">": lambda values, cut: values > cut, - ">=": lambda values, cut: values >= cut, - "<": lambda values, cut: values < cut, - "<=": lambda values, cut: values <= cut, - "==": lambda values, cut: values == cut, - "!=": lambda values, cut: values != cut, -} - - -def load_config(path): - with open(path, "r", encoding="utf-8") as handle: - return yaml.safe_load(handle) - - -def selection_branches(selection): - if isinstance(selection, str): - tokens = re.findall(r"\b[A-Za-z_][A-Za-z0-9_]*\b", selection) - keywords = {"and", "or", "not", "True", "False"} - return [token for token in tokens if token not in keywords] - if isinstance(selection, (list, tuple)) and len(selection) > 0: - return [selection[0]] - return [] - - -def feature_branches(node_branch_names): - branches = [] - for feature in node_branch_names: - if not isinstance(feature, list): - continue - for branch in feature: - if isinstance(branch, str) and branch != "CALC_E": - branches.append(branch) - return branches - - -def branches_for_dataset(dataset_config): - args = dataset_config["args"] - branches = feature_branches(args.get("node_branch_names", [])) - for selection in dataset_config.get("selections", []): - branches.extend(selection_branches(selection)) - return sorted(set(branches)) - - -def resolve_files(args): - raw_dir = args["raw_dir"] - file_names = args["file_names"] - files = [] - if isinstance(file_names, str): - files.extend(glob.glob(os.path.join(raw_dir, file_names))) - else: - for file_name in file_names: - files.extend(glob.glob(os.path.join(raw_dir, file_name))) - return sorted(files) - - -def load_arrays(dataset_config, max_events=None): - args = dataset_config["args"] - tree_name = args.get("tree_name", "nominal_Loose") - branches = branches_for_dataset(dataset_config) - arrays = [] - events_read = 0 - - for file_name in resolve_files(args): - with uproot.open(file_name) as root_file: - tree = root_file[tree_name] - entry_stop = None - if max_events is not None: - remaining = max_events - events_read - if remaining <= 0: - break - entry_stop = remaining - array = tree.arrays(branches, library="ak", entry_stop=entry_stop) - arrays.append(array) - if branches: - events_read += len(array[branches[0]]) - if max_events is not None and events_read >= max_events: - break - - if not arrays: - pattern = os.path.join(args["raw_dir"], str(args["file_names"])) - raise FileNotFoundError(f"No files found for pattern {pattern}") - return ak.concatenate(arrays, axis=0) - - -def selection_mask(data, selections): - first_field = data.fields[0] if len(data.fields) > 0 else None - if first_field is None: - return None - - mask = np.ones(len(data[first_field]), dtype=bool) - for selection in selections: - if isinstance(selection, str): - current_mask = eval(selection, {"__builtins__": {}}, data) - else: - branch, cut, op = selection - if op not in OPERATORS: - raise ValueError(f"Unknown selection operator: {op}") - current_mask = OPERATORS[op](data[branch], cut) - mask = mask & ak.to_numpy(current_mask) - return mask - - -def ensure_node_array(value, reference): - if isinstance(value, (int, float, complex)): - return ak.full_like(reference, value) - return value - - -def branch_array(data, branch, node_type, reference): - value = ensure_node_array(branch, reference) - if not isinstance(branch, str): - return value - value = data[branch] - if node_type == "single": - return ak.singletons(value) - return value - - -def clean_label(value): - return str(value).replace("/", "_") - - -def per_type_feature_label(feature_spec, type_index): - return clean_label(feature_spec[type_index]) - - -def flatten_values(values): - flat_values = np.asarray(ak.to_numpy(ak.ravel(values)), dtype=float) - return flat_values[np.isfinite(flat_values)] - - -def build_feature_values(data, dataset_config): - args = dataset_config["args"] - node_branch_names = args["node_branch_names"] - node_branch_types = args["node_branch_types"] - node_feature_scales = [float(scale) for scale in args["node_feature_scales"]] - n_types = len(node_branch_names[0]) - - references = [] - for type_index in range(n_types): - branch = node_branch_names[0][type_index] - node_type = node_branch_types[type_index] - if isinstance(branch, str): - reference = data[branch] - if node_type == "single": - reference = ak.singletons(reference) - else: - raise ValueError("The first node feature must use real branches to define node counts.") - references.append(reference) - - features = {} - pt_parts = [] - eta_parts = [] - - for type_index in range(n_types): - pt_parts.append(branch_array(data, node_branch_names[0][type_index], node_branch_types[type_index], references[type_index])) - eta_parts.append(branch_array(data, node_branch_names[1][type_index], node_branch_types[type_index], references[type_index])) - - for feature_index, feature_spec in enumerate(node_branch_names): - if not isinstance(feature_spec, list): - continue - - per_type_parts = [] - for type_index in range(n_types): - branch = feature_spec[type_index] - if not isinstance(branch, str) or branch == "CALC_E": - per_type_parts.append(None) - continue - - reference = references[type_index] - node_type = node_branch_types[type_index] - per_type_parts.append(branch_array(data, branch, node_type, reference)) - - for type_index, part in enumerate(per_type_parts): - if part is None: - continue - scaled_part = part * node_feature_scales[feature_index] - scaled_pt = pt_parts[type_index] * node_feature_scales[0] - scaled_part = scaled_part[scaled_pt != 0] - features[per_type_feature_label(feature_spec, type_index)] = flatten_values(scaled_part) - - return features - - -def common_bins(datasets, feature_name, bins): - values = np.concatenate([features[feature_name] for features in datasets.values() if len(features[feature_name]) > 0]) - if len(values) == 0: - return np.linspace(0, 1, bins + 1) - - unique_values = np.unique(values) - if len(unique_values) <= 20 and np.allclose(unique_values, np.round(unique_values)): - low = math.floor(values.min()) - high = math.ceil(values.max()) - return np.arange(low - 0.5, high + 1.5, 1) - - low, high = np.percentile(values, [0.5, 99.5]) - if not np.isfinite(low) or not np.isfinite(high) or low == high: - low, high = values.min(), values.max() - if low == high: - low -= 0.5 - high += 0.5 - return np.linspace(low, high, bins + 1) - - -def plot_feature(feature_name, datasets, bins): - fig, ax = plt.subplots(figsize=(8, 6)) - hist_bins = common_bins(datasets, feature_name, bins) - - for dataset_name, features in datasets.items(): - values = features[feature_name] - if len(values) == 0: - continue - ax.hist( - values, - bins=hist_bins, - histtype="step", - density=True, - linewidth=1.8, - label=f"{dataset_name} (n={len(values)})", - ) - - ax.set_xlabel(feature_name) - ax.set_ylabel("Normalized entries") - ax.legend(frameon=False) - ax.grid(alpha=0.25) - fig.tight_layout() - return fig - - -def safe_filename(name): - return re.sub(r"[^A-Za-z0-9_.-]+", "_", name).strip("_") - - -def main(): - parser = argparse.ArgumentParser( - description="Plot model-input node feature distributions for every dataset in a config." - ) - parser.add_argument("--config", required=True, help="YAML config containing Datasets.") - parser.add_argument( - "--output-dir", - default=None, - help="Directory for optional PNG outputs. Defaults to plots/_distributions.", - ) - parser.add_argument( - "--output-pdf", - default=None, - help="Path for the multi-page PDF. Defaults to plots/_distributions.pdf.", - ) - parser.add_argument("--write-pngs", action="store_true", help="Also write one PNG per plot.") - parser.add_argument("--bins", type=int, default=80, help="Number of bins for continuous features.") - parser.add_argument("--max-events", type=int, default=None, help="Optional maximum events per dataset.") - args = parser.parse_args() - - config = load_config(args.config) - output_dir = Path(args.output_dir) if args.output_dir else Path("plots") / f"{Path(args.config).stem}_distributions" - output_pdf = Path(args.output_pdf) if args.output_pdf else Path("plots") / f"{Path(args.config).stem}_distributions.pdf" - output_pdf.parent.mkdir(parents=True, exist_ok=True) - if args.write_pngs: - output_dir.mkdir(parents=True, exist_ok=True) - - dataset_features = {} - for dataset_name, dataset_config in config["Datasets"].items(): - print(f"Loading {dataset_name}", flush=True) - data = load_arrays(dataset_config, max_events=args.max_events) - mask = selection_mask(data, dataset_config.get("selections", [])) - if mask is not None: - data = data[mask] - dataset_features[dataset_name] = build_feature_values(data, dataset_config) - - feature_names = list(next(iter(dataset_features.values())).keys()) - with PdfPages(output_pdf) as pdf: - for feature_name in feature_names: - fig = plot_feature(feature_name, dataset_features, args.bins) - pdf.savefig(fig) - if args.write_pngs: - output_path = output_dir / f"{safe_filename(feature_name)}.png" - fig.savefig(output_path, dpi=160) - print(f"Wrote {output_path}", flush=True) - plt.close(fig) - print(f"Wrote {output_pdf}", flush=True) - - -if __name__ == "__main__": - main() diff --git a/legacy/root_gnn_dgl/scripts/prep_data.py b/legacy/root_gnn_dgl/scripts/prep_data.py deleted file mode 100644 index 80e6bfa5a80c4ccb79cb76d4b360836d2468f707..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/scripts/prep_data.py +++ /dev/null @@ -1,111 +0,0 @@ -import sys -import os -import glob -from pathlib import Path - -REPO_ROOT = Path(__file__).resolve().parents[1] -sys.path.insert(0, str(REPO_ROOT)) - -import root_gnn_base.utils as utils -from root_gnn_base.dataset import compute_cutflow, print_cutflow -import uproot -import awkward as ak -import argparse -from root_gnn_base.batched_dataset import PreBatchedDataset -from root_gnn_base.batched_dataset import LazyPreBatchedDataset - - -def print_dataset_cutflow(dset_config, dataset_name): - args = dset_config["args"] - raw_dir = args["raw_dir"] - file_names = args["file_names"] - tree_name = args.get("tree_name", "nominal_Loose") - selections = dset_config.get("selections", []) - - # The old cutflow implementation concatenates every branch from every - # input file. For the normal Delphes configs there are no selections, so - # doing that work only creates a large, unnecessary memory spike. - if not selections: - print(f"No selections configured for {dataset_name}; skipping cutflow read.") - return - - files = [] - if isinstance(file_names, str): - files = glob.glob(os.path.join(raw_dir, file_names)) - else: - for file_name in file_names: - files.extend(glob.glob(os.path.join(raw_dir, file_name))) - - branches = [] - for feat in args.get("node_branch_names", []): - if isinstance(feat, list): - for branch in feat: - if isinstance(branch, str) and branch != "CALC_E": - branches.append(branch) - for feat in args.get("global_features", []): - if isinstance(feat, str): - branches.append(feat) - for feat in args.get("tracking_info", []): - if isinstance(feat, str): - branches.append(feat) - from root_gnn_base.dataset import selection_branches - for selection in selections: - branches.extend(selection_branches(selection)) - branches = sorted(set(branches)) - - arrays = [] - for file in files: - with uproot.open(file) as f: - arrays.append(f[tree_name].arrays(branches, library="ak")) - if not arrays: - print(f"No files found for dataset {dataset_name} in {os.path.join(raw_dir, str(file_names))}") - return - - data = ak.concatenate(arrays, axis=0) - cutflow = compute_cutflow(data, selections) - print_cutflow(cutflow, title=f"Cutflow for {dataset_name}") - -def main(): - parser = argparse.ArgumentParser() - add_arg = parser.add_argument - add_arg('--config', type=str, required=True) - add_arg('--dataset', type=str, required=True) - add_arg('--chunk', type=int, default=0) - add_arg('--shuffle_mode', action='store_true', help='Shuffle the dataset before training.') - add_arg('--drop_last', action='store_false', help='Set drop_last to False if the flag is provided. Defaults to True.') - add_arg('--buffer_size', type=int, default=None, - help='Override the LazyDataset graph-chunk buffer size during shuffling.') - add_arg('--shuffle_chunks', type=int, default=None, - help='Override the number of prebatched shuffle partitions.') - args = parser.parse_args() - - config = utils.load_config(args.config) - dset_config = config['Datasets'][args.dataset] - if args.buffer_size is not None: - dset_config['args']['buffer_size'] = args.buffer_size - if args.shuffle_chunks is not None: - dset_config['shuffle_chunks'] = args.shuffle_chunks - print_dataset_cutflow(dset_config, args.dataset) - batch_size = config['Training']['batch_size'] - if not args.shuffle_mode: - dset = utils.buildFromConfig(dset_config, {'process_chunks': [args.chunk,]}) - else: - dset = utils.buildFromConfig(dset_config) - if 'batch_size' in dset_config: - batch_size = dset_config['batch_size'] - - shuffle_chunks = dset_config.get('shuffle_chunks', 10) - shuffle_seed = dset_config.get('shuffle_seed', 12345) - padding_mode = dset_config.get('padding_mode', 'STEPS') - fold_conf = dset_config["folding"] - print(f"shuffle_chunks = {shuffle_chunks}, args.chunk = {args.chunk}, padding_mode = {padding_mode}, shuffle_seed = {shuffle_seed}") - if dset_config["class"] == "LazyMultiLabelDataset": - LazyPreBatchedDataset(start_dataset = dset, batch_size = batch_size, mask_fn = utils.fold_selection(fold_conf, "train"), suffix = utils.fold_selection_name(fold_conf, "train"), chunks = shuffle_chunks, chunkno = args.chunk, padding_mode = padding_mode, drop_last=args.drop_last, hidden_size=config['Model']['args']['hid_size'], shuffle_seed=shuffle_seed ) - LazyPreBatchedDataset(start_dataset = dset, batch_size = batch_size, mask_fn = utils.fold_selection(fold_conf, "test"), suffix = utils.fold_selection_name(fold_conf, 'test'), chunks = shuffle_chunks, chunkno = args.chunk, padding_mode = padding_mode, drop_last=args.drop_last, hidden_size=config['Model']['args']['hid_size'], shuffle_seed=shuffle_seed) - - else: - PreBatchedDataset(dset, batch_size, utils.fold_selection(fold_conf, "train"), suffix = utils.fold_selection_name(fold_conf, "train"), chunks = shuffle_chunks, chunkno = args.chunk, padding_mode = padding_mode, drop_last=args.drop_last,hidden_size=config['Model']['args']['hid_size'], shuffle_seed=shuffle_seed) - PreBatchedDataset(dset, batch_size, utils.fold_selection(fold_conf, "test"), suffix = utils.fold_selection_name(fold_conf, 'test'), chunks = shuffle_chunks, chunkno = args.chunk, padding_mode = padding_mode, drop_last=args.drop_last,hidden_size=config['Model']['args']['hid_size'], shuffle_seed=shuffle_seed ) - -if __name__ == "__main__": - main() diff --git a/legacy/root_gnn_dgl/scripts/selections.py b/legacy/root_gnn_dgl/scripts/selections.py deleted file mode 100644 index 5cf19ca46a8662cf476ebcdeeebd3d8f3c697696..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/scripts/selections.py +++ /dev/null @@ -1,104 +0,0 @@ -import argparse -import glob -import os -import sys -from pathlib import Path - -import awkward as ak -import uproot - -REPO_ROOT = Path(__file__).resolve().parents[1] -sys.path.insert(0, str(REPO_ROOT)) - -from root_gnn_base import utils -from root_gnn_base.dataset import selection_branches, check_selection, print_cutflow, init_cutflow - - -def get_branches(dataset_config): - args = dataset_config["args"] - branches = [] - for feat in args.get("node_branch_names", []): - if isinstance(feat, list): - for branch in feat: - if isinstance(branch, str) and branch != "CALC_E": - branches.append(branch) - for feat in args.get("global_features", []): - if isinstance(feat, str): - branches.append(feat) - for feat in args.get("tracking_info", []): - if isinstance(feat, str): - branches.append(feat) - for selection in dataset_config.get("selections", []): - branches.extend(selection_branches(selection)) - return sorted(set(branches)) - - -def load_arrays(dataset_config): - args = dataset_config["args"] - raw_dir = args["raw_dir"] - file_names = args["file_names"] - tree_name = args.get("tree_name", "nominal_Loose") - - files = [] - if isinstance(file_names, str): - files = glob.glob(os.path.join(raw_dir, file_names)) - else: - for file_name in file_names: - files.extend(glob.glob(os.path.join(raw_dir, file_name))) - - branches = get_branches(dataset_config) - arrays = [] - for file in files: - with uproot.open(file) as f: - arrays.append(f[tree_name].arrays(branches, library="ak")) - if not arrays: - raise FileNotFoundError(f"No files found in {os.path.join(raw_dir, str(file_names))}") - return ak.concatenate(arrays, axis=0), branches - - -def vectorized_cutflow(data, selections): - cutflow = init_cutflow(selections) - first_field = data.fields[0] if len(data.fields) > 0 else None - cutflow["total"] = len(data[first_field]) if first_field is not None else 0 - mask = ak.ones_like(data[first_field], dtype=bool) if first_field is not None else None - - for i, selection in enumerate(selections): - if isinstance(selection, str): - current_mask = eval(selection, {"__builtins__": {}}, data) - else: - current_mask = check_selection(data, selection) - current_mask = ak.to_numpy(current_mask) - if mask is None: - mask = current_mask - else: - mask = mask & current_mask - cutflow["counts"][i] = int(ak.sum(mask)) - return cutflow - - -def main(): - parser = argparse.ArgumentParser(description="Fast selection tester and cutflow printer") - parser.add_argument("--config", required=True, help="Path to YAML config file") - args = parser.parse_args() - - config = utils.load_config(args.config) - for dataset_name, dataset_config in config["Datasets"].items(): - selections = dataset_config.get("selections", []) - print(f"\n== Dataset: {dataset_name} ==") - - data, branches = load_arrays(dataset_config) - - for selection in selections: - try: - _ = eval(selection, {"__builtins__": {}}, data) if isinstance(selection, str) else check_selection({b: data[b] for b in branches}, selection) - print(f"OK: {selection}") - except Exception: - print(f"FAILED: {selection}") - raise - - cutflow = vectorized_cutflow(data, selections) - print_cutflow(cutflow, title=f"Cutflow for {dataset_name}") - - -if __name__ == "__main__": - main() diff --git a/legacy/root_gnn_dgl/scripts/training_script.py b/legacy/root_gnn_dgl/scripts/training_script.py deleted file mode 100644 index a73ffde84c18f5bf1cab81a37753f65beecb4767..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/scripts/training_script.py +++ /dev/null @@ -1,843 +0,0 @@ -import argparse -import time -import datetime -import yaml -import os -from pathlib import Path - -start_time = time.time() - -import dgl -import torch -import torch.nn as nn - -import sys -REPO_ROOT = Path(__file__).resolve().parents[1] -sys.path.insert(0, str(REPO_ROOT)) -import root_gnn_base.batched_dataset as datasets -from root_gnn_base import utils -import root_gnn_base.custom_scheduler as lr_utils -from models import GCN - -import numpy as np -from sklearn.metrics import roc_auc_score -import resource -import gc - -import torch.distributed as dist -import torch.multiprocessing as mp -from torch.utils.data.distributed import DistributedSampler -from torch.nn.parallel import DistributedDataParallel as DDP - -print("import time: {:.4f} s".format(time.time() - start_time)) - -def mem(): - print(f'Current memory usage: {resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024 / 1024} GB') - -def gpu_mem(): - print() - print('GPU Memory Usage:') - sum = 0 - # for obj in gc.get_objects(): - # try: - # if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)): - # print(obj.numel() if len(obj.size()) > 0 else 0, type(obj), obj.size()) - # sum += obj.numel() if len(obj.size()) > 0 else 0 - # except: - # pass - print(f'Current GPU memory usage: {torch.cuda.memory_allocated() / 1024 / 1024 / 1024} GB') - # print(f'Current GPU cache usage: {torch.cuda.memory_cached() / 1024 / 1024 / 1024} GB') - # print(f'Current GPU max memory usage: {torch.cuda.max_memory_allocated() / 1024 / 1024 / 1024} GB') - # print(f'Current GPU max cache usage: {torch.cuda.max_memory_cached() / 1024 / 1024 / 1024} GB') - # print(f'Numel in current tensors: {sum}') - mem() - - -## epoch stores the epoch number I want to evaluate the model at -def evaluate(val_loaders, model, config, device, epoch = -1): - print("Evaluating") - - if (epoch != -1) : - print(f"Evalulating at epoch {epoch}") - last_ep, checkpoint = utils.get_specific_epoch(config, epoch, from_ryan=False) - print(f"Evaluating at epoch = {last_ep}") - else: - starting_epoch = 0 - last_ep, checkpoint = utils.get_last_epoch(config) - - if checkpoint != None: - ep = last_ep - state_dict = checkpoint['model_state_dict'] - new_state_dict = {} - for k, v in state_dict.items(): - new_key = k.replace('module.', '') - new_state_dict[new_key] = v - model.load_state_dict(new_state_dict) - starting_epoch = checkpoint['epoch'] + 1 - print(f"Loaded epoch {checkpoint['epoch']} from checkpoint") - - if 'Loss' not in config: - loss_fcn = nn.BCEWithLogitsLoss(reduction='none') - else: - loss_fcn = utils.buildFromConfig(config['Loss'], {'reduction': 'none'}) - if len(val_loaders) == 0: - return "No validation data" - start = time.time() - scores = [] - labels = [] - weights = [] - before_decoder = [] - after_decoder = [] - tracking = [] - - batch_size = config["Training"]["batch_size"] - - batch_limit = int(np.ceil(1e5 / batch_size)) - - model.eval() - with torch.no_grad(): - for loader in val_loaders: - batch_count = 0 - for batch, label, track, global_feats in loader: - #Don't use compiled model for testing since we can't control the batch size. - #We could before, but it assumes each dataset has the same number of batches... - before_global_decoder, after_global_decoder, after_classify = model.representation(batch.to(device), global_feats.to(device)) - - scores.append(after_classify.to("cpu")) - before_decoder.append(before_global_decoder.to("cpu")) - after_decoder.append(after_global_decoder.to("cpu")) - labels.append(label.to("cpu")) - weights.append(track[:,1].to("cpu")) - tracking.append(track.to("cpu")) - - batch_count += 1 - if batch_count >= batch_limit: - break - - if scores == []: #If validation set is empty. - return - logits = torch.concatenate(scores) - scores = torch.sigmoid(logits) - labels = torch.concatenate(labels) - weights = torch.concatenate(weights) - before_decoder = torch.concatenate(before_decoder) - after_decoder = torch.concatenate(after_decoder) - tracking = torch.concatenate(tracking) - - logits = logits.to("cpu").numpy() - scores = scores.to("cpu").numpy() - labels = labels.to("cpu").numpy() - before_decoder = before_decoder.to("cpu").numpy() - after_decoder = after_decoder.to("cpu").numpy() - tracking = tracking.to("cpu").numpy() - - # Save the NumPy arrays to a .npz file - outfile = f"{config['Training_Directory']}/evaluation_{epoch}.npz" - - np.savez(outfile, logits=logits, scores=scores, labels=labels, before_decoder=before_decoder, after_decoder=after_decoder, tracking=tracking) - - print(f"saved scores to {outfile}") - return - - -def train(train_loaders, test_loaders, model, device, config, args, rank): - nocompile = args.nocompile - restart = args.restart - # define train/val samples, loss function and optimizer - if 'Loss' not in config: - loss_fcn = nn.BCEWithLogitsLoss(reduction='none') - finish_fn = torch.nn.Sigmoid() - else: - loss_fcn = utils.buildFromConfig(config['Loss'], {'reduction':'none'}) - finish_fn = utils.buildFromConfig(config['Loss']['finish']) - - optimizer = torch.optim.Adam(model.parameters(), lr=config['Training']['learning_rate']) - if 'gamma' in config['Training']: - gamma = config['Training']['gamma'] - else: - gamma = 1 - - if 'dynamic_lr' in config['Training']: - factor = config['Training']['dynamic_lr']['factor'] - patience = config['Training']['dynamic_lr']['patience'] - else: - factor = 1 - patience = 1 - - early_termination = utils.EarlyStop() - if 'early_termination' in config['Training']: - early_termination.patience = config['Training']['early_termination']['patience'] - early_termination.threshold = config['Training']['early_termination']['threshold'] - early_termination.mode = config['Training']['early_termination']['mode'] - - scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma = gamma) - #scheduler_reset = custom_scheduler.Dynamic_LR(optimizer, 'max', factor = factor, patience = patience) - custom_scheduler = None - if ('custom_scheduler' in config['Training']): - run_time_args = {} - scheduler_class = config['Training']['custom_scheduler']['class'] - if (scheduler_class == 'Dynamic_LR' or - scheduler_class == 'Dynamic_LR_AND_Partial_Reset' or - scheduler_class == 'Dynamic_LR_AND_Full_Reset'): - - run_time_args={'optimizer': optimizer} - - custom_scheduler = utils.buildFromConfig(config['Training']['custom_scheduler'], run_time_args=run_time_args) - - starting_epoch = 0 - if not restart: - last_ep, checkpoint = utils.get_last_epoch(config) - if checkpoint != None: - ep = starting_epoch - 1 - if nocompile: - new_state_dict = {} - for k, v in checkpoint['model_state_dict'].items(): - new_key = k.replace('module.', '') - new_state_dict[new_key] = v - checkpoint['model_state_dict'] = new_state_dict - if (args.multinode or args.multigpu): - new_state_dict = {} - for k, v in checkpoint['model_state_dict'].items(): - new_key = 'module.' + k - new_state_dict[new_key] = v - checkpoint['model_state_dict'] = new_state_dict - model.load_state_dict(checkpoint['model_state_dict']) - else: - model._orig_mod.load_state_dict(checkpoint['model_state_dict']) - optimizer.load_state_dict(checkpoint['optimizer_state_dict']) - starting_epoch = checkpoint['epoch'] + 1 - if 'early_stop' in checkpoint: - early_termination = utils.EarlyStop.load_from_dict(checkpoint['early_stop']) - print(early_termination.to_str()) - print("EarlyStop state restored successfully.") - if early_termination.should_stop: - print(f"Early Termination at Epoch {epoch}") - return - else: - print("'early_stop' not found in checkpoint. Initializing a new EarlyStop instance.") - early_termination = utils.EarlyStop() - print(f"Loaded epoch {checkpoint['epoch']} from checkpoint") - log = open(config['Training_Directory'] + '/training.log', 'a', buffering=1) - else: - log = open(config['Training_Directory'] + '/training.log', 'w', buffering=1) - - train_cyclers = [] - for loader in train_loaders: - train_cyclers.append(utils.cycler((loader))) - - if args.savecache: - max_batch = [None,] * len(train_loaders) - for dset_i, loader in enumerate(train_loaders): - mbs = 0 - for batch_i, batch in enumerate(loader): - if batch[0].num_nodes() > mbs: - mbs = batch[0].num_nodes() - max_batch[dset_i] = batch[0] - print(f'Max batch size for dataset {dset_i}: {mbs}') - big_batch = dgl.batch(max_batch).to(device) - with torch.no_grad(): - model(big_batch) - - cumulative_times = [0,0,0,0,0] - log.write(f'Training {config["Training_Name"]} {datetime.datetime.now()} \n') - print(f"Starting training for {config['Training']['epochs']} epochs") - - if hasattr(train_loaders[0].dataset, 'padding_mode'): - is_padded = train_loaders[0].dataset.padding_mode != 'NONE' - if (train_loaders[0].dataset.padding_mode == 'NODE'): - is_padded = False - else: - is_padded = False - - lr_utils.print_LR(optimizer) - - # torch.save({ - # 'epoch': 0, - # 'model_state_dict': model.state_dict(), - # 'optimizer_state_dict': optimizer.state_dict(), - # }, os.path.join(config['Training_Directory'], f"model_epoch_{0}.pt")) - # exit() - - - # training loop - # gpu_mem() - for epoch in range(starting_epoch, config['Training']['epochs']): - start = time.time() - run = start - if (args.profile): - if (epoch == 0): - torch.cuda.cudart().cudaProfilerStart() - torch.cuda.nvtx.range_push("Epoch Start") - - if (args.multigpu or args.multinode): - dist.barrier() - - if (epoch == 5): - exit - - # training - model.train() - ibatch = 0 - total_loss = 0 - for batched_graph, labels, _, global_feats in train_loaders[0]: - # # need to fix padded case - # if is_padded: - # tglobals.append(torch.zeros(1, len(global_feats[0]))) - - batch_start = time.time() - logits = torch.tensor([]) - tlabels = torch.tensor([]) - weights = torch.tensor([]) - batch_lengths = [] - for cycler in train_cyclers: - graph, label, track, global_feats = next(cycler) - graph = graph.to(device) - label = label.to(device) - track = track.to(device) - global_feats = global_feats.to(device) - if is_padded: #Padding the globals to match padded graphs. - global_feats = torch.concatenate((global_feats, torch.zeros(1, len(global_feats[0])).to(device))) - load = time.time() - if (args.profile): - torch.cuda.nvtx.range_push("Model Forward") - if (len(logits) == 0): - logits = model(graph, global_feats) - tlabels = label - weights = track[:,1] - else: - logits = torch.concatenate((logits, model(graph, global_feats)), dim=0) - tlabels = torch.concatenate((tlabels, label), dim=0) - weights = torch.concatenate((weights, track[:,1]), dim=0) - batch_lengths.append(logits.shape[0] - 1) - - if (args.profile): - torch.cuda.nvtx.range_pop() # popping model forward - - if is_padded: - keepmask = torch.full_like(logits[:,0], True, dtype=torch.bool) - keepmask[batch_lengths] = False - logits = logits[keepmask] - tlabels = tlabels.to(torch.float) - if logits.shape[1] == 1 and loss_fcn.__class__.__name__ == 'BCEWithLogitsLoss': - logits = logits[:,0] - tlabels = tlabels.to(torch.float) - if loss_fcn.__class__.__name__ == 'CrossEntropyLoss': - tlabels = tlabels.to(torch.long) - # loss = loss_fcn(logits, tlabels.to(device)) # changed logits from logits[:,0] and left labels as int for multiclass. Does this break binary? Yes. - # loss = torch.sum(weights * loss) / torch.sum(weights) - - - if args.abs: - weights = torch.abs(weights) - - loss = loss_fcn(logits, tlabels.to(device)) - # Normalize loss within each label - unique_labels = torch.unique(tlabels) # Get unique labels - normalized_loss = 0.0 - - for label in unique_labels: - # Mask for samples belonging to the current label - label_mask = (tlabels == label) - - # Extract weights and losses for the current label - label_weights = weights[label_mask] - label_losses = loss[label_mask] - - - # Compute normalized loss for the current label - label_loss = torch.sum(label_weights * label_losses) / torch.sum(label_weights) - - # Add to the total normalized loss - normalized_loss += label_loss - loss = normalized_loss / len(unique_labels) - - if (args.profile): - torch.cuda.nvtx.range_push("Model Backward") - optimizer.zero_grad() - loss.backward() - optimizer.step() - total_loss += loss.detach().cpu().item() - - if (args.profile): - torch.cuda.nvtx.range_pop() # pop model backward - ibatch += 1 - cumulative_times[0] += batch_start - run - cumulative_times[1] += load - batch_start - run = time.time() - cumulative_times[2] += run - load - if ibatch % 1000 == 0: - print(f'Batch {ibatch} out of {len(train_loaders[0])}', end='\r') - # gpu_mem() - - if (args.multigpu): - print(f'Rank {rank} Epoch Done.') - elif (args.multinode): - print(f'Rank {args.global_rank} Epoch Done.') - else: - print("Epoch Done.") - # validation - - scores = [] - labels = [] - weights = [] - model.eval() - - if (args.profile): - torch.cuda.nvtx.range_push("Model Evaluation") - - with torch.no_grad(): - for loader in test_loaders: - for batch, label, track, global_feats in loader: - #Don't use compiled model for testing since we can't control the batch size. - #We could before, but it assumes each dataset has the same number of batches... - if is_padded: - global_feats = torch.cat([global_feats, torch.zeros(1, len(global_feats[0]))]) - if nocompile: - batch_scores = model(batch.to(device), global_feats.to(device)) - else: - batch_scores = model._orig_mod(batch.to(device), global_feats.to(device)) - if is_padded: - scores.append(batch_scores[:-1,:]) - else: - scores.append(batch_scores) - labels.append(label) - weights.append(track[:,1]) - eval_end = time.time() - cumulative_times[3] += eval_end - run - - if (args.profile): - torch.cuda.nvtx.range_pop() # pop evaluation - - if scores == []: #If validation set is empty. - continue - logits = torch.concatenate(scores).to(device) - labels = torch.concatenate(labels).to(device) - weights = torch.concatenate(weights).to(device) - - if (args.multigpu or args.multinode): - gathered_logits = [torch.zeros_like(logits) for _ in range(dist.get_world_size())] - gathered_labels = [torch.zeros_like(labels) for _ in range(dist.get_world_size())] - gathered_weights = [torch.zeros_like(weights) for _ in range(dist.get_world_size())] - - if (args.multigpu or args.multinode): - dist.barrier() - if (args.multigpu and rank != 0) or (args.multinode and args.global_rank != 0): - dist.gather(logits, dst=0) - dist.gather(labels, dst=0) - dist.gather(weights, dst=0) - continue - else: - dist.gather(logits, gather_list=gathered_logits) - dist.gather(labels, gather_list=gathered_labels) - dist.gather(weights, gather_list=gathered_weights) - - logits = torch.concatenate(gathered_logits) - labels = torch.concatenate(gathered_labels) - weights = torch.concatenate(gathered_weights) - - wgt_mask = weights > 0 - - if args.abs: - weights = torch.abs(weights) - - print(f"Num batches trained = {ibatch}") - - #Note: This section is a bit ugly. Very conditional. Should maybe config defined behavior? - if (loss_fcn.__class__.__name__ == "ContrastiveClusterLoss"): - scores = logits - preds = scores - accuracy = 0 - test_auc = 0 - acc = 0 - contrastive_cluster_loss = finish_fn(logits) - - elif (loss_fcn.__class__.__name__ == "MultiLabelLoss"): - scores = finish_fn(logits) - preds = torch.round(scores) - multilabel_accuracy = [] - threshold = 0.1 # 10% threshold - - for i in range(len(labels[0])): - # accurate_count = torch.sum(torch.abs(preds[:, i].to("cpu") - labels[:, i].to("cpu")) / labels[:, i].to("cpu") <= threshold) - # multilabel_accruacy.append(accurate_count / len(labels)) - multilabel_accuracy.append(torch.sum(preds[:, i].to("cpu") == labels[:, i].to("cpu")) / len(labels)) - test_auc = 0 - acc = np.mean(multilabel_accuracy) - - elif logits.shape[1] == 1 and loss_fcn.__class__.__name__ == 'BCEWithLogitsLoss': #Proxy for binary classification. - test_auc = 0 - acc = 0 - logits = logits[:,0] - scores = finish_fn(logits) - labels =labels.to(torch.float) - preds = scores > 0.5 - test_auc = roc_auc_score(labels[wgt_mask].to("cpu") == 1, scores[wgt_mask].to("cpu"), sample_weight=weights[wgt_mask].to("cpu")) - acc = torch.sum(preds.to("cpu") == labels.to("cpu")) / len(labels) - - elif logits.shape[1] == 1 and loss_fcn.__class__.__name__ == 'MSELoss': - logits = logits[:,0] - scores = finish_fn(logits) - labels = labels.to(torch.float) - acc = 0 - test_auc = 0 - - else: - preds = torch.argmax(logits, dim=1) - scores = finish_fn(logits) - if labels.dim() == 1: #Multi-class - acc = torch.sum(preds.to("cpu") == labels.to("cpu")) / len(labels) #TODO: Make each class weighted equally? - - labels = labels.to("cpu") - weights = weights.to("cpu") - logits = logits.to("cpu") - wgt_mask = wgt_mask.to("cpu") - - labels_onehot = np.zeros((len(labels), len(scores[0]))) - labels_onehot[np.arange(len(labels)), labels] = 1 - - try: - #test_auc = roc_auc_score(labels[wgt_mask].to("cpu") == 1, scores[wgt_mask].to("cpu"), multi_class='ovr', sample_weight=weights[wgt_mask].to("cpu")) - if (len(scores[0]) != config["Model"]["args"]["out_size"]): - print("ERROR: The out_size and the number of class labels don't match! Please check config.") - test_auc = roc_auc_score(labels_onehot[wgt_mask], scores[wgt_mask].to("cpu"), multi_class='ovr', sample_weight=weights[wgt_mask].to("cpu")) - except ValueError: - test_auc = np.nan - else: #Multi-loss - acc = torch.sum(preds.to("cpu") == labels[:,0].to("cpu")) / len(labels) - try: - test_auc = roc_auc_score(labels[:,0][wgt_mask].to("cpu") == 1, scores[wgt_mask].to("cpu"), multi_class='ovr', sample_weight=weights[wgt_mask].to("cpu")) - except ValueError: - test_auc = np.nan - - - # print(f"logits = {logits[:10]}") - # print(f"preds = {preds[:2]}") - # print(f"labels = {labels[:10]}") - - # print(f"len(Unique logits) = {len(torch.unique(logits))}") - # print(f"Average of labels = {torch.mean(labels)}") - # print(f"unique logits = {torch.unique(logits)[0]:.4f}, {torch.unique(logits)[-1]:.4f}") - - - if (loss_fcn.__class__.__name__ == "MultiLabelLoss"): - multilabel_log_str = "MultiLabel_Accuracy " - for accuracy in multilabel_accuracy: - multilabel_log_str += f" | {accuracy:.4f}" - log.write(multilabel_log_str + '\n') - print(multilabel_log_str, flush=True) - elif (loss_fcn.__class__.__name__ == "ContrastiveClusterLoss"): - contrastive_cluster_log_str = "ContrastiveClusterLoss " - contrastive_cluster_log_str += f"Contrastive Loss: {contrastive_cluster_loss[0]:.4f}, Clustering Loss: {contrastive_cluster_loss[1]:.4f}, Variance Loss: {contrastive_cluster_loss[2]:.4f}" - log.write(contrastive_cluster_log_str + '\n') - print(contrastive_cluster_log_str, flush=True) - - # test_loss = loss_fcn(logits, labels.to(device)) - # test_loss = loss_fcn(logits, labels) - # test_loss = torch.sum(weights * test_loss) / torch.sum(weights) - - test_loss = loss_fcn(logits, labels) - # Normalize loss within each label - unique_labels = torch.unique(labels) # Get unique labels - normalized_loss = 0.0 - - for label in unique_labels: - # Mask for samples belonging to the current label - label_mask = (labels == label) - - # Extract weights and losses for the current label - label_weights = weights[label_mask] - label_losses = test_loss[label_mask] - # Compute normalized loss for the current label - label_loss = torch.sum(label_weights * label_losses) / torch.sum(label_weights) - - # Add to the total normalized loss - normalized_loss += label_loss - test_loss = normalized_loss / len(unique_labels) - - - end = time.time() - log_str = "Epoch {:05d} | LR {:.4e} | Loss {:.4f} | Accuracy {:.4f} | Test_Loss {:.4f} | Test_AUC {:.4f} | Time {:.4f} s".format( - epoch, optimizer.param_groups[0]['lr'], total_loss/ibatch, acc, test_loss, test_auc, end - start - ) - log.write(log_str + '\n') - print(log_str, flush=True) - - state_dict = model.state_dict() - if not nocompile: - state_dict = model._orig_mod.state_dict() - - new_state_dict = {} - for k, v in state_dict.items(): - new_key = k.replace('module.', '') - new_state_dict[new_key] = v - state_dict = new_state_dict - - # print('Testing done') - # gpu_mem() - - if epoch == 2: - # torch.cuda.cudart().cudaProfilerStop() - pass - - torch.save({ - 'epoch': epoch, - 'model_state_dict': state_dict, - 'optimizer_state_dict': optimizer.state_dict(), - 'early_stop': early_termination.to_dict() - }, os.path.join(config['Training_Directory'], f"model_epoch_{epoch}.pt")) - np.savez(os.path.join(config['Training_Directory'], f'model_epoch_{epoch}.npz'), scores=scores.to("cpu"), labels=labels.to("cpu")) - save_end = time.time() - cumulative_times[4] += save_end - eval_end - - early_termination.update(test_loss) - if early_termination.should_stop: - log_str = f"Early Termination at Epoch {epoch}" - log.write(log_str + "\n") - print(log_str) - log_str = early_termination.to_str() - log.write(log_str + "\n") - print(log_str) - break - - if (custom_scheduler): - custom_scheduler.step(model, {'test_auc':test_auc}) - scheduler.step() - - if (args.profile): - torch.cuda.nvtx.range_pop() # pop epoch - - print(f"Load: {cumulative_times[0]:.4f} s") - print(f"Batch: {cumulative_times[1]:.4f} s") - print(f"Train: {cumulative_times[2]:.4f} s") - print(f"Eval: {cumulative_times[3]:.4f} s") - print(f"Save: {cumulative_times[4]:.4f} s") - log.close() - -def find_free_port(): - import socket - from contextlib import closing - - with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: - s.bind(('', 0)) - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - return str(s.getsockname()[1]) - -def init_process_group(world_size, rank, port): - os.environ['MASTER_ADDR'] = 'localhost' - # os.environ['MASTER_PORT'] = find_free_port() - os.environ['MASTER_PORT'] = port - - dist.init_process_group( - backend="nccl", # change to 'nccl' for multiple GPUs (other was gloo) - init_method='env://', - world_size=world_size, - rank=rank, - timeout=datetime.timedelta(seconds=300), - ) - -def main(rank=0, args=None, world_size=1, port=24500, seed=12345): - - #Prevent simultaneous file access - #sleep_time = 120 * rank - #time.sleep(sleep_time) - - #Load config file - config = utils.load_config(args.config) - - if (args.directory): - print(f"New training directory: { config['Training_Directory'] + args.directory}") - config['Training_Directory'] = config['Training_Directory'] + args.directory - - if not os.path.exists(config['Training_Directory']): - os.makedirs(config['Training_Directory'], exist_ok=True) - with open(config['Training_Directory'] + '/config.yaml', 'w') as f: - yaml.dump(config, f) - batch_size = config["Training"]["batch_size"] - - if(args.plot): - rl = utils.read_log(config) - utils.plot_log(rl, config['Training_Directory'] + '/training.png') - print('Log at ' + config['Training_Directory'] + '/training.log') - print('Plotted at ' + config['Training_Directory'] + '/training.png') - exit() - - if (args.multigpu): - print(f"Setting up multigpu") - start_time = time.time() - init_process_group(world_size, rank, port) - print("multigpu setup time: {:.4f} s".format(time.time() - start_time)) - device = torch.device(f'cuda:{rank}') - torch.cuda.device(device) - elif (args.multinode): - device = torch.device(f'cuda:{rank}') - torch.cuda.device(device) - print(f"global rank = {args.global_rank}, local rank = {rank}, device = {device}") - else: - device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - - if (args.cpu): - print(f"Using CPU") - device = "cpu" - - train_loaders = [] - test_loaders = [] - val_loaders = [] - load_start = time.time() - - torch.backends.cuda.matmul.allow_tf32 = True - - ldr_type = datasets.LazyPreBatchedDataset if args.lazy else datasets.PreBatchedDataset - - #Load datasets - if (pargs.statistics): - pargs.statistics = int(pargs.statistics) - print(f"Training Dataset Size: {pargs.statistics}") - num_batches = int(np.ceil(pargs.statistics / batch_size)) - np.random.seed(pargs.seed) - - for dset_conf in config["Datasets"]: - dset = utils.buildFromConfig(config["Datasets"][dset_conf]) - if 'batch_size' in config["Datasets"][dset_conf]: - batch_size = config["Datasets"][dset_conf]['batch_size'] - fold_conf = config["Datasets"][dset_conf]["folding"] - shuffle_chunks = config["Datasets"][dset_conf].get("shuffle_chunks", 10) - padding_mode = config["Datasets"][dset_conf].get("padding_mode", "STEPS") - mask_fn = utils.fold_selection(fold_conf, "train") - if args.preshuffle: - # ldr = ldr_type(start_dataset=dset, batch_size=batch_size, mask_fn=mask_fn, suffix = utils.fold_selection_name(fold_conf, 'train'), chunks = shuffle_chunks, padding_mode = padding_mode, use_ddp = args.multigpu, rank=rank, world_size=world_size) - ldr = ldr_type(start_dataset=dset, batch_size=batch_size, mask_fn=mask_fn, suffix = utils.fold_selection_name(fold_conf, 'train'), chunks = shuffle_chunks, padding_mode = padding_mode, hidden_size = config["Model"]["args"]["hid_size"]) - gsamp, _, _, global_samp = ldr[0] - sampler = None - - if (pargs.statistics): - sampler = np.random.choice(range(len(ldr)), size=num_batches) - - if (args.multigpu): - sampler = DistributedSampler(ldr, num_replicas=world_size, rank=rank, shuffle=False, drop_last=True) - # num_batches = len(ldr) - # sampler = list(sampler) - # if (sampler[0] >= num_batches % world_size): - # sampler.pop() - if (args.multinode): - sampler = DistributedSampler(ldr, num_replicas=world_size, rank=pargs.global_rank, shuffle=False, drop_last=True) - train_loaders.append(torch.utils.data.DataLoader(ldr, batch_size = None, num_workers = 0, sampler = sampler)) - sampler = None - ldr = ldr_type(start_dataset=dset, batch_size=batch_size, mask_fn=mask_fn, suffix = utils.fold_selection_name(fold_conf, 'test'), chunks = shuffle_chunks, padding_mode = padding_mode, hidden_size= config['Model']['args']['hid_size']) - if (args.multigpu): - sampler = DistributedSampler(ldr, num_replicas=world_size, rank=rank, shuffle=False, drop_last=True) - # num_batches = len(ldr) - # sampler = list(sampler) - # if (rank >= num_batches % world_size): - # sampler.pop() - if (args.multinode): - sampler = DistributedSampler(ldr, num_replicas=world_size, rank=pargs.global_rank, shuffle=False, drop_last=True) - - test_loaders.append(torch.utils.data.DataLoader(ldr, batch_size = None, num_workers = 0, sampler=sampler)) - - # if "validation" in fold_conf: - # val_loaders.append(torch.utils.data.DataLoader((ldr_type(start_dataset=dset, batch_size=batch_size, mask_fn=utils.fold_selection(fold_conf, "validation"), suffix = utils.fold_selection_name(fold_conf, 'validation'), chunks = shuffle_chunks, hidden_size=config['Model']['args']['hid_size'], padding_mode = padding_mode, rank=rank, world_size=1)), batch_size = None, num_workers = 0, sampler = sampler)) - # else: - # print("No validation set for dataset ", dset_conf) - else: - train_loaders.append(datasets.GetBatchedLoader(dset, batch_size, utils.fold_selection(fold_conf, "train"))) - gsamp, _, _, global_samp = dset[0] - test_loaders.append(datasets.GetBatchedLoader(dset, batch_size, utils.fold_selection(fold_conf, "test"))) - if "validation" in fold_conf: - val_loaders.append(datasets.GetBatchedLoader(dset, batch_size, utils.fold_selection(fold_conf, "validation"))) - else: - print("No validation set for dataset ", dset_conf) - - load_end = time.time() - print("Load time: {:.4f} s".format(load_end - load_start)) - - model = utils.buildFromConfig(config["Model"], {'sample_graph': gsamp, 'sample_global': global_samp, 'seed': seed}).to(device) - pytorch_total_params = sum(p.numel() for p in model.parameters() if p.requires_grad) - print(f"Number of trainable parameters = {pytorch_total_params}") - if not args.nocompile: - model = torch.compile(model) - if args.multigpu: - print(f"Trying to create DDP model") - start_time = time.time() - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[device]) - print("model creation time: {:.4f} s".format(time.time() - start_time)) - if (args.multinode): - print(f"Trying to create DDP model") - start_time = time.time() - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[device]) - print("model creation time: {:.4f} s".format(time.time() - start_time)) - - # total_params = 0 - # for param_dict in model.parameters(): - # for param in param_dict['params']: - # if param.requires_grad: - # total_params += param.numel() - # print(f"Number of trainable parameters = {total_params}") - - if(type(model) == GCN.Clustering): - print("clustering") - - if args.evaluate != None: - evaluate(test_loaders, model, config, device, args.evaluate) - exit() - - # model training - print("Training...") - gpu_mem() - train(train_loaders, test_loaders, model, device, config, args, rank) - - # test the model - # print("Testing...") - # evaluate(val_loaders, model, config, device) - - # if args.multigpu or args.multinode: - # dist.destroy_process_group() - - # if rank == 0: - # rl = utils.read_log(config) - # utils.plot_log(rl, config['Training_Directory'] + '/training.png') - # print('Log at ' + config['Training_Directory'] + '/training.log') - # print('Plotted at ' + config['Training_Directory'] + '/training.png') - -if __name__ == "__main__": - #Handle CLI arguments - parser = argparse.ArgumentParser() - add_arg = parser.add_argument - add_arg("--config", type=str, help="Config file.", required=True) - add_arg("--restart", action="store_true", help="Restart training from scratch.") - add_arg("--preshuffle", action="store_true", help="Shuffle data before training.") - add_arg("--lazy", action="store_true", help="Lazy loading of data.") - add_arg("--nocompile", action="store_true", help="Disable JIT compilation.") - add_arg("--evaluate", type = int, help="Skip training and go to evaluation.") - add_arg("--plot", action="store_true", help="Plot training logs.") - add_arg("--multigpu", action="store_true", help="Use multiple GPUs.") - add_arg("--multinode", action="store_true", help="Use multiple nodes.") - add_arg("--savecache", action="store_true", help="") - add_arg("--cpu", action="store_true", help="Uses the cpu only") - add_arg("--statistics", type=float, help="Size of training data") - add_arg("--directory", type=str, help="Append to Training Directory") - add_arg("--seed", type=int, default=2, help="Sets random seed") - add_arg("--abs", action="store_true", help="Use abs value of per-event weight") - add_arg("--profile", action="store_true", help="use nsight systems profiler") - - pargs = parser.parse_args() - - if pargs.multigpu: - port = find_free_port() - torch.backends.cudnn.enabled = False - mp.spawn(main, args=(pargs, 4, port), nprocs=4, join=True) - if pargs.multinode: - global_rank = int(os.environ["RANK"]) - local_rank = int(os.environ["LOCAL_RANK"]) - world_size = int(os.environ["WORLD_SIZE"]) - print(f"global_rank = {global_rank}, local_rank = {local_rank}, world_size = {world_size}") - - dist.init_process_group(backend="nccl") - torch.backends.cudnn.enabled = False - - pargs.global_rank = global_rank - - main(rank = local_rank, args=pargs, world_size=world_size) - else: - main(0, pargs) - - diff --git a/legacy/root_gnn_dgl/setup/Dockerfile b/legacy/root_gnn_dgl/setup/Dockerfile deleted file mode 100755 index 854db7c1043c98701a35b99f4fcd5cbfaa04c102..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/setup/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM nvcr.io/nvidia/dgl:25.05-py3 - -WORKDIR /workspace - -LABEL maintainer.name="Joshua Ho" -LABEL maintainer.email="ho22joshua@berkeley.edu" - -ENV LANG=C.UTF-8 - -# System deps (with CA certs for HTTPS downloads) -RUN apt-get update -qq \ - && apt-get install -y --no-install-recommends \ - wget curl ca-certificates lsb-release gnupg software-properties-common \ - vim \ - g++-11 gcc-11 libstdc++-11-dev \ - openmpi-bin openmpi-common libopenmpi-dev \ - && rm -rf /var/lib/apt/lists/* - -# Python packages -RUN pip install --no-cache-dir mpi4py jupyter uproot - -EXPOSE 8888 \ No newline at end of file diff --git a/legacy/root_gnn_dgl/setup/build_image.sh b/legacy/root_gnn_dgl/setup/build_image.sh deleted file mode 100755 index aae10c14f375fb9427b6bc6564375383b3b571d1..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/setup/build_image.sh +++ /dev/null @@ -1,2 +0,0 @@ -podman-hpc build -t joshuaho/pytorch:1.0 --platform linux/amd64 . -podman-hpc migrate joshuaho/pytorch:1.0 diff --git a/legacy/root_gnn_dgl/setup/download_data.sh b/legacy/root_gnn_dgl/setup/download_data.sh deleted file mode 100755 index 389a5ee6c9a658df29ab1bffb1b004477f8f35e7..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/setup/download_data.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash - -# Download the Delphes ROOT samples used by configs/delphes/* with Hugging Face. -# -# Usage: -# bash setup/download_data.sh [output-directory] -# -# The default is $PWD/delphes. Pass a directory explicitly (or set -# DELPHES_DATA_DIR) when a different location is needed. - -set -euo pipefail - -readonly HF_REPOSITORY="HWresearch/Delphes" -readonly HF_REVISION="main" -readonly OUTPUT_DIR="${1:-${DELPHES_DATA_DIR:-${PWD}/delphes}}" - -mkdir -p "${OUTPUT_DIR}" - -if ! command -v hf >/dev/null 2>&1; then - printf 'Error: the Hugging Face CLI (hf) is required.\n' >&2 - printf 'Install it with: python -m pip install -U huggingface_hub\n' >&2 - exit 1 -fi - -readonly STAGING_DIR="$(mktemp -d "${OUTPUT_DIR}/.hf-download.XXXXXX")" -cleanup() { - rm -rf -- "${STAGING_DIR}" -} -trap cleanup EXIT - -# These are the ten unique ROOT samples used by the five binary tasks. -readonly SAMPLE_PATHS=( - "samples/top/fcnc/FCNC_NLO_inc.root" - "samples/higgs/top-associated/thjb/tHjb_NLO_inc.root" - "samples/higgs/vh/zh/ZH_NLO_inc.root" - "samples/higgs/vh/wh/WH_NLO_inc.root" - "samples/top/stop/STOP_LO_inc.root" - "samples/higgs/top-associated/tth/ttH_NLO_inc.root" - "samples/higgs/top-associated/tth/ttH_NLO.root" - "samples/higgs/top-associated/tth/ttH_CPodd.root" - "samples/top/ttv/ttW.root" - "samples/top/multitop/ttt.root" -) - -pending_paths=() -for source_path in "${SAMPLE_PATHS[@]}"; do - filename="${source_path##*/}" - destination="${OUTPUT_DIR}/${filename}" - if [[ -s "${destination}" ]]; then - printf 'Already exists, skipping: %s\n' "${destination}" - else - pending_paths+=("${source_path}") - fi -done - -if ((${#pending_paths[@]} > 0)); then - printf 'Downloading %d ROOT samples with Hugging Face...\n' "${#pending_paths[@]}" - hf download "${HF_REPOSITORY}" "${pending_paths[@]}" \ - --repo-type dataset \ - --revision "${HF_REVISION}" \ - --local-dir "${STAGING_DIR}" \ - --max-workers 8 - - for source_path in "${pending_paths[@]}"; do - filename="${source_path##*/}" - mv -- "${STAGING_DIR}/${source_path}" "${OUTPUT_DIR}/${filename}" - done -fi - -printf '\nDownloaded Delphes samples to %s\n' "${OUTPUT_DIR}" diff --git a/legacy/root_gnn_dgl/setup/environment.yml b/legacy/root_gnn_dgl/setup/environment.yml deleted file mode 100644 index acf2a34ea3b5e72f1e4a4f32ea3b32856362ff75..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/setup/environment.yml +++ /dev/null @@ -1,390 +0,0 @@ -name: pytorch -channels: - - pytorch - - dglteam/label/cu118 - - nvidia - - conda-forge - - defaults -dependencies: - - _libgcc_mutex=0.1 - - _openmp_mutex=4.5 - - _sysroot_linux-64_curr_repodata_hack=3 - - afterimage=1.21 - - anyio=3.7.1 - - appdirs=1.4.4 - - argon2-cffi=21.3.0 - - argon2-cffi-bindings=21.2.0 - - arrow=1.2.3 - - asttokens=2.2.1 - - async-lru=2.0.4 - - atk-1.0=2.38.0 - - attrs=23.1.0 - - awkward-pandas=2023.8.0 - - aws-c-auth=0.7.0 - - aws-c-cal=0.6.0 - - aws-c-common=0.8.23 - - aws-c-compression=0.2.17 - - aws-c-event-stream=0.3.1 - - aws-c-http=0.7.11 - - aws-c-io=0.13.28 - - aws-c-mqtt=0.8.14 - - aws-c-s3=0.3.13 - - aws-c-sdkutils=0.1.11 - - aws-checksums=0.1.16 - - aws-crt-cpp=0.20.3 - - aws-sdk-cpp=1.10.57 - - babel=2.12.1 - - backcall=0.2.0 - - backports=1.0 - - backports.functools_lru_cache=1.6.5 - - beautifulsoup4=4.12.2 - - binutils=2.38 - - binutils_impl_linux-64=2.38 - - binutils_linux-64=2.38.0 - - blas=1.0 - - bleach=6.0.0 - - brotlipy=0.7.0 - - bzip2=1.0.8 - - c-ares=1.19.1 - - c-compiler=1.5.2 - - ca-certificates=2025.4.26 - - cached-property=1.5.2 - - cached_property=1.5.2 - - cairo=1.16.0 - - certifi=2024.8.30 - - cffi=1.15.1 - - cfitsio=4.2.0 - - charset-normalizer=2.0.4 - - comm=0.1.4 - - compilers=1.5.2 - - cryptography=41.0.2 - - cuda-cudart=11.8.89 - - cuda-cupti=11.8.87 - - cuda-libraries=11.8.0 - - cuda-nvrtc=11.8.89 - - cuda-nvtx=11.8.86 - - cuda-runtime=11.8.0 - - cxx-compiler=1.5.2 - - davix=0.8.4 - - debugpy=1.6.8 - - decorator=5.1.1 - - defusedxml=0.7.1 - - dgl=1.1.1.cu118 - - entrypoints=0.4 - - exceptiongroup=1.1.3 - - executing=1.2.0 - - expat=2.5.0 - - ffmpeg=4.3 - - fftw=3.3.10 - - filelock=3.9.0 - - flit-core=3.9.0 - - font-ttf-dejavu-sans-mono=2.37 - - font-ttf-inconsolata=3.000 - - font-ttf-source-code-pro=2.038 - - font-ttf-ubuntu=0.83 - - fontconfig=2.14.2 - - fonts-conda-ecosystem=1 - - fonts-conda-forge=1 - - fortran-compiler=1.5.2 - - fqdn=1.5.1 - - freetype=2.12.1 - - fribidi=1.0.10 - - ftgl=2.4.0 - - gcc=11.2.0 - - gcc_impl_linux-64=11.2.0 - - gcc_linux-64=11.2.0 - - gdk-pixbuf=2.42.8 - - gettext=0.21.1 - - gflags=2.2.2 - - gfortran=11.2.0 - - gfortran_impl_linux-64=11.2.0 - - gfortran_linux-64=11.2.0 - - giflib=5.2.1 - - gl2ps=1.4.2 - - glew=2.1.0 - - glog=0.6.0 - - gmp=6.2.1 - - gmpy2=2.1.2 - - gnutls=3.6.15 - - graphite2=1.3.13 - - graphviz=6.0.2 - - gsl=2.7 - - gsoap=2.8.123 - - gtk2=2.24.33 - - gts=0.7.6 - - gxx=11.2.0 - - gxx_impl_linux-64=11.2.0 - - gxx_linux-64=11.2.0 - - harfbuzz=7.3.0 - - icu=72.1 - - idna=3.4 - - importlib-metadata=6.8.0 - - importlib-resources=6.0.1 - - importlib_metadata=6.8.0 - - importlib_resources=6.0.1 - - intel-openmp=2023.1.0 - - ipykernel=6.25.1 - - ipyparallel=8.6.1 - - ipython=8.12.2 - - isoduration=20.11.0 - - jedi=0.19.0 - - jinja2=3.1.2 - - jpeg=9e - - json5=0.9.14 - - jsonpointer=2.0 - - jsonschema=4.19.0 - - jsonschema-specifications=2023.7.1 - - jsonschema-with-format-nongpl=4.19.0 - - jupyter-lsp=2.2.0 - - jupyter_client=8.3.0 - - jupyter_core=5.3.0 - - jupyter_events=0.7.0 - - jupyter_server=2.7.0 - - jupyter_server_terminals=0.4.4 - - jupyterlab=4.0.5 - - jupyterlab_pygments=0.2.2 - - jupyterlab_server=2.24.0 - - kernel-headers_linux-64=3.10.0 - - keyutils=1.6.1 - - krb5=1.20.1 - - lame=3.100 - - lcms2=2.12 - - ld_impl_linux-64=2.38 - - lerc=3.0 - - libabseil=20230125.3 - - libarrow=12.0.1 - - libblas=3.9.0 - - libbrotlicommon=1.0.9 - - libbrotlidec=1.0.9 - - libbrotlienc=1.0.9 - - libcblas=3.9.0 - - libcrc32c=1.1.2 - - libcublas=11.11.3.6 - - libcufft=10.9.0.58 - - libcufile=1.7.1.12 - - libcurand=10.3.3.129 - - libcurl=8.1.2 - - libcusolver=11.4.1.48 - - libcusparse=11.7.5.86 - - libcxx=15.0.7 - - libcxxabi=15.0.7 - - libdeflate=1.12 - - libedit=3.1.20191231 - - libev=4.33 - - libevent=2.1.12 - - libexpat=2.5.0 - - libffi=3.4.4 - - libgcc-devel_linux-64=11.2.0 - - libgcc-ng=13.1.0 - - libgd=2.3.3 - - libgfortran-ng=11.2.0 - - libgfortran5=11.2.0 - - libglib=2.76.4 - - libglu=9.0.0 - - libgomp=13.1.0 - - libgoogle-cloud=2.12.0 - - libgrpc=1.56.2 - - libiconv=1.17 - - libidn2=2.3.4 - - libllvm13=13.0.1 - - libllvm14=14.0.6 - - libnghttp2=1.52.0 - - libnpp=11.8.0.86 - - libnsl=2.0.0 - - libnuma=2.0.18 - - libnvjpeg=11.9.0.86 - - libpng=1.6.39 - - libprotobuf=4.23.3 - - librsvg=2.54.4 - - libsodium=1.0.18 - - libsqlite=3.42.0 - - libssh2=1.11.0 - - libstdcxx-devel_linux-64=11.2.0 - - libstdcxx-ng=13.1.0 - - libtasn1=4.19.0 - - libthrift=0.18.1 - - libtiff=4.4.0 - - libtool=2.4.7 - - libunistring=0.9.10 - - libutf8proc=2.8.0 - - libuuid=2.38.1 - - libwebp=1.2.4 - - libwebp-base=1.2.4 - - libxcb=1.15 - - libxml2=2.10.4 - - libzlib=1.2.13 - - llvmlite=0.40.1 - - lz4-c=1.9.4 - - markupsafe=2.1.1 - - matplotlib-inline=0.1.6 - - metakernel=0.29.5 - - mistune=3.0.0 - - mkl=2023.1.0 - - mkl-service=2.4.0 - - mkl_fft=1.3.6 - - mkl_random=1.2.2 - - mpc=1.1.0 - - mpfr=4.0.2 - - mpmath=1.3.0 - - nbclient=0.8.0 - - nbconvert-core=7.7.3 - - nbformat=5.9.2 - - ncurses=6.4 - - nest-asyncio=1.5.6 - - nettle=3.7.3 - - networkx=3.1 - - nlohmann_json=3.11.2 - - notebook=7.0.2 - - notebook-shim=0.2.3 - - numba=0.57.1 - - numpy=1.24.3 - - numpy-base=1.24.3 - - openh264=2.1.1 - - openssl=3.3.1 - - orc=1.9.0 - - overrides=7.4.0 - - packaging=23.0 - - pandas=2.0.3 - - pandocfilters=1.5.0 - - pango=1.50.14 - - parso=0.8.3 - - pcre=8.45 - - pcre2=10.40 - - pexpect=4.8.0 - - pickleshare=0.7.5 - - pillow=9.4.0 - - pip=23.2.1 - - pixman=0.40.0 - - pkgutil-resolve-name=1.3.10 - - platformdirs=2.6.0 - - pooch=1.4.0 - - portalocker=2.7.0 - - prometheus_client=0.17.1 - - prompt-toolkit=3.0.39 - - prompt_toolkit=3.0.39 - - psutil=5.9.0 - - pthread-stubs=0.4 - - ptyprocess=0.7.0 - - pure_eval=0.2.2 - - pyarrow=12.0.1 - - pycparser=2.21 - - pygments=2.16.1 - - pyopenssl=23.2.0 - - pysocks=1.7.1 - - pythia8=8.309 - - python=3.8.17 - - python-dateutil=2.8.2 - - python-fastjsonschema=2.18.0 - - python-json-logger=2.0.7 - - python-tzdata=2024.2 - - python_abi=3.8 - - pytorch=2.0.1 - - pytorch-cuda=11.8 - - pytorch-mutex=1.0 - - pytz=2023.3 - - pyyaml=6.0 - - pyzmq=25.1.1 - - rdma-core=28.9 - - re2=2023.03.02 - - readline=8.2 - - referencing=0.30.2 - - requests=2.31.0 - - rfc3339-validator=0.1.4 - - rfc3986-validator=0.1.1 - - root=6.28.0 - - root_base=6.28.0 - - rpds-py=0.9.2 - - s2n=1.3.46 - - scipy=1.10.1 - - scitokens-cpp=0.7.3 - - send2trash=1.8.2 - - setuptools=68.0.0 - - six=1.16.0 - - snappy=1.1.10 - - sniffio=1.3.0 - - soupsieve=2.3.2.post1 - - sqlite=3.41.2 - - stack_data=0.6.2 - - sympy=1.11.1 - - sysroot_linux-64=2.17 - - tbb=2021.8.0 - - terminado=0.17.1 - - tinycss2=1.2.1 - - tk=8.6.12 - - tomli=2.0.1 - - torchaudio=2.0.2 - - torchtriton=2.0.0 - - torchvision=0.15.2 - - tornado=6.3.2 - - tqdm=4.65.0 - - traitlets=5.9.0 - - typing_extensions=4.12.2 - - typing_utils=0.1.0 - - ucx=1.14.1 - - uri-template=1.3.0 - - urllib3=1.26.16 - - vdt=0.4.3 - - vector-classes=1.4.3 - - wcwidth=0.2.6 - - webcolors=1.13 - - webencodings=0.5.1 - - websocket-client=1.6.1 - - wheel=0.38.4 - - xorg-fixesproto=5.0 - - xorg-kbproto=1.0.7 - - xorg-libice=1.1.1 - - xorg-libsm=1.2.4 - - xorg-libx11=1.8.6 - - xorg-libxau=1.0.11 - - xorg-libxcursor=1.2.0 - - xorg-libxdmcp=1.1.3 - - xorg-libxext=1.3.4 - - xorg-libxfixes=5.0.3 - - xorg-libxft=2.3.8 - - xorg-libxpm=3.5.16 - - xorg-libxrender=0.9.11 - - xorg-libxt=1.3.0 - - xorg-renderproto=0.11.1 - - xorg-xextproto=7.3.0 - - xorg-xproto=7.0.31 - - xrootd=5.5.4 - - xxhash=0.8.1 - - xz=5.2.6 - - yaml=0.2.5 - - zeromq=4.3.4 - - zipp=3.16.2 - - zlib=1.2.13 - - zstd=1.5.2 - - pip: - - awkward==2.6.4 - - awkward-cpp==33 - - contourpy==1.1.0 - - cramjam==2.8.3 - - cycler==0.11.0 - - fonttools==4.42.0 - - fsspec==2024.3.1 - - h5py==3.9.0 - - pip-install==1.3.5 - - joblib==1.3.2 - - kiwisolver==1.4.4 - - matplotlib==3.7.2 - - nvidia-cublas-cu12==12.1.3.1 - - nvidia-cuda-cupti-cu12==12.1.105 - - nvidia-cuda-nvrtc-cu12==12.1.105 - - nvidia-cuda-runtime-cu12==12.1.105 - - nvidia-cudnn-cu12==8.9.2.26 - - nvidia-cufft-cu12==11.0.2.54 - - nvidia-curand-cu12==10.3.2.106 - - nvidia-cusolver-cu12==11.4.5.107 - - nvidia-cusparse-cu12==12.1.0.106 - - nvidia-nccl-cu12==2.20.5 - - nvidia-nvjitlink-cu12==12.4.127 - - nvidia-nvtx-cu12==12.1.105 - - pyparsing==3.0.9 - - scikit-learn==1.3.0 - - threadpoolctl==3.2.0 - - torch==2.3.0 - - triton==2.3.0 - - typing-extensions==4.11.0 - - tzdata==2024.1 - - uproot==5.3.7 \ No newline at end of file diff --git a/legacy/root_gnn_dgl/setup/launch_image.sh b/legacy/root_gnn_dgl/setup/launch_image.sh deleted file mode 100644 index 6f0b08dfc55d6577b883839ff18080028dbe0a06..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/setup/launch_image.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -ENTRYPOINT=$1 -shift -ARGUEMENTS="$*" - -echo "launched image" -echo "Entrypoint = $ENTRYPOINT" -echo "Arguements = $ARGUEMENTS" - -podman-hpc run \ - -it \ - --mount type=bind,source=/pscratch/sd/j/joshuaho/,target=/pscratch/sd/j/joshuaho/ \ - --mount type=bind,source=/global/cfs/projectdirs/atlas/joshua/,target=/global/cfs/projectdirs/atlas/joshua/ \ - --rm \ - --network host \ - --gpu \ - --shm-size=32g \ - joshuaho/pytorch:1.0 \ - $ENTRYPOINT \ - $ARGUEMENTS \ No newline at end of file diff --git a/legacy/root_gnn_dgl/setup/test_setup.py b/legacy/root_gnn_dgl/setup/test_setup.py deleted file mode 100644 index f41377b0c50f35b55050ca88fa3f129a89b53d05..0000000000000000000000000000000000000000 --- a/legacy/root_gnn_dgl/setup/test_setup.py +++ /dev/null @@ -1,48 +0,0 @@ -import os -import importlib.util -import sys - -def test_imports(directories): - """ - Test importing all Python files in the specified directories. - - Parameters: - - directories: List of directory paths to test. - """ - print("Testing Conda environment...") - - for directory in directories: - print(f"\nChecking directory: {directory}") - - # Check if the directory exists - if not os.path.isdir(directory): - print(f"Directory not found: {directory}") - continue - - # Iterate through all files in the directory - for filename in os.listdir(directory): - # Only consider Python files - if filename.endswith(".py"): - filepath = os.path.join(directory, filename) - module_name = os.path.splitext(filename)[0] # Remove .py extension - - try: - # Dynamically import the module - spec = importlib.util.spec_from_file_location(module_name, filepath) - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - print(f"Successfully imported: {filepath}") - except Exception as e: - # Print the file and the error message if import fails - print(f"Failed to import: {filepath}") - print(f"Error: {e}") - -if __name__ == "__main__": - # Automatically append the current directory to sys.path - current_directory = os.getcwd() - sys.path.append(current_directory) - print(f"Current directory added to sys.path: {current_directory}") - - # List of directories to check - directories = ["scripts", "root_gnn_base", "models"] - test_imports(directories) \ No newline at end of file diff --git a/legacy/training_time.png b/legacy/training_time.png deleted file mode 100644 index 5cb363d853a012b511c5944ae7ea3c6fa761297a..0000000000000000000000000000000000000000 --- a/legacy/training_time.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:eccc855e8c797c433903e13422bd3e6024270e9db25decd8cba1d2233fd4166a -size 292604 diff --git a/tests/fixtures/root_gnn_reference/README.md b/tests/fixtures/root_gnn_reference/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e32a5ad373e418cdd22eb66e626e8896df112ccc --- /dev/null +++ b/tests/fixtures/root_gnn_reference/README.md @@ -0,0 +1,3 @@ +# Frozen ROOT-GNN reference + +This deterministic fixture was generated from the canonical `src/gnn4colliders.models.root_gnn` implementation at the `root-gnn-parity-baseline` tag. The full legacy-vs-rewrite campaign passed before this fixture replaced live legacy imports in tests. diff --git a/tests/fixtures/root_gnn_reference/reference.npz b/tests/fixtures/root_gnn_reference/reference.npz new file mode 100644 index 0000000000000000000000000000000000000000..676f8d26f717dc1ae55515a70af1349414742649 --- /dev/null +++ b/tests/fixtures/root_gnn_reference/reference.npz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9364934b7149a3337479712eda132a63c49b458e04d86827b82d0ae7cbac3221 +size 1305 diff --git a/tests/parity/conftest.py b/tests/parity/conftest.py index 4412a3574336899b183e8c98d9c9ca3d7ca3eff9..6b21d34c7762b89f458f94489e59540f773435ff 100644 --- a/tests/parity/conftest.py +++ b/tests/parity/conftest.py @@ -1,16 +1,11 @@ -"""Helpers for importing the legacy ROOT-GNN implementation in parity tests.""" +"""Shared setup for parity tests against frozen canonical references.""" import os -import sys -import types -from pathlib import Path import pytest pytestmark = pytest.mark.parity -pytestmark = pytest.mark.parity - def _dgl_is_importable(): try: @@ -30,77 +25,3 @@ def require_root_gnn_dependencies(): "ROOT-GNN parity requires an importable DGL installation", pytrace=False, ) - - -@pytest.fixture(scope="session") -def legacy_dataset_module(): - """Return the active legacy dataset module when DGL is available.""" - pytest.importorskip("dgl") - legacy_root = Path(__file__).parents[2] / "legacy" / "root_gnn_dgl" - legacy_root_string = str(legacy_root) - if legacy_root_string not in sys.path: - sys.path.insert(0, legacy_root_string) - from root_gnn_base import dataset - - return dataset - - -@pytest.fixture(scope="session") -def legacy_model_module(): - """Return the legacy active model module for fixed-weight parity tests.""" - pytest.importorskip("dgl") - legacy_root = Path(__file__).parents[2] / "legacy" / "root_gnn_dgl" - legacy_root_string = str(legacy_root) - if legacy_root_string not in sys.path: - sys.path.insert(0, legacy_root_string) - from models import GCN - - return GCN - - -@pytest.fixture(scope="session") -def legacy_dataset_module_without_dgl(): - """Import pure legacy preprocessing with a minimal DGL import shim.""" - legacy_root = Path(__file__).parents[2] / "legacy" / "root_gnn_dgl" - legacy_root_string = str(legacy_root) - if legacy_root_string not in sys.path: - sys.path.insert(0, legacy_root_string) - try: - import dgl # noqa: F401 - except ImportError: - missing = object() - originals = { - name: sys.modules.get(name, missing) - for name in ("dgl", "dgl.data", "matplotlib", "matplotlib.pyplot") - } - dgl_module = types.ModuleType("dgl") - dgl_data_module = types.ModuleType("dgl.data") - dgl_data_module.DGLDataset = type("DGLDataset", (), {}) - dgl_module.data = dgl_data_module - sys.modules["dgl"] = dgl_module - sys.modules["dgl.data"] = dgl_data_module - matplotlib_module = types.ModuleType("matplotlib") - matplotlib_pyplot_module = types.ModuleType("matplotlib.pyplot") - matplotlib_module.pyplot = matplotlib_pyplot_module - sys.modules["matplotlib"] = matplotlib_module - sys.modules["matplotlib.pyplot"] = matplotlib_pyplot_module - try: - from root_gnn_base import dataset - finally: - for name, original in originals.items(): - if original is missing: - sys.modules.pop(name, None) - else: - sys.modules[name] = original - return dataset - from root_gnn_base import dataset - - return dataset - - -@pytest.fixture(scope="session") -def legacy_utils_module(legacy_dataset_module_without_dgl): - """Return legacy fold-selection helpers after the package path is set up.""" - from root_gnn_base import utils - - return utils diff --git a/tests/parity/test_data_contract.py b/tests/parity/test_data_contract.py new file mode 100644 index 0000000000000000000000000000000000000000..c9895346567714bc95eb1e7bd286d3e0f803d77e --- /dev/null +++ b/tests/parity/test_data_contract.py @@ -0,0 +1,46 @@ +"""Characterization of the canonical named event metadata contract.""" + +import torch + +from gnn4colliders.data import EventMetadata, SplitDefinition, select_split +from gnn4colliders.data.sample import EventSample + + +def test_event_metadata_preserves_fold_weight_and_sample_id(): + metadata = EventMetadata.from_legacy_tracking([3.0, 2.5], sample_id="fixture:0") + assert metadata.fold == 3 + assert metadata.weight == 2.5 + assert metadata.sample_id == "fixture:0" + + +def test_event_sample_compatibility_tracking_view_is_named_metadata_backed(): + metadata = EventMetadata(fold=4, weight=-2.0, sample_id="fixture:1") + sample = EventSample( + objects={}, + label=torch.tensor(1), + global_features=torch.empty(0).numpy(), + event_index=1, + metadata=metadata, + ) + assert sample.event_metadata is metadata + assert sample.tracking.tolist() == [4.0, -2.0] + + +def test_split_selection_preserves_order_and_disjointness(): + events = [ + EventSample({}, 0, torch.empty(0).numpy(), i, EventMetadata(i, 1.0, str(i))) + for i in range(4) + ] + split = SplitDefinition( + train_folds=frozenset({0, 2}), + validation_folds=frozenset({1}), + test_folds=frozenset({3}), + ) + assert [event.event_index for event in select_split(events, split, "train")] == [ + 0, + 2, + ] + assert [ + event.event_index for event in select_split(events, split, "validation") + ] == [1] + assert [event.event_index for event in select_split(events, split, "test")] == [3] diff --git a/tests/parity/test_graph_and_edges.py b/tests/parity/test_graph_and_edges.py new file mode 100644 index 0000000000000000000000000000000000000000..fc61273c63fc7345a1868eac88cc1025b08f7209 --- /dev/null +++ b/tests/parity/test_graph_and_edges.py @@ -0,0 +1,44 @@ +"""Reference tests for canonical graph topology and edge features.""" + +import numpy as np +import torch + +from gnn4colliders.graphs import ( + build_dgl_graph, + build_edge_features, + fully_connected_edges, +) + + +def test_fully_connected_topology_is_source_major_without_self_loops(): + for n_nodes, expected in { + 1: [(0, 0)], + 2: [(0, 1), (1, 0)], + 3: [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)], + }.items(): + source, destination = fully_connected_edges(n_nodes) + assert list(zip(source.tolist(), destination.tolist())) == expected + + +def test_dgl_graph_uses_canonical_topology_and_features(): + nodes = torch.tensor([[10.0, 1.0, 3.1], [20.0, -0.5, -3.1]]) + graph = build_dgl_graph(nodes) + assert graph.num_nodes() == 2 + assert graph.num_edges() == 2 + expected_deta = torch.tensor([1.5, -1.5]) + expected_dphi = torch.tensor([-0.0831853, 0.0831853]) + expected = torch.stack( + [expected_deta, expected_dphi, torch.sqrt(expected_deta**2 + expected_dphi**2)], + dim=1, + ) + np.testing.assert_allclose( + graph.edata["features"].numpy(), expected.numpy(), rtol=0, atol=1e-5 + ) + + +def test_edge_features_preserve_deta_dphi_dr_order(): + nodes = torch.tensor([[10.0, 1.0, 3.1], [20.0, -0.5, -3.1]]) + source, destination = fully_connected_edges(2) + actual = build_edge_features(nodes, source, destination, eta_index=1, phi_index=2) + assert actual.shape == (2, 3) + assert torch.isfinite(actual).all() diff --git a/tests/parity/test_legacy_graph_and_edges.py b/tests/parity/test_legacy_graph_and_edges.py deleted file mode 100644 index ee50ed80b4eb0f6db9ba51cdd3a82e63ec2b0c90..0000000000000000000000000000000000000000 --- a/tests/parity/test_legacy_graph_and_edges.py +++ /dev/null @@ -1,112 +0,0 @@ -"""Characterization tests for legacy directed graph and edge construction.""" - -import numpy as np -import torch - -from gnn4colliders.graphs import build_edge_features, fully_connected_edges - - -def test_full_connected_graph_is_directed_without_self_loops(legacy_dataset_module): - graph = legacy_dataset_module.full_connected_graph(3, self_loops=False) - assert graph.is_homogeneous - assert graph.number_of_nodes() == 3 - assert graph.number_of_edges() == 6 - sources, destinations = graph.edges() - np.testing.assert_array_equal(sources.numpy(), [0, 0, 1, 1, 2, 2]) - np.testing.assert_array_equal(destinations.numpy(), [1, 2, 0, 2, 0, 1]) - - -def test_full_connected_graph_keeps_self_loop_for_single_node( - legacy_dataset_module, -): - graph = legacy_dataset_module.full_connected_graph(1, self_loops=False) - assert graph.number_of_nodes() == 1 - assert graph.number_of_edges() == 1 - - -def test_full_connected_graph_edge_counts_and_order_are_source_major( - legacy_dataset_module, -): - expected_edges = { - 1: [(0, 0)], - 2: [(0, 1), (1, 0)], - 3: [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)], - } - for n_nodes, expected in expected_edges.items(): - graph = legacy_dataset_module.full_connected_graph(n_nodes, self_loops=False) - assert graph.number_of_edges() == len(expected) - sources, destinations = graph.edges() - assert list(zip(sources.tolist(), destinations.tolist())) == expected - - -def test_new_topology_matches_legacy(legacy_dataset_module): - for n_nodes in (1, 2, 3): - legacy_graph = legacy_dataset_module.full_connected_graph( - n_nodes, self_loops=False - ) - source, destination = fully_connected_edges(n_nodes) - legacy_source, legacy_destination = legacy_graph.edges() - torch.testing.assert_close(source, legacy_source) - torch.testing.assert_close(destination, legacy_destination) - - -def test_edge_features_are_deta_dphi_dr_with_phi_wrapping(legacy_dataset_module): - dataset = object.__new__(legacy_dataset_module.EdgeDataset) - dataset.times = [0, 0] - dataset.node_branch_names = [ - ["jet_pt"], - ["jet_eta"], - ["jet_phi"], - "CALC_E", - [0], - [0], - "NODE_TYPE", - ] - dataset.node_branch_types = ["vector"] - dataset.node_feature_scales = torch.ones(7) - event = { - "jet_pt": np.array([10.0, 20.0], dtype=np.float32), - "jet_eta": np.array([1.0, -0.5], dtype=np.float32), - "jet_phi": np.array([3.1, -3.1], dtype=np.float32), - } - graph = dataset.make_graph(event) - expected_deta = torch.tensor([1.5, -1.5]) - expected_dphi = torch.tensor([-0.0831853, 0.0831853]) - expected = torch.stack( - [expected_deta, expected_dphi, torch.sqrt(expected_deta**2 + expected_dphi**2)], - dim=1, - ) - assert graph.edata["features"].shape == (2, 3) - np.testing.assert_allclose( - graph.edata["features"].numpy(), expected.numpy(), rtol=0, atol=1e-5 - ) - - -def test_new_edge_features_match_legacy(legacy_dataset_module): - dataset = object.__new__(legacy_dataset_module.EdgeDataset) - dataset.times = [0, 0] - dataset.node_branch_names = [ - ["jet_pt"], - ["jet_eta"], - ["jet_phi"], - "CALC_E", - [0], - [0], - "NODE_TYPE", - ] - dataset.node_branch_types = ["vector"] - dataset.node_feature_scales = torch.ones(7) - event = { - "jet_pt": np.array([10.0, 20.0], dtype=np.float32), - "jet_eta": np.array([1.0, -0.5], dtype=np.float32), - "jet_phi": np.array([3.1, -3.1], dtype=np.float32), - } - legacy_graph = dataset.make_graph(event) - node_features = legacy_graph.ndata["features"] - source, destination = fully_connected_edges(node_features.shape[0]) - actual = build_edge_features( - node_features, source, destination, eta_index=1, phi_index=2 - ) - np.testing.assert_allclose( - actual.numpy(), legacy_graph.edata["features"].numpy(), rtol=0, atol=1e-6 - ) diff --git a/tests/parity/test_legacy_tracking.py b/tests/parity/test_legacy_tracking.py deleted file mode 100644 index 06dff934841519bf42e140cc1ccb471053dca37d..0000000000000000000000000000000000000000 --- a/tests/parity/test_legacy_tracking.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Characterization of the legacy dataset item contract.""" - -import torch - - -def _dataset_item(legacy_dataset_module_without_dgl, labels, tracking, globals_): - dataset = object.__new__(legacy_dataset_module_without_dgl.RootDataset) - dataset.graphs = [object() for _ in labels] - dataset.labels = torch.as_tensor(labels) - dataset.tracking = torch.as_tensor(tracking, dtype=torch.float32) - dataset.global_features = torch.as_tensor(globals_, dtype=torch.float32) - return dataset - - -def test_dataset_item_contract_preserves_label_tracking_and_global_shapes( - legacy_dataset_module_without_dgl, -): - dataset = object.__new__(legacy_dataset_module_without_dgl.RootDataset) - graph = object() - dataset.graphs = [graph] - dataset.labels = torch.tensor([7]) - dataset.tracking = torch.tensor([[3.0, 2.5]], dtype=torch.float32) - dataset.global_features = torch.empty((1, 0), dtype=torch.float32) - item = dataset[0] - assert item[0] is graph - assert item[1].shape == torch.Size([]) - assert item[1].dtype == torch.int64 - assert item[2].shape == (2,) - assert item[2].dtype == torch.float32 - assert item[2].tolist() == [3.0, 2.5] - assert item[3].shape == (0,) - assert item[3].dtype == torch.float32 - - -def test_dataset_item_contract_preserves_binary_and_multiclass_labels( - legacy_dataset_module_without_dgl, -): - dataset = _dataset_item( - legacy_dataset_module_without_dgl, - labels=[0, 1, 11], - tracking=[[0.0, 1.0], [3.0, -2.5], [7.0, 0.0]], - globals_=[[], [], []], - ) - items = [dataset[index] for index in range(3)] - assert [item[1].item() for item in items] == [0, 1, 11] - assert all(item[1].shape == torch.Size([]) for item in items) - assert all(item[1].dtype == torch.int64 for item in items) - assert items[1][2].tolist() == [3.0, -2.5] - assert all(item[3].shape == (0,) for item in items) - - -def test_dataset_item_contract_preserves_nonempty_global_features( - legacy_dataset_module_without_dgl, -): - dataset = _dataset_item( - legacy_dataset_module_without_dgl, - labels=[1], - tracking=[[4.0, 2.0]], - globals_=[[12.5, -3.0]], - ) - item = dataset[0] - assert item[3].shape == (2,) - assert item[3].dtype == torch.float32 - assert item[3].tolist() == [12.5, -3.0] - - -def test_fold_selection_uses_tracking_column_zero_and_keeps_weights( - legacy_utils_module, -): - sample = type( - "Sample", - (), - {"tracking": torch.tensor([[0.0, 1.0], [1.0, -2.5], [2.0, 0.0], [3.0, 4.0]])}, - )() - selection = legacy_utils_module.fold_selection({"n_folds": 2, "test": [1]}, "test") - assert selection(sample).tolist() == [False, True, False, True] - assert sample.tracking[:, 1].tolist() == [1.0, -2.5, 0.0, 4.0] diff --git a/tests/parity/test_model_parity.py b/tests/parity/test_model_parity.py index aa501f2cf0304be61acfc8dd6a7854b9516e524a..aba2866e8864787280c55b1e0ba1b8a711ee1ff4 100644 --- a/tests/parity/test_model_parity.py +++ b/tests/parity/test_model_parity.py @@ -1,7 +1,10 @@ -"""Fixed-weight parity tests for the active legacy and rewritten models.""" +"""Fixed-reference tests for the canonical ROOT-GNN implementation.""" from __future__ import annotations +from pathlib import Path + +import numpy as np import pytest import torch @@ -15,88 +18,54 @@ from gnn4colliders.models.root_gnn import ( pytest.importorskip("dgl") +REFERENCE = ( + Path(__file__).parents[1] / "fixtures" / "root_gnn_reference" / "reference.npz" +) + + +def _fixture(): + with np.load(REFERENCE) as values: + return {name: values[name] for name in values.files} + + def _graph_and_globals(): - graph = build_dgl_graph( - torch.tensor( - [[10.0, 0.2, 0.1], [8.0, -0.3, -0.2], [4.0, 0.1, 2.8]], - dtype=torch.float32, - ) - ) - return graph, torch.tensor([[1.0, 2.0]], dtype=torch.float32) + values = _fixture() + graph = build_dgl_graph(torch.from_numpy(values["nodes"])) + globals_ = torch.from_numpy(values["globals"]) + return graph, globals_, values -def _new_model(graph, globals_): +def _model(graph, globals_): + torch.manual_seed(314159) return EdgeNetwork(graph, globals_, 8, 3, 2, 2, dropout=0.0).eval() -def test_edge_network_matches_legacy_forward_and_representation( - legacy_model_module, -): - graph, globals_ = _graph_and_globals() - new_model = _new_model(graph, globals_) - legacy_model = legacy_model_module.Edge_Network( - graph, globals_, 8, 3, 2, 2, dropout=0.0 - ).eval() - legacy_state = { - key.replace("classifier.", "classify."): value - for key, value in new_model.state_dict().items() - } - legacy_model.load_state_dict(legacy_state) - +def test_edge_network_matches_frozen_reference(): + graph, globals_, expected = _graph_and_globals() + model = _model(graph, globals_) with torch.no_grad(): - new_representation = new_model.forward_features(graph, globals_) - legacy_representation = legacy_model.representation(graph.clone(), globals_)[1] - new_logits = new_model(graph, globals_) - legacy_logits = legacy_model(graph.clone(), globals_) - assert torch.equal(new_representation, legacy_representation) - assert torch.equal(new_logits, legacy_logits) - - -def test_transfer_forward_matches_legacy_transfer(legacy_model_module, tmp_path): - graph, _ = _graph_and_globals() - globals_ = torch.empty((0, 0), dtype=torch.float32) - new_model = EdgeNetwork(graph, globals_, 8, 3, 2, 2, dropout=0.0).eval() - legacy_pretrained = legacy_model_module.Edge_Network( - graph, globals_, 8, 3, 2, 2, dropout=0.0 - ).eval() - legacy_state = { - key.replace("classifier.", "classify."): value - for key, value in new_model.state_dict().items() - } - legacy_pretrained.load_state_dict(legacy_state) - checkpoint_path = tmp_path / "pretrained.pt" - torch.save({"model_state_dict": legacy_pretrained.state_dict()}, checkpoint_path) - - config = { - "module": "models.GCN", - "class": "Edge_Network", - "args": { - "hid_size": 8, - "out_size": 3, - "n_layers": 2, - "n_proc_steps": 2, - "dropout": 0.0, - }, - } - legacy_transfer = legacy_model_module.Transferred_Learning_Finetuning( - str(checkpoint_path), config, graph, globals_, 8, 1, 2, 2, dropout=0.0 - ).eval() - transfer = FineTunedEdgeNetwork.from_pretrained(new_model, 1) - transfer.classifier.load_state_dict(legacy_transfer.classify.state_dict()) + representation = model.forward_features(graph, globals_).numpy() + logits = model(graph, globals_).numpy() + assert np.array_equal(representation, expected["representation"]) + assert np.array_equal(logits, expected["logits"]) + +def test_transfer_forward_matches_frozen_reference(): + graph, globals_, expected = _graph_and_globals() + model = _model(graph, globals_) + torch.manual_seed(271828) + transfer = FineTunedEdgeNetwork.from_pretrained(model, 1).eval() with torch.no_grad(): - expected = legacy_transfer(graph.clone(), None) - actual = transfer(graph, None) - assert torch.equal(actual, expected) - assert torch.equal( - transfer.representation(graph, None), transfer.forward_features(graph, None) - ) + features = transfer.forward_features(graph, globals_).numpy() + logits = transfer(graph, globals_).numpy() + assert np.array_equal(features, expected["transfer_features"]) + assert np.array_equal(logits, expected["transfer_logits"]) -def test_legacy_prefix_loader_handles_checkpoint_prefixes(): - graph, globals_ = _graph_and_globals() - source = _new_model(graph, globals_) - target = _new_model(graph, globals_) +def test_legacy_prefix_loader_remains_checkpoint_compatibility_only(): + graph, globals_, _ = _graph_and_globals() + source = _model(graph, globals_) + target = _model(graph, globals_) prefixed = { "module._orig_mod." + key.replace("classifier.", "classify."): value for key, value in source.state_dict().items() diff --git a/tests/parity/test_new_node_features.py b/tests/parity/test_new_node_features.py deleted file mode 100644 index 9726594b72d74f2d2236db2a489a95fc42e43ee2..0000000000000000000000000000000000000000 --- a/tests/parity/test_new_node_features.py +++ /dev/null @@ -1,45 +0,0 @@ -import numpy as np -import torch - -from gnn4colliders.features import build_node_features - - -def test_new_builder_matches_legacy_builder(legacy_dataset_module_without_dgl): - event = { - "jet_pt": np.array([100.0, 50.0], dtype=np.float32), - "ele_pt": np.array([20.0], dtype=np.float32), - "mu_pt": np.array([30.0], dtype=np.float32), - "ph_pt": np.array([40.0], dtype=np.float32), - "MET_met": np.float32(25.0), - "jet_eta": np.array([1.0, -0.5], dtype=np.float32), - "ele_eta": np.array([0.25], dtype=np.float32), - "mu_eta": np.array([-0.75], dtype=np.float32), - "ph_eta": np.array([0.5], dtype=np.float32), - "jet_phi": np.array([3.0, -3.0], dtype=np.float32), - "ele_phi": np.array([0.2], dtype=np.float32), - "mu_phi": np.array([-0.4], dtype=np.float32), - "ph_phi": np.array([1.0], dtype=np.float32), - "MET_phi": np.float32(-1.2), - "jet_btag": np.array([0.8, 0.1], dtype=np.float32), - "ele_charge": np.array([-1.0], dtype=np.float32), - "mu_charge": np.array([1.0], dtype=np.float32), - } - names = [ - ["jet_pt", "ele_pt", "mu_pt", "ph_pt", "MET_met"], - ["jet_eta", "ele_eta", "mu_eta", "ph_eta", 0], - ["jet_phi", "ele_phi", "mu_phi", "ph_phi", "MET_phi"], - "CALC_E", - ["jet_btag", 0, 0, 0, 0], - [0, "ele_charge", "mu_charge", 0, 0], - "NODE_TYPE", - ] - object_types = ["vector", "vector", "vector", "vector", "single"] - scales = torch.tensor([0.1, 1, 1, 0.1, 1, 1, 1]) - expected, expected_lengths = ( - legacy_dataset_module_without_dgl.node_features_from_tree( - event, names, object_types, scales - ) - ) - actual, actual_lengths = build_node_features(event, names, object_types, scales) - assert actual_lengths == expected_lengths - torch.testing.assert_close(actual, expected, rtol=0, atol=0) diff --git a/tests/parity/test_legacy_node_features.py b/tests/parity/test_node_features.py similarity index 55% rename from tests/parity/test_legacy_node_features.py rename to tests/parity/test_node_features.py index 9230fe2d7205947aa253a97d08f75560baa76385..ea6ed1d829a7897ceee879ab7c60e5a7c6ea75ef 100644 --- a/tests/parity/test_legacy_node_features.py +++ b/tests/parity/test_node_features.py @@ -1,12 +1,28 @@ -"""Characterization tests for the active legacy node feature builder.""" +"""Reference tests for the shared collider node feature builder.""" import numpy as np -import pytest import torch +from gnn4colliders.features import build_node_features -@pytest.fixture -def event(): + +def _schema(): + return ( + [ + ["jet_pt", "ele_pt", "mu_pt", "ph_pt", "MET_met"], + ["jet_eta", "ele_eta", "mu_eta", "ph_eta", 0], + ["jet_phi", "ele_phi", "mu_phi", "ph_phi", "MET_phi"], + "CALC_E", + ["jet_btag", 0, 0, 0, 0], + [0, "ele_charge", "mu_charge", 0, 0], + "NODE_TYPE", + ], + ["vector", "vector", "vector", "vector", "single"], + torch.tensor([0.1, 1, 1, 0.1, 1, 1, 1]), + ) + + +def _event(): return { "jet_pt": np.array([100.0, 50.0], dtype=np.float32), "ele_pt": np.array([20.0], dtype=np.float32), @@ -17,41 +33,20 @@ def event(): "ele_eta": np.array([0.25], dtype=np.float32), "mu_eta": np.array([-0.75], dtype=np.float32), "ph_eta": np.array([0.5], dtype=np.float32), + "MET_phi": np.float32(-1.2), "jet_phi": np.array([3.0, -3.0], dtype=np.float32), "ele_phi": np.array([0.2], dtype=np.float32), "mu_phi": np.array([-0.4], dtype=np.float32), "ph_phi": np.array([1.0], dtype=np.float32), - "MET_phi": np.float32(-1.2), "jet_btag": np.array([0.8, 0.1], dtype=np.float32), "ele_charge": np.array([-1.0], dtype=np.float32), "mu_charge": np.array([1.0], dtype=np.float32), } -@pytest.fixture -def node_schema(): - return ( - [ - ["jet_pt", "ele_pt", "mu_pt", "ph_pt", "MET_met"], - ["jet_eta", "ele_eta", "mu_eta", "ph_eta", 0], - ["jet_phi", "ele_phi", "mu_phi", "ph_phi", "MET_phi"], - "CALC_E", - ["jet_btag", 0, 0, 0, 0], - [0, "ele_charge", "mu_charge", 0, 0], - "NODE_TYPE", - ], - ["vector", "vector", "vector", "vector", "single"], - [0.1, 1, 1, 0.1, 1, 1, 1], - ) - - -def test_node_features_have_active_schema_and_order( - legacy_dataset_module_without_dgl, event, node_schema -): - names, types, scales = node_schema - features, lengths = legacy_dataset_module_without_dgl.node_features_from_tree( - event, names, types, torch.tensor(scales, dtype=torch.float32) - ) +def test_node_features_match_frozen_schema_and_order(): + names, types, scales = _schema() + features, lengths = build_node_features(_event(), names, types, scales) expected = np.array( [ [10.0, 1.0, 3.0, 15.431, 0.8, 0.0, 0.0], @@ -69,32 +64,13 @@ def test_node_features_have_active_schema_and_order( np.testing.assert_allclose(features.numpy(), expected, rtol=0, atol=2e-3) -def test_node_feature_builder_preserves_zero_length_vector( - legacy_dataset_module_without_dgl, node_schema -): - names, types, scales = node_schema - event = { - "jet_pt": np.array([], dtype=np.float32), - "ele_pt": np.array([20.0], dtype=np.float32), - "mu_pt": np.array([], dtype=np.float32), - "ph_pt": np.array([], dtype=np.float32), - "MET_met": np.float32(25.0), - "jet_btag": np.array([], dtype=np.float32), - "ele_charge": np.array([-1.0], dtype=np.float32), - "mu_charge": np.array([], dtype=np.float32), - "jet_eta": np.array([], dtype=np.float32), - "ele_eta": np.array([0.25], dtype=np.float32), - "mu_eta": np.array([], dtype=np.float32), - "ph_eta": np.array([], dtype=np.float32), - "jet_phi": np.array([], dtype=np.float32), - "ele_phi": np.array([0.2], dtype=np.float32), - "mu_phi": np.array([], dtype=np.float32), - "ph_phi": np.array([], dtype=np.float32), - "MET_phi": np.float32(-1.2), - } - features, lengths = legacy_dataset_module_without_dgl.node_features_from_tree( - event, names, types, torch.tensor(scales) - ) +def test_node_feature_builder_preserves_zero_length_vectors(): + event = _event() + for name in tuple(event): + if name.startswith(("jet_", "mu_", "ph_")): + event[name] = np.array([], dtype=np.float32) + names, types, scales = _schema() + features, lengths = build_node_features(event, names, types, scales) assert lengths == [0, 1, 0, 0, 1] assert features.shape == (2, 7) assert features[:, 6].tolist() == [1.0, 4.0] diff --git a/validation/README.md b/validation/README.md index 10eff5355267698be908a002a785114583895f02..59c872f30df402431221447c15585569168b8b95 100644 --- a/validation/README.md +++ b/validation/README.md @@ -11,13 +11,12 @@ uv run python -m validation.run_public_validation ``` The command verifies the local fixture, downloads it from the pinned Hugging -Face revision when necessary, extracts the rewrite, compares it with the -checked-in legacy golden artifact, writes JSON and Markdown reports, and exits +Face revision when necessary, extracts the canonical implementation, compares +it with the checked-in reference artifact, writes JSON and Markdown reports, and exits nonzero on a scientific mismatch. Use `--no-download` for offline runs. Keep generated output out of Git. -The lower-level artifact tooling remains available for regenerating references -in the historical legacy environment: +The lower-level artifact tooling remains available for local artifact checks: ```bash uv run python -m validation.run_full_validation --smoke @@ -27,7 +26,7 @@ uv run python -m validation.run_full_validation --smoke The normal public regression path requires only the current environment. It verifies the pinned public fixture, downloads it when missing, extracts the -rewrite, and compares it with the legacy golden artifact: +canonical implementation, and compares it with the reference artifact: ```bash uv run python -m validation.run_public_validation @@ -43,28 +42,9 @@ sha256: 89d69eae9cd4d28a5d414d77bbc07185ea5b7de03481fdafe28899e2f3a09dec events: 64 ``` -The historical extraction commands below are retained only for regenerating or -auditing the golden artifact in a legacy environment: - -```bash -ROOT=data/fixtures/testing/ttH_NLO_64.root -HF_SHA=89d69eae9cd4d28a5d414d77bbc07185ea5b7de03481fdafe28899e2f3a09dec - -conda run -n dgl env PYTHONPATH=.:legacy/root_gnn_dgl:src \ - python validation/extract_legacy.py "$ROOT" validation_output/legacy \ - --source-sha256 "$HF_SHA" - -PYTHONPATH=.:src uv run python validation/extract_rewrite.py "$ROOT" \ - validation_output/rewrite --source-sha256 "$HF_SHA" -``` - -The manifest retains the original HF SHA-256. Then run `forward.py` -with `model_epoch_71.pt`, `train_step.py`, `compare_step.py`, and -`compare_tasks.py` to generate fixed-forward, one-step, and task reports. +The manifest retains the original HF SHA-256. Then run `forward.py`, +`train_step.py`, and the comparison tools to generate fixed-forward, one-step, +and task reports. For multiclass validation, `validation/manifests/multiclass_fixture.json` -defines the 96-event composite (eight entries from each of the 12 active -legacy classes). The source files are the HF-derived `stats_100K` samples; -the temporary composite adds only a `validation_label` branch containing the -legacy config class labels. This is the campaign fixture used for the final -12-class report. +defines the 96-event composite used by the final 12-class report. diff --git a/validation/__init__.py b/validation/__init__.py index 4587c82da081a4317e110e5e5019454ba44e890a..1a6ff0a5c0104aee65e8a1fc7e92cf779dfbc1c4 100644 --- a/validation/__init__.py +++ b/validation/__init__.py @@ -1,8 +1,8 @@ -"""Staged end-to-end parity validation utilities. +"""Staged end-to-end validation utilities. -The validation package is intentionally outside the production package. Its +The validation package is intentionally outside the production package. Its interchange format contains NumPy arrays and JSON metadata only, so extraction -can happen in separate legacy and rewrite environments. +and comparison remain independent of model implementation details. """ from .artifacts import ValidationArtifact, load_artifact, save_artifact diff --git a/validation/batching.py b/validation/batching.py index e8ef06fe12c4fefb1907f0701da675d13ea35f06..f58be324d0c9968c903be35ab59f3681bd2780a9 100644 --- a/validation/batching.py +++ b/validation/batching.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Dump deterministic batch membership and aggregate sizes for one implementation.""" +"""Dump deterministic batch membership and aggregate sizes.""" from __future__ import annotations @@ -13,87 +13,42 @@ from validation.artifacts import load_artifact from validation.forward import _graph -class _LegacyDataset(torch.utils.data.Dataset): - def __init__(self, artifact): - self.artifact = artifact - - def __len__(self): - return self.artifact.event_count - - def __getitem__(self, index): - graph = _graph(self.artifact, index) - tracking = torch.tensor( - [ - self.artifact.folds[index], - self.artifact.weights[index], - index, - ], - dtype=torch.float32, - ) - return ( - graph, - torch.tensor(self.artifact.labels[index]), - tracking, - torch.empty(0), - ) - - def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument( - "--implementation", choices=("legacy", "rewrite"), required=True - ) parser.add_argument("--artifact", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) parser.add_argument("--batch-size", type=int, default=8) args = parser.parse_args() artifact = load_artifact(args.artifact) - if args.implementation == "legacy": - from dgl.dataloading import GraphDataLoader - - loader = GraphDataLoader( - _LegacyDataset(artifact), - batch_size=args.batch_size, - shuffle=False, - drop_last=False, - num_workers=0, - ) - else: - from gnn4colliders.data import ( - EventMetadata, - GraphDataLoader, - GraphDataset, - GraphSample, - ) + from gnn4colliders.data import ( + EventMetadata, + GraphDataLoader, + GraphDataset, + GraphSample, + ) - samples = [] - for index in range(artifact.event_count): - samples.append( - GraphSample( - _graph(artifact, index), - torch.tensor(artifact.labels[index]), - None, - EventMetadata( - int(artifact.folds[index]), - float(artifact.weights[index]), - str(artifact.sample_id[index]), - {"index": index}, - ), - ) + samples = [] + for index in range(artifact.event_count): + samples.append( + GraphSample( + _graph(artifact, index), + torch.tensor(artifact.labels[index]), + None, + EventMetadata( + int(artifact.folds[index]), + float(artifact.weights[index]), + str(artifact.sample_id[index]), + {"index": index}, + ), ) - loader = GraphDataLoader(GraphDataset(samples), args.batch_size, shuffle=False) + ) + loader = GraphDataLoader(GraphDataset(samples), args.batch_size, shuffle=False) batches = [] for batch in loader: - if args.implementation == "legacy": - graph, labels, tracking, _ = batch - indices = tracking[:, 2].to(torch.long).tolist() - ids = [str(artifact.sample_id[index]) for index in indices] - weights = tracking[:, 1].tolist() - else: - graph = batch.graph - labels = batch.labels - ids = list(batch.metadata.sample_id) - weights = batch.metadata.weight.tolist() + graph = batch.graph + labels = batch.labels + ids = list(batch.metadata.sample_id) + weights = batch.metadata.weight.tolist() batches.append( { "sample_id": ids, diff --git a/validation/binary_step.py b/validation/binary_step.py index 484876d3621894732bbdd0801f75c2f38af8f4ad..696b8d53ca58d792bbc416cc2ae1d25faff72713 100644 --- a/validation/binary_step.py +++ b/validation/binary_step.py @@ -38,9 +38,6 @@ def _flat(values): def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument( - "--implementation", choices=("legacy", "rewrite"), required=True - ) parser.add_argument("--artifact", type=Path, required=True) parser.add_argument("--checkpoint", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) @@ -56,46 +53,19 @@ def main() -> int: graph = dgl.batch(graphs) empty_globals = torch.empty((len(graphs), 0), dtype=torch.float32) - if args.implementation == "legacy": - from models.GCN import Transferred_Learning_Finetuning - - model = Transferred_Learning_Finetuning( - str(args.checkpoint), - { - "module": "models.GCN", - "class": "Edge_Network", - "args": { - "hid_size": 64, - "out_size": 12, - "n_layers": 4, - "n_proc_steps": 4, - "dropout": 0.0, - }, - }, - graphs[0], - empty_globals, - 64, - 1, - 4, - 4, - dropout=0.0, - frozen_pretraining=not args.trainable_backbone, - ) - classifier = model.classify - else: - from gnn4colliders.models.root_gnn import ( - EdgeNetwork, - FineTunedEdgeNetwork, - load_legacy_edge_network_state_dict, - ) + from gnn4colliders.models.root_gnn import ( + EdgeNetwork, + FineTunedEdgeNetwork, + load_legacy_edge_network_state_dict, + ) - backbone = EdgeNetwork(graphs[0], empty_globals[:1], 64, 12, 4, 4, dropout=0.0) - payload = torch.load(args.checkpoint, map_location="cpu", weights_only=False) - load_legacy_edge_network_state_dict(backbone, payload) - model = FineTunedEdgeNetwork( - backbone, 1, freeze_backbone=not args.trainable_backbone - ) - classifier = model.classifier + backbone = EdgeNetwork(graphs[0], empty_globals[:1], 64, 12, 4, 4, dropout=0.0) + payload = torch.load(args.checkpoint, map_location="cpu", weights_only=False) + load_legacy_edge_network_state_dict(backbone, payload) + model = FineTunedEdgeNetwork( + backbone, 1, freeze_backbone=not args.trainable_backbone + ) + classifier = model.classifier torch.manual_seed(20260818) classifier.load_state_dict(torch.nn.Linear(64, 1).state_dict()) @@ -134,7 +104,7 @@ def main() -> int: parameters=parameters, ) print( - f"{args.implementation}: {len(indices)} events, " + f"rewrite: {len(indices)} events, " f"epochs={args.epochs}, final_loss={losses[-1]:.12g}" ) return 0 diff --git a/validation/compare.py b/validation/compare.py index 40a4519761e037db2d7b54c52334cf612873058a..3161e6ceb0842d26865536114747c262a6ec7638 100644 --- a/validation/compare.py +++ b/validation/compare.py @@ -1,4 +1,4 @@ -"""Stage-aware comparison of normalized legacy and rewrite artifacts.""" +"""Stage-aware comparison of normalized reference and candidate artifacts.""" from __future__ import annotations @@ -64,8 +64,8 @@ def _ids(left: ValidationArtifact, right: ValidationArtifact) -> dict[str, Any]: "status": "PASS" if left_set == right_set and not duplicates else "FAIL", "left_count": len(left_ids), "right_count": len(right_ids), - "missing_in_rewrite": sorted(left_set - right_set), - "missing_in_legacy": sorted(right_set - left_set), + "missing_in_candidate": sorted(left_set - right_set), + "missing_in_reference": sorted(right_set - left_set), "duplicates": duplicates, "order_equal": left_ids == right_ids, } diff --git a/validation/compare_batches.py b/validation/compare_batches.py index 37decdfb76afd204137e2b43498f43e27b3c9fd1..45682c7b19cd5b3b0f9e13b14de334d82d5a8932 100644 --- a/validation/compare_batches.py +++ b/validation/compare_batches.py @@ -10,17 +10,17 @@ from pathlib import Path def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument("legacy", type=Path) - parser.add_argument("rewrite", type=Path) + parser.add_argument("reference", type=Path) + parser.add_argument("candidate", type=Path) parser.add_argument("output", type=Path) args = parser.parse_args() - left = json.loads(args.legacy.read_text()) - right = json.loads(args.rewrite.read_text()) + left = json.loads(args.reference.read_text()) + right = json.loads(args.candidate.read_text()) report = { "schema_version": 1, "status": "PASS" if left == right else "FAIL", - "legacy": left, - "rewrite": right, + "reference": left, + "candidate": right, } args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text(json.dumps(report, indent=2) + "\n") diff --git a/validation/compare_step.py b/validation/compare_step.py index b0f877d2b36b1bda163c88bb5907da9f1edbc03d..7ffda68e1058f209af0eeb5cfcdf0caf5c195f8a 100644 --- a/validation/compare_step.py +++ b/validation/compare_step.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Compare serialized one-step legacy/rewrite diagnostics.""" +"""Compare serialized training diagnostics.""" from __future__ import annotations @@ -27,11 +27,11 @@ def _compare(left: np.ndarray, right: np.ndarray, atol: float, rtol: float): def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument("legacy", type=Path) - parser.add_argument("rewrite", type=Path) + parser.add_argument("reference", type=Path) + parser.add_argument("candidate", type=Path) parser.add_argument("output", type=Path) args = parser.parse_args() - with np.load(args.legacy) as left, np.load(args.rewrite) as right: + with np.load(args.reference) as left, np.load(args.candidate) as right: stages = { "logits": _compare(left["logits"], right["logits"], 1e-5, 1e-5), "loss": _compare(left["loss"], right["loss"], 1e-5, 1e-5), diff --git a/validation/compare_tasks.py b/validation/compare_tasks.py index ca1e60823796e3b50a86d9d778b79e328b47b254..6a0aaff2227c0dd01d8dc02b277901219ef21f2f 100644 --- a/validation/compare_tasks.py +++ b/validation/compare_tasks.py @@ -14,7 +14,7 @@ from sklearn.metrics import roc_auc_score from validation.artifacts import load_artifact -def _evaluate(artifact, *, rewrite: bool): +def _evaluate(artifact): logits = torch.from_numpy(artifact.logits).to(torch.float32) labels = torch.from_numpy(artifact.labels).to(torch.long) weights = torch.from_numpy(artifact.weights).to(torch.float32) @@ -29,7 +29,7 @@ def _evaluate(artifact, *, rewrite: bool): positive = weights > 0 one_hot = torch.nn.functional.one_hot(labels, num_classes=scores.shape[1]).numpy() positive_numpy = positive.numpy() - legacy_auc = float( + reference_auc = float( roc_auc_score( one_hot[positive_numpy], scores.detach().numpy()[positive_numpy], @@ -37,20 +37,18 @@ def _evaluate(artifact, *, rewrite: bool): sample_weight=weights.numpy()[positive_numpy], ) ) - if rewrite: - from gnn4colliders.tasks import MulticlassClassificationTask + from gnn4colliders.tasks import MulticlassClassificationTask - batch = SimpleNamespace( - labels=labels, - metadata=SimpleNamespace(weight=weights), - ) - auc = MulticlassClassificationTask().metrics(logits, batch)["roc_auc"] - else: - auc = legacy_auc + batch = SimpleNamespace( + labels=labels, + metadata=SimpleNamespace(weight=weights), + ) + auc = MulticlassClassificationTask().metrics(logits, batch)["roc_auc"] return { "loss": float(loss), "accuracy": float((predictions == labels).float().mean()), "roc_auc": auc, + "reference_roc_auc": reference_auc, "positive_weight_events": int(positive.sum()), "negative_weight_events": int((weights < 0).sum()), "zero_weight_events": int((weights == 0).sum()), @@ -59,26 +57,26 @@ def _evaluate(artifact, *, rewrite: bool): def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument("legacy", type=Path) - parser.add_argument("rewrite", type=Path) + parser.add_argument("reference", type=Path) + parser.add_argument("candidate", type=Path) parser.add_argument("output", type=Path) args = parser.parse_args() - left = _evaluate(load_artifact(args.legacy), rewrite=False) - right = _evaluate(load_artifact(args.rewrite), rewrite=True) + left = _evaluate(load_artifact(args.reference)) + right = _evaluate(load_artifact(args.candidate)) differences = { name: abs(left[name] - right[name]) for name in ("loss", "accuracy", "roc_auc") } report = { "schema_version": 1, - "legacy": left, - "rewrite": right, + "reference": left, + "candidate": right, "absolute_differences": differences, "overall_status": "PASS" if all(value <= 1e-5 for value in differences.values()) else "FAIL", "note": ( - "Legacy uses sklearn weighted OVR AUC; rewrite uses its task-owned " - "weighted OVR implementation." + "Each artifact is evaluated with canonical task semantics; " + "sklearn AUC is retained as a reference diagnostic." ), } args.output.mkdir(parents=True, exist_ok=True) diff --git a/validation/compare_transfer.py b/validation/compare_transfer.py index 62aca26da432b128987cedee7055b1f6a18bd3c0..382dadecec0ee6b9061a53de7cafe75d646e22b7 100644 --- a/validation/compare_transfer.py +++ b/validation/compare_transfer.py @@ -23,16 +23,16 @@ def compare(left: np.ndarray, right: np.ndarray) -> dict[str, object]: def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument("legacy_frozen", type=Path) - parser.add_argument("rewrite_frozen", type=Path) - parser.add_argument("legacy_trainable", type=Path) - parser.add_argument("rewrite_trainable", type=Path) + parser.add_argument("reference_frozen", type=Path) + parser.add_argument("candidate_frozen", type=Path) + parser.add_argument("reference_trainable", type=Path) + parser.add_argument("candidate_trainable", type=Path) parser.add_argument("output", type=Path) args = parser.parse_args() reports = {} for name, left_path, right_path in ( - ("frozen_backbone", args.legacy_frozen, args.rewrite_frozen), - ("trainable_backbone", args.legacy_trainable, args.rewrite_trainable), + ("frozen_backbone", args.reference_frozen, args.candidate_frozen), + ("trainable_backbone", args.reference_trainable, args.candidate_trainable), ): with np.load(left_path) as left, np.load(right_path) as right: reports[name] = compare(left["logits"], right["logits"]) diff --git a/validation/end_to_end_binary.py b/validation/end_to_end_binary.py index 829dfbc54b952d2e55536d495846cfbef3eaf372..b8b08576e4255c851ac88eb653a08d9960c8b90b 100644 --- a/validation/end_to_end_binary.py +++ b/validation/end_to_end_binary.py @@ -25,33 +25,7 @@ def loss(logits, labels, weights): return result / len(torch.unique(labels)) -def make_model(implementation, graph, globals_, checkpoint, trainable): - if implementation == "legacy": - from models.GCN import Transferred_Learning_Finetuning - - model = Transferred_Learning_Finetuning( - str(checkpoint), - { - "module": "models.GCN", - "class": "Edge_Network", - "args": { - "hid_size": 64, - "out_size": 12, - "n_layers": 4, - "n_proc_steps": 4, - "dropout": 0.0, - }, - }, - graph, - globals_, - 64, - 1, - 4, - 4, - dropout=0.0, - frozen_pretraining=not trainable, - ) - return model +def make_model(graph, globals_, checkpoint, trainable): from gnn4colliders.models.root_gnn import ( EdgeNetwork, FineTunedEdgeNetwork, @@ -87,9 +61,6 @@ def run_batches(model, artifact, indices, batch_size, optimizer=None): def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument( - "--implementation", choices=("legacy", "rewrite"), required=True - ) parser.add_argument("--artifact", type=Path, required=True) parser.add_argument("--checkpoint", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) @@ -108,14 +79,13 @@ def main() -> int: train = train[generator.permutation(len(train))] first_graph = _graph(artifact, int(train[0])) model = make_model( - args.implementation, first_graph, torch.empty((1, 0), dtype=torch.float32), args.checkpoint, args.trainable_backbone, ) # Match the fixed-head initialization used by the preceding parity gates. - classifier = model.classify if args.implementation == "legacy" else model.classifier + classifier = model.classifier torch.manual_seed(20260818) classifier.load_state_dict(torch.nn.Linear(64, 1).state_dict()) optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) diff --git a/validation/extract_legacy.py b/validation/extract_legacy.py deleted file mode 100644 index edc0e6bcd843557228cb857ea2b34b5286015042..0000000000000000000000000000000000000000 --- a/validation/extract_legacy.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 -"""Extract normalized artifacts with the frozen legacy feature builder.""" - -from __future__ import annotations - -import argparse -from pathlib import Path - -import torch - -from validation.extract_common import ( - FEATURE_BRANCHES, - OBJECT_TYPES, - SCALES, - extract_root, -) - - -def main() -> int: - parser = argparse.ArgumentParser() - parser.add_argument("root_file", type=Path) - parser.add_argument("output", type=Path) - parser.add_argument("--source-sha256") - parser.add_argument("--label-branch") - args = parser.parse_args() - from root_gnn_base.dataset import node_features_from_tree - - def build(event): - features, _ = node_features_from_tree( - event, - FEATURE_BRANCHES, - OBJECT_TYPES, - torch.tensor(SCALES, dtype=torch.float32), - ) - return features - - extract_root( - args.root_file, - args.output, - build_features=build, - filter_zero_pt=True, - source_sha256=args.source_sha256, - label_branch=args.label_branch, - ) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/validation/forward.py b/validation/forward.py index 234d331d4a4cf73d38c1bdb25a2698864e0be3f8..afd822b846381cab36bd8afe8b7e0d18972d296c 100644 --- a/validation/forward.py +++ b/validation/forward.py @@ -27,9 +27,6 @@ def _graph(artifact, index: int): def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument( - "--implementation", choices=("legacy", "rewrite"), required=True - ) parser.add_argument("--artifact", type=Path, required=True) parser.add_argument("--checkpoint", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) @@ -45,21 +42,14 @@ def main() -> int: batch_graph = dgl.batch(graphs) first = graphs[0] empty_globals = torch.empty((1, 0), dtype=torch.float32) - if args.implementation == "legacy": - from models.GCN import Edge_Network - - model = Edge_Network(first, empty_globals, 64, 12, 4, 4, dropout=0.0) - payload = torch.load(args.checkpoint, map_location="cpu") - model.load_state_dict(payload["model_state_dict"]) - else: - from gnn4colliders.models.root_gnn import ( - EdgeNetwork, - load_legacy_edge_network_state_dict, - ) + from gnn4colliders.models.root_gnn import ( + EdgeNetwork, + load_legacy_edge_network_state_dict, + ) - model = EdgeNetwork(first, empty_globals, 64, 12, 4, 4, dropout=0.0) - payload = torch.load(args.checkpoint, map_location="cpu", weights_only=False) - load_legacy_edge_network_state_dict(model, payload) + model = EdgeNetwork(first, empty_globals, 64, 12, 4, 4, dropout=0.0) + payload = torch.load(args.checkpoint, map_location="cpu", weights_only=False) + load_legacy_edge_network_state_dict(model, payload) model.eval() with torch.inference_mode(): @@ -83,7 +73,7 @@ def main() -> int: predictions=predictions, manifest={ **artifact.manifest, - "implementation": args.implementation, + "implementation": "rewrite", "checkpoint": str(args.checkpoint), "reload_max_abs": float(np.abs(logits - reloaded_logits).max()), }, diff --git a/validation/golden/testing/legacy/artifact.npz b/validation/golden/testing/reference/artifact.npz similarity index 100% rename from validation/golden/testing/legacy/artifact.npz rename to validation/golden/testing/reference/artifact.npz diff --git a/validation/golden/testing/legacy/manifest.json b/validation/golden/testing/reference/manifest.json similarity index 100% rename from validation/golden/testing/legacy/manifest.json rename to validation/golden/testing/reference/manifest.json diff --git a/validation/manifests/config_mapping.md b/validation/manifests/config_mapping.md index 59d94d4e0c8e19d5e1bdab9d925a9f7358c9c2ce..fcf58374206fdf613cde891bedfe737991e38859 100644 --- a/validation/manifests/config_mapping.md +++ b/validation/manifests/config_mapping.md @@ -1,11 +1,11 @@ # Canonical configuration mapping -| Legacy setting | Rewrite setting | Classification | +| Historical setting | Canonical setting | Classification | |---|---|---| -| `models.GCN.Edge_Network` | `model.type: root_gnn` | implementation-only | +| historical `Edge_Network` | `model.type: root_gnn` | implementation-only | | `args.hid_size`, `out_size`, `n_layers`, `n_proc_steps`, `dropout` | corresponding `model.*` fields | scientific | | `tracking[:,0]` | `EventMetadata.fold` | representation-only | | `tracking[:,1]` | `EventMetadata.weight` | representation-only | -| legacy batch size | `data.batch_size` | scientific | -| legacy fold selection | `data.split.*` and named metadata | scientific | +| historical batch size | `data.batch_size` | scientific | +| historical fold selection | `data.split.*` and named metadata | scientific | | input/output paths, workers, device | invocation/environment | environmental | diff --git a/validation/manifests/environments.json b/validation/manifests/environments.json index 251a4c41f37ba9a1a00ee9553491f11b7b3779b7..3d2bda1c56ec488adedf294d045d9bf9ccddee07 100644 --- a/validation/manifests/environments.json +++ b/validation/manifests/environments.json @@ -1,20 +1,11 @@ { - "legacy": { - "conda_environment": "dgl", - "python": "3.8.17", - "torch": "2.0.1", - "dgl": "1.1.1+cu118", - "uproot": "5.3.7", - "awkward": "2.6.7", - "device": "cpu" - }, - "rewrite": { + "canonical": { "python": "3.12.13", "torch": "2.2.2+cu121", "dgl": "2.4.0+cu121", "device": "cpu" }, - "checkpoint": "legacy/root_gnn_dgl/Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_71.pt", + "checkpoint": "Pretrained_GNN/multiclass_pretrained_model_12/model_epoch_71.pt", "seed_policy": "fixed checkpoint; dropout=0; explicit torch seed 20260818 for transfer head", - "source_identity": "working-tree validation campaign; legacy tree unmodified" + "source_identity": "frozen root-gnn-parity-baseline campaign" } diff --git a/validation/manifests/legacy_config.yaml b/validation/manifests/legacy_config.yaml deleted file mode 100644 index d3127d49301a95f7e1a8f8e89838ec4151eb3d05..0000000000000000000000000000000000000000 --- a/validation/manifests/legacy_config.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# Portable scientific settings from the active legacy pretraining workflow. -source: legacy/root_gnn_dgl/configs/stats_100K/pretraining_multiclass.yaml -model: {type: root_gnn, hid_size: 64, in_size: 7, out_size: 12, n_layers: 4, n_proc_steps: 4, dropout: 0.0} -data: {tree_name: output, batch_size: 1024, fold_count: 4, feature_schema: [pt, eta, phi, energy, btag, charge, node_type]} diff --git a/validation/run_full_validation.py b/validation/run_full_validation.py index 92b3d049de7b70c0a4ae4fc32d4127450646d3e6..f7097ab2538450279a4fc5019ed62794fbe9dbda 100644 --- a/validation/run_full_validation.py +++ b/validation/run_full_validation.py @@ -49,14 +49,14 @@ def _smoke_artifact() -> ValidationArtifact: logits=np.asarray([[0.25]], dtype=np.float32), scores=np.asarray([[0.562]], dtype=np.float32), predictions=np.asarray([1]), - manifest={"mode": "smoke", "legacy": "not_run"}, + manifest={"mode": "smoke", "reference": "not_run"}, ) def main() -> int: parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--legacy-artifact", type=Path) - parser.add_argument("--rewrite-artifact", type=Path) + parser.add_argument("--reference-artifact", type=Path) + parser.add_argument("--candidate-artifact", type=Path) parser.add_argument( "--output", type=Path, default=Path("validation_output/reports") ) @@ -69,9 +69,11 @@ def main() -> int: save_artifact(_smoke_artifact(), path) print(f"wrote smoke artifact: {path}") return 0 - if not args.legacy_artifact or not args.rewrite_artifact: - parser.error("comparison requires --legacy-artifact and --rewrite-artifact") - report = compare_artifacts(args.legacy_artifact, args.rewrite_artifact) + if not args.reference_artifact or not args.candidate_artifact: + parser.error( + "comparison requires --reference-artifact and --candidate-artifact" + ) + report = compare_artifacts(args.reference_artifact, args.candidate_artifact) write_reports(report, args.output) print( json.dumps( diff --git a/validation/run_public_validation.py b/validation/run_public_validation.py index 6f18e69e46101d4440c7de33f314a20e6dfad8f8..0e0d312a55c75311ddb1591fa130f5f691174dbe 100644 --- a/validation/run_public_validation.py +++ b/validation/run_public_validation.py @@ -45,7 +45,7 @@ def main() -> int: args = parser.parse_args() fixture = ensure_fixture(args.fixture, download=not args.no_download) - golden = Path(__file__).parent / "golden" / "testing" / "legacy" + golden = Path(__file__).parent / "golden" / "testing" / "reference" if not (golden / "manifest.json").is_file(): raise FileNotFoundError(f"golden reference is missing: {golden}") rewrite = args.output / "rewrite" diff --git a/validation/train_step.py b/validation/train_step.py index 9227d8ec95073d8587ad62863090060929643261..6e70502d658370c8fa5f6a67cb2b5b3ea0532fac 100644 --- a/validation/train_step.py +++ b/validation/train_step.py @@ -49,9 +49,6 @@ def _flat_optimizer_state(model, optimizer, key): def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument( - "--implementation", choices=("legacy", "rewrite"), required=True - ) parser.add_argument("--artifact", type=Path, required=True) parser.add_argument("--checkpoint", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) @@ -63,21 +60,14 @@ def main() -> int: graphs = [_graph(artifact, index) for index in range(count)] graph = dgl.batch(graphs) empty_globals = torch.empty((count, 0), dtype=torch.float32) - if args.implementation == "legacy": - from models.GCN import Edge_Network - - model = Edge_Network(graphs[0], empty_globals[:1], 64, 12, 4, 4, dropout=0.0) - payload = torch.load(args.checkpoint, map_location="cpu") - model.load_state_dict(payload["model_state_dict"]) - else: - from gnn4colliders.models.root_gnn import ( - EdgeNetwork, - load_legacy_edge_network_state_dict, - ) + from gnn4colliders.models.root_gnn import ( + EdgeNetwork, + load_legacy_edge_network_state_dict, + ) - model = EdgeNetwork(graphs[0], empty_globals[:1], 64, 12, 4, 4, dropout=0.0) - payload = torch.load(args.checkpoint, map_location="cpu", weights_only=False) - load_legacy_edge_network_state_dict(model, payload) + model = EdgeNetwork(graphs[0], empty_globals[:1], 64, 12, 4, 4, dropout=0.0) + payload = torch.load(args.checkpoint, map_location="cpu", weights_only=False) + load_legacy_edge_network_state_dict(model, payload) model.train() labels = torch.from_numpy(artifact.labels[:count]).to(torch.long) weights = torch.from_numpy(artifact.weights[:count]).to(torch.float32) diff --git a/validation/transfer.py b/validation/transfer.py index f8cf2e9485845e8c91220db94840b8d2004edf69..7229401da13b4ec5f568eaaa544dcf87b850cd54 100644 --- a/validation/transfer.py +++ b/validation/transfer.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Compare legacy/new transfer-learning forward with a fixed binary head.""" +"""Run canonical ROOT-GNN transfer-learning forward with a fixed binary head.""" from __future__ import annotations @@ -13,24 +13,9 @@ import torch from validation.artifacts import load_artifact from validation.forward import _graph -LEGACY_CONFIG = { - "module": "models.GCN", - "class": "Edge_Network", - "args": { - "hid_size": 64, - "out_size": 12, - "n_layers": 4, - "n_proc_steps": 4, - "dropout": 0.0, - }, -} - def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument( - "--implementation", choices=("legacy", "rewrite"), required=True - ) parser.add_argument("--artifact", type=Path, required=True) parser.add_argument("--checkpoint", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) @@ -42,34 +27,19 @@ def main() -> int: graphs = [_graph(artifact, index) for index in range(count)] batch_graph = dgl.batch(graphs) empty_globals = torch.empty((1, 0), dtype=torch.float32) - if args.implementation == "legacy": - from models.GCN import Transferred_Learning_Finetuning - - model = Transferred_Learning_Finetuning( - str(args.checkpoint), - LEGACY_CONFIG, - graphs[0], - empty_globals, - 64, - 1, - 4, - 4, - dropout=0.0, - frozen_pretraining=not args.trainable_backbone, - ) - classifier = model.classify - else: - from gnn4colliders.models.root_gnn import EdgeNetwork, FineTunedEdgeNetwork - - backbone = EdgeNetwork(graphs[0], empty_globals, 64, 12, 4, 4, dropout=0.0) - payload = torch.load(args.checkpoint, map_location="cpu", weights_only=False) - from gnn4colliders.models.root_gnn import load_legacy_edge_network_state_dict + from gnn4colliders.models.root_gnn import ( + EdgeNetwork, + FineTunedEdgeNetwork, + load_legacy_edge_network_state_dict, + ) - load_legacy_edge_network_state_dict(backbone, payload) - model = FineTunedEdgeNetwork( - backbone, 1, freeze_backbone=not args.trainable_backbone - ) - classifier = model.classifier + backbone = EdgeNetwork(graphs[0], empty_globals, 64, 12, 4, 4, dropout=0.0) + payload = torch.load(args.checkpoint, map_location="cpu", weights_only=False) + load_legacy_edge_network_state_dict(backbone, payload) + model = FineTunedEdgeNetwork( + backbone, 1, freeze_backbone=not args.trainable_backbone + ) + classifier = model.classifier torch.manual_seed(20260818) classifier.load_state_dict(torch.nn.Linear(64, 1).state_dict()) model.eval()