Ejemplo n.º 1
0
    def test_assert_no_infs_or_nans_passthrough(self, value):
        """Checks that the assert is a passthrough when the flag is False."""
        vector_input = (value, )

        vector_output = asserts.assert_no_infs_or_nans(vector_input)

        self.assertIs(vector_input, vector_output)
Ejemplo n.º 2
0
    def test_assert_no_infs_or_nans_raises_exception_for_nan(self, value):
        """Checks that the assert works for `Inf` or `NaN` values."""
        vector_input = (value, )

        with self.assertRaisesRegex(  # pylint: disable=g-error-prone-assert-raises
                tf.errors.InvalidArgumentError, "Inf or NaN detected."):
            self.evaluate(asserts.assert_no_infs_or_nans(vector_input))
Ejemplo n.º 3
0
def safe_signed_div(a, b, eps=None, name='safe_signed_div'):
    """Calculates a/b safely.

  If the tf-graphics debug flag is set to `True`, this function adds assertions
  to the graph that check whether `abs(b + eps)` is greather than zero, and the
  division has no `NaN` or `Inf` values.

  Note:
    In the following, A1 to An are optional batch dimensions, which must be
    broadcast compatible.

  Args:
    a: A `float` or a tensor of shape `[A1, ..., An]`, which is the nominator.
    b: A `float` or a tensor of shape `[A1, ..., An]`, which is the denominator
      with non-negative values.
    eps: A small `float`, to be added to the denominator. If left `None`, its
      value is automatically selected using `b.dtype`.
    name: A name for this op. Defaults to 'safe_signed_div'.

  Raises:
     InvalidArgumentError: If tf-graphics debug flag is set and the division
       causes `NaN` or `Inf` values.

  Returns:
     A tensor of shape `[A1, ..., An]` containing the results of division.
  """
    with tf.name_scope(name):
        a = tf.convert_to_tensor(value=a)
        b = tf.convert_to_tensor(value=b)
        if eps is None:
            eps = asserts.select_eps_for_division(b.dtype)
        eps = tf.convert_to_tensor(value=eps, dtype=b.dtype)

        return asserts.assert_no_infs_or_nans(a / (b + nonzero_sign(b) * eps))
Ejemplo n.º 4
0
def safe_unsigned_div(a, b, eps=None, name='safe_unsigned_div'):
    """Calculates a/b with b >= 0 safely.

  If the tfg debug flag TFG_ADD_ASSERTS_TO_GRAPH defined in tfg_flags.py
  is set to True, this function adds assertions to the graph that check whether
  b + eps is greather than zero, and the division has no NaN or Inf values.

  Args:
    a: A `float` or a tensor of shape `[A1, ..., An]`, which is the nominator.
    b: A `float` or a tensor of shape `[A1, ..., An]`, which is the denominator.
    eps: A small `float`, to be added to the denominator. If left as `None`, its
      value is automatically selected using `b.dtype`.
    name: A name for this op. Defaults to 'safe_unsigned_div'.

  Raises:
     InvalidArgumentError: If tf-graphics debug flag is set and the division
       causes `NaN` or `Inf` values.

  Returns:
     A tensor of shape `[A1, ..., An]` containing the results of division.
  """
    with tf.name_scope(name):
        a = tf.convert_to_tensor(value=a)
        b = tf.convert_to_tensor(value=b)
        if eps is None:
            eps = asserts.select_eps_for_division(b.dtype)
        eps = tf.convert_to_tensor(value=eps, dtype=b.dtype)

        return asserts.assert_no_infs_or_nans(a / (b + eps))
Ejemplo n.º 5
0
    def test_assert_no_infs_or_nans_passthrough(self):
        """Checks that the assert is a passthrough when the flag is False."""
        vector_input = _pick_random_vector()

        vector_output = asserts.assert_no_infs_or_nans(vector_input)

        self.assertIs(vector_input, vector_output)
Ejemplo n.º 6
0
def build_matrices(image, size=3, eps=1e-5, name=None):
    """Generates the closed form matting Laplacian.

  Generates the closed form matting Laplacian as proposed by Levin et
  al. in "A Closed Form Solution to Natural Image Matting". This function also
  return the pseudo-inverse matrix allowing to retrieve the matting linear
  coefficient.

  Args:
    image: A tensor of shape `[B, H, W, C]`.
    size: An `int` representing the size of the patches used to enforce
      smoothness.
    eps: A small number of type `float` to regularize the problem.
    name: A name for this op. Defaults to "matting_build_matrices".

  Returns:
    A tensor of shape `[B, H - pad, W - pad, size^2, size^2]` containing
    the matting Laplacian matrices. A tensor of shape
    `[B, H - pad, W - pad, C + 1, size^2]` containing the pseudo-inverse
    matrices which can be used to retrieve the matting linear coefficients.
    The padding `pad` is equal to `size - 1`.

  Raises:
    ValueError: If `image` is not of rank 4.
  """
    with tf.compat.v1.name_scope(name, "matting_build_matrices", [image]):
        image = tf.convert_to_tensor(value=image)
        eps = tf.constant(value=eps, dtype=image.dtype)

        shape.check_static(image, has_rank=4)
        if size % 2 == 0:
            raise ValueError("The patch size is expected to be an odd value.")

        pixels = size**2
        channels = tf.shape(input=image)[-1]
        dtype = image.dtype
        # Extracts image patches.
        patches = _image_patches(image, size)
        batches = tf.shape(input=patches)[:-1]
        patches = tf.reshape(patches, shape=_shape(batches, pixels, channels))
        # Creates the data matrix block.
        ones = tf.ones(shape=_shape(batches, pixels, 1), dtype=dtype)
        affine = tf.concat((patches, ones), axis=-1)
        # Creates the regularizer matrix block.
        diag = tf.sqrt(eps) * tf.eye(
            channels, batch_shape=(1, 1, 1), dtype=dtype)
        zeros = tf.zeros(shape=_shape((1, 1, 1), channels, 1), dtype=dtype)
        regularizer = tf.concat((diag, zeros), axis=-1)
        regularizer = tf.tile(regularizer, multiples=_shape(batches, 1, 1))
        # Creates a matrix concatenating the data and regularizer blocks.
        mat = tf.concat((affine, regularizer), axis=-2)
        # Builds the pseudo inverse and the laplacian matrices.
        inverse = tf.linalg.inv(tf.matmul(mat, mat, transpose_a=True))
        inverse = asserts.assert_no_infs_or_nans(inverse)
        pseudo_inverse = tf.matmul(inverse, affine, transpose_b=True)
        identity = tf.eye(num_rows=pixels, dtype=dtype)
        laplacian = identity - tf.matmul(affine, pseudo_inverse)
        return laplacian, pseudo_inverse
Ejemplo n.º 7
0
def _laplacian_matrix(image,
                      size=3,
                      eps=1e-5,
                      name="matting_laplacian_matrix"):
    """Generates the closed form matting Laplacian matrices.

  Generates the closed form matting Laplacian as proposed by Levin et
  al. in "A Closed Form Solution to Natural Image Matting".

  Args:
    image: A tensor of shape `[B, H, W, C]`.
    size: An `int` representing the size of the patches used to enforce
      smoothness.
    eps: A small number of type `float` to regularize the problem.
    name: A name for this op. Defaults to "matting_laplacian_matrix".

  Returns:
    A tensor of shape `[B, H, W, size^2, size^2]` containing the
    matting Laplacian matrices.

  Raises:
    ValueError: If `image` is not of rank 4.
  """
    with tf.name_scope(name):
        image = tf.convert_to_tensor(value=image)

        shape.check_static(image, has_rank=4)
        if size % 2 == 0:
            raise ValueError("The patch size is expected to be an odd value.")

        pixels = size**2
        channels = tf.shape(input=image)[-1]
        dtype = image.dtype
        patches = tf.image.extract_patches(image,
                                           sizes=(1, size, size, 1),
                                           strides=(1, 1, 1, 1),
                                           rates=(1, 1, 1, 1),
                                           padding="VALID")
        batches = tf.shape(input=patches)[:-1]
        new_shape = tf.concat((batches, (pixels, channels)), axis=-1)
        patches = tf.reshape(patches, shape=new_shape)
        mean = tf.reduce_mean(input_tensor=patches, axis=-2, keepdims=True)
        demean = patches - mean
        covariance = tf.matmul(demean, demean, transpose_a=True) / pixels
        regularizer = (eps / pixels) * tf.eye(channels, dtype=dtype)
        covariance_inv = tf.linalg.inv(covariance + regularizer)
        covariance_inv = asserts.assert_no_infs_or_nans(covariance_inv)
        mat = tf.matmul(tf.matmul(demean, covariance_inv),
                        demean,
                        transpose_b=True)
        return tf.eye(pixels, dtype=dtype) - (1.0 + mat) / pixels
Ejemplo n.º 8
0
def safe_cospx_div_cosx(theta: type_alias.TensorLike,
                        factor: type_alias.TensorLike,
                        eps: Optional[type_alias.Float] = None,
                        name: str = 'safe_cospx_div_cosx') -> tf.Tensor:
    """Calculates cos(factor * theta)/cos(theta) safely.

  The term `cos(factor * theta)/cos(theta)` has periodic edge cases with
  division by zero problems, and also zero / zero, e.g. when factor is equal to
  1.0 and `theta` is `(n + 1/2)pi`. This function adds signed eps to the angles
  in both the nominator and the denominator to ensure safety, and returns the
  correct values in all edge cases.

  Note:
    In the following, A1 to An are optional batch dimensions, which must be
    broadcast compatible.

  Args:
    theta: A tensor of shape `[A1, ..., An]`, representing angles in radians.
    factor: A `float` or a tensor of shape `[A1, ..., An]`.
    eps: A `float`, used to perturb the angle. If left as `None`, its value is
      automatically determined from the `dtype` of `theta`.
    name: A name for this op. Defaults to 'safe_cospx_div_cosx'.

  Raises:
    InvalidArgumentError: If tf-graphics debug flag is set and division returns
      `NaN` or `Inf` values.

  Returns:
    A tensor of shape `[A1, ..., An]` containing the resulting values.
  """
    with tf.name_scope(name):
        theta = tf.convert_to_tensor(value=theta)
        factor = tf.convert_to_tensor(value=factor, dtype=theta.dtype)
        if eps is None:
            eps = asserts.select_eps_for_division(theta.dtype)
        eps = tf.convert_to_tensor(value=eps, dtype=theta.dtype)

        # eps will be multiplied with factor next, which can make it zero.
        # Therefore we multiply eps with min(1/factor, 1e10), which can handle
        # factors as small as 1e-10 correctly, while preventing a division by zero.
        eps *= tf.clip_by_value(1.0 / factor, 1.0, 1e10)
        sign = nonzero_sign(0.5 * np.pi - (theta - 0.5 * np.pi) % np.pi)
        theta += sign * eps
        div = tf.cos(factor * theta) / tf.cos(theta)
        return asserts.assert_no_infs_or_nans(div)
Ejemplo n.º 9
0
def safe_sinpx_div_sinx(theta, factor, eps=None, name='safe_sinpx_div_sinx'):
    """Calculates sin(factor * theta)/sin(theta) safely.

  The term `sin(factor * theta)/sin(theta)` appears when calculating spherical
  interpolation weights, and it has periodic edge cases causing both zero / zero
  and division by zero problems. This function adds signed eps to the angles in
  both the nominator and the denominator to ensure safety, and returns the
  correct values estimated by l'Hopital rule in the case of zero / zero.

  Note:
    In the following, A1 to An are optional batch dimensions, which must be
    broadcast compatible.

  Args:
    theta: A tensor of shape `[A1, ..., An]` representing angles in radians.
    factor: A `float` or a tensor of shape `[A1, ..., An]`.
    eps: A `float`, used to perturb the angle. If left as `None`, its value is
      automatically determined from the `dtype` of `theta`.
    name: A name for this op. Defaults to 'safe_sinpx_div_sinx'.

  Raises:
    InvalidArgumentError: If tf-graphics debug flag is set and the division
      returns `NaN` or `Inf` values.

  Returns:
    A tensor of shape `[A1, ..., An]` containing the resulting values.
  """
    with tf.name_scope(name):
        theta = tf.convert_to_tensor(value=theta)
        factor = tf.convert_to_tensor(value=factor, dtype=theta.dtype)
        if eps is None:
            eps = asserts.select_eps_for_division(theta.dtype)
        eps = tf.convert_to_tensor(value=eps, dtype=theta.dtype)

        # eps will be multiplied with factor next, which can make it zero.
        # Therefore we multiply eps with min(1/factor, 1e10), which can handle
        # factors as small as 1e-10 correctly, while preventing a division by zero.
        eps *= tf.clip_by_value(1.0 / factor, 1.0, 1e10)
        sign = nonzero_sign(0.5 * np.pi - theta % np.pi)
        theta += sign * eps
        div = tf.sin(factor * theta) / tf.sin(theta)
        return asserts.assert_no_infs_or_nans(div)
Ejemplo n.º 10
0
def laplacian_weights(image, size=3, eps=1e-5, name=None):
  """Generates the closed form matting Laplacian weights.

  Generates the closed form matting Laplacian weights as proposed by Levin et
  al. in "A Closed Form Solution to Natural Image Matting".

  Args:
    image: A tensor of shape `[B, H, W, C]`.
    size: An `int` representing the size of the patches used to enforce
      smoothness.
    eps: A small number of type `float` to regularize the problem.
    name: A name for this op. Defaults to "matting_laplacian_weights".

  Returns:
    A tensor of shape `[B, H, W, size^2, size^2]` containing the
    matting Laplacian weights .

  Raises:
    ValueError: If `image` is not of rank 4.
  """
  with tf.compat.v1.name_scope(name, "matting_laplacian_weights", [image]):
    image = tf.convert_to_tensor(value=image)

    shape.check_static(image, has_rank=4)

    pixels = size**2
    channels = tf.shape(input=image)[3]
    dtype = image.dtype
    patches = _image_patches(image, size)
    current_shape = tf.shape(input=patches)
    new_shape = tf.concat((current_shape[:-1], (pixels, channels)), axis=-1)
    patches = tf.reshape(patches, shape=new_shape)
    mean = tf.reduce_mean(input_tensor=patches, axis=-2, keepdims=True)
    demean = patches - mean
    covariance = tf.matmul(demean, demean, transpose_a=True) / pixels
    regularizer = (eps / pixels) * tf.eye(channels, dtype=dtype)
    covariance_inv = tf.linalg.inv(covariance + regularizer)
    covariance_inv = asserts.assert_no_infs_or_nans(covariance_inv)
    mat = _quadratic_form(covariance_inv, demean)
    return tf.eye(pixels, dtype=dtype) - (1.0 + mat) / pixels