Multigraph neural networks in Julia

GeometricFlux.jl (Convolutional Layers · GeometricFlux.jl) and GraphNeuralNetworks.jl (Convolutional Layers · GraphNeuralNetworks.jl) both implement a layer based on the Crystal Graph Convolutional Neural Network (CGCNN)(Phys. Rev. Lett. 120, 145301 (2018) - Crystal Graph Convolutional Neural Networks for an Accurate and Interpretable Prediction of Material Properties).

The CGCNN architecture is usually defined over a multi-graph, where a pair of nodes might have multiple connecting edges, and each edge has a different encoding vector. Is this input datatype supported in current Julia graph network packages; or, failing that, is it easily implemented? Light searching has revealed a separate Multigraph.jl package (GitHub - QuantumBFS/Multigraphs.jl: A multigraph extension of LightGraphs.jl) that is not (perhaps?) integrated into the general Graphs ecsystem.

It’s not obvious that the GNNGraph type (GraphNeuralNetworks.jl/gnngraph.jl at master · CarloLucibello/GraphNeuralNetworks.jl · GitHub) in GraphNeuralNetworks.jl supports multigraphs, but I might be missing something obvious.

All I can do is pattern match on “CGCNN”, but does GitHub - Chemellia/AtomicGraphNets.jl: Atomic graph models for molecules and crystals in Julia meet your use case?

It does, but it should be made more explicit indeed. In order to construct a GNNGraph with multi-edges you cannot go through a Graphs.jl graph but you explicitly give the source and target nodes:

julia> using GraphNeuralNetworks

julia> s =  [1,1,2,3];

julia> t = [2,2,2,4];     # we have both multi-edges and self-edges

julia> g = GNNGraph(s, t)
GNNGraph:
    num_nodes = 4
    num_edges = 4
    num_graphs = 1
    ndata:
    edata:
    gdata:

julia> x = rand(Float32, 2, g.num_nodes)
2×4 Matrix{Float32}:
 0.00534022  0.873903  0.757006   0.235914
 0.0701774   0.788159  0.0483252  0.217582

julia> e = rand(Float32, 3, g.num_edges)
3×4 Matrix{Float32}:
 0.801664  0.531405  0.810002   0.690981
 0.158637  0.630085  0.830421   0.19566
 0.579666  0.750919  0.0782821  0.926121

julia> conv = CGConv((2,3) => 4, tanh)
CGConv((2, 3) => 4, tanh, residual=false)

julia> y = conv(g, x, e) 
4×4 Matrix{Float32}:
 0.0  -0.24086    0.0  -0.0644639
 0.0  -1.03614    0.0   0.0932009
 0.0  -1.30664    0.0  -0.45532
 0.0  -0.0407019  0.0   0.0959732
1 Like

@CarloLucibello it seems that there might be an error in the has_multi_edges function (or I’m misunderstanding its use):

using GraphNeuralNetworks
s =  [1,1,2,3];
t = [2,2,2,4];
g = GNNGraph(s, t);

has_multi_edges(g)  # evaluates as `false`
2 Likes

thanks for reporitng this, being fixed in fix has_multi_edges by CarloLucibello · Pull Request #75 · CarloLucibello/GraphNeuralNetworks.jl · GitHub

2 Likes