Skip to content

Backends

edge2torch can compile the same architecture edgelist into different backend-specific sparse PyTorch model classes.

Each backend answers a slightly different question:

  • how should graph structure be translated into neural-network computation?
  • which graph properties are allowed?
  • what internal execution structure should be created?

The goal of edge2torch is to stay minimally opinionated. A backend defines only the structural semantics required for compilation. Broader modeling choices such as activations, heads, losses, optimizers, and training loops remain the user's responsibility.

Overview

The currently implemented backends are:

  • feedforward
  • recurrent
  • graphnn

All three backends share the same high-level interface:

  • they are created with compile_graph(...)
  • they return a normal PyTorch nn.Module
  • they return a CompileArtifact that preserves information needed for alignment, inspection, and interpretation

Across all backends, input and output nodes are inferred from graph structure:

  • input nodes are nodes with no incoming edges
  • output nodes are nodes with no outgoing edges

The current implementation enforces sparse graph-derived connectivity with masked dense PyTorch layers. These masks constrain trainable edge weights: a source-to-target weighted connection can contribute only where the compiled graph contains the corresponding directed edge.

Compiled layers include bias terms by default. Biases are node-level offsets, not graph edges, and are not constrained by the edge mask. Set bias=False in compile_graph() to remove these offsets so node updates depend only on graph-defined weighted inputs.

The use of masked dense layers should not be interpreted as sparse tensor acceleration, which is planned as a future addition.

Common input format

All backends currently start from the same edgelist representation.

The edgelist must contain two required columns:

  • source
  • target

For example:

import pandas as pd

edgelist = pd.DataFrame(
    {
        "source": ["feature_a", "feature_b", "hidden"],
        "target": ["hidden", "hidden", "prediction"],
    }
)

Each row defines a directed edge from one named node to another. The edgelist may come from domain knowledge, a manually designed sparse architecture, a discovered graph, or any other source that can be represented as directed connections between named nodes.

The backend changes the compiled execution semantics, not the graph input format.

Feedforward backend

Meaning

The feedforward backend compiles the graph into a strictly layer-wise sparse PyTorch model.

This backend assumes that the graph can be organized into successive layers. If the graph contains skip edges, these are expanded internally using pseudo nodes so that the final compiled computation remains strictly adjacent layer-to-layer.

Structural properties

The feedforward backend:

  • expects an acyclic, layerable directed graph
  • compiles computation into successive layer blocks
  • uses masks to enforce graph-derived connectivity between adjacent layers
  • expands skip edges internally through pseudo nodes when needed

Internal execution pattern

Conceptually, the feedforward backend behaves like a sparse multilayer perceptron whose connectivity pattern is derived from the edgelist.

The compiled model contains one computation block per adjacent layer pair. Each block applies a masked linear transformation so that only graph-defined weighted connections contribute through edge weights. If bias=True, target nodes may also have learned node-level offsets. Set bias=False to remove these offsets.

Pseudo nodes

Pseudo nodes are internal compiler-generated nodes used by the feedforward backend to represent skip edges in a strictly layer-wise form.

They are stored in the compilation artifact for internal bookkeeping, but they are hidden from user-facing node attribution outputs. User-facing node interpretation reports named graph nodes rather than compiler-generated pseudo nodes.

When to use it

Use feedforward when:

  • the graph is naturally hierarchical or approximately hierarchical
  • you want a sparse layered architecture

Recurrent backend

Meaning

The recurrent backend compiles the graph into a recurrent node-state model.

Instead of layering the graph into a sequence of feedforward blocks, this backend keeps the original graph topology and applies repeated state updates over the graph for a configurable number of steps.

Structural properties

The recurrent backend:

  • allows cyclic graphs
  • keeps the original graph topology
  • requires at least one inferred input node
  • requires at least one inferred output node
  • requires every node that can influence an output node to be reachable from at least one inferred input node
  • updates node states repeatedly over multiple steps
  • uses masks to enforce graph-defined recurrent connectivity
  • re-injects input-node values after each recurrent update step

Cycles are allowed, but disconnected components that can influence an output are rejected because their contributions cannot depend on the provided input features.

Internal execution pattern

Conceptually, the recurrent backend behaves like a sparse recurrent neural system over graph nodes.

Each node has a position in a global node-state vector. At each step, the model updates node states using the graph-defined connectivity mask. Input nodes are then re-injected so that external inputs remain anchored across recurrent updates.

The steps argument to compile_graph() controls how many recurrent update steps are applied during each forward pass. It is not a training epoch count and does not represent a sequence length in the input data.

Pseudo nodes

Pseudo nodes are not used by the recurrent backend.

They are not required by the current recurrent compilation strategy because the backend does not need to force computation into adjacent feedforward layers.

When to use it

Use recurrent when:

  • the graph contains cycles
  • repeated state updates are a natural representation of the system
  • you want a graph-structured recurrent model rather than a layered one

GraphNN backend

Meaning

The graphnn backend compiles the graph into a minimal graph-oriented state-update model over named node states.

Like the recurrent backend, it keeps the original graph topology instead of forcing the graph into a layer-wise feedforward structure. In the current implementation, graphnn is intentionally close to recurrent: both use a single node-state vector, masked dense updates, configurable fixed-step iteration, and input-node re-injection.

The graphnn backend should therefore be understood as a lightweight message-passing-style interface and extension point, not as a full-featured graph neural network library backend.

Structural properties

The graphnn backend:

  • allows cyclic or non-layerable graphs
  • keeps the original graph structure
  • requires at least one inferred input node
  • requires at least one inferred output node
  • requires every node that can influence an output node to be reachable from at least one inferred input node
  • performs repeated graph-defined node-state updates
  • uses masks to enforce graph-derived connectivity
  • re-injects input-node values after each update step
  • currently uses the same minimal masked-update primitive as the recurrent backend

Cycles are allowed, but disconnected components that can influence an output are rejected because their contributions cannot depend on the provided input features.

Internal execution pattern

Conceptually, the current graphnn backend applies a configurable number of message-passing-style updates over scalar node states.

It provides a conservative graph-oriented backend that fits the same compile/train/interpret interface as the other backends, while leaving room for future backend-specific extensions such as richer message functions, aggregation choices, normalization, residual updates, or edge features.

The steps argument to compile_graph() controls how many graph update steps are applied during each forward pass. It is not a training epoch count and does not represent a sequence length in the input data.

Pseudo nodes

Pseudo nodes are not used by the graphnn backend.

GraphNN-style models operate directly on the original graph topology, so pseudo-node expansion is not used as a default mechanism for this backend.

When to use it

Use graphnn when:

  • you want to preserve the original graph topology
  • the graph is not naturally feedforward
  • you want a minimal graph-oriented state-update backend
  • you want a backend that can serve as a future extension point for message-passing-style models

Summary of backend behavior

Backend Layered execution Cycles allowed Pseudo nodes Main internal idea
feedforward yes no yes sparse layer-wise computation
recurrent no yes no sparse recurrent node-state updates
graphnn no yes no minimal message-passing-style node updates

Interpretation support

Node and feature interpretation are available for all implemented backends.

Backend Feature attribution Node attribution
feedforward yes yes
recurrent yes yes
graphnn yes yes

Feature attribution is available through feature-level Captum methods such as IntegratedGradients, Saliency, and DeepLift.

Node attribution is available through layer-level Captum methods such as LayerConductance and LayerIntegratedGradients.

Interpretation sites

Node attribution is computed at interpretation sites inside the compiled model:

  • feedforward: one site per non-input layer (layer_1, layer_2, ...)
  • recurrent and graphnn: one site per unrolled state-update step (step_1, step_2, ...)

Pseudo nodes used internally by the feedforward backend are never exposed in user-facing node interpretation output.

Summary vs per-site node results

interpret_model(..., target="nodes") supports two detail levels:

level Return type Meaning
"summary" (default) pandas.DataFrame One node-importance table per sample
"sites" dict[str, pandas.DataFrame] One table per interpretation site

Use the nodes parameter to filter which graph nodes appear in the result:

nodes Included nodes
"hidden" (default) Internal graph nodes only
"non_input" All nodes except inputs (includes outputs)
"all" All visible graph nodes

For recurrent and graphnn backends, summary results aggregate repeated node columns across steps. Control this with site_aggregation:

site_aggregation Behavior
"max_abs" (default) Keep the step value with largest absolute magnitude
"mean_abs" Average absolute values across steps
"last" Use the final step only

Feedforward summary results merge disjoint site columns. site_aggregation is ignored for feedforward summary output and for level="sites".

Models returned by customize_model() support node interpretation when the wrapped compiled model remains accessible for interpretation-site lookup. Adding a custom output head can change output dimensionality and may require Captum attribute_kwargs such as target for multi-output graphs.

See Scope and limitations for what each backend is designed to cover.