def sum(inputs, indices, latent_indicators, num_sums, inf_type=None, log=False, output=None): if indices is None: inputs = [inputs] else: inputs = [(inputs, indices)] # Generate 'num_sums' Sum nodes, connecting each to inputs and latent_indicators s = [] weights = [] for i in range(0, num_sums): s = s + [spn.Sum(*inputs, latent_indicators=latent_indicators[i])] weights = weights + [s[-1].generate_weights()] # Connect all sum nodes to a single root Sum node and generate its weights root = spn.Sum(*s) root.generate_weights() if log: mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=True) else: mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=False) mpe_path_gen.get_mpe_path(root) path_ops = [mpe_path_gen.counts[w] for w in weights] return spn.initialize_weights(root), path_ops
def test_group_initialization(self): """Group initialization of weights nodes""" v1 = spn.IVs(num_vars=1, num_vals=2) v2 = spn.IVs(num_vars=1, num_vals=4) s1 = spn.Sum(v1) s1.generate_weights([0.2, 0.3]) s2 = spn.Sum(v2) s2.generate_weights(5) p = spn.Product(s1, s2) init = spn.initialize_weights(p) with tf.Session() as sess: sess.run([init]) val1 = sess.run(s1.weights.node.get_value()) val2 = sess.run(s2.weights.node.get_value()) val1_log = sess.run(tf.exp(s1.weights.node.get_log_value())) val2_log = sess.run(tf.exp(s2.weights.node.get_log_value())) self.assertEqual(val1.dtype, spn.conf.dtype.as_numpy_dtype()) self.assertEqual(val2.dtype, spn.conf.dtype.as_numpy_dtype()) np.testing.assert_array_almost_equal(val1, [0.4, 0.6]) np.testing.assert_array_almost_equal(val2, [0.25, 0.25, 0.25, 0.25]) self.assertEqual(val1_log.dtype, spn.conf.dtype.as_numpy_dtype()) self.assertEqual(val2_log.dtype, spn.conf.dtype.as_numpy_dtype()) np.testing.assert_array_almost_equal(val1_log, [0.4, 0.6]) np.testing.assert_array_almost_equal(val2_log, [0.25, 0.25, 0.25, 0.25])
def poon_single(inputs, num_vals, num_mixtures, num_subsets, inf_type, log=False, output=None): # Build a POON-like network with single-op nodes subsets = [[ spn.Sum((inputs, list(range(i * num_vals, (i + 1) * num_vals)))) for _ in range(num_mixtures) ] for i in range(num_subsets)] products = [ spn.Product(*list(inp)) for inp in list(product(*[s for s in subsets])) ] root = spn.Sum(*products, name="root") # Generate dense SPN and all weights in the network spn.generate_weights(root) # Generate path ops based on inf_type and log if log: mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=True) else: mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=False) mpe_path_gen.get_mpe_path(root) path_ops = [ mpe_path_gen.counts[inp] for inp in (inputs if isinstance(inputs, list) else [inputs]) ] return root, spn.initialize_weights(root), path_ops
def test_is_valid_false(self): """Checking validity of the SPN""" # Create graph v12 = spn.IVs(num_vars=2, num_vals=4, name="V12") v34 = spn.ContVars(num_vars=2, name="V34") s1 = spn.Sum((v12, [0, 1, 2, 3]), name="S1") s2 = spn.Sum((v12, [4, 5, 6, 7]), name="S2") p1 = spn.Product((v12, [0, 7]), name="P1") p2 = spn.Product((v12, [2, 3, 4]), name="P2") p3 = spn.Product(v34, name="P3") n1 = spn.Concat(s1, s2, p3, name="N1") n2 = spn.Concat(p1, p2, name="N2") p4 = spn.Product((n1, [0]), (n1, [1]), name="P4") p5 = spn.Product((n2, [0]), (n1, [2]), name="P5") s3 = spn.Sum(p4, n2, name="S3") p6 = spn.Product(s3, (n1, [2]), name="P6") s4 = spn.Sum(p5, p6, name="S4") # Test self.assertTrue(v12.is_valid()) self.assertTrue(v34.is_valid()) self.assertTrue(s1.is_valid()) self.assertTrue(s2.is_valid()) self.assertTrue(p1.is_valid()) self.assertTrue(p3.is_valid()) self.assertTrue(p4.is_valid()) self.assertTrue(n1.is_valid()) self.assertFalse(p2.is_valid()) self.assertFalse(n2.is_valid()) self.assertFalse(s3.is_valid()) self.assertFalse(s4.is_valid()) self.assertFalse(p5.is_valid()) self.assertFalse(p6.is_valid())
def sum(inputs, indices, latent_indicators, num_sums, inf_type, log=False, output=None): if indices is None: inputs = [inputs for _ in range(num_sums)] else: inputs = [(inputs, ind) for ind in indices] # Generate 'num_sums' Sum nodes, connecting each to inputs and latent_indicators s = [] for inp, iv in zip(inputs, latent_indicators): s = s + [spn.Sum(inp, latent_indicators=iv)] # Generate weights for each Sum node s[-1].generate_weights() # Connect all sum nodes to a single root Sum node and generate its weights root = spn.Sum(*s) root.generate_weights() if log: value_op = root.get_log_value(inference_type=inf_type) else: value_op = root.get_value(inference_type=inf_type) return spn.initialize_weights(root), value_op
def test_get_out_size(self): """Computing the sizes of the outputs of nodes in SPN graph""" # Generate graph v1 = spn.ContVars(num_vars=5) v2 = spn.ContVars(num_vars=5) v3 = spn.ContVars(num_vars=5) s1 = spn.Sum((v1, [1, 3]), (v1, [1, 4]), v2) # v1 included twice s2 = spn.Sum(v1, (v3, [0, 1, 2, 3, 4])) s3 = spn.Sum(v2, v3, v3) # v3 included twice n4 = spn.Concat(s1, v1) n5 = spn.Concat((v3, [0, 4]), s3) n6 = spn.Concat(n4, s2, n5, (n4, [0]), (n5, [1])) # n4 and n5 included twice # Test num = v1.get_out_size() self.assertEqual(num, 5) num = v2.get_out_size() self.assertEqual(num, 5) num = v3.get_out_size() self.assertEqual(num, 5) num = s1.get_out_size() self.assertEqual(num, 1) num = s2.get_out_size() self.assertEqual(num, 1) num = s3.get_out_size() self.assertEqual(num, 1) num = n4.get_out_size() self.assertEqual(num, 6) num = n5.get_out_size() self.assertEqual(num, 3) num = n6.get_out_size() self.assertEqual(num, 12)
def test_compute_valid(self): """Calculating validity of Sum""" # Without IVs v12 = spn.IVs(num_vars=2, num_vals=4) v34 = spn.ContVars(num_vars=2) s1 = spn.Sum((v12, [0, 1, 2, 3])) s2 = spn.Sum((v12, [0, 1, 2, 4])) s3 = spn.Sum((v12, [0, 1, 2, 3]), (v34, 0)) p1 = spn.Product((v12, [0, 5]), (v34, 0)) p2 = spn.Product((v12, [1, 6]), (v34, 0)) p3 = spn.Product((v12, [1, 6]), (v34, 1)) s4 = spn.Sum(p1, p2) s5 = spn.Sum(p1, p3) self.assertTrue(v12.is_valid()) self.assertTrue(v34.is_valid()) self.assertTrue(s1.is_valid()) self.assertFalse(s2.is_valid()) self.assertFalse(s3.is_valid()) self.assertTrue(s4.is_valid()) self.assertFalse(s5.is_valid()) # With IVS s6 = spn.Sum(p1, p2) s6.generate_ivs() self.assertTrue(s6.is_valid()) s7 = spn.Sum(p1, p2) s7.set_ivs(spn.ContVars(num_vars=2)) self.assertFalse(s7.is_valid()) s8 = spn.Sum(p1, p2) s8.set_ivs(spn.IVs(num_vars=2, num_vals=2)) with self.assertRaises(spn.StructureError): s8.is_valid() s9 = spn.Sum(p1, p2) s9.set_ivs((v12, [0, 3])) self.assertTrue(s9.is_valid())
def test_get_scope(self): """Computing the scope of nodes of the SPN graph""" # Create graph v12 = spn.IVs(num_vars=2, num_vals=4, name="V12") v34 = spn.ContVars(num_vars=2, name="V34") s1 = spn.Sum((v12, [0, 1, 2, 3]), name="S1") s2 = spn.Sum((v12, [4, 5, 6, 7]), name="S2") p1 = spn.Product((v12, [0, 7]), name="P1") p2 = spn.Product((v12, [3, 4]), name="P2") p3 = spn.Product(v34, name="P3") n1 = spn.Concat(s1, s2, p3, name="N1") n2 = spn.Concat(p1, p2, name="N2") p4 = spn.Product((n1, [0]), (n1, [1]), name="P4") p5 = spn.Product((n2, [0]), (n1, [2]), name="P5") s3 = spn.Sum(p4, n2, name="S3") p6 = spn.Product(s3, (n1, [2]), name="P6") s4 = spn.Sum(p5, p6, name="S4") # Test self.assertListEqual(v12.get_scope(), [spn.Scope(v12, 0), spn.Scope(v12, 0), spn.Scope(v12, 0), spn.Scope(v12, 0), spn.Scope(v12, 1), spn.Scope(v12, 1), spn.Scope(v12, 1), spn.Scope(v12, 1)]) self.assertListEqual(v34.get_scope(), [spn.Scope(v34, 0), spn.Scope(v34, 1)]) self.assertListEqual(s1.get_scope(), [spn.Scope(v12, 0)]) self.assertListEqual(s2.get_scope(), [spn.Scope(v12, 1)]) self.assertListEqual(p1.get_scope(), [spn.Scope(v12, 0) | spn.Scope(v12, 1)]) self.assertListEqual(p2.get_scope(), [spn.Scope(v12, 0) | spn.Scope(v12, 1)]) self.assertListEqual(p3.get_scope(), [spn.Scope(v34, 0) | spn.Scope(v34, 1)]) self.assertListEqual(n1.get_scope(), [spn.Scope(v12, 0), spn.Scope(v12, 1), spn.Scope(v34, 0) | spn.Scope(v34, 1)]) self.assertListEqual(n2.get_scope(), [spn.Scope(v12, 0) | spn.Scope(v12, 1), spn.Scope(v12, 0) | spn.Scope(v12, 1)]) self.assertListEqual(p4.get_scope(), [spn.Scope(v12, 0) | spn.Scope(v12, 1)]) self.assertListEqual(p5.get_scope(), [spn.Scope(v12, 0) | spn.Scope(v12, 1) | spn.Scope(v34, 0) | spn.Scope(v34, 1)]) self.assertListEqual(s3.get_scope(), [spn.Scope(v12, 0) | spn.Scope(v12, 1)]) self.assertListEqual(p6.get_scope(), [spn.Scope(v12, 0) | spn.Scope(v12, 1) | spn.Scope(v34, 0) | spn.Scope(v34, 1)]) self.assertListEqual(s4.get_scope(), [spn.Scope(v12, 0) | spn.Scope(v12, 1) | spn.Scope(v34, 0) | spn.Scope(v34, 1)])
def test_group_initialization(self): """Group initialization of weights nodes""" v1 = spn.IVs(num_vars=1, num_vals=2) v2 = spn.IVs(num_vars=1, num_vals=4) v3 = spn.IVs(num_vars=1, num_vals=2) v4 = spn.IVs(num_vars=1, num_vals=2) # Sum s1 = spn.Sum(v1) s1.generate_weights(tf.initializers.constant([0.2, 0.3])) s2 = spn.Sum(v2) s2.generate_weights(tf.initializers.constant(5)) # ParSums s3 = spn.ParSums(*[v3, v4], num_sums=2) s3.generate_weights( tf.initializers.constant([0.1, 0.2, 0.3, 0.4, 0.4, 0.3, 0.2, 0.1])) s4 = spn.ParSums(*[v1, v2, v3, v4], num_sums=3) s4.generate_weights(tf.initializers.constant(2.0)) # Product p = spn.Product(s1, s2, s3, s4) init = spn.initialize_weights(p) with self.test_session() as sess: sess.run([init]) val1 = sess.run(s1.weights.node.get_value()) val2 = sess.run(s2.weights.node.get_value()) val3 = sess.run(s3.weights.node.get_value()) val4 = sess.run(s4.weights.node.get_value()) val1_log = sess.run(tf.exp(s1.weights.node.get_log_value())) val2_log = sess.run(tf.exp(s2.weights.node.get_log_value())) val3_log = sess.run(tf.exp(s3.weights.node.get_log_value())) val4_log = sess.run(tf.exp(s4.weights.node.get_log_value())) self.assertEqual(val1.dtype, spn.conf.dtype.as_numpy_dtype()) self.assertEqual(val2.dtype, spn.conf.dtype.as_numpy_dtype()) self.assertEqual(val3.dtype, spn.conf.dtype.as_numpy_dtype()) self.assertEqual(val4.dtype, spn.conf.dtype.as_numpy_dtype()) np.testing.assert_array_almost_equal(val1, [[0.4, 0.6]]) np.testing.assert_array_almost_equal(val2, [[0.25, 0.25, 0.25, 0.25]]) np.testing.assert_array_almost_equal( val3, [[0.1, 0.2, 0.3, 0.4], [0.4, 0.3, 0.2, 0.1]]) np.testing.assert_array_almost_equal( val4, [[0.1] * 10, [0.1] * 10, [0.1] * 10]) self.assertEqual(val1_log.dtype, spn.conf.dtype.as_numpy_dtype()) self.assertEqual(val2_log.dtype, spn.conf.dtype.as_numpy_dtype()) self.assertEqual(val3_log.dtype, spn.conf.dtype.as_numpy_dtype()) self.assertEqual(val4_log.dtype, spn.conf.dtype.as_numpy_dtype()) np.testing.assert_array_almost_equal(val1_log, [[0.4, 0.6]]) np.testing.assert_array_almost_equal(val2_log, [[0.25, 0.25, 0.25, 0.25]]) np.testing.assert_array_almost_equal( val3, [[0.1, 0.2, 0.3, 0.4], [0.4, 0.3, 0.2, 0.1]]) np.testing.assert_array_almost_equal( val4, [[0.1] * 10, [0.1] * 10, [0.1] * 10])
def _build_op(self, inputs, placeholders, conf): """ Creates the graph using only ParSum nodes """ # TODO make sure the ivs are correct sum_indices, weights, ivs = inputs.indices, inputs.weights, None log, inf_type = conf.log, conf.inf_type weights = np.split( weights, np.cumsum([len(ind) * inputs.num_parallel for ind in sum_indices])[:-1]) parallel_sum_nodes = [] for ind in sum_indices: parallel_sum_nodes.append( spn.ParSums((placeholders[0], ind), num_sums=inputs.num_parallel)) weight_nodes = [ self._generate_weights(node, w.tolist()) for node, w in zip(parallel_sum_nodes, weights) ] if ivs: [s.set_ivs(iv) for s, iv in zip(parallel_sum_nodes, ivs)] root = spn.Sum(*parallel_sum_nodes) self._generate_weights(root) mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=log) mpe_path_gen.get_mpe_path(root) path_op = [mpe_path_gen.counts[w] for w in weight_nodes] input_counts = [mpe_path_gen.counts[inp] for inp in placeholders] return tf.tuple( path_op + input_counts)[:len(path_op)], self._initialize_from(root)
def mnist_01(inputs, num_decomps, num_subsets, num_mixtures, num_input_mixtures, balanced, input_dist, node_type, inf_type, log=False): # Learning Parameters additive_smoothing = 100 min_additive_smoothing = 1 # Weight initialization weight_init_value = tf.initializers.random_uniform(10, 11) # Generate SPN structure dense_gen = spn.DenseSPNGenerator(num_decomps=num_decomps, num_subsets=num_subsets, num_mixtures=num_mixtures, input_dist=(spn.DenseSPNGenerator. InputDist.RAW if input_dist is "RAW" else spn. DenseSPNGenerator. InputDist.MIXTURE), num_input_mixtures=num_input_mixtures, balanced=balanced, node_type=node_type) root0 = dense_gen.generate(inputs, root_name="root_0") root1 = dense_gen.generate(inputs, root_name="root_1") root = spn.Sum(root0, root1, name="root") spn.generate_weights(root, initializer=weight_init_value) latent = root.generate_latent_indicators() # Add EM Learning additive_smoothing_var = tf.Variable(additive_smoothing, dtype=spn.conf.dtype) learning = spn.HardEMLearning(root, log=log, value_inference_type=inf_type, additive_smoothing=additive_smoothing_var) return root, latent, learning, additive_smoothing, min_additive_smoothing, \ additive_smoothing_var
def sums(inputs, indices, ivs, num_sums, inf_type=None, log=True, output=None): if indices is None: inputs = [inputs for _ in range(num_sums)] else: inputs = [(inputs, indices) for _ in range(num_sums)] # Generate a single Sums node, modeling 'num_sums' sum nodes within, # connecting it to inputs and ivs s = spn.Sums(*inputs, num_sums=num_sums, ivs=ivs[-1]) # Generate weights of the Sums node weights = s.generate_weights() # Connect the Sums nodes to a single root Sum node and generate its weights root = spn.Sum(s) root.generate_weights() if log: mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=True) else: mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=False) mpe_path_gen.get_mpe_path(root) path_op = [mpe_path_gen.counts[weights]] return spn.initialize_weights(root), path_op
def par_sums(inputs, indices, latent_indicators, num_sums, inf_type=None, log=True, output=None): if indices is None: inputs = [inputs] else: inputs = [(inputs, indices)] # Generate a single ParallelSums node, modeling 'num_sums' sum nodes # within, connecting it to inputs and latent_indicators s = spn.ParallelSums(*inputs, num_sums=num_sums, latent_indicators=latent_indicators[-1]) # Generate weights of the ParallelSums node weights = s.generate_weights() # Connect the ParallelSums nodes to a single root Sum node and generate # its weights root = spn.Sum(s) root.generate_weights() if log: mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=True) else: mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=False) mpe_path_gen.get_mpe_path(root) path_op = [mpe_path_gen.counts[weights]] return spn.initialize_weights(root), path_op
def par_sums(inputs, indices, ivs, num_sums, inf_type, log=True, output=None): if indices is None: inputs = [inputs] else: inputs = [(inputs, indices)] # Generate a single ParSums node, modeling 'num_sums' sum nodes # within, connecting it to inputs and ivs s = spn.ParSums(*inputs, num_sums=num_sums, ivs=ivs[0]) # Generate weights of the ParSums node s.generate_weights() # Connect the ParSums nodes to a single root Sum node and generate # its weights root = spn.Sum(s) root.generate_weights() if log: value_op = root.get_log_value(inference_type=inf_type) else: value_op = root.get_value(inference_type=inf_type) return spn.initialize_weights(root), value_op
def sums(inputs, indices, latent_indicators, num_sums, inf_type, log=True, output=None): if indices is None: inputs = [inputs for _ in range(num_sums)] else: inputs = [(inputs, ind) for ind in indices] # Generate a single Sums node, modeling 'num_sums' sum nodes within, # connecting it to inputs and latent_indicators s = spn.Sums(*inputs, num_sums=num_sums, latent_indicators=latent_indicators[0]) # Generate weights of the Sums node s.generate_weights() # Connect the Sums nodes to a single root Sum node and generate its weights root = spn.Sum(s) root.generate_weights() if log: value_op = root.get_log_value(inference_type=inf_type) else: value_op = root.get_value(inference_type=inf_type) return spn.initialize_weights(root), value_op
def test_input_flags(self): """Detection of different types of inputs""" inpt = spn.Input() self.assertFalse(inpt) self.assertFalse(inpt.is_op) self.assertFalse(inpt.is_var) self.assertFalse(inpt.is_param) n = spn.Sum() inpt = spn.Input(n) self.assertTrue(inpt) self.assertTrue(inpt.is_op) self.assertFalse(inpt.is_var) self.assertFalse(inpt.is_param) n = spn.ContVars() inpt = spn.Input(n) self.assertTrue(inpt) self.assertFalse(inpt.is_op) self.assertTrue(inpt.is_var) self.assertFalse(inpt.is_param) n = spn.Weights() inpt = spn.Input(n) self.assertTrue(inpt) self.assertFalse(inpt.is_op) self.assertFalse(inpt.is_var) self.assertTrue(inpt.is_param)
def _build_root_and_value(inf_type, log, sum_nodes): """ Connects the sum node outputs to a single root as a way of grouping Ops """ root = spn.Sum(*sum_nodes) root.generate_weights() if log: value_op = root.get_log_value(inference_type=inf_type) else: value_op = root.get_value(inference_type=inf_type) return root, value_op
def mnist_all(inputs, num_decomps, num_subsets, num_mixtures, num_input_mixtures, balanced, input_dist, node_type, inf_type, log=False): # Learning Parameters additive_smoothing = 0 min_additive_smoothing = 0 initial_accum_value = 20 # Weight initialization weight_init_value = tf.initializers.random_uniform(0, 1) # Add random values before max add_random = None use_unweighted = True # Generate SPN structure dense_gen = spn.DenseSPNGenerator( num_decomps=num_decomps, num_subsets=num_subsets, num_mixtures=num_mixtures, input_dist=(spn.DenseSPNGenerator.InputDist.RAW if input_dist is "RAW" else spn.DenseSPNGenerator.InputDist.MIXTURE), num_input_mixtures=num_input_mixtures, balanced=balanced, node_type=node_type) class_roots = [ dense_gen.generate(inputs, root_name=("Class_%d" % i)) for i in range(10) ] root = spn.Sum(*class_roots, name="root") spn.generate_weights(root, init_value=weight_init_value) latent = root.generate_ivs() # Add EM Learning additive_smoothing_var = tf.Variable(additive_smoothing, dtype=spn.conf.dtype) learning = spn.EMLearning(root, log=log, value_inference_type=inf_type, additive_smoothing=additive_smoothing_var, add_random=add_random, initial_accum_value=initial_accum_value, use_unweighted=use_unweighted) return root, latent, learning, additive_smoothing, min_additive_smoothing, \ additive_smoothing_var
def test_compute_mpe_path_noivs(self): spn.conf.argmax_zero = True v12 = spn.IVs(num_vars=2, num_vals=4) v34 = spn.ContVars(num_vars=2) v5 = spn.ContVars(num_vars=1) s = spn.Sum((v12, [0, 5]), v34, (v12, [3]), v5) w = s.generate_weights() counts = tf.placeholder(tf.float32, shape=(None, 1)) op = s._compute_log_mpe_path(tf.identity(counts), w.get_log_value(), None, v12.get_log_value(), v34.get_log_value(), v12.get_log_value(), v5.get_log_value()) init = w.initialize() counts_feed = [[10], [11], [12], [13]] v12_feed = [[0, 1], [1, 1], [0, 0], [3, 3]] v34_feed = [[0.1, 0.2], [1.2, 0.2], [0.1, 0.2], [0.9, 0.8]] v5_feed = [[0.5], [0.5], [1.2], [0.9]] with self.test_session() as sess: sess.run(init) # Skip the IVs op out = sess.run(op[:1] + op[2:], feed_dict={ counts: counts_feed, v12: v12_feed, v34: v34_feed, v5: v5_feed }) # Weights np.testing.assert_array_almost_equal( np.squeeze(out[0]), np.array([[10., 0., 0., 0., 0., 0.], [0., 0., 11., 0., 0., 0.], [0., 0., 0., 0., 0., 12.], [0., 0., 0., 0., 13., 0.]], dtype=np.float32)) np.testing.assert_array_almost_equal( out[1], np.array([[10., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0.]], dtype=np.float32)) np.testing.assert_array_almost_equal( out[2], np.array([[0., 0.], [11., 0.], [0., 0.], [0., 0.]], dtype=np.float32)) np.testing.assert_array_almost_equal( out[3], np.array([[0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 13., 0., 0., 0., 0.]], dtype=np.float32)) np.testing.assert_array_almost_equal( out[4], np.array([[0.], [0.], [12.], [0.]], dtype=np.float32))
def poon_single(inputs, num_vals, num_mixtures, num_subsets, inf_type, log=False, output=None): # Build a POON-like network with single-op nodes subsets = [[spn.Sum((inputs, list(range(i*num_vals, (i+1)*num_vals)))) for _ in range(num_mixtures)] for i in range(num_subsets)] products = [spn.Product(*list(inp)) for inp in list(product(*[s for s in subsets]))] root = spn.Sum(*products, name="root") # Generate dense SPN and all weights in the network spn.generate_weights(root) # Generate value ops based on inf_type and log if log: value_op = root.get_log_value(inference_type=inf_type) else: value_op = root.get_value(inference_type=inf_type) return root, spn.initialize_weights(root), value_op
def test_traverse_graph_nostop_noparams(self): """Traversing the whole graph excluding param nodes""" counter = [0] nodes = [None] * 10 def fun(node): nodes[counter[0]] = node counter[0] += 1 # Generate graph v1 = spn.RawLeaf(num_vars=1) v2 = spn.RawLeaf(num_vars=1) v3 = spn.RawLeaf(num_vars=1) s1 = spn.Sum(v1, v1, v2) # v1 included twice s2 = spn.Sum(v1, v3) s3 = spn.Sum(v2, v3, v3) # v3 included twice s4 = spn.Sum(s1, v1) s5 = spn.Sum(s2, v3, s3) s6 = spn.Sum(s4, s2, s5, s4, s5) # s4 and s5 included twice spn.generate_weights(s6) # Traverse spn.traverse_graph(s6, fun=fun, skip_params=True) # Test self.assertEqual(counter[0], 9) self.assertIs(nodes[0], s6) self.assertIs(nodes[1], s4) self.assertIs(nodes[2], s2) self.assertIs(nodes[3], s5) self.assertIs(nodes[4], s1) self.assertIs(nodes[5], v1) self.assertIs(nodes[6], v3) self.assertIs(nodes[7], s3) self.assertIs(nodes[8], v2)
def test_compute_graph_up_noconst(self): """Computing value assuming no constant functions""" # Number of times val_fun was called # Use list to avoid creating local fun variable during assignment counter = [0] def val_fun(node, *inputs): counter[0] += 1 if isinstance(node, spn.graph.node.VarNode): return 1 elif isinstance(node, spn.graph.node.ParamNode): return 0.1 else: weight_val, iv_val, *values = inputs return weight_val + sum(values) + 1 # Generate graph v1 = spn.RawLeaf(num_vars=1) v2 = spn.RawLeaf(num_vars=1) v3 = spn.RawLeaf(num_vars=1) s1 = spn.Sum(v1, v1, v2) # v1 included twice s2 = spn.Sum(v1, v3) s3 = spn.Sum(v2, v3, v3) # v3 included twice s4 = spn.Sum(s1, v1) s5 = spn.Sum(s2, v3, s3) s6 = spn.Sum(s4, s2, s5, s4, s5) # s4 and s5 included twice spn.generate_weights(s6) # Calculate value val = spn.compute_graph_up(s6, val_fun) # Test self.assertAlmostEqual(val, 35.2) self.assertEqual(counter[0], 15)
def perm_products(inputs, num_inputs, num_input_cols, num_prods, inf_type, indices=None, log=False, output=None): if indices is not None: # Create inputs list with indices inputs = [[(inp, ind) for inp, ind in zip(inps, inds)] for inps, inds in zip(inputs, indices)] if isinstance(inputs, list): # Is a list of ContVars inputs - Multiple inputs # Generate 'len(inputs)' PermProducts nodes, modeling 'n_prods' products # within each p = [spn.PermProducts(*inps) for inps in inputs] else: # Is a single input of type ContVars - A single input num_inputs_array = np.array(num_inputs) num_input_cols_array = np.array(num_input_cols) num_cols = num_input_cols[0] num_vars = int(np.sum(num_inputs_array * num_input_cols_array)) indices_list = [ list(range(i, i + num_cols)) for i in range(0, num_vars, num_cols) ] num_inputs_cumsum = np.cumsum(num_inputs_array).tolist() num_inputs_cumsum.insert(0, 0) inputs_list = [[(inputs, inds) for inds in indices_list[start:stop]] for start, stop in zip(num_inputs_cumsum[:-1], num_inputs_cumsum[1:])] # Generate 'len(inputs)' PermProducts nodes, modeling 'n_prods' # products within each, and inputs for each node emination from a # commoninput source p = [spn.PermProducts(*inps) for inps in inputs_list] # Connect all PermProducts nodes to a single root Sum node and generate # its weights root = spn.Sum(*p) root.generate_weights() if log: value_op = root.get_log_value(inference_type=inf_type) else: value_op = root.get_value(inference_type=inf_type) return spn.initialize_weights(root), value_op
def test_get_num_nodes(self): """Computing the number of nodes in the SPN graph""" # Generate graph v1 = spn.ContVars(num_vars=1) v2 = spn.ContVars(num_vars=1) v3 = spn.ContVars(num_vars=1) s1 = spn.Sum(v1, v1, v2) # v1 included twice s2 = spn.Sum(v1, v3) s3 = spn.Sum(v2, v3, v3) # v3 included twice s4 = spn.Sum(s1, v1) s5 = spn.Sum(s2, v3, s3) s6 = spn.Sum(s4, s2, s5, s4, s5) # s4 and s5 included twice spn.generate_weights(s6) # Test num = v1.get_num_nodes(skip_params=True) self.assertEqual(num, 1) num = v1.get_num_nodes(skip_params=False) self.assertEqual(num, 1) num = v2.get_num_nodes(skip_params=True) self.assertEqual(num, 1) num = v2.get_num_nodes(skip_params=False) self.assertEqual(num, 1) num = v3.get_num_nodes(skip_params=True) self.assertEqual(num, 1) num = v3.get_num_nodes(skip_params=False) self.assertEqual(num, 1) num = s1.get_num_nodes(skip_params=True) self.assertEqual(num, 3) num = s1.get_num_nodes(skip_params=False) self.assertEqual(num, 4) num = s2.get_num_nodes(skip_params=True) self.assertEqual(num, 3) num = s2.get_num_nodes(skip_params=False) self.assertEqual(num, 4) num = s3.get_num_nodes(skip_params=True) self.assertEqual(num, 3) num = s3.get_num_nodes(skip_params=False) self.assertEqual(num, 4) num = s4.get_num_nodes(skip_params=True) self.assertEqual(num, 4) num = s4.get_num_nodes(skip_params=False) self.assertEqual(num, 6) num = s5.get_num_nodes(skip_params=True) self.assertEqual(num, 6) num = s5.get_num_nodes(skip_params=False) self.assertEqual(num, 9) num = s6.get_num_nodes(skip_params=True) self.assertEqual(num, 9) num = s6.get_num_nodes(skip_params=False) self.assertEqual(num, 15)
def test_gather_input_scopes(self): v12 = spn.IVs(num_vars=2, num_vals=4, name="V12") v34 = spn.ContVars(num_vars=2, name="V34") s1 = spn.Sum(v12, v12, v34, (v12, [7, 3, 1, 0]), (v34, 0), name="S1") scopes_v12 = v12._compute_scope() scopes_v34 = v34._compute_scope() # Note: weights/ivs are disconnected, so None should be output these scopes = s1._gather_input_scopes(None, None, None, scopes_v12, scopes_v34, scopes_v12, scopes_v34) self.assertTupleEqual( scopes, (None, None, None, scopes_v12, scopes_v34, [ scopes_v12[7], scopes_v12[3], scopes_v12[1], scopes_v12[0] ], [scopes_v34[0]]))
def sum(inputs, sum_indices, repetitions, inf_type, log=False, ivs=None): """ Creates the graph using only Sum nodes """ sum_nodes = [] for ind in sum_indices: sum_nodes.extend( [spn.Sum((inputs, ind)) for _ in range(repetitions)]) [s.generate_weights() for s in sum_nodes] if ivs: [s.set_ivs(iv) for s, iv in zip(sum_nodes, ivs)] root, value_op = Ops._build_root_and_value(inf_type, log, sum_nodes) return spn.initialize_weights(root), value_op
def products(inputs, num_inputs, num_input_cols, num_prods, inf_type, indices=None, log=False, output=None): p = [] # Generate 'len(inputs)' Products node, modelling 'n_prods' ∈ 'num_prods' # products within each for inps, n_inp_cols, n_prods in zip(inputs, num_input_cols, num_prods): num_inputs = len(inps) # Create permuted indices based on number and size of inps inds = map(int, np.arange(n_inp_cols)) permuted_inds = list(product(inds, repeat=num_inputs)) permuted_inds_list = [list(elem) for elem in permuted_inds] permuted_inds_list_of_list = [] for elem in permuted_inds_list: permuted_inds_list_of_list.append( [elem[i:i + 1] for i in range(0, len(elem), 1)]) # Create inputs-list by combining inps and indices permuted_inputs = [] for indices in permuted_inds_list_of_list: permuted_inputs.append([tuple(i) for i in zip(inps, indices)]) permuted_inputs = list(chain.from_iterable(permuted_inputs)) # Generate a single Products node, modeling 'n_prods' product nodes # within, connecting it to inputs p = p + [spn.Products(*permuted_inputs, num_prods=n_prods)] # Connect all product nodes to a single root Sum node and generate its # weights root = spn.Sum(*p) root.generate_weights() if log: mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=True) else: mpe_path_gen = spn.MPEPath(value_inference_type=inf_type, log=False) mpe_path_gen.get_mpe_path(root) path_ops = [ mpe_path_gen.counts[inp] for inp in list(chain.from_iterable(inputs)) ] return spn.initialize_weights(root), path_ops
def test(values, ivs, weights, feed, output): with self.subTest(values=values, ivs=ivs, weights=weights, feed=feed): n = spn.Sum(*values, ivs=ivs) n.generate_weights(weights) op = n.get_value(spn.InferenceType.MARGINAL) op_log = n.get_log_value(spn.InferenceType.MARGINAL) with tf.Session() as sess: spn.initialize_weights(n).run() out = sess.run(op, feed_dict=feed) out_log = sess.run(tf.exp(op_log), feed_dict=feed) np.testing.assert_array_almost_equal( out, np.array(output, dtype=spn.conf.dtype.as_numpy_dtype())) np.testing.assert_array_almost_equal( out_log, np.array(output, dtype=spn.conf.dtype.as_numpy_dtype()))
def test_generte_set_errors(self): """Detecting structure errors in __generate_set""" gen = spn.DenseSPNGenerator(num_decomps=2, num_subsets=3, num_mixtures=2) v1 = spn.IVs(num_vars=2, num_vals=4) v2 = spn.ContVars(num_vars=3, name="ContVars1") v3 = spn.ContVars(num_vars=2, name="ContVars2") s1 = spn.Sum(v3, v2) n1 = spn.Concat(v2) with self.assertRaises(spn.StructureError): gen._DenseSPNGenerator__generate_set([ spn.Input(v1, [0, 3, 2, 6, 7]), spn.Input(v2, [1, 2]), spn.Input(s1, None), spn.Input(n1, None) ])
def test_sum_update_1(self): child1 = spn.GaussianLeaf(num_vars=1, num_components=1, total_counts_init=3, loc_init=0.0, scale_init=1.0, learn_dist_params=True) child2 = spn.GaussianLeaf(num_vars=1, num_components=1, total_counts_init=7, loc_init=1.0, scale_init=4.0, learn_dist_params=True) root = spn.Sum(child1, child2) root.generate_weights() value_inference_type = spn.InferenceType.MARGINAL init_weights = spn.initialize_weights(root) learning = spn.EMLearning(root, log=True, value_inference_type=value_inference_type, use_unweighted=True) reset_accumulators = learning.reset_accumulators() accumulate_updates = learning.accumulate_updates() update_spn = learning.update_spn() train_likelihood = learning.value.values[root] with self.test_session() as sess: sess.run(init_weights) sess.run(reset_accumulators) sess.run(accumulate_updates, {child1: [[0.0]], child2: [[0.0]]}) sess.run(update_spn) child1_n = sess.run(child1._total_count_variable) child2_n = sess.run(child2._total_count_variable) # equalWeight is true, so update passes the data point to the component # with highest likelihood without considering the weight of each component. # In this case, N(0|0,1) > N(0|1,4), so child1 is picked. # If component weights are taken into account, then child2 will be picked # since 0.3*N(0|0,1) < 0.7*N(0|1,4). # self.assertEqual(root.n, 11) self.assertEqual(child1_n, 4) self.assertEqual(child2_n, 7)