From 20f7e3de36478305a9f849c6d060cbbdf15fa047 Mon Sep 17 00:00:00 2001 From: John E Date: Sun, 26 Jul 2026 17:40:23 -0400 Subject: [PATCH] docs: fix some typos Signed-off-by: John E --- GNNGraphs/src/gnngraph.jl | 8 +- GNNGraphs/src/gnnheterograph/generate.jl | 23 ++-- GNNGraphs/src/transform.jl | 72 +++++----- GraphNeuralNetworks/docs/src/dev.md | 10 +- .../notebooks/graph_classification.ipynb | 4 +- .../graph_classification_solved.ipynb | 4 +- GraphNeuralNetworks/src/layers/conv.jl | 126 +++++++++--------- 7 files changed, 123 insertions(+), 124 deletions(-) diff --git a/GNNGraphs/src/gnngraph.jl b/GNNGraphs/src/gnngraph.jl index e59c8f1e0..dccaf8d67 100644 --- a/GNNGraphs/src/gnngraph.jl +++ b/GNNGraphs/src/gnngraph.jl @@ -13,7 +13,7 @@ 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`](@ref) objects offering a convenient dictionary-like +as [`DataStore`](@ref) objects offering a convenient dictionary-like and namedtuple-like interface. The features can be passed at construction time or added later. @@ -23,10 +23,10 @@ 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 +as well, unless explicitly set by the keyword arguments `ndata`, `edata`, and `gdata`. -A `GNNGraph` can also represent multiple graphs batched togheter +A `GNNGraph` can also represent multiple graphs batched together (see [`MLUtils.batch`](@ref) or [`SparseArrays.blockdiag`](@ref)). The field `g.graph_indicator` contains the graph membership of each node. @@ -102,7 +102,7 @@ g.edata.e # or just g.e source, target = edge_index(g) ``` A `GNNGraph` can be sent to the GPU, for example by using Flux.jl's `gpu` function -or MLDataDevices.jl's utilities. +or MLDataDevices.jl's utilities. """ struct GNNGraph{T <: Union{COO_T, ADJMAT_T}} <: AbstractGNNGraph{T} graph::T diff --git a/GNNGraphs/src/gnnheterograph/generate.jl b/GNNGraphs/src/gnnheterograph/generate.jl index d6969ad93..a27022405 100644 --- a/GNNGraphs/src/gnnheterograph/generate.jl +++ b/GNNGraphs/src/gnnheterograph/generate.jl @@ -1,9 +1,9 @@ """ rand_heterograph([rng,] n, m; bidirected=false, kws...) -Construct an [`GNNHeteroGraph`](@ref) with random edges and with number of nodes and edges +Construct an [`GNNHeteroGraph`](@ref) 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. +specifying node/edge types and their numbers. Pass a random number generator as a first argument to make the generation reproducible. @@ -67,18 +67,18 @@ end """ - rand_bipartite_heterograph([rng,] - (n1, n2), (m12, m21); - bidirected = true, - node_t = (:A, :B), - edge_t = :to, + rand_bipartite_heterograph([rng,] + (n1, n2), (m12, m21); + bidirected = true, + node_t = (:A, :B), + edge_t = :to, kws...) Construct an [`GNNHeteroGraph`](@ref) with random edges representing a bipartite graph. The graph will have two types of nodes, and edges will only connect nodes of different types. The first argument is a tuple `(n1, n2)` specifying the number of nodes of each type. -The second argument is a tuple `(m12, m21)` specifying the number of edges connecting nodes of type `1` to nodes of type `2` +The second argument is a tuple `(m12, m21)` specifying the number of edges connecting nodes of type `1` to nodes of type `2` and vice versa. The type of nodes and edges can be specified with the `node_t` and `edge_t` keyword arguments, @@ -109,7 +109,7 @@ GNNHeteroGraph: """ rand_bipartite_heterograph(n, m; kws...) = rand_bipartite_heterograph(Random.default_rng(), n, m; kws...) -function rand_bipartite_heterograph(rng::AbstractRNG, (n1, n2)::NTuple{2,Int}, m; bidirected=true, +function rand_bipartite_heterograph(rng::AbstractRNG, (n1, n2)::NTuple{2,Int}, m; bidirected=true, node_t = (:A, :B), edge_t::Symbol = :to, kws...) if m isa Integer m12 = m21 = m @@ -117,8 +117,7 @@ function rand_bipartite_heterograph(rng::AbstractRNG, (n1, n2)::NTuple{2,Int}, m m12, m21 = m end - return rand_heterograph(rng, Dict(node_t[1] => n1, node_t[2] => n2), - Dict((node_t[1], edge_t, node_t[2]) => m12, (node_t[2], edge_t, node_t[1]) => m21); + return rand_heterograph(rng, Dict(node_t[1] => n1, node_t[2] => n2), + Dict((node_t[1], edge_t, node_t[2]) => m12, (node_t[2], edge_t, node_t[1]) => m21); bidirected, kws...) end - diff --git a/GNNGraphs/src/transform.jl b/GNNGraphs/src/transform.jl index a9e7bf586..a89035de7 100644 --- a/GNNGraphs/src/transform.jl +++ b/GNNGraphs/src/transform.jl @@ -42,7 +42,7 @@ end remove_self_loops(g::GNNGraph) Return a graph constructed from `g` where self-loops (edges from a node to itself) -are removed. +are removed. See also [`add_self_loops`](@ref) and [`coalesce`](@ref). """ @@ -100,7 +100,7 @@ julia> g = GNNGraph([1, 1, 2, 2, 3], [2, 3, 1, 3, 1]) GNNGraph: num_nodes: 3 num_edges: 5 - + # Remove the second edge julia> g_new = remove_edges(g, [2]); @@ -143,15 +143,15 @@ end function remove_edges(g::GNNGraph{<:COO_T}, p = 0.5) num_edges = g.num_edges - edges_to_remove = filter(_ -> rand() < p, 1:num_edges) + edges_to_remove = filter(_ -> rand() < p, 1:num_edges) return remove_edges(g, edges_to_remove) end """ coalesce(g::GNNGraph; aggr=+) -Return a new GNNGraph where all multiple edges between the same pair of nodes are merged -(using aggr for edge weights and features), +Return a new GNNGraph where all multiple edges between the same pair of nodes are merged +(using aggr for edge weights and features), and the edge indices are sorted lexicographically (by target, then by source). This method is only applicable to graphs of type `:coo`. @@ -198,7 +198,7 @@ Remove specified nodes, and their associated edges, from a GNNGraph. This operat - `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. +A new GNNGraph with the specified nodes and all edges associated with these nodes removed. # Example ```julia @@ -219,14 +219,14 @@ function remove_nodes(g::GNNGraph{<:COO_T}, nodes_to_remove::AbstractVector) w = get_edge_weight(g) edata = g.edata ndata = g.ndata - + function find_edges_to_remove(nodes, nodes_to_remove) return findall(node_id -> begin idx = searchsortedlast(nodes_to_remove, node_id) idx >= 1 && idx <= length(nodes_to_remove) && nodes_to_remove[idx] == node_id end, nodes) end - + edges_to_remove_s = find_edges_to_remove(s, nodes_to_remove) edges_to_remove_t = find_edges_to_remove(t, nodes_to_remove) edges_to_remove = union(edges_to_remove_s, edges_to_remove_t) @@ -238,7 +238,7 @@ function remove_nodes(g::GNNGraph{<:COO_T}, nodes_to_remove::AbstractVector) w = isnothing(w) ? nothing : getobs(w, mask_edges_to_keep) - for node in sort(nodes_to_remove, rev=true) + for node in sort(nodes_to_remove, rev=true) s[s .> node] .-= 1 t[t .> node] .-= 1 end @@ -248,7 +248,7 @@ function remove_nodes(g::GNNGraph{<:COO_T}, nodes_to_remove::AbstractVector) edata = getobs(edata, mask_edges_to_keep) num_nodes = g.num_nodes - length(nodes_to_remove) - + return GNNGraph((s, t, w), num_nodes, length(s), g.num_graphs, g.graph_indicator, @@ -258,7 +258,7 @@ end """ remove_nodes(g::GNNGraph, p) -Returns a new graph obtained by dropping nodes from `g` with independent probabilities `p`. +Returns a new graph obtained by dropping nodes from `g` with independent probabilities `p`. # Examples @@ -359,11 +359,11 @@ end """ perturb_edges([rng], g::GNNGraph, perturb_ratio) -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. +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 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 @@ -386,7 +386,7 @@ GNNGraph: num_edges: 6 ``` """ -perturb_edges(g::GNNGraph{<:COO_T}, perturb_ratio::AbstractFloat) = +perturb_edges(g::GNNGraph{<:COO_T}, perturb_ratio::AbstractFloat) = perturb_edges(Random.default_rng(), g, perturb_ratio) function perturb_edges(rng::AbstractRNG, g::GNNGraph{<:COO_T}, perturb_ratio::AbstractFloat) @@ -444,10 +444,10 @@ end """ to_bidirected(g) -Adds a reverse edge for each edge in the graph, then calls -[`coalesce`](@ref) with `mean` aggregation to simplify the graph. +Adds a reverse edge for each edge in the graph, then calls +[`coalesce`](@ref) with `mean` aggregation to simplify the graph. -See also [`is_bidirected`](@ref). +See also [`is_bidirected`](@ref). # Examples @@ -550,7 +550,7 @@ end """ add_nodes(g::GNNGraph, n; [ndata]) -Add `n` new nodes to graph `g`. In the +Add `n` new nodes to graph `g`. In the new graph, these nodes will have indexes from `g.num_nodes + 1` to `g.num_nodes + n`. """ @@ -567,7 +567,7 @@ end """ set_edge_weight(g::GNNGraph, w::AbstractVector) -Set `w` as edge weights in the returned graph. +Set `w` as edge weights in the returned graph. """ function set_edge_weight(g::GNNGraph, w::AbstractVector) # TODO preserve the representation instead of converting to COO @@ -634,7 +634,7 @@ end """ batch(gs::Vector{<:GNNGraph}) -Batch together multiple `GNNGraph`s into a single one +Batch together multiple `GNNGraph`s into a single one containing the total number of original nodes and edges. Equivalent to [`SparseArrays.blockdiag`](@ref). @@ -719,7 +719,7 @@ end """ unbatch(g::GNNGraph) -Opposite of the [`MLUtils.batch`](@ref) operation, returns +Opposite of the [`MLUtils.batch`](@ref) operation, returns an array of the individual graphs batched together in `g`. See also [`MLUtils.batch`](@ref) and [`getgraph`](@ref). @@ -816,10 +816,10 @@ CRC.@non_differentiable _unbatch_edgemasks(::Any...) 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 `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. +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`. """ getgraph(g::GNNGraph, i::Int; kws...) = getgraph(g, [i]; kws...) @@ -905,14 +905,14 @@ function getgraph(g::GNNGraph, i::AbstractVector{Int}; nmap = false) end """ - negative_sample(g::GNNGraph; - num_neg_edges = g.num_edges, + negative_sample(g::GNNGraph; + num_neg_edges = g.num_edges, 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. +leakage from the origin graph. See also [`is_bidirected`](@ref). """ @@ -933,11 +933,11 @@ function negative_sample(g::GNNGraph; idx_pos, maxid = edge_encoding(s, t, n) if bidirected num_neg_edges = num_neg_edges ÷ 2 - pneg = 1 - g.num_edges / 2maxid # prob of selecting negative edge + pneg = 1 - g.num_edges / 2maxid # prob of selecting negative edge else - pneg = 1 - g.num_edges / 2maxid # prob of selecting negative edge + pneg = 1 - g.num_edges / 2maxid # prob of selecting negative edge end - # pneg * sample_prob * maxid == num_neg_edges + # pneg * sample_prob * maxid == num_neg_edges sample_prob = min(1, num_neg_edges / (pneg * maxid) * 1.1) idx_neg = Int[] for _ in 1:max_trials @@ -962,14 +962,14 @@ end 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. +`g1` will contain a fraction `frac` of the original edges, +while `g2` will 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. +`rand_edge_split` is typically used to create train/test splits in link prediction tasks. """ function rand_edge_split(g::GNNGraph, frac; bidirected = is_bidirected(g)) s, t = edge_index(g) @@ -999,7 +999,7 @@ end """ random_walk_pe(g, walk_length) -Return the random walk positional encoding from the paper [Graph Neural Networks with Learnable Structural and Positional Representations](https://arxiv.org/abs/2110.07875) of the given graph `g` and the length of the walk `walk_length` as a matrix of size `(walk_length, g.num_nodes)`. +Return the random walk positional encoding from the paper [Graph Neural Networks with Learnable Structural and Positional Representations](https://arxiv.org/abs/2110.07875) of the given graph `g` and the length of the walk `walk_length` as a matrix of size `(walk_length, g.num_nodes)`. """ function random_walk_pe(g::GNNGraph, walk_length::Int) matrix = zeros(walk_length, g.num_nodes) diff --git a/GraphNeuralNetworks/docs/src/dev.md b/GraphNeuralNetworks/docs/src/dev.md index 5e4e6b47b..08750f45c 100644 --- a/GraphNeuralNetworks/docs/src/dev.md +++ b/GraphNeuralNetworks/docs/src/dev.md @@ -1,7 +1,7 @@ # Developer Notes -## Development Enviroment +## Development Environment GraphNeuralNetworks.jl is a collection of packages hosted on a single GitHub repository. These packages are `GraphNeuralNetworks.jl` (a package with the same name as the whole project), `GNNGraphs.jl`, `GNNlib.jl`, and `GNNLux.jl`. @@ -17,7 +17,7 @@ graph TD; Thanks to [workspaces](https://pkgdocs.julialang.org/v1/toml-files/#The-%5Bworkspace%5D-section) introduced in julia 1.12, developing multiple packages in a monorepo is straightforward. -Clone the repository with +Clone the repository with ``` git clone https://github.com/JuliaGraphs/GraphNeuralNetworks.jl ``` @@ -29,7 +29,7 @@ julia --project=. ``` Dependencies in the monorepo will be automatically available in `dev` mode, so you can start editing the code of any of the packages and test your changes immediately. -## Add a New Layer +## Add a New Layer To add a new graph convolutional layer and make it available in both the Flux-based frontend (GraphNeuralNetworks.jl) and the Lux-based frontend (GNNLux), you need to: @@ -70,7 +70,7 @@ end ``` ## Versions and Tagging -Each PR should update the version number in the Porject.toml file of each involved package if needed by semnatic versioning. For instance, when adding new features GNNGraphs could move from "1.17.5" to "1.18.0-DEV". The "DEV" will be removed when the package is tagged and released. Pay also attention to updating +Each PR should update the version number in the Project.toml file of each involved package if needed by semnatic versioning. For instance, when adding new features GNNGraphs could move from "1.17.5" to "1.18.0-DEV". The "DEV" will be removed when the package is tagged and released. Pay also attention to updating the compat bounds, e.g. GraphNeuralNetworks might require a newer version of GNNGraphs. ## Generate Documentation Locally @@ -137,4 +137,4 @@ git add docs/pluto_output # add generated cache Check the [documenter CI logs](https://github.com/JuliaGraphs/GraphNeuralNetworks.jl/actions/workflows/docs.yml) to ensure that it used the local cache: -![](https://user-images.githubusercontent.com/55111154/210061301-c84b7274-9e66-46fd-b272-d45b1c681d00.png) \ No newline at end of file +![](https://user-images.githubusercontent.com/55111154/210061301-c84b7274-9e66-46fd-b272-d45b1c681d00.png) diff --git a/GraphNeuralNetworks/notebooks/graph_classification.ipynb b/GraphNeuralNetworks/notebooks/graph_classification.ipynb index f407b0559..f784f3c9d 100644 --- a/GraphNeuralNetworks/notebooks/graph_classification.ipynb +++ b/GraphNeuralNetworks/notebooks/graph_classification.ipynb @@ -7,10 +7,10 @@ "source": [ "# Graph Classification with Graph Neural Networks\n", "\n", - "*This noteboook is a julia adaptation of the Pytorch Geometric tutorials that can be found [here](https://pytorch-geometric.readthedocs.io/en/latest/notes/colabs.html).*\n", + "*This notebook is a julia adaptation of the Pytorch Geometric tutorials that can be found [here](https://pytorch-geometric.readthedocs.io/en/latest/notes/colabs.html).*\n", "\n", "In this tutorial session we will have a closer look at how to apply **Graph Neural Networks (GNNs) to the task of graph classification**.\n", - "Graph classification refers to the problem of classifiying entire graphs (in contrast to nodes), given a **dataset of graphs**, based on some structural graph properties.\n", + "Graph classification refers to the problem of classifying entire graphs (in contrast to nodes), given a **dataset of graphs**, based on some structural graph properties.\n", "Here, we want to embed entire graphs, and we want to embed those graphs in such a way so that they are linearly separable given a task at hand.\n", "\n", "\n", diff --git a/GraphNeuralNetworks/notebooks/graph_classification_solved.ipynb b/GraphNeuralNetworks/notebooks/graph_classification_solved.ipynb index e938c7a43..c2fcc8d71 100644 --- a/GraphNeuralNetworks/notebooks/graph_classification_solved.ipynb +++ b/GraphNeuralNetworks/notebooks/graph_classification_solved.ipynb @@ -7,10 +7,10 @@ "source": [ "# Graph Classification with Graph Neural Networks\n", "\n", - "*This noteboook is a julia adaptation of the Pytorch Geometric tutorials that can be found [here](https://pytorch-geometric.readthedocs.io/en/latest/notes/colabs.html).*\n", + "*This notebook is a julia adaptation of the Pytorch Geometric tutorials that can be found [here](https://pytorch-geometric.readthedocs.io/en/latest/notes/colabs.html).*\n", "\n", "In this tutorial session we will have a closer look at how to apply **Graph Neural Networks (GNNs) to the task of graph classification**.\n", - "Graph classification refers to the problem of classifiying entire graphs (in contrast to nodes), given a **dataset of graphs**, based on some structural graph properties.\n", + "Graph classification refers to the problem of classifying entire graphs (in contrast to nodes), given a **dataset of graphs**, based on some structural graph properties.\n", "Here, we want to embed entire graphs, and we want to embed those graphs in such a way so that they are linearly separable given a task at hand.\n", "\n", "\n", diff --git a/GraphNeuralNetworks/src/layers/conv.jl b/GraphNeuralNetworks/src/layers/conv.jl index ab038ea01..10a340e90 100644 --- a/GraphNeuralNetworks/src/layers/conv.jl +++ b/GraphNeuralNetworks/src/layers/conv.jl @@ -1,7 +1,7 @@ # The implementations of the forward pass of the graph convolutional layers are in the `GNNlib` module, # in the src/layers/conv.jl file. The `GNNlib` module is re-exported in the GraphNeuralNetworks module. # This annoying for the readability of the code, as the user has to look at two different files to understand -# the implementation of a single layer, +# the implementation of a single layer, # but it is done for GraphNeuralNetworks.jl and GNNLux.jl to be able to share the same code. @doc raw""" @@ -13,7 +13,7 @@ Performs the operation ```math \mathbf{x}'_i = \sum_{j\in N(i)} a_{ij} W \mathbf{x}_j ``` -where ``a_{ij} = 1 / \sqrt{|N(i)||N(j)|}`` is a normalization factor computed from the node degrees. +where ``a_{ij} = 1 / \sqrt{|N(i)||N(j)|}`` is a normalization factor computed from the node degrees. If the input graph has weighted edges and `use_edge_weight=true`, than ``a_{ij}`` will be computed as ```math @@ -32,7 +32,7 @@ and optionally an edge weight vector. - `init`: Weights' initializer. Default `glorot_uniform`. - `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. + 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`. @@ -41,11 +41,11 @@ and optionally an edge weight vector. (::GCNConv)(g::GNNGraph, x, edge_weight = nothing; norm_fn = d -> 1 ./ sqrt.(d), conv_weight = nothing) -> AbstractMatrix 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 +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. +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 @@ -58,7 +58,7 @@ g = GNNGraph(s, t) x = randn(Float32, 3, g.num_nodes) # create layer -l = GCNConv(3 => 5) +l = GCNConv(3 => 5) # forward pass y = l(g, x) # size: 5 × num_nodes @@ -70,8 +70,8 @@ y = l(g, x, w; norm_fn = custom_norm_fn) # 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) +l = GCNConv(3 => 5, use_edge_weight=true) +y = l(g, x) # same as l(g, x, w) ``` """ struct GCNConv{W <: AbstractMatrix, B, F} <: GNNLayer @@ -153,7 +153,7 @@ g = GNNGraph(s, t) x = randn(Float32, 3, g.num_nodes) # create layer -l = ChebConv(3 => 5, 5) +l = ChebConv(3 => 5, 5) # forward pass y = l(g, x) # size: 5 × num_nodes @@ -220,7 +220,7 @@ x = randn(Float32, 3, g.num_nodes) l = GraphConv(in_channel => out_channel, relu, bias = false, aggr = mean) # forward pass -y = l(g, x) +y = l(g, x) ``` """ struct GraphConv{W <: AbstractMatrix, B, F, A} <: GNNLayer @@ -267,10 +267,10 @@ where the attention coefficients ``\alpha_{ij}`` are given by ```math \alpha_{ij} = \frac{1}{z_i} \exp(LeakyReLU(\mathbf{a}^T [W \mathbf{x}_i; W \mathbf{x}_j])) ``` -with ``z_i`` a normalization factor. +with ``z_i`` a normalization factor. -In case `ein > 0` is given, edge features of dimension `ein` will be expected in the forward pass -and the attention coefficients will be calculated as +In case `ein > 0` is given, edge features of dimension `ein` will be expected in the forward pass +and the attention coefficients will be calculated as ```math \alpha_{ij} = \frac{1}{z_i} \exp(LeakyReLU(\mathbf{a}^T [W_e \mathbf{e}_{j\to i}; W \mathbf{x}_i; W \mathbf{x}_j])) ``` @@ -303,7 +303,7 @@ x = randn(Float32, 3, g.num_nodes) l = GATConv(in_channel => out_channel, add_self_loops = false, bias = false; heads=2, concat=true) # forward pass -y = l(g, x) +y = l(g, x) ``` """ struct GATConv{DX<:Dense,DE<:Union{Dense, Nothing},DV,T,A<:AbstractMatrix,F,B} <: GNNLayer @@ -370,8 +370,8 @@ where the attention coefficients ``\alpha_{ij}`` are given by ``` with ``z_i`` a normalization factor. -In case `ein > 0` is given, edge features of dimension `ein` will be expected in the forward pass -and the attention coefficients will be calculated as +In case `ein > 0` is given, edge features of dimension `ein` will be expected in the forward pass +and the attention coefficients will be calculated as ```math \alpha_{ij} = \frac{1}{z_i} \exp(\mathbf{a}^T LeakyReLU(W_3 \mathbf{e}_{j\to i} + W_2 \mathbf{x}_i + W_1 \mathbf{x}_j)). ``` @@ -407,7 +407,7 @@ l = GATv2Conv((in_channel, ein) => out_channel, add_self_loops = false) e = randn(Float32, ein, length(s)) # forward pass -y = l(g, x, e) +y = l(g, x, e) ``` """ struct GATv2Conv{T, A1, A2, A3, DV, B, C <: AbstractMatrix, F} <: GNNLayer @@ -456,7 +456,7 @@ function GATv2Conv(ch::Pair{NTuple{2, Int}, Int}, end b = bias ? Flux.create_bias(dense_i.weight, true, concat ? out * heads : out) : false a = init(out, heads) - return GATv2Conv(dense_i, dense_j, dense_e, + return GATv2Conv(dense_i, dense_j, dense_e, b, a, σ, negative_slope, ch, heads, concat, add_self_loops, dropout) end @@ -509,7 +509,7 @@ g = GNNGraph(s, t) l = GatedGraphConv(out_channel, num_layers) # forward pass -y = l(g, x) +y = l(g, x) ``` """ struct GatedGraphConv{W <: AbstractArray{<:Number, 3}, R, A} <: GNNLayer @@ -552,7 +552,7 @@ where `nn` generally denotes a learnable function, e.g. a linear layer or a mult # Arguments -- `nn`: A (possibly learnable) function. +- `nn`: A (possibly learnable) function. - `aggr`: Aggregation operator for the incoming messages (e.g. `+`, `*`, `max`, `min`, and `mean`). # Examples: @@ -602,7 +602,7 @@ where ``f_\Theta`` typically denotes a learnable function, e.g. a linear layer o # Arguments -- `f`: A (possibly learnable) function acting on node features. +- `f`: A (possibly learnable) function acting on node features. - `ϵ`: Weighting factor. # Examples: @@ -622,7 +622,7 @@ nn = Dense(in_channel, out_channel) l = GINConv(nn, 0.01f0, aggr = mean) # forward pass -y = l(g, x) +y = l(g, x) ``` """ struct GINConv{R <: Real, NN, A} <: GNNLayer @@ -647,9 +647,9 @@ end @doc raw""" NNConv(in => out, f, σ=identity; aggr=+, bias=true, init=glorot_uniform) -The continuous kernel-based convolutional operator from the -[Neural Message Passing for Quantum Chemistry](https://arxiv.org/abs/1704.01212) paper. -This convolution is also known as the edge-conditioned convolution from the +The continuous kernel-based convolutional operator from the +[Neural Message Passing for Quantum Chemistry](https://arxiv.org/abs/1704.01212) paper. +This convolution is also known as the edge-conditioned convolution from the [Dynamic Edge-Conditioned Filters in Convolutional Neural Networks on Graphs](https://arxiv.org/abs/1704.02901) paper. Performs the operation @@ -659,7 +659,7 @@ Performs the operation ``` 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)`, +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. @@ -695,7 +695,7 @@ x = randn(Float32, n_in, g.num_nodes) e = randn(Float32, n_in_edge, g.num_edges) # forward pass -y = l(g, x, e) +y = l(g, x, e) ``` """ struct NNConv{W, B, NN, F, A} <: GNNLayer @@ -764,7 +764,7 @@ g = GNNGraph(s, t) l = SAGEConv(in_channel => out_channel, tanh, bias = false, aggr = +) # forward pass -y = l(g, x) +y = l(g, x) ``` """ struct SAGEConv{W <: AbstractMatrix, B, F, A} <: GNNLayer @@ -815,7 +815,7 @@ where the edge gates ``\eta_{ij}`` are given by - `in`: The dimension of input features. - `out`: The dimension of output features. - `act`: Activation function. -- `init`: Weight matrices' initializing function. +- `init`: Weight matrices' initializing function. - `bias`: Learn an additive bias if true. # Examples: @@ -832,7 +832,7 @@ g = GNNGraph(s, t) l = ResGatedGraphConv(in_channel => out_channel, tanh, bias = true) # forward pass -y = l(g, x) +y = l(g, x) ``` """ struct ResGatedGraphConv{W, B, F} <: GNNLayer @@ -879,16 +879,16 @@ Performs the operation \mathbf{x}_i' = \mathbf{x}_i + \sum_{j\in N(i)}\sigma(W_f \mathbf{z}_{ij} + \mathbf{b}_f)\, act(W_s \mathbf{z}_{ij} + \mathbf{b}_s) ``` -where ``\mathbf{z}_{ij}`` is the node and edge features concatenation -``[\mathbf{x}_i; \mathbf{x}_j; \mathbf{e}_{j\to i}]`` +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 +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. +- `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. @@ -896,7 +896,7 @@ If `ein` is not given, assumes that no edge features are passed as input in the - `init`: Weights' initializer. - `residual`: Add a residual connection. -# Examples +# Examples ```julia g = rand_graph(5, 6) @@ -958,8 +958,8 @@ where the attention coefficients ``\alpha_{ij}`` are given by {\sum_{j'}e^{\beta \cos(\mathbf{x}_i, \mathbf{x}_{j'})}} ``` with the cosine distance defined by -```math -\cos(\mathbf{x}_i, \mathbf{x}_j) = +```math +\cos(\mathbf{x}_i, \mathbf{x}_j) = \frac{\mathbf{x}_i \cdot \mathbf{x}_j}{\lVert\mathbf{x}_i\rVert \lVert\mathbf{x}_j\rVert} ``` and ``\beta`` a trainable parameter if `trainable=true`. @@ -982,7 +982,7 @@ g = GNNGraph(s, t) l = AGNNConv(init_beta=2.0f0) # forward pass -y = l(g, x) +y = l(g, x) ``` """ struct AGNNConv{A <: AbstractVector} <: GNNLayer @@ -1007,7 +1007,7 @@ end Convolution from [Graph Networks as a Universal Machine Learning Framework for Molecules and Crystals](https://arxiv.org/pdf/1812.05055.pdf) paper. In the forward pass, takes as inputs node features `x` and edge features `e` and returns -updated features `x'` and `e'` according to +updated features `x'` and `e'` according to ```math \begin{aligned} @@ -1019,7 +1019,7 @@ updated features `x'` and `e'` according to `aggr` defines the aggregation to be performed. If the neural networks `ϕe` and `ϕv` are not provided, they will be constructed from -the `in` and `out` arguments instead as multi-layer perceptron with one hidden layer and `relu` +the `in` and `out` arguments instead as multi-layer perceptron with one hidden layer and `relu` activations. # Examples @@ -1076,10 +1076,10 @@ w^a_{k}(e^a) = \exp(-\frac{1}{2}(e^a - \mu^a_k)^T (\Sigma^{-1})^a_k(e^a - \mu^a_ 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 +The residual ``\mathbf{x}_i`` is added only if `residual=true` and the output size is the same as the input size. -# Arguments +# Arguments - `in`: Number of input node features. - `ein`: Number of input edge features. @@ -1088,7 +1088,7 @@ as the input size. - `K`: Number of kernels. Default `1`. - `bias`: Add learnable bias. Default `true`. - `init`: Weights' initializer. Default `glorot_uniform`. -- `residual`: Residual conncetion. Default `false`. +- `residual`: Residual connection. Default `false`. # Examples @@ -1097,7 +1097,7 @@ as the input size. s = [1,1,2,3] t = [2,3,1,1] g = GNNGraph(s,t) -nin, ein, out, K = 4, 10, 7, 8 +nin, ein, out, K = 4, 10, 7, 8 x = randn(Float32, nin, g.num_nodes) e = randn(Float32, ein, g.num_edges) @@ -1150,7 +1150,7 @@ end @doc raw""" SGConv(int => out, k=1; [bias, init, add_self_loops, use_edge_weight]) - + SGC layer from [Simplifying Graph Convolutional Networks](https://arxiv.org/pdf/1902.07153.pdf) Performs operation ```math @@ -1179,7 +1179,7 @@ g = GNNGraph(s, t) x = randn(Float32, 3, g.num_nodes) # create layer -l = SGConv(3 => 5; add_self_loops = true) +l = SGConv(3 => 5; add_self_loops = true) # forward pass y = l(g, x) # size: 5 × num_nodes @@ -1190,8 +1190,8 @@ y = l(g, x, w) # 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) +l = SGConv(3 => 5, add_self_loops = true, use_edge_weight=true) +y = l(g, x) # same as l(g, x, w) ``` """ struct SGConv{A <: AbstractMatrix, B} <: GNNLayer @@ -1228,7 +1228,7 @@ end TAGConv(in => out, k=3; bias=true, init=glorot_uniform, add_self_loops=true, use_edge_weight=false) TAGConv layer from [Topology Adaptive Graph Convolutional Networks](https://arxiv.org/pdf/1710.10370.pdf). -This layer extends the idea of graph convolutions by applying filters that adapt to the topology of the data. +This layer extends the idea of graph convolutions by applying filters that adapt to the topology of the data. It performs the operation: ```math @@ -1323,10 +1323,10 @@ computed as ``1/|\mathcal{N}(i)|``. - `hidden_size`: Hidden representation size. - `residual`: If `true`, add a residual connection. Only possible if `in == out`. Default `false`. -# Forward Pass +# Forward Pass l(g, x, h, e=nothing) - + ## Forward Pass Arguments: - `g` : The graph. @@ -1402,11 +1402,11 @@ end TransformerConv((in, ein) => out; [heads, concat, init, add_self_loops, bias_qkv, bias_root, root_weight, gating, skip_connection, batch_norm, ff_channels])) -The transformer-like multi head attention convolutional operator from the -[Masked Label Prediction: Unified Message Passing Model for Semi-Supervised -Classification](https://arxiv.org/abs/2009.03509) paper, which also considers +The transformer-like multi head attention convolutional operator from the +[Masked Label Prediction: Unified Message Passing Model for Semi-Supervised +Classification](https://arxiv.org/abs/2009.03509) paper, which also considers edge features. -It further contains options to also be configured as the transformer-like convolutional operator from the +It further contains options to also be configured as the transformer-like convolutional operator from the [Attention, Learn to Solve Routing Problems!](https://arxiv.org/abs/1706.03762) paper, including a successive feed-forward network as well as skip layers and batch normalization. @@ -1420,7 +1420,7 @@ where the attention scores are W_6e_{ij})}{\sqrt{d}}\right). ``` -Optionally, a combination of the aggregated value with transformed root node features +Optionally, a combination of the aggregated value with transformed root node features by a gating mechanism via ```math x'_i = \beta_i W_1 x_i + (1 - \beta_i) \underbrace{\left(\sum_{j \in \mathcal{N}(i)} @@ -1432,9 +1432,9 @@ with ``` can be performed. -# Arguments +# Arguments -- `in`: Dimension of input features, which also corresponds to the dimension of +- `in`: Dimension of input features, which also corresponds to the dimension of the output features. - `ein`: Dimension of the edge features; if 0, no edge features will be used. - `out`: Dimension of the output. @@ -1445,17 +1445,17 @@ can be performed. - `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 +- `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 +- `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 + number of hidden nodes; this NN also gets a skip connection and batch normalization if the respective parameters are set. Default: `0`. # Examples @@ -1468,7 +1468,7 @@ l = TransformerConv((in_channel, ein) => in_channel; heads, gating = true, bias_ x = rand(Float32, in_channel, N) e = rand(Float32, ein, g.num_edges) l(g, x, e) -``` +``` """ struct TransformerConv{TW1, TW2, TW3, TW4, TW5, TW6, TFF, TBN1, TBN2} <: GNNLayer W1::TW1