Example #1
0
def to_layers(spn, sparse=True, copy=True):
    with elapsed_timer() as e:
        if copy:
            spn = Copy(spn)
        print('copy', e())
        spn = Prune(spn, contract_single_parents=False)
        print('prune', e())
        complete_layers([spn], type(spn))
        print('complete layers', e())
        node_layers = get_topological_order_layers(spn)
        print('topo search', e())
        print('nr layers', len(node_layers))

        layers = [LeafLayer(node_layers[0])]
        for i in tqdm(range(1, len(node_layers))):
            cur_layer = node_layers[i]
            prev_layer = node_layers[i - 1]
            scope = get_scope(cur_layer, prev_layer, sparse)

            if isinstance(cur_layer[0], Sum):
                weights = np.concatenate(
                    list(map(lambda x: x.weights, cur_layer)))
                layers.append(SumLayer(cur_layer, scope, weights))
            else:
                layers.append(ProductLayer(cur_layer, scope))
        print('to layer objects', e())
        return layers
Example #2
0
    def test_eval_parametric(self):
        data = np.array([1, 1, 1, 1, 1, 1, 1], dtype=np.float32).reshape(
            (1, 7))

        spn = (Gaussian(mean=1.0, stdev=1.0, scope=[0]) *
               Exponential(l=1.0, scope=[1]) *
               Gamma(alpha=1.0, beta=1.0, scope=[2]) *
               LogNormal(mean=1.0, stdev=1.0, scope=[3]) *
               Poisson(mean=1.0, scope=[4]) * Bernoulli(p=0.6, scope=[5]) *
               Categorical(p=[0.1, 0.2, 0.7], scope=[6]))

        ll = log_likelihood(spn, data)

        tf_ll = eval_tf(spn, data)

        self.assertTrue(np.all(np.isclose(ll, tf_ll)))

        spn_copy = Copy(spn)

        tf_graph, data_placeholder, variable_dict = spn_to_tf_graph(
            spn_copy, data, 1)

        with tf.Session() as sess:
            sess.run(tf.global_variables_initializer())
            tf_graph_to_spn(variable_dict)

        str_val = spn_to_str_equation(spn)
        str_val2 = spn_to_str_equation(spn_copy)

        self.assertEqual(str_val, str_val2)
Example #3
0
def optimize_tf(spn, data, epochs=1000, optimizer=None):
    spn_copy = Copy(spn)
    tf_graph, data_placeholder, variable_dict = spn_to_tf_graph(spn_copy, data)
    optimize_tf_graph(tf_graph,
                      variable_dict,
                      data_placeholder,
                      data,
                      epochs=epochs,
                      optimizer=optimizer)
    return spn_copy
Example #4
0
def prod_condition(node, children, input_vals=None, scope=None):
    if not scope.intersection(node.scope):
        return Copy(node), 0
    new_node = Product()
    new_node.scope = list(set(node.scope) - scope)
    probability = 0

    for c in children:
        if c[0]:
            new_node.children.append(c[0])
        probability += float(c[1])
    return new_node, probability
def get_node_description(spn, parent_node, size):
    # parent_node.validate()
    parent_type = type(parent_node).__name__
    node_descriptions = dict()
    node_descriptions['num'] = len(parent_node.children)
    nodes = list()
    for i, node in enumerate(parent_node.children):
        node_spn = Copy(node)
        assign_ids(node_spn)
        node_dir = dict()
        node_dir[
            'weight'] = parent_node.weights[i] if parent_type == 'Sum' else 1
        node_dir['size'] = get_number_of_nodes(node) - 1
        node_dir['num_children'] = len(
            node.children) if not isinstance(node, Leaf) else 0
        node_dir['leaf'] = isinstance(node, Leaf)
        node_dir['type'] = type(node).__name__ + ' Node'
        node_dir['split_features'] = [
            list(c.scope) for c in node.children
        ] if not isinstance(node, Leaf) else node.scope
        node_dir['split_features'].sort(key=lambda x: len(x))
        node_dir['depth'] = get_depth(node)
        node_dir['child_depths'] = [get_depth(c) for c in node.children]

        descriptor = node_dir['type']
        if all((d == 0 for d in node_dir['child_depths'])):
            descriptor = 'shallow ' + descriptor
            node_dir['quick'] = 'shallow'
        elif len([d for d in node_dir['child_depths'] if d == 0]) == 1:
            node_dir['quick'] = 'split_one'
            descriptor += ', which separates one feature'
        else:
            node_dir['quick'] = 'deep'
            descriptor = 'deep ' + descriptor
        descriptor = 'a ' + descriptor
        node_dir['descriptor'] = descriptor
        node_dir['short_descriptor'] = descriptor
        node_dir['representative'] = mpe(node_spn, np.array([[np.nan] * size]))
        nodes.append(node_dir)
    node_descriptions['shallow'] = len(
        [d for d in nodes if d['quick'] == 'shallow'])
    node_descriptions['split_one'] = len(
        [d for d in nodes if d['quick'] == 'split_one'])
    node_descriptions['deep'] = len([d for d in nodes if d['quick'] == 'deep'])
    nodes.sort(key=lambda x: x['weight'])
    nodes.reverse()
    node_descriptions['nodes'] = nodes
    return node_descriptions
Example #6
0
def sum_condition(node, children, input_vals=None, scope=None):
    if not scope.intersection(node.scope):
        return Copy(node), 0
    new_node = Sum()
    new_node.scope = list(set(node.scope) - scope)
    new_weights = []
    probs = []
    for i, c in enumerate(children):
        if c[0]:
            new_node.children.append(c[0])
            new_weights.append(node.weights[i] * np.exp(c[1]))
        else:
            probs.append(node.weights[i] * np.exp(c[1]))
    new_node.weights = [w / sum(new_weights) for w in new_weights]
    assert np.all(np.logical_not(np.isnan(
        new_node.weights))), 'Found nan weights'
    if not new_node.scope:
        return None, np.log(sum(probs))
    return new_node, np.log(sum(new_weights))
Example #7
0
def optimize_tf(
    spn: Node,
    data: np.ndarray,
    epochs=1000,
    batch_size: int = None,
    optimizer: tf.train.Optimizer = None,
    return_loss=False,
) -> Union[Tuple[Node, List[float]], Node]:
    """
    Optimize weights of an SPN with a tensorflow stochastic gradient descent optimizer, maximizing the likelihood
    function.
    :param spn: SPN which is to be optimized
    :param data: Input data
    :param epochs: Number of epochs
    :param batch_size: Size of each minibatch for SGD
    :param optimizer: Optimizer procedure
    :param return_loss: Whether to also return the list of losses for each epoch or not
    :return: If `return_loss` is true, a copy of the optimized SPN and the list of the losses for each epoch is
    returned, else only a copy of the optimized SPN is returned
    """
    # Make sure, that the passed SPN is not modified
    spn_copy = Copy(spn)

    # Compile the SPN to a static tensorflow graph
    tf_graph, data_placeholder, variable_dict = spn_to_tf_graph(
        spn_copy, data, batch_size)

    # Optimize the tensorflow graph
    loss_list = optimize_tf_graph(tf_graph,
                                  variable_dict,
                                  data_placeholder,
                                  data,
                                  epochs=epochs,
                                  batch_size=batch_size,
                                  optimizer=optimizer)

    # Return loss as well if flag is set
    if return_loss:
        return spn_copy, loss_list

    return spn_copy
Example #8
0
def to_compressed_layers(spn):
    with elapsed_timer() as e:
        spn = Copy(spn)
        print('copy', e())
        spn = Prune(spn, contract_single_parents=False)
        print('prune', e())
        complete_layers([spn], type(spn))
        print('complete layers', e())
        node_layers = get_topological_order_layers(spn)
        print('topo search', e())
        print('nr layers', len(node_layers))

        layers = [LeafLayer(node_layers[0])]
        for i in range(1, len(node_layers)):

            cur_layer = node_layers[i]
            prev_layer = node_layers[i - 1]

            cur_is_sum = isinstance(cur_layer[0], Sum)
            prev_is_prod = isinstance(prev_layer[0], Product)

            # print(i, cur_is_sum, prev_is_prod)
            if cur_is_sum:
                weights = list(map(lambda x: x.weights, cur_layer))

            if cur_is_sum and prev_is_prod:
                # build sp layer
                # remove prod from previous layer
                layers.pop()
                scopes = get_two_layer_scopes(cur_layer, node_layers[i - 2],
                                              True)
                layers.append(SumProductLayer(cur_layer, scopes, weights))
            else:
                scope = get_scope(cur_layer, prev_layer, True)
                if cur_is_sum:
                    layers.append(SumLayer(cur_layer, scope, weights))
                else:
                    layers.append(ProductLayer(cur_layer, scope))
        print('to layer objects', e())
        return layers
Example #9
0
        # for _ in range(0, 20):
        rg.random_split(2, 2)

    rg_layers = rg.make_layers()
    print("random graph built in  ", (time.perf_counter() - start))

    start = time.perf_counter()
    vector_list, root = Make_SPN_from_RegionGraph(rg_layers, np.random.RandomState(100),
                                                  num_classes=1, num_gauss=20, num_sums=20)
    print("Make_SPN_from_RegionGraph in  ", (time.perf_counter() - start))

    start = time.perf_counter()
    print(get_structure_stats(root))
    print("get_structure_stats in  ", (time.perf_counter() - start))

    old_root = Copy(root)

    start = time.perf_counter()
    root = Prune(root)
    print("Prune in  ", (time.perf_counter() - start))

    start = time.perf_counter()
    root = SPN_Reshape(root, 2)
    print("SPN_Reshape in  ", (time.perf_counter() - start))

    start = time.perf_counter()
    print(get_structure_stats(root))
    print("get_structure_stats in  ", (time.perf_counter() - start))

    start = time.perf_counter()
    layers, layer_types = get_execution_layers(root)
Example #10
0
def leaf_condition(node, input_vals=None, scope=None):
    if not scope.intersection(node.scope):
        return Copy(node), 0

    _likelihood = log_likelihood(node, input_vals)
    return None, _likelihood
def describe_misclassified(spn, dictionary, misclassified, data_dict,
                           numerical_data):
    context = dictionary['context']
    categoricals = get_categoricals(spn, context)
    empty = np.array([[np.nan] * len(spn.scope)])
    for i in categoricals:
        if use_shapley:
            raise NotImplementedError
        else:
            if misclassified_explanations == 'all':
                show_misclassified = misclassified[i]
            elif isinstance(misclassified_explanations, int):
                num_choices = min(misclassified_explanations,
                                  len(misclassified[i]))
                show_misclassified = random.sample(misclassified[i].tolist(),
                                                   k=num_choices)
            else:
                show_misclassified = misclassified_explanations
            for inst_num in show_misclassified:
                instance = data_dict[i][inst_num:inst_num + 1]
                evidence = instance.copy()
                evidence[:, i] = np.nan
                prior = log_likelihood(spn, evidence)
                posterior = log_likelihood(spn, instance)
                total = 0
                all_nodes = []
                for j, node in enumerate(spn.children):
                    node_prob = np.exp(
                        np.log(spn.weights[j]) +
                        log_likelihood(spn, instance) - posterior)
                    total += node_prob
                    all_nodes.append((node_prob, j))
                all_nodes.sort()
                all_nodes.reverse()
                needed_nodes = []
                all_reps = []
                total_prob = 0
                for prob, idx in all_nodes:
                    node = Copy(spn.children[idx])
                    assign_ids(node)
                    total_prob += prob
                    needed_nodes.append(idx)
                    all_reps.append(mpe(node, empty)[0])
                    if total_prob > 0.9:
                        break
                real_value = dictionary['features'][i][
                    'encoder'].inverse_transform(
                        [int(numerical_data[inst_num, i])])
                pred_value = dictionary['features'][i][
                    'encoder'].inverse_transform(
                        [int(data_dict[i][inst_num, i])])
                printmd(
                    'Instance {} was predicted as "{}", even though it is "{}", because it was most similar to the following clusters: {}'
                    .format(inst_num, pred_value, real_value,
                            ', '.join(map(str, needed_nodes))))
                all_reps = np.array(all_reps).reshape(len(needed_nodes),
                                                      len(spn.scope))
                table = np.round(np.concatenate([instance, all_reps], axis=0),
                                 2)
                node_nums = np.array(['instance'] + needed_nodes).reshape(
                    -1, 1)
                table = np.append(node_nums, table, axis=1)

                iplot(
                    p.plot_table([''] + context.feature_names,
                                 table.transpose()))