a
    ==ic<                     @   st   d dl Z d dlZd dlmZmZmZ d dlmZ dd Z	dd Z
dd	 ZdddZG dd deZG dd dZdS )    N)core	workspace
net_drawer)
caffe2_pb2c                 C   s   t j| dd | jD S )Nc                 S   s   g | ]}|d  qS )_grad ).0sr   r   o/home/droni/.local/share/virtualenvs/DPS-5Je3_V2c/lib/python3.9/site-packages/caffe2/python/gradient_checker.py
<listcomp>       z$getGradientForOp.<locals>.<listcomp>)r   ZGradientRegistryZGetGradientForOpoutput)opr   r   r
   getGradientForOp   s    r   c                 C   s^   | | }t |tjrtj| S t |tjs.J d}td|j|j|g|}t	| tj| S )NZtmp_dense_gradZSparseToDense)

isinstancer   ZBlobReferencer   blobsGradientSliceCreateOperatorindicesvaluesRunOperatorOnce)grad_mapinput_to_checkZ	grad_blobZ
dense_gradsparse_to_dense_opr   r   r
   _get_grad_blob   s    

r   c                    s   |  |  d }|| |p"i  D ]\}}|tj|< q(|D ],}| v sZJ d|t|tjv s@J q@t| dd |D }	 fdd|D }
|	|
|fS )NZ_copyz.{} has no gradient, cannot check net gradient.c                 S   s   g | ]}|t j| fqS r   r   r   r   r   r   r   r
   r   6   r   z_get_grad.<locals>.<listcomp>c                    s   i | ]}|t  |qS r   )r   )r   r   r   r   r
   
<dictcomp>7   s   z_get_grad.<locals>.<dictcomp>)	ZCloneNameZAddGradientOperatorsitemsr   r   formatstr
RunNetOnce)netoutputsoutputs_with_gradinput_valuesinputs_with_gradsZgrad_netnamevaluer   Zforward_resultsZgradsr   r   r
   	_get_grad(   s"    



r+    c                 C   s:   t jj| ||||d t | |  }t |t|fS )N)atolrtolerr_msg)nptestingZassert_allcloseabsflattenmeanmax)Zvalue1value2	thresholdr/   deltar   r   r
   _assert_close=   s    r9   c                   @   s(   e Zd ZedddZedd	d
ZdS )NetGradientCheckerNHz>Fc                    s  fdd |rxt | D ]^\}}t| }	tdt| |  d d}
|
|	 W d    q1 sl0    Y  q fddt| |D }|rt| \}}}t |D ]`\}}t| }	tdt| |  d d}
|
|	 W d    q1 s0    Y  q|d	 \}}}|d
d  D ]\}}}t	|t	|ksLJ t t||D ]0\}\\}}\}}t
|||d|||d qZ| | ksJ | D ]$\}}t
|| ||d|d qq,d S )Nc                    s    fddD S )Nc                    s   g | ]} | qS r   r   )r   inet_outputsr   r
   r   N   r   zWNetGradientChecker.CompareNets.<locals>._get_output_with_grad_names.<locals>.<listcomp>r   r=   )outputs_with_grad_idsr=   r
   _get_output_with_grad_namesM   s    zCNetGradientChecker.CompareNets.<locals>._get_output_with_grad_namesZcaffe2_net_forward_z.pngwbc                    s$   g | ]\}}t || |qS r   )r+   )r   r$   r>   )r@   r'   r(   r   r
   r   X   s
   z2NetGradientChecker.CompareNets.<locals>.<listcomp>Zcaffe2_net_r      zVDifferent forward pass results for output id {}. Corresponding output blobs: {} and {})r/   z Different gradients for input {})	enumerater   ZGetPydotGraphZ
create_pngopenr"   r   writeziplenr9   r!   keysr    )netsr%   r?   r(   r'   r7   Zprint_net_imagesr<   r$   Zpngfresults_Zbackward_netsZfirst_net_resultsZfirst_net_gradsnet_results	net_gradsidxZblob1Zblob_value1Zblob2Zblob_value2blobZblob_grad_valuer   )r@   r'   r(   r?   r
   CompareNetsI   sJ    *,

zNetGradientChecker.CompareNets-C6?皙?Tc                    s   t | g g\}} | }	 fdd}
fdd}t }t jD ]8}|
|||}|
||| }|| | d |j|< qZd|  }|r|d|  7 }t	|	|||S )Nc                    s*   | t j< t   tdd D  S )Nc                 S   s   g | ]}t j| qS r   r   r   r   r   r
   r      s   z=NetGradientChecker.Check.<locals>.GetLoss.<locals>.<listcomp>)r   r   r#   sum)	new_value)full_netr   r&   r   r
   GetLoss   s
    

z)NetGradientChecker.Check.<locals>.GetLossc                    s"       }|j|   |7  < |S N)copyflat)dimr8   Zinput_value)r   r'   r   r
   GetValue   s    z*NetGradientChecker.Check.<locals>.GetValue   z'Error in gradient check for net_copy {}z: {})
r+   r0   
zeros_likerangesizerZ   r!   r   ZProtor9   )r$   r&   r'   r   Z	step_sizer7   Z	print_netrM   rN   Zanalytic_gradrW   r\   grad_estimater[   pos_lossneg_lossr/   r   )rV   r   r'   r&   r
   Checkx   s"    
zNetGradientChecker.Check)Nr;   F)rR   rS   T)__name__
__module____qualname__staticmethodrQ   rd   r   r   r   r
   r:   H   s     .  r:   c                   @   s4   e Zd ZdZdddZdd Zdd	d
Zdd ZdS )GradientCheckerzA gradient checker in Python.

    This is not the most efficient way to check gradients, as the Python
    interface will involve a lot of copies back and forth operations. Use at your
    own risk.
    Ngradient_checkc                 C   s:   || _ || _|pt | _|| _|d u r0i | _n|| _d S rX   )	_stepsize
_thresholdr   ZDeviceOption_device_option_workspace_name_input_device_options)selfZstepsizer7   device_optionZworkspace_nameinput_device_optionsr   r   r
   __init__   s    zGradientChecker.__init__c              	   C   sx  t t|D ]*}t|| || | j|| | j q|| }	t| d}
|D ]<}|j| }t	|}|
|d 
 7 }
t|d || j qR|
d }
t| t|tjrftdtj|	tjd tdtjdtjd tjd	|j|jd
 | jd}tjd	|j|jd
 | jd}tddd|jd
 |jd
 dgd}t| t| t| t	d}n
t	|}|
|fS )Ng        r]   r   g       @Zzeros)dtypeonesrB   ZEnsureCPUOutputZ_cpu)rq   ZScatterWeightedSum)r_   rG   r   FeedBlobro   getrm   r   r   	FetchBlobrT   ZRunOperatorsOncer   r   r   r0   r^   float32ru   r   r   r   )rp   r   grad_opsinputsZinput_namesr   	grad_nameoutputs_with_gradsr<   xlossrO   r)   arrZ	gv_cpu_opZ	gi_cpu_opr   gradr   r   r
   GetLossAndGrad   sP    









zGradientChecker.GetLossAndGradFc              
   C   sl  t  }| j|kr t | jd |j| j |du rBt|\}}	|pRt	|d }
t
|D ],\}}t |j| ||
|j| | j q\|	| }| ||||j|||\}}t|| }|j|jkrtd|j|j|r| || tddk}|| j}t|D ]}|sB|dkrB|d |k rB|j| |j|< q|| j|  | j7  < | ||||j|||\}}|| j|  | jd 8  < | ||||j|||\}}|| j|  | j7  < || | j d |j|< qtj||| j| jd	 }t|r@t|}td
 tt ||j| |j| gj! d}nd}| j|krbt "  t | |||fS )a  Checks the operator in a very simple fashion by stacking a sum of
        squares on the top.

        Inputs:
          op: the operator to be checked.
          inputs: the input data in numpy arrays.
          input_to_check: an index specifying which input blob we should
              check.
          outputs_with_grads: indices specifying which output blobs will we
              need to check gradients with. For these outputs, we will collect a
              squared sum and also feed in their gradients.
          grad_operator: the gradient operator. If not given, we will get the
              gradient operator from the gradient registry.
          input_device_options: an optional mapping from input names to
              DeviceOptions (to override the default DeviceOption)
          ensure_outputs_are_inferred: if set will assert that the gradient output
              shapes matches the inferred shapes
        Outputs:
          boolean: True if it passes, False if it does not pass.
        TNr   z5Mismatched gradient shapes: estimated ({}), grad ({})ZCAFFE2_FULL_GRAD_CHECK1   r]   )r-   r.   z'Failed. [idx, grad, grad_estimate] are:F)#r   ZCurrentWorkspacern   ZSwitchWorkspacerq   ZCopyFromrm   r   r   ZInferOpBlobDevicesAsDictrC   rv   inputrw   r   r0   r^   shape	Exceptionr!   _assertInferTensorChecksosgetenvr`   r_   rZ   rk   iscloserl   anyZflatnonzeroprintZvstackTZResetWorkspace)rp   r   r{   r   r}   rz   rr   Zensure_outputs_are_inferredZold_ws_nameZg_inputro   r<   r   r|   r   r   ra   Zfull_grad_checkZdims_to_checkZcurrent_dimrb   rL   rc   Zfail_matrO   retr   r   r
   CheckSimple   s    





"
zGradientChecker.CheckSimplec                 C   sf  t  }|j|g |j| tj|gdd\}}t }|D ]}||j q@|D ]}||vrrt	d
|t|}	t|	j}
t|| }|
|krt	d
|
|t|	tju r4|	jtdkrt jj}n^|	jtdkrt jj}nD|	jtdkr
t jj}n(|	jtdkr&t jj}nd	
tj}ntt|	}|| }||krVt	d

||qVd S )NT)Z
nets_protoz!expected output {} to be inferredz,Mismatched inferred shape: want({}), got({})float64ry   int32int64z
unknown {}z+Mismatched inferred type: want({}), got({}))r   ZNetDefr   extendr   ZInferShapesAndTypessetupdater   r   r!   rx   listr   typer0   Zndarrayrt   ZTensorProtoDOUBLEFLOATZINT32ZINT64r"   )rp   r   rz   Ztmp_netZinferred_shapesZinferred_typesr%   Zgrad_opr   rP   Zcorrect_shapeZinferred_shapeZcorrect_typeZinferred_typer   r   r
   r   Y  sT    







z(GradientChecker._assertInferTensorChecks)Nrj   N)NNF)re   rf   rg   __doc__rs   r   r   r   r   r   r   r
   ri      s      
7   
sri   )r,   )r   numpyr0   Zcaffe2.pythonr   r   r   Zcaffe2.protor   r   r   r+   r9   objectr:   ri   r   r   r   r
   <module>   s   
T