a
    hh                  
   @   s   d dl Z d dlZd dlmZ d dlmZmZmZ d dlZd dl	m
Z
 d dlmZ d dlmZ d dlmZ dd	gZee ZZe
d
dG dd dZejjeedddZe
d
ddeejjeegef eeeef  ee ee eddd	ZdS )    N)OrderedDict)AnyCallableOptional)compatibility)lazy_format_graph_code)GraphModule)Node	Partitionsplit_moduleT)Zis_backward_compatiblec                   @   s(   e Zd ZedddZedddZdS )r
   namec                 C   sN   || _ d| | _g | _i | _i | _i | _i | _tjj	
 | _	i | _i | _d S )NZsubmod_)r   submod_name
node_namesinputsoutputsdependencies
dependentstorchfxgraphGraphenvironmenttargets)selfr    r   J/var/www/auris/lib/python3.9/site-packages/torch/fx/passes/split_module.py__init__   s    zPartition.__init__)returnc                 C   s4   d| j  d| j d| j d| j d| j d| j S )Nzname: z
,
 nodes: z,
 inputs: z,
 outputs: z,
 partitions depended on: z,
 partition dependents: )r   r   r   r   r   r   )r   r   r   r   __repr__    s    
zPartition.__repr__N)__name__
__module____qualname__strr   r   r   r   r   r   r
      s   )modqualnamer   c                 C   s<   | }| dD ](}t||s,td| dt||}q|S )N.zNode target z not found!)splithasattrAttributeErrorgetattr)r$   r%   attr_valZatomr   r   r   _get_attr_from_qualname+   s    
r,   F)mroot_msplit_callbackqualname_mapkeep_original_orderkeep_original_node_namekeep_original_input_namec           8   
      sf
  t dtddd ttttf tttjjj	f dfdd}dd	l
}i i i ttt d
fddfdd}	tjjtjjtjjg}
t }t }i }d	}t }jjD ]		jd }d	urt|tjtjfrt|jj }|jr|vr	|jj< 	jdv r$q|		 	jdkr@	j|
v r@	jtjjkrt	j dkshJ t	j d t!s~J 	}t	h||< n	jtjjkrt"dd 	j D sJ |#	 t	h|	< d	|	< nZ	jtjjkr@t	j dks
J |	j d  #	 |$	j d  	|	j d < |d	ur\|| #	 |D ]}|| #	 q`qt"dd |% D sJ ddd |& D }dd |& D }t'(t)j*rt'd| t'd| t!|pt!|}d}jjD ]			j+< 	jdv r"q	jdkrPtjj,	j d fdd  q|r	}||ks|J d!| d"| |}	j|
vrtjj,	j 	fd#d  tjj,	j-	fd$d  qt./ }g }& D ] \}tj0s|1| qg }|rZ|2 }|1| | j3D ],}| j02| | j0s(|1| q(qt|tkrtt4d%||fD ]}|& D ]\	}t|dksJ 	t|d  j5	< |dd	 D ]T}t| jj6	j	jt7d&d 	j D i 	j8d'}	j9 |_|j5	< qĐqq||D ]}| i dj:D ] } fd(d)}!| jd*krt| jtsJ t;| j}"t|"tj<j=rj>| j}#|"j?| j< n|! }#n|! }# j9 |#_|#j5 < q@_:q&jjD ]	t@	d+r	jA j5tjj,	j fd,d }$tjj,	j-fd-d }%	jd.vrd	j}&nHt;	j}'	jBd/d0}&|'j?|&< |d	urjC d/|& }(	j||(< t|$t7sJ t|%tsJ r؈	j+nd	})jj6	j|&|$|%	j8|)d1}	j9 |_|j5	< q|fD ]}tD|D ]	|	 }t|dksBJ |d	d D ]\}t| |	 }*|*d	usxJ d2jj6|*j|*jj5	 fi |*j8d'}|*j9 |_qNq$qi 
i  tjjE i }+|sjjD ]	|	 |+\ }+qnjjD ]		
	j+< q|s|n|},t }-d3d4 jjD |,D ]}| t7fd5djFD }.t|.}/|/dkrjG|.d  n$|/dkrjG|. njGd6 |	r,
fd7d4j:D }0D ].		|-v rڐq|	 |+\ }1|-#	 q|0D ].		|-v 	rq|	 |+\ }+|-#	 qtjj	j?j|+jC< HjCt7 fd8dj:D }2tjF}3|3dk	rtjjIJ|2}4tKjFD ]\}5}6|4|5 j |6< 	qn|3dkr8|2 tLtMjF< q8|	r 	sjjD ]	|	 |+\ }+	qjjD ]6		jdk
rGtjj,	j d  fd9d  
qtjj	|+}7t dtd:|7dd |7S );a  
    Creates subgraphs out of main graph

    Args:
        m (GraphModule): Graph module to split
        root_m (torch.nn.Module): root nn module. Not currently used. Included
            because the root nn module is usually transformed via
            torch.fx._symbolic_trace.symbolic_trace (see example below)
        split_callback (Callable[[Node], int]): Callable function
            that maps a given Node instance to a numeric partition identifier.
            split_module will use this function as the policy for which operations
            appear in which partitions in the output Module.
        qualname_map: Optional[Dict[str, str]]: optional output parameter that returns a
            mapping from new target names in the module after split to old target
            names in the original module.
        keep_original_order: Optional[bool]: keep the original order of the GraphModule
            or use the Topological order of the new constructed GraphModule
        keep_original_node_name: Optional[bool]: If the partitioned graphs should
            have the same node names as the original graph.
        keep_original_input_name: bool: If the partitioned graphs should
            have the same input names as the original graph.

    Returns:
        GraphModule: the module after split.

    Example:

        This is a sample setup:

            import torch
            from torch.fx.symbolic_trace import symbolic_trace
            from torch.fx.graph_module import GraphModule
            from torch.fx.node import Node
            from torch.fx.passes.split_module import split_module

            class MyModule(torch.nn.Module):
                def __init__(self) -> None:
                    super().__init__()
                    self.param = torch.nn.Parameter(torch.rand(3, 4))
                    self.linear = torch.nn.Linear(4, 5)

                def forward(self, x, y):
                    z = self.linear(x + self.param).clamp(min=0.0, max=1.0)
                    w = self.linear(y).clamp(min=0.0, max=1.0)
                    return z + w

            # symbolically trace model
            my_module = MyModule()
            my_module_traced = symbolic_trace(my_module)

            # random mod partitioning
            partition_counter = 0
            NPARTITIONS = 3

            def mod_partition(node: Node):
                global partition_counter
                partition = partition_counter % NPARTITIONS
                partition_counter = (partition_counter + 1) % NPARTITIONS
                return partition

            # split module in module with submodules
            module_with_submodules = split_module(
                my_module_traced, my_module, mod_partition
            )

        Output looks like this. Original graph is broken into partitions

            > print(module_with_submodules)
            GraphModule(
                (submod_0): GraphModule(
                    (linear): Linear(in_features=4, out_features=5, bias=True)
                )
                (submod_1): GraphModule(
                    (linear): Linear(in_features=4, out_features=5, bias=True)
                )
                (submod_2): GraphModule()
            )

            def forward(self, x, y):
                param = self.param
                submod_0 = self.submod_0(x, param, y);  x = param = y = None
                getitem = submod_0[0]
                getitem_1 = submod_0[1];  submod_0 = None
                submod_1 = self.submod_1(getitem, getitem_1);  getitem = getitem_1 = None
                getitem_2 = submod_1[0]
                getitem_3 = submod_1[1];  submod_1 = None
                submod_2 = self.submod_2(getitem_2, getitem_3);  getitem_2 = getitem_3 = None
                return submod_2

        Output of split module is the same as output of input traced module.
        This is an example within a test setting:

            > orig_out = my_module_traced(x, y)
            > submodules_out = module_with_submodules(x, y)
            > self.assertEqual(orig_out, submodules_out)
            True
    z%szpre split_moduleT)Zcolored)nodebase_mod_envbase_mod_attrsc                    s   | j dkrt| jdkr"| jd ntjj}rb|tjju r>dn|f} jd| j|| jd|| j< n j	| j
| j|d|| j< | j || j _nT| j dkr | j
|| j< | j || j _t| j
tsJ t| j
}||| j
< ||fS )Nplaceholderr   r   )args	type_expr)r9   default_valueget_attr)oplenr8   inspect	Signatureemptycreate_noder   typer7   targetmetacopyr;   
isinstancer#   r,   )r4   r5   r6   r:   r8   r+   )base_mod_graphr2   r-   r   r   construct_graph   s2    


z%split_module.<locals>.construct_graphr   N)def_nodeuse_nodec                    sB  ddl m} t| dd }t|dd }td| j||d ur>|jnd| ||kr>|d ur | }|j| j |d ur|j| |d ur> | }|j	| j | j
d }d ur(t||tdD ]^}| }	|j	|	j | jdkrt|	dd }
|
d urȈ |
 }|j|	j |j| q|d ur>|j| d S )	Nr   )free_symbols_fx_partitionz*record_cross_partition_use %s (%s) %s (%s)-example_value)keyr7   )Z%torch.fx.experimental.symbolic_shapesrK   r*   logdebugr   r   
setdefaultr   r   rD   getsortedr#   r<   r   )rI   rJ   rK   ZdefinedusedZdef_partitionZuse_partitionZdef_valsZs_nodeZ	s_definedZs_def_partition)
partitionssymbol_to_noder   r   record_cross_partition_use   s>    

	
z0split_module.<locals>.record_cross_partition_usec                    sV   t | }td| j|  |}|d u r>t|  |< }|j| j || _d S )Nz*instantiate_node_partition_mapping %s (%s))	r#   rP   rQ   r   rS   r
   r   appendrL   )r4   partition_name	partition)rW   r/   r   r   "instantiate_node_partition_mapping   s    
z8split_module.<locals>.instantiate_node_partition_mappingrN   )r7   r;   outputcall_function   c                 s   s   | ]}t |t V  qd S N)rF   r	   .0argr   r   r   	<genexpr>D      zsplit_module.<locals>.<genexpr>c                 s   s   | ]}|d uV  qd S ra   r   )rc   vr   r   r   re   T  rf   zautocast must exitc                 S   s   i | ]\}}|t |qS r   rT   rc   krg   r   r   r   
<dictcomp>V  rf   z split_module.<locals>.<dictcomp>c                 S   s   i | ]\}}|t |qS r   rh   ri   r   r   r   rk   W  rf   zautocast_regions: %szgrad_regions: %s)r7   r;   r^   c                    s
    | d S ra   r   n)rY   r   r   <lambda>j  rf   zsplit_module.<locals>.<lambda>zRautocast or set_grad_enabled require monotonically increasing partitions:highest: z, this node's: c                    s
   |  S ra   r   rI   r4   rY   r   r   ro   z  rf   c                    s
   |  S ra   r   rp   rq   r   r   ro   }  rf   z cycle exists between partitions!c                 s   s   | ]
}|V  qd S ra   r   rb   r   r   r   re     rf   )r<   rC   r8   kwargsr9   c                     s>   r
} nd  }  d7  j j|  jd}d < |S )NZarg_r`   )r9   )r   r7   rB   )r   r7   )counterinpr3   
new_inputs
orig_nodesr\   r   r   add_placeholder  s    
z%split_module.<locals>.add_placeholderr;   rL   c                    s    |  S ra   r   rm   r   r   r   ro     rf   c                    s    |  S ra   r   rm   rx   r   r   ro     rf   )call_moduler;   r&   _)r<   rC   r8   rr   r9   r   zMissing exit nodec                 S   s   g | ]}|j d kr|qS )r7   )r<   )rc   r4   r   r   r   
<listcomp>)  rf   z split_module.<locals>.<listcomp>c                 3   s   | ]}j  |  V  qd S ra   rx   rc   r   )rv   r\   r   r   re   /  s   r   c                    s   g | ]}|vr | qS r   r   )rc   rO   )orig_mod_envoriginal_orderr   r   r{   ?  s   c                 3   s   | ]} | V  qd S ra   r   r|   r5   r   r   re   ]  rf   c                    s
    | j  S ra   r   rm   r   r   r   ro   w  rf   zpost split_module)NrP   rQ   r   r	   dictr#   r   r   Zgraph_moduler   sympyr   ampZ_enter_autocastZ_exit_autocastZ_CZ_set_grad_enabledr   setr   nodesrD   rS   rF   ZSymIntZSymFloatr4   exprZSymbolr<   rC   r=   r8   boolalladdremovevaluesitems_LOGGERisEnabledForloggingDEBUGr   Zmap_argrr   listkeysr   rZ   popr   RuntimeErrorr   rA   tuplerB   rE   r   r,   nnModuler;   r   r(   rL   replacer   reversedr   r   r^   ry   proxyZProxy	enumeratenextiter)8r-   r.   r/   r0   r1   r2   r3   rH   r   r]   ZGLOBAL_STATE_NODESZgrad_regionsZautocast_regionsZautocast_exitsZactive_gradZactive_autocastsvals0aZassert_monotonically_increasingZhighest_partitionpidZoriginal_partition_orderZroot_partitionsr[   Zsorted_partitionsZroot_partitionZ	dependentZregions_mappingZregionsrnew_nodeZ	orig_noderw   Z	orig_attrr7   Zgathered_argsZgathered_kwargsrC   Ztarget_attrr%   r   Z	exit_noder6   Zconstruct_order_partitionsZalready_constructed_attr_nodesZoutput_valsZnum_output_valsZorig_mod_attr_nodesZ_based_mod_attrsZ
output_valZnum_outputsZoutput_val_proxyiZoutput_nameretr   )r5   rG   rs   r   rt   r3   r2   r-   ru   r4   r}   rv   r~   r\   rW   rY   r/   rX   r   r   5   s   l
"0
		


 









	








)NFFT)r>   r   collectionsr   typingr   r   r   r   Ztorch.fx._compatibilityr   Ztorch.fx._utilsr   Ztorch.fx.graph_moduler   Ztorch.fx.noder	   __all__	getLoggerr    rP   r   r
   r   r   r#   r,   intr   r   r   r   r   r   r   <module>   s6   
    