U
    <c6                     @   s  d dl mZ d dlZd dlmZmZ 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mZ d
dddddddgZdddgZdZdZG dd deZG dd deZG dd deZG dd deZG dd  d eZd,d"d#Zd-d%d&Zejd'd( Zej j!e"d)d*d+Z#dS ).    )OrderedDictN)DictAny)RunMetadata)GraphDef)	StepStatsDeviceStepStats)
VersionDef   )
node_protoattributeNamesZhasMultipleOutputsZhasUsesinputskindoutputsZoutputsSize	scopeNamenodeoffset	debugNamezprim::GetAttrZ	ClassTypec                   @   s   e Zd ZdddZdd ZdS )	NodeBaseNUnSpecified c                 C   s(   || _ || _|| _|| _|| _|| _d S N)r   r   tensor_sizer   
attributesscope)selfr   r   r   r   op_typer    r   J/tmp/pip-unpacked-wheel-gikjz4vx/torch/utils/tensorboard/_pytorch_graph.py__init__$   s    zNodeBase.__init__c              	   C   sh   g }| tt|  t| D ]:}d|kr| |d tt| | ttt| |  qd|d S )N__z: 
z

)appendstrtypedirgetattrjoin)r   reprmr   r   r   __repr__6   s    &zNodeBase.__repr__)NNNNr   r   )__name__
__module____qualname__r   r*   r   r   r   r   r   #   s         
r   c                       s   e Zd Z fddZ  ZS )NodePyc                    s   t t| | |d d  }g | _|D ]}|dks:|dkrtt|| }g }g }|D ]8}||  | r||	 
  qV|d  qVt| || t| |d | q&t| |t||  q&d S )Nr   r   r   )superr.   r   r   listr&   r"   r   ZisCompleteTensorr$   sizessetattr)r   node_cppZvalid_methodsr)   Zlist_of_nodeZio_unique_namesZio_tensor_sizesn	__class__r   r   r   B   s     zNodePy.__init__r+   r,   r-   r   __classcell__r   r   r5   r   r.   A   s   r.   c                       s   e Zd Zd fdd	Z  ZS )NodePyIONc                    s^   t t| |t z|  }W n tk
r<   dg}Y nX || _d| _|rZ|| _	d| _d S )Nr
   	ParameterzIO Node)
r/   r9   r   
methods_IOr$   r1   RuntimeErrorr   r   input_or_output)r   r3   r=   r   r5   r   r   r   [   s    
zNodePyIO.__init__)Nr7   r   r   r5   r   r9   Z   s   r9   c                       s   e Zd Z fddZ  ZS )NodePyOPc                    sD   t t|  t t fdd  D dd| _  | _d S )Nc                    s   i | ]}|t  |qS r   )	_node_get).0kr3   r   r   
<dictcomp>t   s      z%NodePyOP.__init__.<locals>.<dictcomp>' )	r/   r>   r   
methods_OPr#   r   replacer   r   )r   r3   r5   rB   r   r   o   s     zNodePyOP.__init__r7   r   r   r5   r   r>   n   s   r>   c                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )GraphPya  Helper class to convert torch.nn.Module to GraphDef proto and visualization
    with TensorBoard.

    GraphDef generation operates in two passes:

    In the first pass, all nodes are read and saved to two lists.
    One list is for input/output nodes (nodes_io), which only have inbound
    or outbound connections, but not both. Another list is for internal
    operator nodes (nodes_op). The first pass also saves all scope name
    appeared in the nodes in scope_name_appeared list for later processing.

    In the second pass, scope names are fully applied to all nodes.
    debugNameToScopedName is a mapping from a node's ID to its fully qualified
    scope name. e.g. Net1/Linear[0]/1. Unfortunately torch.jit doesn't have
    totally correct scope output, so this is nontrivial. The function
    populate_namespace_from_OP_to_IO and find_common_root are used to
    assign scope name to a node based on the connection between nodes
    in a heuristic kind of way. Bookkeeping is done with shallowest_scope_name
    and scope_name_appeared.
    c                 C   s$   g | _ t | _i | _d| _g | _d S )Ndefault)nodes_opr   nodes_iounique_name_to_scoped_nameshallowest_scope_namescope_name_appearedr   r   r   r   r      s
    zGraphPy.__init__c                 C   s0   t |tr|| j|j< t |tr,| j| d S r   )
isinstancer9   rK   r   r>   rJ   r"   )r   xr   r   r   r"      s    

zGraphPy.appendc                 C   s:   t d | jD ]}t | q| jD ]}t | j|  q"d S )Nz	all nodes)printrJ   rK   )r   r   keyr   r   r   printall   s
    


zGraphPy.printallc                 C   s$   | j D ]}|r|dd | _qd S )N/r   )rN   splitrM   )r   Z	fullscoper   r   r   find_common_root   s    
zGraphPy.find_common_rootc              
      s   j D ]L}t|j|jD ]8\}} j|j t||j|j||j	|j
d j|< qq    j D ]$}|jD ]}|jd |  j|< qlqb j D ]\}}t|tkr|jd |j  j|< t|dr|jd |j  j|< t|dr|jd k	r|jd |j  j|< |jdkr jr jd |j  j|j< q j D ]H\}} fdd|jD  j| _|j jkr: j|j  j| _q:d S )N)r   r   rU   r=   r   r   c                    s   g | ]} j | qS r   )rL   )r@   Znode_input_idrO   r   r   
<listcomp>   s   z<GraphPy.populate_namespace_from_OP_to_IO.<locals>.<listcomp>)rJ   zipr   Zoutputstensor_sizerN   r"   r   r   r   r   r   rK   rW   rL   itemsr$   r   r   hasattrr=   rM   )r   r   Znode_outputZ
outputSizeZinput_node_idrS   r   rO   r    populate_namespace_from_OP_to_IO   sF    
	



z(GraphPy.populate_namespace_from_OP_to_IOc              
   C   s:   g }| j  D ]&}|t|j|j|j|j|jd q|S )zi
        Converts graph representation of GraphPy object to TensorBoard
        required format.
        )inputZ
outputsizeopr   )	rK   valuesr"   r   r   r   r   r   r   )r   nodesvr   r   r   to_proto   s    	zGraphPy.to_protoN)
r+   r,   r-   __doc__r   r"   rT   rW   r\   rb   r   r   r   r   rH   y   s   /rH   Tc                    s2  t |}i }t }|  D ]:}|r4t | dkr4q|  tkr|t|d qi }| 	 D ]}| t
kr$|d}	|  }
|  }| t
kr|d}|  }|| }|dd }d|||	||
< nd|	||
< |   tkr2t|}||
 |_|| qb|t| qbt|  D ]:\}}t|d}d	|d
 |_| g|_|| q@dd }i  ||}|jddD ]0\}}||}|dd }	d||	 |< q|jD ]L}|jd} fdd|D }||_t|r| jdd| 7  _q|  | S )a  This method parses an optimized PyTorch model graph and produces
    a list of nodes and node stats for eventual conversion to TensorBoard
    protobuf format.

    Args:
      graph (PyTorch module): The model graph to be parsed.
      trace (PyTorch JIT TracedModule): The model trace to be parsed.
      args (tuple): input tensor[s] for the model.
      omit_useless_nodes (boolean): Whether to remove nodes from the graph.
    r   r]   namerU   z{}/{}.{}z__module.{}outputz	output.{}r
   c                 S   s&   t | tjjr| j}nt| dd}|S )Noriginal_nameModule)rP   torchjitZTracedModule_namer&   )modulemodule_namer   r   r   parse_traced_name%  s    z parse.<locals>.parse_traced_nameZ__module)prefix.z{}[{}]c                    s*   g | ]"}| kr | n| d d qS )rp   re   )rV   )r@   aliasZalias_to_namer   r   rX   5  s   zparse.<locals>.<listcomp>)lenrH   r   Zusesr$   r   CLASSTYPE_KINDr"   r9   r`   GETATTR_KINDsrf   r   r]   r   rV   formatr>   r   	enumerater   Znamed_modulesrJ   anyr'   r\   rb   )graphtraceargsZomit_useless_nodesZn_inputsr   Znodes_pyr   Zattr_to_scope	attr_nameZattr_keyparentZparent_attr_nameZparent_attr_keyZparent_scopeZ
attr_scopeZnode_pyiZ	node_pyiorn   	base_namerd   rl   mod_nameZmodule_aliasesreplacementsr   rr   r   parse   sn    


  





r   Fc           	      C   s   t | f z(tjj| ||d}|j}tj| W n6 tk
rh } zt| td |W 5 d}~X Y nX W 5 Q R X |rt| t	|||}t
ttddgdd}t|tdd	d
|fS )a
  
    This method processes a PyTorch model and produces a `GraphDef` proto
    that can be logged to TensorBoard.

    Args:
      model (PyTorch module): The model to be parsed.
      args (tuple): input tensor[s] for the model.
      verbose (bool): Whether to print out verbose information while
        processing.
      use_strict_trace (bool): Whether to pass keyword argument `strict` to
        `torch.jit.trace`. Pass False when you want the tracer to
        record your mutable container types (list, dict)
    )strictzError occurs, No graph savedNz/device:CPU:0)Zdevice)Z	dev_stats)Z
step_stats   )Zproducer)r   versions)_set_model_to_evalri   rj   r{   rz   _CZ_jit_pass_inliner<   rR   r   r   r   r   r   r	   )	modelr|   verboseZuse_strict_tracer{   rz   eZlist_of_nodesZ	stepstatsr   r   r   rz   A  s     
 rz   c              	   c   sJ   t | tjjs8| j}| d z
dV  W 5 | | X nz
dV  W 5 X dS )zLA context manager to temporarily set the training mode of ``model`` to eval.FN)rP   ri   rj   ZScriptFunctionZtrainingZtrain)r   Zoriginally_trainingr   r   r   r   n  s    


r   )r   rS   c                 C   s   |  |}t| ||S )z@Gets attributes of a node which is polymorphic over return type.)ZkindOfr&   )r   rS   selr   r   r   r?     s    
r?   )NT)FT)$collectionsr   
contextlibtypingr   r   Z#tensorboard.compat.proto.config_pb2r   Z"tensorboard.compat.proto.graph_pb2r   Z'tensorboard.compat.proto.step_stats_pb2r   r   Z%tensorboard.compat.proto.versions_pb2r	   ri   Z_proto_graphr   rF   r;   ru   rt   objectr   r.   r9   r>   rH   r   rz   contextmanagerr   r   Noder#   r?   r   r   r   r   <module>   s<   
s
U
-
