Skip to content

Commit c734f4c

Browse files
authored
Merge branch 'develop' into issue214
2 parents 9f6d8f1 + 8f8ec4e commit c734f4c

3 files changed

Lines changed: 56 additions & 10 deletions

File tree

openml/runs/functions.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
import numpy as np
66
import warnings
77
import sklearn
8+
import time
9+
from sklearn.model_selection._search import BaseSearchCV
810

911
from ..exceptions import PyOpenMLError
1012
from .. import config
1113
from ..flows import sklearn_to_flow, get_flow, flow_exists
1214
from ..setups import setup_exists
1315
from ..exceptions import OpenMLCacheException, OpenMLServerException
14-
from ..util import URLError
16+
from ..util import URLError, version_complies
1517
from ..tasks.functions import _create_task_from_xml
1618
from .._api_calls import _perform_api_call
1719
from .run import OpenMLRun, _get_version_information
@@ -155,6 +157,7 @@ def _run_task_get_arffcontent(model, task, class_labels):
155157
X, Y = task.get_X_and_y()
156158
arff_datacontent = []
157159
arff_tracecontent = []
160+
user_defined_measures = defaultdict(lambda: defaultdict(dict))
158161

159162
rep_no = 0
160163
# TODO use different iterator to only provide a single iterator (less
@@ -170,20 +173,41 @@ def _run_task_get_arffcontent(model, task, class_labels):
170173
testY = Y[test_indices]
171174

172175
try:
176+
# for measuring runtime. Only available since Python 3.3
177+
if version_complies(3, 3):
178+
modelfit_starttime = time.process_time()
173179
model_fold.fit(trainX, trainY)
180+
181+
if version_complies(3, 3):
182+
modelfit_duration = (time.process_time() - modelfit_starttime) * 1000
183+
user_defined_measures['usercpu_time_millis_training'][rep_no][fold_no] = modelfit_duration
184+
185+
if isinstance(model_fold, sklearn.model_selection._search.BaseSearchCV):
186+
arff_tracecontent.extend(_extract_arfftrace(model_fold, rep_no, fold_no))
187+
model_classes = model_fold.best_estimator_.classes_
188+
else:
189+
model_classes = model_fold.classes_
174190
except AttributeError as e:
175191
# typically happens when training a regressor on classification task
176192
raise PyOpenMLError(str(e))
177-
193+
178194
# extract trace
179195
if isinstance(model_fold, sklearn.model_selection._search.BaseSearchCV):
180196
arff_tracecontent.extend(_extract_arfftrace(model_fold, rep_no, fold_no))
181197
model_classes = model_fold.best_estimator_.classes_
182198
else:
183199
model_classes = model_fold.classes_
184200

201+
if version_complies(3, 3):
202+
modelpredict_starttime = time.process_time()
203+
185204
ProbaY = model_fold.predict_proba(testX)
186205
PredY = model_fold.predict(testX)
206+
if version_complies(3, 3):
207+
modelpredict_duration = (time.process_time() - modelpredict_starttime) * 1000
208+
user_defined_measures['usercpu_time_millis_testing'][rep_no][fold_no] = modelpredict_duration
209+
user_defined_measures['usercpu_time_millis'][rep_no][fold_no] = modelfit_duration + modelpredict_duration
210+
187211
if ProbaY.shape[1] != len(class_labels):
188212
warnings.warn("Repeat %d Fold %d: estimator only predicted for %d/%d classes!" %(rep_no, fold_no, ProbaY.shape[1], len(class_labels)))
189213

@@ -200,7 +224,6 @@ def _run_task_get_arffcontent(model, task, class_labels):
200224
else:
201225
arff_tracecontent = None
202226
arff_trace_attributes = None
203-
204227
return arff_datacontent, arff_tracecontent, arff_trace_attributes
205228

206229

@@ -423,7 +446,7 @@ def _get_cached_run(run_id):
423446
run_file = os.path.join(run_cache_dir,
424447
"run_%d.xml" % int(run_id))
425448
with io.open(run_file, encoding='utf8') as fh:
426-
run = _create_task_from_xml(xml=fh.read())
449+
run = _create_run_from_xml(xml=fh.read())
427450
return run
428451

429452
except (OSError, IOError):

openml/runs/run.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,17 @@ def _create_description_xml(self):
149149

150150
openml_param_settings = OpenMLRun._parse_parameters(self.model, downloaded_flow)
151151

152+
# as a tag, it must be of the form ([a-zA-Z0-9_\-\.])+
153+
# so we format time from 'mm/dd/yy hh:mm:ss' to 'mm-dd-yy_hh.mm.ss'
154+
# well_formatted_time = time.strftime("%c").replace(
155+
# ' ', '_').replace('/', '-').replace(':', '.')
156+
# tags = run_environment + [well_formatted_time] + ['run_task'] + \
157+
# [self.model.__module__ + "." + self.model.__class__.__name__]
152158
description = _to_dict(taskid=self.task_id, flow_id=self.flow_id,
153159
setup_string=_create_setup_string(self.model),
154160
parameter_settings=openml_param_settings,
155161
error_message=self.error_message,
162+
detailed_evaluations=self.detailed_evaluations,
156163
tags=self.tags)
157164
description_xml = xmltodict.unparse(description, pretty=True)
158165
return description_xml
@@ -241,7 +248,7 @@ def _get_version_information():
241248
return [python_version, sklearn_version, numpy_version, scipy_version]
242249

243250

244-
def _to_dict(taskid, flow_id, setup_string, error_message, parameter_settings, tags):
251+
def _to_dict(taskid, flow_id, setup_string, error_message, parameter_settings, tags=None, detailed_evaluations=None):
245252
""" Creates a dictionary corresponding to the desired xml desired by openML
246253
247254
Parameters
@@ -268,11 +275,17 @@ def _to_dict(taskid, flow_id, setup_string, error_message, parameter_settings, t
268275
if error_message is not None:
269276
description['oml:run']['oml:error_message'] = error_message
270277
description['oml:run']['oml:parameter_setting'] = parameter_settings
271-
description['oml:run']['oml:tag'] = tags # Tags describing the run
272-
# description['oml:run']['oml:output_data'] = 0;
273-
# all data that was output of this run, which can be evaluation scores
274-
# (though those are also calculated serverside)
275-
# must be of special data type
278+
if tags is not None:
279+
description['oml:run']['oml:tag'] = tags # Tags describing the run
280+
if detailed_evaluations is not None:
281+
description['oml:run']['oml:output_data'] = dict()
282+
description['oml:run']['oml:output_data']['oml:evaluation'] = list()
283+
for measure in detailed_evaluations:
284+
for repeat in detailed_evaluations[measure]:
285+
for fold, value in detailed_evaluations[measure][repeat].items():
286+
current = OrderedDict([('@repeat', str(repeat)), ('@fold', str(fold)),
287+
('oml:name', measure), ('oml:value', str(value))])
288+
description['oml:run']['oml:output_data']['oml:evaluation'].append(current)
276289
return description
277290

278291

openml/util.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,15 @@ def is_string(obj):
1212
except NameError:
1313
return isinstance(obj, str)
1414

15+
def version_complies(major, minor=None):
16+
version = sys.version_info
17+
if version[0] > major:
18+
return True
19+
if version[0] < major:
20+
return False
21+
# version == major
22+
if minor is None or version[1] >= minor:
23+
return True
24+
return False
1525

1626
__all__ = ['URLError', 'is_string']

0 commit comments

Comments
 (0)