1212from smac .tae .execute_ta_run import StatusType , BudgetExhaustedException , \
1313 TAEAbortException
1414from smac .tae .execute_func import AbstractTAFunc
15+
1516from ConfigSpace import Configuration
1617from sklearn .model_selection ._split import _RepeatedSplits , BaseShuffleSplit ,\
1718 BaseCrossValidator
19+ from autosklearn .metrics import Scorer
1820
1921import autosklearn .evaluation .train_evaluator
2022import autosklearn .evaluation .test_evaluator
2123import autosklearn .evaluation .util
2224
23- WORST_POSSIBLE_RESULT = 1.0
24-
2525
26- def fit_predict_try_except_decorator (ta , queue , ** kwargs ):
26+ def fit_predict_try_except_decorator (ta , queue , cost_for_crash , ** kwargs ):
2727
2828 try :
2929 return ta (queue = queue , ** kwargs )
@@ -35,13 +35,32 @@ def fit_predict_try_except_decorator(ta, queue, **kwargs):
3535 exception_traceback = traceback .format_exc ()
3636 error_message = repr (e )
3737
38- queue .put ({'loss' : WORST_POSSIBLE_RESULT ,
38+ queue .put ({'loss' : cost_for_crash ,
3939 'additional_run_info' : {'traceback' : exception_traceback ,
4040 'error' : error_message },
4141 'status' : StatusType .CRASHED ,
4242 'final_queue_element' : True })
4343
4444
45+ def get_cost_of_crash (metric ):
46+
47+ # The metric must always be defined to extract optimum/worst
48+ if not isinstance (metric , Scorer ):
49+ raise ValueError ("The metric must be stricly be an instance of Scorer" )
50+
51+ # Autosklearn optimizes the err. This function translates
52+ # worst_possible_result to be a minimization problem.
53+ # For metrics like accuracy that are bounded to [0,1]
54+ # metric.optimum==1 is the worst cost.
55+ # A simple guide is to use greater_is_better embedded as sign
56+ if metric ._sign < 0 :
57+ worst_possible_result = metric ._worst_possible_result
58+ else :
59+ worst_possible_result = metric ._optimum - metric ._worst_possible_result
60+
61+ return worst_possible_result
62+
63+
4564# TODO potentially log all inputs to this class to pickle them in order to do
4665# easier debugging of potential crashes
4766class ExecuteTaFuncWithQueue (AbstractTAFunc ):
@@ -78,15 +97,21 @@ def __init__(self, backend, autosklearn_seed, resampling_strategy, metric,
7897 raise ValueError ('Unknown resampling strategy %s' %
7998 resampling_strategy )
8099
81- eval_function = functools .partial (fit_predict_try_except_decorator ,
82- ta = eval_function )
100+ self .worst_possible_result = get_cost_of_crash (metric )
101+
102+ eval_function = functools .partial (
103+ fit_predict_try_except_decorator ,
104+ ta = eval_function ,
105+ cost_for_crash = self .worst_possible_result ,
106+ )
107+
83108 super ().__init__ (
84109 ta = eval_function ,
85110 stats = stats ,
86111 runhistory = runhistory ,
87112 run_obj = run_obj ,
88113 par_factor = par_factor ,
89- cost_for_crash = WORST_POSSIBLE_RESULT ,
114+ cost_for_crash = self . worst_possible_result ,
90115 )
91116
92117 self .backend = backend
@@ -250,7 +275,7 @@ def run(self, config, instance=None,
250275 if status in [StatusType .SUCCESS , StatusType .DONOTADVANCE ]:
251276 cost = result
252277 else :
253- cost = WORST_POSSIBLE_RESULT
278+ cost = self . worst_possible_result
254279
255280 except Empty :
256281 info = None
@@ -265,12 +290,12 @@ def run(self, config, instance=None,
265290 }
266291 else :
267292 raise ValueError (obj .exit_status )
268- cost = WORST_POSSIBLE_RESULT
293+ cost = self . worst_possible_result
269294
270295 elif obj .exit_status is TAEAbortException :
271296 info = None
272297 status = StatusType .ABORT
273- cost = WORST_POSSIBLE_RESULT
298+ cost = self . worst_possible_result
274299 additional_run_info = {'error' : 'Your configuration of '
275300 'auto-sklearn does not work!' }
276301
@@ -285,7 +310,7 @@ def run(self, config, instance=None,
285310 cost = result
286311 else :
287312 status = StatusType .CRASHED
288- cost = WORST_POSSIBLE_RESULT
313+ cost = self . worst_possible_result
289314 additional_run_info ['info' ] = 'Run treated as crashed ' \
290315 'because the pynisher exit ' \
291316 'status %s is unknown.' % \
@@ -294,7 +319,7 @@ def run(self, config, instance=None,
294319 info = None
295320 additional_run_info = {'error' : 'Result queue is empty' }
296321 status = StatusType .CRASHED
297- cost = WORST_POSSIBLE_RESULT
322+ cost = self . worst_possible_result
298323
299324 if (
300325 (self .budget_type is None or budget == 0 )
0 commit comments