Skip to content

Add directed hypergraph layers and Cora node classification example - #15

Open
shonalidixit wants to merge 3 commits into
CoReACTER:mainfrom
shonalidixit:shonali-lux-layer
Open

Add directed hypergraph layers and Cora node classification example#15
shonalidixit wants to merge 3 commits into
CoReACTER:mainfrom
shonalidixit:shonali-lux-layer

Conversation

@shonalidixit

Copy link
Copy Markdown
Contributor

This PR adds several additional directed hypergraph neural network layers, together with their associated tests and documentation.

It also adds an end-to-end Cora node classification proof of concept under examples/cora_node_classification.jl. The example represents the citation network using separate tail and head incidence matrices and uses DirectedHypergraphLayer for directed message passing.

The Cora example includes:

  • data loading and preprocessing
  • construction of tail/head incidence representations
  • stratified train/validation/test splitting
  • directed hypergraph neural network setup
  • Enzyme-based automatic differentiation
  • Adam optimisation and model training
  • validation and test evaluation
  • confusion matrix and per-class performance reporting

With a 64-dimensional hidden representation and 100 training epochs, the current run achieved:

  • Training accuracy: 98.64%
  • Validation accuracy: 85.71%
  • Test accuracy: 85.22%

For the current proof of concept, the incidence matrices are passed directly to DirectedHypergraphLayer. Integration between the layers and HGNNDiHypergraph can be addressed separately.

Extends DirectedHypergraphAttentionLayer with user defined num_heads.

preserves existing single-head behaviour with num_heads = 1
adds independent parameters for each attention head
concatenates head outputs and projects them back to hidden_dim
updates documentation
expands tests for multi-head forward passes, attention normalisation, parameter shapes, and validation

Full test suite passes.
Adds additional directed hypergraph layers with tests and documentation along with an end to end Cora node classification proof of concept using Enzyme for automatic differentiation

@espottesmith espottesmith left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some areas where more documentation would be helpful. Lots of code duplication. Seems like the example is unnecessarily long and probably should be broken up into multiple files. But damn, this is a huge body of work! I so greatly appreciate this contribution.

Comment thread Project.toml
uuid = "1aebdcae-dc77-44ee-b348-f058d326ae63"
authors = ["Evan Walter Clark Spotte-Smith", "Punna Amornvivat"]
version = "0.0.1-DEV"
authors = ["Evan Walter Clark Spotte-Smith", "Punna Amornvivat"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, you should absolutely list yourself as an author.


This allows the two roles in a directed hyperedge to be modelled differently
throughout the complete message-passing step.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Follow the naming convention for new files.
  2. You should explain how this is different from the existing message passing layer (or at least put enough detail in this docstring such that an average user can read both and see the difference).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, also, how does this treat cases where a vertex v is in both the tail and the head of a dihyperedge?

Comment on lines +102 to +116
function _asymmetric_initialise_weight(
initializer,
rng::AbstractRNG,
input_dimension::Int,
output_dimension::Int,
)
return permutedims(
initializer(
rng,
output_dimension,
input_dimension,
),
)
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks identical to _initialize_weight. Am I missing something?

Also, does this function belong here? Is it likely to only be used by layers in this file, or does it belong in more of a utility file elsewhere? Should it be exported?

Comment on lines +118 to +130
function _asymmetric_initialise_bias(
initializer,
rng::AbstractRNG,
output_dimension::Int,
)
return permutedims(
initializer(
rng,
output_dimension,
1,
),
)
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above. Is this actually providing anything new?

Comment on lines +308 to +319
function _asymmetric_unpack_input(
::AsymmetricDirectedHypergraphLayer,
input::Tuple,
)
throw(
ArgumentError(
"The layer expects either " *
"(X_vertex, source_matrix, target_matrix) or " *
"(X_vertex, X_hyperedge, source_matrix, target_matrix).",
),
)
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the user provides something that isn't a Tuple?

Comment on lines +21 to +24
A learnable gate controls the balance between the information received
through hypergraph message passing and the transformed representation of the
vertex itself. Each hidden feature has its own gate value between zero and
one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this come from? Has this been reported in the literature before? This goes for all of the layers you've made. I know you said you haven't copied from other sources, but even so, if these ideas have been published, we should give credit and references so readers/users can get more information

Comment on lines +110 to +138
function _gated_initialise_weight(
initializer,
rng::AbstractRNG,
input_dimension::Int,
output_dimension::Int,
)
return permutedims(
initializer(
rng,
output_dimension,
input_dimension,
),
)
end


function _gated_initialise_bias(
initializer,
rng::AbstractRNG,
output_dimension::Int,
)
return permutedims(
initializer(
rng,
output_dimension,
1,
),
)
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code duplication

Comment on lines +141 to +144
function Lux.initialparameters(
rng::AbstractRNG,
layer::GatedDirectedHypergraphLayer,
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some code duplication in these initialization functions, as well.

Comment on lines +1 to +2
using Lux
using Random

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as a heads up: you shouldn't need to do imports in each file. Anything you globally import in the package file HyperGraphNeuralNetworks.jl should also be available to all modules within the package.

Comment on lines +17 to +18
The layer preserves the source and target roles of vertices while adding a
residual connection to the vertex update. Directed information is first

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "residual connection" mean here? What does "preserv[ing] the [...] roles" mean? Kind of a vague description.

@espottesmith

Copy link
Copy Markdown
Member

Oh, just a heads up: I skipped the tests for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants