U
    d7                     @   s4  d dl Z d dlZd dlZd dlmZ d dlmZ d dlmZ e	e
Zeej zd dlZW n* ek
r   ed ed dZY nX d dlmZ dd	d
ddZddiZdd Zdd Zdd Zdd Zd.ddZd/ddZdd Zdd  Zd0d!d"Zd1d$d%Zd&d' Z d(Z!d)d* Z"d+d, Z#e
d-kr0e#  dS )2    N)defaultdict)utils)	viewitemsa	  Cannot import pydot, which is required for drawing a network. This can usually be installed in python with "pip install pydot". Also, pydot requires graphviz to convert dot files to pdf: in ubuntu, this can usually be installed with "sudo apt-get install graphviz".zKnet_drawer will not run correctly. Please install the correct dependencies.)
caffe2_pb2Zboxz#0F9D58Zfilledz#FFFFFF)shapecolorstyleZ	fontcolorr   Zoctagonc                 C   s   t | tjr"| j}|dkrx| j}nVt| drh|  }t |tjsRtdt	||j}|dkrx|j}n| }|dkrxd}||fS )z0Gets the operators and name for the pydot graph.NProtozExpecting NetDef, but got {}Zunnamed)

isinstancer   NetDefopnamehasattrr	   RuntimeErrorformattype)operators_or_netr   	operatorsnet r   </tmp/pip-unpacked-wheel-ua33x9lu/caffe2/python/net_drawer.py_rectify_operator_and_name+   s"    
r   c                 C   s
   t | S N)jsondumps)r   r   r   r   _escape_label@   s    r   c                    s    fdd}|S )Nc                    sR   | j rd| j | j|f }nd| j|f } rD| jD ]}|d| 7 }q2tj|fS )Nz%s/%s (op#%d)z
%s (op#%d)
)r   r   outputpydotNode)r   op_id	node_nameoutput_nameappend_outputkwargsr   r   ReallyGetOpNodeF   s    
z*GetOpNodeProducer.<locals>.ReallyGetOpNoder   )r$   r%   r&   r   r#   r   GetOpNodeProducerE   s    	r'   c                     s    fdd}|S )Nc                    s   t j| fd|i S )Nlabel)r   r   )r!   r(   r%   r   r   ReallyGetBlobNodeS   s    z.GetBlobNodeProducer.<locals>.ReallyGetBlobNoder   )r%   r*   r   r)   r   GetBlobNodeProducerR   s    r+   LRc                 C   s@  |d krt dt}|d kr$tf t}t| |\}}tj||d}i }tt}t	|D ]\}	}
||
|	}|
| |
jD ]Z}||kr|t|t||  t|d}|||< n|| }|
| |t|| qv|
jD ]`}||kr||  d7  < |t|t||  t|d}|||< |
| |t|| qqT|S )NFrankdirr(      )F)r'   OP_STYLEr+   
BLOB_STYLEr   r   Dotr   int	enumerateadd_nodeinputr   stradd_edgeEdger   )r   r   r.   op_node_producerZblob_node_producerr   graphZpydot_nodesZpydot_node_countsr    r   op_node
input_name
input_noder"   output_noder   r   r   GetPydotGraphW   sH    








rA   Fc                    s  |dkrt dt}t| |\}}tj||d}i  ttt|D ]\}}|||}	||	  fdd|j	D }
|	 
|
 |
D ]|	 
  q|r|
D ].tfdd|
D r|t|	 qn|
D ]|t|	 q|jD ]}|	 |< qqB|S )aY  Different from GetPydotGraph, hide all blob nodes and only show op nodes.

    If minimal_dependency is set as well, for each op, we will only draw the
    edges to the minimal necessary ancestors. For example, if op c depends on
    op a and b, and op b depends on a, then only the edge b->c will be drawn
    because a->c will be implied.
    NFr-   c                    s   g | ]}| kr | qS r   r   ).0r>   )blob_parentsr   r   
<listcomp>   s   z(GetPydotGraphMinimal.<locals>.<listcomp>c                    s   g | ]} | kqS r   r   )rB   Z
other_node)nodeop_ancestryr   r   rD      s   )F)r'   r1   r   r   r3   r   setr5   r6   r7   updateallr9   r:   r   )r   r   r.   minimal_dependencyr;   r   r<   r    r   r=   parentsr"   r   )rC   rE   rF   r   GetPydotGraphMinimal   s8    




rL   c                 C   sR   i }t | jD ]>\}}|dr8|j|| jd |j < q|j|| jd|  < q|S )Nr   _z_network_%d)r5   networkZHasFieldr   r   )plan_defZoperator_mapZnet_idr   r   r   r   GetOperatorMapForPlan   s    
rP   c                 C   s^   g }t | D ]L\}}|tt| ||d  |dkr|t|d |d  q|S )Nr   )r5   appendr   r   r   r6   r9   r:   )netsgnodesir   r   r   r   
_draw_nets   s    rX   c                    s`  d} fdd}dd }g }t | D ]4\}  j}|tjt| ft ||d  |dkr|s|t	|d |d   j
rt j
|}	n: jr|rt jd | |d	d
}	qt j|}	ntd|rB|	D ]}
|||d |
 qt j|krZtjdt j| ft}|| |||d | q$|||d |	d  q$|S )N   c                     sf    j d g}  jr$| d j  jr<| d j  jrL| d  jr\| d d| S )Nr   zReporter: {}zStopper: {}Z
ConcurrentZOnce)r   Z
report_netrS   r   Zshould_stop_blobconcurrent_substepsZ	only_oncejoinr/   stepr   r   	get_label   s    

z_draw_steps.<locals>.get_labelc                 S   s   t j| |dddS )NdotZdashed)Z	arrowheadr   )r   r:   )startendr   r   r   substep_edge   s    z!_draw_steps.<locals>.substep_edgerQ   r   rR   T)skip_step_edgeszinvalid stepz{} more steps)r5   rZ   rS   r   r   r   r1   r6   r9   r:   rN   rX   Zsubstep_draw_steps
ValueErrorlenr   )ZstepsrU   rc   ZkMaxParallelStepsr^   rb   rV   rW   parallelZ	sub_nodesZsnZellipsisr   r\   r   rd      sD      
rd   TBc                 C   s   t j||d}t| j| |S )Nr-   )r   r3   rd   Zexecution_step)rO   r   r.   r<   r   r   r   GetPlanGraph  s    ri   c              	   C   s  t | d \}}i }tt}g }g }t|D ]B\}}	|	jrJ|	jd |	j n|	j}
t|}|||
|dd |	jD ]h}t	|t
||  }||krt||dd}t|||< || n|||  }||| |d qr|	jD ]}t	|t
||  }||kr(||  d7  < t	|t
||  }||krXt||dd}t|||< || |||| d qq*t|d}t||d	| W 5 Q R X d S )
N/r   )idr(   r    r   Zblob)rk   r(   r   )sourcetargetr0   w)rV   edges)r   r   r4   r5   r   r   rf   rS   r7   r   r8   r   openr   dump)r   Zoutput_filepathr   rM   Zblob_strid_to_node_idZnode_name_countsrV   ro   r    r   Zop_labelZ
op_node_idr>   Zstridr?   r"   r@   fr   r   r   GetGraphInJson	  sh    





rs   sC   PNG

   IHDR          7n$   
IDATxc`    Hq    IENDB`c              
   O   sh   z(| ||}t |tjs td| W S  tk
rb } ztd| t	 W Y S d}~X Y nX dS )z
    Invokes `func` (e.g. GetPydotGraph) with args. If anything fails - returns
    and empty image instead of throwing Exception
    z$func is expected to return pydot.DotzFailed to draw graph: {}N)
r
   r   r3   re   Z
create_png	Exceptionloggererrorr   _DummyPngImage)funcargsr%   r<   er   r   r   GetGraphPngSafeK  s    

r{   c            
   	   C   sr  t jdd} | jdtddd | jdtdd	d
 | jdddd | jdddd | jdddd | jdtddd
 |  }t|jd.}| }t	|t
jdd t
jdd i}W 5 Q R X t|D ]\}}|jrt|||jt|jft|jd}nt|||jt|jftd}|j|  d }|j|dd |d d d  }	z||	 W q tk
rj   td! Y qX qd S )"NzCaffe2 net drawer.)descriptionz--inputTzThe input protobuf file.)r   requiredhelpz--output_prefix z.The prefix to be added to the output filename.)r   defaultr~   z	--minimal
store_truez(If set, produce a minimal visualization.)actionr~   z--minimal_dependencyz%If set, only draw minimal dependency.z--append_outputz6If set, append the output blobs to the operator names.z	--rankdirr,   z&The rank direction of the pydot graph.rc                 S   s   t | S r   )rP   xr   r   r   <lambda>z      zmain.<locals>.<lambda>c                 S   s   | j | jiS r   )r   r   r   r   r   r   r   {  r   )r   r.   node_producerrJ   )r   r.   r   z.dotraw)r   Zpdfa#  Error when writing out the pdf file. Pydot requires graphviz to convert dot files to pdf, and you may not have installed graphviz. On ubuntu this can usually be installed with "sudo apt-get install graphviz". We have generated the .dot file but will not be able to generate pdf file for now.)argparseArgumentParseradd_argumentr8   
parse_argsrp   r7   readr   ZGetContentFromProtoStringr   ZPlanDefr   r   ZminimalrL   r.   r'   r$   r1   rJ   rA   Zoutput_prefixget_namewriteZ	write_pdfrt   print)
parserry   ZfidcontentZgraphskeyr   r<   filenameZpdf_filenamer   r   r   mainZ  s             r   __main__)Nr,   NN)Nr,   FN)F)Nrh   )$r   r   loggingcollectionsr   Zcaffe2.pythonr   Zfuture.utilsr   	getLogger__name__ru   setLevelINFOr   ImportErrorinfor   Zcaffe2.protor   r1   r2   r   r   r'   r+   rA   rL   rP   rX   rd   ri   rs   rw   r{   r   r   r   r   r   <module>   sb   

    
2    
3


5
=A
