Skip to content

Commit 7d95cde

Browse files
committed
Add max_broken in exp configuration
The experiment was using `worker.max_broken` but max_broken for the experiment is also configurable and should be handled differently.
1 parent 232cd3f commit 7d95cde

19 files changed

+101
-25
lines changed

src/orion/client/__init__.py

+16-12
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
# pylint: disable=too-many-arguments
2525
def create_experiment(
2626
name, version=None, space=None, algorithms=None,
27-
strategy=None, max_trials=None, storage=None, branching=None,
27+
strategy=None, max_trials=None, max_broken=None, storage=None, branching=None,
2828
max_idle_time=None, heartbeat=None, working_dir=None, debug=False):
2929
"""Create an experiment
3030
@@ -53,12 +53,12 @@ def create_experiment(
5353
2.2) Some other arguments than the name are given.
5454
5555
The configuration will be fetched from database and given arguments will override them.
56-
``max_trials`` may be overwritten in DB, but any other changes will lead to a branching. Instead
57-
of creating the experiment ``(name, version)``, it will create a new experiment
58-
``(name, version+1)`` which will have the same configuration than ``(name, version)`` except for
59-
the differing arguments given by user. This new experiment will have access to trials of
60-
``(name, version)``, adapted according to the differences between ``version`` and ``version+1``.
61-
A previous version can be accessed by specifying the ``version`` argument.
56+
``max_trials`` and ``max_broken`` may be overwritten in DB, but any other changes will lead to a
57+
branching. Instead of creating the experiment ``(name, version)``, it will create a new
58+
experiment ``(name, version+1)`` which will have the same configuration than ``(name, version)``
59+
except for the differing arguments given by user. This new experiment will have access to trials
60+
of ``(name, version)``, adapted according to the differences between ``version`` and
61+
``version+1``. A previous version can be accessed by specifying the ``version`` argument.
6262
6363
Causes of experiment branching are:
6464
@@ -91,6 +91,8 @@ def create_experiment(
9191
Parallel strategy to use to parallelize the algorithm.
9292
max_trials: int, optional
9393
Maximum number or trials before the experiment is considered done.
94+
max_broken: int, optional
95+
Number of broken trials for the experiment to be considered broken.
9496
storage: dict, optional
9597
Configuration of the storage backend.
9698
working_dir: str, optional
@@ -163,16 +165,16 @@ def create_experiment(
163165
try:
164166
experiment = experiment_builder.build(
165167
name, version=version, space=space, algorithms=algorithms,
166-
strategy=strategy, max_trials=max_trials, branching=branching,
168+
strategy=strategy, max_trials=max_trials, max_broken=max_broken, branching=branching,
167169
working_dir=working_dir)
168170
except RaceCondition:
169171
# Try again, but if it fails again, raise. Race conditions due to version increment should
170172
# only occur once in a short window of time unless code version is changing at a crazy pace.
171173
try:
172174
experiment = experiment_builder.build(
173175
name, version=version, space=space, algorithms=algorithms,
174-
strategy=strategy, max_trials=max_trials, branching=branching,
175-
working_dir=working_dir)
176+
strategy=strategy, max_trials=max_trials, max_broken=max_broken,
177+
branching=branching, working_dir=working_dir)
176178
except RaceCondition as e:
177179
raise RaceCondition(
178180
"There was a race condition during branching and new version cannot be infered "
@@ -214,7 +216,7 @@ def get_experiment(name, version=None, storage=None):
214216
return experiment_builder.build_view(name, version)
215217

216218

217-
def workon(function, space, name='loop', algorithms=None, max_trials=None):
219+
def workon(function, space, name='loop', algorithms=None, max_trials=None, max_broken=None):
218220
"""Optimize a function over a given search space
219221
220222
This will create a new experiment with an in-memory storage and optimize the given function
@@ -241,6 +243,8 @@ def workon(function, space, name='loop', algorithms=None, max_trials=None):
241243
Algorithm used for optimization.
242244
max_trials: int, optional
243245
Maximum number or trials before the experiment is considered done.
246+
max_broken: int, optional
247+
Number of broken trials for the experiment to be considered broken.
244248
245249
Raises
246250
------
@@ -256,7 +260,7 @@ def workon(function, space, name='loop', algorithms=None, max_trials=None):
256260

257261
experiment = experiment_builder.build(
258262
name, version=1, space=space, algorithms=algorithms,
259-
strategy='NoParallelStrategy', max_trials=max_trials)
263+
strategy='NoParallelStrategy', max_trials=max_trials, max_broken=max_broken)
260264

261265
producer = Producer(experiment)
262266

src/orion/client/experiment.py

+5
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ def max_trials(self):
9696
"""Max-trials to execute before stopping the experiment."""
9797
return self._experiment.max_trials
9898

99+
@property
100+
def max_broken(self):
101+
"""Minimum number of broken trials before the experiment is considered broken."""
102+
return self._experiment.max_broken
103+
99104
@property
100105
def metadata(self):
101106
"""Metadata of the experiment."""

src/orion/core/io/experiment_builder.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ def build(name, version=None, branching=None, **config):
138138
strategy: str or dict, optional
139139
Parallel strategy to use to parallelize the algorithm.
140140
max_trials: int, optional
141-
Maximum number or trials before the experiment is considered done.
141+
Maximum number of trials before the experiment is considered done.
142+
max_broken: int, optional
143+
Number of broken trials for the experiment to be considered broken.
142144
storage: dict, optional
143145
Configuration of the storage backend.
144146
branching: dict, optional
@@ -277,6 +279,8 @@ def create_experiment(name, version, space, **kwargs):
277279
Parallel strategy to use to parallelize the algorithm.
278280
max_trials: int, optional
279281
Maximum number or trials before the experiment is considered done.
282+
max_broken: int, optional
283+
Number of broken trials for the experiment to be considered broken.
280284
storage: dict, optional
281285
Configuration of the storage backend.
282286
@@ -288,6 +292,7 @@ def create_experiment(name, version, space, **kwargs):
288292
experiment.pool_size = orion.core.config.experiment.get(
289293
'pool_size', deprecated='ignore')
290294
experiment.max_trials = kwargs.get('max_trials', orion.core.config.experiment.max_trials)
295+
experiment.max_broken = kwargs.get('max_broken', orion.core.config.experiment.max_broken)
291296
experiment.space = _instantiate_space(space)
292297
experiment.algorithms = _instantiate_algo(experiment.space, kwargs.get('algorithms'))
293298
experiment.producer = kwargs.get('producer', {})
@@ -324,6 +329,7 @@ def fetch_config_from_db(name, version=None):
324329
"version %s.", name, config['version'])
325330

326331
backward.populate_space(config, force_update=False)
332+
backward.update_max_broken(config)
327333

328334
return config
329335

src/orion/core/utils/backward.py

+6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ def populate_priors(metadata):
3434
metadata["priors"] = dict(parser.priors)
3535

3636

37+
def update_max_broken(config):
38+
"""Set default max_broken if None (in v <= v0.1.9)"""
39+
if not config.get('max_broken', None):
40+
config['max_broken'] = orion.core.config.experiment.max_broken
41+
42+
3743
def populate_space(config, force_update=True):
3844
"""Add the space definition at the root of config."""
3945
if 'space' in config and not force_update:

src/orion/core/utils/format_terminal.py

+1
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ def format_commandline(experiment):
258258
{title}
259259
pool size: {experiment.pool_size}
260260
max trials: {experiment.max_trials}
261+
max broken: {experiment.max_broken}
261262
working dir: {experiment.working_dir}
262263
"""
263264

src/orion/core/worker/experiment.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import datetime
1414
import logging
1515

16-
import orion.core
1716
from orion.core.evc.adapters import BaseAdapter
1817
from orion.core.evc.experiment import ExperimentNode
1918
from orion.storage.base import FailedUpdate, get_storage, ReadOnlyStorageProtocol
@@ -48,6 +47,11 @@ class Experiment:
4847
This attribute can be updated if the rest of the experiment configuration
4948
is the same. In that case, if trying to set to an already set experiment,
5049
it will overwrite the previous one.
50+
max_broken: int
51+
How many trials must be broken, before considering this `Experiment` broken.
52+
This attribute can be updated if the rest of the experiment configuration
53+
is the same. In that case, if trying to set to an already set experiment,
54+
it will overwrite the previous one.
5155
space: Space
5256
Object representing the optimization space.
5357
algorithms : `PrimaryAlgo` object.
@@ -77,10 +81,10 @@ class Experiment:
7781
7882
"""
7983

80-
__slots__ = ('name', 'refers', 'metadata', 'pool_size', 'max_trials', 'version',
84+
__slots__ = ('name', 'refers', 'metadata', 'pool_size', 'max_trials', 'max_broken', 'version',
8185
'space', 'algorithms', 'producer', 'working_dir', '_id',
8286
'_node', '_storage')
83-
non_branching_attrs = ('pool_size', 'max_trials')
87+
non_branching_attrs = ('pool_size', 'max_trials', 'max_broken')
8488

8589
def __init__(self, name, version=None):
8690
self._id = None
@@ -91,6 +95,7 @@ def __init__(self, name, version=None):
9195
self.metadata = {}
9296
self.pool_size = None
9397
self.max_trials = None
98+
self.max_broken = None
9499
self.space = None
95100
self.algorithms = None
96101
self.working_dir = None
@@ -316,7 +321,7 @@ def is_broken(self):
316321
317322
"""
318323
num_broken_trials = self._storage.count_broken_trials(self)
319-
return num_broken_trials >= orion.core.config.worker.max_broken
324+
return num_broken_trials >= self.max_broken
320325

321326
@property
322327
def configuration(self):
@@ -409,7 +414,7 @@ class ExperimentView(object):
409414

410415
# Attributes
411416
valid_attributes = (["_id", "name", "refers", "metadata", "pool_size", "max_trials",
412-
"version", "space", "working_dir"] +
417+
"max_broken", "version", "space", "working_dir"] +
413418
# Properties
414419
["id", "node", "is_done", "is_broken", "algorithms", "stats",
415420
"configuration"] +

src/orion/serving/responses.py

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def build_experiment_response(experiment: Experiment,
7373
"orionVersion": experiment.metadata['orion_version'],
7474
"config": {
7575
"maxTrials": experiment.max_trials,
76+
"maxBroken": experiment.max_broken,
7677
"poolSize": experiment.pool_size,
7778
"algorithm": algorithm,
7879
"space": experiment.configuration['space']

tests/functional/demo/orion_config.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ name: voila_voici
22

33
pool_size: 1
44
max_trials: 100
5+
max_broken: 5
56

67
algorithms:
78
gradient_descent:

tests/functional/demo/orion_config_other.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ name: voila_voici
22

33
pool_size: 1
44
max_trials: 100
5+
max_broken: 5
56

67
algorithms:
78
gradient_descent:

tests/functional/demo/orion_config_random.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ name: demo_random_search
22

33
pool_size: 2
44
max_trials: 400
5+
max_broken: 5
56

67
algorithms: random
78

tests/functional/demo/test_demo.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def test_demo_with_default_algo_cli_config_only(database, monkeypatch):
3939
assert exp['name'] == 'default_algo'
4040
assert exp['pool_size'] == 1
4141
assert exp['max_trials'] == 30
42+
assert exp['max_broken'] == 3
4243
assert exp['algorithms'] == {'random': {'seed': None}}
4344
assert 'user' in exp['metadata']
4445
assert 'datetime' in exp['metadata']
@@ -74,6 +75,7 @@ def test_demo(database, monkeypatch):
7475
assert exp['name'] == 'voila_voici'
7576
assert exp['pool_size'] == 1
7677
assert exp['max_trials'] == 100
78+
assert exp['max_broken'] == 5
7779
assert exp['algorithms'] == {'gradient_descent': {'learning_rate': 0.1,
7880
'dx_tolerance': 1e-7}}
7981
assert 'user' in exp['metadata']
@@ -117,6 +119,7 @@ def test_demo_with_script_config(database, monkeypatch):
117119
assert exp['name'] == 'voila_voici'
118120
assert exp['pool_size'] == 1
119121
assert exp['max_trials'] == 100
122+
assert exp['max_broken'] == 5
120123
assert exp['algorithms'] == {'gradient_descent': {'learning_rate': 0.1,
121124
'dx_tolerance': 1e-7}}
122125
assert 'user' in exp['metadata']
@@ -162,6 +165,7 @@ def test_demo_with_python_and_script(database, monkeypatch):
162165
assert exp['name'] == 'voila_voici'
163166
assert exp['pool_size'] == 1
164167
assert exp['max_trials'] == 100
168+
assert exp['max_broken'] == 5
165169
assert exp['algorithms'] == {'gradient_descent': {'learning_rate': 0.1,
166170
'dx_tolerance': 1e-7}}
167171
assert 'user' in exp['metadata']
@@ -227,6 +231,7 @@ def test_demo_two_workers(database, monkeypatch):
227231
assert exp['name'] == 'two_workers_demo'
228232
assert exp['pool_size'] == 2
229233
assert exp['max_trials'] == 100
234+
assert exp['max_broken'] == 5
230235
assert exp['algorithms'] == {'random': {'seed': None}}
231236
assert 'user' in exp['metadata']
232237
assert 'datetime' in exp['metadata']
@@ -257,6 +262,7 @@ def test_workon():
257262
}
258263
config['pool_size'] = 1
259264
config['max_trials'] = 100
265+
config['exp_max_broken'] = 5
260266
config['user_args'] = [
261267
os.path.abspath(os.path.join(os.path.dirname(__file__), "black_box.py")),
262268
"-x~uniform(-50, 50, precision=None)"]
@@ -275,6 +281,7 @@ def test_workon():
275281
assert exp['name'] == name
276282
assert exp['pool_size'] == 1
277283
assert exp['max_trials'] == 100
284+
assert exp['max_broken'] == 5
278285
assert exp['algorithms'] == {'gradient_descent': {'learning_rate': 0.1,
279286
'dx_tolerance': 1e-7}}
280287
assert 'user' in exp['metadata']
@@ -473,7 +480,6 @@ def test_run_with_parallel_strategy(database, monkeypatch, strategy):
473480
assert len(exp) == 1
474481
exp = exp[0]
475482
assert exp['producer']['strategy'] == strategy
476-
print(exp['max_trials'])
477483
assert '_id' in exp
478484
exp_id = exp['_id']
479485
trials = list(database.trials.find({'experiment': exp_id}))

tests/functional/serving/test_experiments_resource.py

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
version=1,
2323
pool_size=1,
2424
max_trials=10,
25+
max_broken=7,
2526
working_dir='',
2627
algorithms={'random': {'seed': 1}},
2728
producer={'strategy': 'NoParallelStrategy'},
@@ -199,6 +200,7 @@ def _assert_config(config):
199200
"""Asserts properties of the ``config`` dictionary"""
200201
assert config['poolSize'] == 1
201202
assert config['maxTrials'] == 10
203+
assert config['maxBroken'] == 7
202204

203205
algorithm = config['algorithm']
204206
assert algorithm['name'] == 'random'

tests/unittests/client/test_client.py

+6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
version=1,
3838
pool_size=1,
3939
max_trials=10,
40+
max_broken=5,
4041
working_dir='',
4142
algorithms={'random': {'seed': 1}},
4243
producer={'strategy': 'NoParallelStrategy'},
@@ -195,6 +196,7 @@ def test_create_experiment_new_default(self):
195196
assert experiment.space.configuration == space
196197

197198
assert experiment.max_trials == orion.core.config.experiment.max_trials
199+
assert experiment.max_broken == orion.core.config.experiment.max_broken
198200
assert experiment.working_dir == orion.core.config.experiment.working_dir
199201
assert experiment.algorithms.configuration == {'random': {'seed': None}}
200202
assert experiment.configuration['producer'] == {'strategy': 'MaxParallelStrategy'}
@@ -208,6 +210,7 @@ def test_create_experiment_new_full_config(self, user_config):
208210

209211
assert exp_config['space'] == config['space']
210212
assert exp_config['max_trials'] == config['max_trials']
213+
assert exp_config['max_broken'] == config['max_broken']
211214
assert exp_config['working_dir'] == config['working_dir']
212215
assert exp_config['algorithms'] == config['algorithms']
213216
assert exp_config['producer'] == config['producer']
@@ -223,6 +226,7 @@ def test_create_experiment_hit_no_branch(self, user_config):
223226
assert experiment.version == 1
224227
assert exp_config['space'] == config['space']
225228
assert exp_config['max_trials'] == config['max_trials']
229+
assert exp_config['max_broken'] == config['max_broken']
226230
assert exp_config['working_dir'] == config['working_dir']
227231
assert exp_config['algorithms'] == config['algorithms']
228232
assert exp_config['producer'] == config['producer']
@@ -237,6 +241,7 @@ def test_create_experiment_hit_no_config(self):
237241
assert experiment.space.configuration == config['space']
238242
assert experiment.algorithms.configuration == config['algorithms']
239243
assert experiment.max_trials == config['max_trials']
244+
assert experiment.max_broken == config['max_broken']
240245
assert experiment.working_dir == config['working_dir']
241246
assert experiment.producer['strategy'].configuration == config['producer']['strategy']
242247

@@ -250,6 +255,7 @@ def test_create_experiment_hit_branch(self):
250255

251256
assert experiment.algorithms.configuration == config['algorithms']
252257
assert experiment.max_trials == config['max_trials']
258+
assert experiment.max_broken == config['max_broken']
253259
assert experiment.working_dir == config['working_dir']
254260
assert experiment.producer['strategy'].configuration == config['producer']['strategy']
255261

tests/unittests/client/test_experiment_client.py

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
version=1,
2929
pool_size=1,
3030
max_trials=10,
31+
max_broken=5,
3132
working_dir='',
3233
algorithms={'random': {'seed': 1}},
3334
producer={'strategy': 'NoParallelStrategy'},

0 commit comments

Comments
 (0)