U
    de7                     @   s&  d dl mZ d dlmZ d dlmZmZ d dlmZ d dl	Z	d dl
Z
d dlZd dlZd dlZd dlmZmZmZmZ dZdZd/d	d
Zdd Zdd Zd0ddZdd Zdd Zdd Zdd Zdd Zdd Zdd Z G dd  d e!Z"d!d" Z#d#d$ Z$d1d%d&Z%d'd( Z&d)d* Z'd+d, Z(d-d. Z)dS )2    )
caffe2_pb2)	viewitems)DecodeErrorMessage)text_formatN)integer_typesbinary_type	text_typestring_typesZoptimizer_iterationZiteration_mutexc                    sl    pg  t  ts g tdd  D s8td  fdd}|| } ||}| |kpjt| t|kS )zM
    Two ops are identical except for each field in the `ignore_fields`.
    c                 s   s   | ]}t |tV  qd S N)
isinstancer	   ).0f r   7/tmp/pip-unpacked-wheel-ua33x9lu/caffe2/python/utils.py	<genexpr>    s     z OpAlmostEqual.<locals>.<genexpr>z*Expect each field is text type, but got {}c                    s,   t | }  D ]}| |r| | q| S r   )copydeepcopyHasFieldZ
ClearField)opfieldignore_fieldsr   r   clean_op#   s
    

zOpAlmostEqual.<locals>.clean_op)r   listallAssertionErrorformatstr)Zop_aZop_br   r   r   r   r   OpAlmostEqual   s    
r   c                 C   sP   | j dkr0tj| jtjd| j | j| j| jS tj| jtjd| j	j
S d S )Nr   dtype)numnpasarraydatafloat32reshapeZchannelsheightwidthshapeZdim)Zblobr   r   r   CaffeBlobToNumpyArray/   s    
   r+   c                 C   s\  | j tjjkr(tj| jtjd| j	S | j tjj
krPtj| jtjd| j	S | j tjjkrxtj| jtjd| j	S | j tjjkrtj| jtjd| j	S | j tjjkrtj| jtjd| j	S | j tjjk rtj| jtjd| j	S | j tjjkrtj| jtjd| j	S | j tjjkrFtj| jtjd| j	S tdt| j  d S )Nr    z$Tensor data type not supported yet: )	data_typer   TensorProtoFLOATr#   r$   
float_datar&   r'   dimsDOUBLEdouble_datafloat64INT64
int64_dataint64INT32
int32_dataintINT16int16UINT16uint16INT8int8UINT8uint8RuntimeErrorr   tensorr   r   r   Caffe2TensorToNumpyArray:   sv            rE   c                 C   s  t  }|j| j |r ||_| jtjkrTt jj	|_
|jt|  t n| jtjkrt jj|_
|jt|  tj nb| jtjkrt jj|_
|jt|  tj n,| jtjks| jtjkrt jj|_
|j|  tj  n| jtjkr8t jj|_
|jt|  tj n| jtjkrnt jj|_
|jt|  tj n~| jtjkrt jj |_
|jt|  tj nH| jtj!krt jj"|_
|jt|  tj! nt#dt$| j |S )Nz#Numpy data type not supported yet: )%r   r-   r0   extendr*   namer!   r#   r&   r.   r,   r/   r   flattenZastypefloatr3   r1   r2   r6   r4   r5   r9   Zint32r7   r8   tolistr;   r:   r=   r<   r?   r>   rA   r@   rB   r   )ZarrrG   rD   r   r   r   NumpyArrayToCaffe2TensorY   s@    

 
 




rK   c              	   C   sV  t  }| |_t|tjj}t|tjrN|j	j
tjkrN|j|   |S t|tjrh|  }nt|tjr~t|}t
|tkr||_nt
|tkst
|tkr||_nt|tr||_nt|tr|d|_nnt|t jr|j| nPt|tr| |_n6|rPt dd |D rP|jdd |D  n|rt dd |D r|j!dd |D  n|rt dd |D r|j"dd |D  n|rt d	d |D r|j#| nv|rt d
d |D r|j"dd |D  nD|r<t$d%| |t
|t&dd |D nt$d%| |t
||S )z*Makes an argument based on the value type.utf-8c                 s   s    | ]}t |ttjfkV  qd S r   )typerI   r#   float_r   vr   r   r   r      s     zMakeArgument.<locals>.<genexpr>c                 s   s(   | ] }t |tjkr| n|V  qd S r   )rM   r#   rN   itemrO   r   r   r   r      s    c                 s   s,   | ]$}t |tkp"t |ttjfkV  qd S r   )rM   r   boolr#   int_rO   r   r   r   r      s    c                 s   s(   | ] }t |tjkr| n|V  qd S r   )rM   r#   rS   rQ   rO   r   r   r   r      s    c                 s   s"   | ]}t |tpt |tV  qd S r   )r   r   r	   rO   r   r   r   r      s    c                 s   s&   | ]}t |tr|d n|V  qdS )rL   N)r   r	   encoderO   r   r   r   r      s   c                 s   s   | ]}t |tjV  qd S r   )r   r   NetDefrO   r   r   r   r      s     c                 s   s   | ]}t |tV  qd S r   )r   r   rO   r   r   r   r      s     c                 s   s   | ]}|  V  qd S r   )SerializeToStringrO   r   r   r   r      s     zBUnknown iterable argument type: key={} value={}, value type={}[{}]c                 s   s   | ]}t |V  qd S r   )rM   rO   r   r   r   r      s     z5Unknown argument type: key={} value={}, value type={})'r   ZArgumentrG   r   collectionsabcIterabler#   Zndarrayr!   rM   r&   ZfloatsrF   rH   rJ   ZgenericZasscalarrI   r   r   rR   ir   sr	   rT   rU   nZCopyFromr   rV   r   Zintsstringsnets
ValueErrorr   set)keyvalueargumentiterabler   r   r   MakeArgument}   sv    









     re   c              	   C   sF   |  }zt || |W S  t jtfk
r@   || | Y S X dS )a,  Reads a protobuffer with the given proto class.

    Inputs:
      cls: a protobuffer class.
      s: a string of either binary or text protobuffer content.

    Outputs:
      proto: the protobuffer of cls

    Throws:
      google.protobuf.message.DecodeError: if we cannot decode the message.
    N)r   Parse
ParseErrorUnicodeDecodeErrorZParseFromString)clsr[   objr   r   r   TryReadProtoWithClass   s    
rk   c                 C   s.   t |D ] \}}t| |kr||   S qdS )zNGets a specific field from a protocol buffer that matches the given class
    N)r   rM   )rj   function_mapri   funcr   r   r   GetContentFromProto   s    rn   c              	   C   sP   t |D ]:\}}zt|| }||W   S  tk
r@   Y qY qX qtdd S )Nz$Cannot find a fit protobuffer class.)r   rk   r   )r[   rl   ri   rm   rj   r   r   r   GetContentFromProtoString   s    
ro   c              	   C   sJ   t |}t| | }W 5 Q R X t |d}||  W 5 Q R X dS )z:Convert a text file of the given protobuf class to binary.wN)openrk   readwriterV   )Zproto_classfilenameZout_filenamer   protoZfidr   r   r   ConvertProtoToBinary   s    
rv   c               
   C   s   ddl m} m} | |jdg dg|| jdd | d}|dddf |dddf t	|dddf t	|dddf dS )	z|Get GPU memory usage stats from CUDAContext/HIPContext. This requires flag
       --caffe2_gpu_memory_tracking to be enabledr   	workspacecoreZGetGPUMemoryUsageZ____mem____Zdevice_optionN   )Ztotal_by_gpuZ
max_by_gputotalZ	max_total)
caffe2.pythonrx   ry   RunOperatorOnceCreateOperatorDeviceOptionZGpuDeviceTypeZ	FetchBlobr#   sum)rx   ry   br   r   r   GetGPUMemoryUsageStats   s    
r   c              	   C   s<   ddl m}m} ||jdt| t| |tjd d S )Nr   rw   ZFreerz   )	r}   rx   ry   r~   r   r   r   r   CPU)Zblobsrx   ry   r   r   r   
ResetBlobs  s    
r   c                   @   s   e Zd ZdZedd ZdS )	DebugModea=  
    This class allows to drop you into an interactive debugger
    if there is an unhandled exception in your python script

    Example of usage:

    def main():
        # your code here
        pass

    if __name__ == '__main__':
        from caffe2.python.utils import DebugMode
        DebugMode.run(main)
    c                 C   sn   z| W S  t k
r    Y nL tk
rh   dd l}td tt d  t |  td  Y nX d S )Nr   zjEntering interactive debugger. Type "bt" to print the full stacktrace. Type "help" to see command listing.r{   )KeyboardInterrupt	Exceptionpdbprintsysexc_infoZpost_mortemexit)ri   rm   r   r   r   r   run'  s    
zDebugMode.runN)__name__
__module____qualname____doc__classmethodr   r   r   r   r   r     s   r   c                 C   s   | |krt d|| |d S )Nz{}. {} != {})r   r   )ar   msgr   r   r   raiseIfNotEqual;  s    r   c                    s   t   fdd}|S )z
    Use this method to decorate your function with DebugMode's functionality

    Example:

    @debug
    def test_foo(self):
        raise Exception("Bar")

    c                     s    fdd}t |S )Nc                      s
    S r   r   r   )argsr   kwargsr   r   rm   N  s    z$debug.<locals>.wrapper.<locals>.func)r   r   )r   r   rm   r   )r   r   r   wrapperL  s    zdebug.<locals>.wrapper)	functoolswraps)r   r   r   r   r   debug@  s    r   c              	   C   s   |dk	r|nt }|dk	r|nt}ddlm} | |s||jtjdgd@ | j	g |dg||j
jd}| g |g}|||g|g W 5 Q R X n
| |}|S )z
    Often, a mutex guarded iteration counter is needed. This function creates a
    mutex iter in the net uniquely (if the iter already existing, it does
    nothing)

    This function returns the iter blob
    Nr   )ry   zdevice_type_override:cpu)Z
extra_infor{   )r*   rb   r!   )OPTIMIZER_ITERATION_NAMEITERATION_MUTEX_NAMEr}   ry   ZBlobIsDefinedZDeviceScoper   r   r   ZConstantFillZDataTyper4   ZCreateMutexZ
AtomicIterZ
GetBlobRef)Zinit_netnetiterZ
iter_mutexZiter_valry   	iterationr   r   r   BuildUniqueMutexIterU  s(    

r   c              
      s   t | t ksti  t| D ]b}|| krt| |ttr  ksvtd| | fdd D d  |< q S )Nz<Failed to resolve {} as Enum: duplicate entries {}={}, {}={}c                    s   g | ]} | kr|qS r   r   )r   ra   enumrP   r   r   
<listcomp>  s      z$EnumClassKeyVals.<locals>.<listcomp>r   )	rM   r   diruppergetattrr   r
   valuesr   )ri   kr   r   r   EnumClassKeyValsz  s"    

    
r   c                 C   s   i }| D ]}| dsq|jjD ]r}|jdkr0q |j|jkr`| |jr`t||j||j<  qq |j|jkr t||j}t|dkr |||j<  qq d||j< q|S )z
    Convert a list of arguments to a name, value dictionary. Assumes that
    each argument has a name. Otherwise, the argument is skipped.
    rG   r   N)	r   Z
DESCRIPTORfieldsrG   labelZLABEL_OPTIONALr   ZLABEL_REPEATEDlen)r   Zansargdlist_r   r   r   
ArgsToDict  s"    


r   c                 C   s6   | j dkst| d| j d fttd| j d  S )Nr{   r   ndimr   Z	transposetuplerangerC   r   r   r   	NHWC2NCHW  s    r   c                 C   s,   | j dkst| dttd| j  d S )N   )r   )r{   r   rC   r   r   r   	NCHW2NHWC  s    r   )N)N)NNr   )*Zcaffe2.protor   Zfuture.utilsr   Zgoogle.protobuf.messager   r   Zgoogle.protobufr   r   rW   r   r   Znumpyr#   sixr   r   r	   r
   r   r   r   r+   rE   rK   re   rk   rn   ro   rv   r   r   objectr   r   r   r   r   r   r   r   r   r   r   r   <module>   sB   

$H$   
%