Skip to content

Check input model hypers when restarting trainings - #1232

Open
pfebrer wants to merge 5 commits into
metatensor:mainfrom
pfebrer:restart_model_hypers
Open

Check input model hypers when restarting trainings#1232
pfebrer wants to merge 5 commits into
metatensor:mainfrom
pfebrer:restart_model_hypers

Conversation

@pfebrer

@pfebrer pfebrer commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

This is a first design of something that was discussed today in the devel meeting.

When restarting, it should be checked that if the user has provided model hypers in the input yaml, those match the hypers present in the checkpoint.

This enables the possibility that in the future, architectures will allow not only perfect matches, but also updating the model to some compatible hypers. This is for example the case in #1209 , which is what spawned the discussion leading to this PR.

@Luthaf @PicoCentauri could you check if something like this would work?


📚 Documentation preview 📚: https://metatrain--1232.org.readthedocs.build/en/1232/

return self.outputs

def restart(self, dataset_info: DatasetInfo) -> "PET":
def restart(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, I think this this is the canoncial place! Very good.

_OVERWRITTEN_DEFAULTS[hypers_cls] = new_defaults


def get_hypers_diff(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Isn't there a function already from the libraries that we use?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes I will check Omegaconf, this was just so that it was clear what I propose to do

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok, so apparently neither omegaconf or pydantic have such a functionality, and since we are just checking a shallow diff I think it is fine to have this simple function here

return diff


def raise_hypers_mismatch(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same here. I would think there is already something. But maybe I am wrong.

Comment on lines +116 to +119
for key, new_value in new_hypers.items():
old_value = old_hypers[key]
if old_value != new_value:
diff[key] = (old_value, new_value)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does a single loop work if there are deeply nested dictionaries?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Depends on what you mean by "work". It will detect that the dictionaries are different if there is a difference somewhere deep in the keys. But it will include still all the deep keys that are the same. My idea was that dealing with arbitrary nested keys is a bit of a mess and perhaps we can introduce it whenever some model needs it? For example, for the user the top-level key that changed is likely enough to report in the error.

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.

Ok I think this answers my other question: order doesn't matter, right?

@Luthaf

Luthaf commented Jul 31, 2026

Copy link
Copy Markdown
Member

the overall design looks good to me!

@pfebrer

pfebrer commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Ok this is ready for a final review

@pfebrer
pfebrer force-pushed the restart_model_hypers branch from 6f2c41b to be37440 Compare July 31, 2026 15:31

@jwa7 jwa7 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.

I think this looks good and I like what it enables, but I want to question how restrictive this is. For instance one of the current CI failure looks like:

[Mismatch 1] soap
 Previous: {'max_angular': 2, 'max_radial': 4, 'cutoff': {'radius': 5.0, 'width': 0.5}}
 New: {'max_radial': 4, 'max_angular': 2}

and I'm wondering if this is what we want - are implied default hypers no longer acceptable?

# This should work, as we are not changing the hypers
model.restart(dataset_info=dataset_info)
model.restart(dataset_info=dataset_info, model_hypers={})
model.restart(dataset_info=dataset_info, model_hypers=minimal_model_hypers)

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.

How about same hypers but in a different order?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We can add the check just in case

Comment on lines +116 to +119
for key, new_value in new_hypers.items():
old_value = old_hypers[key]
if old_value != new_value:
diff[key] = (old_value, new_value)

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.

Ok I think this answers my other question: order doesn't matter, right?

@pfebrer

pfebrer commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

Yes that one should work, but that's good this is why we have tests 😄

@pfebrer

pfebrer commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

However it's not obvious what should be the behavior there. People would expect that whatever is not specified in the yaml is the defaults or the current hypers of the model?

@pfebrer

pfebrer commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

Maybe we can start by covering only the unambiguous case:

  • For the missing keys, if defaults match the current model's hypers, all good (covers the case of restarting training with the same file).
  • If not, ask user to specify what they want to use.

In principle this would be for nested keys, since for top-level ones we are assuming the missing keys are the current model hypers. But we could also be more strict there if you think it's not fine?

A restart yaml that omits soap.cutoff defaults was treated as a
mismatch against the full checkpoint dict. Recurse into mappings and
treat missing nested keys as keep-the-checkpoint, matching top-level.
@pfebrer

pfebrer commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

I was planning to do something different @HaoZeke , so I will revert. In any case, I think pushing into branches of other people without asking first or having been asked for a review is not the way to go 😅

@pfebrer

pfebrer commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Ah well you were asked for a review, but that is just the automatic one for being the maintainer of dpa3 haha

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.

5 participants