
    ǄgV                     4   d dl mZ d dlmZ d dlmZ d dlmZmZm	Z	m
Z
mZ d dlmZ d dlmZ d dlmZ d dlmZ d	d
lmc mZ d	d
lZd	dlmZmZ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       G d d             Z' ed       G d de'             Z(y
)   )GraphModule)_make_graph_module)Graph)ArgumentNodeTargetmap_argmap_aggregate)Proxy)Tracer)compatibility)config    N)AnyDictIteratorListOptionalTupleUnion)contextmanager)tqdmInterpreterTransformerTis_backward_compatiblec            	           e Zd ZdZ ed      d dej                  j                  dede	e
   fd       Z ed      ddd	d
e	eeef      dedefd       Z ed      d        Zed        Z ed      dedefd       Z ed      dddeedf   deeef   defd       Z ed      dddeedf   deeef   defd       Z ed      dddeedf   deeef   defd       Z ed      dddeedf   deeef   defd       Z ed      dddeedf   deeef   defd       Z ed      dddeedf   deeef   defd       Z ed      defd       Z ed      dedeeef   fd       Z ed      dededefd       Zy)!r   a\	  
    An Interpreter executes an FX graph Node-by-Node. This pattern
    can be useful for many things, including writing code
    transformations as well as analysis passes.

    Methods in the Interpreter class can be overridden to customize
    the behavior of execution. The map of overrideable methods
    in terms of call hierarchy::

        run()
            +-- run_node
                +-- placeholder()
                +-- get_attr()
                +-- call_function()
                +-- call_method()
                +-- call_module()
                +-- output()

    Example:

        Suppose we want to swap all instances of ``torch.neg`` with
        ``torch.sigmoid`` and vice versa (including their ``Tensor``
        method equivalents). We could subclass Interpreter like so::

            class NegSigmSwapInterpreter(Interpreter):
                def call_function(self, target : Target,
                                  args : Tuple, kwargs : Dict) -> Any:
                    if target == torch.sigmoid:
                        return torch.neg(*args, **kwargs)
                    return super().call_function(n)

                def call_method(self, target : Target,
                                args : Tuple, kwargs : Dict) -> Any:
                    if target == 'neg':
                        call_self, *args_tail = args
                        return call_self.sigmoid(*args_tail, **kwargs)
                    return super().call_method(n)

            def fn(x):
                return torch.sigmoid(x).neg()

            gm = torch.fx.symbolic_trace(fn)
            input = torch.randn(3, 4)
            result = NegSigmSwapInterpreter(gm).run(input)
            torch.testing.assert_close(result, torch.neg(input).sigmoid())

    Args:
        module (torch.nn.Module): The module to be executed
        garbage_collect_values (bool): Whether to delete values after their last
            use within the Module's execution. This ensures optimal memory usage during
            execution. This can be disabled to, for example, examine all of the intermediate
            values in the execution by looking at the ``Interpreter.env`` attribute.
        graph (Optional[Graph]): If passed, the interpreter will execute this
            graph instead of `module.graph`, using the provided `module`
            argument to satisfy any requests for state.
    Tr   Nmodulegarbage_collect_valuesgraphc                     | _         t         j                   j                                _        || _        n j                   j                   _        i  _        d _        | _        d _         j                  rui i  _	        dt        dt        f fdt         j                  j                        D ]6  t        j                  fd       t        j                  fd       8 y y )Nr   Tnuserc                 p    | vr1|| <   j                   j                  |g       j                  |        y y N)user_to_last_uses
setdefaultappend)r"   r#   node_to_last_useselfs     \/home/mcse/projects/flask_80/flask-venv/lib/python3.12/site-packages/torch/fx/interpreter.pyregister_last_usesz0Interpreter.__init__.<locals>.register_last_usesb   s=    ,,*.$Q'**55dB?FFqI -    c                      |       S r%    r"   noder,   s    r+   <lambda>z&Interpreter.__init__.<locals>.<lambda>h   s    -?4-H r-   c                      |       S r%   r/   r0   s    r+   r2   z&Interpreter.__init__.<locals>.<lambda>i   s    /A!T/J r-   )r   dictnamed_modules
submodulesr    envnamer   extra_tracebackr&   r   reversednodesr	   argskwargs)r*   r   r   r    r1   r)   r,   s   `   @@@r+   __init__zInterpreter.__init__M   s    t{{88:;DJ**DJ%'!	&<##&&
 35>@D"Jt JD J
 !!1!12 L		#HI%JKL 'r-   )initial_envenable_io_processingr?   r@   returnc          
      t   ||ni | _         |r | j                  j                  | }t        |      | _        t        t        | j                  j                        | j                   dt        j                  r(t        t        | j                  j                              nd dddt        j                  d      }| j                  j                  D ]  }|j                  d       || j                   v r#	 | j                  |      | j                   |<   | j0                  r.| j2                  j5                  |g       D ]  }| j                   |=  |j6                  dk(  s| j                   |   }	|r| j                  j9                  |	      c S |	c S  y# t         $ r}| j"                  rd|j%                          }|j&                  r|j&                  d    d	| n
t        |      }|d
|j(                   z  }|f|j&                  dd z   |_        t+        |t,              rt/        |j&                   | d}~ww xY w)a  
        Run `module` via interpretation and return the result.

        Args:
            *args: The arguments to the Module to run, in positional order
            initial_env (Optional[Dict[Node, Any]]): An optional starting environment for execution.
                This is a dict mapping `Node` to any value. This can be used, for example, to
                pre-populate results for certain `Nodes` so as to do only partial evaluation within
                the interpreter.
            enable_io_processing (bool): If true, we process the inputs and outputs with graph's process_inputs and
                process_outputs function first before using them.

        Returns:
            Any: The value returned from executing the Module
        Nz:  r   T)totaldescinitialpositionleavedisabledelayr   zWhile executing z

z
Original traceback:
output)r7   r    process_inputsiter	args_iterr   lenr;   r8   r   verbose_progressstrlistdisable_progressupdaterun_node	Exceptionr9   format_noder<   stack_trace
isinstanceKeyErrorRuntimeErrorr   r&   getopprocess_outputs)
r*   r?   r@   r<   pbarr1   emsg	to_delete
output_vals
             r+   runzInterpreter.runk   s   " #."9;r
  ,4::,,d3D)-d#djj../ II;bH_H_T$**2B2B-C)Deg(hiv?V?V^_a JJ$$ 	fDKKNtxx
 
!%t!4 **!%!7!7!;!;D"!E ,I+, ww("!XXd^
AUtzz11*=e[ee7	f  '',T-=-=-?,@AC56VVQVVAYKtC51SC4T5E5E4FGGC!VaffQRj0AF!!X.*AFF3:s   5F	H7BH22H7c                     t        |      }i }| j                  j                  D ]   }|j                  dk(  st	        |      ||<   " |j                          | j                  |      S )a  
        Run `module` via interpretation and return the result.  This uses the "boxed"
        calling convention, where you pass a list of arguments, which will be cleared
        by the interpreter.  This ensures that input tensors are promptly deallocated.
        placeholder)r?   )rM   r    r;   r]   nextclearrd   )r*   	args_listrN   r7   r"   s        r+   	boxed_runzInterpreter.boxed_run   sa     O	!! 	)Att}$iA	) 	xxCx((r-   c              #   h   K   t        j                  |      5  d  d d d        y # 1 sw Y   y xY wwr%   )fx_tracebackset_current_meta)r*   r1   s     r+   _set_current_nodezInterpreter._set_current_node   s+     **40 		 	 	s   2&	2/2r"   c                    | j                  |      5  | j                  |      \  }}t        |t              sJ t        |t              sJ  t        | |j                        |j                  ||      cddd       S # 1 sw Y   yxY w)aB  
        Run a specific node ``n`` and return the result.
        Calls into placeholder, get_attr, call_function,
        call_method, call_module, or output depending
        on ``node.op``

        Args:
            n (Node): The Node to execute

        Returns:
            Any: The result of executing ``n``
        N)rn   fetch_args_kwargs_from_envrY   tupler4   getattrr]   targetr*   r"   r<   r=   s       r+   rU   zInterpreter.run_node   sx     ##A& 	?::1=LD&dE***fd+++&74&qxxv>		? 	? 	?s   A A<<Brs   r   r<   .r=   c                    t        |t              sJ |j                  d      rt        | j                        S 	 t        | j                        S # t        $ r-}t        |      dkD  r
|d   cY d}~S t        d| d      |d}~ww xY w)a  
        Execute a ``placeholder`` node. Note that this is stateful:
        ``Interpreter`` maintains an internal iterator over
        arguments passed to ``run`` and this method returns
        next() on that iterator.

        Args:
            target (Target): The call target for this node. See
                `Node <https://pytorch.org/docs/main/fx.html#torch.fx.Node>`__ for
                details on semantics
            args (Tuple): Tuple of positional args for this invocation
            kwargs (Dict): Dict of keyword arguments for this invocation

        Returns:
            Any: The argument value that was retrieved.
        *r   Nz+Expected positional argument for parameter z, but one was not passed in!)	rY   rQ   
startswithrR   rN   rg   StopIterationrO   r[   )r*   rs   r<   r=   sis        r+   rf   zInterpreter.placeholder   s    $ &#&&&S! ''CDNN++  Ct9q=7N&)TU[T\\x'yz  AC  C	Cs#   A 	BB *B0B  Bc                 H    t        |t              sJ | j                  |      S )a0  
        Execute a ``get_attr`` node. Will retrieve an attribute
        value from the ``Module`` hierarchy of ``self.module``.

        Args:
            target (Target): The call target for this node. See
                `Node <https://pytorch.org/docs/main/fx.html#torch.fx.Node>`__ for
                details on semantics
            args (Tuple): Tuple of positional args for this invocation
            kwargs (Dict): Dict of keyword arguments for this invocation

        Return:
            Any: The value of the attribute that was retrieved
        rY   rQ   
fetch_attrr*   rs   r<   r=   s       r+   get_attrzInterpreter.get_attr   s#      &#&&&v&&r-   c                 6    t        |t              rJ  ||i |S )a  
        Execute a ``call_function`` node and return the result.

        Args:
            target (Target): The call target for this node. See
                `Node <https://pytorch.org/docs/main/fx.html#torch.fx.Node>`__ for
                details on semantics
            args (Tuple): Tuple of positional args for this invocation
            kwargs (Dict): Dict of keyword arguments for this invocation

        Return
            Any: The value returned by the function invocation
        )rY   rQ   r}   s       r+   call_functionzInterpreter.call_function  s&     fc*** t&v&&r-   c                 R    |^}}t        |t              sJ  t        ||      |i |S )a  
        Execute a ``call_method`` node and return the result.

        Args:
            target (Target): The call target for this node. See
                `Node <https://pytorch.org/docs/main/fx.html#torch.fx.Node>`__ for
                details on semantics
            args (Tuple): Tuple of positional args for this invocation
            kwargs (Dict): Dict of keyword arguments for this invocation

        Return
            Any: The value returned by the method invocation
        )rY   rQ   rr   )r*   rs   r<   r=   self_obj	args_tails         r+   call_methodzInterpreter.call_method  s9       $9 &#&&&(wx()>v>>r-   c                 X    t        |t              sJ | j                  |      } ||i |S )a  
        Execute a ``call_module`` node and return the result.

        Args:
            target (Target): The call target for this node. See
                `Node <https://pytorch.org/docs/main/fx.html#torch.fx.Node>`__ for
                details on semantics
            args (Tuple): Tuple of positional args for this invocation
            kwargs (Dict): Dict of keyword arguments for this invocation

        Return
            Any: The value returned by the module invocation
        r{   r*   rs   r<   r=   submods        r+   call_modulezInterpreter.call_module+  s2    $ &#&&&(t&v&&r-   c                     |d   S )a4  
        Execute an ``output`` node. This really just retrieves
        the value referenced by the ``output`` node and returns it.

        Args:
            target (Target): The call target for this node. See
                `Node <https://pytorch.org/docs/main/fx.html#torch.fx.Node>`__ for
                details on semantics
            args (Tuple): Tuple of positional args for this invocation
            kwargs (Dict): Dict of keyword arguments for this invocation

        Return:
            Any: The return value referenced by the output node
        r   r/   r}   s       r+   rK   zInterpreter.outputB  s      Awr-   c           
          |j                  d      }| j                  }t        |      D ]@  \  }}t        ||      s#t	        ddj                  |d|dz                 t        ||      }B |S )z
        Fetch an attribute from the ``Module`` hierarchy of ``self.module``.

        Args:
            target (str): The fully-qualified name of the attribute to fetch

        Return:
            Any: The value of the attribute.
        .z#Node referenced nonexistent target Nr   )splitr   	enumeratehasattrr[   joinrr   )r*   rs   target_atomsattr_itriatoms         r+   r|   zInterpreter.fetch_attrU  s}     ||C(;; . 	/GAt8T*"%HR^_c`abc`cRdIeHf#ghhx.H	/ r-   c                     | j                  |j                  |      }t        |t              sJ | j                  |j                  |      }t        |t
              sJ ||fS )aP  
        Fetch the concrete values of ``args`` and ``kwargs`` of node ``n``
        from the current execution environment.

        Args:
            n (Node): The node for which ``args`` and ``kwargs`` should be fetched.

        Return:
            Tuple[Tuple, Dict]: ``args`` and ``kwargs`` with concrete values for ``n``.
        )map_nodes_to_valuesr<   rY   rq   r=   r4   rt   s       r+   rp   z&Interpreter.fetch_args_kwargs_from_envh  sZ     ''2$&&&))!((A6&$'''V|r-   c                 D     dt         dt        f fd}t        ||      S )aV  
        Recursively descend through ``args`` and look up the concrete value
        for each ``Node`` in the current execution environment.

        Args:
            args (Argument): Data structure within which to look up concrete values

            n (Node): Node to which ``args`` belongs. This is only used for error reporting.
        n_argrA   c                 b    | j                   vrt        d d|  d      j                   |    S )NzNode z referenced nonexistent value z*! Run Graph.lint() to diagnose such issues)r7   r[   )r   r"   r*   s    r+   load_argz1Interpreter.map_nodes_to_values.<locals>.load_arg  sB    DHH$"U1#-KE7 S= $> ? ?88E?"r-   )r   r   r	   )r*   r<   r"   r   s   ` ` r+   r   zInterpreter.map_nodes_to_valuesz  s%    	#T 	#c 	#
 tX&&r-   )TN) __name__
__module____qualname____doc__r   torchnnModuleboolr   r   r>   r   r   r   rd   rj   r   rn   rU   r   r   rQ   rf   r~   r   r   r   rK   r|   rp   r   r/   r-   r+   r   r      s1   7p $/Luxx L L\dej\k L 0L: $/CGgk 7fxT3Y'@ 7f`d 7fps 7f 07fr $/) 0)   $/?4 ?C ? 0?( $/C8 CE(C-4H CSWX[]`X`Sa Cfi C 0C> $/' 'x}1E 'PTUXZ]U]P^ 'cf ' 0'$ $/'X 'eHcM6J 'UYZ]_bZbUc 'hk ' 0'& $/?8 ?E(C-4H ?SWX[]`X`Sa ?fi ? 0?* $/'8 'E(C-4H 'SWX[]`X`Sa 'fi ' 0', $/h uXs]/C dSVX[S[n ad  0$ $/#  0$ $/T eE4K6H  0" $/' 't ' ' 0'r-   c            	       r    e Zd ZdZ ed       fd       Z ed      dddeedf   d	ee	e
f   d
efd       Z ed      dddeedf   d	ee	e
f   d
efd       Z ed      dddeedf   d	ee	e
f   d
e
fd       Z ed      dddeedf   d	ee	e
f   d
e
fd       Z ed      d
ef fd       Z xZS )r   a6  
    ``Transformer`` is a special type of interpreter that produces a
    new ``Module``. It exposes a ``transform()`` method that returns
    the transformed ``Module``. ``Transformer`` does not require
    arguments to run, as ``Interpreter`` does. ``Transformer`` works
    entirely symbolically.

    Example:

        Suppose we want to swap all instances of ``torch.neg`` with
        ``torch.sigmoid`` and vice versa (including their ``Tensor``
        method equivalents). We could subclass ``Transformer`` like so::

            class NegSigmSwapXformer(Transformer):
                def call_function(self, target : 'Target', args : Tuple[Argument, ...], kwargs : Dict[str, Any]) -> Any:
                    if target == torch.sigmoid:
                        return torch.neg(*args, **kwargs)
                    return super().call_function(n)

                def call_method(self, target : 'Target', args : Tuple[Argument, ...], kwargs : Dict[str, Any]) -> Any:
                    if target == 'neg':
                        call_self, *args_tail = args
                        return call_self.sigmoid(*args_tail, **kwargs)
                    return super().call_method(n)

            def fn(x):
                return torch.sigmoid(x).neg()

            gm = torch.fx.symbolic_trace(fn)

            transformed : torch.nn.Module = NegSigmSwapXformer(gm).transform()
            input = torch.randn(3, 4)
            torch.testing.assert_close(transformed(input), torch.neg(input).sigmoid())

    Args:
        module (GraphModule): The ``Module`` to be transformed.
    Tr   c                    t         |   |       t               | _        | j                  j	                  |j
                  j                          G d dt              } || j                        | _        || j                  _	        y )Nc                   0     e Zd Zdef fdZdefdZ xZS )/Transformer.__init__.<locals>.TransformerTracerr    c                 >    t         |           || _        i | _        y r%   )superr>   r    tensor_attrs)r*   r    	__class__s     r+   r>   z8Transformer.__init__.<locals>.TransformerTracer.__init__  s     ""
=?!r-   rA   c                      y)NTr/   )r*   ___s      r+   is_leaf_modulez>Transformer.__init__.<locals>.TransformerTracer.is_leaf_module  s    r-   )r   r   r   r   r>   r   r   __classcell__r   s   @r+   TransformerTracerr     s    @e @
t r-   r   )
r   r>   r   	new_graphset_codegenr    _codegenr   tracerroot)r*   r   r   r   s      r+   r>   zTransformer.__init__  s_     ""6<<#8#89	 	 (7!r-   rs   r   r<   .r=   rA   c                     t        |t              sJ |rt        t        |            nt        j
                  j                  }t        | j                  j                  ||      | j                        S )a  
        Execute a ``placeholder`` node. In ``Transformer``, this is
        overridden to insert a new ``placeholder`` into the output
        graph.

        Args:
            target (Target): The call target for this node. See
                `Node <https://pytorch.org/docs/main/fx.html#torch.fx.Node>`__ for
                details on semantics
            args (Tuple): Tuple of positional args for this invocation
            kwargs (Dict): Dict of keyword arguments for this invocation
        )default_value)rY   rQ   rg   rM   inspect	Signatureemptyr   r   rf   r   )r*   rs   r<   r=   r   s        r+   rf   zTransformer.placeholder  sZ     &#&&&,0T$Z(g6G6G6M6MT^^//m/TVZVaVabbr-   c                 b    t        |t              sJ | j                  j                  d|||      S )a  
        Execute a ``get_attr`` node. In ``Transformer``, this is
        overridden to insert a new ``get_attr`` node into the output
        graph.

        Args:
            target (Target): The call target for this node. See
                `Node <https://pytorch.org/docs/main/fx.html#torch.fx.Node>`__ for
                details on semantics
            args (Tuple): Tuple of positional args for this invocation
            kwargs (Dict): Dict of keyword arguments for this invocation
        r~   )rY   rQ   r   create_proxyr}   s       r+   r~   zTransformer.get_attr  s/     &#&&&{{''
FD&IIr-   c                     t        |t              sJ | j                  |      }| j                  j	                  ||j
                  ||      S r%   )rY   rQ   r|   r   r   forwardr   s        r+   r   zTransformer.call_module  sA     &#&&&({{&&vv~~tVLLr-   c                 >    | j                   j                  d|||      S )Nr   )r   r   r}   s       r+   r   zTransformer.call_function  s     {{''vNNr-   c                    t        j                         5  t        |   d      }ddd       dt        t
        t        f   dt        fd}| j                  j                  t        ||            }t        | j                  j                        d   }|j                  dk(  sJ |j                  j!                         D ]  \  }}||j                  |<    t#        | j$                  | j                        S # 1 sw Y   xY w)	z_
        Transform ``self.module`` and return the transformed
        ``GraphModule``.
        F)r@   NarA   c                 >    t        | t              r| j                  S | S r%   )rY   r   r1   )r   s    r+   strip_proxyz*Transformer.transform.<locals>.strip_proxy  s    !+Au!5qvv<1<r-   rK   )rl   preserve_node_metar   rd   r   r   r   r   r   rK   r
   rR   r    r;   r]   metaitemsr   r   )r*   resultr   new_output_nodeold_output_nodekvr   s          r+   	transformzTransformer.transform  s     ,,. 	=W[e[<F	==ho 6 =3 ="nn33M&+4VWO"4::#3#34R8O"%%111',,224 ,1*+$$Q', "$++t~~>>	= 	=s   C77D )r   r   r   r   r   r>   r   r   r   rQ   r   r   rf   r~   r   r   r   r   r   r   s   @r+   r   r     s   $L $/" 0"" $/c8 cE(C-4H cSWX[]`X`Sa cfk c 0c" $/J Jx}1E JPTUXZ]U]P^ Jch J 0J  $/M8 ME(C-4H MSWX[]`X`Sa Mfi M 0M $/OX OeHcM6J OUYZ]_bZbUc Ohk O 0O $/?; ? 0?r-   ))graph_moduler   _lazy_graph_moduler   r    r   r1   r   r   r   r	   r
   proxyr   _symbolic_tracer   _compatibilityr   rC   r   torch.fx.tracebackfx	tracebackrl   r   typingr   r   r   r   r   r   r   r   
contextlibr   	torch.hubr   __all__r   r   r/   r-   r+   <module>r      s    % 2  @ @  # )  ) )  D D D  % -
(d+v' v' ,v'p d+{?+ {? ,{?r-   