Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modularising models #40

Merged
merged 45 commits into from
Nov 9, 2021
Merged

Conversation

asogaard
Copy link
Collaborator

Hi @RasmusOrsoe and @mhaminh,

I am creating this (massive) pull request as an initial proposal for how we can structure model building in a flexible, modular fashion. The main contribution of this PR is the creation of separate Detector, GNN, and Task classes that are chained together through the model Model class. You can see what this looks like in examples/test_model_training_sqlite.py. This way:

  1. Different objectives (detector-specific data ingestion and preprocessing; GNN model building; and task-specific readout), respectively, are handled by dedicated, restricted classes that can be switched out in a plug-and-play fashion
  2. Code duplication (e.g. graph building, read-out) is reduced between models
  3. Comparing different model architectures 1:1 becomes as easy as switching GNN=DynEdge(**kwargs) to GNN=ConvNet(**kwargs)
  4. There is less boilerplate/overhead required to develop, implement, and test novel GNN architectures in the future
  5. Applying existing GNN architectures to novel tasks becomes close to trivial, as it just requires switching the task(s) parameter in Model.
  6. Etc.

All I have done is tried to take the common bits from your respective models and make dedicated, common classes for these; and take the unique bits and turn them into separate classes inheriting from GNN.

@RasmusOrsoe: The only non-trivial (intentional, at least) difference wrt. the previous modelling code is that I have commented out the re-calculation of graph connectivity at each message-passing layer in ConvNet because I have tried to relegate graph-building to the detector-specific read-in layer much like @mhaminh has been doing. We can discuss whether we should prioritise supporting the other functionality as well.

Please take provide as many and as detailed comments as you want; and if we feel like this is a promising direction to pursue I will do my best to update the PR to everyone's liking.

NB: I haven't touched the Trainer/Predictor classes, which may be handled by pytorch-lightning, but we can explore/discuss that in a separate PR.

@asogaard asogaard added the feature New feature or request label Oct 26, 2021
@asogaard asogaard self-assigned this Oct 26, 2021
@asogaard asogaard added this to Review in Initial repository setup via automation Oct 26, 2021
@troelspetersen
Copy link
Contributor

troelspetersen commented Oct 26, 2021 via email

Copy link
Collaborator

@RasmusOrsoe RasmusOrsoe left a comment

Choose a reason for hiding this comment

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

I quite like this.

However, it is absolutely neccesary for the edge_indicies to be recalculated on the fly in DynEdge. thats the "Dyn" in DynEdge. We have no idea how this change effects the performance and it's something I feel strongly we should not mess with.

Also, I cannot see how we get to play around with preprocessing - the scalers seems to have been replaced with some static code? Maybe we should talk about this - it kind of breaks the work I'm doing for the paper.

Also, two minor things:

Lets please keep the original logcosh loss function also (we can have both the original one and the approximated one)

How do we handle loss-function specific final activation functions? Currently it seems like we have lost the vonmisesfisher-required tanh(x) activation functions in the angular task.

Rasmus

src/gnn_reco/components/loss_functions.py Show resolved Hide resolved
src/gnn_reco/models/detector/icecube86.py Show resolved Hide resolved
src/gnn_reco/models/task/reconstruction.py Outdated Show resolved Hide resolved
src/gnn_reco/models/task/task.py Show resolved Hide resolved
src/gnn_reco/models/task/reconstruction.py Outdated Show resolved Hide resolved
@asogaard
Copy link
Collaborator Author

asogaard commented Nov 3, 2021

Hi @RasmusOrsoe,
Thanks for the thorough comments and review! I have now added some additional commits that should address all of your major comments. Specifically:

  • I have added the DynEdgeConv class and used it in the DynEdge GNN model such that now it is dynamical again!
  • I have added support for manually fitted scalers in the Detector class, which can override the "standard" preprocessing for each detector.
    • NB: Scalers are only applied to features, not targets!
  • I have reinstated dedicated LegacyAngularReconstruction and LegacyVonMisesFisherLoss classes that should reproduce exactly the original results.
    • The only difference is that targets are not scaled. For angular reconstruction I figure this is fine, as there is probably no need to scale targets that are in the range [0, π] or [0, 2π]. Let me know if you have a different view. For energy reconstruction this can be done using the transform_output argument to all classes inheriting from LossFunction. E.g. if you want to log-scale energies, this could be reproduced as LogCoshLoss(transform_output=lambda energy: torch.log10(energy), ...
  • I have added the general VonMisesFisherLoss class that allows for the exact calculation of vMF for vectors of any dimension, and have implemented it specifically for a single angle through the VonMisesFisher2DLoss class.
    Please have look through the new commits and let me know if there is anything that should be reworked.

@asogaard
Copy link
Collaborator Author

asogaard commented Nov 9, 2021

Hi @RasmusOrsoe,
As agreed I have made a straight copy of the functions currently used for the paper in src/gnn_reco/legacy/original.py and included a separate example script to run this training (examples/test_legacy_model_training.py). In addition, I have moved the re-implementation of some of this functionality in the new structure into src/gnn_reco/legacy/reimplemented.py (with no iron-clad guarantees yet of 1:1 agreement). Please have a look through the latest commits, as well as the PR as a whole, and once you're happy (and all tests pass) I propose we merge these change to allow us to move on to other tasks (Upgrade MC, further refactoring, etc.)

Closes #45 and #43. Enables #44

@asogaard asogaard removed the request for review from mhaminh November 9, 2021 14:54
Copy link
Collaborator

@RasmusOrsoe RasmusOrsoe left a comment

Choose a reason for hiding this comment

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

Looks good!


# Calculate homophily (scalar variables)
h_x, h_y, h_z, h_t = calculate_xyzt_homophily(x, edge_index, batch)

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not my model! We need to recalculate the connectivity between each convolutional pass!

Its a central point of the approach (See https://arxiv.org/abs/1801.07829)

@RasmusOrsoe RasmusOrsoe merged commit cf3cc52 into graphnet-team:main Nov 9, 2021
Initial repository setup automation moved this from Review to Done Nov 9, 2021
@asogaard asogaard deleted the modularising-models branch November 11, 2021 08:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

None yet

3 participants