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
Fix random state for test_noisy_artificial_function_loss #977
Conversation
Thanks! For the bug in "static" CI, just run "black nevergrad" and this should be solved, this is a formatting issue. |
f005b4d
to
baa41f9
Compare
Merry Christmas! It is necessary to decide if Until the decision is made, the following statement will be fixed: if noise_level > 0:
parametrization.descriptors.deterministic_function = False |
Actually there is deterministic_function which means that the function is deterministic and deterministic which means that the function and the transformation are deterministic. |
Can you show which bug you are fixing ? This is still unclear to me. |
Merry Christmas to all people who have a Christmas or whichever day off you prefer during this time of the year :-) |
This involves several function calls. def _transform(self, x: tp.ArrayLike) -> np.ndarray:
data = self.transform_var.process(x) # <<< self.transform_var is a ArtificialVariable object
return np.array(data) I found that the def process( # pylint: disable=unused-argument
self, data: tp.ArrayLike, deterministic: bool = True
) -> np.ndarray:
if not self._transforms: #This is true as self._transforms is []
self._initialize() # <<< Trace this method
.... From the def _initialize(self) -> None:
for transform_inds in tools.grouper(indices, n=self.block_dimension):
self._transforms.append(
utils.Transform( #<<< This line calls __init__ in utils.Transform
transform_inds,
translation_factor=self.translation_factor,
rotation=self.rotation,
random_state=self.random_state,
)
) Finally, the class initializer of class Transform:
"""Defines a unique random transformation (index selection, translation, and optionally rotation)
which can be applied to a point
"""
def __init__(...):
...
self.translation = ... #<<< This line is stochastic Therefore, my conclusion is |
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.
That's great thanks!
More comments coming, I'm trying to get a better understanding of it little my little.
Also, I am considering adding a test which counts the number of calls to np.random and fails if we add one, with a message explaining the options :D Might be safer on the long run^^
@@ -110,7 +110,7 @@ def __init__( | |||
if mutation == "adaptive": | |||
self._adaptive_mr = 0.5 | |||
if mutation == "coordinatewise_adaptive": | |||
self._velocity = np.random.uniform(size=self.dimension) * arity / 4.0 | |||
self._velocity = self._rng.uniform(size=self.dimension) * arity / 4.0 |
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.
good catch!
I would have expected this to get caught by the CI though :s
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.
same for the 3 changes below, nice catches!
@jrapin Concerning your question about the comment # Because copy() can have different random initialization for the parameters
# The function should be copied early.
np.random.seed(seed)
pfunc = func.copy()
# assert False #Paco: terminate early for debugging Please trace the following code:
@parametrization.setter
def parametrization(self, parametrization: p.Parameter) -> None:
self._parametrization = parametrization
self._parametrization.freeze()
# pylint: disable=pointless-statement
# print(self._parameterization._random_state) #Paco: you will see None is output twice for each run in the console
self._parametrization.random_state # force initialization for synchronization of random state
# # TODO investigate why this synchronization is needed
@property
def random_state(self) -> np.random.RandomState:
"""Random state the instrumentation and the optimizers pull from.
It can be seeded/replaced.
"""
if self._random_state is None:
# use the setter, to make sure the random state is propagated to the variables
seed = np.random.randint(2 ** 32, dtype=np.uint32)
self._set_random_state(np.random.RandomState(seed))
assert self._random_state is not None
return self._random_state Because |
Sorry I took so long, so many things happening solving this has slipped my mind. In both cases anyway, I don't think changing the the seeding and copy location to a few lines above is supposed to matter. |
When I added if self.TEMP_DEBUG:
assert False in the block of In addition, I moved the xp.run()
loss_ref = xp.result["loss"]
# now with copy
assert xp._optimizer is not None
reco = xp._optimizer.provide_recommendation()
assert reco is not None |
Not sure what you mean by this, but I definitely agree that the seed needs to be set before a new function is initialized.
I see your point. My initial aim with the test was to prove that I could reinstantiate a function later on, in an isolated part of the code, and that it would provide the same results. When you move it, you show that the initial function does not change the copy. I'm not sure one claim is stronger than the other, since in the first case you don't really know if there are no intereferences, and in the second, the copy could have modified the initial function (I would expect it shouldn't have... although maybe sometimes it could, so not sure), I guess both should be true^^ |
Is there anything blocking you from continuing? I see the CI has some changed values. I guess the values can be updated if that's only due to different random generators. |
@jrapin The complaints from |
@pacowong the typing issue was due to a mypy version update which now seems to parse non-package files. It's now fixed in master so you can merge master within your branch, and if things are still OK I'll merge this, thanks for the fixes ;) |
@pacowong thanks for the fix! |
@jrapin You're welcome. ;) |
Types of changes
Motivation and Context / Related issue
Related issue: #966
The goal is to resolve the bugs in
random_state
management fortest_noisy_artificial_function_loss
which causes reproducibility issues.If you want to patch the current system immediately, I can add back
np.random.seed(seed)
to the test case.Checklist