def _verify_input(tensor_list, labels, probs_list): """Verify that batched inputs are well-formed.""" checked_probs_list = [] for probs in probs_list: # Since number of classes shouldn't change at runtime, probabilities shape # should be fully defined. probs.get_shape().assert_is_fully_defined() # Probabilities must be 1D. probs.get_shape().assert_has_rank(1) # Probabilities must be nonnegative and sum to one. tol = 1e-6 prob_sum = math_ops.reduce_sum(probs) checked_probs = control_flow_ops.with_dependencies([ check_ops.assert_non_negative(probs), check_ops.assert_less(prob_sum, 1.0 + tol), check_ops.assert_less(1.0 - tol, prob_sum) ], probs) checked_probs_list.append(checked_probs) # All probabilities should be the same length. prob_length = checked_probs_list[0].get_shape().num_elements() for checked_prob in checked_probs_list: if checked_prob.get_shape().num_elements() != prob_length: raise ValueError('Probability parameters must have the same length.') # Labels tensor should only have batch dimension. labels.get_shape().assert_has_rank(1) for tensor in tensor_list: # Data tensor should have a batch dimension. shape = tensor.get_shape().with_rank_at_least(1) # Data and label batch dimensions must be compatible. tensor_shape.dimension_at_index(shape, 0).assert_is_compatible_with( labels.get_shape()[0]) # Data and labels must have the same, strictly positive batch size. Since we # can't assume we know the batch size at graph creation, add runtime checks. labels_batch_size = array_ops.shape(labels)[0] lbl_assert = check_ops.assert_positive(labels_batch_size) # Make each tensor depend on its own checks. labels = control_flow_ops.with_dependencies([lbl_assert], labels) tensor_list = [ control_flow_ops.with_dependencies([ lbl_assert, check_ops.assert_equal(array_ops.shape(x)[0], labels_batch_size) ], x) for x in tensor_list ] # Label's classes must be integers 0 <= x < num_classes. labels = control_flow_ops.with_dependencies([ check_ops.assert_integer(labels), check_ops.assert_non_negative(labels), check_ops.assert_less(labels, math_ops.cast(prob_length, labels.dtype)) ], labels) return tensor_list, labels, checked_probs_list
def _check_domain_range_possibly_add_asserts(self): """Static check of init arg `num_rows`, possibly add asserts.""" # Possibly add asserts. if self._assert_proper_shapes: self._num_rows = control_flow_ops.with_dependencies([ check_ops.assert_rank( self._num_rows, 0, message="Argument num_rows must be a 0-D Tensor."), check_ops.assert_non_negative( self._num_rows, message="Argument num_rows must be non-negative."), ], self._num_rows) self._num_columns = control_flow_ops.with_dependencies([ check_ops.assert_rank( self._num_columns, 0, message="Argument num_columns must be a 0-D Tensor."), check_ops.assert_non_negative( self._num_columns, message="Argument num_columns must be non-negative."), ], self._num_columns) # Static checks. if not self._num_rows.dtype.is_integer: raise TypeError("Argument num_rows must be integer type. Found:" " %s" % self._num_rows) if not self._num_columns.dtype.is_integer: raise TypeError("Argument num_columns must be integer type. Found:" " %s" % self._num_columns) num_rows_static = self._num_rows_static num_columns_static = self._num_columns_static if num_rows_static is not None: if num_rows_static.ndim != 0: raise ValueError("Argument num_rows must be a 0-D Tensor. Found:" " %s" % num_rows_static) if num_rows_static < 0: raise ValueError("Argument num_rows must be non-negative. Found:" " %s" % num_rows_static) if num_columns_static is not None: if num_columns_static.ndim != 0: raise ValueError("Argument num_columns must be a 0-D Tensor. Found:" " %s" % num_columns_static) if num_columns_static < 0: raise ValueError("Argument num_columns must be non-negative. Found:" " %s" % num_columns_static)
def get_sample_ndims(self, x, name="get_sample_ndims"): """Returns number of dimensions corresponding to iid draws ("sample"). Args: x: `Tensor`. name: `String`. The name to give this op. Returns: sample_ndims: `Tensor` (0D, `int32`). Raises: ValueError: if `sample_ndims` is calculated to be negative. """ with self._name_scope(name, values=[x]): ndims = self.get_ndims(x, name=name) if self._is_all_constant_helper(ndims, self.batch_ndims, self.event_ndims): ndims = tensor_util.constant_value(ndims) sample_ndims = (ndims - self._batch_ndims_static - self._event_ndims_static) if sample_ndims < 0: raise ValueError( "expected batch_ndims(%d) + event_ndims(%d) <= ndims(%d)" % (self._batch_ndims_static, self._event_ndims_static, ndims)) return ops.convert_to_tensor(sample_ndims, name="sample_ndims") else: with ops.name_scope(name="sample_ndims"): sample_ndims = ndims - self.batch_ndims - self.event_ndims if self.validate_args: sample_ndims = control_flow_ops.with_dependencies( [check_ops.assert_non_negative(sample_ndims)], sample_ndims) return sample_ndims
def _maybe_assert_valid_x(self, x): if not self.validate_args: return x is_valid = check_ops.assert_non_negative( x, message="Forward transformation input must be at least 0.") return control_flow_ops.with_dependencies([is_valid], x)
def _check_batch_shape_possibly_add_asserts(self): """Static check of init arg `batch_shape`, possibly add asserts.""" if self._batch_shape_arg is None: return # Possibly add asserts if self._assert_proper_shapes: self._batch_shape_arg = control_flow_ops.with_dependencies( [ check_ops.assert_rank( self._batch_shape_arg, 1, message="Argument batch_shape must be a 1-D Tensor."), check_ops.assert_non_negative( self._batch_shape_arg, message="Argument batch_shape must be non-negative."), ], self._batch_shape_arg) # Static checks if not self._batch_shape_arg.dtype.is_integer: raise TypeError("Argument batch_shape must be integer type. Found:" " %s" % self._batch_shape_arg) if self._batch_shape_static is None: return # Cannot do any other static checks. if self._batch_shape_static.ndim != 1: raise ValueError("Argument batch_shape must be a 1-D Tensor. Found:" " %s" % self._batch_shape_static) if np.any(self._batch_shape_static < 0): raise ValueError("Argument batch_shape must be non-negative. Found:" "%s" % self._batch_shape_static)
def _maybe_assert_valid_x(self, x): if not self.validate_args: return x is_valid = check_ops.assert_non_negative( x, message="Forward transformation input must be at least {}.".format(0)) return control_flow_ops.with_dependencies([is_valid], x)
def _check_num_rows_possibly_add_asserts(self): """Static check of init arg `num_rows`, possibly add asserts.""" # Possibly add asserts. if self._assert_proper_shapes: self._num_rows = control_flow_ops.with_dependencies([ check_ops.assert_rank( self._num_rows, 0, message="Argument num_rows must be a 0-D Tensor."), check_ops.assert_non_negative( self._num_rows, message="Argument num_rows must be non-negative."), ], self._num_rows) # Static checks. if not self._num_rows.dtype.is_integer: raise TypeError("Argument num_rows must be integer type. Found:" " %s" % self._num_rows) num_rows_static = self._num_rows_static if num_rows_static is None: return # Cannot do any other static checks. if num_rows_static.ndim != 0: raise ValueError("Argument num_rows must be a 0-D Tensor. Found:" " %s" % num_rows_static) if num_rows_static < 0: raise ValueError("Argument num_rows must be non-negative. Found:" " %s" % num_rows_static)
def _check_batch_shape_possibly_add_asserts(self): """Static check of init arg `batch_shape`, possibly add asserts.""" if self._batch_shape_arg is None: return # Possibly add asserts if self._assert_proper_shapes: self._batch_shape_arg = control_flow_ops.with_dependencies([ check_ops.assert_rank( self._batch_shape_arg, 1, message="Argument batch_shape must be a 1-D Tensor."), check_ops.assert_non_negative( self._batch_shape_arg, message="Argument batch_shape must be non-negative."), ], self._batch_shape_arg) # Static checks if not self._batch_shape_arg.dtype.is_integer: raise TypeError( "Argument batch_shape must be integer type. Found:" " %s" % self._batch_shape_arg) if self._batch_shape_static is None: return # Cannot do any other static checks. if self._batch_shape_static.ndim != 1: raise ValueError( "Argument batch_shape must be a 1-D Tensor. Found:" " %s" % self._batch_shape_static) if np.any(self._batch_shape_static < 0): raise ValueError( "Argument batch_shape must be non-negative. Found:" "%s" % self._batch_shape_static)
def from_row_limits(cls, row_limits, validate=True, preferred_dtype=None): """Creates a `RowPartition` with rows partitioned by `row_limits`. Equivalent to: `from_row_splits(values, concat([0, row_limits], axis=0))`. Args: row_limits: A 1-D integer tensor with shape `[nrows]`. Must be sorted in ascending order. validate: If true, then use assertions to check that the arguments form a valid `RowPartition`. preferred_dtype: If row_limits has an unspecified type, use this one. If preferred_dtype is None, defaults to dtypes.int64. Returns: A `RowPartition`. """ if not isinstance(validate, bool): raise TypeError("validate must have type bool") with ops.name_scope(None, "RowPartitionFromRowLimits", [row_limits]): row_limits = cls._convert_row_partition(row_limits, "row_limits", preferred_dtype) row_limits.shape.assert_has_rank(1) if validate: msg = "Arguments to from_row_limits do not form a valid RaggedTensor" checks = [ check_ops.assert_rank(row_limits, 1, message=msg), check_ops.assert_non_negative(row_limits[:1], message=msg), _assert_monotonic_increasing(row_limits, message=msg), ] row_limits = control_flow_ops.with_dependencies(checks, row_limits) zero = array_ops.zeros([1], row_limits.dtype) row_splits = array_ops.concat([zero, row_limits], axis=0) return cls(row_splits=row_splits, internal=_row_partition_factory_key)
def get_sample_ndims(self, x, name="get_sample_ndims"): """Returns number of dimensions corresponding to iid draws ("sample"). Args: x: `Tensor`. name: Python `str`. The name to give this op. Returns: sample_ndims: `Tensor` (0D, `int32`). Raises: ValueError: if `sample_ndims` is calculated to be negative. """ with self._name_scope(name, values=[x]): ndims = self.get_ndims(x, name=name) if self._is_all_constant_helper(ndims, self.batch_ndims, self.event_ndims): ndims = tensor_util.constant_value(ndims) sample_ndims = (ndims - self._batch_ndims_static - self._event_ndims_static) if sample_ndims < 0: raise ValueError( "expected batch_ndims(%d) + event_ndims(%d) <= ndims(%d)" % (self._batch_ndims_static, self._event_ndims_static, ndims)) return ops.convert_to_tensor(sample_ndims, name="sample_ndims") else: with ops.name_scope(name="sample_ndims"): sample_ndims = ndims - self.batch_ndims - self.event_ndims if self.validate_args: sample_ndims = control_flow_ops.with_dependencies( [check_ops.assert_non_negative(sample_ndims)], sample_ndims) return sample_ndims
def _check_n(self, n): n = ops.convert_to_tensor(n, name="n") if not self.validate_args: return n return control_flow_ops.with_dependencies( [check_ops.assert_non_negative(n), distribution_util.assert_integer_form(n)], n)
def _assert_valid_n(self, n, validate_args): n = ops.convert_to_tensor(n, name="n") if not validate_args: return n return control_flow_ops.with_dependencies( [check_ops.assert_non_negative(n), distribution_util.assert_integer_form(n)], n)
def test_raises_when_negative(self): with self.test_session(): zoe = constant_op.constant([-1, -2], name="zoe") with ops.control_dependencies([check_ops.assert_non_negative(zoe)]): out = array_ops.identity(zoe) with self.assertRaisesOpError("zoe"): out.eval()
def test_raises_when_negative(self): with self.test_session(): zoe = constant_op.constant([-1, -2], name="zoe") with ops.control_dependencies([check_ops.assert_non_negative(zoe)]): out = array_ops.identity(zoe) with self.assertRaisesOpError("zoe"): out.eval()
def __init__(self, n, logits=None, p=None, validate_args=False, allow_nan_stats=True, name="Binomial"): """Initialize a batch of Binomial distributions. Args: n: Non-negative floating point tensor with shape broadcastable to `[N1,..., Nm]` with `m >= 0` and the same dtype as `p` or `logits`. Defines this as a batch of `N1 x ... x Nm` different Binomial distributions. Its components should be equal to integer values. logits: Floating point tensor representing the log-odds of a positive event with shape broadcastable to `[N1,..., Nm]` `m >= 0`, and the same dtype as `n`. Each entry represents logits for the probability of success for independent Binomial distributions. p: Positive floating point tensor with shape broadcastable to `[N1,..., Nm]` `m >= 0`, `p in [0, 1]`. Each entry represents the probability of success for independent Binomial distributions. validate_args: `Boolean`, default `False`. Whether to assert valid values for parameters `n`, `p`, and `x` in `prob` and `log_prob`. If `False` and inputs are invalid, correct behavior is not guaranteed. allow_nan_stats: `Boolean`, default `True`. If `False`, raise an exception if a statistic (e.g. mean/mode/etc...) is undefined for any batch member. If `True`, batch members with valid parameters leading to undefined statistics will return NaN for this statistic. name: The name to prefix Ops created by this distribution class. Examples: ```python # Define 1-batch of a binomial distribution. dist = Binomial(n=2., p=.9) # Define a 2-batch. dist = Binomial(n=[4., 5], p=[.1, .3]) ``` """ self._logits, self._p = distribution_util.get_logits_and_prob( name=name, logits=logits, p=p, validate_args=validate_args) with ops.name_scope(name, values=[n]) as ns: with ops.control_dependencies([ check_ops.assert_non_negative( n, message="n has negative components."), distribution_util.assert_integer_form( n, message="n has non-integer components."), ] if validate_args else []): self._n = array_ops.identity(n, name="n") super(Binomial, self).__init__( dtype=self._p.dtype, parameters={"n": self._n, "p": self._p, "logits": self._logits}, is_continuous=False, is_reparameterized=False, validate_args=validate_args, allow_nan_stats=allow_nan_stats, name=ns)
def _assert_valid_sample(self, x, check_integer=True): if not self.validate_args: return x dependencies = [check_ops.assert_non_negative(x)] if check_integer: dependencies += [distribution_util.assert_integer_form( x, message="x has non-integer components.")] return control_flow_ops.with_dependencies(dependencies, x)
def embed_check_nonnegative_discrete(x, check_integer=True): """Assert x is a non-negative tensor, and optionally of integers.""" assertions = [check_ops.assert_non_negative( x, message="x must be non-negative.")] if check_integer: assertions += [assert_integer_form( x, message="x cannot contain fractional components.")] return control_flow_ops.with_dependencies(assertions, x)
def embed_check_nonnegative_discrete(x, check_integer=True): """Assert x is a non-negative tensor, and optionally of integers.""" assertions = [check_ops.assert_non_negative( x, message="x must be non-negative.")] if check_integer: assertions += [assert_integer_form( x, message="x cannot contain fractional components.")] return control_flow_ops.with_dependencies(assertions, x)
def _maybe_assert_valid_x(self, x): if not self.validate_args or self.power == 0.: return x is_valid = check_ops.assert_non_negative( 1. + self.power * x, message="Forward transformation input must be at least {}.".format( -1. / self.power)) return control_flow_ops.with_dependencies([is_valid], x)
def _assert_valid_sample(self, x, check_integer=True): if not self.validate_args: return x with ops.name_scope("check_x", values=[x]): dependencies = [check_ops.assert_non_negative(x)] if check_integer: dependencies += [distribution_util.assert_integer_form( x, message="x has non-integer components.")] return control_flow_ops.with_dependencies(dependencies, x)
def _maybe_assert_valid_y(self, y): if not self.validate_args: return y is_positive = check_ops.assert_non_negative( y, message="Inverse transformation input must be greater than 0.") less_than_one = check_ops.assert_less_equal( y, constant_op.constant(1., y.dtype), message="Inverse transformation input must be less than or equal to 1.") return control_flow_ops.with_dependencies([is_positive, less_than_one], y)
def _maybe_assert_valid_y(self, y): if not self.validate_args: return y is_positive = check_ops.assert_non_negative( y, message="Inverse transformation input must be greater than 0.") less_than_one = check_ops.assert_less_equal( y, constant_op.constant(1., y.dtype), message="Inverse transformation input must be less than or equal to 1.") return control_flow_ops.with_dependencies([is_positive, less_than_one], y)
def _assert_range(labels, n_classes): assert_less = check_ops.assert_less( labels, ops.convert_to_tensor(n_classes, dtype=labels.dtype), message='Label IDs must < n_classes') assert_greater = check_ops.assert_non_negative( labels, message='Label IDs must >= 0') with ops.control_dependencies((assert_less, assert_greater)): return array_ops.identity(labels)
def _assert_range(labels, n_classes): assert_less = check_ops.assert_less( labels, ops.convert_to_tensor(n_classes, dtype=labels.dtype), message='Label IDs must < n_classes') assert_greater = check_ops.assert_non_negative( labels, message='Label IDs must >= 0') with ops.control_dependencies((assert_less, assert_greater)): return array_ops.identity(labels)
def test_empty_tensor_doesnt_raise(self): # A tensor is non-negative when it satisfies: # For every element x_i in x, x_i >= 0 # and an empty tensor has no elements, so this is trivially satisfied. # This is standard set theory. empty = constant_op.constant([], name="empty") with ops.control_dependencies([check_ops.assert_non_negative(empty)]): out = array_ops.identity(empty) self.evaluate(out)
def _check_x(self, x, check_integer=True): with ops.name_scope('check_x', values=[x]): x = ops.convert_to_tensor(x, name="x") if not self.validate_args: return x dependencies = [check_ops.assert_non_negative(x)] if check_integer: dependencies += [distribution_util.assert_integer_form( x, message="x has non-integer components.")] return control_flow_ops.with_dependencies(dependencies, x)
def test_empty_tensor_doesnt_raise(self): # A tensor is non-negative when it satisfies: # For every element x_i in x, x_i >= 0 # and an empty tensor has no elements, so this is trivially satisfied. # This is standard set theory. with self.test_session(): empty = constant_op.constant([], name="empty") with ops.control_dependencies([check_ops.assert_non_negative(empty)]): out = array_ops.identity(empty) out.eval()
def _maybe_assert_valid_total_count(self, total_count, validate_args): if not validate_args: return total_count return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( total_count, message="total_count must be non-negative."), distribution_util.assert_integer_form( total_count, message="total_count cannot contain fractional values."), ], total_count)
def _inverse_log_det_jacobian(self, y): # If event_ndims = 2, # F^{-1}(y) = (-y, y), so DF^{-1}(y) = (-1, 1), # so Log|DF^{-1}(y)| = Log[1, 1] = [0, 0]. zeros = constant_op.constant(0., dtype=y.dtype) if self.validate_args: zeros = control_flow_ops.with_dependencies( [check_ops.assert_non_negative(y, message="Argument y was negative")], zeros) return zeros, zeros
def _check_counts(self, counts): counts = ops.convert_to_tensor(counts, name="counts_before_deps") if not self.validate_args: return counts return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( counts, message="counts has negative components."), check_ops.assert_less_equal( counts, self._n, message="counts are not less than or equal to n."), distribution_util.assert_integer_form( counts, message="counts have non-integer components.")], counts)
def _maybe_assert_valid(self, x): if not self.validate_args: return x return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( x, message="sample must be non-negative"), check_ops.assert_less_equal( x, array_ops.ones([], self.concentration0.dtype), message="sample must be no larger than `1`."), ], x)
def _get_tol(self, tol): if tol is None: return ops.convert_to_tensor(0, dtype=self.loc.dtype) tol = ops.convert_to_tensor(tol, dtype=self.loc.dtype) if self.validate_args: tol = control_flow_ops.with_dependencies([ check_ops.assert_non_negative( tol, message="Argument 'tol' must be non-negative") ], tol) return tol
def _check_counts(self, counts): """Check counts for proper shape, values, then return tensor version.""" counts = ops.convert_to_tensor(counts, name='counts') if not self.validate_args: return counts candidate_n = math_ops.reduce_sum(counts, reduction_indices=[-1]) return control_flow_ops.with_dependencies([ check_ops.assert_non_negative(counts), check_ops.assert_equal(self._n, candidate_n), _assert_integer_form(counts)], counts)
def _inverse_log_det_jacobian(self, y): # If event_ndims = 2, # F^{-1}(y) = (-y, y), so DF^{-1}(y) = (-1, 1), # so Log|DF^{-1}(y)| = Log[1, 1] = [0, 0]. zeros = constant_op.constant(0., dtype=y.dtype) if self.validate_args: zeros = control_flow_ops.with_dependencies([ check_ops.assert_non_negative( y, message="Argument y was negative") ], zeros) return zeros, zeros
def _maybe_assert_valid(self, x): if not self.validate_args: return x return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( x, message="sample must be non-negative"), check_ops.assert_less_equal( x, array_ops.ones([], self.concentration0.dtype), message="sample must be no larger than `1`."), ], x)
def _check_counts(self, counts): counts = ops.convert_to_tensor(counts, name="counts_before_deps") if not self.validate_args: return counts return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( counts, message="counts has negative components."), check_ops.assert_less_equal( counts, self._n, message="counts are not less than or equal to n."), distribution_util.assert_integer_form( counts, message="counts have non-integer components.")], counts)
def _maybe_assert_valid_total_count(self, total_count, validate_args): if not validate_args: return total_count return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( total_count, message="total_count must be non-negative."), distribution_util.assert_integer_form( total_count, message="total_count cannot contain fractional values."), ], total_count)
def _prepare(self): # We need to put the conversion and check here because a user will likely # want to decay the learning rate dynamically. self._learning_rate_tensor = control_flow_ops.with_dependencies([ check_ops.assert_non_negative( self._learning_rate, message='`learning_rate` must be non-negative') ], ops.convert_to_tensor(self._learning_rate, name='learning_rate_tensor')) self._decay_tensor = ops.convert_to_tensor( self._preconditioner_decay_rate, name='preconditioner_decay_rate') super(SGLDOptimizer, self)._prepare()
def _inverse_log_det_jacobian(self, y): # If event_ndims = 2, # F^{-1}(y) = (-y, y), so DF^{-1}(y) = (-1, 1), # so Log|DF^{-1}(y)| = Log[1, 1] = [0, 0]. batch_shape = array_ops.shape(y)[:array_ops.rank(y) - self.event_ndims] zeros = array_ops.zeros(batch_shape, dtype=y.dtype) if self.validate_args: zeros = control_flow_ops.with_dependencies( [check_ops.assert_non_negative(y, message="Argument y was negative")], zeros) return zeros, zeros
def _inverse_log_det_jacobian(self, y): # If event_ndims = 2, # F^{-1}(y) = (-y, y), so DF^{-1}(y) = (-1, 1), # so Log|DF^{-1}(y)| = Log[1, 1] = [0, 0]. batch_shape = array_ops.shape(y)[:array_ops.rank(y) - self.event_ndims] zeros = array_ops.zeros(batch_shape, dtype=y.dtype) if self.validate_args: zeros = control_flow_ops.with_dependencies( [check_ops.assert_non_negative(y, message="Argument y was negative")], zeros) return zeros, zeros
def _check_counts(self, counts): """Check counts for proper shape, values, then return tensor version.""" counts = ops.convert_to_tensor(counts, name='counts_before_deps') candidate_n = math_ops.reduce_sum(counts, reduction_indices=[-1]) dependencies = [check_ops.assert_non_negative(counts), check_ops.assert_equal(self._n, math_ops.cast(candidate_n, self._n.dtype))] if not self._allow_arbitrary_counts: dependencies += [_assert_integer_form(counts)] return control_flow_ops.with_dependencies(dependencies, counts)
def _check_x(self, x, check_integer=True): with ops.name_scope('check_x', values=[x]): x = ops.convert_to_tensor(x, name="x") if not self.validate_args: return x dependencies = [check_ops.assert_non_negative(x)] if check_integer: dependencies += [ distribution_util.assert_integer_form( x, message="x has non-integer components.") ] return control_flow_ops.with_dependencies(dependencies, x)
def _check_counts(self, counts): """Check counts for proper shape, values, then return tensor version.""" counts = ops.convert_to_tensor(counts, name='counts_before_deps') candidate_n = math_ops.reduce_sum(counts, reduction_indices=[-1]) dependencies = [check_ops.assert_non_negative(counts), check_ops.assert_equal(self._n, math_ops.cast(candidate_n, self._n.dtype))] if not self._allow_arbitrary_counts: dependencies += [_assert_integer_form(counts)] return control_flow_ops.with_dependencies(dependencies, counts)
def _assert_valid_counts(self, counts): """Check counts for proper shape, values, then return tensor version.""" counts = ops.convert_to_tensor(counts, name="counts") if not self.validate_args: return counts candidate_n = math_ops.reduce_sum(counts, reduction_indices=[-1]) return control_flow_ops.with_dependencies([ check_ops.assert_non_negative(counts), check_ops.assert_equal( self._n, candidate_n, message="counts do not sum to n"), distribution_util.assert_integer_form(counts) ], counts)
def _assert_valid_sample(self, counts): """Check counts for proper shape, values, then return tensor version.""" if not self.validate_args: return counts return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( counts, message="counts has negative components."), check_ops.assert_equal( self.n, math_ops.reduce_sum(counts, reduction_indices=[-1]), message="counts do not sum to n."), distribution_util.assert_integer_form( counts, message="counts have non-integer components.") ], counts)
def get_logits_and_prob( logits=None, p=None, multidimensional=False, validate_args=False, name="GetLogitsAndProb"): """Converts logits to probabilities and vice-versa, and returns both. Args: logits: Numeric `Tensor` representing log-odds. p: Numeric `Tensor` representing probabilities. multidimensional: Given `p` a [N1, N2, ... k] dimensional tensor, whether the last dimension represents the probability between k classes. This will additionally assert that the values in the last dimension sum to one. If `False`, will instead assert that each value is in `[0, 1]`. validate_args: `Boolean`, default `False`. Whether to assert `0 <= p <= 1` if multidimensional is `False`, otherwise that the last dimension of `p` sums to one. name: A name for this operation (optional). Returns: Tuple with `logits` and `p`. If `p` has an entry that is `0` or `1`, then the corresponding entry in the returned logits will be `-Inf` and `Inf` respectively. Raises: ValueError: if neither `p` nor `logits` were passed in, or both were. """ with ops.name_scope(name, values=[p, logits]): if p is None and logits is None: raise ValueError("Must pass p or logits.") elif p is not None and logits is not None: raise ValueError("Must pass either p or logits, not both.") elif p is None: logits = array_ops.identity(logits, name="logits") with ops.name_scope("p"): p = math_ops.sigmoid(logits) elif logits is None: with ops.name_scope("p"): p = array_ops.identity(p) if validate_args: one = constant_op.constant(1., p.dtype) dependencies = [check_ops.assert_non_negative(p)] if multidimensional: dependencies += [assert_close( math_ops.reduce_sum(p, reduction_indices=[-1]), one, message="p does not sum to 1.")] else: dependencies += [check_ops.assert_less_equal( p, one, message="p has components greater than 1.")] p = control_flow_ops.with_dependencies(dependencies, p) with ops.name_scope("logits"): logits = math_ops.log(p) - math_ops.log(1. - p) return (logits, p)
def get_logits_and_prob( logits=None, p=None, multidimensional=False, validate_args=True, name=None): """Converts logits to probabilities and vice-versa, and returns both. Args: logits: Numeric `Tensor` representing log-odds. p: Numeric `Tensor` representing probabilities. multidimensional: Given `p` a [N1, N2, ... k] dimensional tensor, whether the last dimension represents the probability between k classes. This will additionally assert that the values in the last dimension sum to one. If `False`, will instead assert that each value is in `[0, 1]`. validate_args: Whether to assert `0 <= p <= 1` if multidimensional is `False`, otherwise that the last dimension of `p` sums to one. name: A name for this operation (optional). Returns: Tuple with `logits` and `p`. If `p` has an entry that is `0` or `1`, then the corresponding entry in the returned logits will be `-Inf` and `Inf` respectively. Raises: ValueError: if neither `p` nor `logits` were passed in, or both were. """ if p is None and logits is None: raise ValueError("Must pass p or logits.") elif p is not None and logits is not None: raise ValueError("Must pass either p or logits, not both.") elif p is None: with ops.name_scope(name, values=[logits]): logits = array_ops.identity(logits, name="logits") with ops.name_scope(name): with ops.name_scope("p"): p = math_ops.sigmoid(logits) elif logits is None: with ops.name_scope(name): with ops.name_scope("p"): p = array_ops.identity(p) if validate_args: one = constant_op.constant(1., p.dtype) dependencies = [check_ops.assert_non_negative(p)] if multidimensional: dependencies += [assert_close( math_ops.reduce_sum(p, reduction_indices=[-1]), one, message="p does not sum to 1.")] else: dependencies += [check_ops.assert_less_equal( p, one, message="p has components greater than 1.")] p = control_flow_ops.with_dependencies(dependencies, p) with ops.name_scope("logits"): logits = math_ops.log(p) - math_ops.log(1. - p) return (logits, p)
def _check_counts(self, counts): """Check counts for proper shape, values, then return tensor version.""" counts = ops.convert_to_tensor(counts, name="counts_before_deps") candidate_n = math_ops.reduce_sum(counts, reduction_indices=[-1]) if not self.validate_args: return counts return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( counts, message="counts has negative components."), check_ops.assert_equal( self._n, candidate_n, message="counts do not sum to n."), distribution_util.assert_integer_form( counts, message="counts have non-integer components.")], counts)
def _verify_input(data, labels, probs_list): """Verify that batched inputs are well-formed.""" checked_probs_list = [] for probs in probs_list: # Probabilities must be able to be converted to non-object numpy array. np_probs = np.asarray(probs) if np_probs.dtype == np.dtype('object'): raise ValueError( 'Probabilities must be able to be converted to a numpy ' 'array.') checked_probs_list.append(np_probs) # Probabilities must sum to one. # TODO(joelshor): Investigate whether logits should be passed instead of # probs. if not np.isclose(np.sum(probs), 1.0): raise ValueError('Probabilities must sum to one.') # All probabilities should be the same length. if not np.array_equiv([probs.shape for probs in checked_probs_list], checked_probs_list[0].shape): raise ValueError('Probability parameters must have the same length.') # Labels tensor should only have batch dimension. labels.get_shape().assert_has_rank(1) # Data tensor should have a batch dimension. data_shape = data.get_shape().with_rank_at_least(1) # Data and label batch dimensions must be compatible. data_shape[0].assert_is_compatible_with(labels.get_shape()[0]) # Data and labels must have the same, strictly positive batch size. Since we # can't assume we know the batch size at graph creation, add runtime checks. data_batch_size = array_ops.shape(data)[0] labels_batch_size = array_ops.shape(labels)[0] data = control_flow_ops.with_dependencies([ check_ops.assert_positive(data_batch_size), check_ops.assert_equal(data_batch_size, labels_batch_size) ], data) # Label's classes must be integers 0 <= x < num_classes. labels = control_flow_ops.with_dependencies([ check_ops.assert_integer(labels), check_ops.assert_non_negative(labels), check_ops.assert_less(labels, math_ops.cast(len(probs), labels.dtype)) ], labels) return data, labels, checked_probs_list
def from_row_lengths(cls, row_lengths, name=None, validate=True, preferred_dtype=None): """Creates a `RowPartition` with rows partitioned by `row_lengths`. A `RaggedTensor` constructed with this corresponds with the python list defined by: ```python result = [[values.pop(0) for i in range(length)] for length in row_lengths] ``` Args: row_lengths: A 1-D integer tensor with shape `[nrows]`. Must be nonnegative. name: A name prefix for the RowPartition (optional). validate: If true, then use assertions to check that the arguments form a valid `RowPartition`. preferred_dtype: If row_lengths has an unspecified type, use this one. If preferred_dtype is None, defaults to dtypes.int64. Returns: A `RowPartition`. """ if not isinstance(validate, bool): raise TypeError("validate must have type bool") with ops.name_scope(name, "RowPartitionFromRowLengths", [row_lengths]): row_lengths = cls._convert_row_partition(row_lengths, "row_lengths", preferred_dtype) row_lengths.shape.assert_has_rank(1) if validate: msg = "Arguments to from_row_lengths do not form a valid RowPartition" checks = [ check_ops.assert_rank(row_lengths, 1, message=msg), check_ops.assert_non_negative(row_lengths, message=msg), ] row_lengths = control_flow_ops.with_dependencies( checks, row_lengths) row_limits = math_ops.cumsum(row_lengths) row_splits = array_ops.concat([[0], row_limits], axis=0) return cls(row_splits=row_splits, cached_row_lengths=row_lengths, internal=True)
def _verify_input(data, labels, probs_list): """Verify that batched inputs are well-formed.""" checked_probs_list = [] for probs in probs_list: # Probabilities must be able to be converted to non-object numpy array. np_probs = np.asarray(probs) if np_probs.dtype == np.dtype('object'): raise ValueError('Probabilities must be able to be converted to a numpy ' 'array.') checked_probs_list.append(np_probs) # Probabilities must sum to one. # TODO(joelshor): Investigate whether logits should be passed instead of # probs. if not np.isclose(np.sum(probs), 1.0): raise ValueError('Probabilities must sum to one.') # All probabilities should be the same length. if not np.array_equiv([probs.shape for probs in checked_probs_list], checked_probs_list[0].shape): raise ValueError('Probability parameters must have the same length.') # Labels tensor should only have batch dimension. labels.get_shape().assert_has_rank(1) # Data tensor should have a batch dimension. data_shape = data.get_shape().with_rank_at_least(1) # Data and label batch dimensions must be compatible. data_shape[0].assert_is_compatible_with(labels.get_shape()[0]) # Data and labels must have the same, strictly positive batch size. Since we # can't assume we know the batch size at graph creation, add runtime checks. data_batch_size = array_ops.shape(data)[0] labels_batch_size = array_ops.shape(labels)[0] data = control_flow_ops.with_dependencies( [check_ops.assert_positive(data_batch_size), check_ops.assert_equal(data_batch_size, labels_batch_size)], data) # Label's classes must be integers 0 <= x < num_classes. labels = control_flow_ops.with_dependencies( [check_ops.assert_integer(labels), check_ops.assert_non_negative(labels), check_ops.assert_less(labels, math_ops.cast(len(probs), labels.dtype))], labels) return data, labels, checked_probs_list
def _maybe_assert_valid_sample(self, counts): """Check counts for proper shape, values, then return tensor version.""" if not self.validate_args: return counts return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( counts, message="counts must be non-negative."), check_ops.assert_equal( self.total_count, math_ops.reduce_sum(counts, -1), message="counts last-dimension must sum to `self.total_count`"), distribution_util.assert_integer_form( counts, message="counts cannot contain fractional components."), ], counts)
def _assert_non_negative_int32_scalar(self, x): """Helper which ensures that input is a non-negative, int32, scalar.""" x = ops.convert_to_tensor(x, name="x") if x.dtype.base_dtype != dtypes.int32.base_dtype: raise TypeError("%s.dtype=%s is not %s" % (x.name, x.dtype, dtypes.int32)) x_value_static = tensor_util.constant_value(x) if x.get_shape().ndims is not None and x_value_static is not None: if x.get_shape().ndims != 0: raise ValueError("%s.ndims=%d is not 0 (scalar)" % (x.name, x.get_shape().ndims)) if x_value_static < 0: raise ValueError("%s.value=%d cannot be negative" % (x.name, x_value_static)) return x if self.validate_args: x = control_flow_ops.with_dependencies([check_ops.assert_rank(x, 0), check_ops.assert_non_negative(x)], x) return x
def _maybe_assert_valid_sample(self, counts): """Check counts for proper shape, values, then return tensor version.""" if not self.validate_args: return counts return control_flow_ops.with_dependencies([ check_ops.assert_non_negative( counts, message="counts must be non-negative."), check_ops.assert_equal( self.total_count, math_ops.reduce_sum(counts, -1), message="counts must sum to `self.total_count`"), distribution_util.assert_integer_form( counts, message="counts cannot contain fractional components."), ], counts)
def embed_check_nonnegative_integer_form( x, name="embed_check_nonnegative_integer_form"): """Assert x is a non-negative tensor, and optionally of integers.""" with ops.name_scope(name, values=[x]): x = ops.convert_to_tensor(x, name="x") assertions = [ check_ops.assert_non_negative( x, message="'{}' must be non-negative.".format(x.op.name)), ] if not x.dtype.is_integer: assertions += [ assert_integer_form( x, message="'{}' cannot contain fractional components.".format( x.op.name)), ] return control_flow_ops.with_dependencies(assertions, x)
def from_row_lengths(cls, row_lengths, validate=True, preferred_dtype=None): """Creates a `RowPartition` with rows partitioned by `row_lengths`. This `RowPartition` divides a sequence `values` into rows by indicating the length of each row: ```python partitioned_rows = [[values.pop(0) for _ in range(length)] for length in row_lengths] ``` Args: row_lengths: A 1-D integer tensor with shape `[nrows]`. Must be nonnegative. validate: If true, then use assertions to check that the arguments form a valid `RowPartition`. preferred_dtype: If row_lengths has an unspecified type, use this one. If preferred_dtype is None, defaults to dtypes.int64. Returns: A `RowPartition`. """ if not isinstance(validate, bool): raise TypeError("validate must have type bool") with ops.name_scope(None, "RowPartitionFromRowLengths", [row_lengths]): row_lengths = cls._convert_row_partition(row_lengths, "row_lengths", preferred_dtype) row_lengths.shape.assert_has_rank(1) if validate: msg = "Arguments to from_row_lengths do not form a valid RowPartition" checks = [ check_ops.assert_rank(row_lengths, 1, message=msg), check_ops.assert_non_negative(row_lengths, message=msg), ] row_lengths = control_flow_ops.with_dependencies( checks, row_lengths) row_limits = math_ops.cumsum(row_lengths) row_splits = array_ops.concat([[0], row_limits], axis=0) return cls(row_splits=row_splits, row_lengths=row_lengths, internal=_row_partition_factory_key)