Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jammy flow integration #728

Merged
merged 36 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
6a06d65
revert changes on main
RasmusOrsoe May 20, 2024
8f7ea52
Merge branch 'graphnet-team:main' into main
RasmusOrsoe May 24, 2024
c1b4099
add NormalizingFlow
RasmusOrsoe May 28, 2024
1e14f54
check
RasmusOrsoe May 28, 2024
0c135b7
hooks
RasmusOrsoe May 28, 2024
ce1223d
hooks
RasmusOrsoe May 28, 2024
8886376
hooks
RasmusOrsoe May 28, 2024
9d8b560
black
RasmusOrsoe May 28, 2024
dbb02c4
black
RasmusOrsoe May 28, 2024
9b90af4
black
RasmusOrsoe May 28, 2024
382651f
black
RasmusOrsoe May 28, 2024
e299aac
polish dtype assignment
RasmusOrsoe May 29, 2024
9c0ad64
add warning
RasmusOrsoe May 29, 2024
f53bc1d
add check for flow package
RasmusOrsoe May 29, 2024
a0afcc3
expand docstrings
RasmusOrsoe May 29, 2024
845293d
update workflow to install jammy_flows
RasmusOrsoe May 29, 2024
a71765c
add example
RasmusOrsoe May 29, 2024
eb15932
check in example
RasmusOrsoe May 29, 2024
4150f14
update example
RasmusOrsoe May 29, 2024
8116c29
update example
RasmusOrsoe May 29, 2024
d51f02c
actions
RasmusOrsoe May 29, 2024
210ef28
update icetray action
RasmusOrsoe May 29, 2024
c32ffd1
update install action
RasmusOrsoe May 29, 2024
59870dd
fix `has_jammy_flows_package`
RasmusOrsoe May 29, 2024
b953ff4
polish
RasmusOrsoe May 29, 2024
5ab298a
add doc string
RasmusOrsoe May 29, 2024
3bc33a3
update docstring
RasmusOrsoe May 29, 2024
b74d9b2
update installation instruction
RasmusOrsoe May 29, 2024
49576cb
add normalization
RasmusOrsoe Jul 13, 2024
e3188e3
Merge branch 'jammy_flow_integration' into main
RasmusOrsoe Jul 20, 2024
7f472cf
Merge pull request #29 from RasmusOrsoe/main
RasmusOrsoe Jul 20, 2024
53eefb4
increase batch size to avoid single event batch
RasmusOrsoe Aug 6, 2024
dfee76d
revert change
RasmusOrsoe Aug 6, 2024
dd41659
increase batch size
RasmusOrsoe Aug 6, 2024
ecd1627
Merge branch 'jammy_flow_integration' of https://github.com/RasmusOrs…
RasmusOrsoe Sep 16, 2024
9aa6936
only initialize if training
RasmusOrsoe Sep 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/install/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ runs:
run: |
echo requirements/torch_${{ inputs.hardware }}.txt ${{ env.PIP_FLAGS }} .${{ inputs.extras }}
pip install -r requirements/torch_${{ inputs.hardware }}.txt ${{ env.PIP_FLAGS }} .${{ inputs.extras }}
pip install git+https://github.com/thoglu/jammy_flows.git
shell: bash
10 changes: 10 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ jobs:
uses: ./.github/actions/install
with:
editable: true
- name: Print packages in pip
run: |
pip show torch
pip show torch-geometric
pip show torch-cluster
pip show torch-sparse
pip show torch-scatter
pip show jammy_flows
- name: Run unit tests and generate coverage report
run: |
coverage run --source=graphnet -m pytest tests/ --ignore=tests/examples/04_training --ignore=tests/utilities
Expand Down Expand Up @@ -110,6 +118,8 @@ jobs:
pip show torch-sparse
pip show torch-scatter
pip show numpy


- name: Run unit tests and generate coverage report
run: |
set -o pipefail # To propagate exit code from pytest
Expand Down
4 changes: 4 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,20 @@ repos:
rev: 4.0.1
hooks:
- id: flake8
language_version: python3
- repo: https://github.com/pycqa/docformatter
rev: v1.5.0
hooks:
- id: docformatter
language_version: python3
- repo: https://github.com/pycqa/pydocstyle
rev: 6.1.1
hooks:
- id: pydocstyle
language_version: python3
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.982
hooks:
- id: mypy
args: [--follow-imports=silent, --disallow-untyped-defs, --disallow-incomplete-defs, --disallow-untyped-calls]
language_version: python3
10 changes: 5 additions & 5 deletions docs/source/installation/quick-start.html
Original file line number Diff line number Diff line change
Expand Up @@ -107,20 +107,20 @@
}

if (os == "linux" && cuda != "cpu" && torch != "no_torch"){
$("#command pre").text(`git clone https://github.com/graphnet-team/graphnet.git\ncd graphnet\n\npip install -r requirements/torch_${$("#command").attr("cuda")}.txt -e .[torch,develop]`);
$("#command pre").text(`git clone https://github.com/graphnet-team/graphnet.git\ncd graphnet\n\npip install -r requirements/torch_${$("#command").attr("cuda")}.txt -e .[torch,develop]\n\n#Optionally, install jammy_flows for normalizing flow support:\npip install git+https://github.com/thoglu/jammy_flows.git`);
}
else if (os == "linux" && cuda == "cpu" && torch != "no_torch"){
$("#command pre").text(`git clone https://github.com/graphnet-team/graphnet.git\ncd graphnet\n\npip install -r requirements/torch_${$("#command").attr("cuda")}.txt -e .[torch,develop]`);
$("#command pre").text(`git clone https://github.com/graphnet-team/graphnet.git\ncd graphnet\n\npip install -r requirements/torch_${$("#command").attr("cuda")}.txt -e .[torch,develop]\n\n#Optionally, install jammy_flows for normalizing flow support:\npip install git+https://github.com/thoglu/jammy_flows.git`);
}
else if (os == "linux" && cuda == "cpu" && torch == "no_torch"){
$("#command pre").text(`# Installations without PyTorch are intended for file conversion only\ngit clone https://github.com/graphnet-team/graphnet.git\ncd graphnet\n\npip install -r requirements/torch_${$("#command").attr("cuda")}.txt -e .[develop]`);
$("#command pre").text(`# Installations without PyTorch are intended for file conversion only\ngit clone https://github.com/graphnet-team/graphnet.git\ncd graphnet\n\npip install -r requirements/torch_${$("#command").attr("cuda")}.txt -e .[develop]\n\n#Optionally, install jammy_flows for normalizing flow support:\npip install git+https://github.com/thoglu/jammy_flows.git`);
}

if (os == "macos" && cuda == "cpu" && torch != "no_torch"){
$("#command pre").text(`git clone https://github.com/graphnet-team/graphnet.git\ncd graphnet\n\npip install -r requirements/torch_macos.txt -e .[torch,develop]`);
$("#command pre").text(`git clone https://github.com/graphnet-team/graphnet.git\ncd graphnet\n\npip install -r requirements/torch_macos.txt -e .[torch,develop]\n\n#Optionally, install jammy_flows for normalizing flow support:\npip install git+https://github.com/thoglu/jammy_flows.git`);
}
if (os == "macos" && cuda == "cpu" && torch == "no_torch"){
$("#command pre").text(`# Installations without PyTorch are intended for file conversion only\ngit clone https://github.com/graphnet-team/graphnet.git\ncd graphnet\n\npip install -r requirements/torch_macos.txt -e .[develop]`);
$("#command pre").text(`# Installations without PyTorch are intended for file conversion only\ngit clone https://github.com/graphnet-team/graphnet.git\ncd graphnet\n\npip install -r requirements/torch_macos.txt -e .[develop]\n\n#Optionally, install jammy_flows for normalizing flow support:\npip install git+https://github.com/thoglu/jammy_flows.git`);
}
}

Expand Down
235 changes: 235 additions & 0 deletions examples/04_training/07_train_normalizing_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
"""Example of training a conditional NormalizingFlow."""

import os
from typing import Any, Dict, List, Optional

from pytorch_lightning.loggers import WandbLogger
import torch
from torch.optim.adam import Adam

from graphnet.constants import EXAMPLE_DATA_DIR, EXAMPLE_OUTPUT_DIR
from graphnet.data.constants import FEATURES, TRUTH
from graphnet.models.detector.prometheus import Prometheus
from graphnet.models.gnn import DynEdge
from graphnet.models.graphs import KNNGraph
from graphnet.training.callbacks import PiecewiseLinearLR
from graphnet.training.utils import make_train_validation_dataloader
from graphnet.utilities.argparse import ArgumentParser
from graphnet.utilities.logging import Logger
from graphnet.utilities.imports import has_jammy_flows_package

# Make sure the jammy flows is installed
try:
assert has_jammy_flows_package()
from graphnet.models import NormalizingFlow
except AssertionError:
raise AssertionError(
"This example requires the package`jammy_flow` "
" to be installed. It appears that the package is "
" not installed. Please install the package."
)

# Constants
features = FEATURES.PROMETHEUS
truth = TRUTH.PROMETHEUS


def main(
path: str,
pulsemap: str,
target: str,
truth_table: str,
gpus: Optional[List[int]],
max_epochs: int,
early_stopping_patience: int,
batch_size: int,
num_workers: int,
wandb: bool = False,
) -> None:
"""Run example."""
# Construct Logger
logger = Logger()

# Initialise Weights & Biases (W&B) run
if wandb:
# Make sure W&B output directory exists
wandb_dir = "./wandb/"
os.makedirs(wandb_dir, exist_ok=True)
wandb_logger = WandbLogger(
project="example-script",
entity="graphnet-team",
save_dir=wandb_dir,
log_model=True,
)

logger.info(f"features: {features}")
logger.info(f"truth: {truth}")

# Configuration
config: Dict[str, Any] = {
"path": path,
"pulsemap": pulsemap,
"batch_size": batch_size,
"num_workers": num_workers,
"target": target,
"early_stopping_patience": early_stopping_patience,
"fit": {
"gpus": gpus,
"max_epochs": max_epochs,
},
}

archive = os.path.join(EXAMPLE_OUTPUT_DIR, "train_model_without_configs")
run_name = "dynedge_{}_example".format(config["target"])
if wandb:
# Log configuration to W&B
wandb_logger.experiment.config.update(config)

# Define graph representation
graph_definition = KNNGraph(detector=Prometheus())

(
training_dataloader,
validation_dataloader,
) = make_train_validation_dataloader(
db=config["path"],
graph_definition=graph_definition,
pulsemaps=config["pulsemap"],
features=features,
truth=truth,
batch_size=config["batch_size"],
num_workers=config["num_workers"],
truth_table=truth_table,
selection=None,
)

# Building model

backbone = DynEdge(
nb_inputs=graph_definition.nb_outputs,
global_pooling_schemes=["min", "max", "mean", "sum"],
)

model = NormalizingFlow(
graph_definition=graph_definition,
backbone=backbone,
optimizer_class=Adam,
target_labels=config["target"],
optimizer_kwargs={"lr": 1e-03, "eps": 1e-03},
scheduler_class=PiecewiseLinearLR,
scheduler_kwargs={
"milestones": [
0,
len(training_dataloader) / 2,
len(training_dataloader) * config["fit"]["max_epochs"],
],
"factors": [1e-2, 1, 1e-02],
},
scheduler_config={
"interval": "step",
},
)

# Training model
model.fit(
training_dataloader,
validation_dataloader,
early_stopping_patience=config["early_stopping_patience"],
logger=wandb_logger if wandb else None,
**config["fit"],
)

# Get predictions
additional_attributes = model.target_labels
assert isinstance(additional_attributes, list) # mypy

results = model.predict_as_dataframe(
validation_dataloader,
additional_attributes=additional_attributes + ["event_no"],
gpus=config["fit"]["gpus"],
)

# Save predictions and model to file
db_name = path.split("/")[-1].split(".")[0]
path = os.path.join(archive, db_name, run_name)
logger.info(f"Writing results to {path}")
os.makedirs(path, exist_ok=True)

# Save results as .csv
results.to_csv(f"{path}/results.csv")

# Save full model (including weights) to .pth file - not version safe
# Note: Models saved as .pth files in one version of graphnet
# may not be compatible with a different version of graphnet.
model.save(f"{path}/model.pth")

# Save model config and state dict - Version safe save method.
# This method of saving models is the safest way.
model.save_state_dict(f"{path}/state_dict.pth")
model.save_config(f"{path}/model_config.yml")


if __name__ == "__main__":

# Parse command-line arguments
parser = ArgumentParser(
description="""
Train conditional NormalizingFlow without the use of config files.
"""
)

parser.add_argument(
"--path",
help="Path to dataset file (default: %(default)s)",
default=f"{EXAMPLE_DATA_DIR}/sqlite/prometheus/prometheus-events.db",
)

parser.add_argument(
"--pulsemap",
help="Name of pulsemap to use (default: %(default)s)",
default="total",
)

parser.add_argument(
"--target",
help=(
"Name of feature to use as regression target (default: "
"%(default)s)"
),
default="total_energy",
)

parser.add_argument(
"--truth-table",
help="Name of truth table to be used (default: %(default)s)",
default="mc_truth",
)

parser.with_standard_arguments(
"gpus",
("max-epochs", 1),
"early-stopping-patience",
("batch-size", 50),
"num-workers",
)

parser.add_argument(
"--wandb",
action="store_true",
help="If True, Weights & Biases are used to track the experiment.",
)

args, unknown = parser.parse_known_args()

main(
args.path,
args.pulsemap,
args.target,
args.truth_table,
args.gpus,
args.max_epochs,
args.early_stopping_patience,
args.batch_size,
args.num_workers,
args.wandb,
)
6 changes: 4 additions & 2 deletions src/graphnet/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
existing, purpose-built components and chain them together to form a complete
GNN
"""


from graphnet.utilities.imports import has_jammy_flows_package
from .model import Model
from .standard_model import StandardModel
from .standard_averaged_model import StandardAveragedModel

if has_jammy_flows_package():
from .normalizing_flow import NormalizingFlow
5 changes: 4 additions & 1 deletion src/graphnet/models/easy_model.py
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these changes unrelated to jammy flows?

Copy link
Collaborator

@Aske-Rosted Aske-Rosted Aug 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reread the minor changes and these changes are described there, you can disregard this question.

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from pytorch_lightning.loggers import Logger as LightningLogger

from graphnet.training.callbacks import ProgressBar
from graphnet.models.graphs import GraphDefinition
from graphnet.models.model import Model
from graphnet.models.task import StandardLearnedTask

Expand Down Expand Up @@ -292,6 +291,7 @@ def predict(
dataloader: DataLoader,
gpus: Optional[Union[List[int], int]] = None,
distribution_strategy: Optional[str] = "auto",
**trainer_kwargs: Any,
) -> List[Tensor]:
"""Return predictions for `dataloader`."""
self.inference()
Expand All @@ -305,6 +305,7 @@ def predict(
gpus=gpus,
distribution_strategy=distribution_strategy,
callbacks=callbacks,
**trainer_kwargs,
)

predictions_list = inference_trainer.predict(self, dataloader)
Expand All @@ -325,6 +326,7 @@ def predict_as_dataframe(
additional_attributes: Optional[List[str]] = None,
gpus: Optional[Union[List[int], int]] = None,
distribution_strategy: Optional[str] = "auto",
**trainer_kwargs: Any,
) -> pd.DataFrame:
"""Return predictions for `dataloader` as a DataFrame.

Expand Down Expand Up @@ -357,6 +359,7 @@ def predict_as_dataframe(
dataloader=dataloader,
gpus=gpus,
distribution_strategy=distribution_strategy,
**trainer_kwargs,
)
predictions = (
torch.cat(predictions_torch, dim=1).detach().cpu().numpy()
Expand Down
Loading
Loading