228 lines
6.1 KiB
Python
228 lines
6.1 KiB
Python
|
# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
# ==============================================================================
|
||
|
|
||
|
"""Inplace operations.
|
||
|
"""
|
||
|
from __future__ import absolute_import
|
||
|
from __future__ import division
|
||
|
from __future__ import print_function
|
||
|
|
||
|
from tensorflow.python.framework import ops
|
||
|
from tensorflow.python.ops import array_ops
|
||
|
from tensorflow.python.ops import gen_array_ops
|
||
|
from tensorflow.python.ops import math_ops
|
||
|
|
||
|
|
||
|
def _inplace_helper(x, i, v, op):
|
||
|
"""Applies an inplace op on (x, i, v).
|
||
|
|
||
|
op is one of gen_array_ops.alias_inplace_update,
|
||
|
gen_array_ops.alias_inplace_add, or gen_array_ops.alias_inplace_sub.
|
||
|
|
||
|
If i is None, x and v must be the same shape. Computes
|
||
|
x op v;
|
||
|
If i is a scalar, x has a rank 1 higher than v's. Computes
|
||
|
x[i, :] op v;
|
||
|
Otherwise, x and v must have the same rank. Computes
|
||
|
x[i, :] op v;
|
||
|
|
||
|
Args:
|
||
|
x: A Tensor.
|
||
|
i: None, a scalar or a vector.
|
||
|
v: A Tensor.
|
||
|
op: alias_inplace_update, alias_inplace_add, or alias_inplace_sub.
|
||
|
|
||
|
Returns:
|
||
|
Returns x.
|
||
|
|
||
|
"""
|
||
|
x = ops.convert_to_tensor(x)
|
||
|
v = ops.convert_to_tensor(v, x.dtype)
|
||
|
if i is None:
|
||
|
# Full tensor.
|
||
|
return array_ops.reshape(
|
||
|
op(array_ops.reshape(x, [1, -1]), [0], array_ops.reshape(v, [1, -1])),
|
||
|
array_ops.shape(x))
|
||
|
i = math_ops.to_int32(i)
|
||
|
if i.get_shape().ndims == 0:
|
||
|
# Single 0-dim update.
|
||
|
return op(x, array_ops.reshape(i, [1]), array_ops.expand_dims(v, 0))
|
||
|
return op(x, i, v)
|
||
|
|
||
|
|
||
|
def alias_inplace_update(x, i, v):
|
||
|
"""Applies an inplace update on input x at index i with value v. Aliases x.
|
||
|
|
||
|
If i is None, x and v must be the same shape. Computes
|
||
|
x = v;
|
||
|
If i is a scalar, x has a rank 1 higher than v's. Computes
|
||
|
x[i, :] = v;
|
||
|
Otherwise, x and v must have the same rank. Computes
|
||
|
x[i, :] = v;
|
||
|
|
||
|
Args:
|
||
|
x: A Tensor.
|
||
|
i: None, a scalar or a vector.
|
||
|
v: A Tensor.
|
||
|
|
||
|
Returns:
|
||
|
Returns x.
|
||
|
|
||
|
"""
|
||
|
return _inplace_helper(x, i, v, gen_array_ops.inplace_update)
|
||
|
|
||
|
|
||
|
def alias_inplace_add(x, i, v):
|
||
|
"""Applies an inplace add on input x at index i with value v. Aliases x.
|
||
|
|
||
|
If i is None, x and v must be the same shape. Computes
|
||
|
x += v;
|
||
|
If i is a scalar, x has a rank 1 higher than v's. Computes
|
||
|
x[i, :] += v;
|
||
|
Otherwise, x and v must have the same rank. Computes
|
||
|
x[i, :] += v;
|
||
|
|
||
|
Args:
|
||
|
x: A Tensor.
|
||
|
i: None, a scalar or a vector.
|
||
|
v: A Tensor.
|
||
|
|
||
|
Returns:
|
||
|
Returns x.
|
||
|
|
||
|
"""
|
||
|
return _inplace_helper(x, i, v, gen_array_ops.inplace_add)
|
||
|
|
||
|
|
||
|
def alias_inplace_sub(x, i, v):
|
||
|
"""Applies an inplace sub on input x at index i with value v. Aliases x.
|
||
|
|
||
|
If i is None, x and v must be the same shape. Computes
|
||
|
x -= v;
|
||
|
If i is a scalar, x has a rank 1 higher than v's. Computes
|
||
|
x[i, :] -= v;
|
||
|
Otherwise, x and v must have the same rank. Computes
|
||
|
x[i, :] -= v;
|
||
|
|
||
|
Args:
|
||
|
x: A Tensor.
|
||
|
i: None, a scalar or a vector.
|
||
|
v: A Tensor.
|
||
|
|
||
|
Returns:
|
||
|
Returns x.
|
||
|
|
||
|
"""
|
||
|
return _inplace_helper(x, i, v, gen_array_ops.inplace_sub)
|
||
|
|
||
|
|
||
|
def empty_like(x, init=None):
|
||
|
"""Returns a non-initialized tensor with the same shape and dtype as x.
|
||
|
|
||
|
Args:
|
||
|
x: A Tensor.
|
||
|
init: Initialize the returned tensor with the default value of
|
||
|
x.dtype(), if True. Otherwise, do not initialize. Defaults to
|
||
|
None.
|
||
|
|
||
|
Returns:
|
||
|
A tensor y, whose dtype and shape are the same as those of x.
|
||
|
y is guaranteed not to be an alias of x. Upon return, y may contain
|
||
|
arbitrary data.
|
||
|
|
||
|
"""
|
||
|
x = ops.convert_to_tensor(x)
|
||
|
return gen_array_ops.empty(array_ops.shape(x), x.dtype, init=init)
|
||
|
|
||
|
|
||
|
def inplace_update(x, i, v):
|
||
|
"""Applies an inplace update on input x at index i with value v.
|
||
|
|
||
|
Note that this function is not actually inplace - it allocates
|
||
|
a copy of x. The utility is not avoiding memory copies but rather
|
||
|
specifying a sparse update.
|
||
|
|
||
|
If i is None, x and v must be the same shape. Computes
|
||
|
y = x; y = v;
|
||
|
If i is a scalar, x has a rank 1 higher than v's. Computes
|
||
|
y = x; y[i, :] = v;
|
||
|
Otherwise, x and v must have the same rank. Computes
|
||
|
y = x; y[i, :] = v;
|
||
|
|
||
|
Args:
|
||
|
x: A Tensor.
|
||
|
i: None, a scalar or a vector.
|
||
|
v: A Tensor.
|
||
|
|
||
|
Returns:
|
||
|
Returns y, which is guaranteed not to be an alias of x.
|
||
|
|
||
|
"""
|
||
|
return alias_inplace_update(gen_array_ops.deep_copy(x), i, v)
|
||
|
|
||
|
|
||
|
def inplace_add(x, i, v):
|
||
|
"""Applies an inplace add on input x at index i with value v.
|
||
|
|
||
|
Note that this function is not actually inplace - it allocates
|
||
|
a copy of x. The utility is not avoiding memory copies but rather
|
||
|
specifying a sparse update.
|
||
|
|
||
|
If i is None, x and v must be the same shape. Computes
|
||
|
y = x; y += v;
|
||
|
If i is a scalar, x has a rank 1 higher than v's. Computes
|
||
|
y = x; y[i, :] += v;
|
||
|
Otherwise, x and v must have the same rank. Computes
|
||
|
y = x; y[i, :] += v;
|
||
|
|
||
|
Args:
|
||
|
x: A Tensor.
|
||
|
i: None, a scalar or a vector.
|
||
|
v: A Tensor.
|
||
|
|
||
|
Returns:
|
||
|
Returns y, which is guaranteed not to be an alias of x.
|
||
|
|
||
|
"""
|
||
|
return alias_inplace_add(gen_array_ops.deep_copy(x), i, v)
|
||
|
|
||
|
|
||
|
def inplace_sub(x, i, v):
|
||
|
"""Applies an inplace sub on input x at index i with value v.
|
||
|
|
||
|
Note that this function is not actually inplace - it allocates
|
||
|
a copy of x. The utility is not avoiding memory copies but rather
|
||
|
specifying a sparse update.
|
||
|
|
||
|
If i is None, x and v must be the same shape. Computes
|
||
|
y = x; y -= v;
|
||
|
If i is a scalar, x has a rank 1 higher than v's. Computes
|
||
|
y = x; y[i, :] -= v;
|
||
|
Otherwise, x and v must have the same rank. Computes
|
||
|
y = x; y[i, :] -= v;
|
||
|
|
||
|
Args:
|
||
|
x: A Tensor.
|
||
|
i: None, a scalar or a vector.
|
||
|
v: A Tensor.
|
||
|
|
||
|
Returns:
|
||
|
Returns y, which is guaranteed not to be an alias of x.
|
||
|
|
||
|
"""
|
||
|
return alias_inplace_sub(gen_array_ops.deep_copy(x), i, v)
|
||
|
|
||
|
empty = gen_array_ops.empty
|