.. _cn_api_fluid_Variable:

Variable
-------------------------------

.. py:class:: paddle.fluid.Variable

**注意：**
  **1. 请不要直接调用** `Variable` **的构造函数，因为这会造成严重的错误发生！**

  **2. 在静态图形模式下：请使用** `Block.create_var` **创建一个静态的** `Variable` **，该静态的** `Variable` **在使用** :ref:`cn_api_fluid_executor` **执行前是没有实际数据的。**

  **3. 在** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下：请使用** :ref:`cn_api_fluid_dygraph_to_variable` 创建一个拥有实际数据的 :ref:`api_guide_Variable`

在Fluid中，OP的每个输入和输出都是 :ref:`api_guide_Variable` 。多数情况下， :ref:`api_guide_Variable` 用于保存不同种类的数据或训练标签。

:ref:`api_guide_Variable` 总是属于某一个 :ref:`api_guide_Block` 。所有 :ref:`api_guide_Variable` 都有其自己的 ``name`` ,不同 :ref:`api_guide_Block` 中的两个 :ref:`api_guide_Variable` 可以具有相同的名称。如果使用的 **不是** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ 模式，那么同一个 :ref:`api_guide_Block` 中的两个或更多 :ref:`api_guide_Variable` 拥有相同 ``name`` 将意味着他们会共享相同的内容。通常我们使用这种方式来实现 **参数共享**

:ref:`api_guide_Variable` 有很多种。它们每种都有自己的属性和用法。请参考 `framework.proto <https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/fluid/framework/framework.proto>`_ 以获得详细信息。 :ref:`api_guide_Variable` 的大多数成员变量可以设置为 ``None``。它的意思是它不可用或稍后指定。

如果您希望创建一个 :ref:`api_guide_Variable` 那么可以参考如下示例：

**示例代码：**

在静态图形模式下：
    .. code-block:: python

        import paddle.fluid as fluid
        cur_program = fluid.Program()
        cur_block = cur_program.current_block()
        new_variable = cur_block.create_var(name="X",
                                            shape=[-1, 23, 48],
                                            dtype='float32')
在 `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ 模式下：
    .. code-block:: python

        import paddle.fluid as fluid
        import numpy as np
        with fluid.dygraph.guard():
            new_variable = fluid.dygraph.to_variable(np.arange(10))


.. py:method:: detach()

**注意：**

  **1. 该API只在** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下生效**

  **2.** ``detach`` **后的**  :ref:`api_guide_Variable` **将会成为临时变量**

产生一个新的，和当前计算图分离的，但是拥有当前 :ref:`api_guide_Variable` 其内容的临时变量

返回：一个新的，和当前计算图分离的，但是拥有当前 :ref:`api_guide_Variable` 其内容的临时 :ref:`api_guide_Variable`

返回类型：（:ref:`api_guide_Variable` | 和输入的 ``Dtype`` 一致）

**示例代码**
  .. code-block:: python

     import paddle.fluid as fluid
     from paddle.fluid.dygraph.base import to_variable
     from paddle.fluid.dygraph import Linear
     import numpy as np

     data = np.random.uniform(-1, 1, [30, 10, 32]).astype('float32')
     with fluid.dygraph.guard():
           linear = Linear(32, 64)
           data = to_variable(data)
           x = linear(data)
           y = x.detach()

.. py:method:: numpy()

**注意：**

  **1. 该API只在** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下生效**


返回一个 ``ndarray`` 来表示当前  :ref:`api_guide_Variable` 的值

返回：``numpy`` 的数组，表示当前 :ref:`api_guide_Variable` 的实际值

返回类型：ndarray，``dtype`` 和输入的 ``dtype`` 一致

**示例代码**
  .. code-block:: python

    import paddle.fluid as fluid
    from paddle.fluid.dygraph.base import to_variable
    from paddle.fluid.dygraph import Linear
    import numpy as np

    data = np.random.uniform(-1, 1, [30, 10, 32]).astype('float32')
    with fluid.dygraph.guard():
        linear = Linear(32, 64)
        data = to_variable(data)
        x = linear(data)
        print(x.numpy())

.. py:method:: set_value()

**注意：**

  **1. 该API只在** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下生效**

为此 :ref:`api_guide_Variable` 设置一个新的值。

**参数:**

  - **value**: ( :ref:`api_guide_Variable` 或 ``ndarray`` ) 要赋值给此 :ref:`api_guide_Variable` 的新的值。

返回：无

抛出异常： ``ValueError`` - 当要赋于的新值的 ``shape`` 和此 :ref:`api_guide_Variable` 原有的 ``shape`` 不同时，抛出 ``ValueError`` 。

**示例代码**
  .. code-block:: python

        import paddle.fluid as fluid
        from paddle.fluid.dygraph.base import to_variable
        from paddle.fluid.dygraph import Linear
        import numpy as np

        data = np.ones([3, 1024], dtype='float32')
        with fluid.dygraph.guard():
            linear = fluid.dygraph.Linear(1024, 4)
            t = to_variable(data)
            linear(t)  # 使用默认参数值调用前向
            custom_weight = np.random.randn(1024, 4).astype("float32")
            linear.weight.set_value(custom_weight)  # 将参数修改为自定义的值
            out = linear(t)  # 使用新的参数值调用前向

.. py:method:: backward()

**注意：**

  **1. 该API只在** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下生效**

  **2. 由于如果该**  :ref:`api_guide_Variable` **以上没有任何地方需要梯度，那么仅仅设置该**  :ref:`api_guide_Variable` **的梯度为** ``1`` **是没有意义的。因此，这种情况下，为了节省一些计算，我们不去产生该** :ref:`api_guide_Variable` **的梯度**

从该节点开始执行反向

**参数:**

  - **backward_strategy**: ( :ref:`cn_api_fluid_dygraph_BackwardStrategy` ) 使用何种 :ref:`cn_api_fluid_dygraph_BackwardStrategy`  聚合反向的梯度

返回：无


**示例代码**
  .. code-block:: python

        import paddle.fluid as fluid
        import numpy as np

        x = np.ones([2, 2], np.float32)
        with fluid.dygraph.guard():
            inputs2 = []
            for _ in range(10):
                tmp = fluid.dygraph.base.to_variable(x)
                # 如果这里我们不为输入tmp设置stop_gradient=False，那么后面loss2也将因为这个链路都不需要梯度
                # 而不产生梯度
                tmp.stop_gradient=False
                inputs2.append(tmp)
            ret2 = fluid.layers.sums(inputs2)
            loss2 = fluid.layers.reduce_sum(ret2)
            backward_strategy = fluid.dygraph.BackwardStrategy()
            backward_strategy.sort_sum_gradient = True
            loss2.backward(backward_strategy)

.. py:method:: gradient()

**注意：**

  **1. 该API只在** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下生效**

  **2. 由于如果该**  :ref:`api_guide_Variable` **以上没有任何地方需要梯度，那么仅仅设置该**  :ref:`api_guide_Variable` **的梯度为** ``1`` **是没有意义的。因此，这种情况下，为了节省一些计算，我们不去产生该** :ref:`api_guide_Variable` **的梯度**

获取该 :ref:`api_guide_Variable` 的梯度值

返回：如果 :ref:`api_guide_Variable` 的类型是LoDTensor（参见 :ref:`cn_user_guide_lod_tensor` ），返回该 :ref:`api_guide_Variable` 类型为 ``ndarray`` 的梯度值；如果 :ref:`api_guide_Variable` 的类型是SelectedRows，返回该 :ref:`api_guide_Variable` 类型为 ``ndarray`` 的梯度值和类型为 ``ndarray`` 的词id组成的tuple。

返回类型：``ndarray`` 或者 ``tuple of ndarray`` , 返回类型 ``tuple of ndarray`` 仅在 :ref:`cn_api_fluid_dygraph_Embedding` 层稀疏更新时产生。


**示例代码**
  .. code-block:: python

        import paddle.fluid as fluid
        import numpy as np

        # example1: 返回ndarray
        x = np.ones([2, 2], np.float32)
        with fluid.dygraph.guard():
            inputs2 = []
            for _ in range(10):
                tmp = fluid.dygraph.base.to_variable(x)
                tmp.stop_gradient=False
                inputs2.append(tmp)
            ret2 = fluid.layers.sums(inputs2)
            loss2 = fluid.layers.reduce_sum(ret2)
            backward_strategy = fluid.dygraph.BackwardStrategy()
            backward_strategy.sort_sum_gradient = True
            loss2.backward(backward_strategy)
            print(loss2.gradient())

        # example2: 返回tuple of ndarray
        with fluid.dygraph.guard():
            embedding = fluid.dygraph.Embedding(
                size=[20, 32],
                param_attr='emb.w',
                is_sparse=True)
            x_data = np.arange(12).reshape(4, 3).astype('int64')
            x_data = x_data.reshape((-1, 3, 1))
            x = fluid.dygraph.base.to_variable(x_data)
            out = embedding(x)
            out.backward()
            print(embedding.weight.gradient())

.. py:method:: clear_gradient()

**注意：**

  **1. 该API只在** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下生效**

  **2. 只有当该** :ref:`api_guide_Variable` **有梯度时才可调用，通常我们都会为参数调用这个方法，因为临时变量的梯度将会在其离开作用域时被** ``python`` **自动清除**

设置该 :ref:`api_guide_Variable` 的梯度为零

返回：无


**示例代码**
  .. code-block:: python

        import paddle.fluid as fluid
        import numpy as np

        x = np.ones([2, 2], np.float32)
        with fluid.dygraph.guard():
            inputs2 = []
            for _ in range(10):
                tmp = fluid.dygraph.base.to_variable(x)
                tmp.stop_gradient=False
                inputs2.append(tmp)
            ret2 = fluid.layers.sums(inputs2)
            loss2 = fluid.layers.reduce_sum(ret2)
            backward_strategy = fluid.dygraph.BackwardStrategy()
            backward_strategy.sort_sum_gradient = True
            loss2.backward(backward_strategy)
            print(loss2.gradient())
            loss2.clear_gradient()
            print("After clear {}".format(loss2.gradient()))


.. py:method:: to_string()

**注意：**

  **1. 该API只在非** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下生效**

获取该 :ref:`api_guide_Variable` 的静态描述字符串

**参数：（仅在非** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下生效）**
 - **throw_on_error** (bool) - 是否在没有设置必需字段时抛出异常。
 - **with_details** (bool) - 值为true时，打印更多关于 :ref:`api_guide_Variable` 的信息，如 ``error_clip`` , ``stop_gradient`` 等


返回：用于静态描述该 :ref:`api_guide_Variable` 的字符串


返回： 将Program转换为字符串

返回类型： str

抛出异常： ``ValueError`` - 当 ``throw_on_error == true`` ，当没有设置任何必需的字段时，抛出 ``ValueError`` 。


**示例代码**
  .. code-block:: python

        import paddle.fluid as fluid

        cur_program = fluid.Program()
        cur_block = cur_program.current_block()
        new_variable = cur_block.create_var(name="X",
                                            shape=[-1, 23, 48],
                                            dtype='float32')
        print(new_variable.to_string(True))
        print("\n=============with detail===============\n")
        print(new_variable.to_string(True, True))


.. py:method:: astype(self, dtype)

将该 :ref:`api_guide_Variable` 中的数据转换成目标 ``Dtype``

**参数：**
 - **self** ( :ref:`api_guide_Variable` ) - 当前 :ref:`api_guide_Variable` ， 用户不需要传入。
 - **dtype** (int | float | float64) - 希望转换成的 ``Dtype``


返回：一个全新的转换了 ``Dtype`` 的 :ref:`api_guide_Variable`

返回类型： :ref:`api_guide_Variable`


**示例代码**

在静态图模式下：
    .. code-block:: python

        import paddle.fluid as fluid

        startup_prog = fluid.Program()
        main_prog = fluid.Program()
        with fluid.program_guard(startup_prog, main_prog):
            original_variable = fluid.data(name = "new_variable", shape=[2,2], dtype='float32')
            new_variable = original_variable.astype('int64')
            print("new var's dtype is: {}".format(new_variable.dtype))


在 `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ 模式下：
    .. code-block:: python

        import paddle.fluid as fluid
        import numpy as np

        x = np.ones([2, 2], np.float32)
        with fluid.dygraph.guard():
            original_variable = fluid.dygraph.to_variable(x)
            print("original var's dtype is: {}, numpy dtype is {}".format(original_variable.dtype, original_variable.numpy().dtype))
            new_variable = original_variable.astype('int64')
            print("new var's dtype is: {}, numpy dtype is {}".format(new_variable.dtype, new_variable.numpy().dtype))



属性
::::::::::::

.. py:attribute:: stop_gradient

**注意：该属性在** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下除参数以外默认值为** ``True`` **，而参数的该属性默认值为** ``False`` **。在静态图下所有的** :ref:`api_guide_Variable` **该属性默认值都为** ``False``

是否从此 :ref:`api_guide_Variable` 开始，之前的相关部分都停止梯度计算

**示例代码**
  .. code-block:: python

        import paddle.fluid as fluid

        with fluid.dygraph.guard():
            value0 = np.arange(26).reshape(2, 13).astype("float32")
            value1 = np.arange(6).reshape(2, 3).astype("float32")
            value2 = np.arange(10).reshape(2, 5).astype("float32")
            linear = fluid.Linear(13, 5, dtype="float32")
            linear2 = fluid.Linear(3, 3, dtype="float32")
            a = fluid.dygraph.to_variable(value0)
            b = fluid.dygraph.to_variable(value1)
            c = fluid.dygraph.to_variable(value2)
            out1 = linear(a)
            out2 = linear2(b)
            out1.stop_gradient = True
            out = fluid.layers.concat(input=[out1, out2, c], axis=1)
            out.backward()
            # 可以发现这里linear的参数变成了
            assert (linear.weight.gradient() == 0).all()
            assert (out1.gradient() == 0).all()

.. py:attribute:: persistable

**注意：该属性我们即将废弃，此介绍仅为了帮助用户理解概念， 1.6版本后用户可以不再关心该属性**

  **1. 该属性除参数以外默认值为** ``False`` **，而参数的该属性默认值为** ``True`` 。

  **2. 该属性在** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下一经初始化即不能修改，这是由于在动态执行时，**  :ref:`api_guide_Variable` **的生命周期将由** ``Python`` **自行控制不再需要通过该属性来修改**

此 :ref:`api_guide_Variable` 是否是长期存活的 :ref:`api_guide_Variable`

.. py:attribute:: name

**注意：在非** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下，那么同一个** :ref:`api_guide_Block` **中的两个或更多** :ref:`api_guide_Variable` **拥有相同** ``name`` **将意味着他们会共享相同的内容。通常我们使用这种方式来实现参数共享**

此 :ref:`api_guide_Variable` 的名字（str）


.. py:attribute:: shape

**注意：该属性是只读属性**

此 :ref:`api_guide_Variable` 的维度

.. py:attribute:: dtype

**注意：该属性是只读属性**

此 :ref:`api_guide_Variable` 的实际数据类型

.. py:attribute:: lod_level

**注意：**

  **1. 该属性是只读属性**

  **2.** `Dygraph <../../user_guides/howto/dygraph/DyGraph.html>`_ **模式下，不支持该属性，该值为零**

此 :ref:`api_guide_Variable` 的 ``LoD`` 信息，关于 ``LoD`` 可以参考 :ref:`api_fluid_LoDTensor` 相关内容

.. py:attribute:: type

**注意：该属性是只读属性**

此 :ref:`api_guide_Variable` 的内存模型，例如是：:ref:`api_fluid_LoDTensor`， 或者SelectedRows
