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

pq #304

Closed
wants to merge 3 commits into from
Closed

pq #304

wants to merge 3 commits into from

Conversation

guillemsimeon
Copy link
Collaborator

Add small hack to be able to test partial charges with SPICE. This can be the base PR to come up with a solution to total charge, partial charges, spins, etc.

@@ -378,6 +378,10 @@ def forward(
assert z.dim() == 1 and z.dtype == torch.long
batch = torch.zeros_like(z) if batch is None else batch

# trick to incorporate SPICE pqs
# set charge: true in yaml ((?) currently I do it)
q = extra_args["pq"]
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would move instead to something like removing "q" and "s" from the forward call of the representation models and instead send everything as extra_args, or atomic_labels:

        atomic_labels = {}
        if q is not None:
             atomic_labels["total_charges"] = q
        if s is not None:
             atomic_labels["spin"] = s 
        # run the potentially wrapped representation model
        x, v, z, pos, batch = self.representation_model(
            z, pos, batch, box=box, atomic_labels=atomic_labels, extra_args=extra_args
        )

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it seems nice

@RaulPPelaez
Copy link
Collaborator

You could avoid creating a tensor of zeros with the charges here:

if q is None:
q = torch.zeros_like(z, device=z.device, dtype=z.dtype)
else:
q = q[batch]

X = X + dX + (1 + 0.1 * q[..., None, None, None]) * torch.matrix_power(dX, 2)

If you set "q" (please lets change the name of that variable) to something like this:

        if q is None:
            q = 0
        else:
            q = q[batch, None, None, None]

@peastman
Copy link
Collaborator

peastman commented Mar 5, 2024

I previously tested this method for injecting partial charges and found it didn't work at all. The loss got much worse. In contrast, the method in #289 does work and makes the loss better.

@guillemsimeon
Copy link
Collaborator Author

guillemsimeon commented Mar 5, 2024 via email

@peastman
Copy link
Collaborator

peastman commented Mar 5, 2024

Yes, we did already have this discussion. :) My point is that this shouldn't be merged until we do a full evaluation of both PRs and determine which one works better.

Also, #289 truly is a generic method that supports arbitrary sets of global and per-atom properties. This one is hardcoded to just a single property which must be called pq, and it isn't clear how it could be generalized to support multiple properties.

@guillemsimeon
Copy link
Collaborator Author

guillemsimeon commented Mar 5, 2024 via email

@AntonioMirarchi
Copy link
Contributor

What do you think about this setup in the yaml file:

model_extra_args:
  total_charge: 
    learnable: true
    coeff: 0.1
  partial_charge: 
    learnable: true
    coeff: 0.1
  spin: 
    learnable: false
    coeff: 1

The keys of the dict will be used to define which args of extra_args should go to the model so the prior behavior is preserved as it is now. Then the coeff is used as starting parameter for the specific arg, if learnable requires_grad is set to true. In the init a nn.ParameterList is initialized with length equal to the model_extra_args.keys().

@RaulPPelaez
Copy link
Collaborator

You are assuming the extra_args are going to just be multiplied by a constant (as guillem does now), this might not be the case in the future, when perhaps we lean towards Peter's strategy of embeddings, or we use some kind of small MLP to compute the prefactors.
OTOH I do not really like the name "model_extra_args". Why would "total_charge" be extra but "box" is just an optional argument? I do not have a better alternative for you, just saying...

@peastman
Copy link
Collaborator

peastman commented Mar 6, 2024

Here are training curves for a pair of models (TensorNet with one interaction layer). They used identical settings except for the handling of partial charges. "pq" used the method in this PR. "embedding" used the method in #289. Here is the total training loss.

image

And to give a sense of the errors in physical units, here is the L1 loss for energies in the validation set.

image

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.

4 participants