Add hooks for indirect learning. - #1209
Conversation
Luthaf
left a comment
There was a problem hiding this comment.
I think the hook idea makes sense and can be very useful!
One question though: is it a hook job to take per atom prediction and make it per-system? It kinda look like this is the case here? Or I might have misunderstood the example
|
|
||
| # Build the input target that we will request from the model, | ||
| # which is the local multipoles | ||
| self._input_name = "mtt::aux::local_multipoles" |
There was a problem hiding this comment.
it would be useful to have some documentation about the custom metatrain outputs somewhere, especially if we start using them across multiple architectures with theses hooks. (Even better, standardizing what makes sense at the metatomic level!)
|
Thanks!
There could be a hook to do that, specially for cases when the aggregation is not simply a sum, but something more complicated like softmin/max for the bandgaps. I guess the case of the global dipoles can be seen as that, we are doing |
|
I guess indeed with standardization of outputs these hooks might become applied by default when needed, instead of the user having to specify them. |
|
@cesaremalosso I have added the hook to produce gap-like targets. I have been testing it and seems to work with both PET (thanks to Joe) and MACE, give it a test when you can :) I basically copied the functionality that you had in your branch, and now there's a hook called The way of using it is: architecture:
name: pet | experimental.mace
model:
...other model hypers
post_hooks:
minmax_gap: mtt::gap_energy
training:
atomic_baseline: {mtt::gap_energy: 0.0}
...whatever
training_set:
systems: train_structures.xyz
targets:
mtt::gap_energy:
quantity: energy
key: Gap_energy
sample_kind: system
type: scalar
forces:
key: Gap_forcesalso you can tune the hook further with something like: post_hooks:
minmax_gap:
outputs: mtt::gap_energy
pooling: {type: softmax}Let me know if it works fine! |
|
Hmm for the gap case the composition model needs to be disabled, I wonder if this should be the job of the hook to warn about this. It certainly complicates things 😅 |
|
Also Cesare is asking if one could do finetuning of an MLIP by adding these hooks, and I see no easy way, since right now the hooks are specified as model hypers, which are not used when finetuning I think (?) So maybe the right design of a UI would be that users specify these hooks in the target itself: targets:
mtt::gap_energy:
...target specification
quantity: intensive_gap # Or whatever way of specifying it.this would make it cleaner for the composition model to avoid this target and for the finetuning to detect it, and probably also be in the spirit of metatrain of "we should require as litle knowledge from users". But then some cases become more complicated, like when a hook has hyperparameters or when a hook produces multiple outputs (e.g. a diagonalization hook that produces eigenvalues, eigenvectors, density matrices, and other electronic structure properties). In general, passing the category in the targets results in a less flexible UI I think, for the good and for the bad 😅 |
|
Geeez, this looks very complicated, but also very useful. So the idea is that you can specify generic modules to be applied after a head? I think that defining them in the targets as |
|
In essence it is what you are saying, and very similar to the approach of metatomic to define wrappers, except these hooks work also during training. Now the problem is that I don't know what is the best way to expose it to the users. In the way metatrain does things, I believe it has to be fully controlled by the architecture. So specifying a full hook in the target seems a bit strange, as some architectures might not want to use that hook (for example a
But then you lose quite some flexibility (do we want that flexibility?). Specifying the full hook in the target would indeed require modifying |
|
Ok so with this we have the three examples that I had in mind for hooks:
The other two that I had involve matrices (graph2mat hook and eigenvalues hook) so they can't be added yet. If someone has more use cases let me know and let's add them. Then once we have all the examples I'll start refining the implementation. |
|
I think the matrix use case is sufficiently complex and useful to consider here in the design (even if not directly implementable yet from the current state of main) as it is different from the others: for the Hamiltonian, for example, we might want to directly and indirectly learn on it simultaneously (i.e. H in the loss function as well as derived eigs and DM), and the basis set still needs passing somehow to the model. This is different from the total dipole, for instance, where the dimensions of the indirectly learned charges and vector contributions are predetermined, there is no reference data for them, and they only enter the loss as a derived quantity (i.e. no term explicitly on them) |
|
Yes, the basis information will be passed through |
Ok good good. A small side note to be aware of: we need to make sure that the hooks are compatible with the optional dependencies installed by the user. Currently when I install with just the base dependencies (i.e. for PET) I get a |
|
Yeah I thought about this, probably optional dependencies for hooks should be in |
* fix output block with cuda values but cpu labels * Move layout's device once at the top --------- Co-authored-by: Pol Febrer Calabozo <42074085+pfebrer@users.noreply.github.com>
|
Ok so this got x10 more complex to review haha it's probably best to explain in person. Essentially we realised that at some point we would need checkpoint updates, things need to be properly documented, well tested, etc... so I decided to follow the same design as with architectures (folder for each hook, automatic documentation, common tests...). Still not finished, but decided to push so that people can modify the hooks in this new setup. I'm happy because the hooks seem like a very nice way to release code when people publish papers, which has been a bit of a problem lately since modifying an architecture is not easy. The barrier for making it serious enough for a hook is lower and there is no friction with architecture maintainers. |
This is done by storing the hooks in DatasetInfo instead of in the model hypers. To do this, hooks config is moved to a top level "hooks" in the yaml file. There are still things to do, like supporting finetuning a model that already has hooks, but with this people can already do first tests.
Removed post_hooks parameter from TrainerHypers.
…in dependent version accessible

After discussion with @ppegolo we agreed that the cleanest way to implement indirect learning in metatrain was through hooks that run at the end of the model.
Why a hook solves things: If you ask for a target to be produced by a hook, the hook will (1) remove the target from the outputs that the model should produce and (2) add the hook's inputs as extra outputs that the model has to produce.
Proof of concept: I implemented a hook to compute global multipoles from local predictions, since this is one of the use cases that needed the functionality. The idea is that architectures fully control these things, in the spirit of metatrain. You can see the proof of concept implementation in MACE. I would like to first get some feedback before continuing. Hopefully at this point it is simple enough to understand it easily.
The input yaml: Here is an input yaml to learn dipoles through the
global_multipoleshook.Here is the dataset with dipoles: QM7X_train_1024.zip
Of course one can train direct targets at the same time as the indirect dipole.
📚 Documentation preview 📚: https://metatrain--1209.org.readthedocs.build/en/1209/