a
    ==icp                     @   s   d dl m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"S )#    )
caffe2_pb2c           $   
      sz  ddl m} t| \} }}t|t| jks6J dt| |\}}|}dd | jD }|dd }dd | jD }	|	dd }	 fd	d|D }
i }i }t|
|D ]0\}}|r|d
 }|||||< t|||< qt|dksJ dt	||\}}t|dkrg g fS g }g }g }i }|	D ]h} | }||v r~|| }|d }|d }|
t|| |||< |
| |
| n
|
d q"g }t }t }|D ]}dd |jD }dd |jD } |D ]h}!|!|v rڐq||!d}"|"s||!d}"|"r$t|"}"|"|vr|
|" |"||!< n
||! q||  q||7 }t| |||||||d}#|
|# t|# ||fS )z
    Generates gradient Do operator, given forward Do op and a list
    of gradient blobs corresponding to forward op's outputs
    Returns a gradient op and a list of blobs corresponding to input gradients
    r   BlobReferencez4Different number of gradient blobs and Do op outputsc                 S   s   g | ]}t |qS  str.0or   r   o/home/droni/.local/share/virtualenvs/DPS-5Je3_V2c/lib/python3.9/site-packages/caffe2/python/control_ops_grad.py
<listcomp>&       z#gen_do_gradient.<locals>.<listcomp>Nc                 S   s   g | ]}t |qS r   r   r	   ir   r   r   r   (   r   c                    s   g | ]} | qS r   r   r   outer_to_inner_mapr   r   r   +   r   z/_DO_OPERATOR_INNER_GRAD_z$Empty initial gradient map for Do op_gradz/_DO_OPERATOR_INNER_GRAD_COPY_c                 S   s   g | ]}t |qS r   r   r   r   r   r   r      r   c                 S   s   g | ]}t |qS r   r   r   r   r   r   r      r   )fwd_opfwd_netgrad_opsinputsoutputsblob_bindingssaved_fwd_blobsworkspace_blob_name)caffe2.python.corer   _do_op_sanity_check_and_processlenoutputdedupe_g_outputinputzipr   _gen_subgradient_passappend_prepare_blob_copy_opsetgetaddupdate_prepare_gradient_do_op)$opg_outputr   subnetinner_to_outer_mapr   r   deduped_g_output	op_outputop_inputZordered_inner_output_blob_namesZbackward_pass_initial_grad_mapZinitial_grad_mapZinner_output_nameZouter_grad_output_nameZinner_grad_output_nameZinner_grad_opsZinner_grad_names_mapZgrad_copy_opsg_inputZnew_op_outputsZnew_blob_bindingsZouter_input_nameZinner_input_nameZinner_grad_input_nameZouter_grad_input_nameZnew_inner_grad_input_nameZnew_op_inputsZoverwritten_namesZsaved_local_blob_namesgrad_opgrad_op_inputgrad_op_outputZgrad_op_input_name
outer_namegradient_do_defr   r   r   gen_do_gradient   s    



*




	
r8   c           	      C   s   g }g }i }t | j|D ]\}}|s0|| q||v rH|||  q|| vrh|||< || q|d | d }|| vsJ t }d|_|j|g |j|g || || |||< q||fS )N_Z_DEDUPCopy)	r"   r   r$   valuesr   OperatorDeftyper!   extend)	r+   r,   r   r/   init_grad_mapoutput_nameZ	grad_nameZdeduped_grad_nameZgrad_copy_opr   r   r   r       s,    



r    c              
      s  ddl m} | jdksJ dt| jdks4J dt| jt|ksNJ dt| |\}}|}i }dd | jD }t||D ]\}}|r~|||||< q~t|dksJ d	t| d
}	|	sJ dt|	j	dkr|	j	d jdksJ d|	j	d }
t
|
}d|vs|d rJ dt|
jdks2J d|
jd }t|	|\} }}|s\J d|t| ||||| d7 }dd | jD } fdd|D }||fS )z+
    Generates gradient While operator
    r   r   WhilezExpected While opz'Expected at least one input in While opz7Different number of gradient blobs and While op outputsc                 S   s   g | ]}t |qS r   r   r   r   r   r   r      r   z&gen_while_gradient.<locals>.<listcomp>z'Empty initial gradient map for While oploop_netz Expected loop subnet in While op   Doz6Gradient While op requires single Do op as a loop bodyreuse_workspacezFGradient While op requires Do loop body op without reuse_workspace setz'Expected Do op with at least one outputr   z4Failed to get gradient net for loop body in While op)r   input_namesoutput_namesloop_grad_networkspace_blobr?   loop_grad_mapc                 S   s   g | ]}t |qS r   r   r   r   r   r   r      r   c                    s   g | ]}  |d qS Nr'   r   rJ   r   r   r      r   )r   r   r=   r   r!   r   r    r"   _get_net_argumentr+   _get_do_arguments_gen_subnet_gradient_prepare_gradient_while_ops)r+   r,   r   r   r/   r?   r0   r@   grad_output_namerB   do_opZdo_argsrI   rH   Zloop_input_namesZloop_output_namesr1   r2   r   rM   r   gen_while_gradient   sT    
 


	rT   c                 C   s  t  }||  |jr&| jd7  _t  }d|_|j| t  }	d|	_ddlm}
m} |
d}|
d}|	|
 d }||| ||| | D ]T\}}t|}t|}||v r|| |kr|||| | |||||  q|	j|  |jd d = |j||	g |jd d = |jd d = |jt|d	gt|  |jd d = |j| d
|_dd | jD |g S )Nr   rB   cond_netr   )Netr   Zgradient_loop_cond_netZgradient_loop_cond_net_initz/condutf-8Tc                 S   s   g | ]}|qS r   r   r   r   r   r   r   0  r   z/_prepare_gradient_while_ops.<locals>.<listcomp>)r   r<   CopyFromnameArgumentnr   rV   r   ZNextScopedBlobNameZHasScopeitemsr   r:   ZProtoargr>   control_inputr!   encodelistr   is_gradient_opr+   )r   rF   rG   rH   rI   r?   rJ   Zgradient_while_defZloop_net_argZcond_net_argrV   r   rU   Zcond_init_netZ	cond_blobZblobZinit_grad_blobZ	blob_nameZinit_grad_blob_namer   r   r   rQ     sN    

rQ   c                 C   s   | j dksJ di }| jD ]}|js(q|jdkrL|js@J d|j|d< q|jdkrt|jsdJ dt|j|d< q|jdkr|jsJ d|j|d< q|jd	kr|jsJ d
|j|d	< q|S )NrD   Expected Do opnetzExpected non empty net argumentrE   z+Expected non empty reuse_workspace argumentinner_blobsz'Expected non empty inner_blobs argumentouter_blobs_idxz+Expected non empty outer_blobs_idx argument)r=   r^   rY   r[   r   boolstringsints)rS   argsr^   r   r   r   rO   3  s$    




rO   c                     s  ddl m} | jdksJ dt| jdks4J dt| jt|ksNJ dt| |\}}|}i }dd | jD }d	d | jD }t||D ]\}}	|	r||	|||< qt|dksJ d
i t| d}
|
sJ dt	|
|\}}}|sJ d
 t }t }i  d}t| d}|rt	||\} }}|sFJ d  D ]\}}|v rʈ| }||kr||v r|| nd}||kr||< n,||kr||< nd| d | d | n||< qN|||@  }tfdd|D }t||}|r|j| nft|dkr~t }|| |jrN| jd7  _|jdd= |j| |jdd= |jdd= |||@  }t fdd|D }t| |}|j| t||B }||B }|d gt|t|d   }t| ||||d}fdd|D }||g |fS )z
    Generates gradient If operator, given forward If op and a list
    of gradient blobs corresponding to forward op's outputs
    Returns a gradient op and a list of blobs corresponding to input gradients
    r   r   IfzExpected If opz$Expected at least one input in If opz4Different number of gradient blobs and If op outputsc                 S   s   g | ]}t |qS r   r   r   r   r   r   r   Z  r   z#gen_if_gradient.<locals>.<listcomp>c                 S   s   g | ]}t |qS r   r   r   r   r   r   r   [  r   z$Empty initial gradient map for If opthen_netzExpected then subnet in If opz,Failed to get gradient net for then in If opNelse_netz,Failed to get gradient net for else in If opzUnexpected grad blob name z, c                    s   g | ]}|   v r|qS r   r;   r   )then_grad_mapr   r   r     r   Z_auto_else_zero_blobs_c                    s   g | ]}|   v r|qS r   rn   r   )else_grad_mapr   r   r     r   )r   rF   rG   then_grad_netelse_grad_netc                    s   g | ]}  |d qS rK   rL   r   )grad_mapr   r   r     r   )r   r   r=   r   r!   r   r    r"   rN   rP   r)   r&   r]   _gen_grad_zero_init_opsr+   r>   r   NetDefrX   rY   external_inputexternal_outputra   _prepare_gradient_if_op) r+   r,   r   r   r/   r?   r1   r0   r@   rR   rl   rq   Zthen_input_namesZthen_output_namesZelse_input_namesZelse_output_namesrr   rm   Z	else_blobZelse_grad_blobZthen_grad_blobinit_grad_nameZthen_other_output_namesZthen_other_grad_output_namesZ	zero_thenZelse_other_output_namesZelse_other_grad_output_namesZ	zero_elserG   rF   gradient_if_defr2   r   )rp   rs   ro   r   gen_if_gradientH  s    














r{   c           
      C   s   t | |\}}t }t }|D ]D}|jD ]}t||vr(|t| q(|jD ]}|t| qNqt }	|	|  |	j	r|	 j	d7  _	|	j
d d = |	j
| |	jd d = |	jd d = |	|||fS )Nr   )r#   r&   r!   r   r(   r   r   ru   rX   rY   r+   r>   rv   rw   )
r-   	init_gradr   grad_names_maprG   rF   r3   r4   r5   gradient_net_defr   r   r   rP     s(    


rP   c                 C   s<   | j D ]0}|jr|j|kr|js,J d| |j  S qd S )Nz Expected non empty net argument )r^   rY   r[   )r+   net_namer^   r   r   r   rN     s
    
rN   c                 C   s
   t | |S )zA wrapper for external call)rN   )r+   r   r   r   r   getNetArgument  s    r   c           	      C   sR   ddl m} || j}||\}}i }| D ]\}}t||t|< q0||fS )Nr   )IR)r   r   r+   ZGetBackwardPassr]   r   )	r-   r|   r   Z	subnet_irr   Zgrad_blob_mapr}   bgr   r   r   r#     s    
r#   c                 C   s  | j dksJ dt| d}|s(J dd }d }| jD ]}|jr|jdkr|rVJ d|jrjt|jdksrJ dd	d
 |jD }|jr|jdkr|rJ d|jrt|jdksJ d|j}|r6|r6 qq6|sJ d|sJ dt|t|ksJ dt|}t|t|ks J ddd
 | jD }t|dksFJ d|d }|d d }dd
 | j	D }t|dksJ d|d }	||	ksJ d|d d }t|}
t|
t|ksJ dt|}t|t|ksJ d|| }t|}t }i }i }t
||D ]f\}}|dkr2|t|k s:J d|| }||vs\J d| d || |||< |||< qt|t|ksJ d||||	fS )NrD   rc   rd   zNo net argument found in Do opre   zinner_blobs redefinitionr   z#Empty inner_blobs argument in Do opc                 S   s   g | ]}| d qS rW   )decode)r	   sr   r   r   r     r   z3_do_op_sanity_check_and_process.<locals>.<listcomp>rf   zouter_blobs_idx redefinitionz'Empty outer_blobs_idx argument in Do opz&No inner_blobs argument found in Do opz*No outer_blobs_idx argument found in Do opzFArguments inner_blobs and outer_blobs_idx of different length in Do opz(Found duplicates in inner_blobs in Do opc                 S   s   g | ]}t |qS r   r   r   r   r   r   r     r   z Expected at least one input blobr   c                 S   s   g | ]}t |qS r   r   r   r   r   r   r     r   z!Expected at least one output blobz)Expected same input/output workspace blobz Found duplicates in Do op inputsz!Found duplicates in Do op outputsz*Outer blob index is out of bounds in Do opzReusage of outer blob name z	 in Do opz;Not all outer blob names are used in blob bindings in Do op)r=   rN   r^   rY   rh   r   ri   r&   r!   r   r"   r(   )r+   r-   re   rf   r^   Zall_inner_blobsr1   Zinput_workspace_blob_namer0   r   Zall_op_input_blob_namesZall_op_output_blob_namesZordered_outer_blob_namesZall_outer_blob_namesZused_outer_blob_namesr   r.   Z
inner_nameZouter_blob_idxr6   r   r   r   r     s    





r   c                 C   s.   t  }d|_|j| g |j|g |S )Nr:   )r   r<   r=   r!   r>   r   )	from_nameZto_nameZcopy_op_defr   r   r   r%   2  s
    r%   c                    s  t  }|| |jr&| jd7  _|jd d = |j| |jd d = |jd d = t  }	|	|  |	jrt	|	jdkr|	 jd7  _|	j
d d = |	j
| |	j
| |	jd d = |	j| |	j| t  }
d|
_|
j| ||   } fdd|D }t  }d|_|jdd |D  t  }d|_|j| t  }d	|_|jd
d |D  |	jd d = |	j|
|||g |	jd d = d|	_|	S )Nr   r   rd   c                    s   g | ]}  | qS r   )indexr	   r   r   Zordered_new_outer_namesr   r   r   Z  s   z+_prepare_gradient_do_op.<locals>.<listcomp>re   c                 S   s   g | ]}| d qS r   r`   r   r   r   r   r   _  r   rf   r   c                 S   s   g | ]}| d qS r   r   r   r   r   r   r   h  r   T)r   ru   rX   rY   r+   r>   rv   rw   r<   r   r!   r$   r   rZ   r[   keysrh   ri   r^   r_   rb   )r   r   r   r   r   r   r   r   r~   r7   Znet_argre   Znew_outer_blobs_idxZinner_blobs_argZouter_blobs_idx_argZsaved_blobs_argr   r   r   r*   :  sX    

r*   c                 C   s   g }|D ]}d }|  D ]\}}||kr|} q2q|sBJ d| d }|| v r| | }	|	|krt }d|_|jt|	g |jt|g nLt }d|_|j|g |j|g t }
d|
_	d|
_
|j|
g |r|| q|S )NzUnknown gradient output r:   ZConstantFillvalueg        )r]   r   r<   r=   r!   r>   r   r   rZ   rY   fr^   r$   )r?   rs   Zgrad_output_namesZgrad_init_opsZgrad_outputr@   r
   r   Zgrad_init_opry   Z	value_argr   r   r   rt   t  s6    rt   c           	      C   s   t  }||  |jd d = |j| |jd d = |j| t  }d|_|j| |g}|rt  }d|_|j| |	| |j
d d = |j
| |jr| jd7  _|jd d = d|_|S )Nrl   rm   r   T)r   r<   rX   r!   r>   r   rZ   rY   r[   r$   r^   r_   rb   )	r   rF   rG   rq   rr   rz   Zthen_net_argZgradient_argsZelse_net_argr   r   r   rx     s,    

rx   c           	      C   s   t | d}| j| }|jD ]*}t|jD ]\}}||kr(||j|< q(qt | d}|r|jD ]*}t|jD ]\}}||krh||j|< qhqZ|| j|< d S )Nrl   rm   )rN   r   r+   	enumerate)	r3   idxZnew_grad_outputrl   Zold_grad_out_matchr+   r   outrm   r   r   r   disambiguate_grad_if_op_output  s    




r   N)Zcaffe2.protor   r8   r    rT   rQ   rO   r{   rP   rN   r   r#   r   r%   r*   rt   rx   r   r   r   r   r   <module>   s"     <.nK:%