
    Pi'9              
       p   d dl Z d dlZd dlmZ d dlmZ d dlmZmZ d dl	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mZ d
dlmZ dZdZdZ ej        e          Z ed           G d d                      ZdeddfdZdedee         fdZ de!de!fdZ"de!de!de#fdZ$dee	j%        e	j%        ge	j%        f         de!de!de!fdZ& G d de	j'        j(                  Z)d eded!edefd"Z*d edefd#Z+ ed           G d$ d%                      Z, ed           G d& d'                      Z-d(e!de.fd)Z/d ede0ee1ee.         e!e2e!         f         f         fd*Z3d+e0ee1ee.         e!e2e	j%                 f         f         d,e0ee1ee.         e!e2e	j%                 f         f         de0ee-f         fd-Z4dS ).    N)Sequence)	dataclass)CallableOptional)compute_sqnr)ExportedProgram)GraphModuleNode)
NodeSource)
functional   )bfs_trace_with_node_processnumeric_debug_handlecustom	from_nodeT)frozenc                   (    e Zd ZU dZeed<   eed<   dS )NodeSourceDebugInfoz
    Contains node source information for locating the node in the original graph.
    This replaces the numeric debug handle approach with direct node source info.
    namegraph_idN)__name__
__module____qualname____doc__str__annotations__int     /home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/torchao/quantization/pt2e/_numeric_debugger.pyr   r      s0           III MMMMMr   r   epreturnc                 ,   t          | t                    s$t          dt          t                               ddt          j        j        ddffd}dt          j        j        ddffd}t          | |           dz  t          | |           dS )	aj  
    Attach numeric_debug_handle_id for all nodes in the graph module of the given
    ExportedProgram, like conv2d, squeeze, conv1d, etc, except for placeholder.
    Notice that nodes like getattr are out of scope since they are not in the graph.

    The graph nodes of input exported program are modified inplace.

    Here's an example of using debug handle quantize flow::

        ep = torch.export.export(eager_model, example_inputs)
        generate_numeric_debug_handle(ep)

        m = ep.module()
        quantizer = XNNPACKQuantizer()
        m = prepare_pt2e(m, quantizer)
        m = convert_pt2e(m)
    z'Expected ep to be ExportedProgram, got r   noder"   Nc                     t          | j                            t          i                               t          d                    d S )Nr   )maxmetaget
CUSTOM_KEYNUMERIC_DEBUG_HANDLE_KEYr$   	unique_ids    r    _find_max_idz3generate_numeric_debug_handle.<locals>._find_max_idG   s=    ty}}Z44889QSTUU
 
			r   c                     t           | j        vri | j        t           <   t          | j        t                    vr!| j        t                    t          <   dz  d S d S )Nr   )r)   r'   r*   r+   s    r    _assign_debug_handlez;generate_numeric_debug_handle.<locals>._assign_debug_handleM   sV    TY&&$&DIj!#49Z+@@@>GDIj!":;NIII A@r   r   )
isinstancer   
ValueErrortypetorchfxr
   r   )r!   r-   r/   r,   s      @r    generate_numeric_debug_handler5   ,   s    ( b/** 
Md?6K6KMM
 
 	
 I
58= 
T 
 
 
 
 
 
58= T        L111NI  $899999r   r$   c                     dt           ddfd}dt           dt          fd}| j        dk    s| j        dk    rdS  ||           sdS  ||           }t          |j        |j        	          S )
a  
    Extract node source debug info from a node, or return None if the node
    does not need to be traced.

    Returns NodeSourceDebugInfo containing the name and graph_id from the
    node's greatest ancestor node source, or None if the node is not in
    the original graph.
    r$   r"   r   c                     | j                             t                    d         }t          |j                  dk    r%|j        d         }t          |j                  dk    %|S )Nr   )r'   r(   FROM_NODE_KEYlenr   )r$   node_sources     r    "_get_greatest_ancestor_node_sourcezK_extract_node_source_debug_info.<locals>._get_greatest_ancestor_node_sourcel   s]    immM2226+'((1,,%/3K +'((1,, r   c                     t           | j        vs| j        t                    dS | j        t                    d         j        dk    rdS dS )NFr8   z!ExportedProgram.module().unlift()T)r9   r'   	pass_name)r$   s    r    _is_node_in_original_graphzC_extract_node_source_debug_info.<locals>._is_node_in_original_grapht   sO    	))TY}-E-M 5 Im$R(223 3 5tr   placeholderoutputN)r   r   )r
   boolopr   r   r   )r$   r<   r?   greatest_ancestor_node_sources       r    _extract_node_source_debug_inforE   b   s     ,     $      w-47h#6#6t%%d++ t$F$Ft$L$L!*/.7   r   xc                 R   d }t          | t          j                  r|                                 }nut          | t          t
          f          r# t          |           d | D                       }n6t          | t                    rd |                                 D             }n| }|S )Nc                 ,    g | ]}t          |          S r   _detach).0es     r    
<listcomp>z_detach.<locals>.<listcomp>   s    2221GAJJ222r   c                 4    i | ]\  }}|t          |          S r   rI   )rK   krL   s      r    
<dictcomp>z_detach.<locals>.<dictcomp>   s$    888daAwqzz888r   )	r0   r3   Tensordetachlisttupler2   dictitems)rF   detacheds     r    rJ   rJ      s    H!U\"" 88::	Ae}	%	% 4772222233	At		 88aggii888Or   yc                 v   t          | t          j                  r*t          |t          j                  r| j        |j        k    S t          | t          t
          f          rCt          |t          t
          f          r't          d t          | |          D                       S t          | t                    r@t          |t                    r+d}| D ]$}|o||v ot          | |         ||                   }%|S t                              d| |           t          |           t          |          k    o| |k    S )Nc              3   <   K   | ]\  }}t          ||          V  d S N)_tensor_shape_equals)rK   e1e2s      r    	<genexpr>z'_tensor_shape_equals.<locals>.<genexpr>   s1      HHFB'B//HHHHHHr   Tz4Comparing non Tensors: %s and %s, they must be equal)r0   r3   rQ   shaperS   rT   allziprU   r\   logdebugr2   )rF   rX   	all_equalrO   s       r    r\   r\      s&   !U\"" -z!U\'B'B -w!'!!	Ae}	%	% 	-*Qu*F*F 	-HHc!QiiHHHHHH	At		 -At!4!4 -	 	T 	TA!Sa1fS2FqtQqT2R2RII		H!QOOOAww$q''!,a1f,r   lossc                 h    t          |t          j                  r`t          t          j                  rF  |                    t          j                                      t          j                            S t          |t
          t          f          rNt          t
          t          f          r2 t          |           fdt          |          D                       S t          |t                    r6t          t                    r! fd|
                                D             S dS )a  The returned loss will have the same structure as `x` and `y`, e.g.
    if both are Tensor, we'll return a Tensor
    if both are list, we'll return a list of Tensors
    if both are dict, we'll return a dict with the same key, and value being the loss between the
    two Tensors
    c                 8    g | ]\  }}t          ||          S r   _loss_fn)rK   r]   r^   rf   s      r    rM   z_loss_fn.<locals>.<listcomp>   s)    GGG62rr2..GGGr   c           	      F    i | ]\  }}|t          ||                   S r   ri   )rK   rO   rL   rf   rX   s      r    rP   z_loss_fn.<locals>.<dictcomp>   s/    AAAtq!8D!QqT**AAAr   N)r0   r3   rQ   tofloat32rS   rT   r2   rb   rU   rV   )rf   rF   rX   s   ` `r    rj   rj      s    !U\"" z!U\'B'B tADD''em)<)<===	Ae}	%	% *Qu*F*F tAwwGGGGSAYYGGGHHH	At		 At!4!4 AAAAAqwwyyAAAAtr   c            	       r     e Zd ZdZdZ	 	 ddedee         dee         ddf fdZ	d	edefd
Z
defdZ xZS )OutputLoggerz
    Base class for capturing output values for nodes in a GraphModule, it only captures
    Tensor output currently, but we can extend it to work for other types of inputs later if needed
    TN
debug_info	node_namenn_module_stackr"   c                     t                                                       || _        || _        || _        g | _        d S r[   )super__init__rq   rr   rp   stats)selfrp   rq   rr   	__class__s       r    ru   zOutputLogger.__init__   s<     	".$#%


r   rF   c                 T    | j                             t          |                     |S r[   )rv   appendrJ   )rw   rF   s     r    forwardzOutputLogger.forward   s#    
'!**%%%r   c                 (    d| j          d| j         dS )Nzdebug_info=z, node_name=zF, nn_module_stack={self.nn_module_stack}, num_stats={len(self.stats)}))rp   rq   rw   s    r    __extra_repr__zOutputLogger.__extra_repr__   s3    S$/ S St~ S S S	
r   )NN)r   r   r   r   
_is_impurer   r   r   objectru   r{   r~   __classcell__)rx   s   @r    ro   ro      s          J
 $(,0	
& 
&'
& C=
& "&)	
&
 

& 
& 
& 
& 
& 
& F    
 
 
 
 
 
 
 
 
r   ro   modelrp   c                    ddl m} | j                            |          5   ||j         d          } ||           }t          | |t          ||j        |j                            d                               | j        	                    ||fi           }ddd           n# 1 swxY w Y   t          |j                                                  }|D ]}||u r|                    ||           |S )zFor a given node, adds an OutputLogger that observes the output of that node,
    and all its users use the OutputLogger output instead.
    The OutputLogger will contain the debug_info which can be used to compare
    graphs after transformsr   )get_new_attr_name_with_prefix_loggerrr   N)torchao.quantization.pt2e.utilsr   graphinserting_afterr   setattrro   r'   r(   call_modulerS   userskeysreplace_input_with)	r   r$   rp   r   get_new_attr_namelogger_namelogger_node
orig_users	user_nodes	            r    _insert_loggerr      sm    NMMMMM 
	$	$T	*	* H H99TY:O:O:OPP''..TY	>O0P0PQQ	
 	
 	

 k--kD7BGGH H H H H H H H H H H H H H H djoo''((J 8 8	##$$T;7777s   A9B&&B*-B*c                     t          j        |           } | j        j        D ]$}t	          |          x}t          | ||           %|                                  | S )zAdd output loggers to unlifted node

    Args:
        model (GraphModule): original model
    Returns:
        a model with output loggers for all unlifted nodes
    )copydeepcopyr   nodesrE   r   	recompile)r   nrp   s      r    "prepare_for_propagation_comparisonr     sb     M%  E[ 1 19!<<<JI5!Z000	OOLr   c                       e Zd ZU ej        ed<   ej        ed<   edefd            Zedefd            Z	de
ej        ej        gej        f         defdZdefdZdd
Zd	S )QuantizationComparisonResultactualrefr"   c                 @    |                      t          j                  S r[   )rf   Fmse_lossr}   s    r    r   z%QuantizationComparisonResult.mse_loss  s    yy$$$r   c                 6    |                      t                    S r[   )rf   r   r}   s    r    sqnrz!QuantizationComparisonResult.sqnr  s    yy&&&r   loss_functionc                 8    t          || j        | j                  S r[   )rj   r   r   )rw   r   s     r    rf   z!QuantizationComparisonResult.loss   s     t{DH===r   c                 (    d| j          d| j         dS )Nz&QuantizationComparisonResult(mse_loss=z, sqnr=))r   r   r}   s    r    __repr__z%QuantizationComparisonResult.__repr__%  s$     XT]WW49WWW	
r   Nc                    t          | j        t          j        t          t
          t          f          st          d| j                   t          | j        t          j        t          t
          t          f          st          d| j                   t          | j        | j                  st          d| j         d| j                   d S )Nz@`self.actual` value must be a Tensor, list, tuple or dict, got: z=`self.ref` value must be a Tensor, list, tuple or dict, got: z2Cannot compare tensors with different shapes: ref=z vs actual=)
r0   r   r3   rQ   rS   rT   rU   r1   r   r\   r}   s    r    __post_init__z*QuantizationComparisonResult.__post_init__,  s    $+dE4'HII 	`SWS^``   $(U\4$EFF 	ZPTPXZZ   $DHdk:: 	gTXggZ^Zegg  	 	r   )r"   N)r   r   r   r3   rQ   r   propertyr   r   r   r   rf   r   r   r   r   r   r    r   r     s         L	%& % % % X% 'f ' ' ' X'>%u|U\&BEL&PQ>	> > > >

# 
 
 
 
     r   r   c                   X    e Zd ZU eed<   eed<   eed<   eed<   eed<   ee         ed<   dS )NodeAccuracySummaryrp   actual_node_nameactual_module_stackref_node_nameref_module_stackresultsN)r   r   r   r   r   r   r   r   r   r   r    r   r   =  s`         ####2333333r   r   module_stackc                 
   t          | t                    st          |           S t          |                                           }t          |          dk    r|d         d         }t          |          S t          |           S )zlSimplifies the stack from ("mod", "mod.foo", "mod.foo.0", "mod.foo.0.linear")
    to "mod.foo.0.linear"
    r   r8   )r0   rU   r   rS   valuesr:   )r   module_values_listowning_modules      r    _module_stack_to_strr   G  s}     lD)) !<   l113344
""*2.q1=!!!<   r   c                     i }|                                  D ]N\  }}t          |t                    r4t          |j                  dk    r|j        |j        |j        f||j        <   O|S )a  For a given model, extract the tensors stats and related information for each debug info.
    The reason we have a list of object, instead of Tensor is because the output of node may not be
    a Tensor, it could be (nested) list, tuple or dict as well.

    Returns:
        A dict is keyed by the NodeSourceDebugInfo and the values are a list of object recorded
        in loggers

    r   )named_childrenr0   ro   r:   rv   rq   rr   rp   )r   handles_modules       r    extract_results_from_loggersr   U  sx     VXG))++  	6fl++ 	FL0A0AA0E0E &*GF%& Nr   ref_resultsactual_resultsc           
         i }|                                  D ]\  }\  }}}||vrt                              d|           )||         \  }}}		 d t          |	|          D             }
n+# t          $ r}t          d| d| d|           |d}~ww xY wt          ||pdt          |          |pdt          |          |
          ||<   |S )	a  Given two dict mapping from `NodeSourceDebugInfo` to list of tensors
    return a map from `NodeSourceDebugInfo` to `NodeAccuracySummary` that contains
    comparison information like SQNR, MSE etc.

    Args:
        ref_results (Dict[NodeSourceDebugInfo, Tuple[str, object, List[torch.Tensor]]]): reference results for each debug info
        actual_results (Dict[NodeSourceDebugInfo, Tuple[str, object, List[torch.Tensor]]]): actual results for each debug info

    Returns:
        Dict[NodeSourceDebugInfo, NodeAccuracySummary]
    zQCannot compare for debug info %s because it wasn't found in the transformed modelc                 6    g | ]\  }}t          ||           S ))r   r   )r   )rK   abs      r    rM   z#compare_results.<locals>.<listcomp>  s9       Aq -A1===  r   zFor debug_info=z from ref node z and actual node N )rp   r   r   r   r   r   )rV   rc   rd   rb   	Exceptionr1   r   r   )r   r   comparisonsrp   ref_name	ref_stack	ref_statsactual_nameactual_stackactual_statsr   rL   s               r    compare_resultsr   n  sA   & K8C8I8I8K8K 
 
4
4Xy)^++IIc   2@2L/\<
	 i88  GG  	 	 	 e*eeXeeXcee 	 #6!(.B 4\ B B".b1)<<#
 #
 #
J s   A((
B2BB)5r   loggingcollections.abcr   dataclassesr   typingr   r   r3   torch.ao.ns.fx.utilsr   torch.exportr   torch.fxr	   r
   torch.fx.tracebackr   torch.nnr   r   graph_utilsr   r*   r)   r9   	getLoggerr   rc   r   r5   rE   r   rJ   rB   r\   rQ   rj   nnModulero   r   r   r   r   r   r   rU   rT   rS   r   r   r   r   r    <module>r      s     $ $ $ $ $ $ ! ! ! ! ! ! % % % % % % % %  - - - - - - ( ( ( ( ( ( & & & & & & & & ) ) ) ) ) ) $ $ $ $ $ $ 4 4 4 4 4 41 
g!! $
 
 
 
 
 
 
 
3:o 3:$ 3: 3: 3: 3:l.$ .8<O3P . . . .b
v 
& 
 
 
 
-F -v -$ - - - -
EL%,/=
>CINT   &
 
 
 
 
58? 
 
 
@"0C	   >k k    $ $& & & & & & & &R $4 4 4 4 4 4 4 4!v !# ! ! ! !	
uXc]FDL%HI
IJ   21U8C=&$u|:L#LMM1 U8C=&$u|:L#LMM	1 

2
231 1 1 1 1 1r   