o
    Me›  ã                   @   sD   d dl mZ d dl mZ d dlmZ d dlZg Zejddd„ƒZdS )	é    )Úcore)Ú	framework)Úgradients_with_optimizerNFc                 C   sü   dd„ }|| dƒ} t | ƒt t| ƒƒksJ dƒ‚|dur=t|ttfƒs%|g}|D ]}|dur;t|tjtjjfƒs;J dƒ‚q'nt	j
rCg }ndgt | ƒ }t |ƒdkr\t | ƒt |ƒks\J dƒ‚t|tƒseJ d	ƒ‚t	j
rrtj | ||¡ dS t | ||t	 ¡ ¡ dS )
aÈ  
    Compute the backward gradients of given tensors.
    
    Args:
        tensors(list of Tensors): the tensors which the gradient to be computed. The tensors can not contain the same tensor.

        grad_tensors(list of Tensors of None, optional): the init gradients of the `tensors`` .If not None, it must have the same length with ``tensors`` ,
            and if any of the elements is None, then the init gradient is the default value which is filled with 1.0. 
            If None, all the gradients of the ``tensors`` is the default value which is filled with 1.0.
            Defaults to None.

        retain_graph(bool, optional): If False, the graph used to compute grads will be freed. If you would
            like to add more ops to the built graph after calling this method( :code:`backward` ), set the parameter
            :code:`retain_graph` to True, then the grads will be retained. Thus, seting it to False is much more memory-efficient.
            Defaults to False.
    
    Returns:
        NoneType: None


    Examples:
        .. code-block:: python

            import paddle
            x = paddle.to_tensor([[1, 2], [3, 4]], dtype='float32', stop_gradient=False)
            y = paddle.to_tensor([[3, 2], [3, 4]], dtype='float32')

            grad_tensor1 = paddle.to_tensor([[1,2], [2, 3]], dtype='float32')
            grad_tensor2 = paddle.to_tensor([[1,1], [1, 1]], dtype='float32')

            z1 = paddle.matmul(x, y)
            z2 = paddle.matmul(x, y)

            paddle.autograd.backward([z1, z2], [grad_tensor1, grad_tensor2], True)
            print(x.grad)
            #[[12. 18.]
            # [17. 25.]]

            x.clear_grad()

            paddle.autograd.backward([z1, z2], [grad_tensor1, None], True)
            print(x.grad)
            #[[12. 18.]
            # [17. 25.]]

            x.clear_grad()

            paddle.autograd.backward([z1, z2])
            print(x.grad)
            #[[10. 14.]
            # [10. 14.]]

    c                 S   s–   | d usJ d  |¡ƒ‚t| ttfƒr7t| ƒdksJ d  |¡ƒ‚| D ]}t|tjtjjfƒs4J d  |¡ƒ‚q!| S t| tjtjjfƒsHJ d  |¡ƒ‚| gS )Nz{} should not be Noner   z{} connot be empytz$Elements of {} must be paddle.Tensorz#{} must be Tensor or list of Tensor)	ÚformatÚ
isinstanceÚlistÚtupleÚlenÚpaddleÚTensorr   Úeager)Zin_out_listÚnameZeach_var© r   úMD:\Projects\ConvertPro\env\Lib\site-packages\paddle/autograd/backward_mode.pyÚcheck_tensorsO   s$   þýþýzbackward.<locals>.check_tensorsÚtensorsz[The argument 'tensors' of paddle.autograd.backward contains duplicate paddle.Tensor object.Nz„The argument 'grad_tensors' of paddle.autograd.backward is invalid, it can be 'None', 'paddle.Tensor' or 'list[None/paddle.Tensor]'.r   z3The length of grad_tensors must be equal to tensorsz"retain_graph must be True or False)r	   Úsetr   r   r   r
   r   r   r   r   Z_in_eager_mode_ÚboolZrun_backwardZdygraph_run_backwardZ_dygraph_tracer)r   Zgrad_tensorsZretain_graphr   Zeach_tensorr   r   r   Úbackward   sD   8
ÿþÿþ€þÿÿ
ÿr   )NF)	Zpaddle.fluidr   r   Zpaddle.fluid.backwardr   r
   Ú__all__Zdygraph_onlyr   r   r   r   r   Ú<module>   s   