示例#1
0
def sparse_put(sp_tensor, sp_updates, name="sparse_put"):
    """Changes a given SparseTensor according to the updates specified in a SparseTensor.

    Creates a new tensor where the values of the updates override the
    values in the original tensor. The input tensors must have the same
    ``dense_shape``.

    Args:
        sp_tensor: a ``SparseTensor`` we which to set some indices to given values
        sp_updates: a ``SparseTensor`` with the indices to be changed and the respective values
        name: name for this operation (optional)

    Returns:
        ``SparseTensor``: a ``SparseTensor`` with the updated values.
    """
    with ops.name_scope(name):
        if sp_updates.dtype != sp_tensor.dtype:
            sp_updates = math_ops.cast(sp_updates, sp_tensor.dtype)

        # 1 concat indices and establish final tensor shape
        update_shape = sp_updates.values.get_shape()
        zero_updates = SparseTensor(
            sp_updates.indices,
            array_ops.zeros(update_shape, dtype=dtypes.float32),
            sp_updates.dense_shape)
        proto_result = sp_ops.sparse_add(sp_tensor, zero_updates)

        # shape of resulting values tensor
        proto_shape = array_ops.shape(proto_result.values)

        # 2 get mask for input tensor
        proto_ones = SparseTensor(proto_result.indices,
                                  array_ops.ones(proto_shape, dtypes.int8),
                                  proto_result.dense_shape)

        # mask_ones = math_ops.scalar_mul(-1, array_ops.ones(update_shape))
        sp_mask = SparseTensor(
            sp_updates.indices,
            array_ops.constant(-1, dtypes.int8, update_shape),
            sp_updates.dense_shape)

        to_retain = sp_ops.sparse_add(proto_ones, sp_mask)
        to_retain = math_ops.not_equal(to_retain.values, 0)

        # get tensor with masked values
        tensor_masked = sp_ops.sparse_retain(proto_result, to_retain)

        # add values to entries previously set to 0
        new_tensor = sp_ops.sparse_add(tensor_masked, sp_updates)
        return new_tensor
示例#2
0
def to_sparse(tensor, name="to_sparse"):
    """ Returns a ``SparseTensor` for a`given dense ``Tensor``.

    Example:

        For a dense ``Tensor`` such as::

            tensor = [[1,0],
                      [2,3]]

        this returns an op that creates the following two ``SparseTensor``::

            SparseTensor(indices = [[0,0],[1,0],[1,1]],
                                    values = [1,2,3],
                                    dense_shape = [2,2])

    Args:
        tensor: a dense ``Tensor``
        name: name for this operation (optional)

    Returns:
        ``SparseTensor``: a sparse tensor with sparse index and value tensors
        with the non-zero entries of the given input.

    """
    with ops.name_scope(name):
        indices = array_ops.where(math_ops.not_equal(tensor, 0))
        dense_shape = array_ops.shape(tensor, out_type=dtypes.int64)

        values = array_ops.gather_nd(tensor, indices)
        sp_tensor = SparseTensor(indices, values, dense_shape)

    return sp_tensor
示例#3
0
def sparse_dropout(sp_tensor, keep_prob=0.2, seed=None, name="sparse_dropout"):
    """Performs a dropout on a ``SparseTensor``.

    With probability `keep_prob`, outputs the input element scaled up by
    `1 / keep_prob`, otherwise outputs `0`.  The scaling is so that the expected
    sum is unchanged.

    Args:
        sp_tensor: a ``SparseTensor`` on which the dropout is performed.
        keep_prob: A scalar `Tensor` with the same type as x. The probability
        that each element is kept.
        seed: A Python integer. Used to create random seeds. (See `TensorFlow` documentation
        for ``tf.set_random_seed`` for behavior.)
        name: A name for this operation (optional).

    """
    with ops.name_scope(name):
        dense_shape = sp_tensor.dense_shape

        drop_values = dropout(sp_tensor.values, keep_prob, seed=seed)
        not_zero = math_ops.not_equal(drop_values, 0)

        # new indices (after dropout)
        # not_zero_indices = array_ops.where(not_zero)
        # indices = array_ops.gather_nd(sp_indices.indices, not_zero_indices)

        values = array_ops.boolean_mask(drop_values, not_zero)
        indices = array_ops.boolean_mask(sp_tensor.indices, not_zero)

        new_tensor = SparseTensor(indices, values, dense_shape)
        return new_tensor
示例#4
0
def dense_put(tensor, sp_updates, name="dense_put"):
    """ Changes a given dense ``Tensor`` according to the updates specified in a ``SparseTensor``.

    Creates a new ``Tensor`` where the values of the updates override the
    values in the original tensor. The tensor `shape` must be the same as the updates `dense_shape`.

    Args:
        tensor: a ``Tensor`` we want to change.
        sp_updates: a ``SparseTensor`` with the indices to be changed and the respective values.
        name: the name for this operation (optional).

    Returns:
        ``Tensor``: a ``Tensor`` with the updated values.
    """
    with ops.name_scope(name):
        tensor = ops.convert_to_tensor(tensor)
        if sp_updates.dtype != tensor.dtype:
            sp_updates = math_ops.cast(sp_updates, tensor.dtype)

        markers = array_ops.ones(shape=array_ops.shape(sp_updates.values))
        sparse_marker_tensor = SparseTensor(indices=sp_updates.indices,
                                            values=markers,
                                            dense_shape=sp_updates.dense_shape)
        dense_update_marker = sp_ops.sparse_tensor_to_dense(
            sparse_marker_tensor)
        dense_updates = sp_ops.sparse_tensor_to_dense(sp_updates)

        new_tensor = array_ops.where(
            math_ops.not_equal(dense_update_marker, 0), dense_updates, tensor)
        return new_tensor
示例#5
0
    def __init__(self,
                 n_units,
                 batch_size=None,
                 dtype=dtypes.float32,
                 name="sparse_input"):
        """

        Args:
            n_units (int): the number of output units for this layer
            batch_size (int): batch_size for the input, helps to define the shape for this sparse layer
            dtype: the output type for the values in the ``SparseTensor`` that this layer outputs
            name: name for the layer
        """
        shape = [batch_size, n_units]
        super().__init__(None, n_units, shape, dtype, name)

        with ops.name_scope(name):
            self.placeholder = array_ops.sparse_placeholder(
                dtype, self.shape, name)
            n_indices = array_ops.shape(self.placeholder.indices)[0]
            n_values = array_ops.shape(self.placeholder.values)[0]

            valid_values = check_ops.assert_equal(
                n_indices, n_values, message="Invalid number of values")
            with ops.control_dependencies([valid_values]):
                values = array_ops.identity(self.placeholder.values)

            self.tensor = SparseTensor(self.placeholder.indices, values,
                                       self.placeholder.dense_shape)
示例#6
0
def sp_indices_from_sp_tensor(sp_values):
    """ Returns the a ``SparseTensor`` with the indices for the active values on a given ``SparseTensor`` .

    Use Case:
        To be used with ``embedding_lookup_sparse`` when we need two ``SparseTensor`` : one with the indices and
        one with the values.

    Args:
        sp_values: a ``SparseTensor`` for which we extract the active indices.

    Returns:
        ``SparseTensor``: a ``SparseTensor`` with the indices of the active elements of another ``SparseTensor`` .
    """
    _, flat_indices = array_ops.unstack(sp_values.indices, num=2, axis=-1)
    return SparseTensor(sp_values.indices, flat_indices, sp_values.dense_shape)
示例#7
0
def sparse_ones(indices, dense_shape, dtype=dtypes.float32):
    """ Creates a new ``SparseTensor`` where the values are 1

    Args:
        indices: a 2-D ``Tensor`` with the indices for the resulting sparse tensor
        dense_shape: the ``SparseTensor`` dense shape
        dtype: the tensor type for the values

    Returns:
        ``SparseTensor``: a new SparseTensor with the values set to 1.
    """
    indices = to_tensor_cast(indices, dtypes.int64)
    dense_shape = to_tensor_cast(dense_shape, dtypes.int64)
    indices_shape = complete_shape(indices)
    values = array_ops.ones([indices_shape[0]], dtype)
    return SparseTensor(indices, values, dense_shape)
示例#8
0
def sparse_random_normal(dense_shape,
                         density=0.1,
                         mean=0.0,
                         stddev=1,
                         dtype=dtypes.float32,
                         seed=None):
    """ Creates a NxM `SparseTensor` with `density` * NXM non-zero entries

    The values for the sparse tensor come from a random normal distribution.

    Args:
        dense_shape: a list of integers, a tuple of integers
        density: the proportion of non-zero entries, 1 means that all the entries have a value sampled from a
        random normal distribution.

        mean: normal distribution mean
        stddev: normal distribution standard deviation
        seed: the seed used for the random number generator
        seed: the seed used for the random number generator
    Returns:
        A `SparseTensor` with a given density with values sampled from the normal distribution
    """
    num_noise = int(density * dense_shape[1])

    if num_noise == 0:
        return empty_sparse_tensor(dense_shape)
    else:
        flat_indices = sample(range_max=dense_shape[1],
                              num_sampled=num_noise,
                              batch_size=dense_shape[0],
                              unique=True,
                              seed=seed)
        indices = batch_to_matrix_indices(flat_indices, dtype=dtypes.int64)

        value_shape = tensor_shape.as_shape([dense_shape[0] * num_noise])

        values = random_ops.random_normal(shape=value_shape,
                                          mean=mean,
                                          stddev=stddev,
                                          dtype=dtype,
                                          seed=seed)

        # dense_shape = tensor_shape.as_shape(dense_shape)
        sp_tensor = SparseTensor(indices, values, dense_shape)
        sp_tensor = sparse_ops.sparse_reorder(sp_tensor)
        return sp_tensor
示例#9
0
def empty_sparse_tensor(dense_shape,
                        dtype=dtypes.float32,
                        name="empty_sp_tensor"):
    """ Creates an empty SparseTensor.

    Note:
        ``shape = [10]``

        ``empty = tf.sparse_tensor_to_dense(transform.empty_sparse_tensor(shape))``

        is equivalent to:

        ``zero = tf.zeros(shape)``

       meaning that:

       ``tf.reduce_all(tf.equal(zeros,empty)).eval()``

       returns True


    Args:
        dense_shape: a 1-D tensor, python list, or numpy array with the output shape for the sparse tensor
        dtype: the dtype of the values for the empty SparseTensor
        name: a name for this operation (optional)

    Returns:
        ``SparseTensor``: an empty sparse tensor with a given shape

    """
    with ops.name_scope(name):
        dense_shape = ops.convert_to_tensor(dense_shape,
                                            name="dense_shape",
                                            dtype=dtypes.int64)

        index_shape = dense_shape.get_shape().with_rank(1)
        empty_indices = array_ops.ones([0, index_shape[0]], dtype=dtypes.int64)
        empty_values = array_ops.ones([0], dtype=dtype)

        return SparseTensor(empty_indices, empty_values, dense_shape)
示例#10
0
def sparse_random_mask(dense_shape,
                       density=0.5,
                       mask_values=[1],
                       symmetrical=True,
                       dtype=dtypes.float32,
                       seed=None):
    """Uses values to create a sparse random mask according to a given density
    a density of 0 returns an empty sparse tensor

    Note:
        if symmetrical the mask has always the same number of mask_values per row
        which means that if ``density * dense_shape[1] < len(mask_values)``, the mask will be an empty ``SparseTensor``.
        It also means that if ``dense_shape[1] % len(mask_values) != 0`` and ``density = 1.0``, not all values will be
        corrupted because we can't fill every entry with a symmetrical mask.

        There are other ways to fill a dense tensor with random values though so a density of 1 defeats the purpose of
        this operation.

        if not symmetrical the number of mask_values will not be the same per row. If we need to fill 2 extra entries
        with values 2 masked values are picked at random to fill the excess.

    Example:
        if **not** symmetrical and

        ``shape = [1,10]]``
        ``density = 0.5``
        ``mask_values = [1,2,3]``

        the result could be something like::

            [[1. 1.  2.  3.  0.  0.  0.  2.  0.  0.]]

    Args:
        seed: int32 to te used as seed
        dtype: tensor tensor value type
        dense_shape: a 1-D tensor tensor with shape [2]
        density: desired density
        mask_values: the values to be used to generate the random mask


    Returns:
        A sparse random mask with a density of the original shape corrupted using the mask values
    """
    # total number of corrupted indices
    num_values = len(mask_values)
    num_corrupted = int(density * dense_shape[1])
    num_mask_values = num_corrupted // num_values * num_values

    if num_mask_values == 0:
        return empty_sparse_tensor(dense_shape)
    else:
        # num corrupted indices per value
        if not symmetrical:
            mask_values = random_ops.random_shuffle(mask_values, seed)
            extra_corrupted = num_corrupted - num_mask_values

        if not symmetrical:
            num_mask_values = num_corrupted

        samples = sample(dense_shape[1],
                         num_mask_values,
                         dense_shape[0],
                         unique=True,
                         seed=seed)
        indices = batch_to_matrix_indices(samples, dtype=dtypes.int64)

        value_tensors = []
        for i in range(num_values):
            num_vi = num_mask_values // num_values
            # spread the extra to be corrupted by n mask_values
            if not symmetrical and i < extra_corrupted:
                num_vi = num_vi + 1
            vi_shape = math_ops.cast([dense_shape[0], num_vi], dtypes.int32)
            vi_tensor = array_ops.fill(vi_shape, mask_values[i])
            value_tensors.append(vi_tensor)

        values = array_ops.concat(value_tensors, axis=-1)
        values = array_ops.reshape(values, [-1])

        if values.dtype != dtype:
            values = math_ops.cast(values, dtype)

        dense_shape = math_ops.cast([dense_shape[0], dense_shape[1]],
                                    dtypes.int64)
        sp_tensor = SparseTensor(indices, values, dense_shape)
        # the indices were generated at random so
        sp_tensor = sparse_ops.sparse_reorder(sp_tensor)

        return sp_tensor