o
     jS                     @   s  d dl Z d dlZd dlmZ d dlZd dlmZmZ d dl	m
Z
mZ 	 g dZd1ddZd	d
 Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Z			+	,	+	d2d-d.Zd3d/d0Z dS )4    N)Sequence)Statedynamic_shape_prim_vjp_guard)build_pipe_for_blockget_used_external_value)gradcalc_gradientcalc_gradient_helper c                 C   s8   t | |std| d| d| dt|  d| 
d S )NzThe type of 'z' in z	 must be z, but received z. )
isinstance	TypeErrortype)inputZ
input_nameexpected_typeZop_nameZextra_message r   \/var/www/html/Deteccion_Ine/venv/lib/python3.10/site-packages/paddle/autograd/ir_backward.py
check_type"   s
   
$r   c                 C   s$   | d u rg S t | trt| S | gS N)r   r   list)xr   r   r   _as_list)   s   r   c                 C   sH   |D ]}|   | krtdq|D ]}|   | kr!tdqd S )Nz%all outputs must be in the same blockz1all inputs must be in the same block with outputs)get_defining_opget_parent_block
ValueError)blockinputsoutputsoutputr   r   r   r   check_all_puts/   s   r   c                 C   sT   t j|| |jd}| }|d }t||j|  ||g |gg|j|< |S )N)dtype   )paddleZ	full_liker   r   operand_sourceupdate_bwdop_structureop_to_opgradvalue_to_valuegrad)float_valuevaluestatebackward_ops
value_gradZfull_like_opZfull_opr   r   r   append_full_like:   s   r+   c                 C   s   |   dv r
t| S |  S )N)pd_op.ifpd_op.while)namer   operands_source)opr   r   r   get_real_op_inputsK   s   r1   c                 C   s6   | j D ]}| D ]}|jr||vr|| q	qd S r   )opsresultsZstop_gradientadd)r   no_grad_setr0   r'   r   r   r   "update_no_grad_set_by_stopgradientR   s   

r6   c                 C   s"   |D ]}|  | | | qd S r   )append)r)   Zop_to_opgrad_listZgrad_op_listgrad_opr   r   r   r#   Y   s   
r#   c                 C   s  | s	dgt | } t | t |krtdg }t| D ]W\}}|| }|du r/td||| q|j|jkrEtd|t|j|t|jf |j|jkr[td|t|j|t|jf | }t||j	|  |g |gg|j
|< q|}| }	t }
|D ]B}||
v rq||  D ]4}||j
v r|
| qtj|rtj gg|j
|< qtd|||}|
| || |	| qq|||	|fS )a  
    if grad_outputs is none, add fill_1 op to create grad_outputs,
    else check whether outputs shape and dtype is same to grad_outputs, otherwise raise error.

    if only part of op's outputs in outputs, add fill_0 op to create other grad_outputs.
    eg: split.

    update value_to_valuegrad and op_to_opgrad.

    return complete_outputs and complete_gradoutputs, backward_ops.

    Nz7grad_outputs should have the same length of as outputs.g      ?zPThe shape of grad_output[%d] %s should be the same as the shape of output[%d] %szPThe dtype of grad_output[%d] %s should be the same as the dtype of output[%d] %s        )lenr   	enumerater+   shapestrr   r   r#   r$   r%   setr3   r4   r!   pirZis_fake_op_resultZfake_op_resultr7   )grad_outputsr   r(   r)   ir   r   Zfeedopcomplete_outputsZcomplete_gradoutputsZvisited_outputZopresultZ
grad_valuer   r   r   prepare_grad_outputs_   sf   





rC   c                 C   s    dd }|| ||@ rdS dS )Nc                 S   s<   t  }| D ]}t|tjjr||  q|| q|S r   )r>   r   r!   r?   Z	OpOperandr4   source)values	value_setitemr   r   r   operand2value   s   z"some_in_set.<locals>.operand2valueTFr   )Z
value_listrF   rH   r   r   r   some_in_set   s   	rI   c                    s  dgt   dgt  |rEtD ]0\}}t| |r$d|< qtt||r@d|< | D ]}||vr>|| q3qd |< qtttD ](\}}t| |rmd|< t|D ]}||vrk|| q`qMd|< d |< qMt}t|D ]-\}}| du r| D ]}	|	 r|		 
 }
|
v r||
 du rd|< qqq~ fddtt D }fddttt D }||fS )z
    prune ops which do not in the path from inputs_set to outputs_set,
    prune ops which do not in the path from outputs_set to inputs_set,

    pruned op in total_ops is uneffective_ops, else is effective_ops

    TFc                    s   g | ]
} | r| qS r   r   .0rA   )intersection_op_flags	total_opsr   r   
<listcomp>   s
    zprune_ops.<locals>.<listcomp>c                    s   g | ]
}| s | qS r   r   rJ   )rM   union_op_flagsr   r   rN      s    )r:   r;   rI   r3   r1   r4   reversedr   Zhas_one_use	first_useownerindexrange)rM   
inputs_setoutputs_setr5   rA   r0   r'   operandZtotal_ops_listresultZnext_opZeffective_opsZuneffective_opsr   )rL   rM   rO   r   	prune_ops   s\   




rY   c                 C   s   t |}|r8| jD ]}tt||r"| D ]}||vr!|| qq	|D ]}t|D ]}||vr6|| q+q%t |}t  }	t|D ],}| D ]}
|
|vr^t|
gt t|s^|	|
 qIt|D ]}||vrn|| qcqC||	 dS )z
    update no_grad_set after forward prune

    from inputs to outputs add value not in the path to no_grad_set,
    from outputs to inputs add value not in the path to no_grad_set,
    N)r>   r2   rI   r1   r3   r4   rP   update)r   effective_forward_opsr5   r   r   rU   r0   r'   rV   Zno_grad_set_tmpr   r   r   r   r   update_no_grad_set_after_prune   s:   	





r\   c                 C   s   t t}t| }g }| D ]}t|D ]}|r'| |v r'||   d7  < qqt  }| D ]}|| dkr<|| q/|rh| }|| t|D ]}| }||  d8  < || dkre|| qL|s?t	|t	| krtt
d|S )zH
    if topo graph is op1 -> op2 -> op3
    return [op3, op2, op1]

    r    r   zHinverse_sort_op wrong, sorted_list size is not equal to origin_list size)collectionsdefaultdictintr>   r1   r   dequer7   popleftr:   r   )r2   Zpending_countZops_setsorted_listr0   r   queueZx_opr   r   r   inverse_sort_op   s:   





rd   c
           (         s4  	fdd  	fddfdd	
fdd
 	fd	d
}
i i }t |dkrZ|d  dkrZ|d }t|  | D ]\}}||< qJ|dd }n|}t|}g }|D ] dkrw dkrw| qd |D ]ttjj	
r\}}}\}} dkrt| tjj	||||}W d   n1 sw   Y  jd }|g}t|dd |dd D ]\}}|d |d < |d ||d < qnt |dkst|rq~ dks dkrqt} D ]}t| qt| tjj	||||}W d   n	1 s+w   Y  jd }|g}t | D ](\} }!	| }" }#g }$tdd |D dd |D | |!| j|$|"|#
 qA
|| n?t j}%t| tjj	||||}W d   n	1 sw   Y  t j}&fddt|%|&D }
|  t	j | q~ dkr dkr D ]}'t 	j|' dkrވ |' qg 	j< qq~td  g 	j< q~|kr|
|| W d   dS W d   dS 1 sw   Y  dS )a8  
    add grad_op in order of topological inverse sort
        eg:
        from :op1 -> v1 -> op2 -> v2 -> op3 -> v3
        to: og1_g <- v1_g <- op2_g <- v2_g <- op3_g <- v3_g

    if op has grad_op, prepare its grad_op's inputs by value_to_valuegrad,
        eg:
        value_to_valuegrad[v3] = [[v3_g]];
        v2_g = call_vjp(op3, [[v2]], [[v3]],[[v3_g]], [[v2_stopgradient]])


    special pattern 1:
        v11 -> combine_op -> v1 -> op -> v3
        v12 ->
                             v2 ->
        value_to_valuegrad[v3] = [[v3_g]]

        v1 is inside python api, we don't describe it in backward process(state)
        so v1_grad is inside vjp, we don't describe it in backward process(state)
        [[v11_g, v12_g], v2_g] = call_vjp(combine_op, [[v11, v12]], [[v3]],[[v3_g]], [[v11_stopgradient, v12_stopgradient], v2_stop_gradient])


        op_vjp is:
        v11_g <- split_op <- v1_g <- op_g <- v3_g
        v12_g <-
                             v2_g <-

        value_to_valuegrad[v11] = [[v11_g]]
        value_to_valuegrad[v12] = [[v12_g]]
        value_to_valuegrad[v2] = [[v2_g]]

    if op don't has grad_op:
        if it don't has input and it's output has more than
        one output_grad, add sumop for grad aggregation.
        (eg: full op and parameter op etc.)

        else continue to next op.
    c                    sx   t dd j|  D }| }|d }t j ||g j|  D ]
}j|  | q(|ggj| < d S )Nc                 S      g | ]}|d  qS r   r   )rK   rG   r   r   r   rN         z=append_backward_ops.<locals>.append_add_n.<locals>.<listcomp>r   )	r!   Zadd_nr%   r   r"   r#   r$   value_to_sumvaluegradr7   )r'   Zadd_n_valueZadd_n_opZ
combine_optmp)r)   r0   r(   r   r   append_add_n~  s   z)append_backward_ops.<locals>.append_add_nc                    s>  dg|    }g }g }t|  D ]\}}|v r| gn|g}|v r-| }|v s%|jv r?tj| dkr? | |jvsKj| g kr| s|   dkr|  \}}}	t	|||< dd |	D }
|
gj|< dd |D }nt
d| d||< || |j| d	  q|||fS )
NFr    builtin.splitc                 S   re   rf   r   )rK   r'   r   r   r   rN     rg   zMappend_backward_ops.<locals>.make_output_with_output_grad.<locals>.<listcomp>c                 S   re   rf   r   rK   infor   r   r   rN     rg   r9   Tr   )num_resultsr;   r3   r%   r:   	use_emptyrQ   rR   r.   allr+   r7   )r0   	zero_flagr   output_gradsrA   r'   	new_valueZsplit_zero_flagZsplit_outputsZsplit_output_gradZgrad_values)rj   r)   #control_flow_value_to_copyvalue_map!inside_value_to_outside_value_mapmake_output_with_output_gradr(   r   r   rv     sB   


	


z9append_backward_ops.<locals>.make_output_with_output_gradc           
         s~  g }g }|   dv rdd ttt| D }n|  }tt| |D ]\}}|sg| d urU|   dkrUg }|  D ]}|| v rK | n| q?|| n| v r^ | gn|g}|| q#| d ur|   dkr| \}}	|dd |D  |dd |	D  q#| v r | gn|g}|| | d u s|v r|dg q#|dg q#||fS )	N)builtin.combiner,   r-   cf.tuple_pushc                 S      g | ]}d qS Tr   rK   _r   r   r   rN     s    zSappend_backward_ops.<locals>.make_input_with_input_stopgradient.<locals>.<listcomp>rw   c                 S   re   rf   r   rl   r   r   r   rN     rg   c                 S   re   rf   r   rl   r   r   r   rN     rg   TF)	r.   rT   r:   r1   get_input_grad_semanticszipr   r/   r7   )
r0   r   input_grad_stopgradientsgrad_semantic_infor   grad_semanticZ	tmp_inputri   Zcombine_inputsZcombine_stop_gradient)rt   "make_input_with_input_stopgradientr5   r   r   r     s\   




z?append_backward_ops.<locals>.make_input_with_input_stopgradientc                    s   d}|   dks|   dks|   dkr dd tt|D }n|  }t||D ]C\}}|s0q)| d urM|   dkrM| || |   n|| }t|tr_ j	| 
| n	 j	| 
|g |d7 }q)d S )Nr   rw   r,   r-   c                 S   ry   rz   r   r{   r   r   r   rN     s    zFappend_backward_ops.<locals>.update_input_grad_map.<locals>.<listcomp>r    )r.   rT   r:   r}   r~   r   r/   r   r   r%   r7   )r0   input_gradsorigin_inputsrA   r   r   r   
input_grad)r(   update_input_grad_mapr   r   r   
  s,   


z2append_backward_ops.<locals>.update_input_grad_mapc                    s   | Y g }t ||D ]@\}}|d u rq
|v r| }|v s|jv r>tj| dkr1 | |j| d d  q
td|}|| q
tjjj	| W d    d S 1 s^w   Y  d S )Nr    r   r9   )
r~   r%   r:   r7   r+   r!   baseZ	libpaddler?   Zcf_yield)r   base_inputsZbase_inputs_gradinputs_gradr'   r*   )rj   r)   ru   r(   r   r   append_yield(  s$   
"z)append_backward_ops.<locals>.append_yieldr    zcf.yieldNrw   rk   rx   r   r,   r-   c                 S   re   rf   r   )rK   r   r   r   r   rN     rg   z'append_backward_ops.<locals>.<listcomp>c                 S   re   rf   r   )rK   r   r   r   r   rN     rg   c                    s   g | ]} j | qS r   )r2   rJ   )	bwd_blockr   r   rN     s    z%s op has no grad op)r:   r.   r~   r3   r/   rd   r7   r!   Z	frameworkcoreZhas_vjpr   Zcall_vjpr2   rp   r   blocksr   copyappend_backward_opsrT   r#   r$   Znum_operandsrn   r%   loggingwarning)(Zbase_opr   Zbase_input_gradsZ	fwd_blockr   r[   r5   r)   r(   ru   r   Z#control_flow_copyvalue_to_value_mapZyield_opZoutside_outputZinside_outputZforward_opsZinverse_effective_forward_opsZclear_effective_forward_opsrq   r   rr   r   r   Zcopy_outZpop_opZbwd_opsr   Zcopy_outputr   Z	sub_blockr   r8   Zsub_fwd_blockZsub_bwd_blockZ	sub_stateZ%sub_inside_value_to_outside_value_mapZsub_backward_opsZbefore_ops_numZafter_ops_numr'   r   )rj   r)   r   rt   ru   r   rv   r5   r0   r(   r   r   r   J  s   48C




"






s$r   c                 C   sf   t  }| D ]}| st|  D ]}|| qqtd qt  }|D ]}|| q'||fS )Nz#input privided by inputs has no use)r>   ro   r1   rQ   rR   r4   r   r   )r   r   outputs_fwd_setZinput_rG   inputs_fwd_setr   r   r   r   prepare_backward_prune_set  s   r   c                 C   s*  t  }| D ]}|j| g kr||j| d d  qt  }|D ]}|j| g kr5||j| d d  q t  }|D ]}| sQt|  D ]}|| qIq;|| t  }	|jD ]}
|
|v rv|j|
 g krv|	|j|
 d d  q]|jD ]}
|
|v r|j|
 d D ]}|	| qqz|||	fS Nr   )	r>   r%   r4   ro   r1   rQ   rR   rZ   rh   )r   r   r5   r(   rV   rG   rU   Zinputs_set_tmpZout_gradno_gradvar_setkeyr   r   r   create_backward_prune_set  s8   



r   c                 C   s   |  | |j| g kr|j| d }|j| | | D ]!}|j| g kr@|j| d }g |j|< ||jv r@td|	 qdS )z
    remove op from block
    r   z.input_grad in [%s] is value which need to sum N)
	remove_opZopgrad_to_opr$   remover3   Zvaluegrad_to_valuer%   Zsumvaluegrad_to_valuer   r.   )r   r0   r(   Zfwd_opZ	valuegradr'   r   r   r   r     s   


r   c                 C   s  | d    }t|}t|||  t|| t|| |\}}}t|}	t|}
t|j|	|
|\}}t	||||| t
||\}}i }td d d |||||||
 t||||\}
}	}t||	|
|\}}|  t|D ]}|d|v ruqk|d rt||| qk|  |j}|S r   )r   r   r   r   r6   rC   r>   rY   r2   r\   r   r   r   Zturn_maprd   rX   ro   r   r%   )r   r   r@   r5   r   r(   rB   r|   r)   rU   rV   r[   r   r   ru   r   Z
remove_opsZbwd_opZinput_grad_mapr   r   r   r	     s^   




r	   c                 C   sH   t | |||d}g }|D ]}||| g kr|| d d nd q|S )ag  
    caclulate gradient of input

    Args:
        outputs (Value|list(Value)|tuple(Value)): the output Value or
            Value list/tuple of the graph to compute gradients.
        inputs (Value|list(Value)|tuple(Value)): the input Value or
            Value list/tuple of the graph to compute gradients. The returned
            values of this API are the gradients of `inputs` .
        grad_outputs (Value|list(Value|None)|tuple(Value|None), optional):
            initial gradient values of `outputs` . If `grad_outputs` is None,
            the initial gradient values of `outputs` would be Values filled with 1;
            if `grad_outputs` is not None, it must have the same length as `outputs` ,
            and in this case, the initial gradient value of the i-th `outputs` would
            be: (1) a Value filled with 1 when the i-th element of `grad_outputs`
            is None; (2) the i-th element of `grad_outputs` when the i-th element of
            `grad_outputs` is a Value. Default None.
        no_grad_set (set(Value), optional):
            the Values whose gradients are not needed to compute. Default None.

    Return:
        list[Value]:A list of gradients for inputs
        If an input does not affect targets, the corresponding gradient Tensor
        will be None
        TODO if allow_unused=False raise TypeError() if input_grad has None
    )r@   r5   r   N)r	   r7   )r   r   r@   r5   Zinput_to_inputgrad_mapZ	inputgradr   r   r   r   r   T  s   r   FTc           
   	   C   s   t | dtjjtjjfttfd t |dtjjtjjfttfd t |dtjjtjjftttdfd t |dtjjtjjfttttdfd t	| } t	|}t	|}|du r[t }n|turdt|}n|}t
| |||}	|	S )a  
    .. note::
        **This API is ONLY available in imperative mode.**

    This API computes the sum of gradients of `outputs` with respect to each `inputs` .

    Parameters:
        outputs (Value|list(Value)|tuple(Value)): the output Value or
            Value list/tuple of the graph to compute gradients.
        inputs (Value|list(Value)|tuple(Value)): the input Value or
            Value list/tuple of the graph to compute gradients. The returned
            values of this API are the gradients of `inputs` .
        grad_outputs (Value|list(Value|None)|tuple(Value|None), optional):
            initial gradient values of `outputs` . If `grad_outputs` is None,
            the initial gradient values of `outputs` would be Values filled with 1;
            if `grad_outputs` is not None, it must have the same length as `outputs` ,
            and in this case, the initial gradient value of the i-th `outputs` would
            be: (1) a Value filled with 1 when the i-th element of `grad_outputs`
            is None; (2) the i-th element of `grad_outputs` when the i-th element of
            `grad_outputs` is a Value. Default None.
        retain_graph (bool, optional): whether to retain the forward graph which
            is used to calculate the gradient. When it is True, the graph would
            be retained, in which way users can calculate backward twice for the
            same graph. When it is False, the graph would be freed. Default None,
            which means it is equal to `create_graph` .
        create_graph (bool, optional): whether to create the gradient graphs of
            the computing process. When it is True, higher order derivatives are
            supported to compute; when it is False, the gradient graphs of the
            computing process would be discarded. Default False.
        only_inputs (bool, optional): whether to only compute the gradients of
            `inputs` . If it is False, the gradients of all remaining leaf
            Values in the graph would be also computed and accumulated.
            If it is True, only the gradients of `inputs` would be computed.
            Default True. only_inputs=False is under development, and it is
            not supported yet.
        allow_unused (bool, optional): whether to raise error or return None if some
            Values of `inputs` are unreachable in the graph. If some Values of
            `inputs` are unreachable in the graph (i.e., their gradients are None),
            error would be raised if allow_unused=False, or None would be returned as
            their gradients if allow_unused=True. Default False.
        no_grad_vars (Value|list(Value)|tuple(Value)|set(Value), optional):
            the Values whose gradients are not needed to compute. Default None.

    Returns:
        list: a list of Values, whose length is the same as the Value number
        inside `inputs`, and the i-th returned Value is the sum of gradients of
        `outputs` with respect to the i-th `inputs`.
    r   z paddle.autograd.ir_backward.gradr   r@   Nno_grad_vars)r   r!   r?   ValueOpResultr   tupler   r>   r   r   )
r   r   r@   Zretain_graphZcreate_graphZonly_inputsZallow_unusedr   r5   r   r   r   r   r   ~  sD   :
r   c           	      C   s   t | dtjjtjjfd |dur4t |dtttfd t|D ]\}}t |d| tjjtjjfd qn| 	 
  }tjj| |}g }t||D ]\}}|||f qK|S )ar  
    Parameters:
        loss (Value): The loss Tensor of the network
        parameter_list (Value|list(Value)|tuple(Value)):  List/Tuple of Parameters
            that need to be updated by optimizers.
            If it is None, all parameters
            will be updated.
            Default: None.
        no_grad_vars (Value|list(Value)|tuple(Value)|set(Value), optional):
            the Values whose gradients are not needed to compute. Default None.

    Returns:
        list of tuple (Value): Pairs of parameter and its corresponding gradients.
        The key is the parameter and the value is gradient Tensor.
    lossz+paddle.autograd.ir_backward.append_backwardNparameter_listz*paddle.autograd.ir_backwardappend_backwardzparameter_list[%s]zbase.backward.append_backward)r   r!   r?   r   r   r   r   r>   r;   r   r   Zall_parametersZautogradZir_backwardr   r~   r7   )	r   r   r5   rA   paramr   Zinput_inputs_gradr   r   r   r   r   append_backward  s8   
r   )r
   )NNFTFN)NN)!r]   r   collections.abcr   Z
paddle.pirr!   Zpaddle.autograd.backward_utilsr   r   Zpaddle.base.libpaddle.pirr   r   __all__r   r   r   r+   r1   r6   r#   rC   rI   rY   r\   rd   r   r   r   r   r	   r   r   r   r   r   r   r   <module>   sJ   
JA&*    >-
c