-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Refactor NSGA-II crossover operations into classes #3221
Refactor NSGA-II crossover operations into classes #3221
Conversation
This class forms common API for all existing and future NSGA-II crossover operations.
This is still early work-in-progress, but general design should be clearly visible by now, so any comments on it would be greatly appreciated. |
Codecov Report
@@ Coverage Diff @@
## master #3221 +/- ##
==========================================
- Coverage 91.72% 91.70% -0.03%
==========================================
Files 146 154 +8
Lines 12065 12132 +67
==========================================
+ Hits 11067 11126 +59
- Misses 998 1006 +8
Continue to review full report at Codecov.
|
Sharp inequality is needed to follow spec
@HideakiImamura @sile Could you review this PR, please? If you don't have enough time, please remove the assignment. |
Yes. I'll review this PR this or next weekend. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the update. I checked all of your changes. I have several minor comments. PTAL.
Seems like workflows are stuck. Could you guys re-trigger them? |
parents_params: np.ndarray, | ||
rng: np.random.RandomState, | ||
study: Study, | ||
search_space: Dict[str, BaseDistribution], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems, in numerical distributions case, parents_params
contains parameters transformed by _SearchSpaceTransform.transform
method. In such a case, the upper and lower bounds of each transformed parameter are not guaranteed to be the same as the original distribution (especially if suggest_float(..., log=True)
or suggest_float(..., step=...)
is used to sample the parameter).
So passing the (non-transformed) distributions here could cause an unexpected calculation if a crossover implementation uses the low
or high
fields of the distributions (e.g., _sbx.py#72). I think that we need to use an instance of _SearchSpaceTransform
(or __SearchSpaceTransform.bounds
) in the crossover calculation instead of the Dict[str, BaseDistribution]
instance (for numerical parameters).
A difficult point is that, in categorical distributions case, we should keep using Dict[str, BaseDistrivution]
because we don't apply the transformation on categorical parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just an idea, but we may be able to define a function converting __SearchSpaceTransform.bounds
to List[BaseDistribution]
and apply the function to search_space
before passing to the crossover
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since _SearchSpaceTransform
already has an information about search space and bounds, maybe it should be able to do this conversion? I could implement this method in separate PR and merge it back here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or not, since it might not be possible to instantiate a distribution with transformed bounds e.g. FloatDistribution(log(1), log(10), log=True)
. I think we might be forced to pass instance of _SearchSpaceTransform
after all. Maybe we could make OHE optional (_SearchSpaceTransform
with ohe=False
would be just identity function for categorical params)? We could then use it regardless of distribution, and pass to crossover instead of search space dict.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hvy As the implementor of _SearchSpaceTransform
, do you have any preference for how to deal with this issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
along with making _SearchSpaceTransform public
I think I could work on this right now in separate PR. This would be really usefull as now public SearchSpaceTransform
would have essentially the functionality of bounds
wrapper I was talking about previously. I think in the process of making it public we could think about some convenience methods such as __len__
to return search space length. What do you think about discussing and implementing it in separate PR? It would be a drop in replacement for search_space
dict.
we could make it more Optuna-like by passing arguments that more resemble those of _try_crossover
Passing some object with params instead of an array in parents_params
? +1 to that in future revisions, as it would probably come in handy if other crossovers were to support OHE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about discussing and implementing it in separate PR?
Sounds good. I think it'll be important to hear what others are thinking about this, considering the fact that this'll likely be an API targeting only a small portion of the users. __len__
by the way sounds interesting. I'd personally prefer named methods, as it's not entirely clear from __len__
whether it will return the length after or prior to the transformation, but this is not a strong opinion.
Given the discussion so far, how do you suggest we proceed with this PR. Should we aim to merge it as is, revisit it at a later time? If so, should we perhaps make APIs in this PR experimental to reserve ourselves for changes? Alternatively, we'll keep this PR open until everything discussed so far is fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to make _SearchSpaceTransform
public. I think it would be beneficial for users to make it public, since it could be used by users who want to implement a new sampler, for example.
On the other hand, I don't think merging this PR will have to wait for that. Frankly speaking, @xadrianzetx's contribution to Optuna V3 is very big and we are relying on your contribution a lot. Making _SearchSpaceTransform
public is out of scope for Optuna V3, but perhaps PR is expected to be somewhat bigger, including the interface. Therefore, in this PR, why not perform an in-line uniform crossover on categorical parameters and pass _SearchSpaceTransform.bounds
to try_crossover? I suggest that making _SearchSpaceTransform
public is a separate issue to be made into future work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fully agree with @HideakiImamura.
- Uniform crossover for categorical params will be inlined, and
BaseCrossover
implementations will be reserved for transformed numerical params (for now). - We will re-design
search_space
arg to accept numpy array of_SearchSpaceTransform.bounds
instead of distribution dict to solve issue reported by @sile. - Making
_SearchSpaceTransform
a public API and passing it instead of justbounds
will be left for future discussion and work (which I'm happy to be assigned to). - Making crossovers accept one-hot-encoded params will be left for future discussion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect! Thank you very much for this useful discussion! > @xadrianzetx @hvy @HideakiImamura
Sorry, I don't know how to resolve that. @HideakiImamura Could you address this problem? |
|
…rossover-classes
@sile, @HideakiImamura, changes discussed in #3221 (comment) are now implemented. Sorry for small delay and PTAL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the long running PR! LGTM!
Thank you for reviews and discussions @sile, @HideakiImamura, @hvy! |
Motivation
This PR aims to create common API for all NSGA-II crossover operations and refactor functions introduced in #2903 into classes following this API. This decouples crossover implementations from sampler implementation, making them modular, easier to maintain/test/extend. Also, some
numpy
operations are vectorized (straightforward ones at least). This is a part of #3133.Description of the changes
NSGAIISampler
support new crossover format