예제 #1
0
 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']
예제 #2
0
 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])
예제 #3
0
 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])
예제 #4
0
    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)
예제 #5
0
 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'])
예제 #6
0
 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'])
예제 #7
0
    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