-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathstorage.py
137 lines (106 loc) · 4.48 KB
/
storage.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import json
import logging
import uuid
from abc import ABC, abstractmethod
from copy import copy, deepcopy
from pathlib import Path
from string import Template
from prettytable import PrettyTable
# pylint: disable=import-error
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger()
LOG_FILENAME = 'log.txt'
class StorageInterface:
def __init__(self, *args, **kwargs):
self._outdir = "N/A"
@property
def outdir(self):
return self._outdir
@abstractmethod
def store_knobs_importances(self, iter_, knob_importances):
raise NotImplementedError
@abstractmethod
def store_executor_result(self, iter_, result):
raise NotImplementedError
@abstractmethod
def store_result_summary(self, summary):
raise NotImplementedError
class NoStorage(StorageInterface):
def store_knobs_importances(self, iter_, knob_importances):
pass
def store_executor_result(self, iter_, result):
pass
def store_result_summary(self, summary):
pass
class FileTablesStorage(StorageInterface):
def __init__(self, outdir=None, columns=None, inner_path=None):
assert outdir != None, 'Need to provide outdir'
assert logger != None, 'Need to provide instance of logger'
# Create base results dir if not exists
outdir = Path(outdir) if not isinstance(outdir, Path) else outdir
outdir.mkdir(exist_ok=True)
if inner_path is None:
# Create unique dir inside
experiment_path = outdir / Path(uuid.uuid4().hex[:8])
while experiment_path.exists():
experiment_path = outdir / Path(uuid.uuid4().hex[:8])
else:
experiment_path = outdir / inner_path
if experiment_path.exists():
raise FileExistsError('Experiment output path already exists')
experiment_path.mkdir(parents=True)
self._outdir = experiment_path
logger.addHandler(
logging.FileHandler(self.outdir / LOG_FILENAME))
logger.info(f'Results will be saved @ "{self.outdir}"\n\n')
# Summary table initialization
self.table = PrettyTable()
self.table.field_names = copy(columns)
self.table_txt_filepath = self.outdir / 'optimizer.txt'
self.table_csv_filepath = self.outdir / 'optimizer.csv'
self.executor_result_filename_template = Template('iter-${iter}.json')
def store_knobs_importances(self, iter_, knob_importances):
# Save to table
ki_table = PrettyTable()
ki_table.field_names = ['Knob', 'Importance Score']
for knob, importance in knob_importances:
logger.info(f'\t{knob}:\t{importance:.3f}')
ki_table.add_row([knob, importance])
ki_table_filepath = self.outdir / f'ki-{iter_}.txt'
ki_table_csv_filepath = self.outdir / f'ki-{iter_}.csv'
with open(ki_table_filepath, 'w') as f:
f.write(ki_table.get_string())
with open(ki_table_csv_filepath, 'w') as f:
f.write(ki_table.get_csv_string())
logger.info(f'Knobs importances saved @ {ki_table_filepath}')
def store_executor_result(self, iter_, result):
filename = self.executor_result_filename_template.substitute(iter=iter_)
filepath = self.outdir / filename
with open(filepath, 'w') as f:
json.dump(result, f)
def store_result_summary(self, summary):
assert set(summary.keys()) == set(self.table.field_names)
row = [ summary[k] for k in self.table.field_names ]
self.table.add_row(row)
with open(self.table_txt_filepath, 'w') as f:
f.write(self.table.get_string())
with open(self.table_csv_filepath, 'w') as f:
f.write(self.table.get_csv_string())
class StorageFactory:
concrete_classes = {
'FileTablesStorage': FileTablesStorage,
'NoStorage': NoStorage,
}
@staticmethod
def from_config(config, **extra_kwargs):
storage_config = deepcopy(config['storage'])
classname = storage_config.pop('classname', None)
assert classname != None, 'Please specify the storage class name'
try:
class_ = StorageFactory.concrete_classes[classname]
except KeyError:
raise ValueError(f'Storage class "{classname}" not found. '
f'Options are [{", ".join(StorageFactory.concrete_classes.keys())}]')
# Override with local
storage_config.update(**extra_kwargs)
return class_(**storage_config)