diff options
Diffstat (limited to 'tensorflow/core/ops/array_ops.cc')
-rw-r--r-- | tensorflow/core/ops/array_ops.cc | 892 |
1 files changed, 892 insertions, 0 deletions
diff --git a/tensorflow/core/ops/array_ops.cc b/tensorflow/core/ops/array_ops.cc new file mode 100644 index 0000000000..8c0571b50e --- /dev/null +++ b/tensorflow/core/ops/array_ops.cc @@ -0,0 +1,892 @@ +#include "tensorflow/core/framework/op.h" + +namespace tensorflow { + +REGISTER_OP("Pack") + .Input("values: N * T") + .Output("output: T") + .Attr("N: int >= 1") + .Attr("T: type") + .Doc(R"doc( +Packs a list of `N` rank-`R` tensors into one rank-`(R+1)` tensor. + +Packs the `N` tensors in `values` into a tensor with rank one higher than each +tensor in `values` and shape `[N] + values[0].shape`. The output satisfies +`output[i, ...] = values[i][...]`. + +This is the opposite of `unpack`. + +values: Must be of same shape and type. +output: The packed tensor. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Unpack") + .Input("value: T") + .Output("output: num * T") + .Attr("num: int >= 0") + .Attr("T: type") + .Doc(R"doc( +Unpacks the outer dimension of a rank-`R` tensor into `num` rank-`(R-1)` tensors. + +Unpacks `num` tensors from `value` by chipping it along the first dimension. +The i'th tensor in `output` is the slice `value[i, ...]`. Each tensor in +`output` has shape `value.shape[1:]`. + +This is the opposite of `pack`. + +value: 1-D or higher, with first dimension `num`. +output: The list of tensors unpacked from `value`. +)doc"); + +// -------------------------------------------------------------------------- +// TODO(josh11b): Remove the >= 2 constraint, once we can rewrite the graph +// in the N == 1 case to remove the node. +REGISTER_OP("Concat") + .Input("concat_dim: int32") + .Input("values: N * T") + .Output("output: T") + .Attr("N: int >= 2") + .Attr("T: type") + .Doc(R"doc( +Concatenates tensors along one dimension. + +concat_dim: 0-D. The dimension along which to concatenate. Must be in the + range [0, rank(values)). +values: The `N` Tensors to concatenate. Their ranks and types must match, + and their sizes must match in all dimensions except `concat_dim`. +output: A `Tensor` with the concatenation of values stacked along the + `concat_dim` dimension. This tensor's shape matches that of `values` except + in `concat_dim` where it has the sum of the sizes. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Split") + .Input("split_dim: int32") + .Input("value: T") + .Output("output: num_split * T") + .Attr("num_split: int >= 1") + .Attr("T: type") + .Doc(R"doc( +Splits a tensor into `num_split` tensors along one dimension. + +split_dim: 0-D. The dimension along which to split. Must be in the range + `[0, rank(value))`. +num_split: The number of ways to split. Must evenly divide + `value.shape[split_dim]`. +value: The tensor to split. +output: They are identically shaped tensors, whose shape matches that of `value` + except along `split_dim`, where their sizes are + `values.shape[split_dim] / num_split`. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Const") + .Output("output: dtype") + .Attr("value: tensor") + .Attr("dtype: type") + .Doc(R"doc( +Returns a constant tensor. + +value: Attr `value` is the tensor to return. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("ZerosLike") + .Input("x: T") + .Output("y: T") + .Attr("T: type") + .Doc(R"doc( +Returns a tensor of zeros with the same shape and type as x. + +x: a tensor of type T. +y: a tensor of the same shape and type as x but filled with zeros. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Diag") + .Input("diagonal: T") + .Output("output: T") + .Attr("T: {float, double, int32, int64}") + .Doc(R"doc( +Returns a diagonal tensor with a given diagonal values. + +Given a `diagonal`, this operation returns a tensor with the `diagonal` and +everything else padded with zeros. The diagonal is computed as follows: + +Assume `diagonal` has dimensions [D1,..., Dk], then the output is a tensor of +rank 2k with dimensions [D1,..., Dk, D1,..., Dk] where: + +`output[i1,..., ik, i1,..., ik] = diagonal[i1, ..., ik]` and 0 everywhere else. + +For example: + +```prettyprint +# 'diagonal' is [1, 2, 3, 4] +tf.diag(diagonal) ==> [[1, 0, 0, 0] + [0, 2, 0, 0] + [0, 0, 3, 0] + [0, 0, 0, 4]] +``` + +diagonal: Rank k tensor where k is at most 3. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Reverse") + .Input("tensor: T") + .Input("dims: bool") + .Output("output: T") + .Attr("T: {uint8, int8, int32, bool, float, double}") + .Doc(R"Doc( +Reverses specific dimensions of a tensor. + +Given a `tensor`, and a `bool` tensor `dims` representing the dimensions +of `tensor`, this operation reverses each dimension i of `tensor` where +`dims[i]` is `True`. + +`tensor` can have up to 8 dimensions. The number of dimensions +of `tensor` must equal the number of elements in `dims`. In other words: + +`rank(tensor) = size(dims)` + +For example: + +```prettyprint +# tensor 't' is [[[[ 0, 1, 2, 3], +# [ 4, 5, 6, 7], +# [ 8, 9, 10, 11]], +# [[12, 13, 14, 15], +# [16, 17, 18, 19], +# [20, 21, 22, 23]]]] +# tensor 't' shape is [1, 2, 3, 4] + +# 'dims' is [False, False, False, True] +reverse(t, dims) ==> [[[[ 3, 2, 1, 0], + [ 7, 6, 5, 4], + [ 11, 10, 9, 8]], + [[15, 14, 13, 12], + [19, 18, 17, 16], + [23, 22, 21, 20]]]] + +# 'dims' is [False, True, False, False] +reverse(t, dims) ==> [[[[12, 13, 14, 15], + [16, 17, 18, 19], + [20, 21, 22, 23] + [[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11]]]] + +# 'dims' is [False, False, True, False] +reverse(t, dims) ==> [[[[8, 9, 10, 11], + [4, 5, 6, 7], + [0, 1, 2, 3]] + [[20, 21, 22, 23], + [16, 17, 18, 19], + [12, 13, 14, 15]]]] +``` + +tensor: Up to 8-D. +dims: 1-D. The dimensions to reverse. +output: The same shape as `tensor`. +)Doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("EditDistance") + .Input("hypothesis_indices: int64") + .Input("hypothesis_values: T") + .Input("hypothesis_shape: int64") + .Input("truth_indices: int64") + .Input("truth_values: T") + .Input("truth_shape: int64") + .Attr("normalize: bool = True") + .Attr("T: type") + .Output("output: float") + .Doc(R"doc( +Computes the (possibly normalized) Levenshtein Edit Distance. + +The inputs are variable-length sequences provided by SparseTensors + (hypothesis_indices, hypothesis_values, hypothesis_shape) +and + (truth_indices, truth_values, truth_shape). + +The inputs are: + +hypothesis_indices: The indices of the hypothesis list SparseTensor. + This is an N x R int64 matrix. +hypothesis_values: The values of the hypothesis list SparseTensor. + This is an N-length vector. +hypothesis_shape: The shape of the hypothesis list SparseTensor. + This is an R-length vector. +truth_indices: The indices of the truth list SparseTensor. + This is an M x R int64 matrix. +truth_values: The values of the truth list SparseTensor. + This is an M-length vector. +truth_shape: The shape of the truth list SparseTensor. + This is an R-length vector. +truth_shape: truth indices, vector. +normalize: boolean (if true, edit distances are normalized by length of truth). + +The output is: + +output: A dense float tensor with rank R - 1. + +For the example input: + + // hypothesis represents a 2x1 matrix with variable-length values: + // (0,0) = ["a"] + // (1,0) = ["b"] + hypothesis_indices = [[0, 0, 0], + [1, 0, 0]] + hypothesis_values = ["a", "b"] + hypothesis_shape = [2, 1, 1] + + // truth represents a 2x2 matrix with variable-length values: + // (0,0) = [] + // (0,1) = ["a"] + // (1,0) = ["b", "c"] + // (1,1) = ["a"] + truth_indices = [[0, 1, 0], + [1, 0, 0], + [1, 0, 1], + [1, 1, 0]] + truth_values = ["a", "b", "c", "a"] + truth_shape = [2, 2, 2] + normalize = true + +The output will be: + + // output is a 2x2 matrix with edit distances normalized by truth lengths. + output = [[inf, 1.0], // (0,0): no truth, (0,1): no hypothesis + [0.5, 1.0]] // (1,0): addition, (1,1): no hypothesis +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Fill") + .Input("dims: int32") + .Input("value: T") + .Output("output: T") + .Attr("T: type") + .Doc(R"doc( +Creates a tensor filled with a scalar value. + +This operation creates a tensor of shape `dims` and fills it with `value`. + +For example: + +```prettyprint +# output tensor shape needs to be [2, 3] +# so 'dims' is [2, 3] +fill(dims, 9) ==> [[9, 9, 9] + [9, 9, 9]] +``` + +dims: 1-D. Represents the shape of the output tensor. +value: 0-D (scalar). Value to fill the returned tensor. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Gather") + .Input("params: Tparams") + .Input("indices: Tindices") + .Output("output: Tparams") + .Attr("Tparams: type") + .Attr("Tindices: {int32,int64}") + .Doc(R"doc( +Gather slices from `params` according to `indices`. + +`indices` must be an integer tensor of any dimension (usually 0-D or 1-D). +Produces an output tensor with shape `indices.shape + params.shape[1:]` where: + + # Scalar indices + output[:, ..., :] = params[indices, :, ... :] + + # Vector indices + output[i, :, ..., :] = params[indices[i], :, ... :] + + # Higher rank indices + output[i, ..., j, :, ... :] = params[indices[i, ..., j], :, ..., :] + +If `indices` is a permutation and `len(indices) == params.shape[0]` then +this operation will permute `params` accordingly. + +<div style="width:70%; margin:auto; margin-bottom:10px; margin-top:20px;"> +<img style="width:100%" src="../images/Gather.png" alt> +</div> +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Identity") + .Input("input: T") + .Output("output: T") + .Attr("T: type") + .Doc(R"Doc( +Return a tensor with the same shape and contents as the input tensor or value. +)Doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("RefIdentity") + .Input("input: Ref(T)") + .Output("output: Ref(T)") + .Attr("T: type") + .Doc(R"Doc( +Return the same ref tensor as the input ref tensor. +)Doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("StopGradient") + .Input("input: T") + .Output("output: T") + .Attr("T: type") + .Doc(R"Doc( +Stops gradient computation. + +When executed in a graph, this op outputs its input tensor as-is. + +When building ops to compute gradients, this op prevents the contribution of +its inputs to be taken into account. Normally, the gradient generator adds ops +to a graph to compute the derivatives of a specified 'loss' by recursively +finding out inputs that contributed to its computation. If you insert this op +in the graph it inputs are masked from the gradient generator. They are not +taken into account for computing gradients. + +This is useful any time you want to compute a value with TensorFlow but need +to pretend that the value was a constant. Some examples include: + +* The *EM* algorithm where the *M-step* should not involve backpropagation + through the output of the *E-step*. +* Contrastive divergence training of Boltzmann machines where, when + differentiating the energy function, the training must not backpropagate + through the graph that generated the samples from the model. +* Adversarial training, where no backprop should happen through the adversarial + example generation process. +)Doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("CheckNumerics") + .Input("tensor: T") + .Output("output: T") + .Attr("T: {float, double}") + .Attr("message: string") + .Doc(R"doc( +Checks a tensor for NaN and Inf values. + +When run, reports an `InvalidArgument` error if `tensor` has any values +that are not a number (NaN) or infinity (Inf). Otherwise, passes `tensor` as-is. + +message: Prefix of the error message. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Reshape") + .Input("tensor: T") + .Input("shape: int32") + .Output("output: T") + .Attr("T: type") + .Doc(R"Doc( +Reshapes a tensor. + +Given `tensor`, this operation returns a tensor that has the same values +as `tensor` with shape `shape`. + +If `shape` is the special value `[-1]`, then `tensor` is flattened and the +operation outputs a 1-D tensor with all elements of `tensor`. + +If `shape` is 1-D or higher, then the operation returns a tensor with shape +`shape` filled with the values of `tensor`. In this case, the number of elements +implied by `shape` must be the same as the number of elements in `tensor`. + +For example: + +```prettyprint +# tensor 't' is [1, 2, 3, 4, 5, 6, 7, 8, 9] +# tensor 't' has shape [9] +reshape(t, [3, 3]) ==> [[1, 2, 3] + [4, 5, 6] + [7, 8, 9]] + +# tensor 't' is [[[1, 1], [2, 2]] +# [[3, 3], [4, 4]]] +# tensor 't' has shape [2, 2] +reshape(t, [2, 4]) ==> [[1, 1, 2, 2] + [3, 3, 4, 4]] + +# tensor 't' is [[[1, 1, 1], +# [2, 2, 2]], +# [[3, 3, 3], +# [4, 4, 4]], +# [[5, 5, 5], +# [6, 6, 6]]] +# tensor 't' has shape [3, 2, 3] +# pass '[-1]' to flatten 't' +reshape(t, [-1]) ==> [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6] +``` + +shape: Defines the shape of the output tensor. +)Doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("InvertPermutation") + .Input("x: int32") + .Output("y: int32") + .Doc(R"doc( +Computes the inverse permutation of a tensor. + +This operation computes the inverse of an index permutation. It takes a 1-D +integer tensor `x`, which represents the indices of a zero-based array, and +swaps each value with its index position. In other words, for an ouput tensor +`y` and an input tensor `x`, this operation computes the following: + +`y[x[i]] = i for i in [0, 1, ..., len(x) - 1]` + +The values must include 0. There can be no duplicate values or negative values. + +For example: + +```prettyprint +# tensor `x` is [3, 4, 0, 2, 1] +invert_permutation(x) ==> [2, 4, 3, 0, 1] +``` + +x: 1-D. +y: 1-D. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Transpose") + .Input("x: T") + .Input("perm: int32") + .Output("y: T") + .Attr("T: type") + .Doc(R"doc( +Shuffle dimensions of x according to a permutation. + +The output `y` has the same rank as `x`. The shapes of `x` and `y` satisfy: + `y.shape[i] == x.shape[perm[i]] for i in [0, 1, ..., rank(x) - 1]` +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Unique") + .Input("x: T") + .Output("y: T") + .Output("idx: int32") + .Attr("T: type") + .Doc(R"doc( +Finds unique elements in a 1-D tensor. + +This operation returns a tensor `y` containing all of the unique elements of `x` +sorted in the same order that they occur in `x`. This operation also returns a +tensor `idx` the same size as `x` that contains the index of each value of `x` +in the unique output `y`. In other words: + +`y[idx[i]] = x[i] for i in [0, 1,...,rank(x) - 1]` + +For example: + +```prettyprint +# tensor 'x' is [1, 1, 2, 4, 4, 4, 7, 8, 8] +y, idx = unique(x) +y ==> [1, 2, 4, 7, 8] +idx ==> [0, 0, 1, 2, 2, 2, 3, 4, 4] +``` + +x: 1-D. +y: 1-D. +idx: 1-D. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Shape") + .Input("input: T") + .Output("output: int32") + .Attr("T: type") + .Doc(R"doc( +Returns the shape of a tensor. + +This operation returns a 1-D integer tensor representing the shape of `input`. + +For example: + +```prettyprint +# 't' is [[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]] +shape(t) ==> [2, 2, 3] +``` + +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("ReverseSequence") + .Input("input: T") + .Input("seq_lengths: int64") + .Output("output: T") + .Attr("seq_dim: int") + .Attr("T: type") + .Doc(R"doc( +Reverses variable length slices in dimension `seq_dim`. + +This op first slices `input` along the first dimension, and for each slice `i`, +reverses the first `seq_lengths[i]` elements along the dimension `seq_dim`. + +The elements of `seq_lengths` must obey `seq_lengths[i] < input.dims[seq_dim]`, +and `seq_lengths` must be a vector of length `input.dims(0)`. + +The output slice `i` along dimension 0 is then given by input slice `i`, with +the first `seq_lengths[i]` slices along dimension `seq_dim` reversed. + +For example: + +```prettyprint +# Given this: +seq_dim = 1 +input.dims = (4, ...) +seq_lengths = [7, 2, 3, 5] + +# then slices of input are reversed on seq_dim, but only up to seq_lengths: +output[0, 0:7, :, ...] = input[0, 7:0:-1, :, ...] +output[1, 0:2, :, ...] = input[1, 2:0:-1, :, ...] +output[2, 0:3, :, ...] = input[2, 3:0:-1, :, ...] +output[3, 0:5, :, ...] = input[3, 5:0:-1, :, ...] + +# while entries past seq_lens are copied through: +output[0, 7:, :, ...] = input[0, 7:, :, ...] +output[1, 2:, :, ...] = input[1, 2:, :, ...] +output[2, 3:, :, ...] = input[2, 3:, :, ...] +output[3, 2:, :, ...] = input[3, 2:, :, ...] +``` + +input: The input to reverse. +seq_lengths: 1-D with length `input.dims(0)` and + `max(seq_lengths) < input.dims(seq_dim)` +seq_dim: The dimension which is partially reversed. +output: The partially reversed input. It has the same shape as `input`. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Rank") + .Input("input: T") + .Output("output: int32") + .Attr("T: type") + .Doc(R"doc( +Returns the rank of a tensor. + +This operation returns an integer representing the rank of `input`. + +For example: + +```prettyprint +# 't' is [[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]] +# shape of tensor 't' is [2, 2, 3] +rank(t) ==> 3 +``` + +**Note**: The rank of a tensor is not the same as the rank of a matrix. The rank +of a tensor is the number of indices required to uniquely select each element +of the tensor. Rank is also known as "order", "degree", or "ndims." +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Size") + .Input("input: T") + .Output("output: int32") + .Attr("T: type") + .Doc(R"doc( +Returns the size of a tensor. + +This operation returns an integer representing the number of elements in +`input`. + +For example: + +```prettyprint +# 't' is [[[1, 1,, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]]] +size(t) ==> 12 +``` + +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Slice") + .Input("input: T") + .Input("begin: Index") + .Input("size: Index") + .Output("output: T") + .Attr("T: type") + .Attr("Index: {int32,int64}") + .Doc(R"doc( +Return a slice from 'input'. + +The output tensor is a tensor with dimensions described by 'size' +whose values are extracted from 'input' starting at the offsets in +'begin'. + +*Requirements*: + 0 <= begin[i] <= begin[i] + size[i] <= Di for i in [0, n) + +begin: begin[i] specifies the offset into the 'i'th dimension of + 'input' to slice from. +size: size[i] specifies the number of elements of the 'i'th dimension + of 'input' to slice. If size[i] is -1, all remaining elements in dimension + i are included in the slice (i.e. this is equivalent to setting + size[i] = input.dim_size(i) - begin[i]). +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Tile") + .Input("input: T") + .Input("multiples: int32") + .Output("output: T") + .Attr("T: type") + .Doc(R"doc( +Constructs a tensor by tiling a given tensor. + +This operation creates a new tensor by replicating `input` `multiples` times. +The output tensor's i'th dimension has `input.dims(i) * multiples[i]` elements, +and the values of `input` are replicated `multiples[i]` times along the 'i'th +dimension. For example, tiling `[a b c d]` by `[2]` produces +`[a b c d a b c d]`. + +input: 1-D or higher. +multiples: 1-D. Length must be the same as the number of dimensions in `input` +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("TileGrad") + .Input("input: T") + .Input("multiples: int32") + .Output("output: T") + .Attr("T: type") + .Doc(R"doc( +Returns the gradient of `Tile`. + +Since `Tile` takes an input and repeats the input `multiples` times +along each dimension, `TileGrad` takes in `multiples` and aggregates +each repeated tile of `input` into `output`. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Where") + .Input("input: bool") + .Output("index: int64") + .Doc(R"doc( +Returns locations of true values in a boolean tensor. + +This operation returns the coordinates of true elements in `input`. The +coordinates are returned in a 2-D tensor where the first dimension (rows) +represents the number of true elements, and the second dimension (columns) +represents the coordinates of the true elements. Keep in mind, the shape of +the output tensor can vary depending on how many true values there are in +`input`. Indices are output in row-major order. + +For example: + +```prettyprint +# 'input' tensor is [[True, False] +# [True, False]] +# 'input' has two true values, so output has two coordinates. +# 'input' has rank of 2, so coordinates have two indices. +where(input) ==> [[0, 0], + [1, 0]] + +# `input` tensor is [[[True, False] +# [True, False]] +# [[False, True] +# [False, True]] +# [[False, False] +# [False, True]]] +# 'input' has 5 true values, so output has 5 coordinates. +# 'input' has rank of 3, so coordinates have three indices. +where(input) ==> [[0, 0, 0], + [0, 1, 0], + [1, 0, 1], + [1, 1, 1], + [2, 1, 1]] +``` + +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("BroadcastGradientArgs") + .Input("s0: int32") + .Input("s1: int32") + .Output("r0: int32") + .Output("r1: int32") + .Doc(R"doc( +Return the reduction indices for computing gradients of s0 op s1 with broadcast. + +This is typically used by gradient computations for a broadcasting operation. +)doc"); + +// -------------------------------------------------------------------------- + +REGISTER_OP("Pad") + .Input("input: T") + .Input("paddings: int32") + .Output("output: T") + .Attr("T: type") + .Doc(R"doc( +Pads a tensor with zeros. + +This operation pads a `input` with zeros according to the `paddings` you +specify. `paddings` is an integer tensor with shape `[Dn, 2]`, where n is the +rank of `input`. For each dimension D of `input`, `paddings[D, 0]` indicates +how many zeros to add before the contents of `input` in that dimension, and +`paddings[D, 1]` indicates how many zeros to add after the contents of `input` +in that dimension. + +The padded size of each dimension D of the output is: + +`paddings(D, 0) + input.dim_size(D) + paddings(D, 1)` + +For example: + +```prettyprint +# 't' is [[1, 1], [2, 2]] +# 'paddings' is [[1, 1]], [2, 2]] +# rank of 't' is 2 +pad(t, paddings) ==> [[0, 0, 0, 0, 0] + [0, 0, 0, 0, 0] + [0, 1, 1, 0, 0] + [[0, 2, 2, 0, 0] + [0, 0, 0, 0, 0]] +``` + +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Placeholder") + .Output("output: dtype") + .Attr("dtype: type") + .Attr("shape: shape") + .Doc(R"doc( +A placeholder op for a value that will be fed into the computation. + +N.B. This operation will fail with an error if it is executed. It is +intended as a way to represent a value that will always be fed, and to +provide attrs that enable the fed value to be checked at runtime. + +output: A placeholder tensor that must be replaced using the feed mechanism. +dtype: The type of elements in the tensor. +shape: (Optional) The shape of the tensor. If the shape has 0 dimensions, the + shape is unconstrained. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("ExpandDims") + .Input("input: T") + .Input("dim: int32") + .Output("output: T") + .Attr("T: type") + .Doc(R"doc( +Inserts a dimension of 1 into a tensor's shape. + +Given a tensor `input`, this operation inserts a dimension of 1 at the +dimension index `dim` of `input`'s shape. The dimension index `dim` starts at +zero; if you specify a negative number for `dim` it is counted backward from +the end. + +This operation is useful if you want to add a batch dimension to a single +element. For example, if you have a single image of shape `[height, width, +channels]`, you can make it a batch of 1 image with `expand_dims(image, 0)`, +which will make the shape `[1, height, width, channels]`. + +Other examples: + +```prettyprint +# 't' is a tensor of shape [2] +shape(expand_dims(t, 0)) ==> [1, 2] +shape(expand_dims(t, 1)) ==> [2, 1] +shape(expand_dims(t, -1)) ==> [2, 1] + +# 't2' is a tensor of shape [2, 3, 5] +shape(expand_dims(t2, 0)) ==> [1, 2, 3, 5] +shape(expand_dims(t2, 2)) ==> [2, 3, 1, 5] +shape(expand_dims(t2, 3)) ==> [2, 3, 5, 1] +``` + +This operation requires that: + +`-1-input.dims() <= dim <= input.dims()` + +This operation is related to `squeeze()`, which removes dimensions of +size 1. + +dim: 0-D (scalar). Specifies the dimension index at which to + expand the shape of `input`. +output: Contains the same data as `input`, but its shape has an additional + dimension of size 1 added. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("Squeeze") + .Input("input: T") + .Output("output: T") + .Attr("T: type") + .Attr("squeeze_dims: list(int) >= 0 = []") + .Doc(R"doc( +Removes dimensions of size 1 from the shape of a tensor. + +Given a tensor `input`, this operation returns a tensor of the same type with +all dimensions of size 1 removed. If you don't want to remove all size 1 +dimensions, you can remove specific size 1 dimensions by specifying +`squeeze_dims`. + +For example: + +```prettyprint +# 't' is a tensor of shape [1, 2, 1, 3, 1, 1] +shape(squeeze(t)) ==> [2, 3] +``` + +Or, to remove specific size 1 dimensions: + +```prettyprint +# 't' is a tensor of shape [1, 2, 1, 3, 1, 1] +shape(squeeze(t, [2, 4])) ==> [1, 2, 3, 1] +``` + +input: The `input` to squeeze. +squeeze_dims: If specified, only squeezes the dimensions listed. The dimension + index starts at 0. It is an error to squeeze a dimension that is not 1. +output: Contains the same data as `input`, but has one or more dimensions of + size 1 removed. +)doc"); + +// -------------------------------------------------------------------------- +REGISTER_OP("ListDiff") + .Input("x: T") + .Input("y: T") + .Output("out: T") + .Output("idx: int32") + .Attr("T: type") + .Doc(R"doc( +Computes the difference between two lists of numbers. + +Given a list `x` and a list `y`, this operation returns a list `out` that +represents all numbers that are in `x` but not in `y`. The returned list `out` +is sorted in the same order that the numbers appear in `x` (duplicates are +preserved). This operation also returns a list `idx` that represents the +position of each `out` element in `x`. In other words: + +`out[i] = x[idx[i]] for i in [0, 1, ..., len(out) - 1]` + +For example, given this input: + +```prettyprint +x = [1, 2, 3, 4, 5, 6] +y = [1, 3, 5] +``` + +This operation would return: + +```prettyprint +out ==> [2, 4, 6] +idx ==> [1, 3, 5] +``` + +x: 1-D. Values to keep. +y: 1-D. Values to remove. +out: 1-D. Values present in `x` but not in `y`. +idx: 1-D. Positions of `x` values preserved in `out`. +)doc"); + +} // namespace tensorflow |