def test_drop_mutation_for_linear_graph(): """ Tests single_drop mutation can remove node """ linear_two_nodes = OptGraph(OptNode('logit', [OptNode('scaling')])) linear_one_node = OptGraph(OptNode('logit')) composer_requirements = GPComposerRequirements(primary=['scaling'], secondary=['logit'], mutation_prob=1) graph_params = GraphGenerationParams( adapter=DirectAdapter(), rules_for_constraint=DEFAULT_DAG_RULES) successful_mutation_drop = False for _ in range(100): graph_after_mutation = mutation(types=[MutationTypesEnum.single_drop], params=graph_params, ind=Individual(linear_two_nodes), requirements=composer_requirements, log=default_log(__name__), max_depth=2).graph if not successful_mutation_drop: successful_mutation_drop = \ graph_after_mutation.root_node.descriptive_id == linear_one_node.root_node.descriptive_id else: break assert successful_mutation_drop
def test_edge_mutation_for_graph(): """ Tests edge mutation can add edge between nodes """ graph_without_edge = \ OptGraph(OptNode('logit', [OptNode('one_hot_encoding', [OptNode('scaling')])])) primary = OptNode('scaling') graph_with_edge = \ OptGraph(OptNode('logit', [OptNode('one_hot_encoding', [primary]), primary])) composer_requirements = GPComposerRequirements( primary=['scaling', 'one_hot_encoding'], secondary=['logit', 'scaling'], mutation_prob=1) graph_params = GraphGenerationParams( adapter=DirectAdapter(), rules_for_constraint=DEFAULT_DAG_RULES) successful_mutation_edge = False for _ in range(100): graph_after_mutation = mutation(types=[MutationTypesEnum.single_edge], params=graph_params, ind=Individual(graph_without_edge), requirements=composer_requirements, log=default_log(__name__), max_depth=graph_with_edge.depth).graph if not successful_mutation_edge: successful_mutation_edge = \ graph_after_mutation.root_node.descriptive_id == graph_with_edge.root_node.descriptive_id else: break assert successful_mutation_edge
def test_intermediate_add_mutation_for_linear_graph(): """ Tests single_add mutation can add node between two existing nodes """ linear_two_nodes = OptGraph(OptNode('logit', [OptNode('scaling')])) linear_three_nodes_inner = \ OptGraph(OptNode('logit', [OptNode('one_hot_encoding', [OptNode('scaling')])])) composer_requirements = GPComposerRequirements( primary=['scaling'], secondary=['one_hot_encoding'], mutation_prob=1) graph_params = GraphGenerationParams( adapter=DirectAdapter(), rules_for_constraint=DEFAULT_DAG_RULES) successful_mutation_inner = False for _ in range(100): graph_after_mutation = mutation(types=[MutationTypesEnum.single_add], params=graph_params, ind=Individual(linear_two_nodes), requirements=composer_requirements, log=default_log(__name__), max_depth=3).graph if not successful_mutation_inner: successful_mutation_inner = \ graph_after_mutation.root_node.descriptive_id == linear_three_nodes_inner.root_node.descriptive_id else: break assert successful_mutation_inner
def random_graph(params, requirements, max_depth=None) -> Any: max_depth = max_depth if max_depth else requirements.max_depth def graph_growth(graph: Any, node_parent: Any): offspring_size = randint(requirements.min_arity, requirements.max_arity) for offspring_node in range(offspring_size): height = graph.operator.distance_to_root_level(node_parent) is_max_depth_exceeded = height >= max_depth - 1 is_primary_node_selected = height < max_depth - 1 and randint(0, 1) if is_max_depth_exceeded or is_primary_node_selected: primary_node = OptNode(nodes_from=None, content=choice(requirements.primary)) node_parent.nodes_from.append(primary_node) graph.add_node(primary_node) else: secondary_node = OptNode(nodes_from=[], content=choice(requirements.secondary)) graph.add_node(secondary_node) node_parent.nodes_from.append(secondary_node) graph_growth(graph, secondary_node) is_correct_graph = False graph = None n_iters = 0 while not is_correct_graph or n_iters > max_iters: graph = OptGraph() graph_root = OptNode(nodes_from=[], content=choice(requirements.secondary)) graph.add_node(graph_root) graph_growth(graph, graph_root) is_correct_graph = constraint_function(graph, params) n_iters += 1 if n_iters > max_iters: warnings.warn(f'Random_graph generation failed for {n_iters} iterations.') return graph
def adapt(self, adaptee: Pipeline): opt_nodes = [] for node in adaptee.nodes: self._transform_to_opt_node(node) opt_nodes.append(node) graph = OptGraph(opt_nodes) graph.uid = adaptee.uid return graph
def decremental_regularization(population: List[Individual], objective_function: Callable, params: 'GraphGenerationParams', size: Optional[int] = None, timer=None) -> List[Any]: size = size if size else len(population) additional_inds = [] prev_nodes_ids = [] for ind in population: ind_subtrees = [node for node in ind.graph.nodes if node != ind.graph.root_node] subtrees = [OptGraph(deepcopy(node.ordered_subnodes_hierarchy())) for node in ind_subtrees if is_fitted_subtree(node, prev_nodes_ids)] additional_inds += subtrees prev_nodes_ids += [subtree.root_node.descriptive_id for subtree in subtrees] for add_ind in additional_inds: add_ind.parent_operators.append( ParentOperator(operator_type='regularization', operator_name='decremental_regularization', parent_objects=[params.adapter.restore_as_template(ind.graph)])) additional_inds = [ind for ind in additional_inds if constraint_function(ind, params)] is_multi_obj = (population[0].fitness) is MultiObjFitness if additional_inds: evaluate_individuals(additional_inds, objective_function, params, is_multi_obj, timer=timer) if additional_inds and len(additional_inds) > size: additional_inds = sorted(additional_inds, key=lambda ind: ind.fitness)[:size] return additional_inds
def create_individual(): first = OptNode(content='logit') second = OptNode(content='lda') final = OptNode(content='knn', nodes_from=[first, second]) indiviual = Individual(graph=OptGraph(final)) indiviual.fitness = 1 return indiviual
def test_boosting_mutation_for_linear_graph(): """ Tests boosting mutation can add correct boosting cascade """ linear_one_node = OptGraph(OptNode('knn', [OptNode('scaling')])) init_node = OptNode('scaling') model_node = OptNode('knn', [init_node]) boosting_graph = \ OptGraph( OptNode('logit', [model_node, OptNode('linear', [OptNode('class_decompose', [model_node, init_node])])])) composer_requirements = GPComposerRequirements(primary=['scaling'], secondary=['logit'], mutation_prob=1) graph_params = GraphGenerationParams( adapter=PipelineAdapter(), advisor=PipelineChangeAdvisor(task=Task(TaskTypesEnum.classification)), rules_for_constraint=DEFAULT_DAG_RULES) successful_mutation_boosting = False for _ in range(100): graph_after_mutation = mutation(types=[boosting_mutation], params=graph_params, ind=Individual(linear_one_node), requirements=composer_requirements, log=default_log(__name__), max_depth=2).graph if not successful_mutation_boosting: successful_mutation_boosting = \ graph_after_mutation.root_node.descriptive_id == boosting_graph.root_node.descriptive_id else: break assert successful_mutation_boosting # check that obtained pipeline can be fitted pipeline = PipelineAdapter().restore(graph_after_mutation) data = file_data() pipeline.fit(data) result = pipeline.predict(data) assert result is not None
def graph_example(): # XG # | \ # XG KNN # | \ | \ # LR LDA LR LDA graph = OptGraph() root_of_tree, root_child_first, root_child_second = \ [OptNode(model) for model in ('xgboost', 'xgboost', 'knn')] for root_node_child in (root_child_first, root_child_second): for requirement_model in ('logit', 'lda'): new_node = OptNode(requirement_model) root_node_child.nodes_from.append(new_node) graph.add_node(new_node) graph.add_node(root_node_child) root_of_tree.nodes_from.append(root_node_child) graph.add_node(root_of_tree) return graph