未验证 提交 f311d3c1 编写于 作者: J joejiong 提交者: GitHub

Fix pow api type error with python side method, merge elementwise_pow and pow. (#26163)

As the title
上级 e4cc6a28
...@@ -22,15 +22,20 @@ namespace operators { ...@@ -22,15 +22,20 @@ namespace operators {
template <typename T> template <typename T>
struct PowFunctor { struct PowFunctor {
inline HOSTDEVICE T operator()(T a, T b) const { inline HOSTDEVICE T operator()(T a, T b) const {
#ifdef __CUDA_ARCH__ // TODO(wujionghao): A potential speed improvement is supporting different
// On CUDAPlace, std::pow(3, 1) calls pow(float, float), and // types in C++.
// it will return a float number like 2.99... , which floor to 2 // #ifdef __CUDA_ARCH__
// when cast to int by default and it is wrong. // // On CUDAPlace, std::pow(3, 1) calls pow(float, float), and
// Use llrint to cast it to the nearest integer, which is 3. // // it will return a float number like 2.99... , which floor to 2
// // when cast to int by default and it is wrong.
// // Use llrint to cast it to the nearest integer, which is 3.
// if (std::is_integral<T>::value) {
// return std::llrint(std::pow(a, b));
// }
// #endif
if (std::is_integral<T>::value) { if (std::is_integral<T>::value) {
return std::llrint(std::pow(a, b)); return std::llrint(std::pow(a, b));
} }
#endif
return std::pow(a, b); return std::pow(a, b);
} }
}; };
......
文件模式从 100644 更改为 100755
文件模式从 100644 更改为 100755
# Copyright (c) 2020 PaddlePaddle 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.
from __future__ import print_function
import paddle
import paddle.tensor as tensor
import paddle.fluid as fluid
from paddle.static import Program, program_guard
import numpy as np
import unittest
DYNAMIC = 1
STATIC = 2
def _run_power(mode, x, y):
# dynamic mode
if mode == DYNAMIC:
paddle.disable_static()
# y is scalar
if isinstance(y, (int, float)):
x_ = paddle.to_tensor(x)
y_ = y
res = paddle.pow(x_, y_)
return res.numpy()
# y is tensor
else:
x_ = paddle.to_tensor(x)
y_ = paddle.to_tensor(y)
res = paddle.pow(x_, y_)
return res.numpy()
# static mode
elif mode == STATIC:
paddle.enable_static()
# y is scalar
if isinstance(y, (int, float)):
with program_guard(Program(), Program()):
x_ = paddle.static.data(name="x", shape=x.shape, dtype=x.dtype)
y_ = y
res = paddle.pow(x_, y_)
place = fluid.CPUPlace()
exe = fluid.Executor(place)
outs = exe.run(feed={'x': x}, fetch_list=[res])
return outs[0]
# y is tensor
else:
with program_guard(Program(), Program()):
x_ = paddle.static.data(name="x", shape=x.shape, dtype=x.dtype)
y_ = paddle.static.data(name="y", shape=y.shape, dtype=y.dtype)
res = paddle.pow(x_, y_)
place = fluid.CPUPlace()
exe = fluid.Executor(place)
outs = exe.run(feed={'x': x, 'y': y}, fetch_list=[res])
return outs[0]
class TestPowerAPI(unittest.TestCase):
"""TestPowerAPI."""
def test_power(self):
"""test_power."""
np.random.seed(7)
# test 1-d float tensor ** float scalar
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.float64)
y = np.random.rand() * 10
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d float tensor ** int scalar
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.float64)
y = int(np.random.rand() * 10)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
x = (np.random.rand(*dims) * 10).astype(np.int64)
y = int(np.random.rand() * 10)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d float tensor ** 1-d float tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.float64)
y = (np.random.rand(*dims) * 10).astype(np.float64)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d float tensor ** 1-d int tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.float64)
y = (np.random.rand(*dims) * 10).astype(np.int64)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d int tensor ** 1-d float tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.int64)
y = (np.random.rand(*dims) * 10).astype(np.float64)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d int tensor ** 1-d int tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.int64)
y = (np.random.rand(*dims) * 10).astype(np.int64)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d int tensor ** 1-d int tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.int32)
y = (np.random.rand(*dims) * 10).astype(np.int32)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d int tensor ** 1-d int tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.int64)
y = (np.random.rand(*dims) * 10).astype(np.int32)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d int tensor ** 1-d int tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.int32)
y = (np.random.rand(*dims) * 10).astype(np.int64)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d int tensor ** 1-d int tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.float32)
y = (np.random.rand(*dims) * 10).astype(np.float32)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d int tensor ** 1-d int tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.float64)
y = (np.random.rand(*dims) * 10).astype(np.float32)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d int tensor ** 1-d int tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.float64)
y = (np.random.rand(*dims) * 10).astype(np.int32)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test 1-d int tensor ** 1-d int tensor
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.float32)
y = (np.random.rand(*dims) * 10).astype(np.int64)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
# test broadcast
dims = (np.random.randint(1, 10), np.random.randint(5, 10),
np.random.randint(5, 10))
x = (np.random.rand(*dims) * 10).astype(np.float64)
y = (np.random.rand(dims[-1]) * 10).astype(np.float64)
res = _run_power(DYNAMIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
res = _run_power(STATIC, x, y)
self.assertTrue(np.allclose(res, np.power(x, y)))
class TestPowerError(unittest.TestCase):
"""TestPowerError."""
def test_errors(self):
"""test_errors."""
np.random.seed(7)
# test dynamic computation graph: inputs must be broadcastable
dims = (np.random.randint(1, 10), np.random.randint(5, 10),
np.random.randint(5, 10))
x = (np.random.rand(*dims) * 10).astype(np.float64)
y = (np.random.rand(dims[-1] + 1) * 10).astype(np.float64)
self.assertRaises(fluid.core.EnforceNotMet, _run_power, DYNAMIC, x, y)
self.assertRaises(fluid.core.EnforceNotMet, _run_power, STATIC, x, y)
# test dynamic computation graph: inputs must be broadcastable
dims = (np.random.randint(1, 10), np.random.randint(5, 10),
np.random.randint(5, 10))
x = (np.random.rand(*dims) * 10).astype(np.float64)
y = (np.random.rand(dims[-1] + 1) * 10).astype(np.int8)
self.assertRaises(TypeError, paddle.pow, x, y)
# test 1-d float tensor ** int string
dims = (np.random.randint(200, 300), )
x = (np.random.rand(*dims) * 10).astype(np.float64)
y = int(np.random.rand() * 10)
self.assertRaises(TypeError, paddle.pow, x, str(y))
if __name__ == '__main__':
unittest.main()
文件模式从 100644 更改为 100755
...@@ -17,6 +17,8 @@ math functions ...@@ -17,6 +17,8 @@ math functions
from __future__ import print_function from __future__ import print_function
from paddle.common_ops_import import * from paddle.common_ops_import import *
from paddle.tensor import cast
import paddle
from ..fluid import layers from ..fluid import layers
from ..fluid.framework import core, _varbase_creator, in_dygraph_mode, Variable from ..fluid.framework import core, _varbase_creator, in_dygraph_mode, Variable
from ..fluid.layer_helper import LayerHelper from ..fluid.layer_helper import LayerHelper
...@@ -64,6 +66,7 @@ from ..fluid.layers import sums #DEFINE_ALIAS ...@@ -64,6 +66,7 @@ from ..fluid.layers import sums #DEFINE_ALIAS
from ..fluid import layers from ..fluid import layers
import paddle import paddle
__all__ = [ __all__ = [
'abs', 'abs',
'acos', 'acos',
...@@ -86,8 +89,8 @@ __all__ = [ ...@@ -86,8 +89,8 @@ __all__ = [
'logsumexp', 'logsumexp',
'mul', 'mul',
'multiplex', 'multiplex',
'prod',
'pow', 'pow',
'prod',
'reciprocal', 'reciprocal',
'reduce_max', 'reduce_max',
'reduce_min', 'reduce_min',
...@@ -147,64 +150,87 @@ _supported_float_dtype_ = [ ...@@ -147,64 +150,87 @@ _supported_float_dtype_ = [
VarDesc.VarType.FP64, VarDesc.VarType.FP64,
] ]
@templatedoc() def pow(x, y, name=None):
def pow(input, exponent, name=None):
""" """
:alias_main: paddle.pow Compute the power of tensor elements. The equation is:
:alias: paddle.pow,paddle.tensor.pow,paddle.tensor.math.pow
This is Pow Activation Operator. .. math::
out = x^{y}
:math:`out = input^{exponent}` **Note**:
``paddle.pow`` supports broadcasting. If you want know more about broadcasting, please refer to :ref:`user_guide_broadcasting` .
Args:
input(Variable): A ``Tensor`` or ``LoDTensor`` . The data type is ``float32`` or ``float64``.
exponent(float32|Variable): A scalar with type ``float32`` or a ``Tensor`` with shape [1] and type ``float32``.
name(str, optional): The default value is None. Normally there is no need for user to set this property.
For more information, please refer to :ref:`api_guide_Name` .
Args:
x (Tensor): An N-D Tensor, the data type is float32, float64, int32 or int64.
y (Tensor): An N-D Tensor with type float32, float64, int32 or int64.
name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
Returns: Returns:
Variable: A ``Tensor`` or ``LoDTensor``. The data type is same as ``input``. N-D Tensor. A location into which the result is stored. Its dimension equals with $x$.
Examples: Examples:
.. code-block:: python .. code-block:: python
import paddle import paddle
import paddle.fluid as fluid import numpy as np
x = fluid.data(name="x", shape=[32,32], dtype="float32")
# example 1: argument exponent is float paddle.disable_static()
y_1 = paddle.pow(x, 2.0)
# y_1 is x^{2.0} # example 1: y is a float
x_data = np.array([1, 2, 3])
y = 2
x = paddle.to_tensor(x_data)
res = paddle.pow(x, y)
print(res.numpy()) # [1 4 9]
# example 2: y is a Tensor
y = paddle.fill_constant(shape=[1], value=2, dtype='float32')
res = paddle.pow(x, y)
print(res.numpy()) # [1 4 9]
# example 2: argument exponent is Variable
exponent_tensor = fluid.layers.fill_constant([1], "float32", 3.0)
y_2 = paddle.pow(x, exponent_tensor)
# y_2 is x^{3.0}
""" """
# in dynamic graph mode
if in_dygraph_mode(): if in_dygraph_mode():
return core.ops.pow(input, "exponent", exponent) if isinstance(y, (int, float)):
return core.ops.pow(x, 'factor', y)
helper = LayerHelper('pow', **locals()) elif isinstance(y, (paddle.Tensor, Variable)):
inputs = {'X': input}
attrs = {} if x.dtype != y.dtype:
if isinstance(exponent, Variable): y = cast(y, dtype='float64')
exponent.stop_gradient = True x = cast(x, dtype='float64')
inputs['FactorTensor'] = exponent out_dygraph = _elementwise_op_in_dygraph(
x, y, axis=-1, act=None, op_name='elementwise_pow')
return out_dygraph
return _elementwise_op_in_dygraph(
x, y, axis=-1, act=None, op_name='elementwise_pow')
else:
raise TypeError('y must be scalar or tensor type, but received: %s '% (y.dtype))
# in static graph mode
else: else:
attrs['factor'] = exponent if isinstance(y, (int, float)):
helper = LayerHelper('pow', **locals())
out = helper.create_variable_for_type_inference(dtype=input.dtype) inputs = {'X': x}
check_dtype( attrs = {'factor': y}
out.dtype, out.name, out = helper.create_variable_for_type_inference(dtype=x.dtype)
convert_dtype(input.dtype), 'pow', helper.append_op(
'(The out data type in pow must be the same with input data type.)') type='pow', inputs=inputs, outputs={'Out': out}, attrs=attrs)
return out
elif isinstance(y, (paddle.Tensor, Variable)):
# TODO A potential speed improvement is supporting different types in C++ and removing the cast ops here
helper = LayerHelper('elementwise_pow', **locals())
if x.dtype != y.dtype:
y = cast(y, dtype='float64')
x = cast(x, dtype='float64')
out = helper.create_variable_for_type_inference(dtype=x.dtype)
else:
out = helper.create_variable_for_type_inference(dtype=x.dtype)
return _elementwise_op(LayerHelper('elementwise_pow', **locals()))
else:
raise TypeError('y must be scalar or tensor type, but received: %s '% (type(y)))
helper.append_op(
type='pow', inputs=inputs, outputs={'Out': out}, attrs=attrs)
return out
@dygraph_only @dygraph_only
...@@ -227,6 +253,8 @@ def _elementwise_op(helper): ...@@ -227,6 +253,8 @@ def _elementwise_op(helper):
x = helper.kwargs.get('x', None) x = helper.kwargs.get('x', None)
y = helper.kwargs.get('y', None) y = helper.kwargs.get('y', None)
out = helper.kwargs.get('out', None)
assert x is not None, 'x cannot be None in {}'.format(original_op_type) assert x is not None, 'x cannot be None in {}'.format(original_op_type)
assert y is not None, 'y cannot be None in {}'.format(original_op_type) assert y is not None, 'y cannot be None in {}'.format(original_op_type)
check_variable_and_dtype( check_variable_and_dtype(
...@@ -239,11 +267,12 @@ def _elementwise_op(helper): ...@@ -239,11 +267,12 @@ def _elementwise_op(helper):
axis = helper.kwargs.get('axis', -1) axis = helper.kwargs.get('axis', -1)
use_mkldnn = helper.kwargs.get('use_mkldnn', False) use_mkldnn = helper.kwargs.get('use_mkldnn', False)
name = helper.kwargs.get('name', None) name = helper.kwargs.get('name', None)
if name is None:
out = helper.create_variable_for_type_inference(dtype=x.dtype) if out is None:
else: if name is None:
out = helper.create_variable( out = helper.create_variable_for_type_inference(dtype=x.dtype)
name=name, dtype=x.dtype, persistable=False) else:
out = helper.create_variable(name=name, dtype=x.dtype, persistable=False)
helper.append_op( helper.append_op(
type=op_type, type=op_type,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册