def deserialize(self, data, load_param_vals=True, sess=None): # Deserialize the graph first nodes_by_name = {} self._root = deserialize_graph(data, load_param_vals=load_param_vals, sess=sess, nodes_by_name=nodes_by_name) # Model specific information # Inputs sample_ivs = data.get('sample_ivs', None) if sample_ivs: self._sample_ivs = nodes_by_name[sample_ivs] else: self._sample_ivs = None self._sample_inputs = tuple( Input(nodes_by_name[nn], i) for nn, i in data['sample_inputs']) class_ivs = data.get('class_ivs', None) if class_ivs: self._class_ivs = nodes_by_name[class_ivs] else: self._class_ivs = None class_input = data.get('class_input', None) if class_input: self._class_input = Input(nodes_by_name[class_input[0]], class_input[1]) else: self._class_input = None # Model params self._num_classes = data['num_classes'] self._num_decomps = data['num_decomps'] self._num_subsets = data['num_subsets'] self._num_mixtures = data['num_mixtures'] self._input_dist = data['input_dist'] self._num_input_mixtures = data['num_input_mixtures'] self._weight_initializer = data['weight_init_value']
def deserialize_inputs(self, data, nodes_by_name): super().deserialize_inputs(data, nodes_by_name) self._values = tuple( Input(nodes_by_name[nn], i) for nn, i in data['values']) weights = data.get('weights', None) if weights: self._weights = Input(nodes_by_name[weights[0]], weights[1]) ivs = data.get('ivs', None) if ivs: self._ivs = Input(nodes_by_name[ivs[0]], ivs[1])
def deserialize_inputs(self, data, nodes_by_name): super().deserialize_inputs(data, nodes_by_name) self._values = tuple( Input(nodes_by_name[nn], i) for nn, i in data['values']) weights = data.get('weights', None) if weights: self._weights = Input(nodes_by_name[weights[0]], weights[1]) latent_indicators = data.get('latent_indicators', None) if latent_indicators: self._latent_indicators = Input( nodes_by_name[latent_indicators[0]], latent_indicators[1])
def generate(self, *inputs, rnd=None, root_name=None): """Generate the SPN. Args: inputs (input_like): Inputs to the generated SPN. rnd (Random): Optional. A custom instance of a random number generator ``random.Random`` that will be used instead of the default global instance. This permits using a generator with a custom state independent of the global one. root_name (str): Name of the root node of the generated SPN. Returns: Sum: Root node of the generated SPN. """ self.__debug1( "Generating dense SPN (num_decomps=%s, num_subsets=%s," " num_mixtures=%s, input_dist=%s, num_input_mixtures=%s)", self.num_decomps, self.num_subsets, self.num_mixtures, self.input_dist, self.num_input_mixtures) inputs = [Input.as_input(i) for i in inputs] input_set = self.__generate_set(inputs) self.__debug1("Found %s distinct input scopes", len(input_set)) # Create root root = Sum(name=root_name) # Subsets left to process subsets = deque() subsets.append(DenseSPNGenerator.SubsetInfo(level=1, subset=input_set, parents=[root])) # Process subsets layer by layer self.__decomp_id = 1 # Id number of a decomposition, for info only while subsets: # Process whole layer (all subsets at the same level) level = subsets[0].level self.__debug1("Processing level %s", level) while subsets and subsets[0].level == level: subset = subsets.popleft() new_subsets = self.__add_decompositions(subset, rnd) for s in new_subsets: subsets.append(s) # If NodeType is LAYER, convert the generated graph with LayerNodes return (self.convert_to_layer_nodes(root) if self.node_type == DenseSPNGenerator.NodeType.LAYER else root)
def deserialize_inputs(self, data, nodes_by_name): super().deserialize_inputs(data, nodes_by_name) self._values = tuple(Input(nodes_by_name[nn], i) for nn, i in data['values'])
def deserialize_inputs(self, data, nodes_by_name): super().deserialize_inputs(data, nodes_by_name) self._values = tuple( Input(nodes_by_name[nn], i) for nn, i in data['values']) self.create_products(input_sizes=data['input_sizes'], num_inputs=data['num_inputs'])
def build(self, *sample_inputs, class_input=None, num_vars=None, num_vals=None, seed=None): """Build the SPN graph of the model. The model can be built on top of any ``sample_inputs``. Otherwise, if no sample inputs are provided, the model will internally crate a single IVs node to represent the input data samples. In such case, ``num_vars`` and ``num_vals`` must be specified. Similarly, if ``class_input`` is provided, it is used as a source of class indicators of the root sum node combining sub-SPNs modeling particular classes. Otherwise, an internal IVs node is created for this purpose. Args: *sample_inputs (input_like): Optional. Inputs to the model providing data samples. class_input (input_like): Optional. Input providing class indicators. num_vars (int): Optional. Number of variables in each sample. Must only be provided if ``sample_inputs`` are not given. num_vals (int or list of int): Optional. Number of values of each variable. Can be a single value or a list of values, one for each of ``num_vars`` variables. Must only be provided if ``sample_inputs`` are not given. seed (int): Optional. Seed used for the dense SPN generator. Returns: Sum: Root node of the generated model. """ if not sample_inputs: if num_vars is None: raise ValueError( "num_vars must be given when sample_inputs are not") if num_vals is None: raise ValueError( "num_vals must be given when sample_inputs are not") if not isinstance(num_vars, int) or num_vars < 1: raise ValueError("num_vars must be an integer > 0") if not isinstance(num_vals, int) or num_vals < 1: raise ValueError("num_vals must be an integer > 0") if self._num_classes > 1: self.__info("Building a discrete dense model with %d classes" % self._num_classes) else: self.__info("Building a 1-class discrete dense model") # Create IVs if inputs not given if not sample_inputs: self._sample_ivs = IVs(num_vars=num_vars, num_vals=num_vals, name="SampleIVs") self._sample_inputs = [Input(self._sample_ivs)] else: self._sample_inputs = tuple( Input.as_input(i) for i in sample_inputs) if self._num_classes > 1: if class_input is None: self._class_ivs = IVs(num_vars=1, num_vals=self._num_classes, name="ClassIVs") self._class_input = Input(self._class_ivs) else: self._class_input = Input.as_input(class_input) # Generate structure dense_gen = DenseSPNGenerator( num_decomps=self._num_decomps, num_subsets=self._num_subsets, num_mixtures=self._num_mixtures, input_dist=self._input_dist, num_input_mixtures=self._num_input_mixtures, balanced=True) rnd = random.Random(seed) if self._num_classes == 1: # One-class self._root = dense_gen.generate(*self._sample_inputs, rnd=rnd, root_name='Root') else: # Multi-class: create sub-SPNs sub_spns = [] for c in range(self._num_classes): rnd_copy = random.Random() rnd_copy.setstate(rnd.getstate()) with tf.name_scope("Class%d" % c): sub_root = dense_gen.generate(*self._sample_inputs, rnd=rnd_copy) if self.__is_debug1(): self.__debug1("sub-SPN %d has %d nodes" % (c, sub_root.get_num_nodes())) sub_spns.append(sub_root) # Create root self._root = Sum(*sub_spns, ivs=self._class_input, name="Root") if self.__is_debug1(): self.__debug1("SPN graph has %d nodes" % self._root.get_num_nodes()) # Generate weight nodes self.__debug1("Generating weight nodes") generate_weights(self._root, initializer=self._weight_initializer) if self.__is_debug1(): self.__debug1( "SPN graph has %d nodes and %d TF ops" % (self._root.get_num_nodes(), self._root.get_tf_graph_size())) return self._root