Module implementing Kipf & Welling Graph Convolutional Network (GCN)
This module implements the graph convolutional layer from Kipf & Welling (2017) with symmetric degree normalisation for semi-supervised learning.
Mathematical operation:
where: * (adjacency matrix with added self-loops) * is the degree matrix of * is the node feature matrix at layer l * is a learnable weight matrix * is the activation function
The normalisation ensures proper scaling by degree. Preserves graph structure, producing node-level (not graph-level) outputs.
Reference: Kipf & Welling (2017), ICLR
Interface for setting up the MPNN layer
Set up the message passing layer
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in), | dimension(:) | :: | num_vertex_features |
Number of features |
|
| integer, | intent(in) | :: | num_time_steps |
Number of time steps |
||
| class(*), | intent(in), | optional | :: | activation |
Activation function and kernel initialiser |
|
| class(*), | intent(in), | optional | :: | kernel_initialiser |
Activation function and kernel initialiser |
|
| integer, | intent(in), | optional | :: | verbose |
Verbosity level |
Instance of the message passing layer
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| class(base_actv_type), | public, | allocatable | :: | activation |
Activation function |
||
| class(base_init_type), | public, | allocatable | :: | bias_init |
Initialisers for kernel and bias |
||
| character(len=14), | public | :: | bias_initialiser | = | '' |
Initialisers for kernel and bias |
|
| integer, | public, | allocatable, dimension(:) | :: | bias_shape |
Shape of biases |
||
| type(graph_type), | public, | allocatable, dimension(:) | :: | graph |
Graph structure of input data |
||
| integer, | public | :: | id |
Unique identifier |
|||
| logical, | public | :: | inference | = | .false. |
Inference mode |
|
| integer, | public | :: | input_rank | = | 0 |
Rank of input data |
|
| integer, | public, | allocatable, dimension(:) | :: | input_shape |
Input shape |
||
| class(base_init_type), | public, | allocatable | :: | kernel_init |
Initialisers for kernel and bias |
||
| character(len=14), | public | :: | kernel_initialiser | = | '' |
Initialisers for kernel and bias |
|
| character(len=:), | public, | allocatable | :: | name |
Layer name |
||
| integer, | public, | dimension(:), allocatable | :: | num_edge_features |
Number of edge features for each time step |
||
| integer, | public | :: | num_output_edge_features |
Number of output edge features |
|||
| integer, | public | :: | num_output_vertex_features |
Number of output vertex features |
|||
| integer, | public | :: | num_outputs |
Number of outputs (if output is not graph structure) |
|||
| integer, | public | :: | num_params | = | 0 |
Number of learnable parameters |
|
| integer, | public, | dimension(:), allocatable | :: | num_params_msg |
Number of learnable parameters for each message |
||
| integer, | public | :: | num_params_readout |
Number of learnable parameters for the readout |
|||
| integer, | public | :: | num_time_steps |
Number of time steps |
|||
| integer, | public, | dimension(:), allocatable | :: | num_vertex_features |
Number of vertex features for each time step |
||
| class(array_type), | public, | allocatable, dimension(:,:) | :: | output |
Output |
||
| integer, | public | :: | output_rank | = | 0 |
Rank of output data |
|
| integer, | public, | allocatable, dimension(:) | :: | output_shape |
Output shape |
||
| type(array_type), | public, | allocatable, dimension(:) | :: | params |
Learnable parameters |
||
| character(len=20), | public | :: | subtype | = | repeat(" ", 20) | ||
| character(len=4), | public | :: | type | = | 'base' |
Layer type |
|
| logical, | public | :: | use_bias | = | .false. |
Layer has bias |
|
| logical, | public | :: | use_graph_input | = | .false. |
Use graph input |
|
| logical, | public | :: | use_graph_output | = | .false. |
Use graph output |
|
| integer, | public, | allocatable, dimension(:,:) | :: | weight_shape |
Shape of weights |
Interface for setting up the MPNN layer
| private module function layer_setup (num_vertex_features, num_time_steps, activation, kernel_initialiser, verbose) | Set up the message passing layer |
| procedure, public :: add_t_t => add_learnable | Add two layers |
| procedure, public, pass(this) :: build_from_onnx => build_from_onnx_base | Build layer from ONNX node and initialiser |
| procedure, public, pass(this) :: emit_onnx_graph_inputs => emit_onnx_graph_inputs_base | Emit graph input tensor declarations for this layer |
| procedure, public, pass(this) :: emit_onnx_nodes => emit_onnx_nodes_kipf | Emit ONNX JSON nodes for Kipf GCN layer |
| procedure, public, pass(this) :: extract_output => extract_output_base | Extract the output of the layer as a standard real array |
| procedure, public, pass(this) :: forward => forward_msgpass | Forward pass for message passing layer |
| procedure, public, pass(this) :: forward_eval => forward_eval_base | Forward pass of layer and return output for evaluation |
| procedure, public, pass(this) :: get_attributes => get_attributes_kipf | Get the attributes of the layer (for ONNX export) |
| procedure, public, pass(this) :: get_gradients | Get parameter gradients of layer |
| procedure, public, pass(this) :: get_num_params => get_num_params_kipf | Get the number of parameters for the message passing layer |
| procedure, public, pass(this) :: get_params | Get learnable parameters of layer |
| procedure, public, pass(this) :: init => init_kipf | Initialise the message passing layer |
| procedure, public, pass(this) :: nullify_graph => nullify_graph_base | Nullify the forward pass data of the layer to free memory |
| generic, public :: operator(+) => add_t_t | Operator overloading for addition |
| procedure, public, pass(this) :: print => print_base | Print the layer to a file with additional information |
| procedure, public, pass(this) :: print_to_unit => print_to_unit_kipf | Print the message passing layer |
| procedure, public, pass(this) :: read => read_kipf | Read the message passing layer |
| procedure, public, pass(this) :: reduce => reduce_learnable | Merge another learnable layer into this one |
| procedure, public, pass(this) :: set_gradients | Set learnable parameters of layer |
| procedure, public, pass(this) :: set_graph => set_graph_msgpass | |
| procedure, public, pass(this) :: set_hyperparams => set_hyperparams_kipf | Set the hyperparameters for the message passing layer |
| procedure, public, pass(this) :: set_params | Set learnable parameters of layer |
| procedure, public, pass(this) :: set_rank => set_rank_base | Set the input and output ranks of the layer |
| procedure, public, pass(this) :: set_shape => set_shape_base | Set the input shape of the layer |
| procedure, public, pass(this) :: update_message => update_message_kipf | Update the message |
| procedure, public, pass(this) :: update_readout => update_readout_kipf | Update the readout |
Read kipf message passing layer from file and return layer
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | unit |
Unit number |
||
| integer, | intent(in), | optional | :: | verbose |
Verbosity level |
Instance of the message passing layer
Get the attributes of the Kipf GCN layer (for ONNX export)
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(kipf_msgpass_layer_type), | intent(in) | :: | this |
Instance of the message passing layer |
Attributes for ONNX export
Get the number of parameters for the message passing layer
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(kipf_msgpass_layer_type), | intent(in) | :: | this |
Instance of the message passing layer |
Number of parameters
Set up the message passing layer
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in), | dimension(:) | :: | num_vertex_features |
Number of features |
|
| integer, | intent(in) | :: | num_time_steps |
Number of time steps |
||
| class(*), | intent(in), | optional | :: | activation |
Activation function and kernel initialiser |
|
| class(*), | intent(in), | optional | :: | kernel_initialiser |
Activation function and kernel initialiser |
|
| integer, | intent(in), | optional | :: | verbose |
Verbosity level |
Instance of the message passing layer
Emit ONNX nodes for one Kipf GCN time step.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | prefix | |||
| integer, | intent(in) | :: | t | |||
| integer, | intent(in) | :: | nv_in | |||
| integer, | intent(in) | :: | nv_out | |||
| real(kind=real32), | intent(in) | :: | weight_data(:) | |||
| character(len=*), | intent(in) | :: | activation_name | |||
| type(onnx_node_type), | intent(inout), | dimension(:) | :: | nodes | ||
| integer, | intent(inout) | :: | num_nodes | |||
| integer, | intent(in) | :: | max_nodes | |||
| type(onnx_initialiser_type), | intent(inout), | dimension(:) | :: | inits | ||
| integer, | intent(inout) | :: | num_inits | |||
| integer, | intent(in) | :: | max_inits | |||
| character(len=128), | intent(out) | :: | vertex_out |
Emit ONNX JSON nodes for Kipf GCN layer
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(kipf_msgpass_layer_type), | intent(in) | :: | this |
Instance of the layer |
||
| character(len=*), | intent(in) | :: | prefix |
Node name prefix (e.g. "node_2") |
||
| type(onnx_node_type), | intent(inout), | dimension(:) | :: | nodes |
Accumulator for ONNX nodes |
|
| integer, | intent(inout) | :: | num_nodes |
Current number of nodes |
||
| integer, | intent(in) | :: | max_nodes |
Maximum capacity |
||
| type(onnx_initialiser_type), | intent(inout), | dimension(:) | :: | inits |
Accumulator for ONNX initialisers |
|
| integer, | intent(inout) | :: | num_inits |
Current number of initialisers |
||
| integer, | intent(in) | :: | max_inits |
Maximum capacity |
||
| character(len=*), | intent(in), | optional | :: | input_name |
Unused sequential input name |
|
| logical, | intent(in), | optional | :: | is_last_layer |
Unused last-layer flag |
|
| integer, | intent(in), | optional | :: | format |
Unused export format selector |
Initialise the message passing layer
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(kipf_msgpass_layer_type), | intent(inout) | :: | this |
Instance of the fully connected layer |
||
| integer, | intent(in), | dimension(:) | :: | input_shape |
Input shape |
|
| integer, | intent(in), | optional | :: | verbose |
Verbosity level |
Print kipf message passing layer to unit
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(kipf_msgpass_layer_type), | intent(in) | :: | this |
Instance of the message passing layer |
||
| integer, | intent(in) | :: | unit |
File unit |
Read the message passing layer
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(kipf_msgpass_layer_type), | intent(inout) | :: | this |
Instance of the message passing layer |
||
| integer, | intent(in) | :: | unit |
Unit to read from |
||
| integer, | intent(in), | optional | :: | verbose |
Verbosity level |
Set the hyperparameters for the message passing layer
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(kipf_msgpass_layer_type), | intent(inout) | :: | this |
Instance of the message passing layer |
||
| integer, | intent(in), | dimension(:) | :: | num_vertex_features |
Number of vertex features |
|
| integer, | intent(in) | :: | num_time_steps |
Number of time steps |
||
| class(base_actv_type), | intent(in), | allocatable | :: | activation |
Activation function |
|
| class(base_init_type), | intent(in), | allocatable | :: | kernel_initialiser |
Kernel initialiser |
|
| integer, | intent(in), | optional | :: | verbose |
Verbosity level |
Update the message
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(kipf_msgpass_layer_type), | intent(inout), | target | :: | this |
Instance of the message passing layer |
|
| class(array_type), | intent(in), | dimension(:,:), target | :: | input |
Input to the message passing layer |
Update the readout (empty for node-level output)
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(kipf_msgpass_layer_type), | intent(inout), | target | :: | this |
Instance of the message passing layer |