diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json
index d90bb8b24..333fdb83d 100644
--- a/dev/.documenter-siteinfo.json
+++ b/dev/.documenter-siteinfo.json
@@ -1 +1 @@
-{"documenter":{"julia_version":"1.10.4","generation_timestamp":"2024-08-19T14:14:14","documenter_version":"1.5.0"}}
\ No newline at end of file
+{"documenter":{"julia_version":"1.10.4","generation_timestamp":"2024-08-21T07:19:57","documenter_version":"1.6.0"}}
\ No newline at end of file
diff --git a/dev/api/basic/index.html b/dev/api/basic/index.html
index 9b3df3afb..d26d5647f 100644
--- a/dev/api/basic/index.html
+++ b/dev/api/basic/index.html
@@ -1,5 +1,5 @@
-
Collects multiple layers / functions to be called in sequence on given input graph and input node features.
It allows to compose layers in a sequential fashion as Flux.Chain does, propagating the output of each layer to the next one. In addition, GNNChain handles the input graph as well, providing it as a first argument only to layers subtyping the GNNLayer abstract type.
GNNChain supports indexing and slicing, m[2] or m[1:end-1], and if names are given, m[:name] == m[1] etc.
A type wrapping the model and tying it to the graph g. In the forward pass, can only take feature arrays as inputs, returning model(g, x...; kws...).
If traingraph=false, the graph's parameters won't be part of the trainable parameters in the gradient updates.
Examples
g = GNNGraph([1,2,3], [2,3,1])
x = rand(Float32, 2, 3)
model = SAGEConv(2 => 3)
wg = WithGraph(model, g)
@@ -51,4 +51,4 @@
g2 = GNNGraph([1,1,2,3], [2,4,1,1])
x2 = rand(Float32, 2, 4)
# WithGraph will ignore the internal graph if fed with a new one.
-@assert wg(g2, x2) == model(g2, x2)
Many different types of graphs convolutional layers have been proposed in the literature. Choosing the right layer for your application could involve a lot of exploration. Some of the most commonly used layers are the GCNConv and the GATv2Conv. Multiple graph convolutional layers are typically stacked together to create a graph neural network model (see GNNChain).
The table below lists all graph convolutional layers implemented in the GraphNeuralNetworks.jl. It also highlights the presence of some additional capabilities with respect to basic message passing:
Sparse Ops: implements message passing as multiplication by sparse adjacency matrix instead of the gather/scatter mechanism. This can lead to better CPU performances but it is not supported on GPU yet.
Heterograph: supports heterogeneous graphs (see GNNHeteroGraph).
TemporalSnapshotsGNNGraphs: supports temporal graphs (see TemporalSnapshotsGNNGraph) by applying the convolution layers to each snapshot independently.
Many different types of graphs convolutional layers have been proposed in the literature. Choosing the right layer for your application could involve a lot of exploration. Some of the most commonly used layers are the GCNConv and the GATv2Conv. Multiple graph convolutional layers are typically stacked together to create a graph neural network model (see GNNChain).
The table below lists all graph convolutional layers implemented in the GraphNeuralNetworks.jl. It also highlights the presence of some additional capabilities with respect to basic message passing:
Sparse Ops: implements message passing as multiplication by sparse adjacency matrix instead of the gather/scatter mechanism. This can lead to better CPU performances but it is not supported on GPU yet.
Heterograph: supports heterogeneous graphs (see GNNHeteroGraph).
TemporalSnapshotsGNNGraphs: supports temporal graphs (see TemporalSnapshotsGNNGraph) by applying the convolution layers to each snapshot independently.
where $\mathbf{z}_{ij}$ is the node and edge features concatenation $[\mathbf{x}_i; \mathbf{x}_j; \mathbf{e}_{j\to i}]$ and $\sigma$ is the sigmoid function. The residual $\mathbf{x}_i$ is added only if residual=true and the output size is the same as the input size.
Arguments
in: The dimension of input node features.
ein: The dimension of input edge features.
If ein is not given, assumes that no edge features are passed as input in the forward pass.
out: The dimension of output node features.
act: Activation function.
bias: Add learnable bias.
init: Weights' initializer.
residual: Add a residual connection.
Examples
g = rand_graph(5, 6)
x = rand(Float32, 2, g.num_nodes)
e = rand(Float32, 3, g.num_edges)
@@ -20,7 +20,7 @@
# No edge features
l = CGConv(2 => 4, tanh)
-y = l(g, x) # size: (4, num_nodes)
add_self_loops: Add self loops to the graph before performing the convolution. Default false.
use_edge_weight: If true, consider the edge weights in the input graph (if available). If add_self_loops=true the new weights will be set to 1. This option is ignored if the edge_weight is explicitly provided in the forward pass. Default false.
Takes as input a graph g, a node feature matrix x of size [in, num_nodes], and optionally an edge weight vector. Returns a node feature matrix of size [out, num_nodes].
The norm_fn parameter allows for custom normalization of the graph convolution operation by passing a function as argument. By default, it computes $\frac{1}{\sqrt{d}}$ i.e the inverse square root of the degree (d) of each node in the graph. If conv_weight is an AbstractMatrix of size [out, in], then the convolution is performed using that weight matrix instead of the weights stored in the model.
add_self_loops: Add self loops to the graph before performing the convolution. Default false.
use_edge_weight: If true, consider the edge weights in the input graph (if available). If add_self_loops=true the new weights will be set to 1. This option is ignored if the edge_weight is explicitly provided in the forward pass. Default false.
Takes as input a graph g, a node feature matrix x of size [in, num_nodes], and optionally an edge weight vector. Returns a node feature matrix of size [out, num_nodes].
The norm_fn parameter allows for custom normalization of the graph convolution operation by passing a function as argument. By default, it computes $\frac{1}{\sqrt{d}}$ i.e the inverse square root of the degree (d) of each node in the graph. If conv_weight is an AbstractMatrix of size [out, in], then the convolution is performed using that weight matrix instead of the weights stored in the model.
Examples
# create data
s = [1,1,2,3]
t = [2,3,1,1]
g = GNNGraph(s, t)
@@ -113,7 +113,7 @@
# Edge weights can also be embedded in the graph.
g = GNNGraph(s, t, w)
l = GCNConv(3 => 5, use_edge_weight=true)
-y = l(g, x) # same as l(g, x, w)
$\Theta_k, \mu^a_k, (\Sigma^{-1})^a_k$ are learnable parameters.
The input to the layer is a node feature array x of size (num_features, num_nodes) and edge pseudo-coordinate array e of size (num_features, num_edges) The residual $\mathbf{x}_i$ is added only if residual=true and the output size is the same as the input size.
$\Theta_k, \mu^a_k, (\Sigma^{-1})^a_k$ are learnable parameters.
The input to the layer is a node feature array x of size (num_features, num_nodes) and edge pseudo-coordinate array e of size (num_features, num_edges) The residual $\mathbf{x}_i$ is added only if residual=true and the output size is the same as the input size.
where $\mathbf{h}^{(l)}_i$ denotes the $l$-th hidden variables passing through GRU. The dimension of input $\mathbf{x}_i$ needs to be less or equal to out.
Arguments
out: The dimension of output features.
num_layers: The number of recursion steps.
aggr: Aggregation operator for the incoming messages (e.g. +, *, max, min, and mean).
init: Weight initialization function.
Examples:
# create data
@@ -153,7 +153,7 @@
l = GatedGraphConv(out_channel, num_layers)
# forward pass
-y = l(g, x)
\[\mathbf{x}_i' = W \mathbf{x}_i + \square_{j \in N(i)} f_\Theta(\mathbf{e}_{j\to i})\,\mathbf{x}_j\]
where $f_\Theta$ denotes a learnable function (e.g. a linear layer or a multi-layer perceptron). Given an input of batched edge features e of size (num_edge_features, num_edges), the function f will return an batched matrices array whose size is (out, in, num_edges). For convenience, also functions returning a single (out*in, num_edges) matrix are allowed.
Arguments
in: The dimension of input features.
out: The dimension of output features.
f: A (possibly learnable) function acting on edge features.
aggr: Aggregation operator for the incoming messages (e.g. +, *, max, min, and mean).
\[\mathbf{x}_i' = W \mathbf{x}_i + \square_{j \in N(i)} f_\Theta(\mathbf{e}_{j\to i})\,\mathbf{x}_j\]
where $f_\Theta$ denotes a learnable function (e.g. a linear layer or a multi-layer perceptron). Given an input of batched edge features e of size (num_edge_features, num_edges), the function f will return an batched matrices array whose size is (out, in, num_edges). For convenience, also functions returning a single (out*in, num_edges) matrix are allowed.
Arguments
in: The dimension of input features.
out: The dimension of output features.
f: A (possibly learnable) function acting on edge features.
aggr: Aggregation operator for the incoming messages (e.g. +, *, max, min, and mean).
σ: Activation function.
bias: Add learnable bias.
init: Weights' initializer.
Examples:
# create data
s = [1,1,2,3]
t = [2,3,1,1]
in_channel = 3
@@ -188,7 +188,7 @@
l = NNConv(in_channel => out_channel, nn, tanh, bias = true, aggr = +)
# forward pass
-y = l(g, x)
add_self_loops: Add self loops to the graph before performing the convolution. Default false.
use_edge_weight: If true, consider the edge weights in the input graph (if available). If add_self_loops=true the new weights will be set to 1. Default false.
add_self_loops: Add self loops to the graph before performing the convolution. Default false.
use_edge_weight: If true, consider the edge weights in the input graph (if available). If add_self_loops=true the new weights will be set to 1. Default false.
Examples
# create data
s = [1,1,2,3]
t = [2,3,1,1]
g = GNNGraph(s, t)
@@ -229,7 +229,7 @@
# Edge weights can also be embedded in the graph.
g = GNNGraph(s, t, w)
l = SGConv(3 => 5, add_self_loops = true, use_edge_weight=true)
-y = l(g, x) # same as l(g, x, w)
TAGConv layer from Topology Adaptive Graph Convolutional Networks. This layer extends the idea of graph convolutions by applying filters that adapt to the topology of the data. It performs the operation:
\[H^{K} = {\sum}_{k=0}^K (D^{-1/2} A D^{-1/2})^{k} X {\Theta}_{k}\]
where A is the adjacency matrix of the graph, D is the degree matrix, X is the input feature matrix, and ${\Theta}_{k}$ is a unique weight matrix for each hop k.
Arguments
in: Number of input features.
out: Number of output features.
k: Maximum number of hops to consider. Default is 3.
bias: Whether to include a learnable bias term. Default is true.
init: Initialization function for the weights. Default is glorot_uniform.
add_self_loops: Whether to add self-loops to the adjacency matrix. Default is true.
use_edge_weight: If true, edge weights are considered in the computation (if available). Default is false.
Examples
# Example graph data
+y = l(g, x) # same as l(g, x, w)
TAGConv layer from Topology Adaptive Graph Convolutional Networks. This layer extends the idea of graph convolutions by applying filters that adapt to the topology of the data. It performs the operation:
\[H^{K} = {\sum}_{k=0}^K (D^{-1/2} A D^{-1/2})^{k} X {\Theta}_{k}\]
where A is the adjacency matrix of the graph, D is the degree matrix, X is the input feature matrix, and ${\Theta}_{k}$ is a unique weight matrix for each hop k.
Arguments
in: Number of input features.
out: Number of output features.
k: Maximum number of hops to consider. Default is 3.
bias: Whether to include a learnable bias term. Default is true.
init: Initialization function for the weights. Default is glorot_uniform.
add_self_loops: Whether to add self-loops to the adjacency matrix. Default is true.
use_edge_weight: If true, edge weights are considered in the computation (if available). Default is false.
Examples
# Example graph data
s = [1, 1, 2, 3]
t = [2, 3, 1, 1]
g = GNNGraph(s, t) # Create a graph
@@ -239,7 +239,7 @@
l = TAGConv(3 => 5, k=3; add_self_loops=true)
# Apply the TAGConv layer
-y = l(g, x) # Output size: 5 × num_nodes
add_self_loops: Add self loops to the input graph. Default false.
bias_qkv: If set, bias is used in the key, query and value transformations for nodes. Default true.
bias_root: If set, the layer will also learn an additive bias for the root when root weight is used. Default true.
root_weight: If set, the layer will add the transformed root node features to the output. Default true.
gating: If set, will combine aggregation and transformed root node features by a gating mechanism. Default false.
skip_connection: If set, a skip connection will be made from the input and added to the output. Default false.
batch_norm: If set, a batch normalization will be applied to the output. Default false.
ff_channels: If positive, a feed-forward NN is appended, with the first having the given number of hidden nodes; this NN also gets a skip connection and batch normalization if the respective parameters are set. Default: 0.
Examples
N, in_channel, out_channel = 4, 3, 5
@@ -248,4 +248,4 @@
l = TransformerConv((in_channel, ein) => in_channel; heads, gating = true, bias_qkv = true)
x = rand(Float32, in_channel, N)
e = rand(Float32, ein, g.num_edges)
-l(g, x, e)
Documentation page for the graph type GNNGraph provided by GraphNeuralNetworks.jl and related methods.
Besides the methods documented here, one can rely on the large set of functionalities given by Graphs.jl thanks to the fact that GNNGraph inherits from Graphs.AbstractGraph.
Documentation page for the graph type GNNGraph provided by GraphNeuralNetworks.jl and related methods.
Besides the methods documented here, one can rely on the large set of functionalities given by Graphs.jl thanks to the fact that GNNGraph inherits from Graphs.AbstractGraph.
A type representing a graph structure that also stores feature arrays associated to nodes, edges, and the graph itself.
The feature arrays are stored in the fields ndata, edata, and gdata as DataStore objects offering a convenient dictionary-like and namedtuple-like interface. The features can be passed at construction time or added later.
A GNNGraph can be constructed out of different data objects expressing the connections inside the graph. The internal representation type is determined by graph_type.
When constructed from another GNNGraph, the internal graph representation is preserved and shared. The node/edge/graph features are retained as well, unless explicitely set by the keyword arguments ndata, edata, and gdata.
A GNNGraph can also represent multiple graphs batched togheter (see MLUtils.batch or SparseArrays.blockdiag). The field g.graph_indicator contains the graph membership of each node.
GNNGraphs are always directed graphs, therefore each edge is defined by a source node and a target node (see edge_index). Self loops (edges connecting a node to itself) and multiple edges (more than one edge between the same pair of nodes) are supported.
A GNNGraph is a Graphs.jl's AbstractGraph, therefore it supports most functionality from that library.
Arguments
data: Some data representing the graph topology. Possible type are
An adjacency matrix
An adjacency list.
A tuple containing the source and target vectors (COO representation)
A Graphs.jl' graph.
graph_type: A keyword argument that specifies the underlying representation used by the GNNGraph. Currently supported values are
:coo. Graph represented as a tuple (source, target), such that the k-th edge connects the node source[k] to node target[k]. Optionally, also edge weights can be given: (source, target, weights).
:sparse. A sparse adjacency matrix representation.
:dense. A dense adjacency matrix representation.
Defaults to :coo, currently the most supported type.
dir: The assumed edge direction when given adjacency matrix or adjacency list input data g. Possible values are :out and :in. Default :out.
num_nodes: The number of nodes. If not specified, inferred from g. Default nothing.
graph_indicator: For batched graphs, a vector containing the graph assignment of each node. Default nothing.
ndata: Node features. An array or named tuple of arrays whose last dimension has size num_nodes.
edata: Edge features. An array or named tuple of arrays whose last dimension has size num_edges.
gdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs.
Examples
using GraphNeuralNetworks
# Construct from adjacency list representation
@@ -35,7 +35,7 @@
# Both source and target are vectors of length num_edges
source, target = edge_index(g)
A GNNGraph can be sent to the GPU using e.g. Flux's gpu function:
Create a copy of g. If deep is true, then copy will be a deep copy (equivalent to deepcopy(g)), otherwise it will be a shallow copy with the same underlying graph data.
Create a copy of g. If deep is true, then copy will be a deep copy (equivalent to deepcopy(g)), otherwise it will be a shallow copy with the same underlying graph data.
Return the adjacency list representation (a vector of vectors) of the graph g.
Calling a the adjacency list, if dir=:out than a[i] will contain the neighbors of node i through outgoing edges. If dir=:in, it will contain neighbors from incoming edges instead.
If nodes is given, return the neighborhood of the nodes in nodes only.
Return a vector containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph. If edges=true, return the graph membership of each edge instead.
Return a Dict of vectors containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph for each node type. If node_t is provided, return the graph membership of each node of type node_t instead.
If dir=:out, A[i,j] > 0 denotes the presence of an edge from node i to node j. If dir=:in instead, A[i,j] > 0 denotes the presence of an edge from node j to node i.
User may specify the eltype T of the returned matrix.
If weighted=true, the A will contain the edge weights if any, otherwise the elements of A will be either 0 or 1.
Return a vector containing the degrees of the nodes in g.
The gradient is propagated through this function only if edge_weight is true or a vector.
Arguments
g: A graph.
T: Element type of the returned vector. If nothing, is chosen based on the graph type and will be an integer if edge_weight = false. Default nothing.
dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two.
edge_weight: If true and the graph contains weighted edges, the degree will be weighted. Set to false instead to just count the number of outgoing/ingoing edges. Finally, you can also pass a vector of weights to be used instead of the graph's own weights. Default true.
degree(g::GNNHeteroGraph, edge_type::EType; dir = :in)
Return a vector containing the degrees of the nodes in g GNNHeteroGraph given edge_type.
Arguments
g: A graph.
edge_type: A tuple of symbols (source_t, edge_t, target_t) representing the edge type.
T: Element type of the returned vector. If nothing, is chosen based on the graph type. Default nothing.
dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two. Default dir = :out.
Return the neighbors of node i in the graph g. If dir=:out, return the neighbors through outgoing edges. If dir=:in, return the neighbors through incoming edges.
Return the adjacency list representation (a vector of vectors) of the graph g.
Calling a the adjacency list, if dir=:out than a[i] will contain the neighbors of node i through outgoing edges. If dir=:in, it will contain neighbors from incoming edges instead.
If nodes is given, return the neighborhood of the nodes in nodes only.
Return a vector containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph. If edges=true, return the graph membership of each edge instead.
Return a Dict of vectors containing the graph membership (an integer from 1 to g.num_graphs) of each node in the graph for each node type. If node_t is provided, return the graph membership of each node of type node_t instead.
If dir=:out, A[i,j] > 0 denotes the presence of an edge from node i to node j. If dir=:in instead, A[i,j] > 0 denotes the presence of an edge from node j to node i.
User may specify the eltype T of the returned matrix.
If weighted=true, the A will contain the edge weights if any, otherwise the elements of A will be either 0 or 1.
Return a vector containing the degrees of the nodes in g.
The gradient is propagated through this function only if edge_weight is true or a vector.
Arguments
g: A graph.
T: Element type of the returned vector. If nothing, is chosen based on the graph type and will be an integer if edge_weight = false. Default nothing.
dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two.
edge_weight: If true and the graph contains weighted edges, the degree will be weighted. Set to false instead to just count the number of outgoing/ingoing edges. Finally, you can also pass a vector of weights to be used instead of the graph's own weights. Default true.
degree(g::GNNHeteroGraph, edge_type::EType; dir = :in)
Return a vector containing the degrees of the nodes in g GNNHeteroGraph given edge_type.
Arguments
g: A graph.
edge_type: A tuple of symbols (source_t, edge_t, target_t) representing the edge type.
T: Element type of the returned vector. If nothing, is chosen based on the graph type. Default nothing.
dir: For dir = :out the degree of a node is counted based on the outgoing edges. For dir = :in, the ingoing edges are used. If dir = :both we have the sum of the two. Default dir = :out.
Return the neighbors of node i in the graph g. If dir=:out, return the neighbors through outgoing edges. If dir=:in, return the neighbors through incoming edges.
Add to graph g the edges with source nodes s and target nodes t. Optionally, pass the edge weight w and the features edata for the new edges. Returns a new graph sharing part of the underlying data with g.
If the s or t contain nodes that are not already present in the graph, they are added to the graph as well.
Add to heterograph g edges of type edge_t with source node vector s and target node vector t. Optionally, pass the edge weights w or the features edata for the new edges. edge_t is a triplet of symbols (src_t, rel_t, dst_t).
If the edge type is not already present in the graph, it is added. If it involves new node types, they are added to the graph as well. In this case, a dictionary or named tuple of num_nodes can be passed to specify the number of nodes of the new types, otherwise the number of nodes is inferred from the maximum node id in s and t.
If the source node type is the same as the destination node type in edge_t, return a graph with the same features as g but also add self-loops of the specified type, edge_t. Otherwise, it returns g unchanged.
Nodes with already existing self-loops of type edge_t will obtain a second set of self-loops of the same type.
If the graph has edge weights for edges of type edge_t, the new edges will have weight 1.
If no edges of type edge_t exist, or all existing edges have no weight, then all new self loops will have no weight.
If edge_t is not passed as argument, for the entire graph self-loop is added to each node for every edge type in the graph where the source and destination node types are the same. This iterates over all edge types present in the graph, applying the self-loop addition logic to each applicable edge type.
Return the subgraph of g induced by those nodes j for which g.graph_indicator[j] == i or, if i is a collection, g.graph_indicator[j] ∈ i. In other words, it extract the component graphs from a batched graph.
If nmap=true, return also a vector v mapping the new nodes to the old ones. The node i in the subgraph will correspond to the node v[i] in g.
Add to heterograph g edges of type edge_t with source node vector s and target node vector t. Optionally, pass the edge weights w or the features edata for the new edges. edge_t is a triplet of symbols (src_t, rel_t, dst_t).
If the edge type is not already present in the graph, it is added. If it involves new node types, they are added to the graph as well. In this case, a dictionary or named tuple of num_nodes can be passed to specify the number of nodes of the new types, otherwise the number of nodes is inferred from the maximum node id in s and t.
If the source node type is the same as the destination node type in edge_t, return a graph with the same features as g but also add self-loops of the specified type, edge_t. Otherwise, it returns g unchanged.
Nodes with already existing self-loops of type edge_t will obtain a second set of self-loops of the same type.
If the graph has edge weights for edges of type edge_t, the new edges will have weight 1.
If no edges of type edge_t exist, or all existing edges have no weight, then all new self loops will have no weight.
If edge_t is not passed as argument, for the entire graph self-loop is added to each node for every edge type in the graph where the source and destination node types are the same. This iterates over all edge types present in the graph, applying the self-loop addition logic to each applicable edge type.
Return the subgraph of g induced by those nodes j for which g.graph_indicator[j] == i or, if i is a collection, g.graph_indicator[j] ∈ i. In other words, it extract the component graphs from a batched graph.
If nmap=true, return also a vector v mapping the new nodes to the old ones. The node i in the subgraph will correspond to the node v[i] in g.
Return a new graph obtained from g by adding random edges, based on a specified perturb_ratio. The perturb_ratio determines the fraction of new edges to add relative to the current number of edges in the graph. These new edges are added without creating self-loops.
The function returns a new GNNGraph instance that shares some of the underlying data with g but includes the additional edges. The nodes for the new edges are selected randomly, and no edge data (edata) or weights (w) are assigned to these new edges.
Arguments
g::GNNGraph: The graph to be perturbed.
perturb_ratio: The ratio of the number of new edges to add relative to the current number of edges in the graph. For example, a perturb_ratio of 0.1 means that 10% of the current number of edges will be added as new random edges.
rng: An optionalrandom number generator to ensure reproducible results.
Examples
julia> g = GNNGraph((s, t, w))
+ bidirected = is_bidirected(g))
Return a graph containing random negative edges (i.e. non-edges) from graph g as edges.
If bidirected=true, the output graph will be bidirected and there will be no leakage from the origin graph.
Return a new graph obtained from g by adding random edges, based on a specified perturb_ratio. The perturb_ratio determines the fraction of new edges to add relative to the current number of edges in the graph. These new edges are added without creating self-loops.
The function returns a new GNNGraph instance that shares some of the underlying data with g but includes the additional edges. The nodes for the new edges are selected randomly, and no edge data (edata) or weights (w) are assigned to these new edges.
Arguments
g::GNNGraph: The graph to be perturbed.
perturb_ratio: The ratio of the number of new edges to add relative to the current number of edges in the graph. For example, a perturb_ratio of 0.1 means that 10% of the current number of edges will be added as new random edges.
rng: An optionalrandom number generator to ensure reproducible results.
Calculates the Personalized PageRank (PPR) diffusion based on the edge weight matrix of a GNNGraph and updates the graph with new edge weights derived from the PPR matrix. References paper: The pagerank citation ranking: Bringing order to the web
The function performs the following steps:
Constructs a modified adjacency matrix A using the graph's edge weights, where A is adjusted by (α - 1) * A + I, with α being the damping factor (alpha_f32) and I the identity matrix.
Normalizes A to ensure each column sums to 1, representing transition probabilities.
Applies the PPR formula α * (I + (α - 1) * A)^-1 to compute the diffusion matrix.
Updates the original edge weights of the graph based on the PPR diffusion matrix, assigning new weights for each edge from the PPR matrix.
Arguments
g::GNNGraph: The input graph for which PPR diffusion is to be calculated. It should have edge weights available.
alpha_f32::Float32: The damping factor used in PPR calculation, controlling the teleport probability in the random walk. Defaults to 0.85f0.
Returns
A new GNNGraph instance with the same structure as g but with updated edge weights according to the PPR diffusion calculation.
Randomly partition the edges in g to form two graphs, g1 and g2. Both will have the same number of nodes as g. g1 will contain a fraction frac of the original edges, while g2 wil contain the rest.
If bidirected = true makes sure that an edge and its reverse go into the same split. This option is supported only for bidirected graphs with no self-loops and multi-edges.
rand_edge_split is tipically used to create train/test splits in link prediction tasks.
Calculates the Personalized PageRank (PPR) diffusion based on the edge weight matrix of a GNNGraph and updates the graph with new edge weights derived from the PPR matrix. References paper: The pagerank citation ranking: Bringing order to the web
The function performs the following steps:
Constructs a modified adjacency matrix A using the graph's edge weights, where A is adjusted by (α - 1) * A + I, with α being the damping factor (alpha_f32) and I the identity matrix.
Normalizes A to ensure each column sums to 1, representing transition probabilities.
Applies the PPR formula α * (I + (α - 1) * A)^-1 to compute the diffusion matrix.
Updates the original edge weights of the graph based on the PPR diffusion matrix, assigning new weights for each edge from the PPR matrix.
Arguments
g::GNNGraph: The input graph for which PPR diffusion is to be calculated. It should have edge weights available.
alpha_f32::Float32: The damping factor used in PPR calculation, controlling the teleport probability in the random walk. Defaults to 0.85f0.
Returns
A new GNNGraph instance with the same structure as g but with updated edge weights according to the PPR diffusion calculation.
Randomly partition the edges in g to form two graphs, g1 and g2. Both will have the same number of nodes as g. g1 will contain a fraction frac of the original edges, while g2 wil contain the rest.
If bidirected = true makes sure that an edge and its reverse go into the same split. This option is supported only for bidirected graphs with no self-loops and multi-edges.
rand_edge_split is tipically used to create train/test splits in link prediction tasks.
Remove multiple edges (also called parallel edges or repeated edges) from graph g. Possible edge features are aggregated according to aggr, that can take value +,min, max or mean.
Remove multiple edges (also called parallel edges or repeated edges) from graph g. Possible edge features are aggregated according to aggr, that can take value +,min, max or mean.
Remove specified nodes, and their associated edges, from a GNNGraph. This operation reindexes the remaining nodes to maintain a continuous sequence of node indices, starting from 1. Similarly, edges are reindexed to account for the removal of edges connected to the removed nodes.
Arguments
g: The input graph from which nodes (and their edges) will be removed.
nodes_to_remove: Vector of node indices to be removed.
Returns
A new GNNGraph with the specified nodes and all edges associated with these nodes removed.
Remove specified nodes, and their associated edges, from a GNNGraph. This operation reindexes the remaining nodes to maintain a continuous sequence of node indices, starting from 1. Similarly, edges are reindexed to account for the removal of edges connected to the removed nodes.
Arguments
g: The input graph from which nodes (and their edges) will be removed.
nodes_to_remove: Vector of node indices to be removed.
Returns
A new GNNGraph with the specified nodes and all edges associated with these nodes removed.
Example
using GraphNeuralNetworks
g = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1])
@@ -154,7 +154,7 @@
g_new = remove_nodes(g, [2, 3])
# g_new now does not contain nodes 2 and 3, and any edges that were connected to these nodes.
-println(g_new)
Return a sorted version of the tuple of vectors ei = (u, v), applying a common permutation to u and v. The sorting is lexycographic, that is the pairs (ui, vi) are sorted first according to the ui and then according to vi.
The color refinement algorithm for graph coloring. Given a graph g and an initial coloring x0, the algorithm iteratively refines the coloring until a fixed point is reached.
At each iteration the algorithm computes a hash of the coloring and the sorted list of colors of the neighbors of each node. This hash is used to determine if the coloring has changed.
math x_i' = hashmap((x_i, sort([x_j for j \in N(i)]))).`
This algorithm is related to the 1-Weisfeiler-Lehman algorithm for graph isomorphism testing.
Arguments
g::GNNGraph: The graph to color.
x0::AbstractVector{<:Integer}: The initial coloring. If not provided, all nodes are colored with 1.
Returns
x::AbstractVector{<:Integer}: The final coloring.
num_colors::Int: The number of colors used.
niters::Int: The number of iterations until convergence.
Return a sorted version of the tuple of vectors ei = (u, v), applying a common permutation to u and v. The sorting is lexycographic, that is the pairs (ui, vi) are sorted first according to the ui and then according to vi.
The color refinement algorithm for graph coloring. Given a graph g and an initial coloring x0, the algorithm iteratively refines the coloring until a fixed point is reached.
At each iteration the algorithm computes a hash of the coloring and the sorted list of colors of the neighbors of each node. This hash is used to determine if the coloring has changed.
math x_i' = hashmap((x_i, sort([x_j for j \in N(i)]))).`
This algorithm is related to the 1-Weisfeiler-Lehman algorithm for graph isomorphism testing.
Arguments
g::GNNGraph: The graph to color.
x0::AbstractVector{<:Integer}: The initial coloring. If not provided, all nodes are colored with 1.
Returns
x::AbstractVector{<:Integer}: The final coloring.
num_colors::Int: The number of colors used.
niters::Int: The number of iterations until convergence.
rand_graph([rng,] n, m; bidirected=true, edge_weight = nothing, kws...)
Generate a random (Erdós-Renyi) GNNGraph with n nodes and m edges.
If bidirected=true the reverse edge of each edge will be present. If bidirected=false instead, m unrelated edges are generated. In any case, the output graph will contain no self-loops or multi-edges.
A vector can be passed as edge_weight. Its length has to be equal to m in the directed case, and m÷2 in the bidirected one.
Pass a random number generator as the first argument to make the generation reproducible.
Additional keyword arguments will be passed to the GNNGraph constructor.
rand_graph([rng,] n, m; bidirected=true, edge_weight = nothing, kws...)
Generate a random (Erdós-Renyi) GNNGraph with n nodes and m edges.
If bidirected=true the reverse edge of each edge will be present. If bidirected=false instead, m unrelated edges are generated. In any case, the output graph will contain no self-loops or multi-edges.
A vector can be passed as edge_weight. Its length has to be equal to m in the directed case, and m÷2 in the bidirected one.
Pass a random number generator as the first argument to make the generation reproducible.
Additional keyword arguments will be passed to the GNNGraph constructor.
Examples
julia> g = rand_graph(5, 4, bidirected=false)
GNNGraph:
num_nodes = 5
num_edges = 4
@@ -318,11 +318,11 @@
# Each edge has a reverse
julia> edge_index(g)
-([1, 3, 3, 4], [3, 4, 1, 3])
rand_heterograph([rng,] n, m; bidirected=false, kws...)
Construct an GNNHeteroGraph with random edges and with number of nodes and edges specified by n and m respectively. n and m can be any iterable of pairs specifing node/edge types and their numbers.
Pass a random number generator as a first argument to make the generation reproducible.
Setting bidirected=true will generate a bidirected graph, i.e. each edge will have a reverse edge. Therefore, for each edge type (:A, :rel, :B) a corresponding reverse edge type (:B, :rel, :A) will be generated.
Additional keyword arguments will be passed to the GNNHeteroGraph constructor.
rand_heterograph([rng,] n, m; bidirected=false, kws...)
Construct an GNNHeteroGraph with random edges and with number of nodes and edges specified by n and m respectively. n and m can be any iterable of pairs specifing node/edge types and their numbers.
Pass a random number generator as a first argument to make the generation reproducible.
Setting bidirected=true will generate a bidirected graph, i.e. each edge will have a reverse edge. Therefore, for each edge type (:A, :rel, :B) a corresponding reverse edge type (:B, :rel, :A) will be generated.
Additional keyword arguments will be passed to the GNNHeteroGraph constructor.
Sample neighboring edges of the given nodes and return the induced subgraph. For each node, a number of inbound (or outbound when dir = :out) edges will be randomly chosen. Ifdropnodes=false`, the graph returned will then contain all the nodes in the original graph, but only the sampled edges.
The returned graph will contain an edge feature EID corresponding to the id of the edge in the original graph. If dropnodes=true, it will also contain a node feature NID with the node ids in the original graph.
Arguments
g. The graph.
nodes. A list of node IDs to sample neighbors from.
K. The maximum number of edges to be sampled for each node. If -1, all the neighboring edges will be selected.
dir. Determines whether to sample inbound (:in) or outbound (`:out) edges (Default :in).
replace. If true, sample with replacement.
dropnodes. If true, the resulting subgraph will contain only the nodes involved in the sampled edges.
Sample neighboring edges of the given nodes and return the induced subgraph. For each node, a number of inbound (or outbound when dir = :out) edges will be randomly chosen. Ifdropnodes=false`, the graph returned will then contain all the nodes in the original graph, but only the sampled edges.
The returned graph will contain an edge feature EID corresponding to the id of the edge in the original graph. If dropnodes=true, it will also contain a node feature NID with the node ids in the original graph.
Arguments
g. The graph.
nodes. A list of node IDs to sample neighbors from.
K. The maximum number of edges to be sampled for each node. If -1, all the neighboring edges will be selected.
dir. Determines whether to sample inbound (:in) or outbound (`:out) edges (Default :in).
replace. If true, sample with replacement.
dropnodes. If true, the resulting subgraph will contain only the nodes involved in the sampled edges.
A type representing a heterogeneous graph structure. It is similar to GNNGraph but nodes and edges are of different types.
Constructor Arguments
data: A dictionary or an iterable object that maps (source_type, edge_type, target_type) triples to (source, target) index vectors (or to (source, target, weight) if also edge weights are present).
pairs: Passing multiple relations as pairs is equivalent to passing data=Dict(pairs...).
ndata: Node features. A dictionary of arrays or named tuple of arrays. The size of the last dimension of each array must be given by g.num_nodes.
edata: Edge features. A dictionary of arrays or named tuple of arrays. Default nothing. The size of the last dimension of each array must be given by g.num_edges. Default nothing.
gdata: Graph features. An array or named tuple of arrays whose last dimension has size num_graphs. Default nothing.
num_nodes: The number of nodes for each type. If not specified, inferred from data. Default nothing.
Fields
graph: A dictionary that maps (sourcetype, edgetype, target_type) triples to (source, target) index vectors.
Return a subgraph of g that contains only the edges of type edge_ts. Edge types can be specified as a single edge type (i.e. a tuple containing 3 symbols) or a vector of edge types.
Return a subgraph of g that contains only the edges of type edge_ts. Edge types can be specified as a single edge type (i.e. a tuple containing 3 symbols) or a vector of edge types.
Heterogeneous graph convolutions are implemented in the type HeteroGraphConv. HeteroGraphConv relies on standard graph convolutional layers to perform message passing on the different relations. See the table at this page for the supported layers.
Heterogeneous graph convolutions are implemented in the type HeteroGraphConv. HeteroGraphConv relies on standard graph convolutional layers to perform message passing on the different relations. See the table at this page for the supported layers.
The itr argument is an iterator of pairs of the form edge_t => layer, where edge_t is a 3-tuple of the form (src_node_type, edge_type, dst_node_type), and layer is a convolutional layers for homogeneous graphs.
Each convolution is applied to the corresponding relation. Since a node type can be involved in multiple relations, the single convolution outputs have to be aggregated using the aggr function. The default is to sum the outputs.
Forward Arguments
g::GNNHeteroGraph: The input graph.
x::Union{NamedTuple,Dict}: The input node features. The keys are node types and the values are node feature tensors.
Examples
julia> g = rand_bipartite_heterograph((10, 15), 20)
GNNHeteroGraph:
num_nodes: Dict(:A => 10, :B => 15)
@@ -63,4 +63,4 @@
julia> y = layer(g, x); # output is a named tuple
julia> size(y.A) == (32, 10) && size(y.B) == (32, 15)
-true
Returns the message from node j to node i applying the message function fmsg on the edges in graph g. In the message-passing scheme, the incoming messages from the neighborhood of i will later be aggregated in order to update the features of node i (see aggregate_neighbors).
The function fmsg operates on batches of edges, therefore xi, xj, and e are tensors whose last dimension is the batch size, or can be named tuples of such tensors.
Arguments
g: An AbstractGNNGraph.
xi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).
xj: As xi, but now to be materialized on each edge's source node.
e: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.
fmsg: A function that takes as inputs the edge-materialized xi, xj, and e. These are arrays (or named tuples of arrays) whose last dimension' size is the size of a batch of edges. The output of f has to be an array (or a named tuple of arrays) with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).
Returns the message from node j to node i applying the message function fmsg on the edges in graph g. In the message-passing scheme, the incoming messages from the neighborhood of i will later be aggregated in order to update the features of node i (see aggregate_neighbors).
The function fmsg operates on batches of edges, therefore xi, xj, and e are tensors whose last dimension is the batch size, or can be named tuples of such tensors.
Arguments
g: An AbstractGNNGraph.
xi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).
xj: As xi, but now to be materialized on each edge's source node.
e: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.
fmsg: A function that takes as inputs the edge-materialized xi, xj, and e. These are arrays (or named tuples of arrays) whose last dimension' size is the size of a batch of edges. The output of f has to be an array (or a named tuple of arrays) with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).
Performs message passing on graph g. Takes care of materializing the node features on each edge, applying the message function fmsg, and returning an aggregated message $\bar{\mathbf{m}}$ (depending on the return value of fmsg, an array or a named tuple of arrays with last dimension's size g.num_nodes).
It can be decomposed in two steps:
m = apply_edges(fmsg, g, xi, xj, e)
m̄ = aggregate_neighbors(g, aggr, m)
GNN layers typically call propagate in their forward pass, providing as input f a closure.
Arguments
g: A GNNGraph.
xi: An array or a named tuple containing arrays whose last dimension's size is g.num_nodes. It will be appropriately materialized on the target node of each edge (see also edge_index).
xj: As xj, but to be materialized on edges' sources.
e: An array or a named tuple containing arrays whose last dimension's size is g.num_edges.
fmsg: A generic function that will be passed over to apply_edges. Has to take as inputs the edge-materialized xi, xj, and e (arrays or named tuples of arrays whose last dimension' size is the size of a batch of edges). Its output has to be an array or a named tuple of arrays with the same batch size. If also layer is passed to propagate, the signature of fmsg has to be fmsg(layer, xi, xj, e) instead of fmsg(xi, xj, e).
aggr: Neighborhood aggregation operator. Use +, mean, max, or min.
Examples
using GraphNeuralNetworks, Flux
@@ -26,4 +26,4 @@
end
l = GNNConv(10 => 20)
-l(g, x)
Global pooling layer for graph neural networks. Takes a graph and feature nodes as inputs and performs the operation
\[\mathbf{u}_V = \square_{i \in V} \mathbf{x}_i\]
where $V$ is the set of nodes of the input graph and the type of aggregation represented by $\square$ is selected by the aggr argument. Commonly used aggregations are mean, max, and +.
Global pooling layer for graph neural networks. Takes a graph and feature nodes as inputs and performs the operation
\[\mathbf{u}_V = \square_{i \in V} \mathbf{x}_i\]
where $V$ is the set of nodes of the input graph and the type of aggregation represented by $\square$ is selected by the aggr argument. Commonly used aggregations are mean, max, and +.
using Flux, GraphNeuralNetworks, Graphs
pool = GlobalPool(mean)
@@ -24,7 +24,7 @@
g = Flux.batch([GNNGraph(erdos_renyi(10, 4)) for _ in 1:5])
X = rand(32, 50)
-pool(g, X) # => 32x5 matrix
init_state: Initial state of the hidden stat of the GRU layer. Default zeros32.
add_self_loops: Add self loops to the graph before performing the convolution. Default false.
use_edge_weight: If true, consider the edge weights in the input graph (if available). If add_self_loops=true the new weights will be set to 1. This option is ignored if the edge_weight is explicitly provided in the forward pass. Default false.
init_state: Initial state of the hidden stat of the GRU layer. Default zeros32.
add_self_loops: Add self loops to the graph before performing the convolution. Default false.
use_edge_weight: If true, consider the edge weights in the input graph (if available). If add_self_loops=true the new weights will be set to 1. This option is ignored if the edge_weight is explicitly provided in the forward pass. Default false.
init_state: Initial state of the hidden stat of the GRU layer. Default zeros32.
add_self_loops: Add self loops to the graph before performing the convolution. Default false.
use_edge_weight: If true, consider the edge weights in the input graph (if available). If add_self_loops=true the new weights will be set to 1. This option is ignored if the edge_weight is explicitly provided in the forward pass. Default false.
init_state: Initial state of the hidden stat of the GRU layer. Default zeros32.
add_self_loops: Add self loops to the graph before performing the convolution. Default false.
use_edge_weight: If true, consider the edge weights in the input graph (if available). If add_self_loops=true the new weights will be set to 1. This option is ignored if the edge_weight is explicitly provided in the forward pass. Default false.
A type representing a temporal graph as a sequence of snapshots. In this case a snapshot is a GNNGraph.
TemporalSnapshotsGNNGraph can store the feature array associated to the graph itself as a DataStore object, and it uses the DataStore objects of each snapshot for the node and edge features. The features can be passed at construction time or added later.
Constructor Arguments
snapshot: a vector of snapshots, where each snapshot must have the same number of nodes.
Examples
julia> using GraphNeuralNetworks
+Temporal Graphs · GraphNeuralNetworks.jl
A type representing a temporal graph as a sequence of snapshots. In this case a snapshot is a GNNGraph.
TemporalSnapshotsGNNGraph can store the feature array associated to the graph itself as a DataStore object, and it uses the DataStore objects of each snapshot for the node and edge features. The features can be passed at construction time or added later.
Constructor Arguments
snapshot: a vector of snapshots, where each snapshot must have the same number of nodes.
Examples
julia> using GraphNeuralNetworks
julia> snapshots = [rand_graph(10,20) for i in 1:5];
@@ -17,7 +17,7 @@
num_edges: [20, 20, 20, 20, 20]
num_snapshots: 5
tgdata:
- x = 4-element Vector{Float64}
For a batched graph g, return the graph-wise aggregation of the node features x. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.
Return the graph-wise aggregation of the node features x given the graph indicator indicator. The aggregation operator aggr can be +, mean, max, or min.
For a batched graph g, return the graph-wise aggregation of the edge features e. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.
For a batched graph g, return the graph-wise aggregation of the node features x. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.
Return the graph-wise aggregation of the node features x given the graph indicator indicator. The aggregation operator aggr can be +, mean, max, or min.
For a batched graph g, return the graph-wise aggregation of the edge features e. The aggregation operator aggr can be +, mean, max, or min. The returned array will have last dimension g.num_graphs.
GraphNeuralNetworks.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the examples in the GraphNeuralNetworks.jl repository make use of the MLDatasets.jl package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and many others.
GraphNeuralNetworks.jl provides the mldataset2gnngraph method for interfacing with MLDatasets.jl.
GraphNeuralNetworks.jl doesn't come with its own datasets, but leverages those available in the Julia (and non-Julia) ecosystem. In particular, the examples in the GraphNeuralNetworks.jl repository make use of the MLDatasets.jl package. There you will find common graph datasets such as Cora, PubMed, Citeseer, TUDataset and many others.
GraphNeuralNetworks.jl provides the mldataset2gnngraph method for interfacing with MLDatasets.jl.
Tutorials in GraphNeuralNetworks.jl are written in Pluto and rendered using DemoCards.jl and PlutoStaticHTML.jl. Rendering a Pluto notebook is time and resource-consuming, especially in a CI environment. So we use the caching functionality provided by PlutoStaticHTML.jl to reduce CI time.
If you are contributing a new tutorial or making changes to the existing notebook, generate the docs locally before committing/pushing. For caching to work, the cache environment(your local) and the documenter CI should have the same Julia version (e.g. "v1.9.1", also the patch number must match). So use the documenter CI Julia version for generating docs locally.
julia --version # check julia version before generating docs
-julia --project=docs docs/make.jl
Note: Use juliaup for easy switching of Julia versions.
During the doc generation process, DemoCards.jl stores the cache notebooks in docs/pluto_output. So add any changes made in this folder in your git commit. Remember that every file in this folder is machine-generated and should not be edited manually.