diff --git a/paddle/fluid/API.spec b/paddle/fluid/API.spec index 9d5ae1ecc1fbafff6905b8201a3c20b86fd69e7c..2e11b01b75ee7379f04f3ca4bc07b70ff8a4eefc 100644 --- a/paddle/fluid/API.spec +++ b/paddle/fluid/API.spec @@ -337,10 +337,10 @@ paddle.fluid.layers.zeros_like (ArgSpec(args=['x', 'out'], varargs=None, keyword paddle.fluid.layers.ones_like (ArgSpec(args=['x', 'out'], varargs=None, keywords=None, defaults=(None,)), ('document', 'd18d42059c6b189cbd3fab2fcb206c15')) paddle.fluid.layers.diag (ArgSpec(args=['diagonal'], varargs=None, keywords=None, defaults=None), ('document', '10f13aae2f0d3db88353d3ec7db4869b')) paddle.fluid.layers.eye (ArgSpec(args=['num_rows', 'num_columns', 'batch_shape', 'dtype'], varargs=None, keywords=None, defaults=(None, None, 'float32')), ('document', '60cdc70ae43ba69fae36d720ef3016a1')) -paddle.fluid.layers.While ('paddle.fluid.layers.control_flow.While', ('document', '50110155608a00f43d3d3fd1be41dcb4')) +paddle.fluid.layers.While ('paddle.fluid.layers.control_flow.While', ('document', '9b1da3fab3636198e65a225e7f5f7b4f')) paddle.fluid.layers.While.__init__ (ArgSpec(args=['self', 'cond', 'is_test', 'name'], varargs=None, keywords=None, defaults=(False, None)), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) paddle.fluid.layers.While.block (ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) -paddle.fluid.layers.Switch ('paddle.fluid.layers.control_flow.Switch', ('document', 'a1c5ef8ff117d7d6ba8940ec104f02ce')) +paddle.fluid.layers.Switch ('paddle.fluid.layers.control_flow.Switch', ('document', '4eeaaf62a4b582b6c263c3b55326e1b3')) paddle.fluid.layers.Switch.__init__ (ArgSpec(args=['self', 'name'], varargs=None, keywords=None, defaults=(None,)), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) paddle.fluid.layers.Switch.case (ArgSpec(args=['self', 'condition'], varargs=None, keywords=None, defaults=None), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) paddle.fluid.layers.Switch.default (ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) @@ -355,7 +355,7 @@ paddle.fluid.layers.equal (ArgSpec(args=['x', 'y', 'cond'], varargs=None, keywor paddle.fluid.layers.not_equal (ArgSpec(args=['x', 'y', 'cond'], varargs=None, keywords=None, defaults=(None,)), ('document', '8b76aaac4ba7cf9111750b9c2c9418cb')) paddle.fluid.layers.array_read (ArgSpec(args=['array', 'i'], varargs=None, keywords=None, defaults=None), ('document', 'caf0d94349cdc28e1bda3b8a19411ac0')) paddle.fluid.layers.array_length (ArgSpec(args=['array'], varargs=None, keywords=None, defaults=None), ('document', '6f24a9b872027634ad758ea2826c9727')) -paddle.fluid.layers.IfElse ('paddle.fluid.layers.control_flow.IfElse', ('document', 'a389f88e19c3b332c3afcbf7df4488a5')) +paddle.fluid.layers.IfElse ('paddle.fluid.layers.control_flow.IfElse', ('document', '720054043e55273224682fdb6b9ad13b')) paddle.fluid.layers.IfElse.__init__ (ArgSpec(args=['self', 'cond', 'name'], varargs=None, keywords=None, defaults=(None,)), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) paddle.fluid.layers.IfElse.false_block (ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) paddle.fluid.layers.IfElse.input (ArgSpec(args=['self', 'x'], varargs=None, keywords=None, defaults=None), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) diff --git a/python/paddle/fluid/layers/control_flow.py b/python/paddle/fluid/layers/control_flow.py index a7ee246fecae6e44622b551f8033dac8ab45a744..3fdd22ceed7f4b074171c3fb51cf94672bbfc455 100644 --- a/python/paddle/fluid/layers/control_flow.py +++ b/python/paddle/fluid/layers/control_flow.py @@ -643,29 +643,34 @@ class WhileGuard(BlockGuard): class While(object): """ - while loop control flow. + while loop control flow. Repeat while body until cond is False. Args: - cond(Variable): condition used to compare. - is_test(bool): A flag indicating whether execution is in test phase. - name(str): The name of this layer. + cond(Variable): A Tensor whose data type is bool controlling whether to continue looping. + is_test(bool, optional): A flag indicating whether execution is in test phase. Default value is None. + 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` . Examples: .. code-block:: python import paddle.fluid as fluid - - i = fluid.layers.fill_constant(shape=[1], dtype='int64', value=0) - d0 = fluid.layers.data("d0", shape=[10], dtype='float32') - data_array = fluid.layers.array_write(x=d0, i=i) - array_len = fluid.layers.fill_constant(shape=[1],dtype='int64', value=3) + import numpy as np + + i = fluid.layers.fill_constant(shape=[1], dtype='int64', value=0) # loop counter + + loop_len = fluid.layers.fill_constant(shape=[1],dtype='int64', value=10) # loop length - cond = fluid.layers.less_than(x=i, y=array_len) + cond = fluid.layers.less_than(x=i, y=loop_len) while_op = fluid.layers.While(cond=cond) - with while_op.block(): - d = fluid.layers.array_read(array=data_array, i=i) + with while_op.block(): i = fluid.layers.increment(x=i, value=1, in_place=True) - fluid.layers.less_than(x=i, y=array_len, cond=cond) + fluid.layers.less_than(x=i, y=loop_len, cond=cond) + + exe = fluid.Executor(fluid.CPUPlace()) + exe.run(fluid.default_startup_program()) + + res = exe.run(fluid.default_main_program(), feed={}, fetch_list=[i]) + print(res) # [array([10])] """ BEFORE_WHILE_BLOCK = 0 @@ -1464,18 +1469,35 @@ class ConditionalBlock(object): class Switch(object): """ - Switch class works just like a `if-elif-else`. Can be used in learning rate scheduler - to modify learning rate - The Semantics: + This class is used to implement Switch branch control function. + Switch branch contains several case branches and one default branch. + Switch control flow checks whether the case branch conditions are satisfied in turn, + and only executes the statement after the first case branch that satisfies the conditions. + If there is no case branch that satisfies the condition, + only the statement following the default branch is executed. - 1. A `switch` control-flow checks cases one-by-one. + Member Functions: + case(cond): The case branch of Switch whose parameter cond is a scalar Variable of bool type. Only if the cond of the current case branch is True and the cond of the previous case branch is False, the statement after the case branch will be executed, and the statement after the case branch will not be executed. + + default(): The default branch of Switch. When cond of all case branches is False, the statement after default branch is executed. - 2. The condition of each case is a boolean value, which is a scalar Variable. + Case and default functions can only be used inside the scope of Switch, as shown below: - 3. It runs the first matched case, or the default case if there is one. + .. code-block:: python + + ''' + with fluid.layers.Switch() as switch: + with switch.case(cond1): + i = fluid.layers.fill_constant(shape=[1], dtype='int64', value=1) + with switch.case(cond2): + i = fluid.layers.fill_constant(shape=[1], dtype='int64', value=2) + with switch.default(): + i = fluid.layers.fill_constant(shape=[1], dtype='int64', value=0) + ''' - 4. Once it matches a case, it runs the corresponding branch and only that branch. + Args: + 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` . Examples: .. code-block:: python @@ -1489,14 +1511,13 @@ class Switch(object): persistable=True, name="learning_rate") zero_var = fluid.layers.fill_constant( - shape=[1], dtype='float32', value=0.0) + shape=[1], dtype='float32', value=0.0) one_var = fluid.layers.fill_constant( shape=[1], dtype='float32', value=1.0) two_var = fluid.layers.fill_constant( - shape=[1], dtype='float32', value=2.0) + shape=[1], dtype='float32', value=2.0) - global_step = fluid.layers.autoincreased_step_counter( - counter_name='@LR_DECAY_COUNTER@', begin=0, step=1) + global_step = fluid.layers.autoincreased_step_counter(counter_name='@LR_DECAY_COUNTER@', begin=0, step=1) with fluid.layers.control_flow.Switch() as switch: with switch.case(global_step == zero_var): @@ -1504,6 +1525,11 @@ class Switch(object): with switch.default(): fluid.layers.assign(input=two_var, output=lr) + exe = fluid.Executor(fluid.CPUPlace()) + exe.run(fluid.default_startup_program()) + + res = exe.run(fluid.default_main_program(), feed={}, fetch_list=[lr]) + print(res) # [array([1.], dtype=float32)] """ def __init__(self, name=None): @@ -1592,36 +1618,72 @@ class IfElseBlockGuard(object): class IfElse(object): """ - if-else control flow. + This class is used to implement IfElse branch control function. IfElse contains two blocks, true_block and false_block. IfElse will put data satisfying True or False conditions into different blocks to run. + + Cond is a 2-D Tensor with shape [N, 1] and data type bool, representing the execution conditions of the corresponding part of the input data. + + IfElse OP is different from other OPs in usage, which may cause some users confusion. Here is a simple example to illustrate this OP. + + .. code-block:: python + + # The following code completes the function: subtract 10 from the data greater than 0 in x, add 10 to the data less than 0 in x, and sum all the data. + import numpy as np + import paddle.fluid as fluid + + x = fluid.layers.data(name='x', shape=[4, 1], dtype='float32', append_batch_size=False) + y = fluid.layers.data(name='y', shape=[4, 1], dtype='float32', append_batch_size=False) + + x_d = np.array([[3], [1], [-2], [-3]]).astype(np.float32) + y_d = np.zeros((4, 1)).astype(np.float32) + + # Compare the size of x, y pairs of elements, output cond, cond is shape [4, 1], data type bool 2-D tensor. + # Based on the input data x_d, y_d, it can be inferred that the data in cond are [[true], [true], [false], [false]]. + cond = fluid.layers.greater_than(x, y) + # Unlike other common OPs, ie below returned by the OP is an IfElse OP object + ie = fluid.layers.IfElse(cond) + + with ie.true_block(): + # In this block, according to cond condition, the data corresponding to true dimension in X is obtained and subtracted by 10. + out_1 = ie.input(x) + out_1 = out_1 - 10 + ie.output(out_1) + with ie.false_block(): + # In this block, according to cond condition, get the data of the corresponding condition in X as false dimension, and add 10 + out_1 = ie.input(x) + out_1 = out_1 + 10 + ie.output(out_1) + + # According to cond condition, the data processed in the two blocks are merged. The output here is output, the type is List, and the element type in List is Variable. + output = ie() # [array([[-7.], [-9.], [ 8.], [ 7.]], dtype=float32)] + + # Get the first Variable in the output List and add all elements. + out = fluid.layers.reduce_sum(output[0]) + + exe = fluid.Executor(fluid.CPUPlace()) + exe.run(fluid.default_startup_program()) + + res = exe.run(fluid.default_main_program(), feed={"x":x_d, "y":y_d}, fetch_list=[out]) + print res + # [array([-1.], dtype=float32)] Args: - cond (Variable): condition used to compare. - name (str, default None): The name of this layer. + cond (Variable): cond is a 2-D Tensor with shape [N, 1] and data type bool, representing the corresponding execution conditions of N input data. The data type is bool. + 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` . - Examples: - .. code-block:: python + Returns: + Unlike other common OPs, the OP call returns an IfElse OP object (e.g. ie in the example), which branches the input data by calling the internal functions of the object ``true_block ()``, ``false_block ()``, ``input ()``, ``output ()``, and integrates the data processed by different branches as the overall output by calling the internal ``call ()`` function. The output type is a list, and the type of each element in the list is Variable. - import paddle.fluid as fluid + Internal Functions: + The block is constructed by calling the ``with ie. true_block()`` function in the object, and the computational logic under condition true is put into the block. If no corresponding block is constructed, the input data in the corresponding conditional dimension is unchanged. + + The block is constructed by calling the ``with ie. false_block()`` function in the object, and the computational logic under condition false is put into the block. If no corresponding block is constructed, the input data in the corresponding conditional dimension is unchanged. + + ``Out = ie. input (x)`` will take out the data of the corresponding conditional dimension in X and put it into out, supporting the internal processing of multiple inputs in block. + + ``ie. output (out)`` writes the result to the output of the corresponding condition. + + There is a ``call ()`` function inside the object, that is, by calling ``output = ie ()``, all the outputs inside the block of False are fused as the whole output, the output type is a list, and the type of each element in the list is Variable. - image = fluid.layers.data(name="X", shape=[2, 5, 5], dtype='float32') - label = fluid.layers.data(name='label', shape=[1], dtype='int64') - limit = fluid.layers.fill_constant_batch_size_like( - input=label, dtype='int64', shape=[1], value=5.0) - cond = fluid.layers.less_than(x=label, y=limit) - ie = fluid.layers.IfElse(cond) - with ie.true_block(): - true_image = ie.input(image) - hidden = fluid.layers.fc(input=true_image, size=100, act='tanh') - prob = fluid.layers.fc(input=hidden, size=10, act='softmax') - ie.output(prob) - - with ie.false_block(): - false_image = ie.input(image) - hidden = fluid.layers.fc( - input=false_image, size=200, act='tanh') - prob = fluid.layers.fc(input=hidden, size=10, act='softmax') - ie.output(prob) - prob = ie() """ OUT_IF_ELSE_BLOCKS = 0 IN_IF_ELSE_TRUE_BLOCKS = 1