Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arange API: start default is 0, end default is None #25452

Merged
merged 7 commits into from
Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 47 additions & 34 deletions python/paddle/fluid/layers/tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -1322,70 +1322,83 @@ def isfinite(x):
return out


def range(start, end, step, dtype):
def range(start, end, step, dtype, name=None):
"""
Return evenly spaced values within a given interval.

Values are generated within the half-open interval [start, stop) (in other words,
the interval including start but excluding stop).
Values are generated within the half-open interval [start, stop) (in other
words, the interval including start but excluding stop).

If dtype is float32 or float64, we advise adding a small epsilon to end to
avoid floating point rounding errors when comparing against end.

Parameters:
start(float32 | float64 | int32 | int64 | Variable): Start of interval. The interval includes this value.
when start is Variable, it is a 1-D Tensor with shape [1].
end(float32 | float64 | int32 | int64 | Variable): End of interval. The interval does not include this
value, except in some cases where step is not an integer
and floating point round-off affects the length of out. When end is Variable,
it is a 1-D Tensor with shape [1].
step(float32 | float64 | int32 | int64 | Variable): Spacing between values. For any output out, this is the
distance between two adjacent values, out[i+1] - out[i].
dtype(str|core.VarDesc.VarType): the data type of the output tensor, can be float32, float64, int32, int64.

Returns: a 1-D Tensor which is evenly spaced values within a given interval. Its data type is set by dtype.
start(float|int|Variable): Start of interval. The interval includes
zhupengyang marked this conversation as resolved.
Show resolved Hide resolved
this value. If start is Variable, it is a 1-D Tensor with shape [1],
and it's data type should be one of int32, int64, float32, float64.
end(float|int|Variable): End of interval. The interval does not include
this value. When end is Variable, it is a 1-D Tensor with shape [1],
and it's data type should be int32, int64, float32, float64.
step(float|int|Variable): Spacing between values. For any out, this is
the istance between two adjacent values, out[i+1] - out[i].
When end is Variable, it is a 1-D Tensor with shape [1], and it's
data type should be one of int32, int64, float32, float64.
dtype(str|np.dtype|core.VarDesc.VarType): The data type of the output
tensor, can be float32, float64, int32, int64.
name(str, optional): Normally there is no need for user to set this property.
For more information, please refer to :ref:`api_guide_Name` .
Default is None.

Returns: a 1-D Tensor which is evenly spaced values within a given interval.
Its data type is set by dtype.

Return type: Variable

examples:

.. code-block:: python

import paddle.fluid as fluid
data = fluid.layers.range(0, 10, 2, 'int32')
import paddle.fluid as fluid

"""
check_type(start, 'start', (float, int, Variable), 'range')
check_type(end, 'end', (float, int, Variable), 'range')
check_type(step, 'step', (float, int, Variable), 'range')
helper = LayerHelper("range", **locals())
out1 = fluid.layers.range(0, 10, 2, 'int32')
# [0, 2, 4, 6, 8]

check_dtype(dtype, 'create data type',
['float32', 'float64', 'int32', 'int64'], 'range')
start_var = fluid.layers.fill_constant([1], 'int64', 3)
out2 = fluid.layers.range(start_var, 7, 1, 'int64')
# [3, 4, 5, 6]

"""
if not isinstance(dtype, core.VarDesc.VarType):
dtype = convert_np_dtype_to_dtype_(dtype)

dtype = convert_dtype(dtype)
if not isinstance(start, Variable):
start = fill_constant([1], dtype, start)
elif convert_dtype(start.dtype) != dtype:
# make sure that start, end, step has the same dtype as
# `dtype`
start = cast(x=start, dtype=dtype)
elif start.dtype != dtype:
start = cast(start, dtype)

if not isinstance(end, Variable):
end = fill_constant([1], dtype, end)
elif convert_dtype(end.dtype) != dtype:
end = cast(x=end, dtype=dtype)
elif end.dtype != dtype:
end = cast(end, dtype)

if not isinstance(step, Variable):
step = fill_constant([1], dtype, step)
elif convert_dtype(step.dtype) != dtype:
step = cast(x=step, dtype=dtype)
elif step.dtype != dtype:
step = cast(step, dtype)

out = helper.create_variable_for_type_inference(dtype=start.dtype)
if in_dygraph_mode():
return core.ops.range(start, end, step)

check_dtype(dtype, 'dtype', ['float32', 'float64', 'int32', 'int64'],
'range/arange')
helper = LayerHelper('range', **locals())
out = helper.create_variable_for_type_inference(dtype)
helper.append_op(
type='range',
inputs={'Start': start,
'End': end,
'Step': step},
outputs={'Out': [out]})
outputs={'Out': out})
out.stop_gradient = True
return out

Expand Down
65 changes: 43 additions & 22 deletions python/paddle/fluid/tests/unittests/test_arange.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
from __future__ import print_function

import paddle
import paddle.fluid as fluid
from paddle.fluid import core
from paddle import program_guard, Program
import unittest
import numpy as np
from op_test import OpTest
Expand Down Expand Up @@ -44,47 +45,67 @@ def test_check_output(self):
self.check_output()


class TestFloatArangeOpCase0(TestArangeOp):
class TestFloatArangeOp(TestArangeOp):
def init_config(self):
self.dtype = np.float32
self.case = (0, 5, 1)


class TestInt32ArangeOpCase0(TestArangeOp):
class TestInt32ArangeOp(TestArangeOp):
def init_config(self):
self.dtype = np.int32
self.case = (0, 5, 2)


class TestInt32ArangeOpCase1(TestArangeOp):
class TestFloat64ArangeOp(TestArangeOp):
def init_config(self):
self.dtype = np.int32
self.dtype = np.float64
self.case = (10, 1, -2)


class TestInt32ArangeOpCase2(TestArangeOp):
class TestInt64ArangeOp(TestArangeOp):
def init_config(self):
self.dtype = np.int32
self.dtype = np.int64
self.case = (-1, -10, -2)


class TestArangeOpError(unittest.TestCase):
def test_errors(self):
with program_guard(Program(), Program()):
self.assertRaises(TypeError, paddle.arange, 10, dtype='int8')


class TestArangeAPI(unittest.TestCase):
def test_out(self):
with fluid.program_guard(fluid.Program()):
data = paddle.arange(0, 5, 1)
place = fluid.CPUPlace()
exe = fluid.Executor(place)
result, = exe.run(fetch_list=[data])
expected_data = np.arange(0, 5, 1).astype(np.float32)
self.assertEqual((result == expected_data).all(), True)

with fluid.program_guard(fluid.Program()):
data = paddle.arange(0.0, 5.0, 1.0, 'int32')
place = fluid.CPUPlace()
exe = fluid.Executor(place)
result, = exe.run(fetch_list=[data])
expected_data = np.arange(0, 5, 1).astype(np.int32)
self.assertEqual((result == expected_data).all(), True)
with program_guard(Program(), Program()):
x1 = paddle.arange(0, 5, 1, 'float32')

place = paddle.CUDAPlace(0) if core.is_compiled_with_cuda(
) else paddle.CPUPlace()
exe = paddle.Executor(place)
out = exe.run(fetch_list=[x1])

expected_data = np.arange(0, 5, 1).astype(np.float32)
self.assertEqual((out == expected_data).all(), True)


class TestArangeImperative(unittest.TestCase):
def test_out(self):
place = paddle.CUDAPlace(0) if core.is_compiled_with_cuda(
) else paddle.CPUPlace()
with paddle.imperative.guard(place):
x1 = paddle.arange(0, 5, 1)
x2 = paddle.tensor.arange(5)
x3 = paddle.tensor.creation.arange(5)

start = paddle.imperative.to_variable(np.array([0], 'float32'))
end = paddle.imperative.to_variable(np.array([5], 'float32'))
step = paddle.imperative.to_variable(np.array([1], 'float32'))
x4 = paddle.arange(start, end, step, 'int64')

expected_data = np.arange(0, 5, 1).astype(np.int64)
for i in [x1, x2, x3, x4]:
self.assertEqual((i.numpy() == expected_data).all(), True)


if __name__ == "__main__":
Expand Down
103 changes: 54 additions & 49 deletions python/paddle/tensor/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from ..fluid.framework import convert_np_dtype_to_dtype_, in_dygraph_mode, _varbase_creator, device_guard, OpProtoHolder
from ..fluid.layers import fill_constant
from paddle.common_ops_import import *
import paddle

# TODO: define functions to get create a tensor
from ..fluid.layers import crop_tensor #DEFINE_ALIAS
Expand Down Expand Up @@ -413,76 +414,80 @@ def full(shape, fill_value, dtype=None, name=None):
return fill_constant(shape=shape, dtype=dtype, value=fill_value, name=name)


def arange(start, end, step=1, dtype=None, name=None):
def arange(start=0, end=None, step=1, dtype=None, name=None):
"""
:alias_main: paddle.arange
:alias: paddle.arange,paddle.tensor.arange,paddle.tensor.creation.arange

Return evenly spaced values within a given interval.

Values are generated within the half-open interval [start, stop) (in other words,
the interval including start but excluding stop).
Values are generated into the half-open interval [start, stop) with the step.
(the interval including start but excluding stop).

If dtype is float32 or float64, we advise adding a small epsilon to end to
avoid floating point rounding errors when comparing against end.

Parameters:
start(float32 | float64 | int32 | int64 | Variable): Start of interval. The interval includes this value.
when start is Variable, it is a 1-D Tensor with shape [1].
end(float32 | float64 | int32 | int64 | Variable): End of interval. The interval does not include this
value, except in some cases where step is not an integer
and floating point round-off affects the length of out. When end is Variable,
it is a 1-D Tensor with shape [1].
step(float32 | float64 | int32 | int64 | Variable): Spacing between values. For any output out, this is the
distance between two adjacent values, out[i+1] - out[i].
dtype(str|core.VarDesc.VarType): the data type of the output tensor, can be float32, float64, int32, int64.

Returns: a 1-D Tensor which is evenly spaced values within a given interval. Its data type is set by dtype.
start(float|int|Variable): Start of interval. The interval includes
this value. If end is None, the half-open interval is [0, start).
If start is Variable, it is a 1-D Tensor with shape [1], and it's
data type should be one of int32, int64, float32, float64. Default
is 0.
end(float|int|Variable, optional): End of interval. The interval does
not include this value. When end is Variable, it is a 1-D Tensor
with shape [1], and it's data type should be one of int32, int64,
float32, float64. If end is None, the half-open interval is [0, start).
Default is None.
step(float|int|Variable, optional): Spacing between values. For any
out, this is the istance between two adjacent values, out[i+1] - out[i].
When end is Variable, it is a 1-D Tensor with shape [1], and it's
data type should be one of int32, int64, float32, float64. Default is 1.
dtype(str|np.dtype|core.VarDesc.VarType, optional): The data type of
the output tensor, can be float32, float64, int32, int64. If dtype
is `None` , the data type of out tensor is `int64` . Defaule is None
name(str, optional): Normally there is no need for user to set this property.
For more information, please refer to :ref:`api_guide_Name` .
Default is None.

Returns: a 1-D Tensor which is evenly spaced values within a given interval.
Its data type is set by dtype.

Return type: Variable

Raises:
TypeError: If dtype is not float32, float64, int32 or int64.

examples:

.. code-block:: python

import paddle
# expected out put: [0, 2, 4, 6, 8]
data = paddle.arange(0, 10, 2, 'int32')

#dygraph mode
import paddle
import paddle.fluid as fluid
with fluid.dygraph.guard():
x = paddle.arange(0, 6, 2)
# x: [0, 2, 4]
# x dtype: float32

"""
helper = LayerHelper("range", **locals())

if dtype is None:
dtype = 'float32'
import paddle
import numpy as np

check_dtype(dtype, 'create data type',
['float32', 'float64', 'int32', 'int64'], 'range')
paddle.enable_imperative()

dtype = convert_dtype(dtype)
if not isinstance(start, Variable):
start = fill_constant([1], dtype, start)
out1 = paddle.arange(5)
# [0, 1, 2, 3, 4]

if not isinstance(end, Variable):
end = fill_constant([1], dtype, end)
out2 = paddle.arange(3, 9, 2.0)
# [3, 5, 7]

if not isinstance(step, Variable):
step = fill_constant([1], dtype, step)
# use 4.999 instead of 5.0 to avoid floating point rounding errors
out3 = paddle.arange(4.999, dtype='float32')
# [0., 1., 2., 3., 4.]

out = helper.create_variable_for_type_inference(dtype=start.dtype)
start_var = paddle.imperative.to_variable(np.array([3]))
out4 = paddle.arange(start_var, 7)
# [3, 4, 5, 6]

"""
if dtype is None:
dtype = 'int64'
if end is None:
zhupengyang marked this conversation as resolved.
Show resolved Hide resolved
end = start
start = 0

helper.append_op(
type='range',
inputs={'Start': start,
'End': end,
'Step': step},
outputs={'Out': [out]})
out.stop_gradient = True
return out
return paddle.fluid.layers.range(start, end, step, dtype, name)
zhupengyang marked this conversation as resolved.
Show resolved Hide resolved


def _tril_triu_op(helper):
Expand Down