Exemplo n.º 1
0
def range(start, limit, delta=1, name="range"):
    """Creates a sequence of integers.

  This operation creates a sequence of integers that begins at `start` and
  extends by increments of `delta` up to but not including `limit`.

  For example:

  ```
  # 'start' is 3
  # 'limit' is 18
  # 'delta' is 3
  tf.range(start, limit, delta) ==> [3, 6, 9, 12, 15]
  ```

  Args:
    start: A 0-D (scalar) of type `int32`. First entry in sequence.
    limit: A 0-D (scalar) of type `int32`. Upper limit of sequence,
      exclusive.
    delta: A 0-D `Tensor` (scalar) of type `int32`. Optional. Default is 1.
      Number that increments `start`.
    name: A name for the operation (optional).

  Returns:
    An 1-D `int32` `Tensor`.
  """
    return gen_math_ops._range(start, limit, delta, name=name)
Exemplo n.º 2
0
def range(start, limit, delta=1, name="range"):
  """Creates a sequence of integers.

  This operation creates a sequence of integers that begins at `start` and
  extends by increments of `delta` up to but not including `limit`.

  For example:

  ```
  # 'start' is 3
  # 'limit' is 18
  # 'delta' is 3
  tf.range(start, limit, delta) ==> [3, 6, 9, 12, 15]
  ```

  Args:
    start: A 0-D (scalar) of type `int32`. First entry in sequence.
    limit: A 0-D (scalar) of type `int32`. Upper limit of sequence,
      exclusive.
    delta: A 0-D `Tensor` (scalar) of type `int32`. Optional. Default is 1.
      Number that increments `start`.
    name: A name for the operation (optional).

  Returns:
    An 1-D `int32` `Tensor`.
  """
  return gen_math_ops._range(start, limit, delta, name=name)
Exemplo n.º 3
0
    def call(self, inputs, state):
        add = math_ops.add
        sub = math_ops.subtract
        mult = math_ops.multiply

        # computing m_t
        m_t = add(math_ops.matmul(state, self._u),
                  math_ops.matmul(inputs, self._v))
        m_t = nn_ops.bias_add(m_t, self._b)
        m_t = math_ops.sigmoid(m_t)

        # add L1 loss
        ops.add_to_collection('L1 loss', math_ops.abs(m_t - self._m_target))

        # computing e_t (= thr)
        i = gen_math_ops._range(1, self._num_units + 1, 1)
        i = math_ops.cast(i, dtype=dtypes.float32)
        mtD = gen_array_ops.tile(mult(m_t[1], self._num_units),
                                 [self._num_units])
        thr = math_ops.sigmoid(mult(self._sharpness, sub(mtD, i)))
        thr = math_ops.round(add(thr, sub(0.5, self._epsilon)))
        ones = array_ops.ones_like(thr)
        thr_inv = sub(ones, thr)

        # computing h_t
        gate_inputs = math_ops.matmul(array_ops.concat([inputs, state], 1),
                                      self._kernel)
        gate_inputs = nn_ops.bias_add(gate_inputs, self._bias)
        output = self._activation(gate_inputs)
        output = add(mult(gate_inputs, thr), mult(state, thr_inv))

        return output, output
Exemplo n.º 4
0
def batch_gather(params, indices, name=None):
  """Gather slices from `params` according to `indices` with leading batch dims.
  This operation assumes that the leading dimensions of `indices` are dense,
  and the gathers on the axis corresponding to the last dimension of `indices`.
  More concretely it computes:
  result[i1, ..., in] = params[i1, ..., in-1, indices[i1, ..., in]]
  Therefore `params` should be a Tensor of shape [A1, ..., AN, B1, ..., BM],
  `indices` should be a Tensor of shape [A1, ..., AN-1, C] and `result` will be
  a Tensor of size `[A1, ..., AN-1, C, B1, ..., BM]`.
  In the case in which indices is a 1D tensor, this operation is equivalent to
  `tf.gather`.
  See also `tf.gather` and `tf.gather_nd`.
  Args:
    params: A Tensor. The tensor from which to gather values.
    indices: A Tensor. Must be one of the following types: int32, int64. Index
        tensor. Must be in range `[0, params.shape[axis]`, where `axis` is the
        last dimension of `indices` itself.
    name: A name for the operation (optional).
  Returns:
    A Tensor. Has the same type as `params`.
  Raises:
    ValueError: if `indices` has an unknown shape.
  """

  with ops.name_scope(name):
    indices = ops.convert_to_tensor(indices, name="indices")
    params = ops.convert_to_tensor(params, name="params")
    indices_shape = tf.shape(indices)
    params_shape = tf.shape(params)
    ndims = indices.shape.ndims
    if ndims is None:
      raise ValueError("batch_gather does not allow indices with unknown "
                       "shape.")
    batch_indices = indices
    accum_dim_value = 1
    for dim in range(ndims-1, 0, -1):
      dim_value = params_shape[dim-1]
      accum_dim_value *= params_shape[dim]
      dim_indices = gen_math_ops._range(0, dim_value, 1)
      dim_indices *= accum_dim_value
      dim_shape = tf.stack([1] * (dim - 1) + [dim_value] + [1] * (ndims - dim),
                        axis=0)
      batch_indices += tf.cast(tf.reshape(dim_indices, dim_shape), tf.int64)

    flat_indices = tf.reshape(batch_indices, [-1])
    outer_shape = params_shape[ndims:]
    flat_inner_shape = gen_math_ops.prod(
        params_shape[:ndims], [0], False)

    flat_params = tf.reshape(
        params, tf.concat([[flat_inner_shape], outer_shape], axis=0))
    flat_result = tf.gather(flat_params, flat_indices)
    result = tf.reshape(flat_result, tf.concat([indices_shape, outer_shape], axis=0))
    final_shape = indices.get_shape()[:ndims-1].merge_with(
        params.get_shape()[:ndims -1])
    final_shape = final_shape.concatenate(indices.get_shape()[ndims-1])
    final_shape = final_shape.concatenate(params.get_shape()[ndims:])
    result.set_shape(final_shape)
    return result
Exemplo n.º 5
0
def transpose(a, perm=None, name="transpose"):
  """Transposes `a`. Permutes the dimensions according to `perm`.

  The returned tensor's dimension i will correspond to the input dimension
  `perm[i]`. If `perm` is not given, it is set to (n-1...0), where n is
  the rank of the input tensor. Hence by default, this operation performs a
  regular matrix transpose on 2-D input Tensors.

  For example:

  ```python
  # 'x' is [[1 2 3]
  #         [4 5 6]]
  tf.transpose(x) ==> [[1 4]
                       [2 5]
                       [3 6]]

  # Equivalently
  tf.transpose(x, perm=[1, 0]) ==> [[1 4]
                                    [2 5]
                                    [3 6]]

  # 'perm' is more useful for n-dimensional tensors, for n > 2
  # 'x' is   [[[1  2  3]
  #            [4  5  6]]
  #           [[7  8  9]
  #            [10 11 12]]]
  # Take the transpose of the matrices in dimension-0
  tf.transpose(b, perm=[0, 2, 1]) ==> [[[1  4]
                                        [2  5]
                                        [3  6]]

                                       [[7 10]
                                        [8 11]
                                        [9 12]]]
  ```

  Args:
    a: A `Tensor`.
    perm: A permutation of the dimensions of `a`.
    name: A name for the operation (optional).

  Returns:
    A transposed `Tensor`.
  """
  with ops.op_scope([a], name, "transpose") as name:
    if perm is None:
      dims = gen_math_ops._range(0, gen_array_ops.rank(a), 1)
      perm = gen_array_ops.reverse(dims, [True])
      ret = gen_array_ops.transpose(a, perm, name=name)
      # NOTE(mrry): Setting the shape explicitly because
      #   reverse is not handled by the shape function.
      input_shape = ret.op.inputs[0].get_shape().dims
      if input_shape is not None:
        ret.set_shape(input_shape[::-1])
    else:
      ret = gen_array_ops.transpose(a, perm, name=name)
    return ret
Exemplo n.º 6
0
def transpose(a, perm=None, name="transpose"):
  """Transposes `a`. Permutes the dimensions according to `perm`.

  The returned tensor's dimension i will correspond to the input dimension
  `perm[i]`. If `perm` is not given, it is set to (n-1...0), where n is
  the rank of the input tensor. Hence by default, this operation performs a
  regular matrix transpose on 2-D input Tensors.

  For example:

  ```python
  # 'x' is [[1 2 3]
  #         [4 5 6]]
  tf.transpose(x) ==> [[1 4]
                       [2 5]
                       [3 6]]

  # Equivalently
  tf.transpose(x, perm=[1, 0]) ==> [[1 4]
                                    [2 5]
                                    [3 6]]

  # 'perm' is more useful for n-dimensional tensors, for n > 2
  # 'x' is   [[[1  2  3]
  #            [4  5  6]]
  #           [[7  8  9]
  #            [10 11 12]]]
  # Take the transpose of the matrices in dimension-0
  tf.transpose(b, perm=[0, 2, 1]) ==> [[[1  4]
                                        [2  5]
                                        [3  6]]

                                       [[7 10]
                                        [8 11]
                                        [9 12]]]
  ```

  Args:
    a: A `Tensor`.
    perm: A permutation of the dimensions of `a`.
    name: A name for the operation (optional).

  Returns:
    A transposed `Tensor`.
  """
  with ops.op_scope([a], name, "transpose") as name:
    if perm is None:
      dims = gen_math_ops._range(0, gen_array_ops.rank(a), 1)
      perm = gen_array_ops.reverse(dims, [True])
      ret = gen_array_ops.transpose(a, perm, name=name)
      # NOTE(mrry): Setting the shape explicitly because
      #   reverse is not handled by the shape function.
      input_shape = ret.op.inputs[0].get_shape().dims
      if input_shape is not None:
        ret.set_shape(input_shape[::-1])
    else:
      ret = gen_array_ops.transpose(a, perm, name=name)
    return ret
Exemplo n.º 7
0
def sequence_mask_mid(lengths, maxlen=None, dtype=dtypes.bool, name=None):
    """Return a mask tensor representing the first N positions of each row.

    Example:

    ```python
    tf.sequence_mask([1, 3, 2], 5) =
      [[True, False, False, False, False],
       [False,False, False, False, False],
       [False, True, False, False, False]]
    ```

    Args:
      lengths: 1D integer tensor, all its values < maxlen.
      maxlen: scalar integer tensor, maximum length of each row. Default: use
              maximum over lengths.
      dtype: output type of the resulting tensor.
      name: name of the op.
    Returns:
      A 2D mask tensor, as shown in the example above, cast to specified dtype.

    Raises:
      ValueError: if the arguments have invalid rank.
    """
    with ops.name_scope(name, "SequenceMask", [lengths, maxlen]):
        lengths = (np.array(lengths)) / 2
        lengths = ops.convert_to_tensor(lengths, dtype=tf.int32)
        # lengths = ops.convert_to_tensor(lengths)
        if lengths.get_shape().ndims != 1:
            raise ValueError("lengths must be 1D for sequence_mask")

        if maxlen is None:
            maxlen = gen_math_ops._max(lengths, [0])
        else:
            maxlen = ops.convert_to_tensor(maxlen)
        if maxlen.get_shape().ndims != 0:
            raise ValueError("maxlen must be scalar for sequence_mask")

        # The basic idea is to compare a range row vector of size maxlen:
        # [0, 1, 2, 3, 4]
        # to length as a matrix with 1 column: [[1], [3], [2]].
        # Because of broadcasting on both arguments this comparison results
        # in a matrix of size (len(lengths), maxlen)
        row_vector = gen_math_ops._range(constant(0, maxlen.dtype), maxlen,
                                         constant(1, maxlen.dtype))
        # Since maxlen >= max(lengths), it is safe to use maxlen as a cast
        # authoritative type. Whenever maxlen fits into tf.int32, so do the lengths.
        matrix_0 = gen_math_ops.cast(expand_dims(lengths, 1), maxlen.dtype)
        matrix_1 = gen_math_ops.cast(expand_dims(lengths - 1, 1), maxlen.dtype)
        result_0 = (row_vector < matrix_0)
        result_1 = (row_vector >= matrix_1)
        result = tf.logical_and(result_0, result_1)

        if dtype is None or result.dtype.base_dtype == dtype.base_dtype:
            return result
        else:
            return gen_math_ops.cast(result, dtype)
Exemplo n.º 8
0
def sequence_mask(lengths, maxlen=None, dtype=dtypes.bool, name=None):
    """Returns a mask tensor representing the first N positions of each cell.
	If `lengths` has shape `[d_1, d_2, ..., d_n]` the resulting tensor `mask` has
	dtype `dtype` and shape `[d_1, d_2, ..., d_n, maxlen]`, with
	```
	mask[i_1, i_2, ..., i_n, j] = (j < lengths[i_1, i_2, ..., i_n])
	```
	Examples:
	```python
	tf.sequence_mask([1, 3, 2], 5)  # [[True, False, False, False, False],
																	#  [True, True, True, False, False],
																	#  [True, True, False, False, False]]
	tf.sequence_mask([[1, 3],[2,0]])  # [[[True, False, False],
																		#   [True, True, True]],
																		#  [[True, True, False],
																		#   [False, False, False]]]
	```
	Args:
		lengths: integer tensor, all its values <= maxlen.
		maxlen: scalar integer tensor, size of last dimension of returned tensor.
			Default is the maximum value in `lengths`.
		dtype: output type of the resulting tensor.
		name: name of the op.
	Returns:
		A mask tensor of shape `lengths.shape + (maxlen,)`, cast to specified dtype.
	Raises:
		ValueError: if `maxlen` is not a scalar.
	"""
    with ops.name_scope(name, "SequenceMask", [lengths, maxlen]):
        lengths = ops.convert_to_tensor(lengths)

        if maxlen is None:
            maxlen = gen_math_ops._max(lengths, _all_dimensions(lengths))
            maxlen = gen_math_ops.maximum(constant(0, maxlen.dtype), maxlen)
        else:
            maxlen = ops.convert_to_tensor(maxlen)
        if maxlen.get_shape(
        ).ndims is not None and maxlen.get_shape().ndims != 0:
            raise ValueError("maxlen must be scalar for sequence_mask")

        # The basic idea is to compare a range row vector of size maxlen:
        # [0, 1, 2, 3, 4]
        # to length as a matrix with 1 column: [[1], [3], [2]].
        # Because of broadcasting on both arguments this comparison results
        # in a matrix of size (len(lengths), maxlen)
        row_vector = gen_math_ops._range(constant(0, maxlen.dtype), maxlen,
                                         constant(1, maxlen.dtype))
        # Since maxlen >= max(lengths), it is safe to use maxlen as a cast
        # authoritative type. Whenever maxlen fits into tf.int32, so do the lengths.
        matrix = gen_math_ops.cast(expand_dims(lengths, -1), maxlen.dtype)
        result = row_vector < matrix

        if dtype is None or result.dtype.base_dtype == dtype.base_dtype:
            return result
        else:
            return gen_math_ops.cast(result, dtype)
Exemplo n.º 9
0
def _all_dimensions(x):
  """Returns a 1D-tensor listing all dimensions in x."""
  # Fast path: avoid creating Rank and Range ops if ndims is known.
  if isinstance(x, ops.Tensor) and x.get_shape().ndims is not None:
    return constant_op.constant(
        np.arange(x.get_shape().ndims), dtype=dtypes.int32)
  if (isinstance(x, sparse_tensor.SparseTensor) and
      x.dense_shape.get_shape().is_fully_defined()):
    r = x.dense_shape.get_shape().dims[0].value  # sparse.dense_shape is 1-D.
    return constant_op.constant(np.arange(r), dtype=dtypes.int32)

  # Otherwise, we rely on `range` and `rank` to do the right thing at runtime.
  return gen_math_ops._range(0, rank(x), 1)
Exemplo n.º 10
0
def transpose(a, perm=None, name="transpose", conjugate=False):
    with ops.name_scope(name, "transpose", [a]) as name:
        transpose_fn = (gen_array_ops.conjugate_transpose if
                        (conjugate
                         and a.dtype.is_complex) else gen_array_ops.transpose)
        if perm is None:
            rank = gen_array_ops.rank(a)
            perm = (rank - 1) - gen_math_ops._range(0, rank, 1)
            ret = transpose_fn(a, perm, name=name)
            if not context.executing_eagerly():
                input_shape = ret.op.inputs[0].get_shape().dims
                if input_shape is not None:
                    ret.set_shape(input_shape[::-1])
        else:
            ret = transpose_fn(a, perm, name=name)
        return ret
Exemplo n.º 11
0
def batch_scatter(indices, updates, shape, name=None):
    with ops.name_scope(name):
        indices = ops.convert_to_tensor(indices, name="indices")
        indices_shape = array_ops.shape(indices)
        indices_dimensions = indices.get_shape().ndims

        if indices_dimensions is None:
            raise ValueError(
                "batch_gather does not allow indices with unknown "
                "shape.")

        nd_indices = array_ops.expand_dims(indices, axis=-1)
        nd_indices_list = []

        # Scatter ND requires indices to have an additional dimension, in which the
        # coordinates of the updated things are specified. For this to be adapted to
        # the scatter_update with several leading dimensions, we simply make use of
        # a tf.range for all the leading dimensions followed by concat of all the
        # coordinates we created with the original indices.

        # For example if indices.shape = [2, 3], we should generate the following
        # indices for tf.scatter_nd_update:
        # nd_indices[:, :, 0] = [[0, 0, 0], [1, 1, 1]]
        # nd_indices[:, :, 1] = [[0, 1, 2], [0, 1, 2]]
        # nd_indices[:, :, 2] = indices
        for dimension in range(indices_dimensions - 1):
            # In this loop we generate the following for the example (one for each
            # iteration).
            # nd_indices[:, :, 0] = [[0, 0, 0], [1, 1, 1]]
            # nd_indices[:, :, 1] = [[0, 1, 2], [0, 1, 2]]
            # This is done at every iteration with a tf.range over the size of the
            # i-th dimension and using broadcasting over the desired shape.
            dimension_size = indices_shape[dimension]
            shape_to_broadcast = [1] * (indices_dimensions + 1)
            shape_to_broadcast[dimension] = dimension_size
            dimension_range = array_ops.reshape(
                gen_math_ops._range(0, dimension_size, 1), shape_to_broadcast)
            if dimension_range.dtype.base_dtype != nd_indices.dtype:
                dimension_range = gen_math_ops.cast(dimension_range,
                                                    nd_indices.dtype)
            nd_indices_list.append(dimension_range *
                                   array_ops.ones_like(nd_indices))
        # Add the original indices at the end, as described above, and concat.
        nd_indices_list.append(nd_indices)
        final_indices = array_ops.concat(nd_indices_list, axis=-1)
        return tf.scatter_nd(final_indices, updates, shape)
Exemplo n.º 12
0
def range(start, limit=None, delta=1, name="range"):
  """Creates a sequence of integers.

  Creates a sequence of integers that begins at `start` and extends by
  increments of `delta` up to but not including `limit`.

  Like the Python builtin `range`, `start` defaults to 0, so that
  `range(n) = range(0, n)`.

  For example:

  ```
  # 'start' is 3
  # 'limit' is 18
  # 'delta' is 3
  tf.range(start, limit, delta) ==> [3, 6, 9, 12, 15]

  # 'limit' is 5
  tf.range(limit) ==> [0, 1, 2, 3, 4]
  ```

  Args:
    start: A 0-D (scalar) of type `int32`. First entry in sequence.
      Defaults to 0.
    limit: A 0-D (scalar) of type `int32`. Upper limit of sequence,
      exclusive.
    delta: A 0-D `Tensor` (scalar) of type `int32`. Optional. Default is 1.
      Number that increments `start`.
    name: A name for the operation (optional).

  Returns:
    An 1-D `int32` `Tensor`.
  """
  if limit is None:
    start, limit = 0, start
  return gen_math_ops._range(start, limit, delta, name=name)
Exemplo n.º 13
0
def batch_scatter_update(ref, indices, updates, use_locking=True, name=None):
    """Generalization of `tf.scatter_update` to axis different than 0.

  Analogous to `batch_gather`. This assumes that `ref`, `indices` and `updates`
  have a series of leading dimensions that are the same for all of them, and the
  updates are performed on the last dimension of indices. In other words, the
  dimensions should be the following:

  `num_prefix_dims = indices.ndims - 1`
  `batch_dim = num_prefix_dims + 1`
  `updates.shape = indices.shape + var.shape[batch_dim:]`

  where

  `updates.shape[:num_prefix_dims]`
  `== indices.shape[:num_prefix_dims]`
  `== var.shape[:num_prefix_dims]`

  And the operation performed can be expressed as:

  `var[i_1, ..., i_n, indices[i_1, ..., i_n, j]] = updates[i_1, ..., i_n, j]`

  When indices is a 1D tensor, this operation is equivalent to
  `tf.scatter_update`.

  To avoid this operation there would be 2 alternatives:
  1) Reshaping the variable by merging the first `ndims` dimensions. However,
     this is not possible because `tf.reshape` returns a Tensor, which we
     cannot use `tf.scatter_update` on.
  2) Looping over the first `ndims` of the variable and using
     `tf.scatter_update` on the subtensors that result of slicing the first
     dimension. This is a valid option for `ndims = 1`, but less efficient than
     this implementation.

  See also `tf.scatter_update` and `tf.scatter_nd_update`.

  Args:
    ref: `Variable` to scatter onto.
    indices: Tensor containing indices as described above.
    updates: Tensor of updates to apply to `ref`.
    use_locking: Boolean indicating whether to lock the writing operation.
    name: Optional scope name string.

  Returns:
    Ref to `variable` after it has been modified.

  Raises:
    ValueError: If the initial `ndims` of `ref`, `indices`, and `updates` are
        not the same.
  """
    with ops.name_scope(name):
        indices = ops.convert_to_tensor(indices, name="indices")
        indices_shape = array_ops.shape(indices)
        indices_dimensions = indices.get_shape().ndims

        if indices_dimensions is None:
            raise ValueError(
                "batch_gather does not allow indices with unknown "
                "shape.")

        nd_indices = array_ops.expand_dims(indices, axis=-1)
        nd_indices_list = []

        # Scatter ND requires indices to have an additional dimension, in which the
        # coordinates of the updated things are specified. For this to be adapted to
        # the scatter_update with several leading dimensions, we simply make use of
        # a tf.range for all the leading dimensions followed by concat of all the
        # coordinates we created with the original indices.

        # For example if indices.shape = [2, 3, 4], we should generate the following
        # indices for tf.scatter_nd_update:
        # nd_indices[:, :, 0] = [[0, 0, 0], [1, 1, 1]]
        # nd_indices[:, :, 1] = [[0, 1, 2], [0, 1, 2]]
        # nd_indices[:, :, 2] = indices
        for dimension in range(indices_dimensions - 1):
            # In this loop we generate the following for the example (one for each
            # iteration).
            # nd_indices[:, :, 0] = [[0, 0, 0], [1, 1, 1]]
            # nd_indices[:, :, 1] = [[0, 1, 2], [0, 1, 2]]
            # This is done at every iteration with a tf.range over the size of the
            # i-th dimension and using broadcasting over the desired shape.
            dimension_size = indices_shape[dimension]
            shape_to_broadcast = [1] * (indices_dimensions + 1)
            shape_to_broadcast[dimension] = dimension_size
            dimension_range = array_ops.reshape(
                gen_math_ops._range(0, dimension_size, 1), shape_to_broadcast)
            if dimension_range.dtype.base_dtype != nd_indices.dtype:
                dimension_range = gen_math_ops.cast(dimension_range,
                                                    nd_indices.dtype)
            nd_indices_list.append(dimension_range *
                                   array_ops.ones_like(nd_indices))
        # Add the original indices at the end, as described above, and concat.
        nd_indices_list.append(nd_indices)
        final_indices = array_ops.concat(nd_indices_list, axis=-1)
        return scatter_nd_update(ref,
                                 final_indices,
                                 updates,
                                 use_locking=use_locking)
Exemplo n.º 14
0
def batch_gather(params, indices, axis, name=None):
    """
    Extension of the batch_gather function in tensorflow
    (see https://github.com/tensorflow/tensorflow/blob/r1.13/tensorflow/python/ops/array_ops.py
    or https://www.tensorflow.org/api_docs/python/tf/batch_gather)
    Gather slices from `params` according to `indices` with leading batch dims.
    This operation assumes that the leading dimensions of `indices` are dense,
    and the gathers on the axis corresponding to the last dimension of `indices`.
    More concretely it computes:
    `result[i1, ..., in, j1, ..., jm, k1, ...., kl] = params[i1, ..., in, indices[i1, ..., in, j1, ..., jm], k1, ..., kl]`
    Therefore `params` should be a Tensor of shape [A1, ..., AN, C0, B1, ..., BM],
    `indices` should be a Tensor of shape [A1, ..., AN, C1, ..., CK] and `result` will be
    a Tensor of size `[A1, ..., AN, C1, ..., CK, B1, ..., BM]`.
    In the case in which indices is a 1D tensor, this operation is equivalent to
    `tf.gather`.
    See also `tf.gather` and `tf.gather_nd`.
    Args:
      params: A `Tensor`. The tensor from which to gather values.
      indices: A `Tensor`. Must be one of the following types: int32, int64. Index
          tensor. Must be in range `[0, params.shape[axis]`, where `axis` is the
          last dimension of `indices` itself.
      axis: A `Tensor`. Must be one of the following types: int32, int64. The axis
            in `params` to gather `indices` from.
      name: A name for the operation (optional).
    Returns:
      A Tensor. Has the same type as `params`.
    Raises:
      ValueError: if `indices` has an unknown shape.
    """

    with ops.name_scope(name):
        indices = ops.convert_to_tensor(indices, name="indices")
        params = ops.convert_to_tensor(params, name="params")
        indices_shape = tf.shape(indices)
        params_shape = tf.shape(params)

        ndims = indices.shape.ndims
        if ndims is None:
            raise ValueError(
                "batch_gather does not allow indices with unknown "
                "shape.")
        batch_indices = indices
        indices_dtype = indices.dtype.base_dtype
        accum_dim_value = tf.ones((), dtype=indices_dtype)
        # Use correct type for offset index computation
        casted_params_shape = gen_math_ops.cast(params_shape, indices_dtype)
        for dim in range(axis, 0, -1):
            dim_value = casted_params_shape[dim - 1]
            accum_dim_value *= casted_params_shape[dim]
            start = tf.zeros((), dtype=indices_dtype)
            step = tf.ones((), dtype=indices_dtype)
            dim_indices = gen_math_ops._range(start, dim_value, step)
            dim_indices *= accum_dim_value
            dim_shape = tf.stack([1] * (dim - 1) + [dim_value] + [1] *
                                 (ndims - dim),
                                 axis=0)
            batch_indices += tf.reshape(dim_indices, dim_shape)

        flat_inner_shape_indices = gen_math_ops.prod(
            indices_shape[:(axis + 1)], [0], False)
        flat_indices = tf.reshape(
            batch_indices,
            tf.concat([[flat_inner_shape_indices], indices_shape[(axis + 1):]],
                      axis=0))
        outer_shape = params_shape[(axis + 1):]
        flat_inner_shape_params = gen_math_ops.prod(params_shape[:(axis + 1)],
                                                    [0], False)

        flat_params = tf.reshape(
            params, tf.concat([[flat_inner_shape_params], outer_shape],
                              axis=0))
        flat_result = tf.gather(flat_params, flat_indices)
        result = tf.reshape(flat_result,
                            tf.concat([indices_shape, outer_shape], axis=0))
        final_shape = indices.get_shape()[:axis].merge_with(
            params.get_shape()[:axis])
        final_shape = final_shape.concatenate(indices.get_shape()[axis:])
        final_shape = final_shape.concatenate(params.get_shape()[(axis + 1):])
        result.set_shape(final_shape)
        return result
Exemplo n.º 15
0
def batch_scatter_update(ref, indices, updates, use_locking=True, name=None):
  """Generalization of `tf.scatter_update` to axis different than 0.

  Analogous to `batch_gather`. This assumes that `ref`, `indices` and `updates`
  have a series of leading dimensions that are the same for all of them, and the
  updates are performed on the last dimension of indices. In other words, the
  dimensions should be the following:

  `num_prefix_dims = indices.ndims - 1`
  `batch_dim = num_prefix_dims + 1`
  `updates.shape = indices.shape + var.shape[batch_dim:]`

  where

  `updates.shape[:num_prefix_dims]`
  `== indices.shape[:num_prefix_dims]`
  `== var.shape[:num_prefix_dims]`

  And the operation performed can be expressed as:

  `var[i_1, ..., i_n, indices[i_1, ..., i_n, j]] = updates[i_1, ..., i_n, j]`

  When indices is a 1D tensor, this operation is equivalent to
  `tf.scatter_update`.

  To avoid this operation there would be 2 alternatives:
  1) Reshaping the variable by merging the first `ndims` dimensions. However,
     this is not possible because `tf.reshape` returns a Tensor, which we
     cannot use `tf.scatter_update` on.
  2) Looping over the first `ndims` of the variable and using
     `tf.scatter_update` on the subtensors that result of slicing the first
     dimension. This is a valid option for `ndims = 1`, but less efficient than
     this implementation.

  See also `tf.scatter_update` and `tf.scatter_nd_update`.

  Args:
    ref: `Variable` to scatter onto.
    indices: Tensor containing indices as described above.
    updates: Tensor of updates to apply to `ref`.
    use_locking: Boolean indicating whether to lock the writing operation.
    name: Optional scope name string.

  Returns:
    Ref to `variable` after it has been modified.

  Raises:
    ValueError: If the initial `ndims` of `ref`, `indices`, and `updates` are
        not the same.
  """
  with ops.name_scope(name):
    indices = ops.convert_to_tensor(indices, name="indices")
    indices_shape = array_ops.shape(indices)
    indices_dimensions = indices.get_shape().ndims

    if indices_dimensions is None:
      raise ValueError("batch_gather does not allow indices with unknown "
                       "shape.")

    nd_indices = array_ops.expand_dims(indices, axis=-1)
    nd_indices_list = []

    # Scatter ND requires indices to have an additional dimension, in which the
    # coordinates of the updated things are specified. For this to be adapted to
    # the scatter_update with several leading dimensions, we simply make use of
    # a tf.range for all the leading dimensions followed by concat of all the
    # coordinates we created with the original indices.

    # For example if indices.shape = [2, 3, 4], we should generate the following
    # indices for tf.scatter_nd_update:
    # nd_indices[:, :, 0] = [[0, 0, 0], [1, 1, 1]]
    # nd_indices[:, :, 1] = [[0, 1, 2], [0, 1, 2]]
    # nd_indices[:, :, 2] = indices
    for dimension in range(indices_dimensions - 1):
      # In this loop we generate the following for the example (one for each
      # iteration).
      # nd_indices[:, :, 0] = [[0, 0, 0], [1, 1, 1]]
      # nd_indices[:, :, 1] = [[0, 1, 2], [0, 1, 2]]
      # This is done at every iteration with a tf.range over the size of the
      # i-th dimension and using broadcasting over the desired shape.
      dimension_size = indices_shape[dimension]
      shape_to_broadcast = [1] * (indices_dimensions + 1)
      shape_to_broadcast[dimension] = dimension_size
      dimension_range = array_ops.reshape(
          gen_math_ops._range(0, dimension_size, 1), shape_to_broadcast)
      if dimension_range.dtype.base_dtype != nd_indices.dtype:
        dimension_range = gen_math_ops.cast(dimension_range, nd_indices.dtype)
      nd_indices_list.append(
          dimension_range * array_ops.ones_like(nd_indices))
    # Add the original indices at the end, as described above, and concat.
    nd_indices_list.append(nd_indices)
    final_indices = array_ops.concat(nd_indices_list, axis=-1)
    return scatter_nd_update(
        ref, final_indices, updates, use_locking=use_locking)
Exemplo n.º 16
0
    def call(self, inputs, state):
        """VCGRU with nunits cells."""
        add = math_ops.add
        sub = math_ops.subtract
        mult = math_ops.multiply

        # computing m_t
        m_t = add(math_ops.matmul(state, self._u),
                  math_ops.matmul(inputs, self._v))
        m_t = nn_ops.bias_add(m_t, self._b)
        m_t = math_ops.sigmoid(m_t)

        # add L1 loss
        ops.add_to_collection('L1 loss', math_ops.abs(m_t - self._m_target))

        # computing e_t (= thr)
        i = gen_math_ops._range(1, self._num_units + 1, 1)
        i = math_ops.cast(i, dtype=dtypes.float32)
        mtD = gen_array_ops.tile(mult(m_t[1], self._num_units),
                                 [self._num_units])
        thr = math_ops.sigmoid(mult(self._sharpness, sub(mtD, i)))
        thr = math_ops.round(add(thr, sub(0.5, self._epsilon)))
        ones = array_ops.ones_like(thr)
        thr_inv = sub(ones, thr)

        # computing h_t
        if inputs.shape[1] < thr.shape[0]:
            _inputs = mult(inputs,
                           array_ops.slice(thr, [
                               0,
                           ], [
                               inputs.shape[1],
                           ]))
        elif inputs.shape[1] > thr.shape[0]:
            _inputs = mult(
                inputs,
                array_ops.concat(1, [
                    thr,
                    array_ops.zeros_like(inputs.shape[1] - thr.shape[0])
                ]))
        else:
            _inputs = mult(inputs, thr)
        _state = mult(state, thr)

        gate_inputs = math_ops.matmul(array_ops.concat([_inputs, _state], 1),
                                      self._gate_kernel)
        gate_inputs = nn_ops.bias_add(gate_inputs, self._gate_bias)

        value = math_ops.sigmoid(gate_inputs)
        r, u = array_ops.split(value=value, num_or_size_splits=2, axis=1)

        _r_state = r * _state

        candidate = math_ops.matmul(array_ops.concat([_inputs, _r_state], 1),
                                    self._candidate_kernel)
        candidate = nn_ops.bias_add(candidate, self._candidate_bias)

        c = self._activation(candidate)
        new_h = u * _state + (1 - u) * c

        output = add(mult(new_h, thr), mult(state, thr_inv))
        return output, output