diff --git a/_modules/graphnet/data/dataclasses.html b/_modules/graphnet/data/dataclasses.html index 20c423cf1..a93a3e455 100644 --- a/_modules/graphnet/data/dataclasses.html +++ b/_modules/graphnet/data/dataclasses.html @@ -324,7 +324,7 @@

Source code for graphnet.data.dataclasses

 """Module containing experiment-specific dataclasses."""
 
-
+from typing import List, Any
 from dataclasses import dataclass
 
 
@@ -335,6 +335,19 @@ 

Source code for graphnet.d i3_file: str gcd_file: str

+ + +
+[docs] +@dataclass +class Settings: + """Dataclass for workers in I3Deployer.""" + + i3_files: List[str] + gcd_file: str + output_folder: str + modules: List[Any]
+ diff --git a/_modules/graphnet/data/dataset/dataset.html b/_modules/graphnet/data/dataset/dataset.html index 442af1a79..84a3f8d92 100644 --- a/_modules/graphnet/data/dataset/dataset.html +++ b/_modules/graphnet/data/dataset/dataset.html @@ -418,6 +418,21 @@

Source code for graphn +
+[docs] +def parse_labels(cfg: dict) -> Dict[str, Label]: + """Construct Label from DatasetConfig.""" + assert cfg["labels"] is not None + + labels = {} + for key in cfg["labels"].keys(): + labels[key] = load_module(cfg["labels"][key]["class_name"])( + **cfg["labels"][key]["arguments"] + ) + return labels
+ + +
[docs] class Dataset( @@ -468,6 +483,8 @@

Source code for graphn cfg = source.dict() if cfg["graph_definition"] is not None: cfg["graph_definition"] = parse_graph_definition(cfg) + if cfg["labels"] is not None: + cfg["labels"] = parse_labels(cfg) return source._dataset_class(**cfg)

@@ -554,6 +571,7 @@

Source code for graphn loss_weight_column: Optional[str] = None, loss_weight_default_value: Optional[float] = None, seed: Optional[int] = None, + labels: Optional[Dict[str, Any]] = None, ): """Construct Dataset. @@ -600,6 +618,7 @@

Source code for graphn `"10000 random events ~ event_no % 5 > 0"` or `"20% random events ~ event_no % 5 > 0"`). graph_definition: Method that defines the graph representation. + labels: Dictionary of labels to be added to the dataset. """ # Base class constructor super().__init__(name=__name__, class_name=self.__class__.__name__) @@ -624,6 +643,7 @@

Source code for graphn self._truth_table = truth_table self._loss_weight_default_value = loss_weight_default_value self._graph_definition = deepcopy(graph_definition) + self._labels = labels if node_truth is not None: assert isinstance(node_truth_table, str) @@ -673,6 +693,10 @@

Source code for graphn seed=seed, ) + if self._labels is not None: + for key in self._labels.keys(): + self.add_label(self._labels[key]) + # Implementation-specific initialisation. self._init() diff --git a/_modules/graphnet/deployment/deployer.html b/_modules/graphnet/deployment/deployer.html new file mode 100644 index 000000000..ea737ce89 --- /dev/null +++ b/_modules/graphnet/deployment/deployer.html @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + graphnet.deployment.deployer — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +

Source code for graphnet.deployment.deployer

+"""Contains the graphnet deployment module."""
+import random
+from abc import abstractmethod, ABC
+import multiprocessing
+from typing import TYPE_CHECKING, List, Union, Sequence, Any
+import time
+
+from graphnet.utilities.imports import has_torch_package
+from .deployment_module import DeploymentModule
+from graphnet.utilities.logging import Logger
+
+if has_torch_package or TYPE_CHECKING:
+    import torch
+
+
+
+[docs] +class Deployer(ABC, Logger): + """A generic baseclass for applying `DeploymentModules` to analysis files. + + Modules are applied in the order that they appear in `modules`. + """ + + @abstractmethod + def _process_files( + self, + settings: Any, + ) -> None: + """Process a single file. + + If n_workers > 1, this function is run in parallel n_worker times. Each + worker will loop over an allocated set of files. + """ + raise NotImplementedError + + @abstractmethod + def _prepare_settings( + self, input_files: List[str], output_folder: str + ) -> List[Any]: + """Produce a list of inputs for each worker. + + This function must produce and return a list of arguments to each + worker. + """ + raise NotImplementedError + + def __init__( + self, + modules: Union[DeploymentModule, Sequence[DeploymentModule]], + n_workers: int = 1, + ) -> None: + """Initialize `Deployer`. + + Will apply `DeploymentModules` to files in the order in which they + appear in `modules`. Each module is run independently. + + Args: + modules: List of `DeploymentModules`. + Order of appearence in the list determines order + of deployment. + n_workers: Number of workers. The deployer will divide the number + of input files across workers. Defaults to 1. + """ + super().__init__(name=__name__, class_name=self.__class__.__name__) + # This makes sure that one worker cannot access more + # than 1 core's worth of compute. + + if torch.get_num_interop_threads() > 1: + torch.set_num_interop_threads(1) + if torch.get_num_threads() > 1: + torch.set_num_threads(1) + + # Check + if isinstance(modules, list): + self._modules = modules + else: + self._modules = [modules] + + # Member Variables + self._n_workers = n_workers + + def _launch_jobs(self, settings: List[Any]) -> None: + """Will launch jobs in parallel if n_workers > 1, else run on main.""" + if self._n_workers > 1: + processes = [] + for i in range(self._n_workers): + processes.append( + multiprocessing.Process( + target=self._process_files, + args=[settings[i]], # type: ignore + ) + ) + + for process in processes: + process.start() + + for process in processes: + process.join() + else: + self._process_files(settings[0]) + +
+[docs] + def run( + self, + input_files: Union[List[str], str], + output_folder: str, + ) -> None: + """Apply `modules` to input files. + + Args: + input_files: Path(s) to i3 file(s) that you wish to + apply the graphnet modules to. + output_folder: The output folder to which the i3 files are written. + """ + start_time = time.time() + if isinstance(input_files, list): + random.shuffle(input_files) + else: + input_files = [input_files] + settings = self._prepare_settings( + input_files=input_files, output_folder=output_folder + ) + + assert len(settings) == self._n_workers + + self.info( + f"""processing {len(input_files)} files \n + using {self._n_workers} workers""" + ) + self._launch_jobs(settings) + self.info( + f"""Processing {len(input_files)} files was completed in \n + {time.time() - start_time} seconds using {self._n_workers} cores.""" + )
+
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/_modules/graphnet/deployment/deployment_module.html b/_modules/graphnet/deployment/deployment_module.html new file mode 100644 index 000000000..812e10b3c --- /dev/null +++ b/_modules/graphnet/deployment/deployment_module.html @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + graphnet.deployment.deployment_module — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +

Source code for graphnet.deployment.deployment_module

+"""Class(es) for deploying GraphNeT models in icetray as I3Modules."""
+from abc import abstractmethod
+from typing import Any, List, Union, Dict
+
+import numpy as np
+from torch import Tensor
+from torch_geometric.data import Data, Batch
+
+from graphnet.models import Model
+from graphnet.utilities.config import ModelConfig
+from graphnet.utilities.logging import Logger
+
+
+
+[docs] +class DeploymentModule(Logger): + """Base DeploymentModule for GraphNeT. + + Contains standard methods for loading models doing inference with them. + Experiment-specific implementations may overwrite methods and should define + `__call__`. + """ + + def __init__( + self, + model_config: Union[ModelConfig, str], + state_dict: Union[Dict[str, Tensor], str], + device: str = "cpu", + prediction_columns: Union[List[str], None] = None, + ): + """Construct DeploymentModule. + + Arguments: + model_config: A model configuration file. + state_dict: A state dict for the model. + device: The computational device to use. Defaults to "cpu". + prediction_columns: Column names for each column in model output. + """ + super().__init__(name=__name__, class_name=self.__class__.__name__) + # Set Member Variables + self.model = self._load_model( + model_config=model_config, state_dict=state_dict + ) + + self.prediction_columns = self._resolve_prediction_columns( + prediction_columns + ) + + # Set model to inference mode. + self.model.inference() + + # Move model to device + self.model.to(device) + + @abstractmethod + def __call__(self, input_data: Any) -> Any: + """Define here how the module acts on a file/data stream.""" + + def _load_model( + self, + model_config: Union[ModelConfig, str], + state_dict: Union[Dict[str, Tensor], str], + ) -> Model: + """Load `Model` from config and insert learned weights.""" + model = Model.from_config(model_config, trust=True) + model.load_state_dict(state_dict) + return model + + def _resolve_prediction_columns( + self, prediction_columns: Union[List[str], None] + ) -> List[str]: + if prediction_columns is not None: + if isinstance(prediction_columns, str): + prediction_columns = [prediction_columns] + else: + prediction_columns = prediction_columns + else: + prediction_columns = self.model.prediction_labels + return prediction_columns + + def _inference(self, data: Union[Data, Batch]) -> List[np.ndarray]: + """Apply model to a single event or batch of events `data`. + + Args: + data: A `Data` or ``Batch` object - + either a single output of a `GraphDefinition` or a batch of + them. + + Returns: + A List of numpy arrays, each representing the output from the + `Task`s that the model contains. + """ + # Perform inference + output = self.model(data=data) + # Loop over tasks in model and transform to numpy + for k in range(len(output)): + output[k] = output[k].detach().numpy() + return output
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/_modules/graphnet/deployment/i3modules/graphnet_module.html b/_modules/graphnet/deployment/icecube/cleaning_module.html similarity index 54% rename from _modules/graphnet/deployment/i3modules/graphnet_module.html rename to _modules/graphnet/deployment/icecube/cleaning_module.html index 5bb5c0a0e..90cb9682f 100644 --- a/_modules/graphnet/deployment/i3modules/graphnet_module.html +++ b/_modules/graphnet/deployment/icecube/cleaning_module.html @@ -60,7 +60,7 @@ - graphnet.deployment.i3modules.graphnet_module — graphnet documentation + graphnet.deployment.icecube.cleaning_module — graphnet documentation + + + + + + + + + + + + + + + + graphnet.deployment.icecube.inference_module — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +

Source code for graphnet.deployment.icecube.inference_module

+"""IceCube I3InferenceModule.
+
+Contains functionality for writing model predictions to i3 files.
+"""
+from typing import List, Union, Optional, TYPE_CHECKING, Dict, Any
+
+import numpy as np
+from torch_geometric.data import Data, Batch
+
+from graphnet.utilities.config import ModelConfig
+from graphnet.deployment import DeploymentModule
+from graphnet.data.extractors.icecube import I3FeatureExtractor
+from graphnet.utilities.imports import has_icecube_package
+
+if has_icecube_package() or TYPE_CHECKING:
+    from icecube.icetray import (
+        I3Frame,
+    )  # pyright: reportMissingImports=false
+    from icecube.dataclasses import (
+        I3Double,
+    )  # pyright: reportMissingImports=false
+
+
+
+[docs] +class I3InferenceModule(DeploymentModule): + """General class for inference on i3 frames.""" + + def __init__( + self, + pulsemap_extractor: Union[ + List[I3FeatureExtractor], I3FeatureExtractor + ], + model_config: Union[ModelConfig, str], + state_dict: str, + model_name: str, + gcd_file: str, + features: Optional[List[str]] = None, + prediction_columns: Optional[Union[List[str], None]] = None, + pulsemap: Optional[str] = None, + ): + """General class for inference on I3Frames (physics). + + Arguments: + pulsemap_extractor: The extractor used to extract the pulsemap. + model_config: The ModelConfig (or path to it) that summarizes the + model used for inference. + state_dict: Path to state_dict containing the learned weights. + model_name: The name used for the model. Will help define the + named entry in the I3Frame. E.g. "dynedge". + gcd_file: path to associated gcd file. + features: the features of the pulsemap that the model is expecting. + prediction_columns: column names for the predictions of the model. + Will help define the named entry in the I3Frame. + E.g. ['energy_reco']. Optional. + pulsemap: the pulsmap that the model is expecting as input. + """ + super().__init__( + model_config=model_config, + state_dict=state_dict, + prediction_columns=prediction_columns, + ) + # Checks + assert isinstance(gcd_file, str), "gcd_file must be string" + + # Set Member Variables + if isinstance(pulsemap_extractor, list): + self._i3_extractors = pulsemap_extractor + else: + self._i3_extractors = [pulsemap_extractor] + if features is None: + features = self.model._graph_definition._input_feature_names + self._graph_definition = self.model._graph_definition + self._pulsemap = pulsemap + self._gcd_file = gcd_file + self.model_name = model_name + self._features = features + + # Set GCD file for pulsemap extractor + for i3_extractor in self._i3_extractors: + i3_extractor.set_gcd(i3_file="", gcd_file=self._gcd_file) + + def __call__(self, frame: I3Frame) -> bool: + """Write predictions from model to frame.""" + # inference + data = self._create_data_representation(frame=frame) + predictions = self._apply_model(data=data) + + # Check dimensions of predictions and prediction columns + dim = self._check_dimensions(predictions=predictions) + + # Build Dictionary from predictions + data = self._create_dictionary(dim=dim, predictions=predictions) + + # Submit Dictionary to frame + frame = self._add_to_frame(frame=frame, data=data) + return True + + def _check_dimensions(self, predictions: np.ndarray) -> int: + if len(predictions.shape) > 1: + dim = predictions.shape[1] + else: + dim = len(predictions) + try: + assert dim == len(self.prediction_columns) + except AssertionError as e: + self.error( + f"predictions have shape {dim} but" + f"prediction columns have [{self.prediction_columns}]" + ) + raise e + + assert predictions.shape[0] == 1 + return dim + + def _create_dictionary( + self, dim: int, predictions: np.ndarray + ) -> Dict[str, Any]: + """Transform predictions into a dictionary.""" + data = {} + for i in range(dim): + try: + assert len(predictions[:, i]) == 1 + data[ + self.model_name + "_" + self.prediction_columns[i] + ] = I3Double(float(predictions[:, i][0])) + except IndexError: + data[ + self.model_name + "_" + self.prediction_columns[i] + ] = I3Double(predictions[0]) + return data + + def _apply_model(self, data: Data) -> np.ndarray: + """Apply model to `Data` and case-handling.""" + if data is not None: + predictions = self._inference(data) + if isinstance(predictions, list): + predictions = predictions[0] + self.warning( + f"{self.__class__.__name__} assumes one Task " + f"but got {len(predictions)}. Only the first will" + " be used." + ) + else: + self.warning( + "At least one event has no pulses " + " - padding {self.prediction_columns} with NaN." + ) + predictions = np.repeat( + [np.nan], len(self.prediction_columns) + ).reshape(-1, len(self.prediction_columns)) + return predictions + + def _create_data_representation(self, frame: I3Frame) -> Data: + """Process Physics I3Frame into graph.""" + # Extract features + input_features = self._extract_feature_array_from_frame(frame) + # Prepare graph data + if len(input_features) > 0: + data = self._graph_definition( + input_features=input_features, + input_feature_names=self._features, + ) + return Batch.from_data_list([data]) + else: + return None + + def _extract_feature_array_from_frame(self, frame: I3Frame) -> np.array: + """Apply the I3FeatureExtractors to the I3Frame. + + Arguments: + frame: Physics I3Frame (PFrame) + + Returns: + array with pulsemap + """ + features = None + for i3extractor in self._i3_extractors: + feature_dict = i3extractor(frame) + features_pulsemap = np.array( + [feature_dict[key] for key in self._features] + ).T + if features is None: + features = features_pulsemap + else: + features = np.concatenate( + (features, features_pulsemap), axis=0 + ) + return features + + def _add_to_frame(self, frame: I3Frame, data: Dict[str, Any]) -> I3Frame: + """Add every field in data to I3Frame. + + Arguments: + frame: I3Frame (physics) + data: Dictionary containing content that will be written to frame. + + Returns: + frame: Same I3Frame as input, but with the new entries + """ + assert isinstance( + data, dict + ), f"data must be of type dict. Got {type(data)}" + for key in data.keys(): + if key not in frame: + frame.Put(key, data[key]) + return frame
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/_modules/graphnet/models/components/embedding.html b/_modules/graphnet/models/components/embedding.html new file mode 100644 index 000000000..9e280dde3 --- /dev/null +++ b/_modules/graphnet/models/components/embedding.html @@ -0,0 +1,521 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + graphnet.models.components.embedding — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +

Source code for graphnet.models.components.embedding

+"""Classes for performing embedding of input data."""
+import torch
+import torch.nn as nn
+from torch.functional import Tensor
+
+from pytorch_lightning import LightningModule
+
+
+
+[docs] +class SinusoidalPosEmb(LightningModule): + """Sinusoidal positional embeddings module. + + This module is from the kaggle competition 2nd place solution (see + arXiv:2310.15674): It performs what is called Fourier encoding or it's used + in the Attention is all you need arXiv:1706.03762. It can be seen as a soft + digitization of the input data + """ + + def __init__( + self, + dim: int = 16, + n_freq: int = 10000, + scaled: bool = False, + ): + """Construct `SinusoidalPosEmb`. + + Args: + dim: Embedding dimension. + n_freq: Number of frequencies. + scaled: Whether or not to scale the output. + """ + super().__init__() + if dim % 2 != 0: + raise ValueError(f"dim has to be even. Got: {dim}") + self.scale = ( + nn.Parameter(torch.ones(1) * dim**-0.5) if scaled else 1.0 + ) + self.dim = dim + self.n_freq = torch.Tensor([n_freq]) + +
+[docs] + def forward(self, x: Tensor) -> Tensor: + """Forward pass.""" + device = x.device + half_dim = self.dim / 2 + emb = torch.log(self.n_freq.to(device=device)) / half_dim + emb = torch.exp(torch.arange(half_dim, device=device) * (-emb)) + emb = x.unsqueeze(-1) * emb.unsqueeze(0) + emb = torch.cat((torch.sin(emb), torch.cos(emb)), dim=-1) + return emb * self.scale
+
+ + + +
+[docs] +class FourierEncoder(LightningModule): + """Fourier encoder module. + + This module incorporates sinusoidal positional embeddings and auxiliary + embeddings to process input sequences and produce meaningful + representations. + """ + + def __init__( + self, + seq_length: int = 128, + output_dim: int = 384, + scaled: bool = False, + ): + """Construct `FourierEncoder`. + + Args: + seq_length: Dimensionality of the base sinusoidal positional + embeddings. + output_dim: Output dimensionality of the final projection. + scaled: Whether or not to scale the embeddings. + """ + super().__init__() + self.sin_emb = SinusoidalPosEmb(dim=seq_length, scaled=scaled) + self.aux_emb = nn.Embedding(2, seq_length // 2) + self.sin_emb2 = SinusoidalPosEmb(dim=seq_length // 2, scaled=scaled) + self.projection = nn.Sequential( + nn.Linear(6 * seq_length, 6 * seq_length), + nn.LayerNorm(6 * seq_length), + nn.GELU(), + nn.Linear(6 * seq_length, output_dim), + ) + +
+[docs] + def forward( + self, + x: Tensor, + seq_length: Tensor, + ) -> Tensor: + """Forward pass.""" + length = torch.log10(seq_length.to(dtype=x.dtype)) + x = torch.cat( + [ + self.sin_emb(4096 * x[:, :, :3]).flatten(-2), # pos + self.sin_emb(1024 * x[:, :, 4]), # charge + self.sin_emb(4096 * x[:, :, 3]), # time + self.aux_emb(x[:, :, 5].long()), # auxiliary + self.sin_emb2(length) + .unsqueeze(1) + .expand(-1, max(seq_length), -1), + ], + -1, + ) + x = self.projection(x) + return x
+
+ + + +
+[docs] +class SpacetimeEncoder(LightningModule): + """Spacetime encoder module.""" + + def __init__( + self, + seq_length: int = 32, + ): + """Construct `SpacetimeEncoder`. + + This module calculates space-time interval between each pair of events + and generates sinusoidal positional embeddings to be added to input + sequences. + + Args: + seq_length: Dimensionality of the sinusoidal positional embeddings. + """ + super().__init__() + self.sin_emb = SinusoidalPosEmb(dim=seq_length) + self.projection = nn.Linear(seq_length, seq_length) + +
+[docs] + def forward( + self, + x: Tensor, + # Lmax: Optional[int] = None, + ) -> Tensor: + """Forward pass.""" + pos = x[:, :, :3] + time = x[:, :, 3] + spacetime_interval = (pos[:, :, None] - pos[:, None, :]).pow(2).sum( + -1 + ) - ((time[:, :, None] - time[:, None, :]) * (3e4 / 500 * 3e-1)).pow(2) + four_distance = torch.sign(spacetime_interval) * torch.sqrt( + torch.abs(spacetime_interval) + ) + sin_emb = self.sin_emb(1024 * four_distance.clip(-4, 4)) + rel_attn = self.projection(sin_emb) + return rel_attn
+
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/_modules/graphnet/models/components/layers.html b/_modules/graphnet/models/components/layers.html index 80fbc5ec0..02ee5c87f 100644 --- a/_modules/graphnet/models/components/layers.html +++ b/_modules/graphnet/models/components/layers.html @@ -324,7 +324,7 @@

Source code for graphnet.models.components.layers

 """Class(es) implementing layers to be used in `graphnet` models."""
 
-from typing import Any, Callable, Optional, Sequence, Union, List, Tuple
+from typing import Any, Callable, Optional, Sequence, Union, List
 
 import torch
 from torch.functional import Tensor
@@ -333,8 +333,10 @@ 

Source code for gr from torch_geometric.typing import Adj, PairTensor from torch_geometric.nn.conv import MessagePassing from torch_geometric.nn.inits import reset +from torch_geometric.data import Data +import torch.nn as nn +from torch.nn.functional import linear from torch.nn.modules import TransformerEncoder, TransformerEncoderLayer -from torch.nn.modules.normalization import LayerNorm from torch_geometric.utils import to_dense_batch from pytorch_lightning import LightningModule @@ -473,13 +475,13 @@

Source code for gr """Construct `DynTrans`. Args: - nn: The MLP/torch.Module to be used within the `DynTrans`. layer_sizes: List of layer sizes to be used in `DynTrans`. aggr: Aggregation method to be used with `DynTrans`. features_subset: Subset of features in `Data.x` that should be used when dynamically performing the new graph clustering after the `EdgeConv` operation. Defaults to all features. - n_head: Number of heads to be used in the multiheadattention models. + n_head: Number of heads to be used in the multiheadattention + models. **kwargs: Additional features to be passed to `DynTrans`. """ # Check(s) @@ -495,17 +497,17 @@

Source code for gr ): if ix == 0: nb_in *= 3 # edgeConv1 - layers.append(torch.nn.Linear(nb_in, nb_out)) - layers.append(torch.nn.LeakyReLU()) + layers.append(nn.Linear(nb_in, nb_out)) + layers.append(nn.LeakyReLU()) d_model = nb_out # Base class constructor - super().__init__(nn=torch.nn.Sequential(*layers), aggr=aggr, **kwargs) + super().__init__(nn=nn.Sequential(*layers), aggr=aggr, **kwargs) # Additional member variables self.features_subset = features_subset - self.norm1 = LayerNorm(d_model, eps=1e-5) # lNorm + self.norm1 = nn.LayerNorm(d_model, eps=1e-5) # lNorm # Transformer layer(s) encoder_layer = TransformerEncoderLayer( @@ -541,6 +543,438 @@

Source code for gr return x

+ + +
+[docs] +class DropPath(LightningModule): + """Drop paths (Stochastic Depth) per sample.""" + + def __init__( + self, + drop_prob: float = 0.0, + ): + """Construct `DropPath`. + + Args: + drop_prob: Probability of dropping a path during training. + If 0.0, no paths are dropped. Defaults to None. + """ + super(DropPath, self).__init__() + self.drop_prob = drop_prob + +
+[docs] + def forward(self, x: Tensor) -> Tensor: + """Forward pass.""" + if self.drop_prob == 0.0 or not self.training: + return x + keep_prob = 1 - self.drop_prob + shape = (x.shape[0],) + (1,) * (x.ndim - 1) + random_tensor = x.new_empty(shape).bernoulli_(keep_prob) + if keep_prob > 0.0: + random_tensor.div_(keep_prob) + return x * random_tensor
+ + +
+[docs] + def extra_repr(self) -> str: + """Return extra representation of the module.""" + return "p={}".format(self.drop_prob)
+
+ + + +
+[docs] +class Mlp(LightningModule): + """Multi-Layer Perceptron (MLP) module.""" + + def __init__( + self, + in_features: int, + hidden_features: Optional[int] = None, + out_features: Optional[int] = None, + activation: nn.Module = nn.GELU, + dropout_prob: float = 0.0, + ): + """Construct `Mlp`. + + Args: + in_features: Number of input features. + hidden_features: Number of hidden features. Defaults to None. + If None, it is set to the value of `in_features`. + out_features: Number of output features. Defaults to None. + If None, it is set to the value of `in_features`. + activation: Activation layer. Defaults to `nn.GELU`. + dropout_prob: Dropout probability. Defaults to 0.0. + """ + super().__init__() + if in_features <= 0: + raise ValueError( + f"in_features must be greater than 0, got in_features " + f"{in_features} instead" + ) + out_features = out_features or in_features + hidden_features = hidden_features or in_features + self.input_projection = nn.Linear(in_features, hidden_features) + self.activation = activation() + self.output_projection = nn.Linear(hidden_features, out_features) + self.dropout = nn.Dropout(dropout_prob) + +
+[docs] + def forward(self, x: Tensor) -> Tensor: + """Forward pass.""" + x = self.input_projection(x) + x = self.activation(x) + x = self.output_projection(x) + x = self.dropout(x) + return x
+
+ + + +
+[docs] +class Block_rel(LightningModule): + """Implementation of BEiTv2 Block.""" + + def __init__( + self, + input_dim: int, + num_heads: int, + mlp_ratio: float = 4.0, + qkv_bias: bool = False, + qk_scale: Optional[float] = None, + dropout: float = 0.0, + attn_drop: float = 0.0, + drop_path: float = 0.0, + init_values: Optional[float] = None, + activation: nn.Module = nn.GELU, + norm_layer: nn.Module = nn.LayerNorm, + attn_head_dim: Optional[int] = None, + ): + """Construct 'Block_rel'. + + Args: + input_dim: Dimension of the input tensor. + num_heads: Number of attention heads to use in the `Attention_rel` + layer. + mlp_ratio: Ratio of the hidden size of the feedforward network to + the input size in the `Mlp` layer. + qkv_bias: Whether or not to include bias terms in the query, key, + and value matrices in the `Attention_rel` layer. + qk_scale: Scaling factor for the dot product of the query and key + matrices in the `Attention_rel` layer. + dropout: Dropout probability to use in the `Mlp` layer. + attn_drop: Dropout probability to use in the `Attention_rel` layer. + drop_path: Probability of applying drop path regularization to the + output of the layer. + init_values: Initial value to use for the `gamma_1` and `gamma_2` + parameters if not `None`. + activation: Activation function to use in the `Mlp` layer. + norm_layer: Normalization layer to use. + attn_head_dim: Dimension of the attention head outputs in the + `Attention_rel` layer. + """ + super().__init__() + self.norm1 = norm_layer(input_dim) + self.attn = Attention_rel( + input_dim, + num_heads, + attn_drop=attn_drop, + qkv_bias=qkv_bias, + qk_scale=qk_scale, + attn_head_dim=attn_head_dim, + ) + self.drop_path = ( + DropPath(drop_path) if drop_path > 0.0 else nn.Identity() + ) + self.norm2 = norm_layer(input_dim) + mlp_hidden_dim = int(input_dim * mlp_ratio) + self.mlp = Mlp( + in_features=input_dim, + hidden_features=mlp_hidden_dim, + activation=activation, + dropout_prob=dropout, + ) + + if init_values is not None: + self.gamma_1 = nn.Parameter( + init_values * torch.ones(input_dim), requires_grad=True + ) + self.gamma_2 = nn.Parameter( + init_values * torch.ones(input_dim), requires_grad=True + ) + else: + self.gamma_1, self.gamma_2 = None, None + +
+[docs] + def forward( + self, + x: Tensor, + key_padding_mask: Optional[Tensor] = None, + rel_pos_bias: Optional[Tensor] = None, + kv: Optional[Tensor] = None, + ) -> Tensor: + """Forward pass.""" + if self.gamma_1 is None: + xn = self.norm1(x) + kv = xn if kv is None else self.norm1(kv) + x = x + self.drop_path( + self.attn( + xn, + kv, + kv, + rel_pos_bias=rel_pos_bias, + key_padding_mask=key_padding_mask, + ) + ) + x = x + self.drop_path(self.mlp(self.norm2(x))) + else: + xn = self.norm1(x) + kv = xn if kv is None else self.norm1(kv) + x = x + self.drop_path( + self.gamma_1 + * self.drop_path( + self.attn( + xn, + kv, + kv, + rel_pos_bias=rel_pos_bias, + key_padding_mask=key_padding_mask, + ) + ) + ) + x = x + self.drop_path(self.gamma_2 * self.mlp(self.norm2(x))) + return x
+
+ + + +
+[docs] +class Attention_rel(LightningModule): + """Attention mechanism with relative position bias.""" + + def __init__( + self, + input_dim: int, + num_heads: int = 8, + qkv_bias: bool = False, + qk_scale: Optional[float] = None, + attn_drop: float = 0.0, + proj_drop: float = 0.0, + attn_head_dim: Optional[int] = None, + ): + """Construct 'Attention_rel'. + + Args: + input_dim: Dimension of the input tensor. + num_heads: the number of attention heads to use (default: 8) + qkv_bias: whether to add bias to the query, key, and value + projections. Defaults to False. + qk_scale: a scaling factor that multiplies the dot product of query + and key vectors. Defaults to None. If None, computed as + :math: `head_dim^(-1/2)`. + attn_drop: the dropout probability for the attention weights. + Defaults to 0.0. + proj_drop: the dropout probability for the output of the attention + module. Defaults to 0.0. + attn_head_dim: the feature dimensionality of each attention head. + Defaults to None. If None, computed as `dim // num_heads`. + """ + if input_dim <= 0 or num_heads <= 0: + raise ValueError( + f"dim and num_heads must be greater than 0," + f" got input_dim={input_dim} and num_heads={num_heads} instead" + ) + + super().__init__() + self.num_heads = num_heads + head_dim = attn_head_dim or input_dim // num_heads + all_head_dim = head_dim * self.num_heads + self.scale = qk_scale or head_dim**-0.5 + + self.proj_q = nn.Linear(input_dim, all_head_dim, bias=False) + self.proj_k = nn.Linear(input_dim, all_head_dim, bias=False) + self.proj_v = nn.Linear(input_dim, all_head_dim, bias=False) + if qkv_bias: + self.q_bias = nn.Parameter(torch.zeros(all_head_dim)) + self.v_bias = nn.Parameter(torch.zeros(all_head_dim)) + else: + self.q_bias = None + self.v_bias = None + + self.attn_drop = nn.Dropout(attn_drop) + self.proj = nn.Linear(all_head_dim, input_dim) + self.proj_drop = nn.Dropout(proj_drop) + +
+[docs] + def forward( + self, + q: Tensor, + k: Tensor, + v: Tensor, + rel_pos_bias: Optional[Tensor] = None, + key_padding_mask: Optional[Tensor] = None, + ) -> Tensor: + """Forward pass.""" + batch_size, event_length, _ = q.shape + + q = linear(input=q, weight=self.proj_q.weight, bias=self.q_bias) + q = q.reshape(batch_size, event_length, self.num_heads, -1).permute( + 0, 2, 1, 3 + ) + k = linear(input=k, weight=self.proj_k.weight, bias=None) + k = k.reshape(batch_size, k.shape[1], self.num_heads, -1).permute( + 0, 2, 1, 3 + ) + v = linear(input=v, weight=self.proj_v.weight, bias=self.v_bias) + v = v.reshape(batch_size, v.shape[1], self.num_heads, -1).permute( + 0, 2, 1, 3 + ) + + q = q * self.scale + attn = q @ k.transpose(-2, -1) + if rel_pos_bias is not None: + bias = torch.einsum("bhic,bijc->bhij", q, rel_pos_bias) + attn = attn + bias + if key_padding_mask is not None: + assert ( + key_padding_mask.dtype == torch.float32 + or key_padding_mask.dtype == torch.float16 + ), "incorrect mask dtype" + bias = torch.min( + key_padding_mask[:, None, :], key_padding_mask[:, :, None] + ) + bias[ + torch.max( + key_padding_mask[:, None, :], key_padding_mask[:, :, None] + ) + < 0 + ] = 0 + attn = attn + bias.unsqueeze(1) + + attn = attn.softmax(dim=-1) + attn = self.attn_drop(attn) + + x = (attn @ v).transpose(1, 2) + if rel_pos_bias is not None: + x = x + torch.einsum("bhij,bijc->bihc", attn, rel_pos_bias) + x = x.reshape(batch_size, event_length, -1) + x = self.proj(x) + x = self.proj_drop(x) + return x
+
+ + + +
+[docs] +class Block(LightningModule): + """Transformer block.""" + + def __init__( + self, + input_dim: int, + num_heads: int, + mlp_ratio: float = 4.0, + dropout: float = 0.0, + attn_drop: float = 0.0, + drop_path: float = 0.0, + init_values: Optional[float] = None, + activation: nn.Module = nn.GELU, + norm_layer: nn.Module = nn.LayerNorm, + ): + """Construct 'Block'. + + Args: + input_dim: Dimension of the input tensor. + num_heads: Number of attention heads to use in the + `MultiheadAttention` layer. + mlp_ratio: Ratio of the hidden size of the feedforward network to + the input size in the `Mlp` layer. + dropout: Dropout probability to use in the `Mlp` layer. + attn_drop: Dropout probability to use in the `MultiheadAttention` + layer. + drop_path: Probability of applying drop path regularization to the + output of the layer. + init_values: Initial value to use for the `gamma_1` and `gamma_2` + parameters if not `None`. + activation: Activation function to use in the `Mlp` layer. + norm_layer: Normalization layer to use. + """ + super().__init__() + self.norm1 = norm_layer(input_dim) + self.attn = nn.MultiheadAttention( + input_dim, num_heads, dropout=attn_drop, batch_first=True + ) + self.drop_path = ( + DropPath(drop_path) if drop_path > 0.0 else nn.Identity() + ) + self.norm2 = norm_layer(input_dim) + mlp_hidden_dim = int(input_dim * mlp_ratio) + self.mlp = Mlp( + in_features=input_dim, + hidden_features=mlp_hidden_dim, + activation=activation, + dropout_prob=dropout, + ) + + if init_values is not None: + self.gamma_1 = nn.Parameter( + init_values * torch.ones((input_dim)), requires_grad=True + ) + self.gamma_2 = nn.Parameter( + init_values * torch.ones((input_dim)), requires_grad=True + ) + else: + self.gamma_1, self.gamma_2 = None, None + +
+[docs] + def forward( + self, + x: Tensor, + attn_mask: Optional[Tensor] = None, + key_padding_mask: Optional[Tensor] = None, + ) -> Tensor: + """Forward pass.""" + if self.gamma_1 is None: + xn = self.norm1(x) + x = x + self.drop_path( + self.attn( + xn, + xn, + xn, + attn_mask=attn_mask, + key_padding_mask=key_padding_mask, + need_weights=False, + )[0] + ) + x = x + self.drop_path(self.mlp(self.norm2(x))) + else: + xn = self.norm1(x) + x = x + self.drop_path( + self.gamma_1 + * self.attn( + xn, + xn, + xn, + attn_mask=attn_mask, + key_padding_mask=key_padding_mask, + need_weights=False, + )[0] + ) + x = x + self.drop_path(self.gamma_2 * self.mlp(self.norm2(x))) + return x
+
+ diff --git a/_modules/graphnet/models/detector/icecube.html b/_modules/graphnet/models/detector/icecube.html index fb38722fc..67974ea57 100644 --- a/_modules/graphnet/models/detector/icecube.html +++ b/_modules/graphnet/models/detector/icecube.html @@ -356,6 +356,7 @@

Source code for gra "charge": self._charge, "rde": self._rde, "pmt_area": self._pmt_area, + "hlc": self._identity, } return feature_map @@ -425,6 +426,7 @@

Source code for gra "charge": self._identity, "rde": self._rde, "pmt_area": self._pmt_area, + "hlc": self._identity, } return feature_map @@ -477,6 +479,7 @@

Source code for gra "pmt_dir_y": self._identity, "pmt_dir_z": self._identity, "dom_type": self._dom_type, + "hlc": self._identity, } return feature_map diff --git a/_modules/graphnet/models/gnn/RNN_tito.html b/_modules/graphnet/models/gnn/RNN_tito.html new file mode 100644 index 000000000..155e0f2e8 --- /dev/null +++ b/_modules/graphnet/models/gnn/RNN_tito.html @@ -0,0 +1,496 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + graphnet.models.gnn.RNN_tito — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +

Source code for graphnet.models.gnn.RNN_tito

+"""RNN_DynEdge model implementation."""
+from typing import List, Optional, Tuple, Union
+
+import torch
+from graphnet.models.gnn.gnn import GNN
+from graphnet.models.gnn.dynedge import DynEdge
+from graphnet.models.gnn.dynedge_kaggle_tito import DynEdgeTITO
+from graphnet.models.rnn.node_rnn import Node_RNN
+
+from graphnet.utilities.config import save_model_config
+from torch_geometric.data import Data
+
+
+
+[docs] +class RNN_TITO(GNN): + """The RNN_TITO model class. + + Combines the Node_RNN and DynEdgeTITO models, intended for data with large + amount of DOM activations per event. This model works only with non- + standard dataset specific to the Node_RNN model see Node_RNN for more + details. + """ + + @save_model_config + def __init__( + self, + nb_inputs: int, + time_series_columns: List[int], + *, + nb_neighbours: int = 8, + rnn_layers: int = 2, + rnn_hidden_size: int = 64, + rnn_dropout: float = 0.5, + features_subset: Optional[List[int]] = None, + dyntrans_layer_sizes: Optional[List[Tuple[int, ...]]] = None, + post_processing_layer_sizes: Optional[List[int]] = None, + readout_layer_sizes: Optional[List[int]] = None, + global_pooling_schemes: List[str] = ["max"], + embedding_dim: Optional[int] = None, + n_head: int = 16, + use_global_features: bool = True, + use_post_processing_layers: bool = True, + ): + """Initialize the RNN_DynEdge model. + + Args: + nb_inputs (int): Number of input features. + time_series_columns (List[int]): The indices of the input data that should be treated as time series data. The first index should be the charge column. + nb_neighbours (int, optional): Number of neighbours to consider. + Defaults to 8. + rnn_layers (int, optional): Number of RNN layers. + Defaults to 1. + rnn_hidden_size (int, optional): Size of the hidden state of the RNN. Also determines the size of the output of the RNN. + Defaults to 64. + rnn_dropout (float, optional): Dropout to use in the RNN. Defaults to 0.5. + features_subset (List[int], optional): The subset of latent + features on each node that are used as metric dimensions when performing the k-nearest neighbours clustering. Defaults to [0,1,2,3] + dyntrans_layer_sizes (List[Tuple[int, ...]], optional): List of tuples representing the sizes of the hidden layers of the DynTrans model. + post_processing_layer_sizes (List[int], optional): List of integers representing the sizes of the hidden layers of the post-processing model. + readout_layer_sizes (List[int], optional): List of integers representing the sizes of the hidden layers of the readout model. + global_pooling_schemes (Union[str, List[str]], optional): Pooling schemes to use. Defaults to None. + embedding_dim (int, optional): Embedding dimension of the RNN. Defaults to None ie. no embedding. + n_head (int, optional): Number of heads to use in the DynTrans model. Defaults to 16. + use_global_features (bool, optional): Whether to use global features after pooling. Defaults to True. + use_post_processing_layers (bool, optional): Whether to use post-processing layers after the DynTrans layers. Defaults to True. + """ + self._nb_neighbours = nb_neighbours + self._nb_inputs = nb_inputs + self._rnn_layers = rnn_layers + self._rnn_hidden_size = rnn_hidden_size + self._rnn_dropout = rnn_dropout + self._embedding_dim = embedding_dim + self._n_head = n_head + self._use_global_features = use_global_features + self._use_post_processing_layers = use_post_processing_layers + + self._features_subset = features_subset + if dyntrans_layer_sizes is None: + dyntrans_layer_sizes = [ + (256, 256), + (256, 256), + (256, 256), + (256, 256), + ] + else: + dyntrans_layer_sizes = [ + tuple(layer_sizes) for layer_sizes in dyntrans_layer_sizes + ] + + self._dyntrans_layer_sizes = dyntrans_layer_sizes + self._post_processing_layer_sizes = post_processing_layer_sizes + self._global_pooling_schemes = global_pooling_schemes + if readout_layer_sizes is None: + readout_layer_sizes = [ + 256, + 128, + ] + self._readout_layer_sizes = readout_layer_sizes + + super().__init__(nb_inputs, self._readout_layer_sizes[-1]) + + self._rnn = Node_RNN( + nb_inputs=2, + hidden_size=self._rnn_hidden_size, + num_layers=self._rnn_layers, + time_series_columns=time_series_columns, + nb_neighbours=self._nb_neighbours, + features_subset=self._features_subset, + dropout=self._rnn_dropout, + embedding_dim=self._embedding_dim, + ) + + self._dynedge_tito = DynEdgeTITO( + nb_inputs=self._rnn_hidden_size + 5, + dyntrans_layer_sizes=self._dyntrans_layer_sizes, + features_subset=self._features_subset, + global_pooling_schemes=self._global_pooling_schemes, + use_global_features=self._use_global_features, + use_post_processing_layers=self._use_post_processing_layers, + post_processing_layer_sizes=self._post_processing_layer_sizes, + readout_layer_sizes=self._readout_layer_sizes, + n_head=self._n_head, + nb_neighbours=self._nb_neighbours, + ) + +
+[docs] + def forward(self, data: Data) -> torch.Tensor: + """Apply learnable forward pass of the RNN and tito model.""" + data = self._rnn(data) + readout = self._dynedge_tito(data) + + return readout
+
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/_modules/graphnet/models/gnn/dynedge.html b/_modules/graphnet/models/gnn/dynedge.html index 90dbb8077..d939a00c7 100644 --- a/_modules/graphnet/models/gnn/dynedge.html +++ b/_modules/graphnet/models/gnn/dynedge.html @@ -323,7 +323,7 @@

Source code for graphnet.models.gnn.dynedge

 """Implementation of the DynEdge GNN model architecture."""
-from typing import List, Optional, Sequence, Tuple, Union
+from typing import List, Optional, Callable, Tuple, Union
 
 import torch
 from torch import Tensor, LongTensor
@@ -358,6 +358,9 @@ 

Source code for graphnet readout_layer_sizes: Optional[List[int]] = None, global_pooling_schemes: Optional[Union[str, List[str]]] = None, add_global_variables_after_pooling: bool = False, + activation_layer: Callable = None, + add_norm_layer: bool = False, + skip_readout: bool = False, ): """Construct `DynEdge`. @@ -391,6 +394,11 @@

Source code for graphnet after global pooling. The alternative is to added (distribute) them to the individual nodes before any convolutional operations. + activation_layer: The activation function to use in the model. + add_norm_layer: Whether to add a normalization layer after each + linear layer. + skip_readout: Whether to skip the readout layer(s). If `True`, the + output of the last post-processing layer is returned directly. """ # Latent feature subset for computing nearest neighbours in DynEdge. if features_subset is None: @@ -475,15 +483,20 @@

Source code for graphnet add_global_variables_after_pooling ) + if activation_layer is None: + activation_layer = torch.nn.ReLU() + # Base class constructor super().__init__(nb_inputs, self._readout_layer_sizes[-1]) # Remaining member variables() - self._activation = torch.nn.LeakyReLU() + self._activation = activation_layer self._nb_inputs = nb_inputs self._nb_global_variables = 5 + nb_inputs self._nb_neighbours = nb_neighbours self._features_subset = features_subset + self._add_norm_layer = add_norm_layer + self._skip_readout = skip_readout self._construct_layers() @@ -505,6 +518,8 @@

Source code for graphnet if ix == 0: nb_in *= 2 layers.append(torch.nn.Linear(nb_in, nb_out)) + if self._add_norm_layer: + layers.append(torch.nn.LayerNorm(nb_out)) layers.append(self._activation) conv_layer = DynEdgeConv( @@ -529,6 +544,8 @@

Source code for graphnet ) for nb_in, nb_out in zip(layer_sizes[:-1], layer_sizes[1:]): post_processing_layers.append(torch.nn.Linear(nb_in, nb_out)) + if self._add_norm_layer: + post_processing_layers.append(torch.nn.LayerNorm(nb_out)) post_processing_layers.append(self._activation) self._post_processing = torch.nn.Sequential(*post_processing_layers) @@ -635,20 +652,21 @@

Source code for graphnet # Post-processing x = self._post_processing(x) - # (Optional) Global pooling - if self._global_pooling_schemes: - x = self._global_pooling(x, batch=batch) - if self._add_global_variables_after_pooling: - x = torch.cat( - [ - x, - global_variables, - ], - dim=1, - ) - - # Read-out - x = self._readout(x) + if not self._skip_readout: + # (Optional) Global pooling + if self._global_pooling_schemes: + x = self._global_pooling(x, batch=batch) + if self._add_global_variables_after_pooling: + x = torch.cat( + [ + x, + global_variables, + ], + dim=1, + ) + + # Read-out + x = self._readout(x) return x

diff --git a/_modules/graphnet/models/gnn/dynedge_kaggle_tito.html b/_modules/graphnet/models/gnn/dynedge_kaggle_tito.html index 046822eaf..61998b585 100644 --- a/_modules/graphnet/models/gnn/dynedge_kaggle_tito.html +++ b/_modules/graphnet/models/gnn/dynedge_kaggle_tito.html @@ -365,6 +365,10 @@

Source code global_pooling_schemes: List[str] = ["max"], use_global_features: bool = True, use_post_processing_layers: bool = True, + post_processing_layer_sizes: List[int] = None, + readout_layer_sizes: Optional[List[int]] = None, + n_head: int = 8, + nb_neighbours: int = 8, ): """Construct `DynEdgeTITO`. @@ -379,8 +383,12 @@

Source code global_pooling_schemes: The list global pooling schemes to use. Options are: "min", "max", "mean", and "sum". use_global_features: Whether to use global features after pooling. - use_post_processing_layers: Whether to use post-processing layers - after the `DynTrans` layers. + use_post_processing_layers: Whether to use post-processing layers after the `DynTrans` layers. + post_processing_layer_sizes: The layer sizes used in the post-processing layers. Defaults to [336, 256]. + readout_layer_sizes: The layer sizes used in the readout layers. Defaults to [256, 128]. + n_head: The number of heads to use in the `DynTrans` layer. + nb_neighbours: The number of neighbours to use in the `DynTrans` + layer. """ # DynTrans layer sizes if dyntrans_layer_sizes is None: @@ -414,18 +422,20 @@

Source code self._dyntrans_layer_sizes = dyntrans_layer_sizes # Post-processing layer sizes - post_processing_layer_sizes = [ - 336, - 256, - ] + if post_processing_layer_sizes is None: + post_processing_layer_sizes = [ + 336, + 256, + ] self._post_processing_layer_sizes = post_processing_layer_sizes # Read-out layer sizes - readout_layer_sizes = [ - 256, - 128, - ] + if readout_layer_sizes is None: + readout_layer_sizes = [ + 256, + 128, + ] self._readout_layer_sizes = readout_layer_sizes @@ -455,10 +465,11 @@

Source code self._activation = torch.nn.LeakyReLU() self._nb_inputs = nb_inputs self._nb_global_variables = 5 + nb_inputs - self._nb_neighbours = 8 + self._nb_neighbours = nb_neighbours self._features_subset = features_subset or [0, 1, 2, 3] self._use_global_features = use_global_features self._use_post_processing_layers = use_post_processing_layers + self._n_head = n_head self._construct_layers() def _construct_layers(self) -> None: @@ -473,7 +484,7 @@

Source code [nb_latent_features] + list(sizes), aggr="max", features_subset=self._features_subset, - n_head=8, + n_head=self._n_head, ) self._conv_layers.append(conv_layer) nb_latent_features = sizes[-1] diff --git a/_modules/graphnet/models/gnn/icemix.html b/_modules/graphnet/models/gnn/icemix.html new file mode 100644 index 000000000..d59d697b9 --- /dev/null +++ b/_modules/graphnet/models/gnn/icemix.html @@ -0,0 +1,528 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + graphnet.models.gnn.icemix — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +

Source code for graphnet.models.gnn.icemix

+"""Implementation of IceMix architecture used in.
+
+                    IceCube - Neutrinos in Deep Ice
+Reconstruct the direction of neutrinos from the Universe to the South Pole
+
+Kaggle competition.
+
+Solution by DrHB: https://github.com/DrHB/icecube-2nd-place
+"""
+import torch
+import torch.nn as nn
+from typing import Set, Dict, Any, List
+
+from graphnet.models.components.layers import (
+    Block_rel,
+    Block,
+)
+from graphnet.models.components.embedding import (
+    FourierEncoder,
+    SpacetimeEncoder,
+)
+from graphnet.models.gnn.dynedge import DynEdge
+from graphnet.models.gnn.gnn import GNN
+from graphnet.models.utils import array_to_sequence
+
+from torch_geometric.utils import to_dense_batch
+from torch_geometric.data import Data
+from torch import Tensor
+
+
+
+[docs] +class DeepIce(GNN): + """DeepIce model.""" + + def __init__( + self, + hidden_dim: int = 384, + seq_length: int = 128, + depth: int = 12, + head_size: int = 32, + depth_rel: int = 4, + n_rel: int = 1, + scaled_emb: bool = False, + include_dynedge: bool = False, + dynedge_args: Dict[str, Any] = None, + ): + """Construct `DeepIce`. + + Args: + hidden_dim: The latent feature dimension. + seq_length: The base feature dimension. + depth: The depth of the transformer. + head_size: The size of the attention heads. + depth_rel: The depth of the relative transformer. + n_rel: The number of relative transformer layers to use. + scaled_emb: Whether to scale the sinusoidal positional embeddings. + include_dynedge: If True, pulse-level predictions from `DynEdge` + will be added as features to the model. + dynedge_args: Initialization arguments for DynEdge. If not + provided, DynEdge will be initialized with the original Kaggle + Competition settings. If `include_dynedge` is False, this + argument have no impact. + """ + super().__init__(seq_length, hidden_dim) + fourier_out_dim = hidden_dim // 2 if include_dynedge else hidden_dim + self.fourier_ext = FourierEncoder( + seq_length, fourier_out_dim, scaled=scaled_emb + ) + self.rel_pos = SpacetimeEncoder(head_size) + self.sandwich = nn.ModuleList( + [ + Block_rel( + input_dim=hidden_dim, num_heads=hidden_dim // head_size + ) + for _ in range(depth_rel) + ] + ) + self.cls_token = nn.Linear(hidden_dim, 1, bias=False) + self.blocks = nn.ModuleList( + [ + Block( + input_dim=hidden_dim, + num_heads=hidden_dim // head_size, + mlp_ratio=4, + drop_path=0.0 * (i / (depth - 1)), + init_values=1, + ) + for i in range(depth) + ] + ) + self.n_rel = n_rel + + if include_dynedge and dynedge_args is None: + self.warning_once("Running with default DynEdge settings") + self.dyn_edge = DynEdge( + nb_inputs=9, + nb_neighbours=9, + post_processing_layer_sizes=[336, hidden_dim // 2], + dynedge_layer_sizes=[ + (128, 256), + (336, 256), + (336, 256), + (336, 256), + ], + global_pooling_schemes=None, + activation_layer=nn.GELU(), + add_norm_layer=True, + skip_readout=True, + ) + elif include_dynedge and not (dynedge_args is None): + self.dyn_edge = DynEdge(**dynedge_args) + + self.include_dynedge = include_dynedge + +
+[docs] + @torch.jit.ignore + def no_weight_decay(self) -> Set: + """cls_tocken should not be subject to weight decay during training.""" + return {"cls_token"}
+ + +
+[docs] + def forward(self, data: Data) -> Tensor: + """Apply learnable forward pass.""" + x0, mask, seq_length = array_to_sequence( + data.x, data.batch, padding_value=0 + ) + x = self.fourier_ext(x0, seq_length) + rel_pos_bias = self.rel_pos(x0) + batch_size = mask.shape[0] + if self.include_dynedge: + graph = self.dyn_edge(data) + graph, _ = to_dense_batch(graph, data.batch) + x = torch.cat([x, graph], 2) + + attn_mask = torch.zeros(mask.shape, device=mask.device) + attn_mask[~mask] = -torch.inf + + for i, blk in enumerate(self.sandwich): + x = blk(x, attn_mask, rel_pos_bias) + if i + 1 == self.n_rel: + rel_pos_bias = None + + mask = torch.cat( + [ + torch.ones( + batch_size, 1, dtype=mask.dtype, device=mask.device + ), + mask, + ], + 1, + ) + attn_mask = torch.zeros(mask.shape, device=mask.device) + attn_mask[~mask] = -torch.inf + cls_token = self.cls_token.weight.unsqueeze(0).expand( + batch_size, -1, -1 + ) + x = torch.cat([cls_token, x], 1) + + for blk in self.blocks: + x = blk(x, None, attn_mask) + + return x[:, 0]
+
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/_modules/graphnet/models/graphs/nodes/nodes.html b/_modules/graphnet/models/graphs/nodes/nodes.html index 0a3da4c5c..b9e868b76 100644 --- a/_modules/graphnet/models/graphs/nodes/nodes.html +++ b/_modules/graphnet/models/graphs/nodes/nodes.html @@ -324,7 +324,7 @@

Source code for graphnet.models.graphs.nodes.nodes

 """Class(es) for building/connecting graphs."""
 
-from typing import List, Tuple, Optional
+from typing import List, Tuple, Optional, Union
 from abc import abstractmethod
 
 import torch
@@ -335,9 +335,13 @@ 

Source code for g from graphnet.models.graphs.utils import ( cluster_summarize_with_percentiles, identify_indices, + lex_sort, + ice_transparency, ) from copy import deepcopy +import numpy as np +
[docs] @@ -553,6 +557,221 @@

Source code for g return Data(x=torch.tensor(array))

+ + +
+[docs] +class NodeAsDOMTimeSeries(NodeDefinition): + """Represent each node as a DOM with time and charge time series data.""" + + def __init__( + self, + keys: List[str] = [ + "dom_x", + "dom_y", + "dom_z", + "dom_time", + "charge", + ], + id_columns: List[str] = ["dom_x", "dom_y", "dom_z"], + time_column: str = "dom_time", + charge_column: str = "charge", + max_activations: Optional[int] = None, + ) -> None: + """Construct `NodeAsDOMTimeSeries`. + + Args: + keys: Names of features in the data (in order). + id_columns: List of columns that uniquely identify a DOM. + time_column: Name of time column. + charge_column: Name of charge column. + max_activations: Maximum number of activations to include in the time series. + """ + self._keys = keys + super().__init__(input_feature_names=self._keys) + self._id_columns = [self._keys.index(key) for key in id_columns] + self._time_index = self._keys.index(time_column) + try: + self._charge_index: Optional[int] = self._keys.index(charge_column) + except ValueError: + self.warning( + "Charge column with name {} not found. Running without.".format( + charge_column + ) + ) + + self._charge_index = None + + self._max_activations = max_activations + + def _define_output_feature_names( + self, input_feature_names: List[str] + ) -> List[str]: + return input_feature_names + ["new_node_col"] + + def _construct_nodes(self, x: torch.Tensor) -> Data: + """Construct nodes from raw node features ´x´.""" + # Cast to Numpy + x = x.numpy() + # if there is no charge column add a dummy column of zeros with the same shape as the time column + if self._charge_index is None: + charge_index: int = len(self._keys) + x = np.insert(x, charge_index, np.zeros(x.shape[0]), axis=1) + else: + charge_index = self._charge_index + + # Sort by time + x = x[x[:, self._time_index].argsort()] + # Undo log10 scaling so we can sum charges + x[:, charge_index] = np.power(10, x[:, charge_index]) + # Shift time to start at 0 + x[:, self._time_index] -= np.min(x[:, self._time_index]) + # Group pulses on the same DOM + x = lex_sort(x, self._id_columns) + + unique_sensors, counts = np.unique( + x[:, self._id_columns], axis=0, return_counts=True + ) + + sort_this = np.concatenate( + [unique_sensors, counts.reshape(-1, 1)], axis=1 + ) + sort_this = lex_sort(x=sort_this, cluster_columns=self._id_columns) + unique_sensors = sort_this[:, 0 : unique_sensors.shape[1]] + counts = sort_this[:, unique_sensors.shape[1] :].flatten().astype(int) + + new_node_col = np.zeros(x.shape[0]) + new_node_col[counts.cumsum()[:-1]] = 1 + new_node_col[0] = 1 + x = np.column_stack([x, new_node_col]) + + return Data(x=torch.tensor(x))
+ + + +
+[docs] +class IceMixNodes(NodeDefinition): + """Calculate ice properties and perform random sampling. + + Ice properties are calculated based on the z-coordinate of the pulse. For + each event, a random sampling is performed to keep the number of pulses + below a maximum number of pulses if n_pulses is over the limit. + """ + + def __init__( + self, + input_feature_names: Optional[List[str]] = None, + max_pulses: int = 768, + z_name: str = "dom_z", + hlc_name: str = "hlc", + ) -> None: + """Construct `IceMixNodes`. + + Args: + input_feature_names: Column names for input features. Minimum + required features are z coordinate and hlc column names. + max_pulses: Maximum number of pulses to keep in the event. + z_name: Name of the z-coordinate column. + hlc_name: Name of the `Hard Local Coincidence Check` column. + """ + super().__init__(input_feature_names=input_feature_names) + + if input_feature_names is None: + input_feature_names = [ + "dom_x", + "dom_y", + "dom_z", + "dom_time", + "charge", + "hlc", + "rde", + ] + + if z_name not in input_feature_names: + raise ValueError( + f"z name {z_name} not found in " + f"input_feature_names {input_feature_names}" + ) + if hlc_name not in input_feature_names: + raise ValueError( + f"hlc name {hlc_name} not found in " + f"input_feature_names {input_feature_names}" + ) + + self.all_features = input_feature_names + [ + "scatt_lenght", + "abs_lenght", + ] + + self.feature_indexes = { + feat: self.all_features.index(feat) for feat in input_feature_names + } + + self.f_scattering, self.f_absoprtion = ice_transparency() + + self.input_feature_names = input_feature_names + self.n_features = len(self.all_features) + self.max_length = max_pulses + self.z_name = z_name + self.hlc_name = hlc_name + + def _define_output_feature_names( + self, input_feature_names: List[str] + ) -> List[str]: + return self.all_features + + def _add_ice_properties( + self, graph: torch.Tensor, x: torch.Tensor, ids: List[int] + ) -> torch.Tensor: + + graph[: len(ids), -2] = torch.tensor( + self.f_scattering(x[ids, self.feature_indexes[self.z_name]]) + ) + graph[: len(ids), -1] = torch.tensor( + self.f_absoprtion(x[ids, self.feature_indexes[self.z_name]]) + ) + return graph + + def _pulse_sampler( + self, x: torch.Tensor, event_length: int + ) -> torch.Tensor: + + if event_length < self.max_length: + ids = torch.arange(event_length) + else: + ids = torch.randperm(event_length) + auxiliary_n = torch.nonzero( + x[:, self.feature_indexes[self.hlc_name]] == 0 + ).squeeze(1) + auxiliary_p = torch.nonzero( + x[:, self.feature_indexes[self.hlc_name]] == 1 + ).squeeze(1) + ids_n = ids[auxiliary_n][: min(self.max_length, len(auxiliary_n))] + ids_p = ids[auxiliary_p][ + : min(self.max_length - len(ids_n), len(auxiliary_p)) + ] + ids = torch.cat([ids_n, ids_p]).sort().values + return ids + + def _construct_nodes(self, x: torch.Tensor) -> Tuple[Data, List[str]]: + + event_length = x.shape[0] + x[:, self.feature_indexes[self.hlc_name]] = torch.logical_not( + x[:, self.feature_indexes[self.hlc_name]] + ) # hlc in kaggle was flipped + ids = self._pulse_sampler(x, event_length) + event_length = min(self.max_length, event_length) + + graph = torch.zeros([event_length, self.n_features]) + for idx, feature in enumerate( + self.all_features[: self.n_features - 2] + ): + graph[:event_length, idx] = x[ids, self.feature_indexes[feature]] + + graph = self._add_ice_properties(graph, x, ids) # ice properties + return Data(x=graph)
+

diff --git a/_modules/graphnet/models/graphs/utils.html b/_modules/graphnet/models/graphs/utils.html index 7081b3238..18ba17add 100644 --- a/_modules/graphnet/models/graphs/utils.html +++ b/_modules/graphnet/models/graphs/utils.html @@ -325,7 +325,12 @@

Source code for graphne """Utility functions for construction of graphs.""" from typing import List, Tuple +import os import numpy as np +import pandas as pd +from scipy.interpolate import interp1d +from sklearn.preprocessing import RobustScaler +from graphnet.constants import DATA_DIR
@@ -494,6 +499,37 @@

Source code for graphne return array

+ + +
+[docs] +def ice_transparency() -> Tuple[interp1d, interp1d]: + """Return interpolation functions for optical properties of IceCube. + + NOTE: The resulting interpolation functions assumes that the + Z-coordinate of pulse are scaled as `z = z/500`. + Any deviation from this scaling method results in inaccurate results. + + Returns: + f_scattering: Function that takes a normalized depth and returns the + corresponding normalized scattering length. + f_absorption: Function that takes a normalized depth and returns the + corresponding normalized absorption length. + """ + # Data from page 31 of https://arxiv.org/pdf/1301.5361.pdf + df = pd.read_parquet( + os.path.join(DATA_DIR, "ice_properties/ice_transparency.parquet"), + ) + df["z"] = df["depth"] - 1950 + df["z_norm"] = df["z"] / 500 + df[ + ["scattering_len_norm", "absorption_len_norm"] + ] = RobustScaler().fit_transform(df[["scattering_len", "absorption_len"]]) + + f_scattering = interp1d(df["z_norm"], df["scattering_len_norm"]) + f_absorption = interp1d(df["z_norm"], df["absorption_len_norm"]) + return f_scattering, f_absorption
+ diff --git a/_modules/graphnet/models/model.html b/_modules/graphnet/models/model.html index 746e98773..4449c04fe 100644 --- a/_modules/graphnet/models/model.html +++ b/_modules/graphnet/models/model.html @@ -349,6 +349,8 @@

Source code for graphnet.model ): """Base class for all components in graphnet.""" + verbose_print = True + @staticmethod def _get_batch_size(data: List[Data]) -> int: return sum([torch.numel(torch.unique(d.batch)) for d in data]) @@ -393,7 +395,7 @@

Source code for graphnet.model
[docs] - def load_state_dict( + def load_state_dict( # type: ignore[override] self, path: Union[str, Dict], **kargs: Optional[Any] ) -> "Model": # pylint: disable=arguments-differ """Load model `state_dict` from `path`.""" @@ -444,6 +446,53 @@

Source code for graphnet.model ), f"Argument `source` of type ({type(source)}) is not a `ModelConfig" return source._construct_model(trust, load_modules)

+ + +
+[docs] + def set_verbose_print_recursively(self, verbose_print: bool) -> None: + """Set verbose_print recursively for all Model modules.""" + for module in self.modules(): + if isinstance(module, Model): + module.verbose_print = verbose_print + self.verbose_print = verbose_print
+ + +
+[docs] + def extra_repr(self) -> str: + """Provide a more detailed description of the object print. + + Returns: + str: A string representation containing detailed information + about the object. + """ + return self._extra_repr() if self.verbose_print else ""
+ + + def _extra_repr(self) -> str: + """Detailed information about the object.""" + return f"""{self.__class__.__name__}(\n{self.extra_repr_recursive( + self._config.__dict__)})""" + +
+[docs] + def extra_repr_recursive(self, dictionary: dict, indent: int = 4) -> str: + """Recursively format a dictionary for extra_repr.""" + result = "{\n" + for key, value in dictionary.items(): + if key == "class_name": + continue + result += " " * indent + f"'{key}': " + if isinstance(value, dict): + result += self.extra_repr_recursive(value, indent + 4) + elif isinstance(value, Model): + result += value.__repr__() + else: + result += repr(value) + result += ",\n" + result += " " * (indent - 4) + "}" + return result
diff --git a/_modules/graphnet/models/rnn/node_rnn.html b/_modules/graphnet/models/rnn/node_rnn.html new file mode 100644 index 000000000..e508b91e5 --- /dev/null +++ b/_modules/graphnet/models/rnn/node_rnn.html @@ -0,0 +1,505 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + graphnet.models.rnn.node_rnn — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +

Source code for graphnet.models.rnn.node_rnn

+"""Implementation of the NodeTimeRNN model.
+
+(cannot be used as a standalone model)
+"""
+import torch
+
+from graphnet.models.gnn.gnn import GNN
+from graphnet.utilities.config import save_model_config
+from torch_geometric.data import Data
+from torch_geometric.nn.pool import knn_graph
+from typing import List, Optional
+
+
+from graphnet.models.components.embedding import SinusoidalPosEmb
+
+
+
+[docs] +class Node_RNN(GNN): + """Implementation of the Node RNN model architecture. + + The model takes as input the typical DOM data format and transforms it into + a time series of DOM activations pr. DOM. before applying a RNN layer and + outputting the an RNN output for each DOM. This model is in its current + state not intended to be used as a standalone model. Furthermore, it needs + to be used with a time-series dataset object, where the last column in x is + a special column that is used to seperate the activation into time series + per dom per batch. + """ + + @save_model_config + def __init__( + self, + nb_inputs: int, + hidden_size: int, + num_layers: int, + time_series_columns: List[int], + nb_neighbours: int = 8, + features_subset: Optional[List[int]] = None, + dropout: float = 0.5, + embedding_dim: int = 0, + ) -> None: + """Construct `Node_RNN`. + + Args: + nb_inputs: Number of features in the input data. + hidden_size: Number of features for the RNN output and hidden layers. + num_layers: Number of layers in the RNN. + time_series_columns: The indices of the input data that should be treated as time series data. The first index should be the charge column. + nb_neighbours: Number of neighbours to use when reconstructing the graph representation. Defaults to 8. + features_subset: The subset of latent features on each node that are used as metric dimensions when performing the k-nearest neighbours clustering. Defaults to [0,1,2,3] + dropout: Dropout fraction to use in the RNN. Defaults to 0.5. + embedding_dim: Embedding dimension of the RNN. Defaults to no embedding. + """ + self._hidden_size = hidden_size + self._num_layers = num_layers + self._time_series_columns = time_series_columns + self._nb_neighbors = nb_neighbours + self._features_subset = features_subset + self._embedding_dim = embedding_dim + self._nb_inputs = nb_inputs + + super().__init__(nb_inputs, hidden_size + 5) + + if self._embedding_dim != 0: + self._nb_inputs = self._embedding_dim * nb_inputs + + self._rnn = torch.nn.GRU( + num_layers=self._num_layers, + input_size=self._nb_inputs, + hidden_size=self._hidden_size, + batch_first=True, + dropout=dropout, + ) + self._emb = SinusoidalPosEmb(dim=self._embedding_dim) + +
+[docs] + def clean_up_data_object(self, data: Data) -> Data: + """Update the feature names of the data object. + + Args: + data: The input data object. + """ + # old features removing the new_node column + old_features = data.features[0][:-1] + new_features = old_features + [ + "rnn_out_" + str(i) for i in range(self._hidden_size) + ] + data.features = [new_features] * len(data.features) + for i, name in enumerate(old_features): + data[name] = data.x[i] + return data
+ + +
+[docs] + def forward(self, data: Data) -> torch.Tensor: + """Apply learnable forward pass to the GNN.""" + # cutter = data.cutter.cumsum(0)[:-1] + # Optional embedding of the time and charge time series data. + x = data.x + time_series = x[:, self._time_series_columns] + if self._embedding_dim != 0: + time_series = self._emb(time_series * 4096).reshape( + ( + time_series.shape[0], + self._embedding_dim * time_series.shape[-1], + ) + ) + # Create the dom + batch unique splitter from the new_node_col + splitter = x[:, -1].argwhere()[1:].flatten().cpu() + time_series = time_series.tensor_split(splitter) + # apply RNN per DOM irrespective of batch and return the final state. + time_series = torch.nn.utils.rnn.pack_sequence( + time_series, enforce_sorted=False + ) + rnn_out = self._rnn(time_series)[-1][0] + # prepare node level features + charge = data.x[:, self._time_series_columns[0]].tensor_split(splitter) + charge = torch.tensor( + [ + torch.asinh(5 * torch.sum(node_charges) / 5) + for node_charges in charge + ] + ) + batch = data.batch[x[:, -1].bool()] + x = x[x[:, -1].bool()][:, :-1] + x[:, self._time_series_columns[0]] = charge + + # combine the RNN output with the DOM summary features + data.x = torch.hstack([x, rnn_out]) + # correct the batches + data.batch = batch + data = self.clean_up_data_object(data) + # Recompute adjacency + data.edge_index = knn_graph( + x=x[:, self._features_subset], + k=self._nb_neighbors, + batch=batch, + ).to(self.device) + + return data
+
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/_modules/graphnet/models/standard_averaged_model.html b/_modules/graphnet/models/standard_averaged_model.html new file mode 100644 index 000000000..b6bf471e3 --- /dev/null +++ b/_modules/graphnet/models/standard_averaged_model.html @@ -0,0 +1,532 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + graphnet.models.standard_averaged_model — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +

Source code for graphnet.models.standard_averaged_model

+"""Averaged Standard model class(es)."""
+from typing import Any, Callable, Dict, List, Optional, Union, Type
+from collections import OrderedDict
+
+import torch
+from torch import Tensor
+from torch.optim import Adam
+from torch.optim.swa_utils import (
+    AveragedModel,
+    update_bn,
+    get_ema_multi_avg_fn,
+)
+from torch_geometric.data import Data
+
+from graphnet.models import StandardModel
+from graphnet.models.graphs import GraphDefinition
+from graphnet.models.gnn.gnn import GNN
+from graphnet.models.task import Task
+
+
+
+[docs] +class StandardAveragedModel(StandardModel): + """Class for SWA and EMA models in graphnet.""" + + def __init__( + self, + *, + graph_definition: GraphDefinition, + backbone: GNN, + gnn: Optional[GNN] = None, + tasks: Union[Task, List[Task]], + optimizer_class: Type[torch.optim.Optimizer] = Adam, + optimizer_kwargs: Optional[Dict] = None, + scheduler_class: Optional[type] = None, + scheduler_kwargs: Optional[Dict] = None, + scheduler_config: Optional[Dict] = None, + swa_starting_epoch: Optional[int] = None, + ema_decay: Optional[float] = None, + ) -> None: + """Construct `StandardAverageModel`.""" + # Base class constructor + super().__init__( + graph_definition=graph_definition, + backbone=backbone, + gnn=gnn, + tasks=tasks, + optimizer_class=optimizer_class, + optimizer_kwargs=optimizer_kwargs, + scheduler_class=scheduler_class, + scheduler_kwargs=scheduler_kwargs, + scheduler_config=scheduler_config, + ) + + averaged_model_kwargs = { + "device": self.device, + } + + if ema_decay is not None: + averaged_model_kwargs["multi_avg_fn"] = get_ema_multi_avg_fn( + ema_decay + ) + + if swa_starting_epoch is None: + self._swa_starting_epoch = 0 + else: + self._swa_starting_epoch = swa_starting_epoch + + self._averaged_model = AveragedModel(self, **averaged_model_kwargs) + + for param in self._averaged_model.parameters(): + param.requires_grad = False + +
+[docs] + def training_step( + self, train_batch: Union[Data, List[Data]], batch_idx: int + ) -> Tensor: + """Perform training step.""" + if isinstance(train_batch, Data): + train_batch = [train_batch] + preds = self(train_batch) + loss = self.compute_loss(preds, train_batch) + self.log( + "train_loss", + loss, + batch_size=self._get_batch_size(train_batch), + prog_bar=True, + on_epoch=True, + on_step=False, + sync_dist=True, + ) + return loss
+ + +
+[docs] + def validation_step( + self, val_batch: Union[Data, List[Data]], batch_idx: int + ) -> Tensor: + """Perform validation step.""" + if isinstance(val_batch, Data): + val_batch = [val_batch] + preds = self._averaged_model(val_batch) + loss = self._averaged_model.module.compute_loss(preds, val_batch) + self.log( + "val_loss", + loss, + batch_size=self._get_batch_size(val_batch), + prog_bar=True, + on_epoch=True, + on_step=False, + sync_dist=True, + ) + + current_lr = self.trainer.optimizers[0].param_groups[0]["lr"] + self.log("lr", current_lr, prog_bar=True, on_step=True) + return loss
+ + +
+[docs] + def optimizer_step( + self, + epoch: int, + batch_idx: int, + optimizer: Type[torch.optim.Optimizer], + optimizer_closure: Optional[Callable[[], Any]] = None, + ) -> None: + """Perform an optimizer step.""" + super().optimizer_step(epoch, batch_idx, optimizer, optimizer_closure) + if epoch >= self._swa_starting_epoch: + self._averaged_model.update_parameters(self)
+ + +
+[docs] + def load_state_dict( + self, path: Union[str, Dict], **kargs: Optional[Any] + ) -> "StandardAveragedModel": # pylint: disable=arguments-differ + """Load model `state_dict` from `path`.""" + if isinstance(path, str): + state_dict = torch.load(path) + else: + state_dict = path + + new_state_dict = OrderedDict() + for key, value in state_dict.items(): + if not key.startswith("_averaged_model"): + if "_averaged_model.module." + key in state_dict: + new_state_dict[key] = state_dict[ + "_averaged_model.module." + key + ] + else: + new_state_dict[key] = value + + return super().load_state_dict(new_state_dict, **kargs)
+ + +
+[docs] + def on_train_end(self) -> None: + """Update the model parameters with the Averaged ones.""" + # Update bn statistics for the swa_model at the end + update_bn(self.trainer.train_dataloader, self._averaged_model) + + average_model_state_dict = self._averaged_model.module.state_dict() + del self._averaged_model + # Update the model parameters with the Averaged ones + self.load_state_dict(average_model_state_dict)
+
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/_modules/graphnet/models/utils.html b/_modules/graphnet/models/utils.html index edcfe6b39..2640186a4 100644 --- a/_modules/graphnet/models/utils.html +++ b/_modules/graphnet/models/utils.html @@ -324,7 +324,7 @@

Source code for graphnet.models.utils

 """Utility functions for `graphnet.models`."""
 
-from typing import List, Tuple, Union
+from typing import List, Tuple, Any
 from torch_geometric.nn import knn_graph
 from torch_geometric.data import Batch
 import torch
@@ -392,6 +392,53 @@ 

Source code for graphnet.model ) return Batch.from_data_list(data_list)

+ + +
+[docs] +def array_to_sequence( + x: Tensor, + batch_idx: LongTensor, + padding_value: Any = 0, + excluding_value: Any = torch.inf, +) -> Tuple[Tensor, Tensor, Tensor]: + """Convert `x` of shape [n,d] into a padded sequence of shape [B, L, D]. + + Where B is the batch size, L is the sequence length and D is the + features for each time step. + + Args: + x: array-like tensor with shape `[n,d]` where `n` is the total number + of pulses in the batch and `d` is the number of node features. + batch_idx: a LongTensor identifying which row in `x` belongs to + which training example. + E.g. `torch_geometric.data.Batch.batch`. + padding_value: The value to use for padding. + excluding_value: This parameter represents a unique value that should + not be present in the input tensor 'x' + Returns: + x: Padded sequence with dimensions [B, L, D]. + mask: A tensor that identifies masked entries in `x`. + E.g. : `masked_entries = x[mask]` + seq_length: A tensor containing the number of pulses in each event. + """ + if torch.any(torch.eq(x, excluding_value)): + raise ValueError( + f"Transformation cannot be made because input tensor " + f"`x` contains at least one element equal to " + f"excluding value {excluding_value}." + ) + + _, seq_length = torch.unique(batch_idx, return_counts=True) + x_list = torch.split(x, seq_length.tolist()) + + x = torch.nn.utils.rnn.pad_sequence( + x_list, batch_first=True, padding_value=excluding_value + ) + mask = torch.ne(x[:, :, 1], excluding_value) + x[~mask] = padding_value + return x, mask, seq_length
+ diff --git a/_modules/graphnet/utilities/config/dataset_config.html b/_modules/graphnet/utilities/config/dataset_config.html index f5390b772..743743b2e 100644 --- a/_modules/graphnet/utilities/config/dataset_config.html +++ b/_modules/graphnet/utilities/config/dataset_config.html @@ -381,6 +381,7 @@

Source code loss_weight_default_value: Optional[float] = None seed: Optional[int] = None graph_definition: Any = None + labels: Optional[Dict[str, Any]] = None def __init__(self, **data: Any) -> None: """Construct `DataConfig`. diff --git a/_modules/graphnet/utilities/config/model_config.html b/_modules/graphnet/utilities/config/model_config.html index 03fb80c8d..e990ed616 100644 --- a/_modules/graphnet/utilities/config/model_config.html +++ b/_modules/graphnet/utilities/config/model_config.html @@ -576,7 +576,29 @@

Source code f ) return {self.__class__.__name__: config_dict} - + + + def __repr__(self) -> str: + """Return a string representation of the object.""" + arguments_str = self._format_arguments(self.arguments) + return f"{self.__class__.__name__}(\n{arguments_str}\n)" + + def _format_arguments( + self, arguments: Dict[str, Any], indent: int = 4 + ) -> str: + """Format the arguments dictionary into a string representation.""" + lines = [] + for arg, value in arguments.items(): + if isinstance(value, ModelConfig): + value_str = repr(value) + elif isinstance(value, dict): + value_str = self._format_arguments(value, indent + 4) + else: + value_str = repr(value) + + lines.append(f"{' ' * indent}'{arg}': {value_str},") + + return "{\n" + "\n".join(lines) + "\n" + " " * (indent - 4) + "}" diff --git a/_modules/index.html b/_modules/index.html index 62c9098b0..b9ec07420 100644 --- a/_modules/index.html +++ b/_modules/index.html @@ -359,18 +359,24 @@

All modules for which code is available

  • graphnet.data.writers.graphnet_writer
  • graphnet.data.writers.parquet_writer
  • graphnet.data.writers.sqlite_writer
  • -
  • graphnet.deployment.i3modules.graphnet_module
  • +
  • graphnet.deployment.deployer
  • +
  • graphnet.deployment.deployment_module
  • +
  • graphnet.deployment.icecube.cleaning_module
  • +
  • graphnet.deployment.icecube.inference_module
  • graphnet.models.coarsening
  • +
  • graphnet.models.components.embedding
  • graphnet.models.components.layers
  • graphnet.models.components.pool
  • graphnet.models.detector.detector
  • graphnet.models.detector.icecube
  • graphnet.models.detector.prometheus
  • +
  • graphnet.models.gnn.RNN_tito
  • graphnet.models.gnn.convnet
  • graphnet.models.gnn.dynedge
  • graphnet.models.gnn.dynedge_jinst
  • graphnet.models.gnn.dynedge_kaggle_tito
  • graphnet.models.gnn.gnn
  • +
  • graphnet.models.gnn.icemix
  • graphnet.models.graphs.edges.edges
  • graphnet.models.graphs.edges.minkowski
  • graphnet.models.graphs.graph_definition
  • @@ -378,6 +384,8 @@

    All modules for which code is available

  • graphnet.models.graphs.nodes.nodes
  • graphnet.models.graphs.utils
  • graphnet.models.model
  • +
  • graphnet.models.rnn.node_rnn
  • +
  • graphnet.models.standard_averaged_model
  • graphnet.models.standard_model
  • graphnet.models.task.classification
  • graphnet.models.task.reconstruction
  • diff --git a/_sources/api/graphnet.deployment.i3modules.deployer.rst.txt b/_sources/api/graphnet.deployment.deployer.rst.txt similarity index 57% rename from _sources/api/graphnet.deployment.i3modules.deployer.rst.txt rename to _sources/api/graphnet.deployment.deployer.rst.txt index e5266caa3..518251334 100644 --- a/_sources/api/graphnet.deployment.i3modules.deployer.rst.txt +++ b/_sources/api/graphnet.deployment.deployer.rst.txt @@ -2,7 +2,7 @@ deployer ======== -.. automodule:: graphnet.deployment.i3modules.deployer +.. automodule:: graphnet.deployment.deployer :members: :undoc-members: :show-inheritance: diff --git a/_sources/api/graphnet.deployment.deployment_module.rst.txt b/_sources/api/graphnet.deployment.deployment_module.rst.txt new file mode 100644 index 000000000..8b0692591 --- /dev/null +++ b/_sources/api/graphnet.deployment.deployment_module.rst.txt @@ -0,0 +1,8 @@ + +deployment\_module +================== + +.. automodule:: graphnet.deployment.deployment_module + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/api/graphnet.deployment.i3modules.deprecated_methods.rst.txt b/_sources/api/graphnet.deployment.i3modules.deprecated_methods.rst.txt new file mode 100644 index 000000000..064f4af69 --- /dev/null +++ b/_sources/api/graphnet.deployment.i3modules.deprecated_methods.rst.txt @@ -0,0 +1,8 @@ + +deprecated\_methods +=================== + +.. automodule:: graphnet.deployment.i3modules.deprecated_methods + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/api/graphnet.deployment.i3modules.graphnet_module.rst.txt b/_sources/api/graphnet.deployment.i3modules.graphnet_module.rst.txt deleted file mode 100644 index 45e2e93f3..000000000 --- a/_sources/api/graphnet.deployment.i3modules.graphnet_module.rst.txt +++ /dev/null @@ -1,8 +0,0 @@ - -graphnet\_module -================ - -.. automodule:: graphnet.deployment.i3modules.graphnet_module - :members: - :undoc-members: - :show-inheritance: diff --git a/_sources/api/graphnet.deployment.i3modules.rst.txt b/_sources/api/graphnet.deployment.i3modules.rst.txt index e7e2c8f33..11d13bcb3 100644 --- a/_sources/api/graphnet.deployment.i3modules.rst.txt +++ b/_sources/api/graphnet.deployment.i3modules.rst.txt @@ -15,8 +15,7 @@ i3modules .. toctree:: :maxdepth: 2 - graphnet.deployment.i3modules.deployer - graphnet.deployment.i3modules.graphnet_module + graphnet.deployment.i3modules.deprecated_methods diff --git a/_sources/api/graphnet.deployment.icecube.cleaning_module.rst.txt b/_sources/api/graphnet.deployment.icecube.cleaning_module.rst.txt new file mode 100644 index 000000000..f86925081 --- /dev/null +++ b/_sources/api/graphnet.deployment.icecube.cleaning_module.rst.txt @@ -0,0 +1,8 @@ + +cleaning\_module +================ + +.. automodule:: graphnet.deployment.icecube.cleaning_module + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/api/graphnet.deployment.icecube.i3deployer.rst.txt b/_sources/api/graphnet.deployment.icecube.i3deployer.rst.txt new file mode 100644 index 000000000..d7a08b69d --- /dev/null +++ b/_sources/api/graphnet.deployment.icecube.i3deployer.rst.txt @@ -0,0 +1,8 @@ + +i3deployer +========== + +.. automodule:: graphnet.deployment.icecube.i3deployer + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/api/graphnet.deployment.icecube.inference_module.rst.txt b/_sources/api/graphnet.deployment.icecube.inference_module.rst.txt new file mode 100644 index 000000000..cc8948488 --- /dev/null +++ b/_sources/api/graphnet.deployment.icecube.inference_module.rst.txt @@ -0,0 +1,8 @@ + +inference\_module +================= + +.. automodule:: graphnet.deployment.icecube.inference_module + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/api/graphnet.deployment.icecube.rst.txt b/_sources/api/graphnet.deployment.icecube.rst.txt new file mode 100644 index 000000000..cd2519bf2 --- /dev/null +++ b/_sources/api/graphnet.deployment.icecube.rst.txt @@ -0,0 +1,38 @@ + +icecube +======= + + +.. automodule:: graphnet.deployment.icecube + :members: + :undoc-members: + :show-inheritance: + + +|start-h2| Submodules |end-h2| + + +.. toctree:: + :maxdepth: 2 + + graphnet.deployment.icecube.cleaning_module + graphnet.deployment.icecube.i3deployer + graphnet.deployment.icecube.inference_module + + + +.. |start-h2| raw:: html + +

    + +.. |end-h2| raw:: html + +

    + +.. |start-h3| raw:: html + +

    + +.. |end-h3| raw:: html + +

    \ No newline at end of file diff --git a/_sources/api/graphnet.deployment.rst.txt b/_sources/api/graphnet.deployment.rst.txt index ed0dbc80e..7f3273ef4 100644 --- a/_sources/api/graphnet.deployment.rst.txt +++ b/_sources/api/graphnet.deployment.rst.txt @@ -15,6 +15,17 @@ deployment :maxdepth: 2 graphnet.deployment.i3modules + graphnet.deployment.icecube + +|start-h2| Submodules |end-h2| + + +.. toctree:: + :maxdepth: 2 + + graphnet.deployment.deployer + graphnet.deployment.deployment_module + .. |start-h2| raw:: html diff --git a/_sources/api/graphnet.models.components.embedding.rst.txt b/_sources/api/graphnet.models.components.embedding.rst.txt new file mode 100644 index 000000000..02d40e032 --- /dev/null +++ b/_sources/api/graphnet.models.components.embedding.rst.txt @@ -0,0 +1,8 @@ + +embedding +========= + +.. automodule:: graphnet.models.components.embedding + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/api/graphnet.models.components.rst.txt b/_sources/api/graphnet.models.components.rst.txt index 257ab645f..9d3ef8355 100644 --- a/_sources/api/graphnet.models.components.rst.txt +++ b/_sources/api/graphnet.models.components.rst.txt @@ -15,6 +15,7 @@ components .. toctree:: :maxdepth: 2 + graphnet.models.components.embedding graphnet.models.components.layers graphnet.models.components.pool diff --git a/_sources/api/graphnet.models.gnn.RNN_tito.rst.txt b/_sources/api/graphnet.models.gnn.RNN_tito.rst.txt new file mode 100644 index 000000000..5e12663e2 --- /dev/null +++ b/_sources/api/graphnet.models.gnn.RNN_tito.rst.txt @@ -0,0 +1,8 @@ + +RNN\_tito +========= + +.. automodule:: graphnet.models.gnn.RNN_tito + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/api/graphnet.models.gnn.icemix.rst.txt b/_sources/api/graphnet.models.gnn.icemix.rst.txt new file mode 100644 index 000000000..b68492726 --- /dev/null +++ b/_sources/api/graphnet.models.gnn.icemix.rst.txt @@ -0,0 +1,8 @@ + +icemix +====== + +.. automodule:: graphnet.models.gnn.icemix + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/api/graphnet.models.gnn.rst.txt b/_sources/api/graphnet.models.gnn.rst.txt index 244d72540..8f4855e8b 100644 --- a/_sources/api/graphnet.models.gnn.rst.txt +++ b/_sources/api/graphnet.models.gnn.rst.txt @@ -15,11 +15,13 @@ gnn .. toctree:: :maxdepth: 2 + graphnet.models.gnn.RNN_tito graphnet.models.gnn.convnet graphnet.models.gnn.dynedge graphnet.models.gnn.dynedge_jinst graphnet.models.gnn.dynedge_kaggle_tito graphnet.models.gnn.gnn + graphnet.models.gnn.icemix diff --git a/_sources/api/graphnet.models.rnn.node_rnn.rst.txt b/_sources/api/graphnet.models.rnn.node_rnn.rst.txt new file mode 100644 index 000000000..022a7fb69 --- /dev/null +++ b/_sources/api/graphnet.models.rnn.node_rnn.rst.txt @@ -0,0 +1,8 @@ + +node\_rnn +========= + +.. automodule:: graphnet.models.rnn.node_rnn + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/api/graphnet.models.rnn.rst.txt b/_sources/api/graphnet.models.rnn.rst.txt new file mode 100644 index 000000000..8e13b2d81 --- /dev/null +++ b/_sources/api/graphnet.models.rnn.rst.txt @@ -0,0 +1,36 @@ + +rnn +=== + + +.. automodule:: graphnet.models.rnn + :members: + :undoc-members: + :show-inheritance: + + +|start-h2| Submodules |end-h2| + + +.. toctree:: + :maxdepth: 2 + + graphnet.models.rnn.node_rnn + + + +.. |start-h2| raw:: html + +

    + +.. |end-h2| raw:: html + +

    + +.. |start-h3| raw:: html + +

    + +.. |end-h3| raw:: html + +

    \ No newline at end of file diff --git a/_sources/api/graphnet.models.rst.txt b/_sources/api/graphnet.models.rst.txt index 8a7dbf317..f9db7b179 100644 --- a/_sources/api/graphnet.models.rst.txt +++ b/_sources/api/graphnet.models.rst.txt @@ -18,6 +18,7 @@ models graphnet.models.detector graphnet.models.gnn graphnet.models.graphs + graphnet.models.rnn graphnet.models.task |start-h2| Submodules |end-h2| @@ -28,6 +29,7 @@ models graphnet.models.coarsening graphnet.models.model + graphnet.models.standard_averaged_model graphnet.models.standard_model graphnet.models.utils diff --git a/_sources/api/graphnet.models.standard_averaged_model.rst.txt b/_sources/api/graphnet.models.standard_averaged_model.rst.txt new file mode 100644 index 000000000..0f7596a19 --- /dev/null +++ b/_sources/api/graphnet.models.standard_averaged_model.rst.txt @@ -0,0 +1,8 @@ + +standard\_averaged\_model +========================= + +.. automodule:: graphnet.models.standard_averaged_model + :members: + :undoc-members: + :show-inheritance: diff --git a/api/graphnet.data.dataclasses.html b/api/graphnet.data.dataclasses.html index 522ebf923..9a0ff4708 100644 --- a/api/graphnet.data.dataclasses.html +++ b/api/graphnet.data.dataclasses.html @@ -388,6 +388,18 @@
  • i3_file
  • gcd_file +
  • + + +
  • Settings
  • @@ -414,6 +426,41 @@ gcd_file + + + +
  • + + + Settings +
  • @@ -514,6 +561,18 @@
  • i3_file
  • gcd_file +
  • + + +
  • Settings
  • @@ -552,6 +611,38 @@ gcd_file: str
    +
    +
    +class graphnet.data.dataclasses.Settings(i3_files, gcd_file, output_folder, modules)[source]
    +

    Bases: object

    +

    Dataclass for workers in I3Deployer.

    +
    +
    Parameters:
    +
      +
    • i3_files (List[str]) –

    • +
    • gcd_file (str) –

    • +
    • output_folder (str) –

    • +
    • modules (List[Any]) –

    • +
    +
    +
    +
    +
    +i3_files: List[str]
    +
    +
    +
    +gcd_file: str
    +
    +
    +
    +output_folder: str
    +
    +
    +
    +modules: List[Any]
    +
    +
    diff --git a/api/graphnet.data.dataset.dataset.html b/api/graphnet.data.dataset.dataset.html index 96f8ef107..3d311fc7b 100644 --- a/api/graphnet.data.dataset.dataset.html +++ b/api/graphnet.data.dataset.dataset.html @@ -346,6 +346,8 @@
  • parse_graph_definition()
  • +
  • parse_labels() +
  • Dataset
  • graph_definition (GraphDefinition) – Method that defines the graph representation.

  • +
  • labels (Optional[Dict[str, Any]], default: None) – Dictionary of labels to be added to the dataset.

  • args (Any) –

  • kwargs (Any) –

  • diff --git a/api/graphnet.data.dataset.sqlite.sqlite_dataset.html b/api/graphnet.data.dataset.sqlite.sqlite_dataset.html index 2764ece23..c5c664424 100644 --- a/api/graphnet.data.dataset.sqlite.sqlite_dataset.html +++ b/api/graphnet.data.dataset.sqlite.sqlite_dataset.html @@ -601,6 +601,7 @@ “10000 random events ~ event_no % 5 > 0” or “20% random events ~ event_no % 5 > 0”).

  • graph_definition (GraphDefinition) – Method that defines the graph representation.

  • +
  • labels (Optional[Dict[str, Any]], default: None) – Dictionary of labels to be added to the dataset.

  • args (Any) –

  • kwargs (Any) –

  • diff --git a/api/graphnet.data.html b/api/graphnet.data.html index 2f19625ef..ea5ca2d92 100644 --- a/api/graphnet.data.html +++ b/api/graphnet.data.html @@ -541,6 +541,7 @@
  • dataclasses
  • dataconverter
  • @@ -398,8 +419,26 @@
    +
    +

    Submodules

    +
    + diff --git a/api/graphnet.deployment.i3modules.deployer.html b/api/graphnet.deployment.i3modules.deprecated_methods.html similarity index 92% rename from api/graphnet.deployment.i3modules.deployer.html rename to api/graphnet.deployment.i3modules.deprecated_methods.html index 9ebe17073..e4a56ae6a 100644 --- a/api/graphnet.deployment.i3modules.deployer.html +++ b/api/graphnet.deployment.i3modules.deprecated_methods.html @@ -61,7 +61,7 @@ - deployer — graphnet documentation + deprecated_methods — graphnet documentation + + + + + + + + + + + + + + + + icecube — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
    + +
    + + +
    + + + + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/api/graphnet.deployment.icecube.i3deployer.html b/api/graphnet.deployment.icecube.i3deployer.html new file mode 100644 index 000000000..ef9795a2c --- /dev/null +++ b/api/graphnet.deployment.icecube.i3deployer.html @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + i3deployer — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
    + +
    + + +
    + + + + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    + +
    +

    i3deployer

    +
    + + +
    +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/api/graphnet.deployment.icecube.inference_module.html b/api/graphnet.deployment.icecube.inference_module.html new file mode 100644 index 000000000..b9937cf35 --- /dev/null +++ b/api/graphnet.deployment.icecube.inference_module.html @@ -0,0 +1,549 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inference_module — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
    + +
    + + +
    + + + + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    + +
    +

    inference_module

    +

    IceCube I3InferenceModule.

    +

    Contains functionality for writing model predictions to i3 files.

    +
    +
    +class graphnet.deployment.icecube.inference_module.I3InferenceModule(pulsemap_extractor, model_config, state_dict, model_name, gcd_file, features, prediction_columns, pulsemap)[source]
    +

    Bases: DeploymentModule

    +

    General class for inference on i3 frames.

    +

    General class for inference on I3Frames (physics).

    +
    +
    Parameters:
    +
      +
    • pulsemap_extractor (Union[List[I3FeatureExtractor], I3FeatureExtractor]) – The extractor used to extract the pulsemap.

    • +
    • model_config (Union[ModelConfig, str]) – The ModelConfig (or path to it) that summarizes the +model used for inference.

    • +
    • state_dict (str) – Path to state_dict containing the learned weights.

    • +
    • model_name (str) – The name used for the model. Will help define the +named entry in the I3Frame. E.g. “dynedge”.

    • +
    • gcd_file (str) – path to associated gcd file.

    • +
    • features (Optional[List[str]], default: None) – the features of the pulsemap that the model is expecting.

    • +
    • prediction_columns (Optional[List[str]], default: None) –

      column names for the predictions of the model. +Will help define the named entry in the I3Frame.

      +
      +

      E.g. [‘energy_reco’]. Optional.

      +
      +

    • +
    • pulsemap (Optional[str], default: None) – the pulsmap that the model is expecting as input.

    • +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/api/graphnet.html b/api/graphnet.html index 9f329cdb2..17187a8ce 100644 --- a/api/graphnet.html +++ b/api/graphnet.html @@ -433,6 +433,9 @@
  • deployment
  • models diff --git a/api/graphnet.models.coarsening.html b/api/graphnet.models.coarsening.html index 602eed114..6646174e8 100644 --- a/api/graphnet.models.coarsening.html +++ b/api/graphnet.models.coarsening.html @@ -348,6 +348,13 @@ graphs +
  • +
  • + + + rnn + +
  • @@ -457,6 +464,13 @@ model +
  • +
  • + + + standard_averaged_model + +
  • diff --git a/api/graphnet.models.components.embedding.html b/api/graphnet.models.components.embedding.html new file mode 100644 index 000000000..849f8b6fa --- /dev/null +++ b/api/graphnet.models.components.embedding.html @@ -0,0 +1,733 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + embedding — graphnet documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
    + +
    + + +
    + + + + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    + +
    +

    embedding

    +

    Classes for performing embedding of input data.

    +
    +
    +class graphnet.models.components.embedding.SinusoidalPosEmb(dim, n_freq, scaled)[source]
    +

    Bases: LightningModule

    +

    Sinusoidal positional embeddings module.

    +

    This module is from the kaggle competition 2nd place solution (see +arXiv:2310.15674): It performs what is called Fourier encoding or it’s used +in the Attention is all you need arXiv:1706.03762. It can be seen as a soft +digitization of the input data

    +

    Construct SinusoidalPosEmb.

    +
    +
    Parameters:
    +
      +
    • dim (int, default: 16) – Embedding dimension.

    • +
    • n_freq (int, default: 10000) – Number of frequencies.

    • +
    • scaled (bool, default: False) – Whether or not to scale the output.

    • +
    +
    +
    +
    +
    +forward(x)[source]
    +

    Forward pass.

    +
    +
    Return type:
    +

    Tensor

    +
    +
    Parameters:
    +

    x (Tensor) –

    +
    +
    +
    +
    +
    +
    +class graphnet.models.components.embedding.FourierEncoder(seq_length, output_dim, scaled)[source]
    +

    Bases: LightningModule

    +

    Fourier encoder module.

    +

    This module incorporates sinusoidal positional embeddings and auxiliary +embeddings to process input sequences and produce meaningful +representations.

    +

    Construct FourierEncoder.

    +
    +
    Parameters:
    +
      +
    • seq_length (int, default: 128) – Dimensionality of the base sinusoidal positional +embeddings.

    • +
    • output_dim (int, default: 384) – Output dimensionality of the final projection.

    • +
    • scaled (bool, default: False) – Whether or not to scale the embeddings.

    • +
    +
    +
    +
    +
    +forward(x, seq_length)[source]
    +

    Forward pass.

    +
    +
    Return type:
    +

    Tensor

    +
    +
    Parameters:
    +
      +
    • x (Tensor) –

    • +
    • seq_length (Tensor) –

    • +
    +
    +
    +
    +
    +
    +
    +class graphnet.models.components.embedding.SpacetimeEncoder(seq_length)[source]
    +

    Bases: LightningModule

    +

    Spacetime encoder module.

    +

    Construct SpacetimeEncoder.

    +

    This module calculates space-time interval between each pair of events +and generates sinusoidal positional embeddings to be added to input +sequences.

    +
    +
    Parameters:
    +

    seq_length (int, default: 32) – Dimensionality of the sinusoidal positional embeddings.

    +
    +
    +
    +
    +forward(x)[source]
    +

    Forward pass.

    +
    +
    Return type:
    +

    Tensor

    +
    +
    Parameters:
    +

    x (Tensor) –

    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/api/graphnet.models.components.html b/api/graphnet.models.components.html index 073301a16..142a492cf 100644 --- a/api/graphnet.models.components.html +++ b/api/graphnet.models.components.html @@ -129,7 +129,7 @@ - + @@ -337,6 +337,13 @@
  • + embedding + + +
  • +
  • + + layers @@ -370,6 +377,13 @@ graphs +
  • +
  • + + + rnn + +
  • @@ -391,6 +405,13 @@ model +
  • +
  • + + + standard_averaged_model + +
  • @@ -466,10 +487,21 @@

    Submodules

  • +
  • + + + DropPath + + +
  • +
  • + + + Mlp + + +
  • +
  • + + + Block_rel + + +
  • +
  • + + + Attention_rel + + +
  • +
  • + + + Block +
  • @@ -454,6 +570,13 @@ graphs + +
  • + + + rnn + +
  • @@ -475,6 +598,13 @@ model +
  • +
  • + + + standard_averaged_model + +
  • @@ -557,6 +687,38 @@
  • DynTrans +
  • +
  • DropPath +
  • +
  • Mlp +
  • +
  • Block_rel +
  • +
  • Attention_rel +
  • +
  • Block
  • @@ -681,13 +843,13 @@
    Parameters:
      -
    • nn – The MLP/torch.Module to be used within the DynTrans.

    • layer_sizes (Optional[List[int]], default: None) – List of layer sizes to be used in DynTrans.

    • aggr (str, default: 'max') – Aggregation method to be used with DynTrans.

    • features_subset (Union[Sequence[int], slice, None], default: None) – Subset of features in Data.x that should be used when dynamically performing the new graph clustering after the EdgeConv operation. Defaults to all features.

    • -
    • n_head (int, default: 8) – Number of heads to be used in the multiheadattention models.

    • +
    • n_head (int, default: 8) – Number of heads to be used in the multiheadattention +models.

    • **kwargs (Any) – Additional features to be passed to DynTrans.

    @@ -710,6 +872,214 @@
    +
    +
    +class graphnet.models.components.layers.DropPath(drop_prob)[source]
    +

    Bases: LightningModule

    +

    Drop paths (Stochastic Depth) per sample.

    +

    Construct DropPath.

    +
    +
    Parameters:
    +

    drop_prob (float, default: 0.0) – Probability of dropping a path during training. +If 0.0, no paths are dropped. Defaults to None.

    +
    +
    +
    +
    +forward(x)[source]
    +

    Forward pass.

    +
    +
    Return type:
    +

    Tensor

    +
    +
    Parameters:
    +

    x (Tensor) –

    +
    +
    +
    +
    +
    +extra_repr()[source]
    +

    Return extra representation of the module.

    +
    +
    Return type:
    +

    str

    +
    +
    +
    +
    +
    +
    +class graphnet.models.components.layers.Mlp(in_features, hidden_features, out_features, activation=<class 'torch.nn.modules.activation.GELU'>, dropout_prob)[source]
    +

    Bases: LightningModule

    +

    Multi-Layer Perceptron (MLP) module.

    +

    Construct Mlp.

    +
    +
    Parameters:
    +
      +
    • in_features (int) – Number of input features.

    • +
    • hidden_features (Optional[int], default: None) – Number of hidden features. Defaults to None. +If None, it is set to the value of in_features.

    • +
    • out_features (Optional[int], default: None) – Number of output features. Defaults to None. +If None, it is set to the value of in_features.

    • +
    • activation (Module, default: <class 'torch.nn.modules.activation.GELU'>) – Activation layer. Defaults to nn.GELU.

    • +
    • dropout_prob (float, default: 0.0) – Dropout probability. Defaults to 0.0.

    • +
    +
    +
    +
    +
    +forward(x)[source]
    +

    Forward pass.

    +
    +
    Return type:
    +

    Tensor

    +
    +
    Parameters:
    +

    x (Tensor) –

    +
    +
    +
    +
    +
    +
    +class graphnet.models.components.layers.Block_rel(input_dim, num_heads, mlp_ratio, qkv_bias, qk_scale, dropout, attn_drop, drop_path, init_values, activation=<class 'torch.nn.modules.activation.GELU'>, norm_layer=<class 'torch.nn.modules.normalization.LayerNorm'>, attn_head_dim)[source]
    +

    Bases: LightningModule

    +

    Implementation of BEiTv2 Block.

    +

    Construct ‘Block_rel’.

    +
    +
    Parameters:
    +
      +
    • input_dim (int) – Dimension of the input tensor.

    • +
    • num_heads (int) – Number of attention heads to use in the Attention_rel

    • +
    • layer.

    • +
    • mlp_ratio (float, default: 4.0) – Ratio of the hidden size of the feedforward network to +the input size in the Mlp layer.

    • +
    • qkv_bias (bool, default: False) – Whether or not to include bias terms in the query, key, +and value matrices in the Attention_rel layer.

    • +
    • qk_scale (Optional[float], default: None) – Scaling factor for the dot product of the query and key +matrices in the Attention_rel layer.

    • +
    • dropout (float, default: 0.0) – Dropout probability to use in the Mlp layer.

    • +
    • attn_drop (float, default: 0.0) – Dropout probability to use in the Attention_rel layer.

    • +
    • drop_path (float, default: 0.0) – Probability of applying drop path regularization to the +output of the layer.

    • +
    • init_values (Optional[float], default: None) – Initial value to use for the gamma_1 and gamma_2 +parameters if not None.

    • +
    • activation (Module, default: <class 'torch.nn.modules.activation.GELU'>) – Activation function to use in the Mlp layer.

    • +
    • norm_layer (Module, default: <class 'torch.nn.modules.normalization.LayerNorm'>) – Normalization layer to use.

    • +
    • attn_head_dim (Optional[int], default: None) – Dimension of the attention head outputs in the +Attention_rel layer.

    • +
    +
    +
    +
    +
    +forward(x, key_padding_mask, rel_pos_bias, kv)[source]
    +

    Forward pass.

    +
    +
    Return type:
    +

    Tensor

    +
    +
    Parameters:
    +
      +
    • x (Tensor) –

    • +
    • key_padding_mask (Tensor | None) –

    • +
    • rel_pos_bias (Tensor | None) –

    • +
    • kv (Tensor | None) –

    • +
    +
    +
    +
    +
    +
    +
    +class graphnet.models.components.layers.Attention_rel(input_dim, num_heads, qkv_bias, qk_scale, attn_drop, proj_drop, attn_head_dim)[source]
    +

    Bases: LightningModule

    +

    Attention mechanism with relative position bias.

    +

    Construct ‘Attention_rel’.

    +
    +
    Parameters:
    +
      +
    • input_dim (int) – Dimension of the input tensor.

    • +
    • num_heads (int, default: 8) – the number of attention heads to use (default: 8)

    • +
    • qkv_bias (bool, default: False) – whether to add bias to the query, key, and value +projections. Defaults to False.

    • +
    • qk_scale (Optional[float], default: None) – a scaling factor that multiplies the dot product of query +and key vectors. Defaults to None. If None, computed as +:math: head_dim^(-1/2).

    • +
    • attn_drop (float, default: 0.0) – the dropout probability for the attention weights. +Defaults to 0.0.

    • +
    • proj_drop (float, default: 0.0) – the dropout probability for the output of the attention +module. Defaults to 0.0.

    • +
    • attn_head_dim (Optional[int], default: None) – the feature dimensionality of each attention head. +Defaults to None. If None, computed as dim // num_heads.

    • +
    +
    +
    +
    +
    +forward(q, k, v, rel_pos_bias, key_padding_mask)[source]
    +

    Forward pass.

    +
    +
    Return type:
    +

    Tensor

    +
    +
    Parameters:
    +
      +
    • q (Tensor) –

    • +
    • k (Tensor) –

    • +
    • v (Tensor) –

    • +
    • rel_pos_bias (Tensor | None) –

    • +
    • key_padding_mask (Tensor | None) –

    • +
    +
    +
    +
    +
    +
    +
    +class graphnet.models.components.layers.Block(input_dim, num_heads, mlp_ratio, dropout, attn_drop, drop_path, init_values, activation=<class 'torch.nn.modules.activation.GELU'>, norm_layer=<class 'torch.nn.modules.normalization.LayerNorm'>)[source]
    +

    Bases: LightningModule

    +

    Transformer block.

    +

    Construct ‘Block’.

    +
    +
    Parameters:
    +
      +
    • input_dim (int) – Dimension of the input tensor.

    • +
    • num_heads (int) – Number of attention heads to use in the +MultiheadAttention layer.

    • +
    • mlp_ratio (float, default: 4.0) – Ratio of the hidden size of the feedforward network to +the input size in the Mlp layer.

    • +
    • dropout (float, default: 0.0) – Dropout probability to use in the Mlp layer.

    • +
    • attn_drop (float, default: 0.0) – Dropout probability to use in the MultiheadAttention +layer.

    • +
    • drop_path (float, default: 0.0) – Probability of applying drop path regularization to the +output of the layer.

    • +
    • init_values (Optional[float], default: None) – Initial value to use for the gamma_1 and gamma_2 +parameters if not None.

    • +
    • activation (Module, default: <class 'torch.nn.modules.activation.GELU'>) – Activation function to use in the Mlp layer.

    • +
    • norm_layer (Module, default: <class 'torch.nn.modules.normalization.LayerNorm'>) – Normalization layer to use.

    • +
    +
    +
    +
    +
    +forward(x, attn_mask, key_padding_mask)[source]
    +

    Forward pass.

    +
    +
    Return type:
    +

    Tensor

    +
    +
    Parameters:
    +
      +
    • x (Tensor) –

    • +
    • attn_mask (Tensor | None) –

    • +
    • key_padding_mask (Tensor | None) –

    • +
    +
    +
    +
    +
    @@ -722,7 +1092,7 @@