o
    h<                     @   s   d dl Z d dlmZmZmZmZmZ d dlZd dlm	Z	 d dl
mZ ddgZe	ddG d	d dZe	dd		
ddedejjdeejjjgef deeeef  dee f
ddZdS )    N)AnyCallableDictListOptional)compatibility)GraphModule	Partitionsplit_moduleT)is_backward_compatiblec                   @   s(   e Zd ZdefddZdefddZdS )r	   namec                 C   sN   || _ d| | _g | _i | _i | _i | _i | _tjj	
 | _	i | _i | _d S )Nsubmod_)r   submod_name
node_namesinputsoutputspartitions_dependent_onpartition_dependentstorchfxgraphGraphenvironmenttargets)selfr    r   R/var/www/html/ai/venv/lib/python3.10/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 dependent 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    Fmroot_msplit_callbackqualname_mapkeep_original_orderc           !   	      s|  dt jjjdttt jjjf dttt jjjf ffdd}i i dt jjjdtt jjj ffdd		j	j
D ]_j< jd
v rGq:jdkr\t jj	jd 	fdd q:t|}|du rst| |< jj |_t jj	j	fdd t jj	j	fdd q:t }g } D ]\}tjs|| qg }	|r| }
|	|
 |
 jD ]}| j|
 | js|| q|st|	tkrtd|	D ]&}| jD ]}j	j|| jd}| j ! |_ |j"| < qqj	j
D ]t#drj j"t jj	jfdd}t jj	jfdd}jdvrKj$}n>j$%d}}|D ]}t#||sft&dj$ dt'||}qUd(|}|j)|< |durj* d| }j$||< t+|t,sJ t+|t-sJ j	j.j|||jd}j ! |_ |j"< qi i  t jj	/ i }|sӈj	j
D ]| |\ }qnj	j
D ]j< q|s|	n|}t0 }|D ]}| t,fddj1D }t|}|dkrj	2|d  n|dkrj	2| |rCfd d!jD }|D ]|v r4q+| |\ }|3 q+t jjj)j	|j*< 4j*t, fd"djD }tj1}|dkrt jj56|}t7j1D ]\}} || j | < qwq|dkr| tj1d < qj	j
D ]jdkr2t jj	jd  fd#d qt jj|S )$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[[torch.fx.node.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


    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):
                    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
    nodebase_mod_envbase_mod_attrsc                    s   | j dkr/t| jdkr| jd ntjj} j| j| j|d|| j	< | j
 || j	 _
||fS | j dkri | j|| j	< | j
 || j	 _
}| jdD ]}t||s^td| j dt||}qN||| j< ||fS )Nplaceholderr   )	type_exprdefault_valueget_attr.zNode target  not found!)oplenargsinspect	Signatureemptyr,   targettyper   metacopyr/   splithasattrAttributeErrorgetattr)r)   r*   r+   r.   attr_valatom)base_mod_graphr$   r   r   construct_graph   s$   





z%split_module.<locals>.construct_graphdef_nodeuse_nodec                    s   t | dd }t |dd }||krD|d ur) | }|j| j |d ur)|j| |d urF | }|j| j |d urH|j| d S d S d S d S )N_fx_partition)r?   r   
setdefaultr   r   r   r   )rD   rE   def_partition_nameuse_partition_namedef_partitionuse_partition)
partitionsr   r   record_cross_partition_use   s    z0split_module.<locals>.record_cross_partition_use)r,   r/   outputr   c                    s
    | d S Nr   n)rM   r   r   <lambda>      
 zsplit_module.<locals>.<lambda>Nc                    
   |  S rO   r   rD   r)   rM   r   r   rR      rS   c                    rT   rO   r   rU   rV   r   r   rR      rS   z cycle exists between partitions!)r-   rF   c                        |  S rO   r   rP   r   r   r   rR          c                    rW   rO   r   rP   rX   r   r   rR      rY   )call_moduler/   r0   zOperator target r1   _)r2   r8   r4   kwargsr-   c                 3   s    | ]
}j  |  V  qd S rO   rX   .0r   )
orig_nodes	partitionr   r   	<genexpr>@  s    
zsplit_module.<locals>.<genexpr>   c                    s   g | ]} | qS r   r   )r^   key)org_mod_envr   r   
<listcomp>M  s    z split_module.<locals>.<listcomp>c                 3   s    | ]} | V  qd S rO   r   r]   r*   r   r   ra   `  s    c                    s
    | j  S rO   )r   rP   rf   r   r   rR   o  rS   )8r   r   r)   Noder   r#   graph_moduler   r   r   nodesr   r2   map_argr4   getr	   r   appendrF   r\   listkeysitemsr3   r   popr   RuntimeErrorr   r,   r9   r:   r;   r   r=   r8   r<   r>   r?   joinr   r   
isinstancetupledictcreate_noder   setr   rN   addrZ   proxyProxy	enumerate)!r$   r%   r&   r'   r(   rC   partition_nameoriginal_partition_orderroot_partitionssorted_partitionsroot_partition	dependentinputr,   gathered_argsgathered_kwargsr8   target_atomstarget_attrrA   qualnamenew_noder+   construct_order_partitionsalready_constructed_attr_nodesoutput_valsnum_output_valsorg_mod_attr_nodes
output_valnum_outputsoutput_val_proxyioutput_namer   )
r*   rB   r   r$   r)   rd   r_   r`   rL   rM   r   r
   %   s6  g









	





	







)NF)r5   typingr   r   r   r   r   r   torch.fx._compatibilityr   torch.fx.graph_moduler   __all__r	   nnModuler   r)   rg   intr#   boolr
   r   r   r   r   <module>   s,    