def to_networkx(self, prefix: str = None): import networkx as nx g = nx.DiGraph() predecessor = None for name, estimator in self.steps_.items(): name = prefixed_name(prefix, name) g.add_node(name, label=estimator.name().split('.')[-1], name=name) if predecessor is not None: g.add_edge(predecessor, name) predecessor = name return g
def _get_config_for_step(self, idx: int, prefix: str, name: str, logger: ProcessLogger) -> Configuration: start = timeit.default_timer() cfg_key = self.cfg_keys[idx] config, cfg_key = self.cfg_cache.sample_configuration(cid=self.cid, name=name, cfg_key=cfg_key) intermediate = PartialConfig(cfg_key, config, name, None) logger.new_step(prefixed_name(prefix, name), intermediate) self.config_time += timeit.default_timer() - start return config
def merge_configurations( partial_configs, # type: List[PartialConfig] cs: ConfigurationSpace) -> Configuration: complete = {} for partial_config in partial_configs: for param, value in partial_config.config.get_dictionary().items(): param = prefixed_name(partial_config.name, param) complete[param] = value config = Configuration(cs, complete) config.origin = Counter([ p.config.origin for p in partial_configs if not p.is_empty() ]).most_common(1)[0][0] return config
def __init__(self, data: Dict[CandidateId, CandidateStructure], meta_information: MetaInformation, structure_xai: Dict[str, Any], config_xai: Dict[ConfigKey, Any]): # Map structures to JSON structure structures = [] config_explanations = {} for s in data.values(): structure = s.as_dict() # Store budget in each configuration instead of only in structure. Only necessary for compatability with # other AutoML frameworks structure['configs'] = [ r.as_dict(s.budget, loss_sign=metric_sign(meta_information.metric)) for r in s.results ] del structure['budget'] del structure['cfg_keys'] structures.append(structure) # Extract and merge all (partial-) configurations explanations_for_steps = [config_xai[key] for key in s.cfg_keys] for cid in [r.cid.external_name for r in s.results]: try: partial_configs = [] loss = [] marginalization = {} for explanations_for_step in explanations_for_steps: pcs = explanations_for_step[cid]['candidates'] if len(pcs) == 0: continue prefix = pcs[0].name partial_configs.append(pcs) loss.append(explanations_for_step[cid]['loss']) marginalization = { **marginalization, **{ prefixed_name(prefix, key): value for key, value in explanations_for_step[cid]['marginalization'].items( ) } } if len(loss) > 0 and len(partial_configs) == len( explanations_for_steps): loss = np.array(loss).T.mean(axis=1) configs = [ merge_configurations( pc.tolist(), s.configspace).get_dictionary() for pc in np.array(partial_configs).T ] config_explanations[cid] = { 'loss': np.clip(loss, -100, 100).tolist(), 'candidates': configs, 'marginalization': marginalization } except ValueError as ex: # noinspection PyUnboundLocalVariable logging.error( 'Failed to reconstruct global config.\n' f'Exception: {ex}\nStructure: {structure["pipeline"]}\n' f'ConfigSpace: {structure["configspace"]}\nConfig: {partial_configs}' ) except KeyError: logging.error( f'Failed to find cid {cid} in config explanations') self.data = data self.meta_information = meta_information self.complete_data = { 'meta': meta_information.as_dict(), 'structures': structures, 'explanations': { 'structures': structure_xai, 'configs': config_explanations } }
def all_names(self, prefix: str = None) -> List[str]: res = [] for name, component in self.steps_.items(): res.append(prefixed_name(prefix, name)) return res