Skip to content

Node classification (NC)

hypertorch.node_classification

NCClassifier

Bases: LightningModule

A LightningModule base class for multiclass node-classification models.

Attributes:

Name Type Description
encoder Module | None

Optional encoder module. Defaults to None.

classifier Module

Module that maps node features to class logits.

loss_fn Module

Multiclass loss function.

metrics_log_kwargs dict[str, Any]

Keyword arguments passed to metric log calls.

train_metrics MetricCollection | None

Optional training metrics.

val_metrics MetricCollection | None

Optional validation metrics.

test_metrics MetricCollection | None

Optional test metrics.

Source code in hypertorch/node_classification/common.py
class NCClassifier(L.LightningModule):
    """
    A LightningModule base class for multiclass node-classification models.

    Attributes:
        encoder: Optional encoder module. Defaults to ``None``.
        classifier: Module that maps node features to class logits.
        loss_fn: Multiclass loss function.
        metrics_log_kwargs: Keyword arguments passed to metric log calls.
        train_metrics: Optional training metrics.
        val_metrics: Optional validation metrics.
        test_metrics: Optional test metrics.
    """

    def __init__(
        self,
        classifier: nn.Module,
        loss_fn: nn.Module,
        encoder: nn.Module | None = None,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the NC classifier.

        Args:
            classifier: Module producing one class-logit row per node.
            loss_fn: Loss function used on supervised target nodes.
            encoder: Optional encoder module. Defaults to ``None``.
            metrics: Optional metric collection cloned independently per stage.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
        """
        super().__init__()
        self.encoder: nn.Module | None = encoder
        self.classifier: nn.Module = classifier
        self.loss_fn: nn.Module = loss_fn
        self.metrics_log_kwargs: dict[str, Any] = metrics_log_kwargs or {}

        if metrics is not None:
            self.train_metrics: MetricCollection | None = metrics.clone(
                prefix=stage_metric_prefix(Stage.TRAIN)
            )
            self.val_metrics: MetricCollection | None = metrics.clone(
                prefix=stage_metric_prefix(Stage.VAL)
            )
            self.test_metrics: MetricCollection | None = metrics.clone(
                prefix=stage_metric_prefix(Stage.TEST)
            )
        else:
            self.train_metrics = None
            self.val_metrics = None
            self.test_metrics = None

    def _compute_loss(
        self,
        logits: Tensor,
        labels: Tensor,
        batch_size: int,
        stage: Stage,
    ) -> Tensor:
        """
        Compute and log loss based on logits and labels.

        Args:
            logits: The predicted logits from the model.
            labels: The true labels corresponding to the logits.
            batch_size: The size of the current batch, used for logging.
            stage: The current stage (train/val/test) for logging purposes.

        Returns:
            loss: The computed loss tensor.
        """
        loss = self.loss_fn(logits, labels)
        self.log(
            name=stage_metric_name(stage, "loss"),
            value=loss,
            prog_bar=True,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
        return loss

    def _compute_metrics(
        self,
        logits: Tensor,
        labels: Tensor,
        batch_size: int,
        stage: Stage,
    ) -> None:
        """
        Compute and log metrics based on logits and labels.

        Uses class-based torchmetrics with proper multi-batch accumulation:
        1. ``update()`` accumulates predictions/targets across batches.
        2. Passing the MetricCollection to ``self.log_dict()`` tells Lightning to call
            ``compute()`` at epoch end and ``reset()`` automatically.

        Args:
            logits: The predicted logits from the model.
            labels: The true labels corresponding to the logits.
            batch_size: The size of the current batch, used for logging.
            stage: The current stage (train/val/test) for logging purposes.
        """
        stage_metrics = self._get_stage_metrics(stage)
        if stage_metrics is None:
            return  # No metrics to compute for this stage
        self._configure_metric_distributed_available(stage_metrics)

        # Accumulate predictions/targets for this batch
        stage_metrics.update(logits, labels)
        self.log_dict(
            stage_metrics,
            prog_bar=True,
            on_step=False,
            on_epoch=True,  # Compute and log metrics at epoch end for proper accumulation
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )

    def _get_stage_metrics(self, stage: Stage) -> MetricCollection | None:
        """
        Return the metric collection for the given stage.
        """
        match stage:
            case Stage.TRAIN:
                return self.train_metrics
            case Stage.VAL:
                return self.val_metrics
            case Stage.TEST:
                return self.test_metrics
            case _:
                raise ValueError(f"Unrecognized stage: {stage}")

    def _configure_metric_distributed_available(self, metrics: MetricCollection) -> None:
        """
        Make torchmetrics sync decisions follow the active Lightning trainer.
        """
        for metric in metrics.values(copy_state=False):
            metric.distributed_available_fn = self._distributed_available_fn

    def _distributed_available_fn(self) -> bool:
        """
        Return whether metrics should synchronize for the current trainer.
        """
        if self._trainer is None:
            return False
        return (
            self._trainer.world_size > 1
            and torch.distributed.is_available()
            and torch.distributed.is_initialized()
        )

    def _target_logits_and_labels(self, logits: Tensor, batch: HData) -> tuple[Tensor, Tensor]:
        """
        Select supervised node logits and labels from a batch.

        Args:
            logits: Node logits of shape ``[num_nodes, num_classes]``.
            batch: Batch containing node labels and an optional target mask.

        Returns:
            target_logits: Logits for supervised nodes.
            target_labels: Labels for supervised nodes.
        """
        target_node_mask = batch.target_node_mask
        target_logits = logits[target_node_mask]
        target_labels = batch.y[target_node_mask]
        return target_logits, target_labels

__init__(classifier, loss_fn, encoder=None, metrics=None, metrics_log_kwargs=None)

Initialize the NC classifier.

Parameters:

Name Type Description Default
classifier Module

Module producing one class-logit row per node.

required
loss_fn Module

Loss function used on supervised target nodes.

required
encoder Module | None

Optional encoder module. Defaults to None.

None
metrics MetricCollection | None

Optional metric collection cloned independently per stage.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls.

None
Source code in hypertorch/node_classification/common.py
def __init__(
    self,
    classifier: nn.Module,
    loss_fn: nn.Module,
    encoder: nn.Module | None = None,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the NC classifier.

    Args:
        classifier: Module producing one class-logit row per node.
        loss_fn: Loss function used on supervised target nodes.
        encoder: Optional encoder module. Defaults to ``None``.
        metrics: Optional metric collection cloned independently per stage.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
    """
    super().__init__()
    self.encoder: nn.Module | None = encoder
    self.classifier: nn.Module = classifier
    self.loss_fn: nn.Module = loss_fn
    self.metrics_log_kwargs: dict[str, Any] = metrics_log_kwargs or {}

    if metrics is not None:
        self.train_metrics: MetricCollection | None = metrics.clone(
            prefix=stage_metric_prefix(Stage.TRAIN)
        )
        self.val_metrics: MetricCollection | None = metrics.clone(
            prefix=stage_metric_prefix(Stage.VAL)
        )
        self.test_metrics: MetricCollection | None = metrics.clone(
            prefix=stage_metric_prefix(Stage.TEST)
        )
    else:
        self.train_metrics = None
        self.val_metrics = None
        self.test_metrics = None

CommonNeighborsClassifier

Bases: NCClassifier

A LightningModule for the CommonNeighbors-based NC classifier.

Attributes:

Name Type Description
encoder Module | None

Optional encoder module inherited from NCClassifier. Defaults to None.

classifier Module

Identity placeholder inherited from NCClassifier.

loss_fn Module

Loss function inherited from NCClassifier.

metrics_log_kwargs dict[str, Any]

Metric logging keyword arguments inherited from NCClassifier.

train_metrics MetricCollection | None

Optional training metrics inherited from NCClassifier.

val_metrics MetricCollection | None

Optional validation metrics inherited from NCClassifier.

test_metrics MetricCollection | None

Optional test metrics inherited from NCClassifier.

node_to_neighbors dict[int, Neighborhood]

Precomputed training-world node neighborhoods.

automatic_optimization bool

Disabled because this module has no trainable optimization.

Source code in hypertorch/node_classification/common_neighbors_nc.py
class CommonNeighborsClassifier(NCClassifier):
    """
    A LightningModule for the CommonNeighbors-based NC classifier.

    Attributes:
        encoder: Optional encoder module inherited from ``NCClassifier``. Defaults to ``None``.
        classifier: Identity placeholder inherited from ``NCClassifier``.
        loss_fn: Loss function inherited from ``NCClassifier``.
        metrics_log_kwargs: Metric logging keyword arguments inherited from ``NCClassifier``.
        train_metrics: Optional training metrics inherited from ``NCClassifier``.
        val_metrics: Optional validation metrics inherited from ``NCClassifier``.
        test_metrics: Optional test metrics inherited from ``NCClassifier``.
        node_to_neighbors: Precomputed training-world node neighborhoods.
        automatic_optimization: Disabled because this module has no trainable optimization.
    """

    def __init__(
        self,
        train_hdata: HData,
        num_classes: int,
        aggregation: Literal["mean", "min", "sum"] = "sum",
        exclude_self_reference: bool = True,
        classifier: nn.Module | None = None,
        loss_fn: nn.Module | None = None,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the CommonNeighbors-based NC classifier.

        Args:
            train_hdata: Training data used to precompute neighborhoods and labeled
                reference nodes.
            num_classes: Number of node classes.
            aggregation: Method used to aggregate reference-node scores per class.
                Defaults to ``"sum"``.
            exclude_self_reference: Whether a node should ignore itself when it also
                appears among labeled reference nodes. Defaults to ``True``.
            classifier: Optional classifier module.
            loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
            metrics: Optional metric collection for evaluation. Defaults to ``None``.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
                Defaults to ``None``.
        """
        super().__init__(
            classifier=classifier
            if classifier is not None
            else self.__default_classifier(
                train_hdata=train_hdata,
                num_classes=num_classes,
                aggregation=aggregation,
                exclude_self_reference=exclude_self_reference,
            ),
            loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
            metrics=metrics,
            metrics_log_kwargs=metrics_log_kwargs,
        )

        # Pre-compute neighbors of training nodes based on training edges only
        # to create a "known world" for the model to make predictions from
        self.node_to_neighbors: dict[int, Neighborhood] = Hypergraph.from_hyperedge_index(
            hyperedge_index=HyperedgeIndex(
                hyperedge_index=train_hdata.hyperedge_index,
            )
            .to_global(global_node_ids=train_hdata.global_node_ids)
            .item
        ).neighbors_of_all()

        self.automatic_optimization: bool = False

    def forward(self, global_node_ids: Tensor) -> Tensor:
        """
        Compute common-neighbor class scores for the given nodes.

        Args:
            global_node_ids: Stable node IDs matching the training-world node IDs.

        Returns:
            logits: Node-class scores of shape ``(num_nodes, num_classes)``.
        """
        return self.classifier(
            candidate_nodes=global_node_ids,
            node_to_neighbors=self.node_to_neighbors,
        )

    def on_fit_start(self) -> None:
        """
        Warn users if they are running unnecessary training epochs.
        """
        if self.trainer.max_epochs is None or self.trainer.max_epochs > 0:
            warnings.warn(
                f"{self.__class__.__name__} is a non-trainable heuristic model. "
                "No optimization occurs. Set max_epochs=0 in your trainer for instant evaluation.",
                UserWarning,
                stacklevel=2,
            )

    def training_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Return a zero loss for the non-trainable heuristic.

        Args:
            batch: Input batch, unused.
            batch_idx: Batch index, unused.

        Returns:
            loss: Zero scalar tensor on the module device.
        """
        return torch.tensor(0.0, dtype=torch.float, device=self.device)

    def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Return a zero validation loss for the non-trainable heuristic.

        Args:
            batch: Input batch, unused.
            batch_idx: Batch index, unused.

        Returns:
            loss: Zero scalar tensor on the module device.
        """
        return torch.tensor(0.0, dtype=torch.float, device=self.device)

    def test_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Evaluate a test batch.

        Args:
            batch: Test batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Test loss.
        """
        return self.__step(batch, stage=Stage.TEST)

    def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Predict common-neighbor class scores for a batch.

        Args:
            batch: Prediction batch.
            batch_idx: Batch index, unused.

        Returns:
            logits: Predicted node-class scores.
        """
        return self.forward(batch.global_node_ids)

    def configure_optimizers(self) -> None:
        """
        Return no optimizer for the non-trainable heuristic.

        Returns:
            optimizer: No optimizer is configured, so always returns ``None``.
        """
        # No training, so no optimizers needed

    def __step(self, batch: HData, stage: Stage) -> Tensor:
        """
        Shared evaluation logic for all stages.

        Args:
            batch: `HData` object containing the hypergraph.
            stage: Current evaluation stage.

        Returns:
            loss: Computed loss.
        """
        scores = self.forward(batch.global_node_ids)
        target_logits, target_labels = self._target_logits_and_labels(scores, batch)
        batch_size = int(target_labels.size(0))

        loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
        self._compute_metrics(target_logits, target_labels, batch_size, stage)

        return loss

    def __class_to_node_ids(self, train_hdata: HData, num_classes: int) -> dict[int, list[int]]:
        """
        Group labeled training nodes by class.

        Args:
            train_hdata: Training data containing node labels and train node mask.
            num_classes: Number of node classes.

        Returns:
            class_to_node_ids: Dictionary mapping class IDs to lists of node IDs.
        """
        class_to_node_ids: dict[int, list[int]] = {class_id: [] for class_id in range(num_classes)}
        train_node_ids = train_hdata.global_node_ids[train_hdata.target_node_mask].tolist()
        train_class_labels = train_hdata.y[train_hdata.target_node_mask].tolist()

        for node_id, class_label in zip(train_node_ids, train_class_labels, strict=True):
            class_to_node_ids[int(class_label)].append(int(node_id))

        return class_to_node_ids

    def __default_classifier(
        self,
        train_hdata: HData,
        num_classes: int,
        aggregation: Literal["mean", "min", "sum"],
        exclude_self_reference: bool = True,
    ) -> CommonNeighbors:
        """
        Create a default CommonNeighbors classifier with a CommonNeighborsNodeScorer.

        Args:
            train_hdata: Training data containing node labels and train node mask.
            num_classes: Number of node classes.
            aggregation: Method used to aggregate reference-node scores per class.
            exclude_self_reference: Whether a node should ignore itself when it also
                appears among labeled reference nodes.

        Returns:
            classifier: A CommonNeighbors classifier with a CommonNeighborsNodeScorer.
        """
        class_to_node_ids = self.__class_to_node_ids(
            train_hdata=train_hdata,
            num_classes=num_classes,
        )

        scorer = CommonNeighborsNodeScorer(
            num_classes=num_classes,
            class_to_node_ids=class_to_node_ids,
            aggregation=aggregation,
            exclude_self_reference=exclude_self_reference,
        )

        return CommonNeighbors(aggregation=aggregation, scorer=scorer)

__init__(train_hdata, num_classes, aggregation='sum', exclude_self_reference=True, classifier=None, loss_fn=None, metrics=None, metrics_log_kwargs=None)

Initialize the CommonNeighbors-based NC classifier.

Parameters:

Name Type Description Default
train_hdata HData

Training data used to precompute neighborhoods and labeled reference nodes.

required
num_classes int

Number of node classes.

required
aggregation Literal['mean', 'min', 'sum']

Method used to aggregate reference-node scores per class. Defaults to "sum".

'sum'
exclude_self_reference bool

Whether a node should ignore itself when it also appears among labeled reference nodes. Defaults to True.

True
classifier Module | None

Optional classifier module.

None
loss_fn Module | None

Optional loss function. Defaults to CrossEntropyLoss.

None
metrics MetricCollection | None

Optional metric collection for evaluation. Defaults to None.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls. Defaults to None.

None
Source code in hypertorch/node_classification/common_neighbors_nc.py
def __init__(
    self,
    train_hdata: HData,
    num_classes: int,
    aggregation: Literal["mean", "min", "sum"] = "sum",
    exclude_self_reference: bool = True,
    classifier: nn.Module | None = None,
    loss_fn: nn.Module | None = None,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the CommonNeighbors-based NC classifier.

    Args:
        train_hdata: Training data used to precompute neighborhoods and labeled
            reference nodes.
        num_classes: Number of node classes.
        aggregation: Method used to aggregate reference-node scores per class.
            Defaults to ``"sum"``.
        exclude_self_reference: Whether a node should ignore itself when it also
            appears among labeled reference nodes. Defaults to ``True``.
        classifier: Optional classifier module.
        loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
        metrics: Optional metric collection for evaluation. Defaults to ``None``.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
            Defaults to ``None``.
    """
    super().__init__(
        classifier=classifier
        if classifier is not None
        else self.__default_classifier(
            train_hdata=train_hdata,
            num_classes=num_classes,
            aggregation=aggregation,
            exclude_self_reference=exclude_self_reference,
        ),
        loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
        metrics=metrics,
        metrics_log_kwargs=metrics_log_kwargs,
    )

    # Pre-compute neighbors of training nodes based on training edges only
    # to create a "known world" for the model to make predictions from
    self.node_to_neighbors: dict[int, Neighborhood] = Hypergraph.from_hyperedge_index(
        hyperedge_index=HyperedgeIndex(
            hyperedge_index=train_hdata.hyperedge_index,
        )
        .to_global(global_node_ids=train_hdata.global_node_ids)
        .item
    ).neighbors_of_all()

    self.automatic_optimization: bool = False

forward(global_node_ids)

Compute common-neighbor class scores for the given nodes.

Parameters:

Name Type Description Default
global_node_ids Tensor

Stable node IDs matching the training-world node IDs.

required

Returns:

Name Type Description
logits Tensor

Node-class scores of shape (num_nodes, num_classes).

Source code in hypertorch/node_classification/common_neighbors_nc.py
def forward(self, global_node_ids: Tensor) -> Tensor:
    """
    Compute common-neighbor class scores for the given nodes.

    Args:
        global_node_ids: Stable node IDs matching the training-world node IDs.

    Returns:
        logits: Node-class scores of shape ``(num_nodes, num_classes)``.
    """
    return self.classifier(
        candidate_nodes=global_node_ids,
        node_to_neighbors=self.node_to_neighbors,
    )

on_fit_start()

Warn users if they are running unnecessary training epochs.

Source code in hypertorch/node_classification/common_neighbors_nc.py
def on_fit_start(self) -> None:
    """
    Warn users if they are running unnecessary training epochs.
    """
    if self.trainer.max_epochs is None or self.trainer.max_epochs > 0:
        warnings.warn(
            f"{self.__class__.__name__} is a non-trainable heuristic model. "
            "No optimization occurs. Set max_epochs=0 in your trainer for instant evaluation.",
            UserWarning,
            stacklevel=2,
        )

training_step(batch, batch_idx)

Return a zero loss for the non-trainable heuristic.

Parameters:

Name Type Description Default
batch HData

Input batch, unused.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Zero scalar tensor on the module device.

Source code in hypertorch/node_classification/common_neighbors_nc.py
def training_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Return a zero loss for the non-trainable heuristic.

    Args:
        batch: Input batch, unused.
        batch_idx: Batch index, unused.

    Returns:
        loss: Zero scalar tensor on the module device.
    """
    return torch.tensor(0.0, dtype=torch.float, device=self.device)

validation_step(batch, batch_idx)

Return a zero validation loss for the non-trainable heuristic.

Parameters:

Name Type Description Default
batch HData

Input batch, unused.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Zero scalar tensor on the module device.

Source code in hypertorch/node_classification/common_neighbors_nc.py
def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Return a zero validation loss for the non-trainable heuristic.

    Args:
        batch: Input batch, unused.
        batch_idx: Batch index, unused.

    Returns:
        loss: Zero scalar tensor on the module device.
    """
    return torch.tensor(0.0, dtype=torch.float, device=self.device)

test_step(batch, batch_idx)

Evaluate a test batch.

Parameters:

Name Type Description Default
batch HData

Test batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Test loss.

Source code in hypertorch/node_classification/common_neighbors_nc.py
def test_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Evaluate a test batch.

    Args:
        batch: Test batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Test loss.
    """
    return self.__step(batch, stage=Stage.TEST)

predict_step(batch, batch_idx)

Predict common-neighbor class scores for a batch.

Parameters:

Name Type Description Default
batch HData

Prediction batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
logits Tensor

Predicted node-class scores.

Source code in hypertorch/node_classification/common_neighbors_nc.py
def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Predict common-neighbor class scores for a batch.

    Args:
        batch: Prediction batch.
        batch_idx: Batch index, unused.

    Returns:
        logits: Predicted node-class scores.
    """
    return self.forward(batch.global_node_ids)

configure_optimizers()

Return no optimizer for the non-trainable heuristic.

Returns:

Name Type Description
optimizer None

No optimizer is configured, so always returns None.

Source code in hypertorch/node_classification/common_neighbors_nc.py
def configure_optimizers(self) -> None:
    """
    Return no optimizer for the non-trainable heuristic.

    Returns:
        optimizer: No optimizer is configured, so always returns ``None``.
    """

__step(batch, stage)

Shared evaluation logic for all stages.

Parameters:

Name Type Description Default
batch HData

HData object containing the hypergraph.

required
stage Stage

Current evaluation stage.

required

Returns:

Name Type Description
loss Tensor

Computed loss.

Source code in hypertorch/node_classification/common_neighbors_nc.py
def __step(self, batch: HData, stage: Stage) -> Tensor:
    """
    Shared evaluation logic for all stages.

    Args:
        batch: `HData` object containing the hypergraph.
        stage: Current evaluation stage.

    Returns:
        loss: Computed loss.
    """
    scores = self.forward(batch.global_node_ids)
    target_logits, target_labels = self._target_logits_and_labels(scores, batch)
    batch_size = int(target_labels.size(0))

    loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
    self._compute_metrics(target_logits, target_labels, batch_size, stage)

    return loss

__class_to_node_ids(train_hdata, num_classes)

Group labeled training nodes by class.

Parameters:

Name Type Description Default
train_hdata HData

Training data containing node labels and train node mask.

required
num_classes int

Number of node classes.

required

Returns:

Name Type Description
class_to_node_ids dict[int, list[int]]

Dictionary mapping class IDs to lists of node IDs.

Source code in hypertorch/node_classification/common_neighbors_nc.py
def __class_to_node_ids(self, train_hdata: HData, num_classes: int) -> dict[int, list[int]]:
    """
    Group labeled training nodes by class.

    Args:
        train_hdata: Training data containing node labels and train node mask.
        num_classes: Number of node classes.

    Returns:
        class_to_node_ids: Dictionary mapping class IDs to lists of node IDs.
    """
    class_to_node_ids: dict[int, list[int]] = {class_id: [] for class_id in range(num_classes)}
    train_node_ids = train_hdata.global_node_ids[train_hdata.target_node_mask].tolist()
    train_class_labels = train_hdata.y[train_hdata.target_node_mask].tolist()

    for node_id, class_label in zip(train_node_ids, train_class_labels, strict=True):
        class_to_node_ids[int(class_label)].append(int(node_id))

    return class_to_node_ids

__default_classifier(train_hdata, num_classes, aggregation, exclude_self_reference=True)

Create a default CommonNeighbors classifier with a CommonNeighborsNodeScorer.

Parameters:

Name Type Description Default
train_hdata HData

Training data containing node labels and train node mask.

required
num_classes int

Number of node classes.

required
aggregation Literal['mean', 'min', 'sum']

Method used to aggregate reference-node scores per class.

required
exclude_self_reference bool

Whether a node should ignore itself when it also appears among labeled reference nodes.

True

Returns:

Name Type Description
classifier CommonNeighbors

A CommonNeighbors classifier with a CommonNeighborsNodeScorer.

Source code in hypertorch/node_classification/common_neighbors_nc.py
def __default_classifier(
    self,
    train_hdata: HData,
    num_classes: int,
    aggregation: Literal["mean", "min", "sum"],
    exclude_self_reference: bool = True,
) -> CommonNeighbors:
    """
    Create a default CommonNeighbors classifier with a CommonNeighborsNodeScorer.

    Args:
        train_hdata: Training data containing node labels and train node mask.
        num_classes: Number of node classes.
        aggregation: Method used to aggregate reference-node scores per class.
        exclude_self_reference: Whether a node should ignore itself when it also
            appears among labeled reference nodes.

    Returns:
        classifier: A CommonNeighbors classifier with a CommonNeighborsNodeScorer.
    """
    class_to_node_ids = self.__class_to_node_ids(
        train_hdata=train_hdata,
        num_classes=num_classes,
    )

    scorer = CommonNeighborsNodeScorer(
        num_classes=num_classes,
        class_to_node_ids=class_to_node_ids,
        aggregation=aggregation,
        exclude_self_reference=exclude_self_reference,
    )

    return CommonNeighbors(aggregation=aggregation, scorer=scorer)

GCNClassifierConfig

Bases: TypedDict

Configuration for the GCN classifier in GCNClassifier.

Attributes:

Name Type Description
in_channels int

Number of input features per node.

out_channels int

Number of node classes.

hidden_channels NotRequired[int]

Number of hidden units in intermediate GCN layers.

num_layers NotRequired[int]

Number of GCN layers. Defaults to 2.

drop_rate NotRequired[float]

Dropout rate applied after each hidden GCN layer. Defaults to 0.0.

bias NotRequired[bool]

Whether to include bias terms. Defaults to True.

improved NotRequired[bool]

Whether to use the improved GCN normalization. Defaults to False.

add_self_loops NotRequired[bool]

Whether to add self-loops before convolution. Defaults to True.

normalize NotRequired[bool]

Whether to normalize the adjacency matrix in GCNConv. Defaults to True.

cached NotRequired[bool]

Whether to cache the normalized graph in GCNConv. Defaults to False.

graph_reduction_strategy NotRequired[GraphReductionStrategy]

Strategy for reducing the hypergraph to a graph. Defaults to "clique_expansion".

num_nodes NotRequired[int]

Optional total number of nodes to use during graph reduction.

activation_fn NotRequired[ActivationFn]

Activation function to use after each hidden layer. Defaults to nn.ReLU.

activation_fn_kwargs NotRequired[dict]

Keyword arguments for the activation function. Defaults to empty dict.

Source code in hypertorch/node_classification/gcn_nc.py
class GCNClassifierConfig(TypedDict):
    """
    Configuration for the GCN classifier in ``GCNClassifier``.

    Attributes:
        in_channels: Number of input features per node.
        out_channels: Number of node classes.
        hidden_channels: Number of hidden units in intermediate GCN layers.
        num_layers: Number of GCN layers. Defaults to ``2``.
        drop_rate: Dropout rate applied after each hidden GCN layer. Defaults to ``0.0``.
        bias: Whether to include bias terms. Defaults to ``True``.
        improved: Whether to use the improved GCN normalization. Defaults to ``False``.
        add_self_loops: Whether to add self-loops before convolution. Defaults to ``True``.
        normalize: Whether to normalize the adjacency matrix in ``GCNConv``. Defaults to ``True``.
        cached: Whether to cache the normalized graph in ``GCNConv``. Defaults to ``False``.
        graph_reduction_strategy: Strategy for reducing the hypergraph to a graph.
            Defaults to ``"clique_expansion"``.
        num_nodes: Optional total number of nodes to use during graph reduction.
        activation_fn: Activation function to use after each hidden layer.
            Defaults to ``nn.ReLU``.
        activation_fn_kwargs: Keyword arguments for the activation function.
            Defaults to empty dict.
    """

    in_channels: int
    out_channels: int
    hidden_channels: NotRequired[int]
    num_layers: NotRequired[int]
    drop_rate: NotRequired[float]
    bias: NotRequired[bool]
    improved: NotRequired[bool]
    add_self_loops: NotRequired[bool]
    normalize: NotRequired[bool]
    cached: NotRequired[bool]
    graph_reduction_strategy: NotRequired[GraphReductionStrategy]
    num_nodes: NotRequired[int]
    activation_fn: NotRequired[ActivationFn]
    activation_fn_kwargs: NotRequired[dict]

GCNClassifier

Bases: NCClassifier

A LightningModule for GCN-based NC classifier.

Reduces the hypergraph to a graph, then applies GCN layers to produce per-node class logits.

Attributes:

Name Type Description
encoder Module | None

Optional encoder module inherited from NCClassifier. Defaults to None.

classifier Module

GCN classifier module inherited from NCClassifier.

loss_fn Module

Loss function inherited from NCClassifier.

metrics_log_kwargs dict[str, Any]

Metric logging keyword arguments inherited from NCClassifier.

train_metrics MetricCollection | None

Optional training metrics inherited from NCClassifier.

val_metrics MetricCollection | None

Optional validation metrics inherited from NCClassifier.

test_metrics MetricCollection | None

Optional test metrics inherited from NCClassifier.

lr float

Learning rate for the optimizer. Defaults to 0.01.

weight_decay float

L2 regularization. Defaults to 5e-4.

Source code in hypertorch/node_classification/gcn_nc.py
class GCNClassifier(NCClassifier):
    """
    A LightningModule for GCN-based NC classifier.

    Reduces the hypergraph to a graph, then applies GCN
    layers to produce per-node class logits.

    Attributes:
        encoder: Optional encoder module inherited from ``NCClassifier``. Defaults to ``None``.
        classifier: GCN classifier module inherited from ``NCClassifier``.
        loss_fn: Loss function inherited from ``NCClassifier``.
        metrics_log_kwargs: Metric logging keyword arguments inherited from ``NCClassifier``.
        train_metrics: Optional training metrics inherited from ``NCClassifier``.
        val_metrics: Optional validation metrics inherited from ``NCClassifier``.
        test_metrics: Optional test metrics inherited from ``NCClassifier``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``5e-4``.
    """

    def __init__(
        self,
        classifier_config: GCNClassifierConfig,
        loss_fn: nn.Module | None = None,
        lr: float = 0.01,
        weight_decay: float = 5e-4,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the GCN-based NC classifier.

        Args:
            classifier_config: Configuration for the GCN classifier.
            loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
            lr: Learning rate for the optimizer. Defaults to ``0.01``.
            weight_decay: L2 regularization. Defaults to ``5e-4``.
            metrics: Optional metric collection for evaluation. Defaults to ``None``.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
                Useful for configuring distributed synchronization behavior
                of ``torchmetrics``. Defaults to ``None``.
        """
        classifier = GCN(
            in_channels=classifier_config["in_channels"],
            out_channels=classifier_config["out_channels"],
            hidden_channels=classifier_config.get("hidden_channels"),
            num_layers=classifier_config.get("num_layers", 2),
            drop_rate=classifier_config.get("drop_rate", 0.0),
            bias=classifier_config.get("bias", True),
            activation_fn=classifier_config.get("activation_fn"),
            activation_fn_kwargs=classifier_config.get("activation_fn_kwargs"),
            improved=classifier_config.get("improved", False),
            add_self_loops=classifier_config.get("add_self_loops", True),
            normalize=classifier_config.get("normalize", True),
            cached=classifier_config.get("cached", False),
        )

        super().__init__(
            classifier=classifier,
            loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
            metrics=metrics,
            metrics_log_kwargs=metrics_log_kwargs,
        )

        self.classifier_config: GCNClassifierConfig = classifier_config
        self.lr: float = lr
        self.weight_decay: float = weight_decay

    def forward(self, x: Tensor, hyperedge_index: Tensor) -> Tensor:
        """
        Predict node-class logits from node features and hypergraph structure.

        Examples:
            Given 4 nodes with 3 features each and 2 output classes:
                >>> x.shape
                ... torch.Size([4, 3])
                >>> hyperedge_index.shape
                ... torch.Size([2, 6])

            The forward pass maps each node to one row of class logits:
                >>> logits = model.forward(x, hyperedge_index)
                >>> logits.shape
                ... torch.Size([4, 2])

        Args:
            x: Node feature matrix of shape ``(num_nodes, in_channels)``.
            hyperedge_index: Hyperedge connectivity of shape ``(2, num_incidences)``.

        Returns:
            logits: Node-class logits of shape ``(num_nodes, num_classes)``.
        """
        # Reduce hypergraph to graph and remove self-loops
        reduced_edge_index = HyperedgeIndex(hyperedge_index).reduce(
            strategy=self.classifier_config.get(
                "graph_reduction_strategy",
                GraphReductionStrategyEnum.CLIQUE_EXPANSION,
            ),
            num_nodes=self.classifier_config.get("num_nodes"),
        )
        edge_index = EdgeIndex(reduced_edge_index).remove_selfloops().item

        return self.classifier(x, edge_index)

    def training_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a training step.

        Args:
            batch: Training batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Training loss.
        """
        return self.__eval_step(batch, Stage.TRAIN)

    def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a validation step.

        Args:
            batch: Validation batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Validation loss.
        """
        return self.__eval_step(batch, Stage.VAL)

    def test_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a test step.

        Args:
            batch: Test batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Test loss.
        """
        return self.__eval_step(batch, Stage.TEST)

    def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Predict node-class logits for a batch.

        Args:
            batch: Prediction batch.
            batch_idx: Batch index, unused.

        Returns:
            logits: Predicted node-class logits.
        """
        return self.forward(batch.x, batch.hyperedge_index)

    def configure_optimizers(self) -> optim.Adam:
        """
        Configure the optimizer.

        Returns:
            optimizer: Adam optimizer.
        """
        return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

    def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
        """
        Run shared evaluation logic for a stage.

        Args:
            batch: Input batch.
            stage: Current evaluation stage.

        Returns:
            loss: Computed loss.
        """
        logits = self.forward(batch.x, batch.hyperedge_index)
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = int(target_labels.size(0))

        loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
        self._compute_metrics(target_logits, target_labels, batch_size, stage)
        return loss

__init__(classifier_config, loss_fn=None, lr=0.01, weight_decay=0.0005, metrics=None, metrics_log_kwargs=None)

Initialize the GCN-based NC classifier.

Parameters:

Name Type Description Default
classifier_config GCNClassifierConfig

Configuration for the GCN classifier.

required
loss_fn Module | None

Optional loss function. Defaults to CrossEntropyLoss.

None
lr float

Learning rate for the optimizer. Defaults to 0.01.

0.01
weight_decay float

L2 regularization. Defaults to 5e-4.

0.0005
metrics MetricCollection | None

Optional metric collection for evaluation. Defaults to None.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls. Useful for configuring distributed synchronization behavior of torchmetrics. Defaults to None.

None
Source code in hypertorch/node_classification/gcn_nc.py
def __init__(
    self,
    classifier_config: GCNClassifierConfig,
    loss_fn: nn.Module | None = None,
    lr: float = 0.01,
    weight_decay: float = 5e-4,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the GCN-based NC classifier.

    Args:
        classifier_config: Configuration for the GCN classifier.
        loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``5e-4``.
        metrics: Optional metric collection for evaluation. Defaults to ``None``.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
            Useful for configuring distributed synchronization behavior
            of ``torchmetrics``. Defaults to ``None``.
    """
    classifier = GCN(
        in_channels=classifier_config["in_channels"],
        out_channels=classifier_config["out_channels"],
        hidden_channels=classifier_config.get("hidden_channels"),
        num_layers=classifier_config.get("num_layers", 2),
        drop_rate=classifier_config.get("drop_rate", 0.0),
        bias=classifier_config.get("bias", True),
        activation_fn=classifier_config.get("activation_fn"),
        activation_fn_kwargs=classifier_config.get("activation_fn_kwargs"),
        improved=classifier_config.get("improved", False),
        add_self_loops=classifier_config.get("add_self_loops", True),
        normalize=classifier_config.get("normalize", True),
        cached=classifier_config.get("cached", False),
    )

    super().__init__(
        classifier=classifier,
        loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
        metrics=metrics,
        metrics_log_kwargs=metrics_log_kwargs,
    )

    self.classifier_config: GCNClassifierConfig = classifier_config
    self.lr: float = lr
    self.weight_decay: float = weight_decay

forward(x, hyperedge_index)

Predict node-class logits from node features and hypergraph structure.

Examples:

Given 4 nodes with 3 features each and 2 output classes: >>> x.shape ... torch.Size([4, 3]) >>> hyperedge_index.shape ... torch.Size([2, 6])

The forward pass maps each node to one row of class logits: >>> logits = model.forward(x, hyperedge_index) >>> logits.shape ... torch.Size([4, 2])

Parameters:

Name Type Description Default
x Tensor

Node feature matrix of shape (num_nodes, in_channels).

required
hyperedge_index Tensor

Hyperedge connectivity of shape (2, num_incidences).

required

Returns:

Name Type Description
logits Tensor

Node-class logits of shape (num_nodes, num_classes).

Source code in hypertorch/node_classification/gcn_nc.py
def forward(self, x: Tensor, hyperedge_index: Tensor) -> Tensor:
    """
    Predict node-class logits from node features and hypergraph structure.

    Examples:
        Given 4 nodes with 3 features each and 2 output classes:
            >>> x.shape
            ... torch.Size([4, 3])
            >>> hyperedge_index.shape
            ... torch.Size([2, 6])

        The forward pass maps each node to one row of class logits:
            >>> logits = model.forward(x, hyperedge_index)
            >>> logits.shape
            ... torch.Size([4, 2])

    Args:
        x: Node feature matrix of shape ``(num_nodes, in_channels)``.
        hyperedge_index: Hyperedge connectivity of shape ``(2, num_incidences)``.

    Returns:
        logits: Node-class logits of shape ``(num_nodes, num_classes)``.
    """
    # Reduce hypergraph to graph and remove self-loops
    reduced_edge_index = HyperedgeIndex(hyperedge_index).reduce(
        strategy=self.classifier_config.get(
            "graph_reduction_strategy",
            GraphReductionStrategyEnum.CLIQUE_EXPANSION,
        ),
        num_nodes=self.classifier_config.get("num_nodes"),
    )
    edge_index = EdgeIndex(reduced_edge_index).remove_selfloops().item

    return self.classifier(x, edge_index)

training_step(batch, batch_idx)

Run a training step.

Parameters:

Name Type Description Default
batch HData

Training batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Training loss.

Source code in hypertorch/node_classification/gcn_nc.py
def training_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a training step.

    Args:
        batch: Training batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Training loss.
    """
    return self.__eval_step(batch, Stage.TRAIN)

validation_step(batch, batch_idx)

Run a validation step.

Parameters:

Name Type Description Default
batch HData

Validation batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Validation loss.

Source code in hypertorch/node_classification/gcn_nc.py
def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a validation step.

    Args:
        batch: Validation batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Validation loss.
    """
    return self.__eval_step(batch, Stage.VAL)

test_step(batch, batch_idx)

Run a test step.

Parameters:

Name Type Description Default
batch HData

Test batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Test loss.

Source code in hypertorch/node_classification/gcn_nc.py
def test_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a test step.

    Args:
        batch: Test batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Test loss.
    """
    return self.__eval_step(batch, Stage.TEST)

predict_step(batch, batch_idx)

Predict node-class logits for a batch.

Parameters:

Name Type Description Default
batch HData

Prediction batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
logits Tensor

Predicted node-class logits.

Source code in hypertorch/node_classification/gcn_nc.py
def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Predict node-class logits for a batch.

    Args:
        batch: Prediction batch.
        batch_idx: Batch index, unused.

    Returns:
        logits: Predicted node-class logits.
    """
    return self.forward(batch.x, batch.hyperedge_index)

configure_optimizers()

Configure the optimizer.

Returns:

Name Type Description
optimizer Adam

Adam optimizer.

Source code in hypertorch/node_classification/gcn_nc.py
def configure_optimizers(self) -> optim.Adam:
    """
    Configure the optimizer.

    Returns:
        optimizer: Adam optimizer.
    """
    return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

__eval_step(batch, stage)

Run shared evaluation logic for a stage.

Parameters:

Name Type Description Default
batch HData

Input batch.

required
stage Stage

Current evaluation stage.

required

Returns:

Name Type Description
loss Tensor

Computed loss.

Source code in hypertorch/node_classification/gcn_nc.py
def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
    """
    Run shared evaluation logic for a stage.

    Args:
        batch: Input batch.
        stage: Current evaluation stage.

    Returns:
        loss: Computed loss.
    """
    logits = self.forward(batch.x, batch.hyperedge_index)
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = int(target_labels.size(0))

    loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
    self._compute_metrics(target_logits, target_labels, batch_size, stage)
    return loss

HGNNClassifierConfig

Bases: TypedDict

Configuration for the HGNN classifier in HGNNClassifier.

Attributes:

Name Type Description
in_channels int

Number of input features per node.

hidden_channels int

Number of hidden units in the intermediate HGNN layer.

out_channels int

Number of node classes.

bias NotRequired[bool]

Whether to include bias terms. Defaults to True.

use_batch_normalization NotRequired[bool]

Whether to use batch normalization. Defaults to False.

drop_rate NotRequired[float]

Dropout rate. Defaults to 0.5.

Source code in hypertorch/node_classification/hgnn_nc.py
class HGNNClassifierConfig(TypedDict):
    """
    Configuration for the HGNN classifier in ``HGNNClassifier``.

    Attributes:
        in_channels: Number of input features per node.
        hidden_channels: Number of hidden units in the intermediate HGNN layer.
        out_channels: Number of node classes.
        bias: Whether to include bias terms. Defaults to ``True``.
        use_batch_normalization: Whether to use batch normalization. Defaults to ``False``.
        drop_rate: Dropout rate. Defaults to ``0.5``.
    """

    in_channels: int
    hidden_channels: int
    out_channels: int
    bias: NotRequired[bool]
    use_batch_normalization: NotRequired[bool]
    drop_rate: NotRequired[float]

HGNNClassifier

Bases: NCClassifier

A LightningModule for HGNN-based NC classifier.

Uses HGNN to transform node features and hypergraph incidence structure directly into per-node class logits. During training, validation, and testing, loss and metrics are computed on supervised target nodes selected by HData.target_node_mask.

Attributes:

Name Type Description
encoder Module | None

Optional encoder module inherited from NCClassifier. Defaults to None.

classifier Module

HGNN classifier module inherited from NCClassifier.

loss_fn Module

Loss function inherited from NCClassifier.

metrics_log_kwargs dict[str, Any]

Metric logging keyword arguments inherited from NCClassifier.

train_metrics MetricCollection | None

Optional training metrics inherited from NCClassifier.

val_metrics MetricCollection | None

Optional validation metrics inherited from NCClassifier.

test_metrics MetricCollection | None

Optional test metrics inherited from NCClassifier.

lr float

Learning rate for the optimizer. Defaults to 0.01.

weight_decay float

L2 regularization. Defaults to 5e-4.

Source code in hypertorch/node_classification/hgnn_nc.py
class HGNNClassifier(NCClassifier):
    """
    A LightningModule for HGNN-based NC classifier.

    Uses HGNN to transform node features and hypergraph incidence structure directly into
    per-node class logits. During training, validation, and testing, loss and metrics
    are computed on supervised target nodes selected by ``HData.target_node_mask``.

    Attributes:
        encoder: Optional encoder module inherited from ``NCClassifier``. Defaults to ``None``.
        classifier: HGNN classifier module inherited from ``NCClassifier``.
        loss_fn: Loss function inherited from ``NCClassifier``.
        metrics_log_kwargs: Metric logging keyword arguments inherited from ``NCClassifier``.
        train_metrics: Optional training metrics inherited from ``NCClassifier``.
        val_metrics: Optional validation metrics inherited from ``NCClassifier``.
        test_metrics: Optional test metrics inherited from ``NCClassifier``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``5e-4``.
    """

    def __init__(
        self,
        classifier_config: HGNNClassifierConfig,
        loss_fn: nn.Module | None = None,
        lr: float = 0.01,
        weight_decay: float = 5e-4,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the HGNN-based NC classifier.

        Args:
            classifier_config: Configuration for the HGNN classifier.
            loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
            lr: Learning rate for the optimizer. Defaults to ``0.01``.
            weight_decay: L2 regularization. Defaults to ``5e-4``.
            metrics: Optional metric collection for evaluation. Defaults to ``None``.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
                Useful for configuring distributed synchronization behavior
                of ``torchmetrics``. Defaults to ``None``.
        """
        classifier = HGNN(
            in_channels=classifier_config["in_channels"],
            hidden_channels=classifier_config["hidden_channels"],
            num_classes=classifier_config["out_channels"],
            bias=classifier_config.get("bias", True),
            use_batch_normalization=classifier_config.get("use_batch_normalization", False),
            drop_rate=classifier_config.get("drop_rate", 0.5),
        )

        super().__init__(
            classifier=classifier,
            loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
            metrics=metrics,
            metrics_log_kwargs=metrics_log_kwargs,
        )

        self.lr: float = lr
        self.weight_decay: float = weight_decay

    def forward(self, x: Tensor, hyperedge_index: Tensor) -> Tensor:
        """
        Predict node-class logits from node features and hypergraph structure.

        Examples:
            Given 4 nodes with 3 features each and 2 output classes:
                >>> x.shape
                ... torch.Size([4, 3])
                >>> hyperedge_index.shape
                ... torch.Size([2, 6])

            The forward pass maps each node to one row of class logits:
                >>> logits = model.forward(x, hyperedge_index)
                >>> logits.shape
                ... torch.Size([4, 2])

        Args:
            x: Node feature matrix of shape ``(num_nodes, in_channels)``.
            hyperedge_index: Hyperedge connectivity of shape ``(2, num_incidences)``.

        Returns:
            logits: Node-class logits of shape ``(num_nodes, num_classes)``.
        """
        return self.classifier(x, hyperedge_index)

    def training_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a training step.

        Args:
            batch: Training batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Training loss.
        """
        return self.__eval_step(batch, Stage.TRAIN)

    def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a validation step.

        Args:
            batch: Validation batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Validation loss.
        """
        return self.__eval_step(batch, Stage.VAL)

    def test_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a test step.

        Args:
            batch: Test batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Test loss.
        """
        return self.__eval_step(batch, Stage.TEST)

    def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Predict node-class logits for a batch.

        Args:
            batch: Prediction batch.
            batch_idx: Batch index, unused.

        Returns:
            logits: Predicted node-class logits.
        """
        return self.forward(batch.x, batch.hyperedge_index)

    def configure_optimizers(self) -> optim.Adam:
        """
        Configure the optimizer.

        Returns:
            optimizer: Adam optimizer.
        """
        return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

    def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
        """
        Run shared evaluation logic for a stage.

        Args:
            batch: Input batch.
            stage: Current evaluation stage.

        Returns:
            loss: Computed loss.
        """
        logits = self.forward(batch.x, batch.hyperedge_index)
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = int(target_labels.size(0))

        loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
        self._compute_metrics(target_logits, target_labels, batch_size, stage)
        return loss

__init__(classifier_config, loss_fn=None, lr=0.01, weight_decay=0.0005, metrics=None, metrics_log_kwargs=None)

Initialize the HGNN-based NC classifier.

Parameters:

Name Type Description Default
classifier_config HGNNClassifierConfig

Configuration for the HGNN classifier.

required
loss_fn Module | None

Optional loss function. Defaults to CrossEntropyLoss.

None
lr float

Learning rate for the optimizer. Defaults to 0.01.

0.01
weight_decay float

L2 regularization. Defaults to 5e-4.

0.0005
metrics MetricCollection | None

Optional metric collection for evaluation. Defaults to None.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls. Useful for configuring distributed synchronization behavior of torchmetrics. Defaults to None.

None
Source code in hypertorch/node_classification/hgnn_nc.py
def __init__(
    self,
    classifier_config: HGNNClassifierConfig,
    loss_fn: nn.Module | None = None,
    lr: float = 0.01,
    weight_decay: float = 5e-4,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the HGNN-based NC classifier.

    Args:
        classifier_config: Configuration for the HGNN classifier.
        loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``5e-4``.
        metrics: Optional metric collection for evaluation. Defaults to ``None``.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
            Useful for configuring distributed synchronization behavior
            of ``torchmetrics``. Defaults to ``None``.
    """
    classifier = HGNN(
        in_channels=classifier_config["in_channels"],
        hidden_channels=classifier_config["hidden_channels"],
        num_classes=classifier_config["out_channels"],
        bias=classifier_config.get("bias", True),
        use_batch_normalization=classifier_config.get("use_batch_normalization", False),
        drop_rate=classifier_config.get("drop_rate", 0.5),
    )

    super().__init__(
        classifier=classifier,
        loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
        metrics=metrics,
        metrics_log_kwargs=metrics_log_kwargs,
    )

    self.lr: float = lr
    self.weight_decay: float = weight_decay

forward(x, hyperedge_index)

Predict node-class logits from node features and hypergraph structure.

Examples:

Given 4 nodes with 3 features each and 2 output classes: >>> x.shape ... torch.Size([4, 3]) >>> hyperedge_index.shape ... torch.Size([2, 6])

The forward pass maps each node to one row of class logits: >>> logits = model.forward(x, hyperedge_index) >>> logits.shape ... torch.Size([4, 2])

Parameters:

Name Type Description Default
x Tensor

Node feature matrix of shape (num_nodes, in_channels).

required
hyperedge_index Tensor

Hyperedge connectivity of shape (2, num_incidences).

required

Returns:

Name Type Description
logits Tensor

Node-class logits of shape (num_nodes, num_classes).

Source code in hypertorch/node_classification/hgnn_nc.py
def forward(self, x: Tensor, hyperedge_index: Tensor) -> Tensor:
    """
    Predict node-class logits from node features and hypergraph structure.

    Examples:
        Given 4 nodes with 3 features each and 2 output classes:
            >>> x.shape
            ... torch.Size([4, 3])
            >>> hyperedge_index.shape
            ... torch.Size([2, 6])

        The forward pass maps each node to one row of class logits:
            >>> logits = model.forward(x, hyperedge_index)
            >>> logits.shape
            ... torch.Size([4, 2])

    Args:
        x: Node feature matrix of shape ``(num_nodes, in_channels)``.
        hyperedge_index: Hyperedge connectivity of shape ``(2, num_incidences)``.

    Returns:
        logits: Node-class logits of shape ``(num_nodes, num_classes)``.
    """
    return self.classifier(x, hyperedge_index)

training_step(batch, batch_idx)

Run a training step.

Parameters:

Name Type Description Default
batch HData

Training batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Training loss.

Source code in hypertorch/node_classification/hgnn_nc.py
def training_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a training step.

    Args:
        batch: Training batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Training loss.
    """
    return self.__eval_step(batch, Stage.TRAIN)

validation_step(batch, batch_idx)

Run a validation step.

Parameters:

Name Type Description Default
batch HData

Validation batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Validation loss.

Source code in hypertorch/node_classification/hgnn_nc.py
def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a validation step.

    Args:
        batch: Validation batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Validation loss.
    """
    return self.__eval_step(batch, Stage.VAL)

test_step(batch, batch_idx)

Run a test step.

Parameters:

Name Type Description Default
batch HData

Test batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Test loss.

Source code in hypertorch/node_classification/hgnn_nc.py
def test_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a test step.

    Args:
        batch: Test batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Test loss.
    """
    return self.__eval_step(batch, Stage.TEST)

predict_step(batch, batch_idx)

Predict node-class logits for a batch.

Parameters:

Name Type Description Default
batch HData

Prediction batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
logits Tensor

Predicted node-class logits.

Source code in hypertorch/node_classification/hgnn_nc.py
def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Predict node-class logits for a batch.

    Args:
        batch: Prediction batch.
        batch_idx: Batch index, unused.

    Returns:
        logits: Predicted node-class logits.
    """
    return self.forward(batch.x, batch.hyperedge_index)

configure_optimizers()

Configure the optimizer.

Returns:

Name Type Description
optimizer Adam

Adam optimizer.

Source code in hypertorch/node_classification/hgnn_nc.py
def configure_optimizers(self) -> optim.Adam:
    """
    Configure the optimizer.

    Returns:
        optimizer: Adam optimizer.
    """
    return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

__eval_step(batch, stage)

Run shared evaluation logic for a stage.

Parameters:

Name Type Description Default
batch HData

Input batch.

required
stage Stage

Current evaluation stage.

required

Returns:

Name Type Description
loss Tensor

Computed loss.

Source code in hypertorch/node_classification/hgnn_nc.py
def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
    """
    Run shared evaluation logic for a stage.

    Args:
        batch: Input batch.
        stage: Current evaluation stage.

    Returns:
        loss: Computed loss.
    """
    logits = self.forward(batch.x, batch.hyperedge_index)
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = int(target_labels.size(0))

    loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
    self._compute_metrics(target_logits, target_labels, batch_size, stage)
    return loss

HNHNClassifierConfig

Bases: TypedDict

Configuration for the HNHN classifier in HNHNClassifier.

Attributes:

Name Type Description
in_channels int

Number of input features per node.

hidden_channels int

Number of hidden units in the intermediate HNHN layer.

out_channels int

Number of node classes.

bias NotRequired[bool]

Whether to include bias terms. Defaults to True.

use_batch_normalization NotRequired[bool]

Whether to use batch normalization. Defaults to False.

drop_rate NotRequired[float]

Dropout rate. Defaults to 0.5.

Source code in hypertorch/node_classification/hnhn_nc.py
class HNHNClassifierConfig(TypedDict):
    """
    Configuration for the HNHN classifier in ``HNHNClassifier``.

    Attributes:
        in_channels: Number of input features per node.
        hidden_channels: Number of hidden units in the intermediate HNHN layer.
        out_channels: Number of node classes.
        bias: Whether to include bias terms. Defaults to ``True``.
        use_batch_normalization: Whether to use batch normalization. Defaults to ``False``.
        drop_rate: Dropout rate. Defaults to ``0.5``.
    """

    in_channels: int
    hidden_channels: int
    out_channels: int
    bias: NotRequired[bool]
    use_batch_normalization: NotRequired[bool]
    drop_rate: NotRequired[float]

HNHNClassifier

Bases: NCClassifier

A LightningModule for HNHN-based NC classifier.

Uses HNHN to transform node features and hypergraph incidence structure into per-node class logits through explicit hyperedge neurons. During training, validation, and testing, loss and metrics are computed on supervised target nodes selected by HData.target_node_mask.

Attributes:

Name Type Description
encoder Module | None

Optional encoder module inherited from NCClassifier. Defaults to None.

classifier Module

HNHN classifier module inherited from NCClassifier.

loss_fn Module

Loss function inherited from NCClassifier.

metrics_log_kwargs dict[str, Any]

Metric logging keyword arguments inherited from NCClassifier.

train_metrics MetricCollection | None

Optional training metrics inherited from NCClassifier.

val_metrics MetricCollection | None

Optional validation metrics inherited from NCClassifier.

test_metrics MetricCollection | None

Optional test metrics inherited from NCClassifier.

lr float

Learning rate for the optimizer. Defaults to 0.01.

weight_decay float

L2 regularization. Defaults to 5e-4.

Source code in hypertorch/node_classification/hnhn_nc.py
class HNHNClassifier(NCClassifier):
    """
    A LightningModule for HNHN-based NC classifier.

    Uses HNHN to transform node features and hypergraph incidence structure into
    per-node class logits through explicit hyperedge neurons. During training,
    validation, and testing, loss and metrics are computed on supervised target
    nodes selected by ``HData.target_node_mask``.

    Attributes:
        encoder: Optional encoder module inherited from ``NCClassifier``. Defaults to ``None``.
        classifier: HNHN classifier module inherited from ``NCClassifier``.
        loss_fn: Loss function inherited from ``NCClassifier``.
        metrics_log_kwargs: Metric logging keyword arguments inherited from ``NCClassifier``.
        train_metrics: Optional training metrics inherited from ``NCClassifier``.
        val_metrics: Optional validation metrics inherited from ``NCClassifier``.
        test_metrics: Optional test metrics inherited from ``NCClassifier``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``5e-4``.
    """

    def __init__(
        self,
        classifier_config: HNHNClassifierConfig,
        loss_fn: nn.Module | None = None,
        lr: float = 0.01,
        weight_decay: float = 5e-4,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the HNHN-based NC classifier.

        Args:
            classifier_config: Configuration for the HNHN classifier.
            loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
            lr: Learning rate for the optimizer. Defaults to ``0.01``.
            weight_decay: L2 regularization. Defaults to ``5e-4``.
            metrics: Optional metric collection for evaluation. Defaults to ``None``.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
                Useful for configuring distributed synchronization behavior
                of ``torchmetrics``. Defaults to ``None``.
        """
        classifier = HNHN(
            in_channels=classifier_config["in_channels"],
            hidden_channels=classifier_config["hidden_channels"],
            num_classes=classifier_config["out_channels"],
            bias=classifier_config.get("bias", True),
            use_batch_normalization=classifier_config.get("use_batch_normalization", False),
            drop_rate=classifier_config.get("drop_rate", 0.5),
        )

        super().__init__(
            classifier=classifier,
            loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
            metrics=metrics,
            metrics_log_kwargs=metrics_log_kwargs,
        )

        self.lr: float = lr
        self.weight_decay: float = weight_decay

    def forward(self, x: Tensor, hyperedge_index: Tensor) -> Tensor:
        """
        Predict node-class logits from node features and hypergraph structure.

        Examples:
            Given 4 nodes with 3 features each and 2 output classes:
                >>> x.shape
                ... torch.Size([4, 3])
                >>> hyperedge_index.shape
                ... torch.Size([2, 6])

            The forward pass maps each node to one row of class logits:
                >>> logits = model.forward(x, hyperedge_index)
                >>> logits.shape
                ... torch.Size([4, 2])

        Args:
            x: Node feature matrix of shape ``(num_nodes, in_channels)``.
            hyperedge_index: Hyperedge connectivity of shape ``(2, num_incidences)``.

        Returns:
            logits: Node-class logits of shape ``(num_nodes, num_classes)``.
        """
        return self.classifier(x, hyperedge_index)

    def training_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a training step.

        Args:
            batch: Training batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Training loss.
        """
        return self.__eval_step(batch, Stage.TRAIN)

    def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a validation step.

        Args:
            batch: Validation batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Validation loss.
        """
        return self.__eval_step(batch, Stage.VAL)

    def test_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a test step.

        Args:
            batch: Test batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Test loss.
        """
        return self.__eval_step(batch, Stage.TEST)

    def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Predict node-class logits for a batch.

        Args:
            batch: Prediction batch.
            batch_idx: Batch index, unused.

        Returns:
            logits: Predicted node-class logits.
        """
        return self.forward(batch.x, batch.hyperedge_index)

    def configure_optimizers(self) -> optim.Adam:
        """
        Configure the optimizer.

        Returns:
            optimizer: Adam optimizer.
        """
        return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

    def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
        """
        Run shared evaluation logic for a stage.

        Args:
            batch: Input batch.
            stage: Current evaluation stage.

        Returns:
            loss: Computed loss.
        """
        logits = self.forward(batch.x, batch.hyperedge_index)
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = int(target_labels.size(0))

        loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
        self._compute_metrics(target_logits, target_labels, batch_size, stage)
        return loss

__init__(classifier_config, loss_fn=None, lr=0.01, weight_decay=0.0005, metrics=None, metrics_log_kwargs=None)

Initialize the HNHN-based NC classifier.

Parameters:

Name Type Description Default
classifier_config HNHNClassifierConfig

Configuration for the HNHN classifier.

required
loss_fn Module | None

Optional loss function. Defaults to CrossEntropyLoss.

None
lr float

Learning rate for the optimizer. Defaults to 0.01.

0.01
weight_decay float

L2 regularization. Defaults to 5e-4.

0.0005
metrics MetricCollection | None

Optional metric collection for evaluation. Defaults to None.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls. Useful for configuring distributed synchronization behavior of torchmetrics. Defaults to None.

None
Source code in hypertorch/node_classification/hnhn_nc.py
def __init__(
    self,
    classifier_config: HNHNClassifierConfig,
    loss_fn: nn.Module | None = None,
    lr: float = 0.01,
    weight_decay: float = 5e-4,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the HNHN-based NC classifier.

    Args:
        classifier_config: Configuration for the HNHN classifier.
        loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``5e-4``.
        metrics: Optional metric collection for evaluation. Defaults to ``None``.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
            Useful for configuring distributed synchronization behavior
            of ``torchmetrics``. Defaults to ``None``.
    """
    classifier = HNHN(
        in_channels=classifier_config["in_channels"],
        hidden_channels=classifier_config["hidden_channels"],
        num_classes=classifier_config["out_channels"],
        bias=classifier_config.get("bias", True),
        use_batch_normalization=classifier_config.get("use_batch_normalization", False),
        drop_rate=classifier_config.get("drop_rate", 0.5),
    )

    super().__init__(
        classifier=classifier,
        loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
        metrics=metrics,
        metrics_log_kwargs=metrics_log_kwargs,
    )

    self.lr: float = lr
    self.weight_decay: float = weight_decay

forward(x, hyperedge_index)

Predict node-class logits from node features and hypergraph structure.

Examples:

Given 4 nodes with 3 features each and 2 output classes: >>> x.shape ... torch.Size([4, 3]) >>> hyperedge_index.shape ... torch.Size([2, 6])

The forward pass maps each node to one row of class logits: >>> logits = model.forward(x, hyperedge_index) >>> logits.shape ... torch.Size([4, 2])

Parameters:

Name Type Description Default
x Tensor

Node feature matrix of shape (num_nodes, in_channels).

required
hyperedge_index Tensor

Hyperedge connectivity of shape (2, num_incidences).

required

Returns:

Name Type Description
logits Tensor

Node-class logits of shape (num_nodes, num_classes).

Source code in hypertorch/node_classification/hnhn_nc.py
def forward(self, x: Tensor, hyperedge_index: Tensor) -> Tensor:
    """
    Predict node-class logits from node features and hypergraph structure.

    Examples:
        Given 4 nodes with 3 features each and 2 output classes:
            >>> x.shape
            ... torch.Size([4, 3])
            >>> hyperedge_index.shape
            ... torch.Size([2, 6])

        The forward pass maps each node to one row of class logits:
            >>> logits = model.forward(x, hyperedge_index)
            >>> logits.shape
            ... torch.Size([4, 2])

    Args:
        x: Node feature matrix of shape ``(num_nodes, in_channels)``.
        hyperedge_index: Hyperedge connectivity of shape ``(2, num_incidences)``.

    Returns:
        logits: Node-class logits of shape ``(num_nodes, num_classes)``.
    """
    return self.classifier(x, hyperedge_index)

training_step(batch, batch_idx)

Run a training step.

Parameters:

Name Type Description Default
batch HData

Training batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Training loss.

Source code in hypertorch/node_classification/hnhn_nc.py
def training_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a training step.

    Args:
        batch: Training batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Training loss.
    """
    return self.__eval_step(batch, Stage.TRAIN)

validation_step(batch, batch_idx)

Run a validation step.

Parameters:

Name Type Description Default
batch HData

Validation batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Validation loss.

Source code in hypertorch/node_classification/hnhn_nc.py
def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a validation step.

    Args:
        batch: Validation batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Validation loss.
    """
    return self.__eval_step(batch, Stage.VAL)

test_step(batch, batch_idx)

Run a test step.

Parameters:

Name Type Description Default
batch HData

Test batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Test loss.

Source code in hypertorch/node_classification/hnhn_nc.py
def test_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a test step.

    Args:
        batch: Test batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Test loss.
    """
    return self.__eval_step(batch, Stage.TEST)

predict_step(batch, batch_idx)

Predict node-class logits for a batch.

Parameters:

Name Type Description Default
batch HData

Prediction batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
logits Tensor

Predicted node-class logits.

Source code in hypertorch/node_classification/hnhn_nc.py
def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Predict node-class logits for a batch.

    Args:
        batch: Prediction batch.
        batch_idx: Batch index, unused.

    Returns:
        logits: Predicted node-class logits.
    """
    return self.forward(batch.x, batch.hyperedge_index)

configure_optimizers()

Configure the optimizer.

Returns:

Name Type Description
optimizer Adam

Adam optimizer.

Source code in hypertorch/node_classification/hnhn_nc.py
def configure_optimizers(self) -> optim.Adam:
    """
    Configure the optimizer.

    Returns:
        optimizer: Adam optimizer.
    """
    return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

__eval_step(batch, stage)

Run shared evaluation logic for a stage.

Parameters:

Name Type Description Default
batch HData

Input batch.

required
stage Stage

Current evaluation stage.

required

Returns:

Name Type Description
loss Tensor

Computed loss.

Source code in hypertorch/node_classification/hnhn_nc.py
def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
    """
    Run shared evaluation logic for a stage.

    Args:
        batch: Input batch.
        stage: Current evaluation stage.

    Returns:
        loss: Computed loss.
    """
    logits = self.forward(batch.x, batch.hyperedge_index)
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = int(target_labels.size(0))

    loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
    self._compute_metrics(target_logits, target_labels, batch_size, stage)
    return loss

HGNNPClassifierConfig

Bases: TypedDict

Configuration for the HGNN+ classifier in HGNNPClassifier.

Attributes:

Name Type Description
in_channels int

Number of input features per node.

hidden_channels int

Number of hidden units in the intermediate HGNN+ layer.

out_channels int

Number of node classes.

bias NotRequired[bool]

Whether to include bias terms. Defaults to True.

use_batch_normalization NotRequired[bool]

Whether to use batch normalization. Defaults to False.

drop_rate NotRequired[float]

Dropout rate. Defaults to 0.5.

Source code in hypertorch/node_classification/hgnnp_nc.py
class HGNNPClassifierConfig(TypedDict):
    """
    Configuration for the HGNN+ classifier in ``HGNNPClassifier``.

    Attributes:
        in_channels: Number of input features per node.
        hidden_channels: Number of hidden units in the intermediate HGNN+ layer.
        out_channels: Number of node classes.
        bias: Whether to include bias terms. Defaults to ``True``.
        use_batch_normalization: Whether to use batch normalization. Defaults to ``False``.
        drop_rate: Dropout rate. Defaults to ``0.5``.
    """

    in_channels: int
    hidden_channels: int
    out_channels: int
    bias: NotRequired[bool]
    use_batch_normalization: NotRequired[bool]
    drop_rate: NotRequired[float]

HGNNPClassifier

Bases: NCClassifier

A LightningModule for HGNN+-based NC classifier.

Uses HGNN+ to transform node features and hypergraph incidence structure directly into per-node class logits. During training, validation, and testing, loss and metrics are computed on supervised target nodes selected by HData.target_node_mask.

Attributes:

Name Type Description
encoder Module | None

Optional encoder module inherited from NCClassifier. Defaults to None.

classifier Module

HGNN+ classifier module inherited from NCClassifier.

loss_fn Module

Loss function inherited from NCClassifier.

metrics_log_kwargs dict[str, Any]

Metric logging keyword arguments inherited from NCClassifier.

train_metrics MetricCollection | None

Optional training metrics inherited from NCClassifier.

val_metrics MetricCollection | None

Optional validation metrics inherited from NCClassifier.

test_metrics MetricCollection | None

Optional test metrics inherited from NCClassifier.

lr float

Learning rate for the optimizer. Defaults to 0.01.

weight_decay float

L2 regularization. Defaults to 5e-4.

Source code in hypertorch/node_classification/hgnnp_nc.py
class HGNNPClassifier(NCClassifier):
    """
    A LightningModule for HGNN+-based NC classifier.

    Uses HGNN+ to transform node features and hypergraph incidence structure directly into
    per-node class logits. During training, validation, and testing, loss and metrics
    are computed on supervised target nodes selected by ``HData.target_node_mask``.

    Attributes:
        encoder: Optional encoder module inherited from ``NCClassifier``. Defaults to ``None``.
        classifier: HGNN+ classifier module inherited from ``NCClassifier``.
        loss_fn: Loss function inherited from ``NCClassifier``.
        metrics_log_kwargs: Metric logging keyword arguments inherited from ``NCClassifier``.
        train_metrics: Optional training metrics inherited from ``NCClassifier``.
        val_metrics: Optional validation metrics inherited from ``NCClassifier``.
        test_metrics: Optional test metrics inherited from ``NCClassifier``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``5e-4``.
    """

    def __init__(
        self,
        classifier_config: HGNNPClassifierConfig,
        loss_fn: nn.Module | None = None,
        lr: float = 0.01,
        weight_decay: float = 5e-4,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the HGNN+-based NC classifier.

        Args:
            classifier_config: Configuration for the HGNN+ classifier.
            loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
            lr: Learning rate for the optimizer. Defaults to ``0.01``.
            weight_decay: L2 regularization. Defaults to ``5e-4``.
            metrics: Optional metric collection for evaluation. Defaults to ``None``.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
                Useful for configuring distributed synchronization behavior
                of ``torchmetrics``. Defaults to ``None``.
        """
        classifier = HGNNP(
            in_channels=classifier_config["in_channels"],
            hidden_channels=classifier_config["hidden_channels"],
            num_classes=classifier_config["out_channels"],
            bias=classifier_config.get("bias", True),
            use_batch_normalization=classifier_config.get("use_batch_normalization", False),
            drop_rate=classifier_config.get("drop_rate", 0.5),
        )

        super().__init__(
            classifier=classifier,
            loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
            metrics=metrics,
            metrics_log_kwargs=metrics_log_kwargs,
        )

        self.lr: float = lr
        self.weight_decay: float = weight_decay

    def forward(self, x: Tensor, hyperedge_index: Tensor) -> Tensor:
        """
        Predict node-class logits from node features and hypergraph structure.

        Examples:
            Given 4 nodes with 3 features each and 2 output classes:
                >>> x.shape
                ... torch.Size([4, 3])
                >>> hyperedge_index.shape
                ... torch.Size([2, 6])

            The forward pass maps each node to one row of class logits:
                >>> logits = model.forward(x, hyperedge_index)
                >>> logits.shape
                ... torch.Size([4, 2])

        Args:
            x: Node feature matrix of shape ``(num_nodes, in_channels)``.
            hyperedge_index: Hyperedge connectivity of shape ``(2, num_incidences)``.

        Returns:
            logits: Node-class logits of shape ``(num_nodes, num_classes)``.
        """
        return self.classifier(x, hyperedge_index)

    def training_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a training step.

        Args:
            batch: Training batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Training loss.
        """
        return self.__eval_step(batch, Stage.TRAIN)

    def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a validation step.

        Args:
            batch: Validation batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Validation loss.
        """
        return self.__eval_step(batch, Stage.VAL)

    def test_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a test step.

        Args:
            batch: Test batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Test loss.
        """
        return self.__eval_step(batch, Stage.TEST)

    def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Predict node-class logits for a batch.

        Args:
            batch: Prediction batch.
            batch_idx: Batch index, unused.

        Returns:
            logits: Predicted node-class logits.
        """
        return self.forward(batch.x, batch.hyperedge_index)

    def configure_optimizers(self) -> optim.Adam:
        """
        Configure the optimizer.

        Returns:
            optimizer: Adam optimizer.
        """
        return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

    def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
        """
        Run shared evaluation logic for a stage.

        Args:
            batch: Input batch.
            stage: Current evaluation stage.

        Returns:
            loss: Computed loss.
        """
        logits = self.forward(batch.x, batch.hyperedge_index)
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = int(target_labels.size(0))

        loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
        self._compute_metrics(target_logits, target_labels, batch_size, stage)
        return loss

__init__(classifier_config, loss_fn=None, lr=0.01, weight_decay=0.0005, metrics=None, metrics_log_kwargs=None)

Initialize the HGNN+-based NC classifier.

Parameters:

Name Type Description Default
classifier_config HGNNPClassifierConfig

Configuration for the HGNN+ classifier.

required
loss_fn Module | None

Optional loss function. Defaults to CrossEntropyLoss.

None
lr float

Learning rate for the optimizer. Defaults to 0.01.

0.01
weight_decay float

L2 regularization. Defaults to 5e-4.

0.0005
metrics MetricCollection | None

Optional metric collection for evaluation. Defaults to None.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls. Useful for configuring distributed synchronization behavior of torchmetrics. Defaults to None.

None
Source code in hypertorch/node_classification/hgnnp_nc.py
def __init__(
    self,
    classifier_config: HGNNPClassifierConfig,
    loss_fn: nn.Module | None = None,
    lr: float = 0.01,
    weight_decay: float = 5e-4,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the HGNN+-based NC classifier.

    Args:
        classifier_config: Configuration for the HGNN+ classifier.
        loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``5e-4``.
        metrics: Optional metric collection for evaluation. Defaults to ``None``.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
            Useful for configuring distributed synchronization behavior
            of ``torchmetrics``. Defaults to ``None``.
    """
    classifier = HGNNP(
        in_channels=classifier_config["in_channels"],
        hidden_channels=classifier_config["hidden_channels"],
        num_classes=classifier_config["out_channels"],
        bias=classifier_config.get("bias", True),
        use_batch_normalization=classifier_config.get("use_batch_normalization", False),
        drop_rate=classifier_config.get("drop_rate", 0.5),
    )

    super().__init__(
        classifier=classifier,
        loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
        metrics=metrics,
        metrics_log_kwargs=metrics_log_kwargs,
    )

    self.lr: float = lr
    self.weight_decay: float = weight_decay

forward(x, hyperedge_index)

Predict node-class logits from node features and hypergraph structure.

Examples:

Given 4 nodes with 3 features each and 2 output classes: >>> x.shape ... torch.Size([4, 3]) >>> hyperedge_index.shape ... torch.Size([2, 6])

The forward pass maps each node to one row of class logits: >>> logits = model.forward(x, hyperedge_index) >>> logits.shape ... torch.Size([4, 2])

Parameters:

Name Type Description Default
x Tensor

Node feature matrix of shape (num_nodes, in_channels).

required
hyperedge_index Tensor

Hyperedge connectivity of shape (2, num_incidences).

required

Returns:

Name Type Description
logits Tensor

Node-class logits of shape (num_nodes, num_classes).

Source code in hypertorch/node_classification/hgnnp_nc.py
def forward(self, x: Tensor, hyperedge_index: Tensor) -> Tensor:
    """
    Predict node-class logits from node features and hypergraph structure.

    Examples:
        Given 4 nodes with 3 features each and 2 output classes:
            >>> x.shape
            ... torch.Size([4, 3])
            >>> hyperedge_index.shape
            ... torch.Size([2, 6])

        The forward pass maps each node to one row of class logits:
            >>> logits = model.forward(x, hyperedge_index)
            >>> logits.shape
            ... torch.Size([4, 2])

    Args:
        x: Node feature matrix of shape ``(num_nodes, in_channels)``.
        hyperedge_index: Hyperedge connectivity of shape ``(2, num_incidences)``.

    Returns:
        logits: Node-class logits of shape ``(num_nodes, num_classes)``.
    """
    return self.classifier(x, hyperedge_index)

training_step(batch, batch_idx)

Run a training step.

Parameters:

Name Type Description Default
batch HData

Training batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Training loss.

Source code in hypertorch/node_classification/hgnnp_nc.py
def training_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a training step.

    Args:
        batch: Training batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Training loss.
    """
    return self.__eval_step(batch, Stage.TRAIN)

validation_step(batch, batch_idx)

Run a validation step.

Parameters:

Name Type Description Default
batch HData

Validation batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Validation loss.

Source code in hypertorch/node_classification/hgnnp_nc.py
def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a validation step.

    Args:
        batch: Validation batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Validation loss.
    """
    return self.__eval_step(batch, Stage.VAL)

test_step(batch, batch_idx)

Run a test step.

Parameters:

Name Type Description Default
batch HData

Test batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Test loss.

Source code in hypertorch/node_classification/hgnnp_nc.py
def test_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a test step.

    Args:
        batch: Test batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Test loss.
    """
    return self.__eval_step(batch, Stage.TEST)

predict_step(batch, batch_idx)

Predict node-class logits for a batch.

Parameters:

Name Type Description Default
batch HData

Prediction batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
logits Tensor

Predicted node-class logits.

Source code in hypertorch/node_classification/hgnnp_nc.py
def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Predict node-class logits for a batch.

    Args:
        batch: Prediction batch.
        batch_idx: Batch index, unused.

    Returns:
        logits: Predicted node-class logits.
    """
    return self.forward(batch.x, batch.hyperedge_index)

configure_optimizers()

Configure the optimizer.

Returns:

Name Type Description
optimizer Adam

Adam optimizer.

Source code in hypertorch/node_classification/hgnnp_nc.py
def configure_optimizers(self) -> optim.Adam:
    """
    Configure the optimizer.

    Returns:
        optimizer: Adam optimizer.
    """
    return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

__eval_step(batch, stage)

Run shared evaluation logic for a stage.

Parameters:

Name Type Description Default
batch HData

Input batch.

required
stage Stage

Current evaluation stage.

required

Returns:

Name Type Description
loss Tensor

Computed loss.

Source code in hypertorch/node_classification/hgnnp_nc.py
def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
    """
    Run shared evaluation logic for a stage.

    Args:
        batch: Input batch.
        stage: Current evaluation stage.

    Returns:
        loss: Computed loss.
    """
    logits = self.forward(batch.x, batch.hyperedge_index)
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = int(target_labels.size(0))

    loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
    self._compute_metrics(target_logits, target_labels, batch_size, stage)
    return loss

HyperGCNClassifierConfig

Bases: TypedDict

Configuration for the HyperGCN classifier in HyperGCNClassifier.

Attributes:

Name Type Description
in_channels int

Number of input features per node.

hidden_channels int

Number of hidden units in the intermediate HyperGCN layer.

out_channels int

Number of node classes.

bias NotRequired[bool]

Whether to include bias terms. Defaults to True.

use_batch_normalization NotRequired[bool]

Whether to use batch normalization. Defaults to False.

drop_rate NotRequired[float]

Dropout rate. Defaults to 0.5.

use_mediator NotRequired[bool]

Whether to use mediator nodes for hyperedge-to-edge conversion. Defaults to False.

fast NotRequired[bool]

Whether to cache the graph structure after first computation. Defaults to True.

seed NotRequired[int]

Optional random seed for the random reduction of hyperedges to edges. Defaults to None.

Source code in hypertorch/node_classification/hypergcn_nc.py
class HyperGCNClassifierConfig(TypedDict):
    """
    Configuration for the HyperGCN classifier in ``HyperGCNClassifier``.

    Attributes:
        in_channels: Number of input features per node.
        hidden_channels: Number of hidden units in the intermediate HyperGCN layer.
        out_channels: Number of node classes.
        bias: Whether to include bias terms. Defaults to ``True``.
        use_batch_normalization: Whether to use batch normalization. Defaults to ``False``.
        drop_rate: Dropout rate. Defaults to ``0.5``.
        use_mediator: Whether to use mediator nodes for hyperedge-to-edge conversion.
            Defaults to ``False``.
        fast: Whether to cache the graph structure after first computation.
            Defaults to ``True``.
        seed: Optional random seed for the random reduction of hyperedges to edges.
            Defaults to ``None``.
    """

    in_channels: int
    hidden_channels: int
    out_channels: int
    bias: NotRequired[bool]
    use_batch_normalization: NotRequired[bool]
    drop_rate: NotRequired[float]
    use_mediator: NotRequired[bool]
    fast: NotRequired[bool]
    seed: NotRequired[int]

HyperGCNClassifier

Bases: NCClassifier

A LightningModule for HyperGCN-based NC classifier.

Uses HyperGCN to transform node features and hypergraph structure directly into per-node class logits. During training, validation, and testing, loss and metrics are computed on supervised target nodes selected by HData.target_node_mask.

Attributes:

Name Type Description
encoder Module | None

Optional encoder module inherited from NCClassifier. Defaults to None.

classifier Module

HyperGCN classifier module inherited from NCClassifier.

loss_fn Module

Loss function inherited from NCClassifier.

metrics_log_kwargs dict[str, Any]

Metric logging keyword arguments inherited from NCClassifier.

train_metrics MetricCollection | None

Optional training metrics inherited from NCClassifier.

val_metrics MetricCollection | None

Optional validation metrics inherited from NCClassifier.

test_metrics MetricCollection | None

Optional test metrics inherited from NCClassifier.

lr float

Learning rate for the optimizer. Defaults to 0.01.

weight_decay float

L2 regularization. Defaults to 5e-4.

Source code in hypertorch/node_classification/hypergcn_nc.py
class HyperGCNClassifier(NCClassifier):
    """
    A LightningModule for HyperGCN-based NC classifier.

    Uses HyperGCN to transform node features and hypergraph structure directly into
    per-node class logits. During training, validation, and testing, loss and metrics
    are computed on supervised target nodes selected by ``HData.target_node_mask``.

    Attributes:
        encoder: Optional encoder module inherited from ``NCClassifier``. Defaults to ``None``.
        classifier: HyperGCN classifier module inherited from ``NCClassifier``.
        loss_fn: Loss function inherited from ``NCClassifier``.
        metrics_log_kwargs: Metric logging keyword arguments inherited from ``NCClassifier``.
        train_metrics: Optional training metrics inherited from ``NCClassifier``.
        val_metrics: Optional validation metrics inherited from ``NCClassifier``.
        test_metrics: Optional test metrics inherited from ``NCClassifier``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``5e-4``.
    """

    def __init__(
        self,
        classifier_config: HyperGCNClassifierConfig,
        loss_fn: nn.Module | None = None,
        lr: float = 0.01,
        weight_decay: float = 5e-4,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the HyperGCN-based NC classifier.

        Args:
            classifier_config: Configuration for the HyperGCN classifier.
            loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
            lr: Learning rate for the optimizer. Defaults to ``0.01``.
            weight_decay: L2 regularization. Defaults to ``5e-4``.
            metrics: Optional metric collection for evaluation. Defaults to ``None``.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
                Useful for configuring distributed synchronization behavior
                of ``torchmetrics``. Defaults to ``None``.
        """
        classifier = HyperGCN(
            in_channels=classifier_config["in_channels"],
            hidden_channels=classifier_config["hidden_channels"],
            num_classes=classifier_config["out_channels"],
            bias=classifier_config.get("bias", True),
            use_batch_normalization=classifier_config.get("use_batch_normalization", False),
            drop_rate=classifier_config.get("drop_rate", 0.5),
            use_mediator=classifier_config.get("use_mediator", False),
            fast=classifier_config.get("fast", True),
            seed=classifier_config.get("seed"),
        )

        super().__init__(
            classifier=classifier,
            loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
            metrics=metrics,
            metrics_log_kwargs=metrics_log_kwargs,
        )

        self.lr: float = lr
        self.weight_decay: float = weight_decay

    def forward(self, x: Tensor, hyperedge_index: Tensor) -> Tensor:
        """
        Predict node-class logits from node features and hypergraph structure.

        Examples:
            Given 4 nodes with 3 features each and 2 output classes:
                >>> x.shape
                ... torch.Size([4, 3])
                >>> hyperedge_index.shape
                ... torch.Size([2, 6])

            The forward pass maps each node to one row of class logits:
                >>> logits = model.forward(x, hyperedge_index)
                >>> logits.shape
                ... torch.Size([4, 2])

        Args:
            x: Node feature matrix of shape ``(num_nodes, in_channels)``.
            hyperedge_index: Hyperedge connectivity of shape ``(2, num_incidences)``.

        Returns:
            logits: Node-class logits of shape ``(num_nodes, num_classes)``.
        """
        return self.classifier(x, hyperedge_index)

    def training_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a training step.

        Args:
            batch: Training batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Training loss.
        """
        return self.__eval_step(batch, Stage.TRAIN)

    def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a validation step.

        Args:
            batch: Validation batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Validation loss.
        """
        return self.__eval_step(batch, Stage.VAL)

    def test_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a test step.

        Args:
            batch: Test batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Test loss.
        """
        return self.__eval_step(batch, Stage.TEST)

    def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Predict node-class logits for a batch.

        Args:
            batch: Prediction batch.
            batch_idx: Batch index, unused.

        Returns:
            logits: Predicted node-class logits.
        """
        return self.forward(batch.x, batch.hyperedge_index)

    def configure_optimizers(self) -> optim.Adam:
        """
        Configure the optimizer.

        Returns:
            optimizer: Adam optimizer.
        """
        return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

    def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
        """
        Run shared evaluation logic for a stage.

        Args:
            batch: Input batch.
            stage: Current evaluation stage.

        Returns:
            loss: Computed loss.
        """
        logits = self.forward(batch.x, batch.hyperedge_index)
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = int(target_labels.size(0))

        loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
        self._compute_metrics(target_logits, target_labels, batch_size, stage)
        return loss

__init__(classifier_config, loss_fn=None, lr=0.01, weight_decay=0.0005, metrics=None, metrics_log_kwargs=None)

Initialize the HyperGCN-based NC classifier.

Parameters:

Name Type Description Default
classifier_config HyperGCNClassifierConfig

Configuration for the HyperGCN classifier.

required
loss_fn Module | None

Optional loss function. Defaults to CrossEntropyLoss.

None
lr float

Learning rate for the optimizer. Defaults to 0.01.

0.01
weight_decay float

L2 regularization. Defaults to 5e-4.

0.0005
metrics MetricCollection | None

Optional metric collection for evaluation. Defaults to None.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls. Useful for configuring distributed synchronization behavior of torchmetrics. Defaults to None.

None
Source code in hypertorch/node_classification/hypergcn_nc.py
def __init__(
    self,
    classifier_config: HyperGCNClassifierConfig,
    loss_fn: nn.Module | None = None,
    lr: float = 0.01,
    weight_decay: float = 5e-4,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the HyperGCN-based NC classifier.

    Args:
        classifier_config: Configuration for the HyperGCN classifier.
        loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``5e-4``.
        metrics: Optional metric collection for evaluation. Defaults to ``None``.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
            Useful for configuring distributed synchronization behavior
            of ``torchmetrics``. Defaults to ``None``.
    """
    classifier = HyperGCN(
        in_channels=classifier_config["in_channels"],
        hidden_channels=classifier_config["hidden_channels"],
        num_classes=classifier_config["out_channels"],
        bias=classifier_config.get("bias", True),
        use_batch_normalization=classifier_config.get("use_batch_normalization", False),
        drop_rate=classifier_config.get("drop_rate", 0.5),
        use_mediator=classifier_config.get("use_mediator", False),
        fast=classifier_config.get("fast", True),
        seed=classifier_config.get("seed"),
    )

    super().__init__(
        classifier=classifier,
        loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
        metrics=metrics,
        metrics_log_kwargs=metrics_log_kwargs,
    )

    self.lr: float = lr
    self.weight_decay: float = weight_decay

forward(x, hyperedge_index)

Predict node-class logits from node features and hypergraph structure.

Examples:

Given 4 nodes with 3 features each and 2 output classes: >>> x.shape ... torch.Size([4, 3]) >>> hyperedge_index.shape ... torch.Size([2, 6])

The forward pass maps each node to one row of class logits: >>> logits = model.forward(x, hyperedge_index) >>> logits.shape ... torch.Size([4, 2])

Parameters:

Name Type Description Default
x Tensor

Node feature matrix of shape (num_nodes, in_channels).

required
hyperedge_index Tensor

Hyperedge connectivity of shape (2, num_incidences).

required

Returns:

Name Type Description
logits Tensor

Node-class logits of shape (num_nodes, num_classes).

Source code in hypertorch/node_classification/hypergcn_nc.py
def forward(self, x: Tensor, hyperedge_index: Tensor) -> Tensor:
    """
    Predict node-class logits from node features and hypergraph structure.

    Examples:
        Given 4 nodes with 3 features each and 2 output classes:
            >>> x.shape
            ... torch.Size([4, 3])
            >>> hyperedge_index.shape
            ... torch.Size([2, 6])

        The forward pass maps each node to one row of class logits:
            >>> logits = model.forward(x, hyperedge_index)
            >>> logits.shape
            ... torch.Size([4, 2])

    Args:
        x: Node feature matrix of shape ``(num_nodes, in_channels)``.
        hyperedge_index: Hyperedge connectivity of shape ``(2, num_incidences)``.

    Returns:
        logits: Node-class logits of shape ``(num_nodes, num_classes)``.
    """
    return self.classifier(x, hyperedge_index)

training_step(batch, batch_idx)

Run a training step.

Parameters:

Name Type Description Default
batch HData

Training batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Training loss.

Source code in hypertorch/node_classification/hypergcn_nc.py
def training_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a training step.

    Args:
        batch: Training batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Training loss.
    """
    return self.__eval_step(batch, Stage.TRAIN)

validation_step(batch, batch_idx)

Run a validation step.

Parameters:

Name Type Description Default
batch HData

Validation batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Validation loss.

Source code in hypertorch/node_classification/hypergcn_nc.py
def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a validation step.

    Args:
        batch: Validation batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Validation loss.
    """
    return self.__eval_step(batch, Stage.VAL)

test_step(batch, batch_idx)

Run a test step.

Parameters:

Name Type Description Default
batch HData

Test batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Test loss.

Source code in hypertorch/node_classification/hypergcn_nc.py
def test_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a test step.

    Args:
        batch: Test batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Test loss.
    """
    return self.__eval_step(batch, Stage.TEST)

predict_step(batch, batch_idx)

Predict node-class logits for a batch.

Parameters:

Name Type Description Default
batch HData

Prediction batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
logits Tensor

Predicted node-class logits.

Source code in hypertorch/node_classification/hypergcn_nc.py
def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Predict node-class logits for a batch.

    Args:
        batch: Prediction batch.
        batch_idx: Batch index, unused.

    Returns:
        logits: Predicted node-class logits.
    """
    return self.forward(batch.x, batch.hyperedge_index)

configure_optimizers()

Configure the optimizer.

Returns:

Name Type Description
optimizer Adam

Adam optimizer.

Source code in hypertorch/node_classification/hypergcn_nc.py
def configure_optimizers(self) -> optim.Adam:
    """
    Configure the optimizer.

    Returns:
        optimizer: Adam optimizer.
    """
    return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

__eval_step(batch, stage)

Run shared evaluation logic for a stage.

Parameters:

Name Type Description Default
batch HData

Input batch.

required
stage Stage

Current evaluation stage.

required

Returns:

Name Type Description
loss Tensor

Computed loss.

Source code in hypertorch/node_classification/hypergcn_nc.py
def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
    """
    Run shared evaluation logic for a stage.

    Args:
        batch: Input batch.
        stage: Current evaluation stage.

    Returns:
        loss: Computed loss.
    """
    logits = self.forward(batch.x, batch.hyperedge_index)
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = int(target_labels.size(0))

    loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
    self._compute_metrics(target_logits, target_labels, batch_size, stage)
    return loss

MLPClassifier

Bases: NCClassifier

A LightningModule for MLP-based NC classifier.

Uses an MLP classifier to map node features directly to per-node class logits. During training, validation, and testing, loss and metrics are computed on the supervised target nodes selected by HData.target_node_mask when present.

Attributes:

Name Type Description
encoder Module | None

Optional encoder module inherited from NCClassifier. Defaults to None.

classifier Module

MLP classifier module inherited from NCClassifier.

loss_fn Module

Loss function inherited from NCClassifier.

metrics_log_kwargs dict[str, Any]

Metric logging keyword arguments inherited from NCClassifier.

train_metrics MetricCollection | None

Optional training metrics inherited from NCClassifier.

val_metrics MetricCollection | None

Optional validation metrics inherited from NCClassifier.

test_metrics MetricCollection | None

Optional test metrics inherited from NCClassifier.

lr float

Learning rate for the optimizer. Defaults to 0.001.

Source code in hypertorch/node_classification/mlp_nc.py
class MLPClassifier(NCClassifier):
    """
    A LightningModule for MLP-based NC classifier.

    Uses an MLP classifier to map node features directly to per-node class logits.
    During training, validation, and testing, loss and metrics are computed on the
    supervised target nodes selected by ``HData.target_node_mask`` when present.

    Attributes:
        encoder: Optional encoder module inherited from ``NCClassifier``. Defaults to ``None``.
        classifier: MLP classifier module inherited from ``NCClassifier``.
        loss_fn: Loss function inherited from ``NCClassifier``.
        metrics_log_kwargs: Metric logging keyword arguments inherited from ``NCClassifier``.
        train_metrics: Optional training metrics inherited from ``NCClassifier``.
        val_metrics: Optional validation metrics inherited from ``NCClassifier``.
        test_metrics: Optional test metrics inherited from ``NCClassifier``.
        lr: Learning rate for the optimizer. Defaults to ``0.001``.
    """

    def __init__(
        self,
        classifier_config: MLPClassifierConfig,
        loss_fn: nn.Module | None = None,
        lr: float = 0.001,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the MLP-based NC classifier.

        Args:
            classifier_config: Configuration for the MLP classifier.
            loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
            lr: Learning rate for the optimizer. Defaults to ``0.001``.
            metrics: Optional metric collection for evaluation. Defaults to ``None``.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
                Useful for configuring distributed synchronization behavior
                of ``torchmetrics``. Defaults to ``None``.
        """
        classifier = MLP(
            in_channels=classifier_config["in_channels"],
            hidden_channels=classifier_config.get("hidden_channels"),
            out_channels=classifier_config["out_channels"],
            num_layers=classifier_config.get("num_layers", 1),
            activation_fn=classifier_config.get("activation_fn"),
            activation_fn_kwargs=classifier_config.get("activation_fn_kwargs"),
            normalization_fn=classifier_config.get("normalization_fn"),
            normalization_fn_kwargs=classifier_config.get("normalization_fn_kwargs"),
            bias=classifier_config.get("bias", True),
            drop_rate=classifier_config.get("drop_rate", 0.0),
        )

        super().__init__(
            classifier=classifier,
            loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
            metrics=metrics,
            metrics_log_kwargs=metrics_log_kwargs,
        )

        self.lr: float = lr

    def forward(self, x: Tensor) -> Tensor:
        """
        Predict node-class logits from node features.

        Examples:
            Given 4 nodes with 3 features each and 2 output classes:
                >>> x = [[0.1, 0.2, 0.3],   # node 0
                ...      [0.4, 0.5, 0.6],   # node 1
                ...      [0.7, 0.8, 0.9],   # node 2
                ...      [1.0, 1.1, 1.2]]   # node 3

            The forward pass maps each node to one row of class logits:
                >>> logits = model.forward(x)
                >>> logits.shape
                torch.Size([4, 2])

        Args:
            x: Node feature matrix of shape ``(num_nodes, in_channels)``.

        Returns:
            logits: Node-class logits of shape ``(num_nodes, num_classes)``.
        """
        return self.classifier(x)

    def training_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a training step.

        Args:
            batch: Training batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Training loss.
        """
        return self.__eval_step(batch, Stage.TRAIN)

    def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a validation step.

        Args:
            batch: Validation batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Validation loss.
        """
        return self.__eval_step(batch, Stage.VAL)

    def test_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a test step.

        Args:
            batch: Test batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Test loss.
        """
        return self.__eval_step(batch, Stage.TEST)

    def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Predict node-class logits for a batch.

        Args:
            batch: Prediction batch.
            batch_idx: Batch index, unused.

        Returns:
            logits: Predicted node-class logits.
        """
        return self.forward(batch.x)

    def configure_optimizers(self) -> optim.Adam:
        """
        Configure the optimizer.

        Returns:
            optimizer: Adam optimizer.
        """
        return optim.Adam(self.parameters(), lr=self.lr)

    def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
        """
        Run shared evaluation logic for a stage.

        Args:
            batch: Input batch.
            stage: Current evaluation stage.

        Returns:
            loss: Computed loss.
        """
        logits = self.forward(batch.x)
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = int(target_labels.size(0))

        loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
        self._compute_metrics(target_logits, target_labels, batch_size, stage)
        return loss

__init__(classifier_config, loss_fn=None, lr=0.001, metrics=None, metrics_log_kwargs=None)

Initialize the MLP-based NC classifier.

Parameters:

Name Type Description Default
classifier_config MLPClassifierConfig

Configuration for the MLP classifier.

required
loss_fn Module | None

Optional loss function. Defaults to CrossEntropyLoss.

None
lr float

Learning rate for the optimizer. Defaults to 0.001.

0.001
metrics MetricCollection | None

Optional metric collection for evaluation. Defaults to None.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls. Useful for configuring distributed synchronization behavior of torchmetrics. Defaults to None.

None
Source code in hypertorch/node_classification/mlp_nc.py
def __init__(
    self,
    classifier_config: MLPClassifierConfig,
    loss_fn: nn.Module | None = None,
    lr: float = 0.001,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the MLP-based NC classifier.

    Args:
        classifier_config: Configuration for the MLP classifier.
        loss_fn: Optional loss function. Defaults to ``CrossEntropyLoss``.
        lr: Learning rate for the optimizer. Defaults to ``0.001``.
        metrics: Optional metric collection for evaluation. Defaults to ``None``.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
            Useful for configuring distributed synchronization behavior
            of ``torchmetrics``. Defaults to ``None``.
    """
    classifier = MLP(
        in_channels=classifier_config["in_channels"],
        hidden_channels=classifier_config.get("hidden_channels"),
        out_channels=classifier_config["out_channels"],
        num_layers=classifier_config.get("num_layers", 1),
        activation_fn=classifier_config.get("activation_fn"),
        activation_fn_kwargs=classifier_config.get("activation_fn_kwargs"),
        normalization_fn=classifier_config.get("normalization_fn"),
        normalization_fn_kwargs=classifier_config.get("normalization_fn_kwargs"),
        bias=classifier_config.get("bias", True),
        drop_rate=classifier_config.get("drop_rate", 0.0),
    )

    super().__init__(
        classifier=classifier,
        loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
        metrics=metrics,
        metrics_log_kwargs=metrics_log_kwargs,
    )

    self.lr: float = lr

forward(x)

Predict node-class logits from node features.

Examples:

Given 4 nodes with 3 features each and 2 output classes: >>> x = [[0.1, 0.2, 0.3], # node 0 ... [0.4, 0.5, 0.6], # node 1 ... [0.7, 0.8, 0.9], # node 2 ... [1.0, 1.1, 1.2]] # node 3

The forward pass maps each node to one row of class logits: >>> logits = model.forward(x) >>> logits.shape torch.Size([4, 2])

Parameters:

Name Type Description Default
x Tensor

Node feature matrix of shape (num_nodes, in_channels).

required

Returns:

Name Type Description
logits Tensor

Node-class logits of shape (num_nodes, num_classes).

Source code in hypertorch/node_classification/mlp_nc.py
def forward(self, x: Tensor) -> Tensor:
    """
    Predict node-class logits from node features.

    Examples:
        Given 4 nodes with 3 features each and 2 output classes:
            >>> x = [[0.1, 0.2, 0.3],   # node 0
            ...      [0.4, 0.5, 0.6],   # node 1
            ...      [0.7, 0.8, 0.9],   # node 2
            ...      [1.0, 1.1, 1.2]]   # node 3

        The forward pass maps each node to one row of class logits:
            >>> logits = model.forward(x)
            >>> logits.shape
            torch.Size([4, 2])

    Args:
        x: Node feature matrix of shape ``(num_nodes, in_channels)``.

    Returns:
        logits: Node-class logits of shape ``(num_nodes, num_classes)``.
    """
    return self.classifier(x)

training_step(batch, batch_idx)

Run a training step.

Parameters:

Name Type Description Default
batch HData

Training batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Training loss.

Source code in hypertorch/node_classification/mlp_nc.py
def training_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a training step.

    Args:
        batch: Training batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Training loss.
    """
    return self.__eval_step(batch, Stage.TRAIN)

validation_step(batch, batch_idx)

Run a validation step.

Parameters:

Name Type Description Default
batch HData

Validation batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Validation loss.

Source code in hypertorch/node_classification/mlp_nc.py
def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a validation step.

    Args:
        batch: Validation batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Validation loss.
    """
    return self.__eval_step(batch, Stage.VAL)

test_step(batch, batch_idx)

Run a test step.

Parameters:

Name Type Description Default
batch HData

Test batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Test loss.

Source code in hypertorch/node_classification/mlp_nc.py
def test_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a test step.

    Args:
        batch: Test batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Test loss.
    """
    return self.__eval_step(batch, Stage.TEST)

predict_step(batch, batch_idx)

Predict node-class logits for a batch.

Parameters:

Name Type Description Default
batch HData

Prediction batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
logits Tensor

Predicted node-class logits.

Source code in hypertorch/node_classification/mlp_nc.py
def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Predict node-class logits for a batch.

    Args:
        batch: Prediction batch.
        batch_idx: Batch index, unused.

    Returns:
        logits: Predicted node-class logits.
    """
    return self.forward(batch.x)

configure_optimizers()

Configure the optimizer.

Returns:

Name Type Description
optimizer Adam

Adam optimizer.

Source code in hypertorch/node_classification/mlp_nc.py
def configure_optimizers(self) -> optim.Adam:
    """
    Configure the optimizer.

    Returns:
        optimizer: Adam optimizer.
    """
    return optim.Adam(self.parameters(), lr=self.lr)

__eval_step(batch, stage)

Run shared evaluation logic for a stage.

Parameters:

Name Type Description Default
batch HData

Input batch.

required
stage Stage

Current evaluation stage.

required

Returns:

Name Type Description
loss Tensor

Computed loss.

Source code in hypertorch/node_classification/mlp_nc.py
def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
    """
    Run shared evaluation logic for a stage.

    Args:
        batch: Input batch.
        stage: Current evaluation stage.

    Returns:
        loss: Computed loss.
    """
    logits = self.forward(batch.x)
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = int(target_labels.size(0))

    loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
    self._compute_metrics(target_logits, target_labels, batch_size, stage)
    return loss

MLPClassifierConfig

Bases: TypedDict

Configuration for the MLP classifier in MLPClassifier.

Attributes:

Name Type Description
in_channels int

Number of input features per node.

out_channels int

Number of node classes.

num_layers NotRequired[int]

Number of layers in the MLP classifier.

hidden_channels NotRequired[int | None]

Optional number of hidden units per layer. If None, no hidden layers are used and the classifier is a simple linear layer.

activation_fn NotRequired[ActivationFn | None]

Optional activation function class to use in the MLP classifier. If None, no activation function is applied.

activation_fn_kwargs NotRequired[dict | None]

Optional dictionary of keyword arguments to pass to the activation function constructor.

normalization_fn NotRequired[NormalizationFn | None]

Optional normalization function class to use in the MLP classifier. If None, no normalization is applied.

normalization_fn_kwargs NotRequired[dict | None]

Optional dictionary of keyword arguments to pass to the normalization function constructor.

bias NotRequired[bool]

Whether to include bias terms in the MLP layers. Defaults to True.

drop_rate NotRequired[float]

Dropout rate to apply after each MLP layer except the last one. Defaults to 0.0.

Source code in hypertorch/node_classification/mlp_nc.py
class MLPClassifierConfig(TypedDict):
    """
    Configuration for the MLP classifier in ``MLPClassifier``.

    Attributes:
        in_channels: Number of input features per node.
        out_channels: Number of node classes.
        num_layers: Number of layers in the MLP classifier.
        hidden_channels: Optional number of hidden units per layer. If ``None``, no hidden layers
            are used and the classifier is a simple linear layer.
        activation_fn: Optional activation function class to use in the MLP classifier.
            If ``None``, no activation function is applied.
        activation_fn_kwargs: Optional dictionary of keyword arguments to pass to the activation
            function constructor.
        normalization_fn: Optional normalization function class to use in the MLP classifier.
            If ``None``, no normalization is applied.
        normalization_fn_kwargs: Optional dictionary of keyword arguments to pass to the
            normalization function constructor.
        bias: Whether to include bias terms in the MLP layers. Defaults to ``True``.
        drop_rate: Dropout rate to apply after each MLP layer except the last one.
            Defaults to ``0.0``.
    """

    in_channels: int
    out_channels: int
    num_layers: NotRequired[int]
    hidden_channels: NotRequired[int | None]
    activation_fn: NotRequired[ActivationFn | None]
    activation_fn_kwargs: NotRequired[dict | None]
    normalization_fn: NotRequired[NormalizationFn | None]
    normalization_fn_kwargs: NotRequired[dict | None]
    bias: NotRequired[bool]
    drop_rate: NotRequired[float]

Node2VecGCNClassifierConfig

Bases: TypedDict

Configuration for the Node2VecGCN classifier in Node2VecGCNClassifier.

Attributes:

Name Type Description
mode NotRequired[Node2VecMode]

Whether to use precomputed node embeddings from x or train a Node2Vec encoder jointly inside the module. Defaults to "joint".

num_features int

Dimension of the Node2Vec embeddings, which is also used by the GCN.

node2vec_config Node2VecEncoderConfig

Shared Node2Vec configuration used in joint mode. It is ignored in precomputed mode. So, it can be provided as an empty dictionary: {}.

gcn_config Node2VecGCNEncoderConfig

Configuration for the GCN classifier.

Source code in hypertorch/node_classification/node2vecgcn_nc.py
class Node2VecGCNClassifierConfig(TypedDict):
    """
    Configuration for the Node2VecGCN classifier in ``Node2VecGCNClassifier``.

    Attributes:
        mode: Whether to use precomputed node embeddings from ``x`` or train a Node2Vec
            encoder jointly inside the module. Defaults to ``"joint"``.
        num_features: Dimension of the Node2Vec embeddings, which is also used by the GCN.
        node2vec_config: Shared Node2Vec configuration used in joint mode. It is ignored
            in precomputed mode. So, it can be provided as an empty dictionary: ``{}``.
        gcn_config: Configuration for the GCN classifier.
    """

    mode: NotRequired[Node2VecMode]
    num_features: int
    node2vec_config: Node2VecNCConfig
    gcn_config: Node2VecGCNNCConfig

Node2VecGCNClassifier

Bases: NCClassifier

A LightningModule for Node2VecGCN-based NC classifier.

Supports two modes
  • precomputed: use node embeddings already stored in batch.x.
  • joint: train a Node2Vec encoder jointly with the GCN classifier.

Attributes:

Name Type Description
encoder Module | None

Optional Node2Vec-GCN encoder inherited from NCClassifier.

classifier Module

GCN classifier inherited from NCClassifier in precomputed mode.

loss_fn Module

Loss function inherited from NCClassifier.

metrics_log_kwargs dict[str, Any]

Metric logging keyword arguments inherited from NCClassifier.

train_metrics MetricCollection | None

Optional training metrics inherited from NCClassifier.

val_metrics MetricCollection | None

Optional validation metrics inherited from NCClassifier.

test_metrics MetricCollection | None

Optional test metrics inherited from NCClassifier.

mode Node2VecMode

Whether to use precomputed or joint Node2Vec embeddings.

embedding_dim int

Node embedding dimension consumed by GCN.

node2vec_config Node2VecEncoderConfig

Node2Vec configuration.

gcn_config Node2VecGCNEncoderConfig

GCN configuration.

lr float

Learning rate for the optimizer. Defaults to 0.001.

weight_decay float

Weight decay for the optimizer. Defaults to 0.0.

random_walk_batch_size int

Batch size used for Node2Vec walk loss in joint mode. Defaults to 128.

node2vec_loss_weight float

Weight applied to Node2Vec walk loss in joint mode. Defaults to 1.0.

Source code in hypertorch/node_classification/node2vecgcn_nc.py
class Node2VecGCNClassifier(NCClassifier):
    """
    A LightningModule for Node2VecGCN-based NC classifier.

    Supports two modes:
        - ``precomputed``: use node embeddings already stored in ``batch.x``.
        - ``joint``: train a Node2Vec encoder jointly with the GCN classifier.

    Attributes:
        encoder: Optional Node2Vec-GCN encoder inherited from ``NCClassifier``.
        classifier: GCN classifier inherited from ``NCClassifier`` in precomputed mode.
        loss_fn: Loss function inherited from ``NCClassifier``.
        metrics_log_kwargs: Metric logging keyword arguments inherited from ``NCClassifier``.
        train_metrics: Optional training metrics inherited from ``NCClassifier``.
        val_metrics: Optional validation metrics inherited from ``NCClassifier``.
        test_metrics: Optional test metrics inherited from ``NCClassifier``.
        mode: Whether to use precomputed or joint Node2Vec embeddings.
        embedding_dim: Node embedding dimension consumed by GCN.
        node2vec_config: Node2Vec configuration.
        gcn_config: GCN configuration.
        lr: Learning rate for the optimizer. Defaults to ``0.001``.
        weight_decay: Weight decay for the optimizer. Defaults to ``0.0``.
        random_walk_batch_size: Batch size used for Node2Vec walk loss in joint mode.
            Defaults to ``128``.
        node2vec_loss_weight: Weight applied to Node2Vec walk loss in joint mode.
            Defaults to ``1.0``.
    """

    def __init__(
        self,
        classifier_config: Node2VecGCNClassifierConfig,
        loss_fn: nn.Module | None = None,
        lr: float = 0.001,
        weight_decay: float = 0.0,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the Node2VecGCN-based NC classifier.

        Args:
            classifier_config: Configuration for Node2Vec embeddings and GCN layers.
            loss_fn: Optional NC loss function. Defaults to ``CrossEntropyLoss``.
            lr: Learning rate for the optimizer. Defaults to ``0.001``.
            weight_decay: Weight decay for the optimizer. Defaults to ``0.0``.
            metrics: Optional metric collection for evaluation. Defaults to ``None``.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
                Useful for configuring distributed synchronization behavior of ``torchmetrics``.
                Defaults to ``None``.
        """
        self.mode: Node2VecMode = classifier_config.get("mode", NODE2VEC_JOINT_MODE)
        self.embedding_dim: int = classifier_config["num_features"]
        self.node2vec_config: Node2VecNCConfig = classifier_config["node2vec_config"]
        self.gcn_config: Node2VecGCNNCConfig = classifier_config["gcn_config"]

        node2vecgcn_encoder = (
            build_node2vecgcn_encoder(
                embedding_dim=self.embedding_dim,
                node2vec_config=self.node2vec_config,
                gcn_config=self.gcn_config,
                mode=self.mode,
            )
            if self.mode == NODE2VEC_JOINT_MODE
            else None
        )

        classifier = (
            build_gcn_encoder(self.embedding_dim, self.gcn_config)
            if self.mode == NODE2VEC_PRECOMPUTED_MODE
            else nn.Identity()
        )

        super().__init__(
            encoder=node2vecgcn_encoder,
            classifier=classifier,
            loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
            metrics=metrics,
            metrics_log_kwargs=metrics_log_kwargs,
        )

        self.lr: float = lr
        self.weight_decay: float = weight_decay
        self.random_walk_batch_size: int = self.node2vec_config.get("random_walk_batch_size", 128)
        self.node2vec_loss_weight: float = self.node2vec_config.get("node2vec_loss_weight", 1.0)

        self.__walk_loader_state: Node2VecWalkLoaderState = Node2VecWalkLoaderState()

    def forward(
        self,
        x: Tensor,
        hyperedge_index: Tensor,
        global_node_ids: Tensor | None = None,
    ) -> Tensor:
        """
        Predict node-class logits from Node2Vec embeddings refined by GCN.

        Args:
            x: Node feature or precomputed embedding matrix.
            hyperedge_index: Hyperedge incidence tensor.
            global_node_ids: Optional global node IDs for joint Node2Vec lookup.
                Defaults to ``None``.

        Returns:
            logits: Node-class logits.

        Raises:
            ValueError: If the configured mode cannot supply node embeddings.
        """
        gcn_edge_index = to_gcn_edge_index(hyperedge_index, self.gcn_config)

        if self.mode == NODE2VEC_JOINT_MODE:
            encoder = to_node2vecgcn_encoder(self.encoder, self.mode)
            validate_global_node_ids(encoder.num_embeddings, global_node_ids, self.mode)
            logits = encoder(batch=global_node_ids, edge_index=gcn_edge_index)
        else:
            if x.size(1) != self.embedding_dim:
                raise ValueError(
                    f"Expected precomputed node embeddings with dimension "
                    f"{self.embedding_dim}, got {x.size(1)}."
                )
            logits = self.classifier(x, gcn_edge_index)

        return logits

    def training_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a training step.

        In joint mode this combines NC loss with one stochastic Node2Vec walk loss batch.

        Args:
            batch: Training batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Training loss.
        """
        logits = self.forward(batch.x, batch.hyperedge_index, batch.global_node_ids)
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = int(target_labels.size(0))

        if self.mode == NODE2VEC_JOINT_MODE:
            positive_random_walk, negative_random_walk = next_walk_batch(
                mode=self.mode,
                encoder=self.encoder,
                batch_size=self.random_walk_batch_size,
                state=self.__walk_loader_state,
            )
            positive_random_walk = positive_random_walk.to(self.device)
            negative_random_walk = negative_random_walk.to(self.device)

            nc_loss = self.loss_fn(target_logits, target_labels)
            node2vec_loss = to_node2vec_encoder(self.encoder, self.mode).loss(
                positive_random_walk,
                negative_random_walk,
            )
            loss = nc_loss + (self.node2vec_loss_weight * node2vec_loss)

            self.log(
                stage_metric_name(Stage.TRAIN, "nc_loss"),
                nc_loss,
                prog_bar=True,
                batch_size=batch_size,
                **self.metrics_log_kwargs,
            )
            self.log(
                stage_metric_name(Stage.TRAIN, "node2vec_loss"),
                node2vec_loss,
                prog_bar=True,
                batch_size=batch_size,
                **self.metrics_log_kwargs,
            )
            self.log(
                stage_metric_name(Stage.TRAIN, "loss"),
                loss,
                prog_bar=True,
                batch_size=batch_size,
                **self.metrics_log_kwargs,
            )
        else:
            loss = self._compute_loss(target_logits, target_labels, batch_size, Stage.TRAIN)

        self._compute_metrics(target_logits, target_labels, batch_size, Stage.TRAIN)
        return loss

    def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a validation step.

        Args:
            batch: Validation batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Validation loss.
        """
        return self.__eval_step(batch, Stage.VAL)

    def test_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a test step.

        Args:
            batch: Test batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Test loss.
        """
        return self.__eval_step(batch, Stage.TEST)

    def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Predict node-class logits for a batch.

        Args:
            batch: Prediction batch.
            batch_idx: Batch index, unused.

        Returns:
            logits: Predicted node-class logits.
        """
        return self.forward(batch.x, batch.hyperedge_index, batch.global_node_ids)

    def configure_optimizers(self) -> optim.Adam:
        """
        Configure the optimizer.

        Returns:
            optimizer: Adam optimizer.
        """
        return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

    def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
        """
        Run shared evaluation logic for a stage.

        Args:
            batch: Input batch.
            stage: Current evaluation stage.

        Returns:
            loss: Computed loss.
        """
        logits = self.forward(batch.x, batch.hyperedge_index, batch.global_node_ids)
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = int(target_labels.size(0))

        loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
        self._compute_metrics(target_logits, target_labels, batch_size, stage)
        return loss

__init__(classifier_config, loss_fn=None, lr=0.001, weight_decay=0.0, metrics=None, metrics_log_kwargs=None)

Initialize the Node2VecGCN-based NC classifier.

Parameters:

Name Type Description Default
classifier_config Node2VecGCNClassifierConfig

Configuration for Node2Vec embeddings and GCN layers.

required
loss_fn Module | None

Optional NC loss function. Defaults to CrossEntropyLoss.

None
lr float

Learning rate for the optimizer. Defaults to 0.001.

0.001
weight_decay float

Weight decay for the optimizer. Defaults to 0.0.

0.0
metrics MetricCollection | None

Optional metric collection for evaluation. Defaults to None.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls. Useful for configuring distributed synchronization behavior of torchmetrics. Defaults to None.

None
Source code in hypertorch/node_classification/node2vecgcn_nc.py
def __init__(
    self,
    classifier_config: Node2VecGCNClassifierConfig,
    loss_fn: nn.Module | None = None,
    lr: float = 0.001,
    weight_decay: float = 0.0,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the Node2VecGCN-based NC classifier.

    Args:
        classifier_config: Configuration for Node2Vec embeddings and GCN layers.
        loss_fn: Optional NC loss function. Defaults to ``CrossEntropyLoss``.
        lr: Learning rate for the optimizer. Defaults to ``0.001``.
        weight_decay: Weight decay for the optimizer. Defaults to ``0.0``.
        metrics: Optional metric collection for evaluation. Defaults to ``None``.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
            Useful for configuring distributed synchronization behavior of ``torchmetrics``.
            Defaults to ``None``.
    """
    self.mode: Node2VecMode = classifier_config.get("mode", NODE2VEC_JOINT_MODE)
    self.embedding_dim: int = classifier_config["num_features"]
    self.node2vec_config: Node2VecNCConfig = classifier_config["node2vec_config"]
    self.gcn_config: Node2VecGCNNCConfig = classifier_config["gcn_config"]

    node2vecgcn_encoder = (
        build_node2vecgcn_encoder(
            embedding_dim=self.embedding_dim,
            node2vec_config=self.node2vec_config,
            gcn_config=self.gcn_config,
            mode=self.mode,
        )
        if self.mode == NODE2VEC_JOINT_MODE
        else None
    )

    classifier = (
        build_gcn_encoder(self.embedding_dim, self.gcn_config)
        if self.mode == NODE2VEC_PRECOMPUTED_MODE
        else nn.Identity()
    )

    super().__init__(
        encoder=node2vecgcn_encoder,
        classifier=classifier,
        loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
        metrics=metrics,
        metrics_log_kwargs=metrics_log_kwargs,
    )

    self.lr: float = lr
    self.weight_decay: float = weight_decay
    self.random_walk_batch_size: int = self.node2vec_config.get("random_walk_batch_size", 128)
    self.node2vec_loss_weight: float = self.node2vec_config.get("node2vec_loss_weight", 1.0)

    self.__walk_loader_state: Node2VecWalkLoaderState = Node2VecWalkLoaderState()

forward(x, hyperedge_index, global_node_ids=None)

Predict node-class logits from Node2Vec embeddings refined by GCN.

Parameters:

Name Type Description Default
x Tensor

Node feature or precomputed embedding matrix.

required
hyperedge_index Tensor

Hyperedge incidence tensor.

required
global_node_ids Tensor | None

Optional global node IDs for joint Node2Vec lookup. Defaults to None.

None

Returns:

Name Type Description
logits Tensor

Node-class logits.

Raises:

Type Description
ValueError

If the configured mode cannot supply node embeddings.

Source code in hypertorch/node_classification/node2vecgcn_nc.py
def forward(
    self,
    x: Tensor,
    hyperedge_index: Tensor,
    global_node_ids: Tensor | None = None,
) -> Tensor:
    """
    Predict node-class logits from Node2Vec embeddings refined by GCN.

    Args:
        x: Node feature or precomputed embedding matrix.
        hyperedge_index: Hyperedge incidence tensor.
        global_node_ids: Optional global node IDs for joint Node2Vec lookup.
            Defaults to ``None``.

    Returns:
        logits: Node-class logits.

    Raises:
        ValueError: If the configured mode cannot supply node embeddings.
    """
    gcn_edge_index = to_gcn_edge_index(hyperedge_index, self.gcn_config)

    if self.mode == NODE2VEC_JOINT_MODE:
        encoder = to_node2vecgcn_encoder(self.encoder, self.mode)
        validate_global_node_ids(encoder.num_embeddings, global_node_ids, self.mode)
        logits = encoder(batch=global_node_ids, edge_index=gcn_edge_index)
    else:
        if x.size(1) != self.embedding_dim:
            raise ValueError(
                f"Expected precomputed node embeddings with dimension "
                f"{self.embedding_dim}, got {x.size(1)}."
            )
        logits = self.classifier(x, gcn_edge_index)

    return logits

training_step(batch, batch_idx)

Run a training step.

In joint mode this combines NC loss with one stochastic Node2Vec walk loss batch.

Parameters:

Name Type Description Default
batch HData

Training batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Training loss.

Source code in hypertorch/node_classification/node2vecgcn_nc.py
def training_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a training step.

    In joint mode this combines NC loss with one stochastic Node2Vec walk loss batch.

    Args:
        batch: Training batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Training loss.
    """
    logits = self.forward(batch.x, batch.hyperedge_index, batch.global_node_ids)
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = int(target_labels.size(0))

    if self.mode == NODE2VEC_JOINT_MODE:
        positive_random_walk, negative_random_walk = next_walk_batch(
            mode=self.mode,
            encoder=self.encoder,
            batch_size=self.random_walk_batch_size,
            state=self.__walk_loader_state,
        )
        positive_random_walk = positive_random_walk.to(self.device)
        negative_random_walk = negative_random_walk.to(self.device)

        nc_loss = self.loss_fn(target_logits, target_labels)
        node2vec_loss = to_node2vec_encoder(self.encoder, self.mode).loss(
            positive_random_walk,
            negative_random_walk,
        )
        loss = nc_loss + (self.node2vec_loss_weight * node2vec_loss)

        self.log(
            stage_metric_name(Stage.TRAIN, "nc_loss"),
            nc_loss,
            prog_bar=True,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
        self.log(
            stage_metric_name(Stage.TRAIN, "node2vec_loss"),
            node2vec_loss,
            prog_bar=True,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
        self.log(
            stage_metric_name(Stage.TRAIN, "loss"),
            loss,
            prog_bar=True,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
    else:
        loss = self._compute_loss(target_logits, target_labels, batch_size, Stage.TRAIN)

    self._compute_metrics(target_logits, target_labels, batch_size, Stage.TRAIN)
    return loss

validation_step(batch, batch_idx)

Run a validation step.

Parameters:

Name Type Description Default
batch HData

Validation batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Validation loss.

Source code in hypertorch/node_classification/node2vecgcn_nc.py
def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a validation step.

    Args:
        batch: Validation batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Validation loss.
    """
    return self.__eval_step(batch, Stage.VAL)

test_step(batch, batch_idx)

Run a test step.

Parameters:

Name Type Description Default
batch HData

Test batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Test loss.

Source code in hypertorch/node_classification/node2vecgcn_nc.py
def test_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a test step.

    Args:
        batch: Test batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Test loss.
    """
    return self.__eval_step(batch, Stage.TEST)

predict_step(batch, batch_idx)

Predict node-class logits for a batch.

Parameters:

Name Type Description Default
batch HData

Prediction batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
logits Tensor

Predicted node-class logits.

Source code in hypertorch/node_classification/node2vecgcn_nc.py
def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Predict node-class logits for a batch.

    Args:
        batch: Prediction batch.
        batch_idx: Batch index, unused.

    Returns:
        logits: Predicted node-class logits.
    """
    return self.forward(batch.x, batch.hyperedge_index, batch.global_node_ids)

configure_optimizers()

Configure the optimizer.

Returns:

Name Type Description
optimizer Adam

Adam optimizer.

Source code in hypertorch/node_classification/node2vecgcn_nc.py
def configure_optimizers(self) -> optim.Adam:
    """
    Configure the optimizer.

    Returns:
        optimizer: Adam optimizer.
    """
    return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

__eval_step(batch, stage)

Run shared evaluation logic for a stage.

Parameters:

Name Type Description Default
batch HData

Input batch.

required
stage Stage

Current evaluation stage.

required

Returns:

Name Type Description
loss Tensor

Computed loss.

Source code in hypertorch/node_classification/node2vecgcn_nc.py
def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
    """
    Run shared evaluation logic for a stage.

    Args:
        batch: Input batch.
        stage: Current evaluation stage.

    Returns:
        loss: Computed loss.
    """
    logits = self.forward(batch.x, batch.hyperedge_index, batch.global_node_ids)
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = int(target_labels.size(0))

    loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
    self._compute_metrics(target_logits, target_labels, batch_size, stage)
    return loss

Node2VecClassifierConfig

Bases: TypedDict

Configuration for the Node2Vec classifier in Node2VecClassifier.

Attributes:

Name Type Description
out_channels int

Number of node classes.

Source code in hypertorch/node_classification/node2vec_nc.py
class Node2VecClassifierConfig(TypedDict):
    """
    Configuration for the Node2Vec classifier in ``Node2VecClassifier``.

    Attributes:
        out_channels: Number of node classes.
    """

    out_channels: int

Node2VecEncoderConfig

Bases: TypedDict

Configuration for the Node2Vec encoder in Node2VecClassifier.

Attributes:

Name Type Description
mode NotRequired[Node2VecMode]

Whether to use precomputed node embeddings from x or train a Node2Vec encoder jointly inside the module. Defaults to "joint".

num_features int

Dimension of the Node2Vec embeddings, which is also the input dimension of the classifier.

node2vec_config Node2VecEncoderConfig

Shared Node2Vec configuration used in joint mode, or metadata for validating precomputed embeddings.

Source code in hypertorch/node_classification/node2vec_nc.py
class Node2VecEncoderConfig(TypedDict):
    """
    Configuration for the Node2Vec encoder in ``Node2VecClassifier``.

    Attributes:
        mode: Whether to use precomputed node embeddings from ``x`` or train a Node2Vec
            encoder jointly inside the module. Defaults to ``"joint"``.
        num_features: Dimension of the Node2Vec embeddings, which is also
            the input dimension of the classifier.
        node2vec_config: Shared Node2Vec configuration used in joint mode, or metadata for
            validating precomputed embeddings.
    """

    mode: NotRequired[Node2VecMode]
    num_features: int
    node2vec_config: Node2VecNCConfig

Node2VecClassifier

Bases: NCClassifier

A LightningModule for Node2Vec-based NC classifier.

Supports two modes
  • precomputed: use node embeddings already stored in batch.x.
  • joint: train a Node2Vec encoder jointly with the node classifier.

Attributes:

Name Type Description
encoder Module | None

Optional Node2Vec encoder inherited from NCClassifier.

classifier Module

Classifier inherited from NCClassifier.

loss_fn Module

Loss function inherited from NCClassifier.

metrics_log_kwargs dict[str, Any]

Metric logging keyword arguments inherited from NCClassifier.

train_metrics MetricCollection | None

Optional training metrics inherited from NCClassifier.

val_metrics MetricCollection | None

Optional validation metrics inherited from NCClassifier.

test_metrics MetricCollection | None

Optional test metrics inherited from NCClassifier.

mode Node2VecMode

Whether to use precomputed or joint Node2Vec embeddings.

embedding_dim int

Node embedding dimension consumed by the classifier.

lr float

Learning rate for the optimizer. Defaults to 0.001.

weight_decay float

Weight decay for the optimizer. Defaults to 0.0.

random_walk_batch_size int

Batch size used for Node2Vec walk loss in joint mode. Defaults to 128.

node2vec_loss_weight float

Weight applied to Node2Vec walk loss in joint mode. Defaults to 1.0.

Source code in hypertorch/node_classification/node2vec_nc.py
class Node2VecClassifier(NCClassifier):
    """
    A LightningModule for Node2Vec-based NC classifier.

    Supports two modes:
        - ``precomputed``: use node embeddings already stored in ``batch.x``.
        - ``joint``: train a Node2Vec encoder jointly with the node classifier.

    Attributes:
        encoder: Optional Node2Vec encoder inherited from ``NCClassifier``.
        classifier: Classifier inherited from ``NCClassifier``.
        loss_fn: Loss function inherited from ``NCClassifier``.
        metrics_log_kwargs: Metric logging keyword arguments inherited from ``NCClassifier``.
        train_metrics: Optional training metrics inherited from ``NCClassifier``.
        val_metrics: Optional validation metrics inherited from ``NCClassifier``.
        test_metrics: Optional test metrics inherited from ``NCClassifier``.
        mode: Whether to use precomputed or joint Node2Vec embeddings.
        embedding_dim: Node embedding dimension consumed by the classifier.
        lr: Learning rate for the optimizer. Defaults to ``0.001``.
        weight_decay: Weight decay for the optimizer. Defaults to ``0.0``.
        random_walk_batch_size: Batch size used for Node2Vec walk loss in joint mode.
            Defaults to ``128``.
        node2vec_loss_weight: Weight applied to Node2Vec walk loss in joint mode.
            Defaults to ``1.0``.
    """

    def __init__(
        self,
        encoder_config: Node2VecEncoderConfig,
        classifier_config: Node2VecClassifierConfig,
        loss_fn: nn.Module | None = None,
        lr: float = 0.001,
        weight_decay: float = 0.0,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the Node2Vec-based NC classifier.

        Args:
            encoder_config: Configuration for the Node2Vec encoder.
            classifier_config: Configuration for the classifier.
            loss_fn: Optional NC loss function. Defaults to ``CrossEntropyLoss``.
            lr: Learning rate for the optimizer. Defaults to ``0.001``.
            weight_decay: Weight decay for the optimizer. Defaults to ``0.0``.
            metrics: Optional metric collection for evaluation. Defaults to ``None``.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
                Useful for configuring distributed synchronization behavior of ``torchmetrics``.
                Defaults to ``None``.
        """
        self.mode: Node2VecMode = encoder_config.get("mode", NODE2VEC_JOINT_MODE)
        self.embedding_dim: int = encoder_config["num_features"]
        node2vec_config = encoder_config["node2vec_config"]

        encoder = (
            build_node2vec_encoder(self.embedding_dim, node2vec_config, self.mode)
            if self.mode == NODE2VEC_JOINT_MODE
            else None
        )

        classifier = SLP(
            in_channels=self.embedding_dim,
            out_channels=classifier_config["out_channels"],
        )

        super().__init__(
            encoder=encoder,
            classifier=classifier,
            loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
            metrics=metrics,
            metrics_log_kwargs=metrics_log_kwargs,
        )

        self.lr: float = lr
        self.weight_decay: float = weight_decay
        self.random_walk_batch_size: int = node2vec_config.get("random_walk_batch_size", 128)
        self.node2vec_loss_weight: float = node2vec_config.get("node2vec_loss_weight", 1.0)

        self.__walk_loader_state: Node2VecWalkLoaderState = Node2VecWalkLoaderState()

    def forward(
        self,
        x: Tensor,
        global_node_ids: Tensor | None = None,
    ) -> Tensor:
        """
        Predict node-class logits from precomputed or jointly trained Node2Vec embeddings.

        Args:
            x: Node feature or precomputed embedding matrix.
            global_node_ids: Optional global node IDs for joint Node2Vec lookup.
                Defaults to ``None``.

        Returns:
            logits: Node-class logits.

        Raises:
            ValueError: If the configured mode cannot supply node embeddings.
        """
        # Encode: get node embeddings from precomputation or joint encoder
        if self.mode == NODE2VEC_JOINT_MODE:
            encoder = to_node2vec_encoder(self.encoder, self.mode)
            validate_global_node_ids(encoder.num_embeddings, global_node_ids, self.mode)
            node_embeddings = encoder(batch=global_node_ids)
        else:
            if x.size(1) != self.embedding_dim:
                raise ValueError(
                    f"Expected precomputed node embeddings with dimension "
                    f"{self.embedding_dim}, got {x.size(1)}."
                )
            node_embeddings = x

        # Decode: linear projection to scalar score per node class
        # shape: (num_nodes, out_channels)
        logits: Tensor = self.classifier(node_embeddings)
        return logits

    def training_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a training step.

        In joint mode this combines NC loss with one stochastic Node2Vec walk loss batch.

        Args:
            batch: Training batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Training loss.
        """
        logits = self.forward(batch.x, batch.global_node_ids)
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = int(target_labels.size(0))

        if self.mode == NODE2VEC_JOINT_MODE:
            # Node2Vec.loss() is already a stochastic objective over sampled walks,
            # so one walk batch is a standard SGD estimate, not a logically different loss,
            # meaning we can optimize training by using a single walk batch per training step,
            # instead of averaging over multiple walk batches.
            positive_random_walk, negative_random_walk = next_walk_batch(
                mode=self.mode,
                encoder=self.encoder,
                batch_size=self.random_walk_batch_size,
                state=self.__walk_loader_state,
            )
            positive_random_walk = positive_random_walk.to(self.device)
            negative_random_walk = negative_random_walk.to(self.device)

            nc_loss = self.loss_fn(target_logits, target_labels)
            node2vec_loss = to_node2vec_encoder(self.encoder, self.mode).loss(
                positive_random_walk,
                negative_random_walk,
            )
            loss = nc_loss + (self.node2vec_loss_weight * node2vec_loss)

            self.log(
                stage_metric_name(Stage.TRAIN, "nc_loss"),
                nc_loss,
                prog_bar=True,
                batch_size=batch_size,
                **self.metrics_log_kwargs,
            )
            self.log(
                stage_metric_name(Stage.TRAIN, "node2vec_loss"),
                node2vec_loss,
                prog_bar=True,
                batch_size=batch_size,
                **self.metrics_log_kwargs,
            )
            self.log(
                stage_metric_name(Stage.TRAIN, "loss"),
                loss,
                prog_bar=True,
                batch_size=batch_size,
                **self.metrics_log_kwargs,
            )
        else:
            loss = self._compute_loss(target_logits, target_labels, batch_size, Stage.TRAIN)

        self._compute_metrics(target_logits, target_labels, batch_size, Stage.TRAIN)
        return loss

    def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a validation step.

        Args:
            batch: Validation batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Validation loss.
        """
        return self.__eval_step(batch, Stage.VAL)

    def test_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a test step.

        Args:
            batch: Test batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Test loss.
        """
        return self.__eval_step(batch, Stage.TEST)

    def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Predict node-class logits for a batch.

        Args:
            batch: Prediction batch.
            batch_idx: Batch index, unused.

        Returns:
            logits: Predicted node-class logits.
        """
        return self.forward(batch.x, batch.global_node_ids)

    def configure_optimizers(self) -> optim.Adam:
        """
        Configure the optimizer.

        Returns:
            optimizer: Adam optimizer.
        """
        return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

    def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
        """
        Run shared evaluation logic for a stage.

        Args:
            batch: Input batch.
            stage: Current evaluation stage.

        Returns:
            loss: Computed loss.
        """
        logits = self.forward(batch.x, batch.global_node_ids)
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = int(target_labels.size(0))

        loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
        self._compute_metrics(target_logits, target_labels, batch_size, stage)
        return loss

__init__(encoder_config, classifier_config, loss_fn=None, lr=0.001, weight_decay=0.0, metrics=None, metrics_log_kwargs=None)

Initialize the Node2Vec-based NC classifier.

Parameters:

Name Type Description Default
encoder_config Node2VecEncoderConfig

Configuration for the Node2Vec encoder.

required
classifier_config Node2VecClassifierConfig

Configuration for the classifier.

required
loss_fn Module | None

Optional NC loss function. Defaults to CrossEntropyLoss.

None
lr float

Learning rate for the optimizer. Defaults to 0.001.

0.001
weight_decay float

Weight decay for the optimizer. Defaults to 0.0.

0.0
metrics MetricCollection | None

Optional metric collection for evaluation. Defaults to None.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls. Useful for configuring distributed synchronization behavior of torchmetrics. Defaults to None.

None
Source code in hypertorch/node_classification/node2vec_nc.py
def __init__(
    self,
    encoder_config: Node2VecEncoderConfig,
    classifier_config: Node2VecClassifierConfig,
    loss_fn: nn.Module | None = None,
    lr: float = 0.001,
    weight_decay: float = 0.0,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the Node2Vec-based NC classifier.

    Args:
        encoder_config: Configuration for the Node2Vec encoder.
        classifier_config: Configuration for the classifier.
        loss_fn: Optional NC loss function. Defaults to ``CrossEntropyLoss``.
        lr: Learning rate for the optimizer. Defaults to ``0.001``.
        weight_decay: Weight decay for the optimizer. Defaults to ``0.0``.
        metrics: Optional metric collection for evaluation. Defaults to ``None``.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
            Useful for configuring distributed synchronization behavior of ``torchmetrics``.
            Defaults to ``None``.
    """
    self.mode: Node2VecMode = encoder_config.get("mode", NODE2VEC_JOINT_MODE)
    self.embedding_dim: int = encoder_config["num_features"]
    node2vec_config = encoder_config["node2vec_config"]

    encoder = (
        build_node2vec_encoder(self.embedding_dim, node2vec_config, self.mode)
        if self.mode == NODE2VEC_JOINT_MODE
        else None
    )

    classifier = SLP(
        in_channels=self.embedding_dim,
        out_channels=classifier_config["out_channels"],
    )

    super().__init__(
        encoder=encoder,
        classifier=classifier,
        loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
        metrics=metrics,
        metrics_log_kwargs=metrics_log_kwargs,
    )

    self.lr: float = lr
    self.weight_decay: float = weight_decay
    self.random_walk_batch_size: int = node2vec_config.get("random_walk_batch_size", 128)
    self.node2vec_loss_weight: float = node2vec_config.get("node2vec_loss_weight", 1.0)

    self.__walk_loader_state: Node2VecWalkLoaderState = Node2VecWalkLoaderState()

forward(x, global_node_ids=None)

Predict node-class logits from precomputed or jointly trained Node2Vec embeddings.

Parameters:

Name Type Description Default
x Tensor

Node feature or precomputed embedding matrix.

required
global_node_ids Tensor | None

Optional global node IDs for joint Node2Vec lookup. Defaults to None.

None

Returns:

Name Type Description
logits Tensor

Node-class logits.

Raises:

Type Description
ValueError

If the configured mode cannot supply node embeddings.

Source code in hypertorch/node_classification/node2vec_nc.py
def forward(
    self,
    x: Tensor,
    global_node_ids: Tensor | None = None,
) -> Tensor:
    """
    Predict node-class logits from precomputed or jointly trained Node2Vec embeddings.

    Args:
        x: Node feature or precomputed embedding matrix.
        global_node_ids: Optional global node IDs for joint Node2Vec lookup.
            Defaults to ``None``.

    Returns:
        logits: Node-class logits.

    Raises:
        ValueError: If the configured mode cannot supply node embeddings.
    """
    # Encode: get node embeddings from precomputation or joint encoder
    if self.mode == NODE2VEC_JOINT_MODE:
        encoder = to_node2vec_encoder(self.encoder, self.mode)
        validate_global_node_ids(encoder.num_embeddings, global_node_ids, self.mode)
        node_embeddings = encoder(batch=global_node_ids)
    else:
        if x.size(1) != self.embedding_dim:
            raise ValueError(
                f"Expected precomputed node embeddings with dimension "
                f"{self.embedding_dim}, got {x.size(1)}."
            )
        node_embeddings = x

    # Decode: linear projection to scalar score per node class
    # shape: (num_nodes, out_channels)
    logits: Tensor = self.classifier(node_embeddings)
    return logits

training_step(batch, batch_idx)

Run a training step.

In joint mode this combines NC loss with one stochastic Node2Vec walk loss batch.

Parameters:

Name Type Description Default
batch HData

Training batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Training loss.

Source code in hypertorch/node_classification/node2vec_nc.py
def training_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a training step.

    In joint mode this combines NC loss with one stochastic Node2Vec walk loss batch.

    Args:
        batch: Training batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Training loss.
    """
    logits = self.forward(batch.x, batch.global_node_ids)
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = int(target_labels.size(0))

    if self.mode == NODE2VEC_JOINT_MODE:
        # Node2Vec.loss() is already a stochastic objective over sampled walks,
        # so one walk batch is a standard SGD estimate, not a logically different loss,
        # meaning we can optimize training by using a single walk batch per training step,
        # instead of averaging over multiple walk batches.
        positive_random_walk, negative_random_walk = next_walk_batch(
            mode=self.mode,
            encoder=self.encoder,
            batch_size=self.random_walk_batch_size,
            state=self.__walk_loader_state,
        )
        positive_random_walk = positive_random_walk.to(self.device)
        negative_random_walk = negative_random_walk.to(self.device)

        nc_loss = self.loss_fn(target_logits, target_labels)
        node2vec_loss = to_node2vec_encoder(self.encoder, self.mode).loss(
            positive_random_walk,
            negative_random_walk,
        )
        loss = nc_loss + (self.node2vec_loss_weight * node2vec_loss)

        self.log(
            stage_metric_name(Stage.TRAIN, "nc_loss"),
            nc_loss,
            prog_bar=True,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
        self.log(
            stage_metric_name(Stage.TRAIN, "node2vec_loss"),
            node2vec_loss,
            prog_bar=True,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
        self.log(
            stage_metric_name(Stage.TRAIN, "loss"),
            loss,
            prog_bar=True,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
    else:
        loss = self._compute_loss(target_logits, target_labels, batch_size, Stage.TRAIN)

    self._compute_metrics(target_logits, target_labels, batch_size, Stage.TRAIN)
    return loss

validation_step(batch, batch_idx)

Run a validation step.

Parameters:

Name Type Description Default
batch HData

Validation batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Validation loss.

Source code in hypertorch/node_classification/node2vec_nc.py
def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a validation step.

    Args:
        batch: Validation batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Validation loss.
    """
    return self.__eval_step(batch, Stage.VAL)

test_step(batch, batch_idx)

Run a test step.

Parameters:

Name Type Description Default
batch HData

Test batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Test loss.

Source code in hypertorch/node_classification/node2vec_nc.py
def test_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a test step.

    Args:
        batch: Test batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Test loss.
    """
    return self.__eval_step(batch, Stage.TEST)

predict_step(batch, batch_idx)

Predict node-class logits for a batch.

Parameters:

Name Type Description Default
batch HData

Prediction batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
logits Tensor

Predicted node-class logits.

Source code in hypertorch/node_classification/node2vec_nc.py
def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Predict node-class logits for a batch.

    Args:
        batch: Prediction batch.
        batch_idx: Batch index, unused.

    Returns:
        logits: Predicted node-class logits.
    """
    return self.forward(batch.x, batch.global_node_ids)

configure_optimizers()

Configure the optimizer.

Returns:

Name Type Description
optimizer Adam

Adam optimizer.

Source code in hypertorch/node_classification/node2vec_nc.py
def configure_optimizers(self) -> optim.Adam:
    """
    Configure the optimizer.

    Returns:
        optimizer: Adam optimizer.
    """
    return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

__eval_step(batch, stage)

Run shared evaluation logic for a stage.

Parameters:

Name Type Description Default
batch HData

Input batch.

required
stage Stage

Current evaluation stage.

required

Returns:

Name Type Description
loss Tensor

Computed loss.

Source code in hypertorch/node_classification/node2vec_nc.py
def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
    """
    Run shared evaluation logic for a stage.

    Args:
        batch: Input batch.
        stage: Current evaluation stage.

    Returns:
        loss: Computed loss.
    """
    logits = self.forward(batch.x, batch.global_node_ids)
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = int(target_labels.size(0))

    loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
    self._compute_metrics(target_logits, target_labels, batch_size, stage)
    return loss

VilLainClassifierConfig

Bases: TypedDict

Configuration for the classifier in VilLainClassifier.

Attributes:

Name Type Description
out_channels int

Number of node classes.

Source code in hypertorch/node_classification/villain_nc.py
class VilLainClassifierConfig(TypedDict):
    """
    Configuration for the classifier in ``VilLainClassifier``.

    Attributes:
        out_channels: Number of node classes.
    """

    out_channels: int

VilLainEncoderConfig

Bases: TypedDict

Configuration for the VilLain encoder in VilLainClassifier.

Attributes:

Name Type Description
num_nodes int

Total number of trainable nodes.

embedding_dim NotRequired[int]

Returned node embedding dimension. Defaults to 128.

labels_per_subspace NotRequired[int]

Number of virtual labels per subspace. Defaults to 2.

training_steps NotRequired[int]

Propagation steps used for VilLain loss. Defaults to 4.

generation_steps NotRequired[int]

Propagation steps averaged by forward. Defaults to 100.

tau NotRequired[float]

Gumbel-Softmax temperature. Defaults to 1.0.

eps NotRequired[float]

Numerical stability constant. Defaults to 1e-10.

villain_loss_weight NotRequired[float]

Weight applied to VilLain self-supervision. Defaults to 1.0.

Source code in hypertorch/node_classification/villain_nc.py
class VilLainEncoderConfig(TypedDict):
    """
    Configuration for the VilLain encoder in ``VilLainClassifier``.

    Attributes:
        num_nodes: Total number of trainable nodes.
        embedding_dim: Returned node embedding dimension. Defaults to ``128``.
        labels_per_subspace: Number of virtual labels per subspace. Defaults to ``2``.
        training_steps: Propagation steps used for VilLain loss. Defaults to ``4``.
        generation_steps: Propagation steps averaged by ``forward``. Defaults to ``100``.
        tau: Gumbel-Softmax temperature. Defaults to ``1.0``.
        eps: Numerical stability constant. Defaults to ``1e-10``.
        villain_loss_weight: Weight applied to VilLain self-supervision. Defaults to ``1.0``.
    """

    num_nodes: int
    embedding_dim: NotRequired[int]
    labels_per_subspace: NotRequired[int]
    training_steps: NotRequired[int]
    generation_steps: NotRequired[int]
    tau: NotRequired[float]
    eps: NotRequired[float]
    villain_loss_weight: NotRequired[float]

VilLainClassifier

Bases: NCClassifier

Feature-free VilLain-based NC classifier.

The module learns transductive node embeddings from the hypergraph structure with VilLain and classifies the generated embeddings with an MLP.

Attributes:

Name Type Description
encoder Module | None

VilLain encoder module inherited from NCClassifier.

classifier Module

Classifier module inherited from NCClassifier.

loss_fn Module

Loss function inherited from NCClassifier.

metrics_log_kwargs dict[str, Any]

Metric logging keyword arguments inherited from NCClassifier.

train_metrics MetricCollection | None

Optional training metrics inherited from NCClassifier.

val_metrics MetricCollection | None

Optional validation metrics inherited from NCClassifier.

test_metrics MetricCollection | None

Optional test metrics inherited from NCClassifier.

embedding_dim int

VilLain node embedding dimension.

lr float

Learning rate for the optimizer. Defaults to 0.01.

weight_decay float

L2 regularization. Defaults to 0.0.

villain_loss_weight float

Weight applied to VilLain self-supervision. Defaults to 1.0.

Source code in hypertorch/node_classification/villain_nc.py
class VilLainClassifier(NCClassifier):
    """
    Feature-free VilLain-based NC classifier.

    The module learns transductive node embeddings from the hypergraph structure with
    ``VilLain`` and classifies the generated embeddings with an MLP.

    Attributes:
        encoder: VilLain encoder module inherited from ``NCClassifier``.
        classifier: Classifier module inherited from ``NCClassifier``.
        loss_fn: Loss function inherited from ``NCClassifier``.
        metrics_log_kwargs: Metric logging keyword arguments inherited from ``NCClassifier``.
        train_metrics: Optional training metrics inherited from ``NCClassifier``.
        val_metrics: Optional validation metrics inherited from ``NCClassifier``.
        test_metrics: Optional test metrics inherited from ``NCClassifier``.
        embedding_dim: VilLain node embedding dimension.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``0.0``.
        villain_loss_weight: Weight applied to VilLain self-supervision. Defaults to ``1.0``.
    """

    def __init__(
        self,
        encoder_config: VilLainEncoderConfig,
        classifier_config: VilLainClassifierConfig,
        loss_fn: nn.Module | None = None,
        lr: float = 0.01,
        weight_decay: float = 0.0,
        metrics: MetricCollection | None = None,
        metrics_log_kwargs: dict[str, Any] | None = None,
    ) -> None:
        """
        Initialize the VilLain-based NC classifier.

        Args:
            encoder_config: Configuration for the VilLain encoder.
            classifier_config: Configuration for the classifier.
            loss_fn: Optional NC loss function. Defaults to ``CrossEntropyLoss``.
            lr: Learning rate for the optimizer. Defaults to ``0.01``.
            weight_decay: L2 regularization. Defaults to ``0.0``.
            metrics: Optional metric collection for evaluation. Defaults to ``None``.
            metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
                Useful for configuring distributed synchronization behavior
                of ``torchmetrics``. Defaults to ``None``.
        """
        self.embedding_dim: int = encoder_config.get("embedding_dim", 128)
        self.lr: float = lr
        self.weight_decay: float = weight_decay
        self.villain_loss_weight: float = encoder_config.get("villain_loss_weight", 1.0)

        encoder = VilLain(
            num_nodes=encoder_config["num_nodes"],
            embedding_dim=self.embedding_dim,
            labels_per_subspace=encoder_config.get("labels_per_subspace", 2),
            training_steps=encoder_config.get("training_steps", 4),
            generation_steps=encoder_config.get("generation_steps", 100),
            tau=encoder_config.get("tau", 1.0),
            eps=encoder_config.get("eps", 1e-10),
        )
        classifier = SLP(
            in_channels=self.embedding_dim,
            out_channels=classifier_config["out_channels"],
        )

        super().__init__(
            encoder=encoder,
            classifier=classifier,
            loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
            metrics=metrics,
            metrics_log_kwargs=metrics_log_kwargs,
        )

    def forward(
        self,
        hyperedge_index: Tensor,
        global_node_ids: Tensor | None = None,
        num_hyperedges: int | None = None,
    ) -> Tensor:
        """
        Predict node-class logits from VilLain-generated node embeddings.

        Args:
            hyperedge_index: Hyperedge incidence tensor.
            global_node_ids: Optional global node IDs for transductive embedding lookup.
                Defaults to ``None``.
            num_hyperedges: Optional explicit number of hyperedges. Defaults to ``None``.

        Returns:
            logits: Node-class logits of shape ``(num_nodes, num_classes)``.
        """
        node_embeddings = self.__to_villain_encoder().node_embeddings(
            hyperedge_index=hyperedge_index,
            node_ids=global_node_ids,
            num_hyperedges=num_hyperedges,
        )
        logits: Tensor = self.classifier(node_embeddings)
        return logits

    def training_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a training step with NC and VilLain self-supervised losses.

        Args:
            batch: Training batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Combined training loss.
        """
        logits = self.forward(
            hyperedge_index=batch.hyperedge_index,
            global_node_ids=batch.global_node_ids,
            num_hyperedges=batch.num_hyperedges,
        )
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = target_labels.size(0)

        nc_loss = self.loss_fn(target_logits, target_labels)
        villain_loss, villain_loss_parts = self.__to_villain_encoder().loss(
            hyperedge_index=batch.hyperedge_index,
            node_ids=batch.global_node_ids,
            num_hyperedges=batch.num_hyperedges,
        )
        loss = nc_loss + (self.villain_loss_weight * villain_loss)

        self.log(
            stage_metric_name(Stage.TRAIN, "nc_loss"),
            nc_loss,
            prog_bar=True,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
        self.log(
            stage_metric_name(Stage.TRAIN, "villain_loss"),
            villain_loss,
            prog_bar=True,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
        self.log(
            stage_metric_name(Stage.TRAIN, "local_loss"),
            villain_loss_parts["local_loss"],
            prog_bar=False,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
        self.log(
            stage_metric_name(Stage.TRAIN, "global_loss"),
            villain_loss_parts["global_loss"],
            prog_bar=False,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )
        self.log(
            stage_metric_name(Stage.TRAIN, "loss"),
            loss,
            prog_bar=True,
            batch_size=batch_size,
            **self.metrics_log_kwargs,
        )

        self._compute_metrics(target_logits, target_labels, batch_size, Stage.TRAIN)
        return loss

    def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a validation step.

        Args:
            batch: Validation batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Validation loss.
        """
        return self.__eval_step(batch, Stage.VAL)

    def test_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Run a test step.

        Args:
            batch: Test batch.
            batch_idx: Batch index, unused.

        Returns:
            loss: Test loss.
        """
        return self.__eval_step(batch, Stage.TEST)

    def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
        """
        Predict node-class logits for a batch.

        Args:
            batch: Prediction batch.
            batch_idx: Batch index, unused.

        Returns:
            logits: Predicted node-class logits.
        """
        return self.forward(
            hyperedge_index=batch.hyperedge_index,
            global_node_ids=batch.global_node_ids,
            num_hyperedges=batch.num_hyperedges,
        )

    def configure_optimizers(self) -> optim.Adam:
        """
        Configure the optimizer.

        Returns:
            optimizer: Adam optimizer.
        """
        return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

    def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
        """
        Run shared evaluation logic for a stage.

        Args:
            batch: Input batch.
            stage: Current evaluation stage.

        Returns:
            loss: Computed loss.
        """
        logits = self.forward(
            hyperedge_index=batch.hyperedge_index,
            global_node_ids=batch.global_node_ids,
            num_hyperedges=batch.num_hyperedges,
        )
        target_logits, target_labels = self._target_logits_and_labels(logits, batch)
        batch_size = target_labels.size(0)

        loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
        self._compute_metrics(target_logits, target_labels, batch_size, stage)
        return loss

    def __to_villain_encoder(self) -> VilLain:
        """
        Return the configured VilLain encoder.

        Returns:
            encoder: VilLain encoder instance.

        Raises:
            ValueError: If the configured encoder is missing or has the wrong type.
        """
        if self.encoder is None or not isinstance(self.encoder, VilLain):
            raise ValueError("VilLain requires a VilLain encoder, but none was provided.")
        return self.encoder

__init__(encoder_config, classifier_config, loss_fn=None, lr=0.01, weight_decay=0.0, metrics=None, metrics_log_kwargs=None)

Initialize the VilLain-based NC classifier.

Parameters:

Name Type Description Default
encoder_config VilLainEncoderConfig

Configuration for the VilLain encoder.

required
classifier_config VilLainClassifierConfig

Configuration for the classifier.

required
loss_fn Module | None

Optional NC loss function. Defaults to CrossEntropyLoss.

None
lr float

Learning rate for the optimizer. Defaults to 0.01.

0.01
weight_decay float

L2 regularization. Defaults to 0.0.

0.0
metrics MetricCollection | None

Optional metric collection for evaluation. Defaults to None.

None
metrics_log_kwargs dict[str, Any] | None

Additional keyword arguments passed to metric log calls. Useful for configuring distributed synchronization behavior of torchmetrics. Defaults to None.

None
Source code in hypertorch/node_classification/villain_nc.py
def __init__(
    self,
    encoder_config: VilLainEncoderConfig,
    classifier_config: VilLainClassifierConfig,
    loss_fn: nn.Module | None = None,
    lr: float = 0.01,
    weight_decay: float = 0.0,
    metrics: MetricCollection | None = None,
    metrics_log_kwargs: dict[str, Any] | None = None,
) -> None:
    """
    Initialize the VilLain-based NC classifier.

    Args:
        encoder_config: Configuration for the VilLain encoder.
        classifier_config: Configuration for the classifier.
        loss_fn: Optional NC loss function. Defaults to ``CrossEntropyLoss``.
        lr: Learning rate for the optimizer. Defaults to ``0.01``.
        weight_decay: L2 regularization. Defaults to ``0.0``.
        metrics: Optional metric collection for evaluation. Defaults to ``None``.
        metrics_log_kwargs: Additional keyword arguments passed to metric log calls.
            Useful for configuring distributed synchronization behavior
            of ``torchmetrics``. Defaults to ``None``.
    """
    self.embedding_dim: int = encoder_config.get("embedding_dim", 128)
    self.lr: float = lr
    self.weight_decay: float = weight_decay
    self.villain_loss_weight: float = encoder_config.get("villain_loss_weight", 1.0)

    encoder = VilLain(
        num_nodes=encoder_config["num_nodes"],
        embedding_dim=self.embedding_dim,
        labels_per_subspace=encoder_config.get("labels_per_subspace", 2),
        training_steps=encoder_config.get("training_steps", 4),
        generation_steps=encoder_config.get("generation_steps", 100),
        tau=encoder_config.get("tau", 1.0),
        eps=encoder_config.get("eps", 1e-10),
    )
    classifier = SLP(
        in_channels=self.embedding_dim,
        out_channels=classifier_config["out_channels"],
    )

    super().__init__(
        encoder=encoder,
        classifier=classifier,
        loss_fn=loss_fn if loss_fn is not None else nn.CrossEntropyLoss(),
        metrics=metrics,
        metrics_log_kwargs=metrics_log_kwargs,
    )

forward(hyperedge_index, global_node_ids=None, num_hyperedges=None)

Predict node-class logits from VilLain-generated node embeddings.

Parameters:

Name Type Description Default
hyperedge_index Tensor

Hyperedge incidence tensor.

required
global_node_ids Tensor | None

Optional global node IDs for transductive embedding lookup. Defaults to None.

None
num_hyperedges int | None

Optional explicit number of hyperedges. Defaults to None.

None

Returns:

Name Type Description
logits Tensor

Node-class logits of shape (num_nodes, num_classes).

Source code in hypertorch/node_classification/villain_nc.py
def forward(
    self,
    hyperedge_index: Tensor,
    global_node_ids: Tensor | None = None,
    num_hyperedges: int | None = None,
) -> Tensor:
    """
    Predict node-class logits from VilLain-generated node embeddings.

    Args:
        hyperedge_index: Hyperedge incidence tensor.
        global_node_ids: Optional global node IDs for transductive embedding lookup.
            Defaults to ``None``.
        num_hyperedges: Optional explicit number of hyperedges. Defaults to ``None``.

    Returns:
        logits: Node-class logits of shape ``(num_nodes, num_classes)``.
    """
    node_embeddings = self.__to_villain_encoder().node_embeddings(
        hyperedge_index=hyperedge_index,
        node_ids=global_node_ids,
        num_hyperedges=num_hyperedges,
    )
    logits: Tensor = self.classifier(node_embeddings)
    return logits

training_step(batch, batch_idx)

Run a training step with NC and VilLain self-supervised losses.

Parameters:

Name Type Description Default
batch HData

Training batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Combined training loss.

Source code in hypertorch/node_classification/villain_nc.py
def training_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a training step with NC and VilLain self-supervised losses.

    Args:
        batch: Training batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Combined training loss.
    """
    logits = self.forward(
        hyperedge_index=batch.hyperedge_index,
        global_node_ids=batch.global_node_ids,
        num_hyperedges=batch.num_hyperedges,
    )
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = target_labels.size(0)

    nc_loss = self.loss_fn(target_logits, target_labels)
    villain_loss, villain_loss_parts = self.__to_villain_encoder().loss(
        hyperedge_index=batch.hyperedge_index,
        node_ids=batch.global_node_ids,
        num_hyperedges=batch.num_hyperedges,
    )
    loss = nc_loss + (self.villain_loss_weight * villain_loss)

    self.log(
        stage_metric_name(Stage.TRAIN, "nc_loss"),
        nc_loss,
        prog_bar=True,
        batch_size=batch_size,
        **self.metrics_log_kwargs,
    )
    self.log(
        stage_metric_name(Stage.TRAIN, "villain_loss"),
        villain_loss,
        prog_bar=True,
        batch_size=batch_size,
        **self.metrics_log_kwargs,
    )
    self.log(
        stage_metric_name(Stage.TRAIN, "local_loss"),
        villain_loss_parts["local_loss"],
        prog_bar=False,
        batch_size=batch_size,
        **self.metrics_log_kwargs,
    )
    self.log(
        stage_metric_name(Stage.TRAIN, "global_loss"),
        villain_loss_parts["global_loss"],
        prog_bar=False,
        batch_size=batch_size,
        **self.metrics_log_kwargs,
    )
    self.log(
        stage_metric_name(Stage.TRAIN, "loss"),
        loss,
        prog_bar=True,
        batch_size=batch_size,
        **self.metrics_log_kwargs,
    )

    self._compute_metrics(target_logits, target_labels, batch_size, Stage.TRAIN)
    return loss

validation_step(batch, batch_idx)

Run a validation step.

Parameters:

Name Type Description Default
batch HData

Validation batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Validation loss.

Source code in hypertorch/node_classification/villain_nc.py
def validation_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a validation step.

    Args:
        batch: Validation batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Validation loss.
    """
    return self.__eval_step(batch, Stage.VAL)

test_step(batch, batch_idx)

Run a test step.

Parameters:

Name Type Description Default
batch HData

Test batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
loss Tensor

Test loss.

Source code in hypertorch/node_classification/villain_nc.py
def test_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Run a test step.

    Args:
        batch: Test batch.
        batch_idx: Batch index, unused.

    Returns:
        loss: Test loss.
    """
    return self.__eval_step(batch, Stage.TEST)

predict_step(batch, batch_idx)

Predict node-class logits for a batch.

Parameters:

Name Type Description Default
batch HData

Prediction batch.

required
batch_idx int

Batch index, unused.

required

Returns:

Name Type Description
logits Tensor

Predicted node-class logits.

Source code in hypertorch/node_classification/villain_nc.py
def predict_step(self, batch: HData, batch_idx: int) -> Tensor:
    """
    Predict node-class logits for a batch.

    Args:
        batch: Prediction batch.
        batch_idx: Batch index, unused.

    Returns:
        logits: Predicted node-class logits.
    """
    return self.forward(
        hyperedge_index=batch.hyperedge_index,
        global_node_ids=batch.global_node_ids,
        num_hyperedges=batch.num_hyperedges,
    )

configure_optimizers()

Configure the optimizer.

Returns:

Name Type Description
optimizer Adam

Adam optimizer.

Source code in hypertorch/node_classification/villain_nc.py
def configure_optimizers(self) -> optim.Adam:
    """
    Configure the optimizer.

    Returns:
        optimizer: Adam optimizer.
    """
    return optim.Adam(self.parameters(), lr=self.lr, weight_decay=self.weight_decay)

__eval_step(batch, stage)

Run shared evaluation logic for a stage.

Parameters:

Name Type Description Default
batch HData

Input batch.

required
stage Stage

Current evaluation stage.

required

Returns:

Name Type Description
loss Tensor

Computed loss.

Source code in hypertorch/node_classification/villain_nc.py
def __eval_step(self, batch: HData, stage: Stage) -> Tensor:
    """
    Run shared evaluation logic for a stage.

    Args:
        batch: Input batch.
        stage: Current evaluation stage.

    Returns:
        loss: Computed loss.
    """
    logits = self.forward(
        hyperedge_index=batch.hyperedge_index,
        global_node_ids=batch.global_node_ids,
        num_hyperedges=batch.num_hyperedges,
    )
    target_logits, target_labels = self._target_logits_and_labels(logits, batch)
    batch_size = target_labels.size(0)

    loss = self._compute_loss(target_logits, target_labels, batch_size, stage)
    self._compute_metrics(target_logits, target_labels, batch_size, stage)
    return loss

__to_villain_encoder()

Return the configured VilLain encoder.

Returns:

Name Type Description
encoder VilLain

VilLain encoder instance.

Raises:

Type Description
ValueError

If the configured encoder is missing or has the wrong type.

Source code in hypertorch/node_classification/villain_nc.py
def __to_villain_encoder(self) -> VilLain:
    """
    Return the configured VilLain encoder.

    Returns:
        encoder: VilLain encoder instance.

    Raises:
        ValueError: If the configured encoder is missing or has the wrong type.
    """
    if self.encoder is None or not isinstance(self.encoder, VilLain):
        raise ValueError("VilLain requires a VilLain encoder, but none was provided.")
    return self.encoder

Node2VecGCNNCConfig

Bases: TypedDict

Configuration for the GCN model.

Attributes:

Name Type Description
out_channels int

Dimension of the output node embeddings from the GCN layers.

hidden_channels NotRequired[int]

Dimension of the hidden node embeddings in the GCN layers.

num_layers NotRequired[int]

Number of GCN layers. Must be at least 1. Defaults to 2.

drop_rate NotRequired[float]

Dropout rate applied after each GCN layer (except the last one). Defaults to 0.0 (no dropout).

bias NotRequired[bool]

Whether to include a bias term in the GCN layers. Defaults to True.

improved NotRequired[bool]

Whether to use the improved version of GCNConv. Defaults to False.

add_self_loops NotRequired[bool]

Whether to add self-loops to the input graph. Defaults to True.

normalize NotRequired[bool]

Whether to symmetrically normalize the adjacency matrix in GCNConv. Defaults to True.

cached NotRequired[bool]

Whether to cache the normalized adjacency matrix in GCNConv. Only applicable if the graph structure does not change between epochs. Defaults to False.

graph_reduction_strategy NotRequired[GraphReductionStrategy]

Strategy for reducing the hyperedge graph. Defaults to clique_expansion.

num_nodes NotRequired[int]

Total number of nodes in the hypergraph. This is useful when setting is transductive but train dataset may not contain all hyperedges where some nodes appear, to ensure consistent encoding across splits.

activation_fn NotRequired[ActivationFn]

Activation function to use after each hidden layer. Defaults to nn.ReLU.

activation_fn_kwargs NotRequired[dict]

Keyword arguments for the activation function. Defaults to empty dict.

Source code in hypertorch/models/node2vec_common.py
class Node2VecGCNEncoderConfig(TypedDict):
    """
    Configuration for the GCN model.

    Attributes:
        out_channels: Dimension of the output node embeddings from the GCN layers.
        hidden_channels: Dimension of the hidden node embeddings in the GCN layers.
        num_layers: Number of GCN layers. Must be at least 1. Defaults to ``2``.
        drop_rate: Dropout rate applied after each GCN layer (except the last one).
            Defaults to ``0.0`` (no dropout).
        bias: Whether to include a bias term in the GCN layers. Defaults to ``True``.
        improved: Whether to use the improved version of GCNConv. Defaults to ``False``.
        add_self_loops: Whether to add self-loops to the input graph. Defaults to ``True``.
        normalize: Whether to symmetrically normalize the adjacency matrix in GCNConv.
            Defaults to ``True``.
        cached: Whether to cache the normalized adjacency matrix in GCNConv.
            Only applicable if the graph structure does not change between epochs.
            Defaults to ``False``.
        graph_reduction_strategy: Strategy for reducing the hyperedge graph.
            Defaults to ``clique_expansion``.
        num_nodes: Total number of nodes in the hypergraph. This is useful when setting is
            transductive but train dataset may not contain all hyperedges where some nodes appear,
            to ensure consistent encoding across splits.
        activation_fn: Activation function to use after each hidden layer.
            Defaults to ``nn.ReLU``.
        activation_fn_kwargs: Keyword arguments for the activation function.
            Defaults to empty dict.
    """

    out_channels: int
    hidden_channels: NotRequired[int]
    num_layers: NotRequired[int]
    drop_rate: NotRequired[float]
    bias: NotRequired[bool]
    improved: NotRequired[bool]
    add_self_loops: NotRequired[bool]
    normalize: NotRequired[bool]
    cached: NotRequired[bool]
    graph_reduction_strategy: NotRequired[GraphReductionStrategy]
    num_nodes: NotRequired[int]
    activation_fn: NotRequired[ActivationFn]
    activation_fn_kwargs: NotRequired[dict]

Node2VecNCConfig

Bases: TypedDict

Configuration for the Node2Vec encoder.

Attributes:

Name Type Description
context_size NotRequired[int]

Skip-gram context size for Node2Vec. For example, if context_size=2 and walk_length=5, then for a random walk [v0, v1, v2, v3, v4], the context for v2 would be [v0, v1, v3, v4] as we take neighbors within distance 2 in the walk. The pairs generated by skip-gram would be [(v2, v0), (v2, v1), (v2, v3), (v2, v4)]. Rule of thumb: Graphs with strong local structure (5-10), Graphs with communities/long-range patterns (10-20). Defaults to 10.

walk_length NotRequired[int]

Length of each random walk.

num_walks_per_node NotRequired[int]

Number of walks sampled per node.

p NotRequired[float]

Node2Vec return parameter. Controls the probability of stepping back to the node visited in the previous step. Lower values of p make immediate backtracking more likely, while higher values discourage returning to the previous node.

q NotRequired[float]

Node2Vec in-out parameter. Controls whether walks stay near the source node or explore further outward. Lower values of q bias the walk toward DFS-like exploration and structural similarity, while higher values bias it toward BFS-like exploration and local community structure and homophily.

num_negative_samples NotRequired[int]

Number of negative samples per positive walk context. If set to X, then for each positive pair (u, v) generated from the random walks, X negative pairs (u, v_neg) will be generated, where v_neg is a node sampled uniformly at random from all nodes in the graph. Defaults to 1, meaning one negative sample per positive pair.

num_nodes NotRequired[int]

Number of nodes in the stable node space. Defaults to the number of nodes in the hyperedge_index if not provided.

train_hyperedge_index NotRequired[Tensor]

Training hypereddge index used to build the Node2Vec walk graph. Required in joint mode.

graph_reduction_strategy NotRequired[GraphReductionStrategy]

Strategy for reducing the hyperedge graph. Defaults to clique_expansion.

random_walk_batch_size NotRequired[int]

Batch size used by the walk sampler in joint mode.

node2vec_loss_weight NotRequired[float]

Weight applied to the Node2Vec walk loss in joint mode. This is to decide how much the loss of Node2Vec contributes to the overall loss in joint training, relative to the task loss. Defaults to 1.0 (equal weighting). Set to a higher value to prioritize learning good node embeddings, or a lower value to prioritize the task loss. Ignored in precomputed mode.

sparse NotRequired[bool]

Whether to use sparse gradients in the Node2Vec encoder. Defaults to False.

Source code in hypertorch/models/node2vec_common.py
class Node2VecEncoderConfig(TypedDict):
    """
    Configuration for the Node2Vec encoder.

    Attributes:
        context_size: Skip-gram context size for Node2Vec.
            For example, if ``context_size=2`` and ``walk_length=5``, then for a
            random walk ``[v0, v1, v2, v3, v4]``,
            the context for ``v2`` would be ``[v0, v1, v3, v4]`` as we take neighbors within
            distance 2 in the walk.
            The pairs generated by skip-gram would be ``[(v2, v0), (v2, v1), (v2, v3), (v2, v4)]``.
            Rule of thumb: Graphs with strong local structure (5-10), Graphs with
            communities/long-range patterns (10-20).
            Defaults to ``10``.
        walk_length: Length of each random walk.
        num_walks_per_node: Number of walks sampled per node.
        p: Node2Vec return parameter. Controls the probability of stepping back to the node visited
            in the previous step. Lower values of ``p`` make immediate backtracking more likely,
            while higher values discourage returning to the previous node.
        q: Node2Vec in-out parameter. Controls whether walks stay near the source node or explore
            further outward. Lower values of ``q`` bias the walk toward DFS-like exploration and
            structural similarity, while higher values bias it toward BFS-like exploration and
            local community structure and homophily.
        num_negative_samples: Number of negative samples per positive walk context.
            If set to ``X``, then for each positive pair ``(u, v)`` generated from the random walks,
            ``X`` negative pairs ``(u, v_neg)`` will be generated,
            where ``v_neg`` is a node sampled uniformly at random from all nodes in the graph.
            Defaults to ``1``, meaning one negative sample per positive pair.
        num_nodes: Number of nodes in the stable node space. Defaults to the number of nodes
            in the ``hyperedge_index`` if not provided.
        train_hyperedge_index: Training hypereddge index used to build the Node2Vec walk graph.
            Required in ``joint`` mode.
        graph_reduction_strategy: Strategy for reducing the hyperedge graph.
            Defaults to ``clique_expansion``.
        random_walk_batch_size: Batch size used by the walk sampler in joint mode.
        node2vec_loss_weight: Weight applied to the Node2Vec walk loss in joint mode.
            This is to decide how much the loss of Node2Vec contributes to the overall loss in
            joint training, relative to the task loss.
            Defaults to ``1.0`` (equal weighting). Set to a higher value to prioritize learning
            good node embeddings, or a lower value to prioritize the task loss.
            Ignored in precomputed mode.
        sparse: Whether to use sparse gradients in the Node2Vec encoder. Defaults to ``False``.
    """

    context_size: NotRequired[int]
    walk_length: NotRequired[int]
    num_walks_per_node: NotRequired[int]
    p: NotRequired[float]
    q: NotRequired[float]
    num_negative_samples: NotRequired[int]
    num_nodes: NotRequired[int]
    train_hyperedge_index: NotRequired[Tensor]
    graph_reduction_strategy: NotRequired[GraphReductionStrategy]
    random_walk_batch_size: NotRequired[int]
    node2vec_loss_weight: NotRequired[float]
    sparse: NotRequired[bool]