
    Vhf/              
          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 d dlmZmZ d d	lmZ d
ZdZ ej0                  e      Zdedd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	jD                  jF                        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e,e%e-ee*   ee.e   f   f   fd$Z/d%e,e%e-ee*   ee.e	j@                     f   f   d&e,e%e-ee*   ee.e	j@                     f   f   de,e%e)f   fd'Z0y)(    N)Sequence)	dataclass)CallableOptional)compute_sqnr)bfs_trace_with_node_process)ExportedProgram)GraphModuleNode)
functionalnumeric_debug_handlecustom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        | |       y)	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 = export_for_training(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                  j                  t        i       j                  t        d            y )Nr   )maxmetaget
CUSTOM_KEYNUMERIC_DEBUG_HANDLE_KEYr   	unique_ids    \/home/dcms/DCMS/lib/python3.12/site-packages/torch/ao/quantization/pt2e/_numeric_debugger.py_find_max_idz3generate_numeric_debug_handle.<locals>._find_max_id0   s0    tyy}}Z4889QSTU
	    c                     t         | j                  vri | j                  t         <   t        | j                  t            vr | j                  t            t        <   dz  y y )N   )r   r   r   r   s    r   _assign_debug_handlez;generate_numeric_debug_handle.<locals>._assign_debug_handle6   sQ    TYY&$&DIIj!#499Z+@@>GDIIj!":;NI Ar   r   )
isinstancer	   
ValueErrortypetorchfxr   r   )r   r   r    r   s      @r   generate_numeric_debug_handler&      s    ( b/*5d?6K5LM
 	
 I
588== 
T 
588== T   L1NI  $89r   xc                 x   d }t        | t        j                        r| j                         }|S t        | t        t
        f      r* t        |       | D cg c]  }t        |       c}      }|S t        | t              r.| j                         D ci c]  \  }}|t        |       }}}|S | }|S c c}w c c}}w N)
r!   r$   Tensordetachlisttupler#   _detachdictitems)r'   detachedeks       r   r.   r.   K   s    H!U\\"88: O 
Ae}	%4721GAJ23
 O	 
At	./ggi8daAwqzM88 O O 38s   B1B6yc                 $   t        | t        j                        r3t        |t        j                        r| j                  |j                  k(  S t        | t        t
        f      r2t        |t        t
        f      rt        d t        | |      D              S t        | t              r7t        |t              r'd}| D ]  }|xr ||v xr t        | |   ||         }  |S t        j                  d| |       t        |       t        |      k(  xr | |k(  S )Nc              3   :   K   | ]  \  }}t        ||        y wr)   )_tensor_shape_equals).0e1e2s      r   	<genexpr>z'_tensor_shape_equals.<locals>.<genexpr>\   s     HFB'B/Hs   Tz4Comparing non Tensors: %s and %s, they must be equal)r!   r$   r*   shaper,   r-   allzipr/   r7   logdebugr#   )r'   r4   	all_equalr3   s       r   r7   r7   X   s    !U\\"z!U\\'Bww!''!!	Ae}	%*Qu*FHc!QiHHH	At	At!4	 	TA!Sa1fS2FqtQqT2RI	T		H!QOAw$q'!,a1f,r   lossc                 x   t        |t        j                        r]t        |t        j                        rC | |j                  t        j                        |j                  t        j                              S t        |t
        t        f      rOt        |t
        t        f      r9 t        |      t        ||      D cg c]  \  }}t        | ||       c}}      S t        |t              rBt        |t              r2|j                         D ci c]  \  }}|t        | |||          c}}S yc c}}w c c}}w )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
    N)r!   r$   r*   tofloat32r,   r-   r#   r>   _loss_fnr/   r0   )rB   r'   r4   r9   r:   r3   r2   s          r   rF   rF   g   s     !U\\"z!U\\'BADD'emm)<==	Ae}	%*Qu*FtAwSAYG62rr2.GHH	At	At!478wwyAtq!8D!QqT**AA	 HAs   >D0
D6c            	       f     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_handle	node_namenn_module_stackr   c                 Z    t         |           || _        || _        || _        g | _        y r)   )super__init__rJ   rK   rI   stats)selfrI   rJ   rK   	__class__s       r   rN   zOutputLogger.__init__   s.     	".(#%
r   r'   c                 N    | j                   j                  t        |             |S r)   )rO   appendr.   )rP   r'   s     r   forwardzOutputLogger.forward   s    

'!*%r   c                 <    d| j                    d| j                   dS )Nzdebug_handle=z, node_name=zF, nn_module_stack={self.nn_module_stack}, num_stats={len(self.stats)}))rI   rJ   rP   s    r   __extra_repr__zOutputLogger.__extra_repr__   s-    D--.l4>>:J KS S	
r   )NN)__name__
__module____qualname____doc__
_is_impureintr   strobjectrN   rT   rW   __classcell__)rQ   s   @r   rH   rH   z   sj     J
 $(,0	
&
& C=
& "&)	
&
 

& F 
 
r   rH   modelr   rI   c                    ddl m} | j                  j                  |      5   ||j                   d      } ||       }t        | |t        ||j                  |j                  j                  d                   | j                  j                  ||fi       }ddd       t        |j                  j                               }|D ]  }|u r|j                  ||        S # 1 sw Y   LxY w)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_handle which can be used to compare
    graphs after transformsr   )get_new_attr_name_with_prefix_loggerrK   N)torch.ao.quantization.fx.utilsrc   graphinserting_afternamesetattrrH   r   r   call_moduler,   userskeysreplace_input_with)	ra   r   rI   rc   get_new_attr_namelogger_namelogger_node
orig_users	user_nodes	            r   _insert_loggerrs      s     M 
	$	$T	* H9TYYKw:OP'.tyy$))--@Q2RS	

 kk--kD7BGH djjoo'(J 8	#$$T;78
 !H Hs   A7C$$C-c                 ,   t        j                  |       } | j                  j                  D ]U  }t        |j
                  vst        |j
                  t           vr/|j
                  t           t           }t        | ||       W | j                          | S )zAdd output loggers to node that has numeric_debug_handle

    Args:
        model (GraphModule): original model
    Returns:
        a model with output loggers for all nodes that has numeric_debug_handle_id
    )	copydeepcopyrf   nodesr   r   r   rs   	recompile)ra   nr   s      r   "prepare_for_propagation_comparisonrz      s~     MM% E[[ 7aff$'qvvj/AA vvj12JKua!567 
OOLr   T)frozenc                       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y	)QuantizationComparisonResultactualrefr   c                 @    | j                  t        j                        S r)   )rB   Fmse_lossrV   s    r   r   z%QuantizationComparisonResult.mse_loss   s    yy$$r   c                 ,    | j                  t              S r)   )rB   r   rV   s    r   sqnrz!QuantizationComparisonResult.sqnr   s    yy&&r   loss_functionc                 D    t        || j                  | j                        S r)   )rF   r~   r   )rP   r   s     r   rB   z!QuantizationComparisonResult.loss   s     t{{DHH==r   c                 <    d| j                    d| j                   dS )Nz&QuantizationComparisonResult(mse_loss=z, sqnr=))r   r   rV   s    r   __repr__z%QuantizationComparisonResult.__repr__   s$     5T]]O7499+UV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                         y )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=)
r!   r~   r$   r*   r,   r-   r/   r"   r   r7   rV   s    r   __post_init__z*QuantizationComparisonResult.__post_init__   s    $++dE4'HIRSWS^S^R_`  $((U\\4$EFOPTPXPXzZ  $DHHdkk:DTXXJkZ^ZeZeYfg  ;r   )r   N)rX   rY   rZ   r$   r*   __annotations__propertyr_   r   r   r   rB   r^   r   r    r   r   r}   r}      s    LL	%& % % 'f ' '>%u||U\\&BELL&PQ>	>

# 
r   r}   c                   P    e Zd ZU eed<   eed<   eed<   eed<   eed<   ee   ed<   y)NodeAccuracySummaryhandleactual_node_nameactual_module_stackref_node_nameref_module_stackresultsN)rX   rY   rZ   r]   r   r^   r   r}   r   r   r   r   r      s+    K233r   r   module_stackc                     t        | t              st        |       S t        | j	                               }t        |      dkD  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   )r!   r/   r^   r,   valueslen)r   module_values_listowning_modules      r   _module_stack_to_strr     s`     lD)<  l1134
"*2.q1=!!<  r   c                     i }| j                         D ]_  \  }}t        |t              st        |j                        dkD  s0|j
                  |j                  |j                  f||j                  <   a |S )a  For a given model, extract the tensors stats and related information for each debug handle.
    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 debug_handle id and the values are a list of object recorded
        in loggers

    r   )named_childrenr!   rH   r   rO   rJ   rK   rI   )ra   handles_namemodules       r   extract_results_from_loggersr     ss     FHG--/ vfl+FLL0AA0E  &&,GF''( Nr   ref_resultsactual_resultsc           
         i }| j                         D ]  \  }\  }}}||vrt        j                  d|       %||   \  }}}		 t        |	|      D 
cg c]  \  }
}t	        |
|       }}
}t        ||xs dt        |      |xs dt        |      |      ||<    |S c c}}
w # t
        $ r}t        d| d| d|       |d}~ww xY w)	a  Given two dict mapping from `debug_handle_id` (int) to list of tensors
    return a map from `debug_handle_id` to `NodeAccuracySummary` that contains
    comparison information like SQNR, MSE etc.

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

    Returns:
        Dict[int, NodeAccuracySummary]
    zMCannot compare for handle %s because it wasn't found in the transformed model)r~   r   zFor numeric_debug_handle=z from ref node z and actual node N )r   r   r   r   r   r   )	r0   r?   r@   r>   r}   	Exceptionr"   r   r   )r   r   comparisonsrI   ref_name	ref_stack	ref_statsactual_nameactual_stackactual_statsabr   r2   s                 r   compare_resultsr   )  s    K:E:K:K:M 
66xI~-II_ 2@2N/\<
	  i8Aq -A1=G  %8(.B 4\ B".b1)<%
L!)
: )  	 +L>
Rcdocpq	s*   B#B(B#B##	C,CC)1ru   loggingcollections.abcr   dataclassesr   typingr   r   r$   torch.ao.ns.fx.utilsr   &torch.ao.quantization.pt2e.graph_utilsr   torch.exportr	   torch.fxr
   r   torch.nnr   r   r   r   	getLoggerrX   r?   r&   r_   r.   boolr7   r*   rF   nnModulerH   r]   rs   rz   r}   r   r^   r   r/   r-   r,   r   r   r   r   r   <module>r      s     $ ! %  - N ( & $ 2 
g!3:o 3:$ 3:l
v 
& 
-F -v -$ -
ELL%,,/=
>CINT&
588?? 
@+ T   :k k . $& & &R $4 4 4!v !# !	#uXc]FDL89
9:2-c5#U\\8J!JKKL-eHSM64;M$MNNO- 
#"
"#-r   