
    Vh                     	   d Z ddlZddlmZmZmZmZ ddlZddlm	c m
c mZ 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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%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/Z/ ddl0m1Z1m2Z2 ddl3m4Z4m5Z5m6Z6 ddl7m8Z8m9Z9m:Z: ddl;m<Z< erddl=m>Z> e?ej                  e?ej                  ej                  f   f   ZA G d dej                        ZC G d deC      ZD G d dej                        ZF	 dWdeGde-deHe?e/eGf      d e5d!eeIeGeIeef   f      d"dfd#ZJ	 	 	 dXd$eGd%e-d&eGd'e-d(eeIeGeKe4   f      d)eeIeGeKe4   f      d!eeIeGeIeef   f      d"e5fd*ZL	 	 	 dXd$eGd+ej                  d&eGd,ej                  d(eeIeGeKe4   f      d)eeIeGeKe4   f      d!eeIeGeIeef   f      d"e5fd-ZMdeGde-d.eHe?e/eGeGf      d/eHe?e/eGeGf      d0ed"ej                  fd1ZN	 	 dYd2eGd%e-d3eGd'e-d0ed4eOd(eeIeGeKe4   f      d)eeIeGeKe4   f      d"e?ej                  ej                  f   fd5ZP	 	 	 dZd2eGd+ej                  d3eGd,ej                  d0ed4eOd(eeIeGeKe4   f      d)eeIeGeKe4   f      d"e?ej                  ej                  f   fd6ZQdej                  d e5d0ed"dfd7ZRd+ej                  d,ej                  d0ed8eGd"e5f
d9ZS	 	 	 dXd2eGd%e-d3eGd'e-d0ed4eOd(eeIeGeKe4   f      d:eeIeGeKe4   f      d)eeIeGeKe4   f      d"ej                  fd;ZT	 	 	 	 d[d2eGd+ej                  d3eGd,ej                  d0ed4eOd(eeIeGeKe4   f      d:eeIeGeKe4   f      d)eeIeGeKe4   f      d"ej                  fd<ZUd=ej                  d0ed8eGd"e5fd>ZVd e5d?eGd@eGdAeej                  ej                  gej                  f   dBeGd"dfdCZW	 	 	 dXdej                  j                  dDedEedFe!dGee   dHeeIeGef      dIed"e-fdJZXdej                  j                  dDedKedFe!d"ej                  j                  f
dLZYdej                  j                  dDedKedFe!d"e5f
dMZZdej                  j                  dNeOd"dfdOZ[dej                  j                  dPeOd"dfdQZ\	 	 dYde-dRee   dSeeIeGef      d"e-fdTZ]dej                  j                  d"e5fdUZ^d e5d"dfdVZ_y)\a4
  
This module contains tooling to compare weights and activations
across models. Example usage::

    import copy
    import torch
    import torch.ao.quantization.quantize_fx as quantize_fx
    import torch.ao.ns._numeric_suite_fx as ns

    m = torch.nn.Sequential(torch.nn.Conv2d(1, 1, 1)).eval()
    mp = quantize_fx.prepare_fx(m, {'': torch.ao.quantization.default_qconfig})
    # We convert a copy because we need the original prepared model
    # to be available for comparisons, and `quantize_fx.convert_fx` is inplace.
    mq = quantize_fx.convert_fx(copy.deepcopy(mp))

    #
    # Comparing weights
    #

    # extract weight pairs
    weight_comparison = ns.extract_weights('a', mp, 'b', mq)

    # add SQNR for each comparison, inplace
    ns.extend_logger_results_with_comparison(
        weight_comparison, 'a', 'b', torch.ao.ns.fx.utils.compute_sqnr,
        'sqnr')

    # weight_comparison contains the weights from `mp` and `mq` stored
    # in pairs, and can be used for further analysis.


    #
    # Comparing activations, with error propagation
    #

    # add loggers
    mp_ns, mq_ns = ns.add_loggers(
        'a', copy.deepcopy(mp),
        'b', copy.deepcopy(mq),
        ns.OutputLogger)

    # send an example datum to capture intermediate activations
    datum = torch.randn(1, 1, 1, 1)
    mp_ns(datum)
    mq_ns(datum)

    # extract intermediate activations
    act_comparison = ns.extract_logger_info(
        mp_ns, mq_ns, ns.OutputLogger, 'b')

    # add SQNR for each comparison, inplace
    ns.extend_logger_results_with_comparison(
        act_comparison, 'a', 'b', torch.ao.ns.fx.utils.compute_sqnr,
        'sqnr')

    # act_comparison contains the activations from `mp_ns` and `mq_ns` stored
    # in pairs, and can be used for further analysis.

    #
    # Comparing activations, without error propagation
    #

    # create shadow model
    mp_shadows_mq = ns.add_shadow_loggers(
        'a', copy.deepcopy(mp),
        'b', copy.deepcopy(mq),
        ns.OutputLogger)

    # send an example datum to capture intermediate activations
    datum = torch.randn(1, 1, 1, 1)
    mp_shadows_mq(datum)

    # extract intermediate activations
    shadow_act_comparison = ns.extract_shadow_logger_info(
        mp_shadows_mq, ns.OutputLogger, 'b')

    # add SQNR for each comparison, inplace
    ns.extend_logger_results_with_comparison(
        shadow_act_comparison, 'a', 'b', torch.ao.ns.fx.utils.compute_sqnr,
        'sqnr')

    # shadow_act_comparison contains the activations from `mp_ns` and `mq_ns` stored
    # in pairs, and can be used for further analysis.

    N)AnyCallableOptionalTYPE_CHECKING)get_matching_subgraph_pairs)$get_base_name_to_sets_of_related_ops)	_get_dedup_subgraphscreate_add_loggers_graph2create_n_transformed_and_logged_copies_of_subgraphcreate_results_comparisonextract_weight_comparisongroup_results_by_subgraph
OutputPropprint_n_shadows_summarySHADOW_WRAPPER_NODE_NAME_PREFIX)QConfigMultiMapping)QConfigMapping)BackendConfig)&get_fusion_pattern_to_root_node_getter)_get_observed_graph_module_attr)_find_matches)_generate_node_name_to_qconfig)!_get_pattern_to_quantize_handlers)GraphModule)Node   )add_loggers_to_modelcreate_a_shadows_b)NSNodeTargetTypeNSResultsTypeNSSingleResultValuesType)get_target_type_strmaybe_add_missing_fqns'rekey_logger_info_on_node_name_of_model)extract_weight_from_node)
QConfigAnyc                        e Zd ZU dZeej                     ed<   ee   ed<   dZ		 dde
de
de
de
d	e
d
e
de
dededee
   dee
   f fdZd Zd Z xZS )OutputLoggerz7
    Base class for capturing intermediate values.
    stats	stats_rnnTref_node_nameprev_node_name
model_nameref_nameprev_node_target_typeref_node_target_typeresults_typeindex_within_argindex_of_argfqnqconfig_strc                     t         |           g | _        g | _        || _        || _        || _        || _        || _        || _	        || _
        || _        |	| _        |
| _        d| _        || _        d| _        y )NT)super__init__r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   enabledr5   save_activations)selfr+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   	__class__s               M/home/dcms/DCMS/lib/python3.12/site-packages/torch/ao/ns/_numeric_suite_fx.pyr8   zOutputLogger.__init__   s     	)+
.0  +, % !%:" %9!( !1 ) & $    c                    | j                   s|S | j                  s|S t        |t        j                        r+| j
                  j                  |j                                |S t        |t              ryt        |      dk(  rkt        |d         dk(  rZ|d   j                         |d   d   j                         |d   d   j                         ff}| j                  j                  |       |S )	
           r   r   )r9   r:   
isinstancetorchTensorr)   appenddetachtuplelenr*   )r;   xnew_ress      r=   forwardzOutputLogger.forward   s     ||H$$H a&JJahhj)  5!c!fkc!A$i1nt{{}qtAw~~'71a9I&JKGNN!!'*r>   c                     | j                   j                         D ci c]  \  }}|dk7  r|j                  d      s||  }}}d| dS c c}}w )Ntraining_zOutputLogger()__dict__items
startswithr;   kv
clean_dicts       r=   __repr__zOutputLogger.__repr__   s^     ++-
1Zc): qD

 
 zl!,,
   #A
) )__name__
__module____qualname____doc__listrC   rD   __annotations__RNNReturnType
_is_impurestrintr   r8   rK   rX   __classcell__r<   s   @r=   r(   r(      s     M"" J &(?%?% ?% 	?%
 ?%  #?% "?% ?% ?% ?% c]?% c]?%F(-r>   r(   c                   .     e Zd ZdZ fdZd Zd Z xZS )OutputComparisonLoggerz
    Same as OutputLogger, but also requires the original activation
    in order to calculate the comparison at calibration time
    c                     t        |   |i | t        j                  j                  j
                  j                  j                  | _        d| _	        g | _
        y )Nsqnr)r7   r8   rC   aonsfxutilscompute_sqnrcomparison_fncomparison_fn_namecomparisons)r;   argskwargsr<   s      r=   r8   zOutputComparisonLogger.__init__   sE    $)&)"XX[[^^11>>"(r>   c                 $   | j                   s|S t        |t        j                        sJ d       | j                  r)| j
                  j                  |j                                | j                  j                  | j                  ||             |S )r@   z#non-tensor inputs not yet supported)
r9   rB   rC   rD   r:   r)   rE   rF   rr   rp   )r;   rI   x_refs      r=   rK   zOutputComparisonLogger.forward  sq    
 ||H!U\\*Q,QQ*  JJahhj) 2 21e <=r>   c                     | j                   j                         D ci c]  \  }}|dk7  r|j                  d      s||  }}}d| dS c c}}w )NrM   rN   zOutputComparisonLogger(rO   rP   rT   s       r=   rX   zOutputComparisonLogger.__repr__  s^     ++-
1Zc): qD

 
 )A66
rY   )r[   r\   r]   r^   r8   rK   rX   re   rf   s   @r=   rh   rh      s    
7r>   rh   c                   X     e Zd ZdZdej
                  j                  dedef fdZ	 xZ
S )NSTracerzy
    Just like a regular FX quantization tracer, but treats observers and fake_quantize
    modules as leaf modules.
    mmodule_qualified_namereturnc                     t        |t        j                  j                  j                        ryt        |t        j                  j                  j
                        ryt        |   ||      S )r@   T)rB   rC   rk   quantizationObserverBaseFakeQuantizeBaser7   is_leaf_module)r;   rz   r{   r<   s      r=   r   zNSTracer.is_leaf_module$  sR    
 a..;;<58800AABw%a)>??r>   )r[   r\   r]   r^   rC   nnModulerc   boolr   re   rf   s   @r=   ry   ry     s5    
	@ 	@ 	@PT 	@ 	@r>   ry   r-   modelnodes_and_names_to_instrumentresults"op_to_type_to_weight_extraction_fnr|   c                     t         j                  j                  d       |D ]F  \  }}t        j                  j
                  }t        |||      }|s0||vr|i i||<   |g||   |   | <   H y )Nz=quantization_api._numeric_suite_fx._extract_weights_one_model)rC   _C_log_api_usage_oncer!   WEIGHTvaluer%   )	r-   r   r   r   r   noder.   res_typeextracted_weights	            r=   _extract_weights_one_modelr   0  s     
HH  G 8 Ih+22883%;
 w&%-rN!7G6HGHh'
3Ir>   model_name_agm_amodel_name_bgm_b base_name_to_sets_of_related_opsunmatchable_types_mapc                    t         j                  j                  d       t        ||||      }g }g }	|j	                         D ]D  \  }
}|\  }}|j                  |j                  |
f       |	j                  |j                  |
f       F i }t        | ||||       t        |||	||       t        |       t        ||      }|S )Nz8quantization_api._numeric_suite_fx._extract_weights_impl)
rC   r   r   r   rR   rE   base_op_noder   r#   r$   )r   r   r   r   r   r   r   matched_subgraph_pairsnodes_and_names_to_instrument_anodes_and_names_to_instrument_b
match_namematch
subgraph_a
subgraph_br   s                  r=   _extract_weights_implr   G  s     
HH  B 9d46K
 ?A#>@#399; V
E!&
J'..
0G0G/TU'..
0G0G/TUV  G'* '* 7# 6g|LGNr>   model_amodel_bc           	      r   t         j                  j                  d       |
t               }g }g }t	        ||      }	t	        ||      }
t        ||	j                  |            }t        |d      }|||_        t        ||
j                  |            }t        |d      }|||_        t        | ||||||      S )a  
    Extract weights from model A and model B, and return a comparison.

    Args:
        model_name_a: string name of model A to use in results
        model_a: model A
        model_name_b: string name of model B to use in results
        model_b: model B
        base_name_to_sets_of_related_ops: optional override of subgraph base nodes, subject to change
        unmatchable_types_map: optional override of unmatchable types, subject to change
        op_to_type_to_weight_extraction_fn: optional override of function which extracts weight
            from a type, subject to change

    Return:
        NSResultsType, containing the weight comparisons
    z2quantization_api._numeric_suite_fx.extract_weightsnode_name_to_scope)
rC   r   r   r   ry   r   tracer   _node_name_to_scoper   )r   r   r   r   r   r   r   skipped_module_namesskipped_module_classestracer_atracer_br    maybe_model_a_node_name_to_scoper    maybe_model_b_node_name_to_scopes                  r=   extract_weightsr   {  s    8 
HH  !UV'/+O+Q( ')-/,.DEH,.DEHww 78D'F%($ (3#C ww 78D'F%($ (3#C  (* r>   $nodes_and_names_to_instrument_inputs%nodes_and_names_to_instrument_outputs
logger_clsc                     t         j                  j                  d       i }i }|D ]  \  }}}	||	f||<    |D ]  \  }}}	||	f||<    t        |||||       }|S )Nz9quantization_api._numeric_suite_fx._add_loggers_one_model)rC   r   r   r   )
r-   r   r   r   r   %node_to_instrument_inputs_to_ref_name&node_to_instrument_outputs_to_ref_namer   r.   ref_node_types
             r=   _add_loggers_one_modelr     s     
HH  C JL)JL*)M P%h7?6O-d3P)N Q%h8@-7P.t4Q !-.E Lr>   name_aname_bshould_log_inputsc                 2   t         j                  j                  d       t        ||||      }g }	g }
g }g }|j	                         D ]  \  }\  }}t        |j                  |      }t        |j                  |      }|r<|	j                  |j                  ||f       |
j                  |j                  ||f       |j                  |j                  ||f       |j                  |j                  ||f        t        | ||	||      }t        |||
||      }||fS )Nz4quantization_api._numeric_suite_fx._add_loggers_impl)rC   r   r   r   rR   r"   r   rE   
start_nodeend_noder   )r   r   r   r   r   r   r   r   r   &nodes_and_names_to_instrument_inputs_a&nodes_and_names_to_instrument_inputs_b'nodes_and_names_to_instrument_outputs_a'nodes_and_names_to_instrument_outputs_br   r   r   ref_node_type_aref_node_type_bnew_model_anew_model_bs                       r=   _add_loggers_implr     sS    
HH  !WX8d46K .0*-/*.0+.0+0F0L0L0N 
,
,Z-j.E.EtL-j.E.EtL 299&&
OD 399&&
OD
 	066  *o>	
 	066  *o>	
#
* )./K )./K %%r>   c           
      ^   t         j                  j                  d       g }g }	t        ||	      }
t        ||	      }t	        ||
j                  |            }t        |d      }|||_        t	        ||j                  |            }t        |d      }|||_        t        | |||||||      S )aD  
    Instrument model A and model B with loggers.

    Args:
        name_a: string name of model A to use in results
        model_a: model A
        name_b: string name of model B to use in results
        model_b: model B
        logger_cls: class of Logger to use
        base_name_to_sets_of_related_ops: optional override of subgraph base nodes, subject to change
        unmatchable_types_map: optional override of unmatchable types, subject to change

    Return:
        Returns a tuple of (model_a_with_loggers, model_b_with_loggers).  Modifies both models inplace.
    z.quantization_api._numeric_suite_fx.add_loggersr   )r   r   r   )	rC   r   r   ry   r   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   s                   r=   add_loggersr     s    4 
HH  !QR&(-/,.DEH,.DEHww 78D'F%($ (3#C ww 78D'F%($ (3#C +)I3	 	r>   c                    t         j                  j                  d       | j                         D ]  \  }}t	        ||      xs5 t	        |t         j
                  j                        xr |j                  dk(  }|sM|j                  }||vri ||<   |j                  ||   vsJ |j                   d       |j                  ||   vri ||   |j                  <   |j                  ||   |j                     vrg ||   |j                     |j                  <   |j                  }t        |j                        dkD  r|j                  }|j                  ||j                  |j                  |j                   |j"                  |j$                  |j&                  |j(                  |j*                  d
}t-        |d      r|j.                  |d<   |j0                  |d<   n
g |d<   d|d<   ||   |j                     |j                     j3                  |       ||   |j                     |j                     j5                  d	 
        y )NzAquantization_api._numeric_suite_fx._extract_logger_info_one_modelr(   z is already present in resultsr   )
typevaluesr+   r0   r,   r/   r2   r3   r4   r5   rr   rq   rZ   c                     | d    d| d    S )Nr3   :r2    )ress    r=   <lambda>z0_extract_logger_info_one_model.<locals>.<lambda>v  s    3~#6"7q=O9P8Q R r>   )key)rC   r   r   named_modulesrB   jitRecursiveScriptModuleoriginal_namer.   r-   r1   r)   rH   r*   r+   r0   r,   r/   r2   r3   r4   r5   hasattrrr   rq   rE   sort)	r   r   r   _gm_namemod	is_loggerr   stats_to_usedatas	            r=   _extract_logger_info_one_modelr   E  s.   
 
HH  K ,,. *#sJ/ 
sEII;;< 4!!^3 	 ,,C'!!gcl2A..!!?@A2ws|313S--.~~WS\#2B2B%CCACS--.s~~>99L3==!A%"}}((&!$!2!2(+(@(@"%"4"4),)B)B$'$8$8 # 0 0ww"D sM*&)oo]#-0-C-C)*&(]#-/)*CL))*3>>:AA$GCL))*3>>:??R @ Q*r>   !model_name_to_use_for_layer_namesc                     t         j                  j                  d       i }| |fD ]  }t        |||        t	        |       t        ||      }|S )a  
    Traverse all loggers in `model_a` and `model_b`, and extract the logged
    information.

    Args:
        model_a: model A
        model_b: model B
        logger_cls: class of Logger to use
        model_name_to_use_for_layer_names: string name of model to use for
          layer names in the output

    Return:
        NSResultsType, containing the logged comparisons
    z6quantization_api._numeric_suite_fx.extract_logger_info)rC   r   r   r   r#   r$   )r   r   r   r   r   r   s         r=   extract_logger_infor   |  sc    ( 
HH  @  G7# C&ugzBC 7#52G Nr>   node_type_to_io_type_mapc	           
          t         j                  j                  d       t        ||||      }	t	        | ||||	|||      }
|
S )Nz;quantization_api._numeric_suite_fx._add_shadow_loggers_impl)r   r   )rC   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   gm_a_shadows_bs              r=   _add_shadow_loggers_implr     s]     
HH  E 9d46K (+!9	N r>   c	                 `   t         j                  j                  d       g }	g }
t        |	|
      }t        |	|
      }t	        ||j                  |            }t        |d      }|||_        t	        ||j                  |            }t        |d      }|||_        t        | ||||||||	      S )a  
    Instrument model A and model B with shadow loggers.

    Args:
        name_a: string name of model A to use in results
        model_a: model A
        name_b: string name of model B to use in results
        model_b: model B
        logger_cls: class of Logger to use
        should_log_inputs: whether to log inputs
        base_name_to_sets_of_related_ops: optional override of subgraph base nodes, subject to change
        unmatchable_types_map: optional override of unmatchable types, subject to change
    z5quantization_api._numeric_suite_fx.add_shadow_loggersr   )r   r   r   r   )	rC   r   r   ry   r   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   s                    r=   add_shadow_loggersr     s    0 
HH  ? ')-/,.DEH,.DEHww 78D'F%($ (3#C ww 78D'F%($ (3#C #+)I!93
 
r>   model_a_shadows_bc                     t         j                  j                  d       t        j                  t
              }t        | ||       t        |       t        ||      }t        |      S )al  
    Traverse all loggers in a shadow model, and extract the logged
    information.

    Args:
        model_a_shadows_b: shadow model
        logger_cls: class of Logger to use
        model_name_to_use_for_layer_names: string name of model to use for
          layer names in the output

    Return:
        NSResultsType, containing the logged comparisons
    z=quantization_api._numeric_suite_fx.extract_shadow_logger_info)	rC   r   r   collectionsdefaultdictdictr   r#   r$   )r   r   r   r   s       r=   extract_shadow_logger_infor     s\    $ 
HH  G )44T:G"#4gzJ7#52G =r>   model_name_1model_name_2rp   comparison_namec                    | j                         D ]  }|j                         D ]  }||v s
J | d       ||v s
J | d       ||   }||   }|D ]r  }	|	d   }
|	d   }d}|D ]  }|d   }|d   }||
k(  s||k(  s|} n |J |d   }|	d   }g |	|<   t        ||      D ]"  \  }} |||      }|	|   j                  |       $ t   y)aY  
    Compares the logged values from `model_name_2` against the corresponding
    values in `model_name_1`, using `comparison_fn`. Records the result
    in `model_name_2`'s results under `comparison_name`. Modifies `results` inplace.

    Args:
        results: the result data structure from `extract_logger_info` or
          `extract_shadow_logger_info`.
        model_name_1: string name of model 1
        model_name_2: string name of model 2
        comparison_fn: function to compare two Tensors
        comparison_name: string name of model to use for
          layer names in the output
    z not found in resultsr2   r3   Nr   )r   ziprE   )r   r   r   rp   r   results_type_to_resultsmodel_name_to_results	results_1	results_2result_2index_within_arg_2index_of_arg_2result_1cur_result_1index_within_arg_1index_of_arg_1values_1values_2value_1value_2comparison_results                        r=   %extend_logger_results_with_comparisonr    sf   * $+>>#3  H%<%C%C%E 	H! 5564565  5564565 .l;I-l;I% H%-.@%A"!).!9$- L)56H)I&%1.%AN*.@@&.8#/  +++#H-#H-,.)(+Hh(? H$GW(5gw(G%_-445FGH%H	H Hr>   example_inputsqconfig_multi_mappingbackend_configcustom_prepare_fncustom_prepare_kwargscustom_tracerc                    |t        j                  g g       }n|}t        j                  j	                  | |j                  |             }|j                  |_        t        |      }	 |	j                  |  t        |j                  d            }
t        |      }t        |      }g }g }g }t        |j                  |
|||||      }t!        |      }g }|j"                  D ]6  }t%        ||
|j                  ||j                        }|j'                  |       8 t)        |j+                               D ]$  \  }\  }}t-        |||||j"                  |||       & |S )a  
    Given a model with a graph with M ops such as


      args_kwargs_m -> op_m -> output_m


    And a set of N qconfigs for each op, creates a new model, with
    each of the subgraph of `op_m` transformed into

    .. code::

           |---------> op_m_n -> log_m_n
           |                     /
      args_kwargs_m ---------> op_m -> log_m_0

    Where op_m_n is op_m wrapped in a submodule and transformed with
    qconfig_n, and its inner graph looks like

    .. code::

      args_m -------- op_m_prepared_with_qconfig_n -> out_m_n
                  /
      kwargs_m ---

    This is useful for testing different quantization of multiple layers in
    a single pass through the model.

    High level TODOs for future PRs:
    * figure out a better way to name the output structure
    * return a results data structure instead of printing it out
    * add examples to docblocks
    Fremove_duplicate)quantize_fxQuantizationTracerrC   rm   r   r   r   r   r   	propagater   r   r   r   r   graphr	   qconfig_mappings_listr   rE   	enumeraterR   r   )r   r  r  r  r  r  r  tracermtoutput_propmodulespatternsroot_node_getter_mappingstandalone_module_namesstandalone_module_classescustom_module_classesmatchessubgraphs_deduplist_of_node_name_to_qconfigqconfig_mappingnode_name_to_qconfigsubgraph_idxr   nodes_in_this_subgraphs                           r=   prepare_n_shadows_modelr!  N  s   V //B7			eV\\%%8	9B#66B R.KK>* 2##U#;<G0@HEnU)+,.(*
 !G .B'-JO AC 0FF B=?F4M4M 
 	%++,@A	B ?H? 
::z#9 	;"!77(!		

 Ir>   r  c           	         t        j                  g g       }t        j                  j	                  | |j                  |             }|j                  |_        t        |      } |j                  |  t        |j                  d            }t        |      }t        |      }	g }
g }g }t        |j                  |||	|
||      }t!        |      }t#        |||j                  ||j                        }t%        ||||       |S )a  
    Note: this API is not recommended for wide usage, it is only
    provided for customers who need to migrate from the `add_loggers`
    API.

    This creates a model which provides logging for the following
    problem: if we quantize `model` with `qconfig_mapping` and feed
    the same input through both models, log the comparisons of
    corresponding intermediate layers.

    The problem is solved with a single model.  Specifically, we
    partition `model` into N subgraphs, create a copy of each relevant
    subgraph, wrap it in a module, apply the quantization API to that
    module, and hook up loggers to measure the comparisons.

    Example starting graph:

      x0 -> op0 -> x1 -> op1 -> x2

    Example config: quantize op0 to int8, do nothing to op1.
    The following graph will be created:

    .. code::

      x0_0 -> op0_0 -> x1_0 -> log -----> op1_0 -> x2_0 -> log
       \                        \                           \       # noqa: W605
         ---> op0_1 -> x1_1 ----> clog -> op1_0 -> x2_1 ----> clog

    Where op0_0 is op0, op0_1 is op0 wrapped in a submodule and quantized
    to int8, op1_0 is op1 (appearing in the graph twice), log is a logger,
    and clog is a comparison logger.
    Fr	  )r  r  rC   rm   r   r   r   r   r   r  r   r   r   r   r   r  r	   r   r
   )r   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  s                   r=   $_prepare_n_shadows_add_loggers_modelr#    s   N ++B3F			eV\\%%8	9B#66B R.KK>* 2##U#;<G0@HEnU)+,.(*
 !G .B'-JO :
GRXX0I0I R/CWXIr>   c                     t        j                  |g      }t        | |||      } ||  t        |      }t	        |      }|S )z
    Note: this API is not recommended for wide usage, it is only
    provided for customers who need to migrate from the `add_loggers`
    API.
    )r   from_list_qconfig_mappingr!  convert_n_shadows_modelr   )r   r  r  r  r  mpmqweight_comparisons           r=   _n_shadows_compare_weightsr*    sV     0II	 
!~4n
B
 	 	$B1"5r>   r9   c                 d    | j                         D ]  \  }}t        |t              s||_         y)z;
    Sets the `enabled` setting on a `model`'s loggers
    N)r   rB   r(   r9   )r   r9   rN   childs       r=   loggers_set_enabledr-  '  s1     '') $5e\*#EM$r>   r:   c                 d    | j                         D ]  \  }}t        |t              s||_         y)zD
    Sets the `save_activations` setting on a `model`'s loggers
    N)r   rB   r(   r:   )r   r:   _namer,  s       r=   loggers_set_save_activationsr0  2  s2     ++- 6ue\*%5E"6r>   custom_convert_fncustom_convert_kwargsc                 \   | j                   j                  D ]  }|j                  j                  t              s#t        | |j                        }|4t        j                  j                  j                  j                  |      }n|i } ||fi |}t        | |j                  |        | S )zg
    Given a model from `prepare_n_shadows_model`, runs `convert_fx`
    on each shadow submodule.
    )r  nodesnamerS   r   getattrrC   rk   r~   r  
convert_fxsetattr)r   r1  r2  r   orig_modconverted_mods         r=   r&  r&  >  s     !! 5 99 ?@udii0H ( % 5 5 A A L LX V(0,.) 1( T>S TE499m45 Lr>   c                 ,    i }t        | |t               |S )z/
    Extracts logger results from `model`.
    )r   r(   )r   r   s     r=   extract_results_n_shadows_modelr<  W  s      G"5'<@Nr>   c                 F    t        |       }t        |      }t        |       y)z2
    Prints a summary of extracted `results`.
    N)r   r   r   )r   results_groupedresults_comparisons      r=   !print_comparisons_n_shadows_modelr@  `  s"     08O2?C./r>   )N)NNN)NN)FNN)FNNN)`r^   r   typingr   r   r   r   rC   !torch.ao.quantization.quantize_fxrk   r~   r  torch.nnr   torch.ao.ns.fx.graph_matcherr   torch.ao.ns.fx.mappingsr   torch.ao.ns.fx.n_shadows_utilsr	   r
   r   r   r   r   r   r   r   $torch.ao.ns.fx.qconfig_multi_mappingr   torch.ao.quantizationr   $torch.ao.quantization.backend_configr   *torch.ao.quantization.backend_config.utilsr   %torch.ao.quantization.fx.graph_moduler   $torch.ao.quantization.fx.match_utilsr   .torch.ao.quantization.fx.qconfig_mapping_utilsr   )torch.ao.quantization.fx.quantize_handlerr   torch.fxr   torch.fx.graphr   fx.graph_passesr   r   fx.ns_typesr   r    r!   fx.utilsr"   r#   r$   fx.weight_utilsr%   torch.ao.quantization.qconfigr&   rG   rD   ra   r   r(   rh   r  ry   rc   r_   r   r   setr   r   r   r   r   r   r   r   r   r   r   r  r!  r#  r*  r-  r0  r&  r<  r@  r   r>   r=   <module>rW     s  Tl  9 9  7 7  D H
 
 
 E 0 > R > X    E R R 
 6 8ellE%,,*D$EEFi-299 i-X%7\ %7P@{-- @2 	III $(dCi(8#9I 	I
 )1S$x)**+)I 
I8 TXHL 	11
1 1 	1
 '/tC=M9N4N/O&P1 $Dc2B.C)C$DE1 )1S$x)**+)1 1r TXHL 	99YY9 9 YY	9
 '/tC=M9N4N/O&P9 $Dc2B.C)C$DE9 )1S$x)**+)9 9x +/uT3^/D*E ,0dCn0E+F	
  YYJ TXHL5&5&
5& 5& 	5&
 5& 5& '/tC=M9N4N/O&P5& $Dc2B.C)C$DE5& 299bii 5&| $SWHL55YY5 5 YY	5
 5 5 '/tC=M9N4N/O&P5 $Dc2B.C)C$DE5 299bii 5p29922 2 
	2n YY YY    (+	 
  T TXKOHL
  	
   '/tC=M9N4N/O&P 'tC5E1F,F'GH $Dc2B.C)C$DE YYH $SWKOHL66YY6 6 YY	6
 6 6 '/tC=M9N4N/O&P6 'tC5E1F,F'GH6 $Dc2B.C)C$DE6 YY6ryy (+ 	@5H5H5H 5H U\\5<<8%,,FG	5H
 5H 
5Hz -16:i88??ii /i "	i
  )i $DcN3i i iZM88??MM $M "	M
 XX__Mb88?? $ "	
 6$uxx $ $$ $	688??	6	6 
	6 -16:) $DcN3 	2588?? } 0} 0 0r>   