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

Added code to reverse transforms for more flexibility #132

Conversation

ThibeauWouters
Copy link
Collaborator

@ThibeauWouters ThibeauWouters commented Aug 17, 2024

New attempt at improving the flexibility and use of "pre-made" transforms such as masses transforms etc.

Source code changes

I have added two utility functions:

  • One function to create a BijectiveTransform given a name_mapping and the forward and backward transformation functions which take arrays as input. That way, we can easily create these "pre-made" transforms by specifying these in a one-liner. At the same time, it allows users to create similar transforms themselves very easily, which therefore also makes the name_mapping no longer hardcoded for the masses since users can change it if they desire, as @thomasckng mentioned some time ago.
  • Another function reverses a BijectiveTransform object, as @kazewong suggested in my previous PR attempt.

These functions are then used to simplify the "pre-made" transforms in single_event/transforms.py to be shorter and clearer.

Test changes

  • Made sure the GW150914_D.py file in test/integration matches this new implementation.
  • Added a new toy example test file to play around with the transforms in a simplified setting.

@thomasckng
Copy link
Collaborator

thomasckng commented Aug 18, 2024

@ThibeauWouters Thanks for the PR! The changes look good!

For the tests, I think the test scripts in test/ are meant to be light-weighted, as they will run whenever there is a new commit. They meant to check if everything is working instead of generating meaningful result. A example with optimized parameters are meant to be put in example/. I am canceling the test runs now.

@ThibeauWouters
Copy link
Collaborator Author

@thomasckng Thanks! I had local copies of the test file to try more agressive hyperparameters but indeed I seemed to have messed them up with the ones in the test directory. Thanks for canceling the runs.

n_epochs=n_epochs,
learning_rate=learning_rate,
n_max_examples=30,
n_flow_samples=100,
n_max_examples=30000,
Copy link
Owner

Choose a reason for hiding this comment

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

Test are supposed to be light weight. Reminder to revert these numbers

@@ -445,3 +445,54 @@ def __init__(
)
for i in range(len(name_mapping[1]))
}


def create_bijective_transform(
Copy link
Owner

Choose a reason for hiding this comment

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

I think this is not a good practice in general. Here transform_func_array and inverse_transform_func_array can be potentially harmful functions, and in the long run, this flexibility will create trouble in reproducibility. Any bijective transform should be explicitly declared with the class interface.

@ThibeauWouters ThibeauWouters changed the title Added code to create and reverse transforms for more flexibility Added code to reverse transforms for more flexibility Aug 22, 2024
@ThibeauWouters
Copy link
Collaborator Author

ThibeauWouters commented Aug 22, 2024

@kazewong I adapted the code to adapt to your previous comment. But now it feels a bit off in the sense that the "predefined" transforms are classes, that have to be instantiated in order to get the actual transform to be used in PE, and the reverse transforms that are created from the reverse function are objects/instances already. The former require users to give name_mapping, which as I mentioned earlier on is a bit redundant since we would like the name mapping to be fixed for these classes, whereas the former doesn't. So the predefined transform and its reverse are not treated equally in the current implementation.

@kazewong
Copy link
Owner

@kazewong I adapted the code to adapt to your previous comment. But now it feels a bit off in the sense that the "predefined" transforms are classes, that have to be instantiated in order to get the actual transform to be used in PE, and the reverse transforms that are created from the reverse function are objects/instances already. The former require users to give name_mapping, which as I mentioned earlier on is a bit redundant since we would like the name mapping to be fixed for these classes, whereas the former doesn't. So the predefined transform and its reverse are not treated equally in the current implementation.

There are a couple of things you mentioned here:

  1. Re: predefined transform and its reverse are not treated equally: I don't think they should. Inverting a transform target a bijective transform, and predefined transforms are a subset of bijective transforms. For example, reverse_bijective_transform(ScaleTransform((['x'], ['y']), 1.0)) should return a valid transform. As long as this is the interface the user will use, I think this is legit.
  2. If we later establish predefined transform can be called with PredefinedTransform(), the interface makes sense to me still, which will be replacing PredefinedTransform() with reverse_bijective_transform(PredefinedTransform()) at the same spot.

I think this is more ergonomic for the user, instead of needing to use a function to call the predefined transform.

Going forward, I do think predefined transforms that enforce the naming strictly should mostly be constructed using the interface PredefinedTransform(). Only transform that does not enforce naming such as ScaleTransform should allow inputs other than the transform parameters.

@ThibeauWouters
Copy link
Collaborator Author

@thomasckng @kazewong I have updated the PR a bit after the discussion yesterday. Let me know if this looks OK to you or if further changes are required.

@ThibeauWouters
Copy link
Collaborator Author

@thomasckng The files have been deleted

return f"{self.__class__.__name__[1:]}()"


ComponentMassesToChirpMassMassRatioTransform = (
Copy link
Owner

Choose a reason for hiding this comment

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

Do you want to further consolidate it? From what I see, this can be just

def named_transform_func...
def named_transform_inverse_func...
ComponentMassesToChirpMassMassRatioTransform =  BijectiveTransform(name_mapping = (["m_1", "m_2"], ["M_c", "q"]),  transform_func =  named_transform, self.inverse_transform_func = named_inverse_transform)

Copy link
Owner

@kazewong kazewong left a comment

Choose a reason for hiding this comment

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

Please resolve the comment related to further consolidation. But after that it should be good for merging

@ThibeauWouters
Copy link
Collaborator Author

@kazewong I have updated the source code as requested -- is this what you were referring to?

@kazewong kazewong merged commit 0e96439 into kazewong:98-moving-naming-tracking-into-jim-class-from-prior-class Sep 2, 2024
2 of 4 checks passed
@ThibeauWouters ThibeauWouters deleted the 98-moving-naming-tracking-into-jim-class-from-prior-class branch October 29, 2024 17:25
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