U
    ©Ê¹j±<  ã                	   @   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eejjeejjjgef eeeef  ee dœdd„ƒZdS )é    N)ÚAnyÚCallableÚDictÚListÚOptional)Úcompatibility)ÚGraphModuleÚ	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Úpartitions_dependent_onÚpartition_dependentsÚtorchÚfxÚgraphÚGraphÚenvironmentÚtargets)Úselfr   © r   ú[/var/www/html/bwave/python/venv/lib/python3.8/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    2ÿ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ˆ  t jjjttt jjjf ttt jjjf dœ‡‡fdd„}i ‰i ‰t jjjtt jjj dœ‡fdd„‰	ˆj	j
D ]¾‰ˆˆˆj< ˆjdkrˆqnˆjdkr²t jj	 ˆjd	 ‡	fd
d„¡ qnt|ˆƒƒ}ˆ |¡‰ˆdkràt|ƒ ˆ|< ‰ˆj ˆj¡ |ˆ_t jj	 ˆj‡‡	fdd„¡ t jj	 ˆj‡‡	fdd„¡ qntˆ ¡ ƒ}g }ˆ ¡ D ] \}‰tˆjƒ�sF| |¡ �qFg }	|�rÀ| ¡ }
|	 |
¡ ˆ|
 jD ],}ˆ| j |
¡ ˆ| j�sŽ| |¡ �qŽ�qlt|	ƒtˆƒk�rÚtdƒ‚|	D ]P}ˆ| ‰ˆjD ]:}ˆj	j|ˆ| jd�}ˆ| j  !¡ |_ |ˆj"ˆ| < �qð�qÞˆj	j
D �]6‰t#ˆdƒ�r8ˆˆj ‰ˆj"‰t jj	 ˆj‡fdd„¡}t jj	 ˆj‡fdd„¡}ˆjdk�r¢ˆj$}n|ˆj$ %d¡}ˆ}|D ].}t#||ƒ�sØt&dˆj$› d�ƒ‚t'||ƒ}�q¶d (|¡}|ˆj)|< |dk	�rˆj*› d|› �}ˆj$||< t+|t,ƒ�s.t-‚t+|t.ƒ�s>t-‚ˆj	j/ˆj|||ˆjd�}ˆj  !¡ |_ |ˆj"ˆ< �q8i ‰i ‰ t jj	 0¡ ‰i }|�s²ˆj	j
D ]‰|ˆˆ |ƒ\‰ }�q˜nˆj	j
D ]‰ˆˆˆj< �qº|�sÖ|	n|}t1ƒ }|D �]P}ˆ| ‰t,‡‡fdd„ˆj2D ƒƒ}t|ƒ}|dk�r0ˆj	 3|d	 ¡ n|dk�rFˆj	 3|¡ |�r”‡fdd„ˆjD ƒ}|D ].‰ˆ|k�rv�qd|ˆˆ |ƒ\‰ }| 4ˆ¡ �qdt jj ˆj)ˆj	¡|ˆj*< ˆ 5ˆj*t,‡ fdd„ˆjD ƒƒ¡}tˆj2ƒ}|dk�rt jj6 7|¡}t8ˆj2ƒD ]\}} || jˆ | < �qün|dk�rä|ˆ tˆj2ƒd	 < �qäˆj	j
D ]6‰ˆjdk�r@ˆ 3t jj	 ˆjd	 ‡ fd d„¡¡ �q@t 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rXt| jƒdkr"| jd ntjj}ˆ j| j| j|d�|| j	< | j
 ¡ || j	 _
nt| j dkrÌˆ  | j¡|| j	< | j
 ¡ || j	 _
ˆ}| j d¡D ]*}t||ƒs¶td| j› d�ƒ‚t||ƒ}q–||| 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-   Z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r„|d k	rRˆ | }|j | j¡ |d k	rR|j |¡ |d k	r„ˆ | }|j | j¡ |d k	r„|j |¡ d S )NÚ_fx_partition)r>   r   Ú
setdefaultr   r   r   r   )rB   rC   Zdef_partition_nameZuse_partition_nameZdef_partitionZ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)rG   r   r   Ú<lambda>Ã   ó    zsplit_module.<locals>.<lambda>Nc                    s
   ˆ| ˆ ƒS rI   r   ©rB   ©r(   rG   r   r   rL   Ñ   rM   c                    s
   ˆ| ˆ ƒS rI   r   rN   rO   r   r   rL   Ô   rM   z cycle exists between partitions!)r,   rD   c                    s   ˆ |  S rI   r   rJ   ©r   r   r   rL   ü   rM   c                    s   ˆ |  S rI   r   rJ   rP   r   r   rL   þ   rM   )Úcall_moduler.   r/   zOperator target r0   Ú_)r1   r7   r3   Úkwargsr,   c                 3   s   | ]}ˆj ˆ |  V  qd S rI   rP   ©Ú.0r   )Ú
orig_nodesÚ	partitionr   r   Ú	<genexpr>@  s    zsplit_module.<locals>.<genexpr>é   c                    s   g | ]}ˆ | ‘qS r   r   )rU   Úkey)Úorg_mod_envr   r   Ú
<listcomp>M  s    z split_module.<locals>.<listcomp>c                 3   s   | ]}ˆ | V  qd S rI   r   rT   ©r)   r   r   rX   `  s     c                    s
   ˆ | j  S rI   r   rJ   r]   r   r   rL   o  rM   )9r   r   r(   ÚNoder   r"   Zgraph_moduler   r   r   Znodesr   r1   Zmap_argr3   Úgetr	   r   ÚappendrD   rS   ÚlistÚkeysÚitemsr2   r   Úpopr   ÚRuntimeErrorr   r+   r8   r9   r:   r   r<   r7   r;   r=   r>   Újoinr   r   Ú
isinstanceÚtupleÚAssertionErrorÚdictZcreate_noder   Úsetr   rH   ÚaddrQ   ÚproxyZProxyÚ	enumerate)!r#   r$   r%   r&   r'   rA   Zpartition_nameZoriginal_partition_orderZroot_partitionsZsorted_partitionsZroot_partitionZ	dependentÚinputr+   Zgathered_argsZgathered_kwargsr7   Ztarget_atomsZtarget_attrr?   ÚqualnameÚnew_noder*   Zconstruct_order_partitionsZalready_constructed_attr_nodesZoutput_valsZnum_output_valsZorg_mod_attr_nodesZ
output_valZnum_outputsZoutput_val_proxyÚiZoutput_namer   )
r)   r@   r   r#   r(   r[   rV   rW   rF   rG   r   r
   %   s,   hý ÿ


 
ÿ
 ÿ ÿ

þ
 
ÿ



û  ÿ	ÿ
ÿ


ÿ
  ÿ ÿ
þ


ÿ)NF)r4   Útypingr   r   r   r   r   r   Ztorch.fx._compatibilityr   Ztorch.fx.graph_moduler   Ú__all__r	   ÚnnÚModuler   r(   r^   Úintr"   Úboolr
   r   r   r   r   Ú<module>   s"     ûû