Skip to content

Commit

Permalink
Handle bounds through the layer system (#1050)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrapin authored Mar 1, 2021
1 parent ffb58b4 commit 5eb7d8e
Show file tree
Hide file tree
Showing 18 changed files with 666 additions and 284 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@
- `Parameter` classes have now a layer structure [#1045](https://github.com/facebookresearch/nevergrad/pull/1045)
which simplifies changing their behavior. In future PRs this system will take charge of bounds, other constraints,
sampling etc.
- The layer structures allows disentangling bounds and log-distribution. This goal has been reached with
[#1053](https://github.com/facebookresearch/nevergrad/pull/1053) but may create some instabilities. In particular,
the representation (`__repr__`) of `Array` has changed, and their `bounds` attribute is no longer reliable for now.
This change will eventually lead to a new syntax for settings bounds and distribution, but it's not ready yet.
- `DE` initial sampling as been updated to take bounds into accounts [#1058](https://github.com/facebookresearch/nevergrad/pull/1058)


### Other changes

- the new `nevergrad.errors` module gathers errors and warnings used throughout the package (WIP) [#1031](https://github.com/facebookresearch/nevergrad/pull/1031).
Expand Down
17 changes: 13 additions & 4 deletions nevergrad/common/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class NevergradWarning(Warning):


# errors
# pylint: disable=too-many-ancestors


class NevergradEarlyStopping(StopIteration, NevergradError):
Expand Down Expand Up @@ -70,21 +71,29 @@ class NevergradDeprecationWarning(DeprecationWarning, NevergradWarning):
"""Deprecated function/class"""


class InefficientSettingsWarning(RuntimeWarning, NevergradWarning):
class NevergradRuntimeWarning(RuntimeWarning, NevergradWarning):
"""Runtime warning raise by nevergrad"""


class InefficientSettingsWarning(NevergradRuntimeWarning):
"""Optimization settings are not optimal for the optimizer"""


class BadLossWarning(RuntimeWarning, NevergradWarning):
class BadLossWarning(NevergradRuntimeWarning):
"""Provided loss is unhelpful"""


class LossTooLargeWarning(BadLossWarning):
"""Sent when Loss is clipped because it is too large"""


class FinishedUnderlyingOptimizerWarning(RuntimeWarning, NevergradWarning):
class NevergradBehaviorChangesWarning(NevergradRuntimeWarning):
"""Notifies a change of behavior"""


class FinishedUnderlyingOptimizerWarning(NevergradRuntimeWarning):
"""Underlying scipy optimizer finished"""


class FailedConstraintWarning(RuntimeWarning, NevergradWarning):
class FailedConstraintWarning(NevergradRuntimeWarning):
"""Constraint could not be applied"""
5 changes: 5 additions & 0 deletions nevergrad/common/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,8 @@ def test_set_env() -> None:
with tools.set_env(BLUBLU=1):
assert os.environ.get("BLUBLU", None) == "1"
assert os.environ.get("BLUBLU", None) is None


def test_flatten() -> None:
out = tools.flatten(["a", {"truc": [4, 5]}])
assert out == {"0": "a", "1.truc.0": 4, "1.truc.1": 5}
25 changes: 25 additions & 0 deletions nevergrad/common/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,28 @@ def set_env(**environ: tp.Any) -> tp.Generator[None, None, None]:
os.environ.pop(k)
if val is not None:
os.environ[k] = val


def flatten(obj: tp.Any) -> tp.Any:
"""Flatten a dict/list structure
Example
-------
>>> flatten(["a", {"truc": [4, 5]}])
>>> {"0": "a", "1.truc.0": 4, "1.truc.1": 5}
"""
output: tp.Any = {}
if isinstance(obj, (tuple, list)):
iterator = enumerate(obj)
elif isinstance(obj, dict):
iterator = obj.items() # type: ignore
else:
return obj
for k, val in iterator:
content = flatten(val)
if isinstance(content, dict):
output.update({f"{k}.{x}": y for x, y in content.items()})
else:
output[str(k)] = val
return output
4 changes: 2 additions & 2 deletions nevergrad/functions/leaderboard.csv
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"bragg,80",0.000694261986,"[2.999999999999995,2.0,2.9999999999999982,2.0,2.9999999999999942,2.0000000000000204,2.9999999999999982,2.0000000000000204,2.999999999999997,2.0000000000000577,2.999999999999994,2.0000000000000178,2.9999999999999996,2.0000000000000258,2.9999999999999956,2.0,3.0,2.0,3.0,2.0000000000000258,2.9999999999998677,2.0,2.999999999999998,2.0000000000000524,2.999999999999998,2.0,2.999999999999731,2.0000000000000204,3.0,2.0,3.0,2.0,2.999999999999869,2.0000000000000524,2.999999999999998,2.0,2.999999999999731,2.0,2.9999999999999982,2.0,86.60255045244762,106.06599965930195,86.60255443305651,106.06600747129924,86.60257272790835,106.06594450536937,86.60261007043326,106.06596664220048,86.60256991846003,106.06601083817202,86.60251126812021,106.06605239950612,86.60252027566017,106.06598075034444,86.60259101280616,106.06599907105759,86.60256520284221,106.06597421940252,86.60257498882078,106.06598483902887,86.60258117175987,106.06597850626063,86.60257221703684,106.06597517269579,86.60257273903393,106.06600072357362,86.60255405767539,106.06597375534662,86.60256934296459,106.06596027660167,86.60259348834224,106.06598724294983,86.60256638431304,106.06597523757073,86.60257261435468,106.06600050328808,86.60255444923789,106.06596589510059,86.60257650073991,106.06599053476317]"
"bragg_as_tuple,80",0.056503784218,"[2.0,104.19050205854796,3.0,103.3871864897671,2.432368384694066,107.16845414573265,3.0,105.04397032814755,3.0,101.4115279880702,2.0,101.82340730595631,2.0,106.29835865548985,3.0,100.50409945218179,2.0,103.8534464724715,2.7907130282425876,106.34796100526032,3.0,106.3101270117349,3.0,104.8166097932767,2.0,105.20061310675672,3.0,108.05008553576533,2.0,106.65130169395327,2.0,106.79217956093568,2.0,107.57998256628777,3.0,106.11538453696315,3.0,104.18859447446258,2.0,104.61099654298489,3.0,104.34768767390064,2.0,105.010434962529,2.0,103.77385312377623,3.0,105.21975402145074,2.0,103.66175885994471,2.0,104.86077071154178,3.0,103.68862394055434,2.0,106.2706255197518,2.0,103.64438413549227,3.0,105.6950172939732,2.0,106.69119981455366,2.0,104.1415087744897,2.592088288124082,107.06731776173814,3.0,102.19253037912654,2.527507400315132,102.89774703567296,2.0,105.81418087457429,2.0,106.50427342380392,2.0,105.61415322728554,2.0,106.66208085013761,2.0,105.28693844768354]"
"cf_photosic_realistic,20",0.086025742545,"[2.0,3.0,2.1076,2.0,3.0,2.5783,2.0,3.0,2.0,3.0,90.0231,78.9789,72.8369,99.9577,82.7487,62.7583,104.1682,139.9002,93.3356,75.6039]"
"cf_photosic_reference,16",0.431072337632,"[109.72985831489979,98.18574120560555,107.42439496690479,87.99264365961669,112.531428339492,89.65278659791956,105.05127078132273,103.79772329843809,96.93018121427048,133.71819394988916,99.02177080593657,109.72456993535758,115.95956118008561,92.84831198907784,118.42356371437981,103.77850212331678]"
"chirped,16",0.594587712739,"[109.72985831489979,98.18574120560555,107.42439496690479,87.99264365961669,112.531428339492,89.65278659791956,105.05127078132273,103.79772329843809,96.93018121427048,133.71819394988916,99.02177080593657,109.72456993535758,115.95956118008561,92.84831198907784,118.42356371437981,103.77850212331678]"
"cf_photosic_reference,16",0.431072337632,"[109.72985831489979,98.18574120560555,107.42439496690479,87.99264365961669,112.531428339492,89.65278659791956,105.05127078132273,103.79772329843809,96.93018121427048,133.71819394988918,99.02177080593655,109.72456993535758,115.95956118008563,92.84831198907784,118.42356371437981,103.77850212331678]"
"chirped,16",0.594587712739,"[109.72985831489979,98.18574120560555,107.42439496690479,87.99264365961669,112.531428339492,89.65278659791956,105.05127078132273,103.79772329843809,96.93018121427048,133.71819394988918,99.02177080593655,109.72456993535758,115.95956118008563,92.84831198907784,118.42356371437981,103.77850212331678]"
"chirped,30",0.275923457222,"[89.04887416,109.54188095,89.74520725,121.81700431,179.99830918,124.38222473,95.31017129,116.0239629,92.92345776,118.06108198,179.99965859,116.89288181,88.90191494,110.30816229,93.11974992,137.42629858,118.81810084,110.74139708,85.15270955,100.9382438,81.44070951,100.6382896,84.97336252,110.59252719,134.89164276,121.84205195,89.28450356,106.72776991,85.77168797,102.33562547]"
"chirped,50",0.116563972901,"[93.65223418423034,118.48802644462693,107.4154177701731,146.1273996196957,104.76814425546243,122.46259169233943,101.63070554932264,132.01391635156088,113.23959177552805,134.21191762900222,104.52593631355413,123.84798946548463,99.53290830788647,124.5717299569956,114.84349635591072,136.69596308542052,94.99997481641495,107.55307917381322,82.394994109015,96.18784040922577,79.12042692721471,101.72854687985267,87.61947895483019,118.06040186972581,129.67099220470743,120.08173331893012,89.30208035845052,105.27994144055239,83.02744104990198,98.53738160919845,80.48856203248494,103.55664056758202,92.3091829150373,123.27796260700957,97.2529066260935,110.36369311643149,84.99816155046332,97.87908100788103,75.53207272339498,92.1090256322082,78.09126315339792,98.11980069427835,79.9260762785673,95.27087465581414,75.64339912130325,93.41051297755547,79.35090675442197,100.5778583399821,83.55758649426299,101.84134444518143]"
"chirped,80",0.032443709031,"[88.52483361145642,108.92603698859098,97.04696158396622,179.9939570600735,94.19642075128272,103.30846616331984,81.29625993675596,95.05063197150761,77.709373680586,100.81610182681413,86.26517388248608,114.3151119519831,118.27692052373264,133.67143913893963,93.5311449270739,112.88478884103904,179.99906128209363,110.96886636925439,87.0525494740198,106.19238243264702,83.45680472650062,95.87480240302271,74.84514445698744,98.03831429770835,88.6130544913638,119.73483873341877,104.48001445731423,138.6323535761068,119.63010391311067,133.8309836804302,100.92157824350483,119.92550379046051,98.78641008123896,125.06765971003176,108.32078089504897,133.42173063233668,108.29941119571218,143.58622375887546,109.98502471825267,122.41478193726267,97.57862293264694,121.49336184447904,112.96592454386476,139.9492761564363,102.26548370710076,123.56636864464592,104.34370920471545,122.48140828139725,90.78171115586403,103.52126551047564,81.50102387202843,99.05592025264554,81.64377285362491,100.70682268909643,82.50875593897791,102.6738651822106,85.42810341360513,110.17382926802803,95.76846125991416,119.89313171852815,97.0419755376557,118.01612116654306,98.50691933568284,124.82813911505264,99.16589049747316,112.32579883953483,86.46250343538372,97.21862569154766,78.13118077960564,96.09801884928629,80.2192268261995,100.62638167590012,81.06326903762309,95.3241238185923,73.49025216866023,90.58651009490646,77.93688016160958,99.68921531581518,81.9810425130764,97.60997762584654]"
Expand Down
2 changes: 1 addition & 1 deletion nevergrad/ops/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def parameter(self) -> core.Parameter:
"""Returns a constraint-free parameter, for the optimization process"""
param = self._layers[0].copy()
# remove last layer and make sure it is the last one
if self._index != param._layers.pop()._index:
if self._layer_index != param._layers.pop()._layer_index:
raise RuntimeError("Constraint layer should be unique and placed last")
return param # type: ignore

Expand Down
11 changes: 8 additions & 3 deletions nevergrad/optimization/test_externalbo.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest
import numpy as np
import nevergrad as ng
from nevergrad.common.tools import flatten
from .optimizerlib import registry
from .externalbo import _hp_parametrization_to_dict, _hp_dict_to_parametrization

Expand Down Expand Up @@ -61,7 +62,9 @@ def test_hyperopt(parametrization, has_transform) -> None:
optim1.tell(cand, 0) # Tell asked
del cand._meta["trial_id"]
optim2.tell(cand, 0) # Tell not asked
assert optim1.trials._dynamic_trials[it]["misc"]["vals"] == optim2.trials._dynamic_trials[it]["misc"]["vals"] # type: ignore
assert flatten(optim1.trials._dynamic_trials[it]["misc"]["vals"]) == pytest.approx( # type: ignore
flatten(optim2.trials._dynamic_trials[it]["misc"]["vals"]) # type: ignore
)

assert optim1.trials.new_trial_ids(1) == optim2.trials.new_trial_ids(1) # type: ignore
assert optim1.trials.new_trial_ids(1)[0] == (it + 2) # type: ignore
Expand Down Expand Up @@ -125,5 +128,7 @@ def test_hyperopt(parametrization, has_transform) -> None:
def test_hyperopt_helpers(parametrization, values):
for val, dict_val, hyperopt_val in values:
parametrization.value = val
assert _hp_parametrization_to_dict(parametrization) == dict_val
assert _hp_dict_to_parametrization(hyperopt_val) == parametrization.value
assert flatten(_hp_parametrization_to_dict(parametrization)) == pytest.approx(flatten(dict_val))
assert flatten(_hp_dict_to_parametrization(hyperopt_val)) == pytest.approx(
flatten(parametrization.value)
)
4 changes: 2 additions & 2 deletions nevergrad/optimization/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ def test_pruning() -> None:
testing.assert_set_equal([x[0] for x in archive2.keys_as_arrays()], [0, 3], err_msg=f"Repetition #{k+1}")


@pytest.mark.parametrize(
@pytest.mark.parametrize( # type: ignore
"nw,dimension,expected_min,expected_max",
[ # type: ignore
[
(12, 8, 100, 1000),
(24, 8, 168, 1680),
(24, 100000, 168, 671),
Expand Down
15 changes: 7 additions & 8 deletions nevergrad/optimization/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import numpy as np
from nevergrad.parametrization import parameter as p
from nevergrad.parametrization.utils import float_penalty as _float_penalty
from nevergrad.parametrization import _datalayers
import nevergrad.common.typing as tp
from nevergrad.common.tools import OrderedSet

Expand Down Expand Up @@ -416,17 +417,15 @@ def _transform(
start = 0
for ref in self._ref_arrays:
end = start + ref.dimension
if any(b is None for b in ref.bounds) or not ref.full_range_sampling:
layers = _datalayers.BoundLayer.filter_from(ref) # find bound layers
layers = [x for x in layers if x.uniform_sampling] # keep only uniform sampling
if not layers:
x[start:end] = unbounded_transform(x[start:end])
else:
layer_index = layers[-1]._layer_index
array = ref.spawn_child()
bounds: tp.List[tp.Any] = list(ref.bounds)
if array.exponent is not None:
bounds = [np.log(b) for b in bounds]
value = bounds[0] + (bounds[1] - bounds[0]) * x[start:end].reshape(ref._value.shape)
if array.exponent is not None:
value = np.exp(value)
array._value = value
normalized = x[start:end].reshape(ref._value.shape)
array._layers[layer_index].set_normalized_value(normalized) # type: ignore
x[start:end] = array.get_standardized_data(reference=ref)
start = end
return x
Expand Down
Loading

0 comments on commit 5eb7d8e

Please sign in to comment.