The simplest and most readable way to make small SPNs is through 'single op' nodes like Sum
or Product
.
import libspn as spn
import tensorflow as tf
indicator_leaves = spn.IndicatorLeaf(
num_vars=2, num_vals=2, name="indicator_x")
# Connect first two sums to indicators of first variable
sum_11 = spn.Sum((indicator_leaves, [0,1]), name="sum_11")
sum_12 = spn.Sum((indicator_leaves, [0,1]), name="sum_12")
# Connect another two sums to indicators of the second variable
sum_21 = spn.Sum((indicator_leaves, [2,3]), name="sum_21")
sum_22 = spn.Sum((indicator_leaves, [2,3]), name="sum_22")
# Connect three product nodes
prod_1 = spn.Product(sum_11, sum_21, name="prod_1")
prod_2 = spn.Product(sum_11, sum_22, name="prod_2")
prod_3 = spn.Product(sum_12, sum_22, name="prod_3")
# Connect a root sum
root = spn.Sum(prod_1, prod_2, prod_3, name="root")
# Connect a latent indicator
indicator_y = root.generate_latent_indicators(name="indicator_y") # Can be added manually
# Generate weights
spn.generate_weights(root, initializer=tf.initializers.random_uniform()) # Can be added manually
# Inspect
print(root.get_num_nodes())
print(root.get_scope())
print(root.is_valid())
The visualization below uses graphviz
. Depending on your setup (e.g. jupyter lab
vs. jupyter notebook
) this might fail to show. At least Chrome
+ jupyter notebook
seems to work.
# Visualize SPN graph
spn.display_spn_graph(root)