未验证 提交 400c3aa7 编写于 作者: X xiemoyuan 提交者: GitHub

[2.1 API] Modified params of some APIs to support tuple and list. (#32528)

* Modified params of some APIs to support tuple and list.

* fixed bug.
上级 c40c16a9
......@@ -105,7 +105,7 @@ class Distribution(object):
for arg in args:
if isinstance(arg, float):
arg = [arg]
if not isinstance(arg, (list, np.ndarray, tensor.Variable)):
if not isinstance(arg, (list, tuple, np.ndarray, tensor.Variable)):
raise TypeError(
"Type of input args must be float, list, numpy.ndarray or Tensor, but received type {}".
format(type(arg)))
......@@ -190,8 +190,8 @@ class Uniform(Distribution):
[broadcasting](https://www.paddlepaddle.org.cn/documentation/docs/en/develop/beginners_guide/basic_concept/broadcasting_en.html) (e.g., `high - low` is a valid operation).
Args:
low(int|float|list|numpy.ndarray|Tensor): The lower boundary of uniform distribution.The data type is int, float, list, numpy.ndarray or Tensor
high(int|float|list|numpy.ndarray|Tensor): The higher boundary of uniform distribution.The data type is int, float, list, numpy.ndarray or Tensor
low(int|float|list|tuple|numpy.ndarray|Tensor): The lower boundary of uniform distribution.The data type is int, float, list, numpy.ndarray or Tensor
high(int|float|list|tuple|numpy.ndarray|Tensor): The higher boundary of uniform distribution.The data type is int, float, list, numpy.ndarray or Tensor
name(str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
Examples:
......@@ -229,10 +229,10 @@ class Uniform(Distribution):
def __init__(self, low, high, name=None):
if not in_dygraph_mode():
check_type(low, 'low',
(int, float, np.ndarray, tensor.Variable, list),
(int, float, np.ndarray, tensor.Variable, list, tuple),
'Uniform')
check_type(high, 'high',
(int, float, np.ndarray, tensor.Variable, list),
(int, float, np.ndarray, tensor.Variable, list, tuple),
'Uniform')
self.all_arg_is_float = False
......@@ -409,8 +409,8 @@ class Normal(Distribution):
* :math:`Z`: is the normalization constant.
Args:
loc(int|float|list|numpy.ndarray|Tensor): The mean of normal distribution.The data type is int, float, list, numpy.ndarray or Tensor.
scale(int|float|list|numpy.ndarray|Tensor): The std of normal distribution.The data type is int, float, list, numpy.ndarray or Tensor.
loc(int|float|list|tuple|numpy.ndarray|Tensor): The mean of normal distribution.The data type is int, float, list, numpy.ndarray or Tensor.
scale(int|float|list|tuple|numpy.ndarray|Tensor): The std of normal distribution.The data type is int, float, list, numpy.ndarray or Tensor.
name(str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
Examples:
......@@ -451,10 +451,10 @@ class Normal(Distribution):
def __init__(self, loc, scale, name=None):
if not in_dygraph_mode():
check_type(loc, 'loc',
(int, float, np.ndarray, tensor.Variable, list),
(int, float, np.ndarray, tensor.Variable, list, tuple),
'Normal')
check_type(scale, 'scale',
(int, float, np.ndarray, tensor.Variable, list),
(int, float, np.ndarray, tensor.Variable, list, tuple),
'Normal')
self.batch_size_unknown = False
......@@ -655,7 +655,7 @@ class Categorical(Distribution):
* :math:`[x=i]` : it evaluates to 1 if :math:`x==i` , 0 otherwise.
Args:
logits(list|numpy.ndarray|Tensor): The logits input of categorical distribution. The data type is float32 or float64.
logits(list|tuple|numpy.ndarray|Tensor): The logits input of categorical distribution. The data type is float32 or float64.
name(str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
Examples:
......@@ -702,11 +702,12 @@ class Categorical(Distribution):
def __init__(self, logits, name=None):
"""
Args:
logits(list|numpy.ndarray|Tensor): The logits input of categorical distribution. The data type is float32 or float64.
logits(list|tuple|numpy.ndarray|Tensor): The logits input of categorical distribution. The data type is float32 or float64.
name(str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
"""
if not in_dygraph_mode():
check_type(logits, 'logits', (np.ndarray, tensor.Variable, list),
check_type(logits, 'logits',
(np.ndarray, tensor.Variable, list, tuple),
'Categorical')
self.name = name if name is not None else 'Categorical'
......
......@@ -1036,7 +1036,7 @@ def _append_backward_ops_(block,
val(list) the op path of block(index)
"""
if callbacks is not None:
assert (isinstance(callbacks, list))
assert (isinstance(callbacks, (list, tuple)))
for cb in callbacks:
if not hasattr(cb, '__call__'):
raise ValueError("'callback' must be a callable object.")
......@@ -1157,7 +1157,7 @@ def _append_backward_ops_(block,
new_op_desc._set_attr(op_role_attr_name, backward)
grad_to_var["__current_op_desc__"] = new_op_desc
if callbacks is not None:
assert (isinstance(callbacks, list))
assert (isinstance(callbacks, (list, tuple)))
for cb in callbacks:
cb(block=target_block, context=grad_to_var)
......@@ -1380,7 +1380,7 @@ def append_backward(loss,
Parameters:
loss(Tensor): The loss Tensor of the network.
parameter_list(list[Tensor|str], optional): List of Parameters or Parameter.names
parameter_list(list[Tensor|str]|tuple[Tensor|str], optional): List/Tuple of Parameters or Parameter.names
that need to be updated by optimizers.
If it is None, all parameters
will be updated.
......@@ -1391,7 +1391,7 @@ def append_backward(loss,
be automatically added into this set.
If this parameter is not None, the Tensors or Tensor.names in this set will be added to the default set.
Default: None.
callbacks(list[callable object], optional): List of callback functions.
callbacks(list[callable object]|tuple[callable object], optional): List/Tuple of callback functions.
The callbacks are used for
doing some custom jobs during
backward part building. All
......@@ -1477,7 +1477,7 @@ def append_backward(loss,
int(core.op_proto_and_checker_maker.OpRole.Loss))
if callbacks is not None:
check_type(callbacks, 'callbacks', list,
check_type(callbacks, 'callbacks', (list, tuple),
'paddle.static.append_backward')
program = loss.block.program
......@@ -1823,9 +1823,9 @@ def calc_gradient(targets, inputs, target_gradients=None, no_grad_set=None):
Backpropagate the gradients of targets to inputs.
Args:
targets(Tensor|list[Tensor]): The target Tensors
inputs(Tensor|list[Tensor]): The input Tensors
target_gradients (Tensor|list[Tensor], optional): The gradient Tensors
targets(Tensor|list[Tensor]|tuple[Tensor]): The target Tensors
inputs(Tensor|list[Tensor]|tuple[Tensor]): The input Tensors
target_gradients (Tensor|list[Tensor]|tuple[Tensor], optional): The gradient Tensors
of targets which has the same shape with targets, If None, ones will
be created for them.
no_grad_set(set[Tensor|str], optional): Set of Tensors or Tensor.names in the :ref:`api_guide_Block_en` 0 whose gradients
......@@ -1962,9 +1962,9 @@ def gradients(targets, inputs, target_gradients=None, no_grad_set=None):
Backpropagate the gradients of targets to inputs.
Args:
targets (Tensor|list[Tensor]): The target Tensors.
inputs (Tensor|list[Tensor]): The input Tensors.
target_gradients (Tensor|list[Tensor], optional): The gradient Tensor
targets (Tensor|list[Tensor]|tuple[Tensor]): The target Tensors.
inputs (Tensor|list[Tensor]|tuple[Tensor]): The input Tensors.
target_gradients (Tensor|list[Tensor]|tuple[Tensor], optional): The gradient Tensor
of targets which has the same shape with targets, If None, ones will
be created for them.
no_grad_set (set[Tensor|str], optional): Set of Tensors or Tensor.names in the :ref:`api_guide_Block_en` 0 whose gradients
......@@ -1992,12 +1992,12 @@ def gradients(targets, inputs, target_gradients=None, no_grad_set=None):
z = paddle.static.gradients([y], x)
print(z) # [var x@GRAD : fluid.VarType.LOD_TENSOR.shape(-1L, 2L, 8L, 8L).astype(VarType.FP32)]
"""
check_type(targets, 'targets', (framework.Variable, list),
check_type(targets, 'targets', (framework.Variable, list, tuple),
'paddle.static.gradients')
check_type(inputs, 'inputs', (framework.Variable, list),
check_type(inputs, 'inputs', (framework.Variable, list, tuple),
'paddle.static.gradients')
check_type(target_gradients, 'target_gradients', (
framework.Variable, list, type(None)), 'paddle.static.gradients')
framework.Variable, list, tuple, type(None)), 'paddle.static.gradients')
outs = calc_gradient(targets, inputs, target_gradients, no_grad_set)
return _as_list(outs)
......@@ -29,7 +29,7 @@ class Sequential(Layer):
The argument passed to the constructor can be iterable Layers or iterable name Layer pairs.
Parameters:
*layers(tuple): Layers or iterable name Layer pairs.
layers(Layer|list|tuple): Layer or list/tuple of iterable name Layer pair.
Examples:
.. code-block:: python
......@@ -59,7 +59,7 @@ class Sequential(Layer):
def __init__(self, *layers):
super(Sequential, self).__init__()
if len(layers) > 0 and isinstance(layers[0], tuple):
if len(layers) > 0 and isinstance(layers[0], (list, tuple)):
for name, layer in layers:
self.add_sublayer(name, layer)
else:
......
......@@ -168,7 +168,7 @@ def declarative(function=None, input_spec=None):
Args:
function (callable): callable imperative function.
input_spec(list[InputSpec]): list of InputSpec to specific the shape/dtype/name
input_spec(list[InputSpec]|tuple[InputSpec]): list/tuple of InputSpec to specific the shape/dtype/name
information of each input Tensor.
Returns:
......@@ -525,7 +525,7 @@ def save(layer, path, input_spec=None, **configs):
Args:
layer (Layer): The Layer to be saved.
path (str): The path prefix to save model. The format is ``dirname/file_prefix`` or ``file_prefix``.
input_spec (list[InputSpec|Tensor], optional): Describes the input of the saved model's forward
input_spec (list[InputSpec|Tensor]|tuple[InputSpec|Tensor], optional): Describes the input of the saved model's forward
method, which can be described by InputSpec or example Tensor. If None, all input variables of
the original Layer's forward method would be the inputs of the saved model. Default None.
**configs (dict, optional): Other save configuration options for compatibility. We do not
......@@ -654,7 +654,7 @@ def save(layer, path, input_spec=None, **configs):
raise ValueError(
"If there are static functions other than 'forward' that need to be saved, the input 'input_spec' should be None, but received the type of 'input_spec' is %s."
% type(input_spec))
if not isinstance(input_spec, list):
if not isinstance(input_spec, (list, tuple)):
raise TypeError(
"The input input_spec should be 'list', but received input_spec's type is %s."
% type(input_spec))
......
......@@ -301,6 +301,41 @@ class UniformTest9(UniformTest):
name='values', shape=[dims], dtype='float32')
class UniformTest10(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low and high are list.
self.low_np = np.random.randn(batch_size,
dims).astype('float32').tolist()
self.high_np = np.random.uniform(
5.0, 15.0, (batch_size, dims)).astype('float32').tolist()
self.values_np = np.random.randn(batch_size, dims).astype('float32')
def init_static_data(self, batch_size, dims):
self.static_low = self.low_np
self.static_high = self.high_np
with fluid.program_guard(self.test_program):
self.static_values = layers.data(
name='values', shape=[dims], dtype='float32')
class UniformTest11(UniformTest):
def init_numpy_data(self, batch_size, dims):
# low and high are tuple.
self.low_np = tuple(
np.random.randn(batch_size, dims).astype('float32').tolist())
self.high_np = tuple(
np.random.uniform(5.0, 15.0, (batch_size, dims)).astype('float32')
.tolist())
self.values_np = np.random.randn(batch_size, dims).astype('float32')
def init_static_data(self, batch_size, dims):
self.static_low = self.low_np
self.static_high = self.high_np
with fluid.program_guard(self.test_program):
self.static_values = layers.data(
name='values', shape=[dims], dtype='float32')
class NormalNumpy(DistributionNumpy):
def __init__(self, loc, scale):
self.loc = np.array(loc)
......@@ -673,6 +708,66 @@ class NormalTest8(NormalTest):
name='other_scale', shape=[dims], dtype='float64')
class NormalTest9(NormalTest):
def init_numpy_data(self, batch_size, dims):
# loc and scale are list.
self.loc_np = np.random.randn(batch_size,
dims).astype('float32').tolist()
self.scale_np = np.random.randn(batch_size, dims).astype('float32')
while not np.all(self.scale_np > 0):
self.scale_np = np.random.randn(batch_size, dims).astype('float32')
self.scale_np = self.scale_np.tolist()
self.values_np = np.random.randn(batch_size, dims).astype('float32')
# used to construct another Normal object to calculate kl_divergence
self.other_loc_np = np.random.randn(batch_size,
dims).astype('float32').tolist()
self.other_scale_np = np.random.randn(batch_size,
dims).astype('float32')
while not np.all(self.other_scale_np > 0):
self.other_scale_np = np.random.randn(batch_size,
dims).astype('float32')
self.other_scale_np = self.other_scale_np.tolist()
def init_static_data(self, batch_size, dims):
self.static_loc = self.loc_np
self.static_scale = self.scale_np
self.static_other_loc = self.other_loc_np
self.static_other_scale = self.other_scale_np
with fluid.program_guard(self.test_program):
self.static_values = layers.data(
name='values', shape=[dims], dtype='float32')
class NormalTest10(NormalTest):
def init_numpy_data(self, batch_size, dims):
# loc and scale are tuple.
self.loc_np = tuple(
np.random.randn(batch_size, dims).astype('float32').tolist())
self.scale_np = np.random.randn(batch_size, dims).astype('float32')
while not np.all(self.scale_np > 0):
self.scale_np = np.random.randn(batch_size, dims).astype('float32')
self.scale_np = tuple(self.scale_np.tolist())
self.values_np = np.random.randn(batch_size, dims).astype('float32')
# used to construct another Normal object to calculate kl_divergence
self.other_loc_np = tuple(
np.random.randn(batch_size, dims).astype('float32').tolist())
self.other_scale_np = np.random.randn(batch_size,
dims).astype('float32')
while not np.all(self.other_scale_np > 0):
self.other_scale_np = np.random.randn(batch_size,
dims).astype('float32')
self.other_scale_np = tuple(self.other_scale_np.tolist())
def init_static_data(self, batch_size, dims):
self.static_loc = self.loc_np
self.static_scale = self.scale_np
self.static_other_loc = self.other_loc_np
self.static_other_scale = self.other_scale_np
with fluid.program_guard(self.test_program):
self.static_values = layers.data(
name='values', shape=[dims], dtype='float32')
class CategoricalNumpy(DistributionNumpy):
def __init__(self, logits):
self.logits = np.array(logits).astype('float32')
......@@ -961,6 +1056,38 @@ class CategoricalTest7(CategoricalTest):
return np_probs
class CategoricalTest8(CategoricalTest):
def init_dynamic_data(self, batch_size, dims):
# input logtis is 2-D list
# value used in probs and log_prob method is 1-D Tensor
self.logits = self.logits_np.tolist()
self.other_logits = self.other_logits_np.tolist()
self.value = paddle.to_tensor(self.value_np)
def init_static_data(self, batch_size, dims):
with fluid.program_guard(self.test_program):
self.logits_static = self.logits_np.tolist()
self.other_logits_static = self.other_logits_np.tolist()
self.value_static = fluid.data(
name='value', shape=self.value_shape, dtype='int64')
class CategoricalTest9(CategoricalTest):
def init_dynamic_data(self, batch_size, dims):
# input logtis is 2-D tuple
# value used in probs and log_prob method is 1-D Tensor
self.logits = tuple(self.logits_np.tolist())
self.other_logits = tuple(self.other_logits_np.tolist())
self.value = paddle.to_tensor(self.value_np)
def init_static_data(self, batch_size, dims):
with fluid.program_guard(self.test_program):
self.logits_static = tuple(self.logits_np.tolist())
self.other_logits_static = tuple(self.other_logits_np.tolist())
self.value_static = fluid.data(
name='value', shape=self.value_shape, dtype='int64')
class DistributionTestError(unittest.TestCase):
def test_distribution_error(self):
distribution = Distribution()
......
......@@ -303,6 +303,12 @@ class TestDropoutFAPI(unittest.TestCase):
mode='downscale_in_infer')
res10 = paddle.nn.functional.dropout(x=input, p=1., training=True)
res11 = paddle.fluid.layers.dropout(x=input, dropout_prob=0.)
res12 = paddle.nn.functional.dropout(
x=input,
p=0.,
axis=(0, 1),
training=False,
mode='upscale_in_train')
in_np = np.random.random([40, 40]).astype("float32")
res_np = in_np
......@@ -310,7 +316,8 @@ class TestDropoutFAPI(unittest.TestCase):
exe = fluid.Executor(place)
res_list = [
res1, res2, res3, res4, res5, res6, res7, res8, res9, res11
res1, res2, res3, res4, res5, res6, res7, res8, res9, res11,
res12
]
for res in res_list:
fetches = exe.run(fluid.default_main_program(),
......@@ -388,9 +395,16 @@ class TestDropoutFAPI(unittest.TestCase):
x=input, p=1., training=True)
dropout = paddle.fluid.dygraph.Dropout(p=0, )
res11 = dropout(input)
res12 = paddle.nn.functional.dropout(
x=input,
p=0.,
axis=(0, 1),
training=False,
mode='upscale_in_train')
res_list = [
res1, res2, res3, res4, res5, res6, res7, res8, res9, res11
res1, res2, res3, res4, res5, res6, res7, res8, res9, res11,
res12
]
for res in res_list:
self.assertTrue(np.allclose(res.numpy(), res_np))
......
......@@ -55,6 +55,41 @@ class TestImperativeContainerSequential(unittest.TestCase):
loss2 = fluid.layers.reduce_mean(res2)
loss2.backward()
def test_sequential_list_params(self):
data = np.random.uniform(-1, 1, [5, 10]).astype('float32')
with fluid.dygraph.guard():
data = fluid.dygraph.to_variable(data)
model1 = fluid.dygraph.Sequential(
fluid.Linear(10, 1), fluid.Linear(1, 2))
res1 = model1(data)
self.assertListEqual(res1.shape, [5, 2])
model1[1] = fluid.Linear(1, 3)
res1 = model1(data)
self.assertListEqual(res1.shape, [5, 3])
loss1 = fluid.layers.reduce_mean(res1)
loss1.backward()
l1 = fluid.Linear(10, 1)
l2 = fluid.Linear(1, 3)
model2 = fluid.dygraph.Sequential(['l1', l1], ['l2', l2])
self.assertEqual(len(model2), 2)
res2 = model2(data)
self.assertTrue(l1 is model2.l1)
self.assertListEqual(res2.shape, res1.shape)
self.assertEqual(len(model1.parameters()), len(model2.parameters()))
del model2['l2']
self.assertEqual(len(model2), 1)
res2 = model2(data)
self.assertListEqual(res2.shape, [5, 1])
model2.add_sublayer('l3', fluid.Linear(1, 3))
model2.add_sublayer('l4', fluid.Linear(3, 4))
self.assertEqual(len(model2), 3)
res2 = model2(data)
self.assertListEqual(res2.shape, [5, 4])
loss2 = fluid.layers.reduce_mean(res2)
loss2.backward()
if __name__ == '__main__':
unittest.main()
......@@ -718,6 +718,18 @@ class TestAssign(unittest.TestCase):
self.assertTrue((linear_3.weight.numpy() == [2.0, 2.0]).all(), '')
def test_assign_initializer_dygraph_4(self):
"""Test assign initializer in dygraph model.
"""
paddle.disable_static()
weight_attr_4 = paddle.framework.ParamAttr(
name="linear_weight_4",
initializer=paddle.nn.initializer.Assign((2, 2)))
linear_4 = paddle.nn.Linear(2, 2, weight_attr=weight_attr_4)
self.assertTrue((linear_4.weight.numpy() == [2.0, 2.0]).all(), '')
if __name__ == '__main__':
unittest.main()
......@@ -158,6 +158,22 @@ class LinearNetMultiInput(fluid.dygraph.Layer):
return x_out, y_out, loss
class LinearNetMultiInput1(fluid.dygraph.Layer):
def __init__(self, in_size, out_size):
super(LinearNetMultiInput1, self).__init__()
self._linear1 = Linear(in_size, out_size)
self._linear2 = Linear(in_size, out_size)
@declarative(input_spec=(InputSpec(
[None, 8], dtype='float32'), InputSpec(
[None, 8], dtype='float32')))
def forward(self, x, y):
x_out = self._linear1(x)
y_out = self._linear2(y)
loss = fluid.layers.mean(x_out + y_out)
return x_out, y_out, loss
class MultiLoadingLinearNet(fluid.dygraph.Layer):
def __init__(self, size, model_path):
super(MultiLoadingLinearNet, self).__init__()
......@@ -542,6 +558,42 @@ class TestSaveLoadWithInputSpec(unittest.TestCase):
# 4. assert pred_x == pred_xx
self.assertTrue(np.allclose(pred_x.numpy(), pred_xx.numpy()))
def test_multi_in_out1(self):
net = LinearNetMultiInput1(8, 8)
model_path = "multi_inout1.output_spec1/model"
# 1. check inputs and outputs
self.assertTrue(len(net.forward.inputs) == 2)
input_x = net.forward.inputs[0]
input_y = net.forward.inputs[1]
self.assertTrue(input_x.shape == (-1, 8))
self.assertTrue(input_y.shape == (-1, 8))
# 2. prune loss
output_spec = net.forward.outputs[:2]
paddle.jit.save(net, model_path, output_spec=output_spec)
# 3. load to infer
infer_layer = paddle.jit.load(model_path)
x = fluid.dygraph.to_variable(
np.random.random((4, 8)).astype('float32'))
y = fluid.dygraph.to_variable(
np.random.random((4, 8)).astype('float32'))
# 4. predict
pred_x, pred_y = infer_layer(x, y)
# 1. prune y and loss
model_path = "multi_inout1.output_spec2/model"
output_spec = net.forward.outputs[:1]
paddle.jit.save(net, model_path, (input_x, ), output_spec=output_spec)
# 2. load again
infer_layer2 = paddle.jit.load(model_path)
# 3. predict
pred_xx = infer_layer2(x)
# 4. assert pred_x == pred_xx
self.assertTrue(np.allclose(pred_x.numpy(), pred_xx.numpy()))
class TestJitSaveLoadConfig(unittest.TestCase):
def setUp(self):
......
......@@ -236,7 +236,7 @@ def _update_input_info(inputs):
if isinstance(inputs, Input):
shapes = [list(inputs.shape)]
dtypes = [inputs.dtype]
elif isinstance(inputs, list):
elif isinstance(inputs, (list, tuple)):
shapes = [list(input.shape) for input in inputs]
dtypes = [input.dtype for input in inputs]
elif isinstance(inputs, dict):
......@@ -895,12 +895,12 @@ class Model(object):
Args:
network (paddle.nn.Layer): The network is an instance of
paddle.nn.Layer.
inputs (InputSpec|list|dict|None): `inputs`, entry points of network,
could be a InputSpec instance, or lits of InputSpec instances,
inputs (InputSpec|list|tuple|dict|None): `inputs`, entry points of network,
could be a InputSpec instance, or list/tuple of InputSpec instances,
or dict ({name: InputSpec}), and it couldn't be None in static
graph.
labels (InputSpec|list|None): `labels`, entry points of network,
could be a InputSpec instnace or lits of InputSpec instances,
labels (InputSpec|list|tuple|None): `labels`, entry points of network,
could be a InputSpec instnace or list/tuple of InputSpec instances,
or None. For static graph, if labels is required in loss,
labels must be set. Otherwise, it could be None.
......@@ -994,9 +994,10 @@ class Model(object):
self.stop_training = False
if not in_dygraph_mode():
if not isinstance(inputs, (list, dict, Input)):
if not isinstance(inputs, (list, tuple, dict, Input)):
raise TypeError(
"'inputs' must be list or dict, and couldn't be None.")
"'inputs' must be list or tuple or dict, and couldn't be None."
)
elif inputs:
self._input_info = _update_input_info(inputs)
......
......@@ -764,8 +764,8 @@ def dropout(x,
Args:
x (Tensor): The input tensor. The data type is float32 or float64.
p (float | int): Probability of setting units to zero. Default 0.5.
axis (int | list): The axis along which the dropout is performed. Default None.
p (float|int): Probability of setting units to zero. Default 0.5.
axis (int|list|tuple): The axis along which the dropout is performed. Default None.
training (bool): A flag indicating whether it is in train phrase or not. Default True.
mode(str): ['upscale_in_train'(default) | 'downscale_in_infer'].
......@@ -896,7 +896,7 @@ def dropout(x,
if mode not in ('downscale_in_infer', 'upscale_in_train'):
raise ValueError(
"mode argument should be 'downscale_in_infer' or 'upscale_in_train'")
if axis and not isinstance(axis, (int, list)):
if axis and not isinstance(axis, (int, list, tuple)):
raise TypeError("datatype of axis argument should be int or list")
if axis == None: # commonly used dropout
......@@ -955,7 +955,7 @@ def dropout(x,
#get mask shape
input_shape = x.shape
drop_axes = [axis] if isinstance(axis, int) else axis
drop_axes = [axis] if isinstance(axis, int) else list(axis)
if min(drop_axes) < 0 or max(drop_axes) > len(input_shape) - 1:
raise ValueError("axis value should be greater than or equal to 0 and less than dimensions of x:{}, but get axis value:{} " \
.format(len(input_shape), max(drop_axes)))
......
......@@ -26,7 +26,7 @@ class Assign(NumpyArrayInitializer):
"""Init an parameter with a numpy array, list, or tensor.
Args:
value (Tensor|numpy.ndarray|list): numpy array, list, or tensor to initialize the parameter.
value (Tensor|numpy.ndarray|list|tuple): numpy array, list, tuple, or tensor to initialize the parameter.
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`.
......@@ -87,10 +87,10 @@ class Assign(NumpyArrayInitializer):
def __init__(self, value, name=None):
import numpy
check_type(value, 'value', (numpy.ndarray, list, framework.Variable),
'Assign')
check_type(value, 'value',
(numpy.ndarray, list, tuple, framework.Variable), 'Assign')
if (isinstance(value, list)):
if (isinstance(value, (list, tuple))):
value = numpy.array(value)
# TODO: value is already is a tensor, accounting efficiency maybe it does not need to convert tensor to numpy data and then initialized.
......
......@@ -680,8 +680,8 @@ class Dropout(layers.Layer):
In dygraph mode, please use ``eval()`` to switch to evaluation mode, where dropout is disabled.
Parameters:
p (float | int): Probability of setting units to zero. Default: 0.5
axis (int | list): The axis along which the dropout is performed. Default None.
p (float|int): Probability of setting units to zero. Default: 0.5
axis (int|list|tuple): The axis along which the dropout is performed. Default None.
mode(str, optional): ['upscale_in_train'(default) | 'downscale_in_infer']
1. upscale_in_train(default), upscale the output at training time
......
......@@ -172,6 +172,12 @@ class TestModel(unittest.TestCase):
def test_fit_static(self):
self.fit(False)
def test_fit_dynamic_with_tuple_input(self):
self.fit_with_tuple_input(True)
def test_fit_static_with_tuple_input(self):
self.fit_with_tuple_input(False)
def test_fit_dynamic_with_rank(self):
self.fit(True, 2, 0)
......@@ -240,6 +246,53 @@ class TestModel(unittest.TestCase):
model.fit(train_loader, val_loader)
fluid.disable_dygraph() if dynamic else None
def fit_with_tuple_input(self, dynamic, num_replicas=None, rank=None):
fluid.enable_dygraph(self.device) if dynamic else None
seed = 333
paddle.seed(seed)
paddle.framework.random._manual_program_seed(seed)
net = LeNet()
optim_new = fluid.optimizer.Adam(
learning_rate=0.001, parameter_list=net.parameters())
model = Model(net, inputs=tuple(self.inputs), labels=tuple(self.labels))
model.prepare(
optim_new,
loss=CrossEntropyLoss(reduction="sum"),
metrics=Accuracy())
model.fit(self.train_dataset, batch_size=64, shuffle=False)
result = model.evaluate(self.val_dataset, batch_size=64)
np.testing.assert_allclose(result['acc'], self.acc1)
train_sampler = DistributedBatchSampler(
self.train_dataset,
batch_size=64,
shuffle=False,
num_replicas=num_replicas,
rank=rank)
val_sampler = DistributedBatchSampler(
self.val_dataset,
batch_size=64,
shuffle=False,
num_replicas=num_replicas,
rank=rank)
train_loader = fluid.io.DataLoader(
self.train_dataset,
batch_sampler=train_sampler,
places=self.device,
return_list=True)
val_loader = fluid.io.DataLoader(
self.val_dataset,
batch_sampler=val_sampler,
places=self.device,
return_list=True)
model.fit(train_loader, val_loader)
fluid.disable_dygraph() if dynamic else None
def evaluate(self, dynamic):
fluid.enable_dygraph(self.device) if dynamic else None
model = Model(LeNet(), self.inputs, self.labels)
......
......@@ -454,6 +454,18 @@ class TestFunctional(unittest.TestCase):
np.testing.assert_equal(rotated_np_img.shape,
np.array(rotated_pil_img).shape)
def test_rotate1(self):
np_img = (np.random.rand(28, 28, 3) * 255).astype('uint8')
pil_img = Image.fromarray(np_img).convert('RGB')
rotated_np_img = F.rotate(
np_img, 80, expand=True, center=[0, 0], fill=[0, 0, 0])
rotated_pil_img = F.rotate(
pil_img, 80, expand=True, center=[0, 0], fill=[0, 0, 0])
np.testing.assert_equal(rotated_np_img.shape,
np.array(rotated_pil_img).shape)
if __name__ == '__main__':
unittest.main()
......@@ -538,10 +538,10 @@ def rotate(img,
If true, expands the output image to make it large enough to hold the entire rotated image.
If false or omitted, make the output image the same size as the input image.
Note that the expand flag assumes rotation around the center and no translation.
center (2-tuple, optional): Optional center of rotation.
center (2-list|2-tuple, optional): Optional center of rotation.
Origin is the upper left corner.
Default is the center of the image.
fill (3-tuple or int): RGB pixel fill value for area outside the rotated image.
fill (3-list|3-tuple or int): RGB pixel fill value for area outside the rotated image.
If int, it is used for all channels respectively.
......@@ -568,6 +568,11 @@ def rotate(img,
'img should be PIL Image or ndarray with dim=[2 or 3]. Got {}'.
format(type(img)))
if isinstance(center, list):
center = tuple(center)
if isinstance(fill, list):
fill = tuple(fill)
if _is_pil_image(img):
return F_pil.rotate(img, angle, interpolation, expand, center, fill)
else:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册