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

Dedicate half constraint budget to a suboptimizer #1047

Merged
merged 55 commits into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
09b9774
cst_solver
teytaud Dec 7, 2020
748dd8c
warning
teytaud Dec 7, 2020
1aec317
warning
teytaud Dec 7, 2020
066fd8d
Merge branch 'master' of github.com:facebookresearch/nevergrad into c…
teytaud Dec 11, 2020
7b2ca76
fix
teytaud Dec 11, 2020
4b0c9d7
black
teytaud Dec 11, 2020
5ff0766
fix keras issue
teytaud Dec 16, 2020
08dd791
Update test_mlfunctionlib.py
teytaud Dec 16, 2020
2d51bfa
black
teytaud Dec 16, 2020
c3f46d0
Merge branch 'master' into cstsolve
jrapin Dec 17, 2020
7ee4d9a
[PR on cstsolve PR] Try to extract constraint solving (#968)
jrapin Dec 18, 2020
4501834
Merge branch 'master' of github.com:facebookresearch/nevergrad
teytaud Dec 20, 2020
7e4ec60
Update utils.py
teytaud Dec 30, 2020
54dc137
Merge branch 'master' of github.com:facebookresearch/nevergrad into c…
teytaud Dec 30, 2020
5f59739
Merge branch 'master' of github.com:facebookresearch/nevergrad
teytaud Dec 31, 2020
7651c97
Fix a bug.
teytaud Jan 1, 2021
c3671e1
Update base.py
teytaud Jan 1, 2021
22d589c
Merge branch 'master' of gthub.com:facebookresearch/nevergrad
teytaud Jan 7, 2021
adceda1
Merge branch 'master' of github.com:facebookresearch/nevergrad into c…
teytaud Jan 7, 2021
3809c2b
fix
teytaud Jan 7, 2021
e10dd0c
fix
teytaud Jan 7, 2021
dc2dd86
Merge bt checZZranch 'master' of github.com:facebookresearch/nevergrad
teytaud Jan 8, 2021
4910f3d
Merge branch 'master' of github.com:facebookresearch/nevergrad
teytaud Jan 26, 2021
f0fa604
Merge branch 'master' of github.com:facebookresearch/nevergrad
teytaud Feb 8, 2021
c86b6cf
fix
teytaud Feb 15, 2021
da89ea4
Merge branch 'master' into ctr_and_cstsolve
teytaud Feb 15, 2021
558c066
Update base.py
teytaud Feb 15, 2021
2289c15
Update base.py
teytaud Feb 15, 2021
43ed96b
Update base.py
teytaud Feb 15, 2021
dfec878
fix
teytaud Feb 15, 2021
a5756e6
fix
teytaud Mar 9, 2021
77b661b
fix
teytaud Mar 9, 2021
8d8aa9a
fix_comment
teytaud Mar 9, 2021
7bf71b1
Merge branch 'master' into ctr_and_cstsolve
teytaud Mar 9, 2021
b5184d8
fixes
teytaud Mar 9, 2021
8f28edb
black
teytaud Mar 9, 2021
a483223
fix
teytaud Mar 9, 2021
09fe55f
fix
teytaud Mar 12, 2021
5472f75
fix_typo
teytaud Mar 12, 2021
663bdd2
Update nevergrad/optimization/base.py
teytaud Mar 12, 2021
a790abf
Update nevergrad/optimization/base.py
jrapin Mar 15, 2021
240acd5
Clarify suggest arguments (#1072)
jrapin Mar 10, 2021
7d35a25
Skip rocket xp test for speed (#1075)
jrapin Mar 12, 2021
70ccc97
Update parametrization flatten function (#1074)
jrapin Mar 12, 2021
c49f2c0
Add configuration for PSO + simplifications (#1073)
jrapin Mar 12, 2021
9da6c9d
Remove deprecated stuff (#1041)
teytaud Mar 12, 2021
5493ec8
Morphing with Nevergrad (#1042)
teytaud Mar 12, 2021
0bfa4ed
Add MOO xp variants (#1004)
teytaud Mar 12, 2021
bbbfa2c
minor
jrapin Mar 15, 2021
db68498
fix
jrapin Mar 15, 2021
1ce89ba
CHANGELOG
jrapin Mar 15, 2021
b9effad
merge
jrapin Mar 15, 2021
0102ab1
black
teytaud Mar 15, 2021
da52dd7
fix
teytaud Mar 15, 2021
af0ef7c
[PR on PR] Fix constraints (#1079)
jrapin Mar 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
variables since in this case `parameter.sample()` samples uniformly (unless otherwise specified).
The previous behavior can be obtained with `RandomSearchMaker(sampler="gaussian")`.
- `PSO` API has been slightly changed [#1073](https://github.com/facebookresearch/nevergrad/pull/1073)
- Half the budget alloted to solve cheap constrained is now used by a sub-optimizer
[#1047](https://github.com/facebookresearch/nevergrad/pull/1047). More changes of constraint management will land
in the near future.

### Important changes

Expand Down
59 changes: 45 additions & 14 deletions nevergrad/optimization/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,30 +432,39 @@ def ask(self) -> p.Parameter:
callback(self)
current_num_ask = self.num_ask
# tentatives if a cheap constraint is available
# TODO: this should be replaced by an optimization algorithm.
max_trials = self._constraints_manager.max_trials
for k in range(max_trials):
max_trials = max(1, self._constraints_manager.max_trials // 2)
# half will be used for sub-optimization --- if the optimization method does not need/use a budget.
# TODO(oteytaud): actually we could do this even when the budget is known, if we are sure that
# exceeding the budget is not a problem.
# Very simple constraint solver:
# - we use a simple algorithm.
# - no memory of previous iterations.
# - just projection to constraint satisfaction.
# We try using the normal tool during half constraint budget, in order to reduce the impact on the normal run.
for _ in range(max_trials):
is_suggestion = False
if self._suggestions:
if self._suggestions: # use suggestions if available
is_suggestion = True
candidate = self._suggestions.pop()
else:
candidate = self._internal_ask_candidate()
# only register actual asked points
if candidate.satisfies_constraints():
break # good to go!
if self._penalize_cheap_violations:
# TODO using a suboptimizer instead may help remove this
# Warning! This might be a tell not asked.
self._internal_tell_candidate(candidate, float("Inf")) # DE requires a tell
self._num_ask += (
1 # this is necessary for some algorithms which need new num to ask another point
# updating num_ask is necessary for some algorithms which need new num to ask another point
self._num_ask += 1
satisfies = candidate.satisfies_constraints()
if not satisfies:
# still not solving, let's run sub-optimization
candidate = _constraint_solver(candidate, budget=max_trials)
if not (satisfies or candidate.satisfies_constraints()):
warnings.warn(
f"Could not bypass the constraint after {max_trials} tentatives, "
"sending candidate anyway.",
errors.FailedConstraintWarning,
)
if k == max_trials - 1:
warnings.warn(
f"Could not bypass the constraint after {max_trials} tentatives, "
"sending candidate anyway.",
errors.FailedConstraintWarning,
)
if not is_suggestion:
if candidate.uid in self._asked:
raise RuntimeError(
Expand Down Expand Up @@ -736,3 +745,25 @@ def __eq__(self, other: tp.Any) -> tp.Any:
if self._config == other._config:
return True
return False


def _constraint_solver(parameter: p.Parameter, budget: int) -> p.Parameter:
"""Runs a suboptimization to solve the parameter constraints"""
parameter_without_constraint = parameter.copy()
parameter_without_constraint._constraint_checkers.clear()
opt = registry["OnePlusOne"](parameter_without_constraint, num_workers=1, budget=budget)
for _ in range(budget):
cand = opt.ask()
# Our objective function is minimum for the point the closest to
# the original candidate under the constraints.
penalty = sum(utils._float_penalty(func(cand.value)) for func in parameter._constraint_checkers)

# TODO: this may not scale well with dimension
distance = np.tanh(np.sum(cand.get_standardized_data(reference=parameter) ** 2))
# TODO: because of the return whenever constraints are satisfied, the first case never arises
loss = distance if penalty <= 0 else penalty + distance + 1.0
opt.tell(cand, loss)
if penalty <= 0: # constraints are satisfied
break
data = opt.recommend().get_standardized_data(reference=parameter_without_constraint)
return parameter.spawn_child().set_standardized_data(data)
9 changes: 4 additions & 5 deletions nevergrad/optimization/test_optimizerlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,24 +523,23 @@ def _ellips(x: np.ndarray) -> float:
"penalization,expected,as_layer",
[
(False, [1.005573e00, 3.965783e-04], False),
(True, [0.999987, -0.322118], False),
(True, [0.999975, -0.111235], False),
(False, [1.000760, -5.116619e-4], True),
],
)
@testing.suppress_nevergrad_warnings() # hides failed constraints
def test_constrained_optimization(penalization: bool, expected: tp.List[float], as_layer: bool) -> None:
def constraint(i: tp.Any) -> tp.Union[bool, float]:
if penalization:
return -float(abs(i[1]["x"][0] - 1))
out = i[1]["x"][0] >= 1
return out if not as_layer else float(not out)

parametrization = ng.p.Instrumentation(x=ng.p.Array(shape=(1,)), y=ng.p.Scalar())
optimizer = optlib.OnePlusOne(parametrization, budget=100)
optimizer.parametrization.random_state.seed(12)
if penalization:
optimizer._constraints_manager.update(max_trials=2, penalty_factor=10)

def constraint(i: tp.Any) -> tp.Union[bool, float]: # pylint: disable=function-redefined
return -abs(i[1]["x"][0] - 1)
optimizer._constraints_manager.update(max_trials=10, penalty_factor=10)

with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=UserWarning)
Expand Down
2 changes: 0 additions & 2 deletions nevergrad/parametrization/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ def __init__(self) -> None:
# Additional convenient features
self._random_state: tp.Optional[np.random.RandomState] = None # lazy initialization
self._generation = 0
# self._constraint_checkers: tp.List[tp.Union[tp.Callable[[tp.Any], bool], tp.Callable[[tp.Any], float]]] = []
self._constraint_checkers: tp.List[tp.Callable[[tp.Any], tp.Union[bool, float]]] = []
self._name: tp.Optional[str] = None
self._frozen = False
Expand Down Expand Up @@ -240,7 +239,6 @@ def __repr__(self) -> str:
return ":".join(strings)

# %% Constraint management

def satisfies_constraints(self) -> bool:
"""Whether the instance satisfies the constraints added through
the `register_cheap_constraint` method
Expand Down