def testMakeDenseSplitEmptyInputs(self):
   """Tests empty inputs op."""
   with self.test_session() as sess:
     partition_ids = array_ops.constant([], dtype=dtypes.int32)
     bucket_ids = array_ops.constant([[]], dtype=dtypes.int64)
     gradients = array_ops.constant([])
     hessians = array_ops.constant([])
     bucket_boundaries = [0.3, 0.52]
     partitions, gains, splits = (
         split_handler_ops.build_dense_inequality_splits(
             num_minibatches=0,
             partition_ids=partition_ids,
             bucket_ids=bucket_ids,
             gradients=gradients,
             hessians=hessians,
             bucket_boundaries=bucket_boundaries,
             l1_regularization=0.1,
             l2_regularization=1,
             tree_complexity_regularization=0,
             min_node_weight=0,
             class_id=-1,
             feature_column_group_id=0,
             multiclass_strategy=learner_pb2.LearnerConfig.TREE_PER_CLASS))
     partitions, gains, splits = sess.run([partitions, gains, splits])
   # .assertEmpty doesn't exist on ubuntu-contrib
   self.assertEqual(0, len(partitions))
   self.assertEqual(0, len(gains))
   self.assertEqual(0, len(splits))
Exemplo n.º 2
0
 def testMakeDenseSplitEmptyInputs(self):
     """Tests empty inputs op."""
     with self.test_session() as sess:
         partition_ids = array_ops.constant([], dtype=dtypes.int32)
         bucket_ids = array_ops.constant([[]], dtype=dtypes.int64)
         gradients = array_ops.constant([])
         hessians = array_ops.constant([])
         bucket_boundaries = [0.3, 0.52]
         partitions, gains, splits = (
             split_handler_ops.build_dense_inequality_splits(
                 num_minibatches=0,
                 partition_ids=partition_ids,
                 bucket_ids=bucket_ids,
                 gradients=gradients,
                 hessians=hessians,
                 bucket_boundaries=bucket_boundaries,
                 l1_regularization=0.1,
                 l2_regularization=1,
                 tree_complexity_regularization=0,
                 min_node_weight=0,
                 class_id=-1,
                 feature_column_group_id=0,
                 multiclass_strategy=learner_pb2.LearnerConfig.
                 TREE_PER_CLASS))
         partitions, gains, splits = sess.run([partitions, gains, splits])
     # .assertEmpty doesn't exist on ubuntu-contrib
     self.assertEqual(0, len(partitions))
     self.assertEqual(0, len(gains))
     self.assertEqual(0, len(splits))
def _make_dense_split(quantile_accumulator_handle, stats_accumulator_handle,
                      stamp_token, next_stamp_token, multiclass_strategy,
                      class_id, feature_column_id, l1_regularization,
                      l2_regularization, tree_complexity_regularization,
                      min_node_weight, is_multi_dimentional,
                      loss_uses_sum_reduction, weak_learner_type):
  """Function that builds splits for a dense feature column."""
  # Get the bucket boundaries
  are_splits_ready, buckets = (
      gen_quantile_ops.quantile_accumulator_get_buckets(
          quantile_accumulator_handles=[quantile_accumulator_handle],
          stamp_token=stamp_token))
  # quantile_accumulator_get_buckets returns a list of results per handle that
  # we pass to it. In this case we're getting results just for one resource.
  are_splits_ready = are_splits_ready[0]
  buckets = buckets[0]

  # After we receive the boundaries from previous iteration we can flush
  # the quantile accumulator.
  with ops.control_dependencies([buckets]):
    flush_quantiles = gen_quantile_ops.quantile_accumulator_flush(
        quantile_accumulator_handle=quantile_accumulator_handle,
        stamp_token=stamp_token,
        next_stamp_token=next_stamp_token)

  if is_multi_dimentional:
    num_minibatches, partition_ids, bucket_ids, gradients, hessians = (
        gen_stats_accumulator_ops.stats_accumulator_tensor_flush(
            stats_accumulator_handle, stamp_token, next_stamp_token))
  else:
    num_minibatches, partition_ids, bucket_ids, gradients, hessians = (
        gen_stats_accumulator_ops.stats_accumulator_scalar_flush(
            stats_accumulator_handle, stamp_token, next_stamp_token))
  # For sum_reduction, we don't need to divide by number of minibatches.
  num_minibatches = control_flow_ops.cond(
      loss_uses_sum_reduction,
      lambda: math_ops.cast(1, dtypes.int64),
      lambda: num_minibatches)
  # Put quantile and stats accumulator flushing in the dependency path.
  with ops.control_dependencies([flush_quantiles, partition_ids]):
    are_splits_ready = array_ops.identity(are_splits_ready)
  partition_ids, gains, split_infos = (
      split_handler_ops.build_dense_inequality_splits(
          num_minibatches=num_minibatches,
          bucket_boundaries=buckets,
          partition_ids=partition_ids,
          bucket_ids=bucket_ids,
          gradients=gradients,
          hessians=hessians,
          class_id=class_id,
          feature_column_group_id=feature_column_id,
          l1_regularization=l1_regularization,
          l2_regularization=l2_regularization,
          tree_complexity_regularization=tree_complexity_regularization,
          min_node_weight=min_node_weight,
          multiclass_strategy=multiclass_strategy,
          weak_learner_type=weak_learner_type))
  return are_splits_ready, partition_ids, gains, split_infos
def _make_dense_split(quantile_accumulator_handle, stats_accumulator_handle,
                      stamp_token, next_stamp_token, multiclass_strategy,
                      class_id, feature_column_id, l1_regularization,
                      l2_regularization, tree_complexity_regularization,
                      min_node_weight, is_multi_dimentional,
                      loss_uses_sum_reduction, weak_learner_type):
    """Function that builds splits for a dense feature column."""
    # Get the bucket boundaries
    are_splits_ready, buckets = (
        gen_quantile_ops.quantile_accumulator_get_buckets(
            quantile_accumulator_handles=[quantile_accumulator_handle],
            stamp_token=stamp_token))
    # quantile_accumulator_get_buckets returns a list of results per handle that
    # we pass to it. In this case we're getting results just for one resource.
    are_splits_ready = are_splits_ready[0]
    buckets = buckets[0]

    # After we receive the boundaries from previous iteration we can flush
    # the quantile accumulator.
    with ops.control_dependencies([buckets]):
        flush_quantiles = gen_quantile_ops.quantile_accumulator_flush(
            quantile_accumulator_handle=quantile_accumulator_handle,
            stamp_token=stamp_token,
            next_stamp_token=next_stamp_token)

    if is_multi_dimentional:
        num_minibatches, partition_ids, bucket_ids, gradients, hessians = (
            gen_stats_accumulator_ops.stats_accumulator_tensor_flush(
                stats_accumulator_handle, stamp_token, next_stamp_token))
    else:
        num_minibatches, partition_ids, bucket_ids, gradients, hessians = (
            gen_stats_accumulator_ops.stats_accumulator_scalar_flush(
                stats_accumulator_handle, stamp_token, next_stamp_token))
    # For sum_reduction, we don't need to divide by number of minibatches.
    num_minibatches = control_flow_ops.cond(loss_uses_sum_reduction,
                                            lambda: math_ops.to_int64(1),
                                            lambda: num_minibatches)
    # Put quantile and stats accumulator flushing in the dependency path.
    with ops.control_dependencies([flush_quantiles, partition_ids]):
        are_splits_ready = array_ops.identity(are_splits_ready)
    partition_ids, gains, split_infos = (
        split_handler_ops.build_dense_inequality_splits(
            num_minibatches=num_minibatches,
            bucket_boundaries=buckets,
            partition_ids=partition_ids,
            bucket_ids=bucket_ids,
            gradients=gradients,
            hessians=hessians,
            class_id=class_id,
            feature_column_group_id=feature_column_id,
            l1_regularization=l1_regularization,
            l2_regularization=l2_regularization,
            tree_complexity_regularization=tree_complexity_regularization,
            min_node_weight=min_node_weight,
            multiclass_strategy=multiclass_strategy,
            weak_learner_type=weak_learner_type))
    return are_splits_ready, partition_ids, gains, split_infos
Exemplo n.º 5
0
    def testMakeMulticlassDenseSplit(self):
        """Tests split handler op."""
        with self.cached_session() as sess:
            partition_ids = array_ops.constant([0, 0, 1], dtype=dtypes.int32)
            bucket_ids = array_ops.constant([[0, 0], [1, 0], [1, 0]],
                                            dtype=dtypes.int64)
            gradients = array_ops.constant([[2.4, 3.0], [-0.6, 0.1],
                                            [8.0, 1.0]])
            hessians = array_ops.constant([[[0.4, 1], [1, 1]],
                                           [[0.38, 1], [1, 1]],
                                           [[0.26, 1], [1, 1]]])
            bucket_boundaries = [0.3, 0.52]
            partitions, gains, splits = (
                split_handler_ops.build_dense_inequality_splits(
                    num_minibatches=2,
                    partition_ids=partition_ids,
                    bucket_ids=bucket_ids,
                    gradients=gradients,
                    hessians=hessians,
                    bucket_boundaries=bucket_boundaries,
                    l1_regularization=0,
                    l2_regularization=1,
                    tree_complexity_regularization=0,
                    min_node_weight=0,
                    class_id=-1,
                    feature_column_group_id=0,
                    multiclass_strategy=learner_pb2.LearnerConfig.FULL_HESSIAN,
                    weak_learner_type=learner_pb2.LearnerConfig.
                    NORMAL_DECISION_TREE))
            partitions, gains, splits = sess.run([partitions, gains, splits])
        self.assertAllEqual([0, 1], partitions)

        split_info = split_info_pb2.SplitInfo()
        split_info.ParseFromString(splits[0])

        left_child = split_info.left_child.vector
        right_child = split_info.right_child.vector
        split_node = split_info.split_node.dense_float_binary_split

        # Each leaf has 2 element vector.
        self.assertEqual(2, len(left_child.value))
        self.assertEqual(2, len(right_child.value))
        self.assertEqual(0, split_node.feature_column)
        self.assertAllClose(0.3, split_node.threshold, 1e-6)
Exemplo n.º 6
0
    def make_splits(self, stamp_token, next_stamp_token, class_id):
        """Create the best split using the accumulated stats and flush the state."""
        # Get the bucket boundaries
        are_splits_ready, buckets = (
            self._quantile_accumulator.get_buckets(stamp_token))
        # After we receive the boundaries from previous iteration we can flush
        # the quantile accumulator.
        with ops.control_dependencies([buckets]):
            flush_quantiles = self._quantile_accumulator.flush(
                stamp_token=stamp_token, next_stamp_token=next_stamp_token)

        # Get the aggregated gradients and hessians per <partition_id, feature_id>
        # pair.
        # In order to distribute the computation on all the PSs we use the PS that
        # had the stats accumulator on.
        with ops.device(None):
            with ops.device(self._stats_accumulator.resource().device):
                num_minibatches, partition_ids, bucket_ids, gradients, hessians = (
                    self._stats_accumulator.flush(stamp_token,
                                                  next_stamp_token))

                # Put quantile and stats accumulator flushing in the dependency path.
                are_splits_ready = control_flow_ops.with_dependencies(
                    [flush_quantiles, partition_ids], are_splits_ready)

                partition_ids, gains, split_infos = (
                    split_handler_ops.build_dense_inequality_splits(
                        num_minibatches=num_minibatches,
                        bucket_boundaries=buckets,
                        partition_ids=partition_ids,
                        bucket_ids=bucket_ids,
                        gradients=gradients,
                        hessians=hessians,
                        class_id=class_id,
                        feature_column_group_id=self._feature_column_group_id,
                        l1_regularization=self._l1_regularization,
                        l2_regularization=self._l2_regularization,
                        tree_complexity_regularization=self.
                        _tree_complexity_regularization,
                        min_node_weight=self._min_node_weight,
                        multiclass_strategy=self._multiclass_strategy))
        return (are_splits_ready, partition_ids, gains, split_infos)
  def make_splits(self, stamp_token, next_stamp_token, class_id):
    """Create the best split using the accumulated stats and flush the state."""
    # Get the bucket boundaries
    are_splits_ready, buckets = (
        self._quantile_accumulator.get_buckets(stamp_token))
    # After we receive the boundaries from previous iteration we can flush
    # the quantile accumulator.
    with ops.control_dependencies([buckets]):
      flush_quantiles = self._quantile_accumulator.flush(
          stamp_token=stamp_token, next_stamp_token=next_stamp_token)

    # Get the aggregated gradients and hessians per <partition_id, feature_id>
    # pair.
    # In order to distribute the computation on all the PSs we use the PS that
    # had the stats accumulator on.
    with ops.device(None):
      with ops.device(self._stats_accumulator.resource().device):
        num_minibatches, partition_ids, bucket_ids, gradients, hessians = (
            self._stats_accumulator.flush(stamp_token, next_stamp_token))

        # Put quantile and stats accumulator flushing in the dependency path.
        are_splits_ready = control_flow_ops.with_dependencies(
            [flush_quantiles, partition_ids], are_splits_ready)

        partition_ids, gains, split_infos = (
            split_handler_ops.build_dense_inequality_splits(
                num_minibatches=num_minibatches,
                bucket_boundaries=buckets,
                partition_ids=partition_ids,
                bucket_ids=bucket_ids,
                gradients=gradients,
                hessians=hessians,
                class_id=class_id,
                feature_column_group_id=self._feature_column_group_id,
                l1_regularization=self._l1_regularization,
                l2_regularization=self._l2_regularization,
                tree_complexity_regularization=self.
                _tree_complexity_regularization,
                min_node_weight=self._min_node_weight,
                multiclass_strategy=self._multiclass_strategy))
    return (are_splits_ready, partition_ids, gains, split_infos)
  def testMakeMulticlassDenseSplit(self):
    """Tests split handler op."""
    with self.test_session() as sess:
      partition_ids = array_ops.constant([0, 0, 1], dtype=dtypes.int32)
      bucket_ids = array_ops.constant(
          [[0, 0], [1, 0], [1, 0]], dtype=dtypes.int64)
      gradients = array_ops.constant([[2.4, 3.0], [-0.6, 0.1], [8.0, 1.0]])
      hessians = array_ops.constant([[[0.4, 1], [1, 1]], [[0.38, 1], [1, 1]],
                                     [[0.26, 1], [1, 1]]])
      bucket_boundaries = [0.3, 0.52]
      partitions, gains, splits = (
          split_handler_ops.build_dense_inequality_splits(
              num_minibatches=2,
              partition_ids=partition_ids,
              bucket_ids=bucket_ids,
              gradients=gradients,
              hessians=hessians,
              bucket_boundaries=bucket_boundaries,
              l1_regularization=0,
              l2_regularization=1,
              tree_complexity_regularization=0,
              min_node_weight=0,
              class_id=-1,
              feature_column_group_id=0,
              multiclass_strategy=learner_pb2.LearnerConfig.FULL_HESSIAN,
              weak_learner_type=learner_pb2.LearnerConfig.NORMAL_DECISION_TREE))
      partitions, gains, splits = sess.run([partitions, gains, splits])
    self.assertAllEqual([0, 1], partitions)

    split_info = split_info_pb2.SplitInfo()
    split_info.ParseFromString(splits[0])

    left_child = split_info.left_child.vector
    right_child = split_info.right_child.vector
    split_node = split_info.split_node.dense_float_binary_split

    # Each leaf has 2 element vector.
    self.assertEqual(2, len(left_child.value))
    self.assertEqual(2, len(right_child.value))
    self.assertEqual(0, split_node.feature_column)
    self.assertAllClose(0.3, split_node.threshold, 1e-6)
Exemplo n.º 9
0
    def testMakeDenseSplit(self):
        """Tests split handler op."""
        with self.test_session() as sess:
            # The data looks like the following after dividing by number of steps (2).
            # Gradients    | Partition | Dense Quantile |
            # (1.2, 0.2)   | 0         | 0              |
            # (-0.3, 0.19) | 0         | 1              |
            # (4.0, 0.13)  | 1         | 1              |
            partition_ids = array_ops.constant([0, 0, 1], dtype=dtypes.int32)
            bucket_ids = array_ops.constant([[0, 0], [1, 0], [1, 0]],
                                            dtype=dtypes.int64)
            gradients = array_ops.constant([2.4, -0.6, 8.0])
            hessians = array_ops.constant([0.4, 0.38, 0.26])
            bucket_boundaries = [0.3, 0.52]
            partitions, gains, splits = (
                split_handler_ops.build_dense_inequality_splits(
                    num_minibatches=2,
                    partition_ids=partition_ids,
                    bucket_ids=bucket_ids,
                    gradients=gradients,
                    hessians=hessians,
                    bucket_boundaries=bucket_boundaries,
                    l1_regularization=0.1,
                    l2_regularization=1,
                    tree_complexity_regularization=0,
                    min_node_weight=0,
                    class_id=-1,
                    feature_column_group_id=0,
                    multiclass_strategy=learner_pb2.LearnerConfig.
                    TREE_PER_CLASS))
            partitions, gains, splits = sess.run([partitions, gains, splits])
        self.assertAllEqual([0, 1], partitions)

        # Check the split on partition 0.
        # -(1.2 - 0.1) / (0.2 + 1)
        expected_left_weight = -0.91666

        # expected_left_weight * -(1.2 - 0.1)
        expected_left_gain = 1.0083333333333331

        # (-0.3 + 0.1) / (0.19 + 1)
        expected_right_weight = 0.1680672

        # expected_right_weight * -(-0.3 + 0.1)
        expected_right_gain = 0.033613445378151252

        # (-0.3 + 1.2 - 0.1) ** 2 / (0.19 + 0.2 + 1)
        expected_bias_gain = 0.46043165467625885

        split_info = split_info_pb2.SplitInfo()
        split_info.ParseFromString(splits[0])
        left_child = split_info.left_child.vector
        right_child = split_info.right_child.vector
        split_node = split_info.split_node.dense_float_binary_split
        self.assertAllClose(
            expected_left_gain + expected_right_gain - expected_bias_gain,
            gains[0], 0.00001)
        self.assertAllClose([expected_left_weight], left_child.value, 0.00001)
        self.assertAllClose([expected_right_weight], right_child.value,
                            0.00001)
        self.assertEqual(0, split_node.feature_column)
        self.assertAllClose(0.3, split_node.threshold, 0.00001)

        # Check the split on partition 1.
        # (-4 + 0.1) / (0.13 + 1)
        expected_left_weight = -3.4513274336283186
        expected_right_weight = 0
        split_info = split_info_pb2.SplitInfo()
        split_info.ParseFromString(splits[1])
        left_child = split_info.left_child.vector
        right_child = split_info.right_child.vector
        split_node = split_info.split_node.dense_float_binary_split
        # There's only one active bucket here so zero gain is expected.
        self.assertAllClose(0.0, gains[1], 0.00001)
        self.assertAllClose([expected_left_weight], left_child.value, 0.00001)
        self.assertAllClose([expected_right_weight], right_child.value,
                            0.00001)
        self.assertEqual(0, split_node.feature_column)
        self.assertAllClose(0.52, split_node.threshold, 0.00001)
  def testMakeDenseSplit(self):
    """Tests split handler op."""
    with self.test_session() as sess:
      # The data looks like the following after dividing by number of steps (2).
      # Gradients    | Partition | Dense Quantile |
      # (1.2, 0.2)   | 0         | 0              |
      # (-0.3, 0.19) | 0         | 1              |
      # (4.0, 0.13)  | 1         | 1              |
      partition_ids = array_ops.constant([0, 0, 1], dtype=dtypes.int32)
      bucket_ids = array_ops.constant(
          [[0, 0], [1, 0], [1, 0]], dtype=dtypes.int64)
      gradients = array_ops.constant([2.4, -0.6, 8.0])
      hessians = array_ops.constant([0.4, 0.38, 0.26])
      bucket_boundaries = [0.3, 0.52]
      partitions, gains, splits = (
          split_handler_ops.build_dense_inequality_splits(
              num_minibatches=2,
              partition_ids=partition_ids,
              bucket_ids=bucket_ids,
              gradients=gradients,
              hessians=hessians,
              bucket_boundaries=bucket_boundaries,
              l1_regularization=0.1,
              l2_regularization=1,
              tree_complexity_regularization=0,
              min_node_weight=0,
              class_id=-1,
              feature_column_group_id=0,
              multiclass_strategy=learner_pb2.LearnerConfig.TREE_PER_CLASS))
      partitions, gains, splits = sess.run([partitions, gains, splits])
    self.assertAllEqual([0, 1], partitions)

    # Check the split on partition 0.
    # -(1.2 - 0.1) / (0.2 + 1)
    expected_left_weight = -0.91666

    # expected_left_weight * -(1.2 - 0.1)
    expected_left_gain = 1.0083333333333331

    # (-0.3 + 0.1) / (0.19 + 1)
    expected_right_weight = 0.1680672

    # expected_right_weight * -(-0.3 + 0.1)
    expected_right_gain = 0.033613445378151252

    # (-0.3 + 1.2 - 0.1) ** 2 / (0.19 + 0.2 + 1)
    expected_bias_gain = 0.46043165467625885

    split_info = split_info_pb2.SplitInfo()
    split_info.ParseFromString(splits[0])
    left_child = split_info.left_child.vector
    right_child = split_info.right_child.vector
    split_node = split_info.split_node.dense_float_binary_split
    self.assertAllClose(
        expected_left_gain + expected_right_gain - expected_bias_gain, gains[0],
        0.00001)
    self.assertAllClose([expected_left_weight], left_child.value, 0.00001)
    self.assertAllClose([expected_right_weight], right_child.value, 0.00001)
    self.assertEqual(0, split_node.feature_column)
    self.assertAllClose(0.3, split_node.threshold, 0.00001)

    # Check the split on partition 1.
    # (-4 + 0.1) / (0.13 + 1)
    expected_left_weight = -3.4513274336283186
    expected_right_weight = 0
    split_info = split_info_pb2.SplitInfo()
    split_info.ParseFromString(splits[1])
    left_child = split_info.left_child.vector
    right_child = split_info.right_child.vector
    split_node = split_info.split_node.dense_float_binary_split
    # There's only one active bucket here so zero gain is expected.
    self.assertAllClose(0.0, gains[1], 0.00001)
    self.assertAllClose([expected_left_weight], left_child.value, 0.00001)
    self.assertAllClose([expected_right_weight], right_child.value, 0.00001)
    self.assertEqual(0, split_node.feature_column)
    self.assertAllClose(0.52, split_node.threshold, 0.00001)