This repository has been archived by the owner on Sep 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
feature: export experiment results #2706
Merged
Merged
Changes from 17 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
1362b00
feature: export experiment results
tabVersion a128bc0
code format
tabVersion e862c1a
fix
tabVersion d3e03a7
merge to `nnictl experiment export`
tabVersion 7ac572b
code format
tabVersion 8379c0f
remove unused import
tabVersion 194679e
add example
tabVersion 3b23df0
code change
tabVersion ff3eea9
Update Nnictl.md
tabVersion 8d9713f
Update nnictl.py
tabVersion dea1c23
Update nnictl.py
tabVersion 4316393
optimize logic flow
tabVersion 7c7dba8
optimize
tabVersion 5ef17ff
remove unused import
tabVersion 74827a5
patch
tabVersion 6ff03d0
patch
tabVersion a58a588
Update Nnictl.md
tabVersion ca195da
Update nnictl_utils.py
tabVersion 135b7b2
replace eval with json.loads & rename
tabVersion 7d115a5
Merge branch 'master' into export-results
tabVersion File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,7 @@ | |
from nni.package_utils import get_nni_installation_path | ||
from nni_annotation import expand_annotations | ||
from .rest_utils import rest_get, rest_delete, check_rest_server_quick, check_response | ||
from .url_utils import trial_jobs_url, experiment_url, trial_job_id_url, export_data_url | ||
from .url_utils import trial_jobs_url, experiment_url, trial_job_id_url, export_data_url, metric_data_url | ||
from .config_utils import Config, Experiments | ||
from .constants import NNICTL_HOME_DIR, EXPERIMENT_INFORMATION_FORMAT, EXPERIMENT_DETAIL_FORMAT, \ | ||
EXPERIMENT_MONITOR_INFO, TRIAL_MONITOR_HEAD, TRIAL_MONITOR_CONTENT, TRIAL_MONITOR_TAIL, REST_TIME_OUT | ||
|
@@ -681,45 +681,64 @@ def monitor_experiment(args): | |
set_monitor(False, args.time) | ||
|
||
def export_trials_data(args): | ||
'''export experiment metadata to csv | ||
'''export experiment metadata and intermediate results to json or csv | ||
''' | ||
def groupby_trial_id(intermediate_results): | ||
sorted(intermediate_results, key=lambda x: x['timestamp']) | ||
groupby = dict() | ||
for content in intermediate_results: | ||
groupby.setdefault(content['trialJobId'], []).append(eval(content['data'])) | ||
return groupby | ||
|
||
nni_config = Config(get_config_filename(args)) | ||
rest_port = nni_config.get_config('restServerPort') | ||
rest_pid = nni_config.get_config('restServerPid') | ||
|
||
if not detect_process(rest_pid): | ||
print_error('Experiment is not running...') | ||
return | ||
running, response = check_rest_server_quick(rest_port) | ||
if running: | ||
response = rest_get(export_data_url(rest_port), 20) | ||
if response is not None and check_response(response): | ||
if args.type == 'json': | ||
with open(args.path, 'w') as file: | ||
file.write(response.text) | ||
elif args.type == 'csv': | ||
content = json.loads(response.text) | ||
trial_records = [] | ||
for record in content: | ||
record_value = json.loads(record['value']) | ||
if not isinstance(record_value, (float, int)): | ||
formated_record = {**record['parameter'], **record_value, **{'id': record['id']}} | ||
else: | ||
formated_record = {**record['parameter'], **{'reward': record_value, 'id': record['id']}} | ||
trial_records.append(formated_record) | ||
if not trial_records: | ||
print_error('No trial results collected! Please check your trial log...') | ||
exit(0) | ||
with open(args.path, 'w', newline='') as file: | ||
writer = csv.DictWriter(file, set.union(*[set(r.keys()) for r in trial_records])) | ||
writer.writeheader() | ||
writer.writerows(trial_records) | ||
else: | ||
print_error('Unknown type: %s' % args.type) | ||
exit(1) | ||
if not running: | ||
print_error('Restful server is not Running') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Running -> running There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
return | ||
response = rest_get(export_data_url(rest_port), 20) | ||
if response is not None and check_response(response): | ||
content = json.loads(response.text) | ||
if args.intermediate: | ||
intermediate_results = rest_get(metric_data_url(rest_port), REST_TIME_OUT) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in my point, use |
||
if not intermediate_results or not check_response(intermediate_results): | ||
print_error('Error getting intermediate results.') | ||
return | ||
intermediate_results = groupby_trial_id(json.loads(intermediate_results.text)) | ||
for record in content: | ||
record['intermediate'] = intermediate_results[record['id']] | ||
if args.type == 'json': | ||
with open(args.path, 'w') as file: | ||
file.write(json.dumps(content)) | ||
elif args.type == 'csv': | ||
trial_records = [] | ||
for record in content: | ||
formated_record = dict() | ||
if args.intermediate: | ||
formated_record['intermediate'] = '[' + ','.join(record['intermediate']) + ']' | ||
record_value = json.loads(record['value']) | ||
if not isinstance(record_value, (float, int)): | ||
formated_record.update({**record['parameter'], **record_value, **{'id': record['id']}}) | ||
else: | ||
formated_record.update({**record['parameter'], **{'reward': record_value, 'id': record['id']}}) | ||
trial_records.append(formated_record) | ||
if not trial_records: | ||
print_error('No trial results collected! Please check your trial log...') | ||
exit(0) | ||
with open(args.path, 'w', newline='') as file: | ||
writer = csv.DictWriter(file, set.union(*[set(r.keys()) for r in trial_records])) | ||
writer.writeheader() | ||
writer.writerows(trial_records) | ||
else: | ||
print_error('Export failed...') | ||
print_error('Unknown type: %s' % args.type) | ||
return | ||
else: | ||
print_error('Restful server is not Running') | ||
print_error('Export failed...') | ||
|
||
def search_space_auto_gen(args): | ||
'''dry run trial code to generate search space file''' | ||
|
@@ -736,3 +755,4 @@ def search_space_auto_gen(args): | |
print_warning('Expected search space file \'{}\' generated, but not found.'.format(file_path)) | ||
else: | ||
print_normal('Generate search space done: \'{}\'.'.format(file_path)) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why use eval()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The returned data is serialized. For example,
"\"{\\\"default\\\": 93.64, \\\"other_metric\\\": 2.0}\""
.Using
eval()
can easily handle the\
part and reconstruct the data structure from the string. It is troublesome for users to handle serialized data.The data from the server can be trusted so I think using
eval
here is safe here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not simply use json.loads?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks that
json.loads()
is a good solution.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please double check whether it works properly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure I will. Thanks for reminding me.