
    Phޢ                     	   d Z ddlZddlZddlm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 ddlmZ dd	lmZmZ dd
lmZmZmZ ddl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/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8 ddl9m:Z: ddl;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZC e=ej                  e=ej                  ej                  f   f   ZE G d dej                        ZG G d deG      ZH G d dej                        ZJ	 dWdeKde
de?e=eeKf      d ed!e@e<eKe<e>e>f   f      d"dfd#ZL	 	 	 dXd$eKd%e
d&eKd'e
d(e@e<eKeAe   f      d)e@e<eKeAe   f      d!e@e<eKe<e>e>f   f      d"efd*ZM	 	 	 dXd$eKd+ej                  d&eKd,ej                  d(e@e<eKeAe   f      d)e@e<eKeAe   f      d!e@e<eKe<e>e>f   f      d"efd-ZNdeKde
d.e?e=eeKeKf      d/e?e=eeKeKf      d0e>d"ej                  fd1ZO	 	 dYd2eKd%e
d3eKd'e
d0e>d4ePd(e@e<eKeAe   f      d)e@e<eKeAe   f      d"e=ej                  ej                  f   fd5ZQ	 	 	 dZd2eKd+ej                  d3eKd,ej                  d0e>d4ePd(e@e<eKeAe   f      d)e@e<eKeAe   f      d"e=ej                  ej                  f   fd6ZRdej                  d ed0e>d"dfd7ZSd+ej                  d,ej                  d0e>d8eKd"ef
d9ZT	 	 	 dXd2eKd%e
d3eKd'e
d0e>d4ePd(e@e<eKeAe   f      d:e@e<eKeAe   f      d)e@e<eKeAe   f      d"ej                  fd;ZU	 	 	 	 d[d2eKd+ej                  d3eKd,ej                  d0e>d4ePd(e@e<eKeAe   f      d:e@e<eKeAe   f      d)e@e<eKeAe   f      d"ej                  fd<ZVd=ej                  d0e>d8eKd"efd>ZWd ed?eKd@eKdAe>ej                  ej                  gej                  f   dBeKd"dfdCZX	 	 	 dXdej                  j                  dDeBdEe:dFe"dGe@e>   dHe@e<eKeBf      dIeBd"e
fdJZYdej                  j                  dDeBdKe.dFe"d"ej                  j                  f
dLZZdej                  j                  dDeBdKe.dFe"d"ef
dMZ[dej                  j                  dNePd"dfdOZ\dej                  j                  dPePd"dfdQZ]	 	 dYde
dRe@e>   dSe@e<eKeBf      d"e
fdTZ^dej                  j                  d"efdUZ_d ed"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)GraphModule)Node)$get_base_name_to_sets_of_related_ops)get_matching_subgraph_pairsget_type_a_related_to_b   )extract_weight_from_node)add_loggers_to_modelcreate_a_shadows_b)'rekey_logger_info_on_node_name_of_modelmaybe_add_missing_fqnsget_target_type_str)NSSingleResultValuesTypeNSResultsTypeNSNodeTargetType)&get_fusion_pattern_to_root_node_getter)BackendConfig)_find_matches)_get_observed_graph_module_attr)_generate_node_name_to_qconfig)!_get_pattern_to_quantize_handlers)
QConfigAny)QConfigMapping)	
OutputProp_get_dedup_subgraphsSHADOW_WRAPPER_NODE_NAME_PREFIXgroup_results_by_subgraphcreate_results_comparisonprint_n_shadows_summary2create_n_transformed_and_logged_copies_of_subgraphcreate_add_loggers_graphextract_weight_comparison)QConfigMultiMapping)DictTupleCallableListOptionalSetAnyTypec                        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/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   enabledr:   save_activations)selfr0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   	__class__s               hC:\Users\daisl\Desktop\realtime-object-detection\venv\Lib\site-packages\torch/ao/ns/_numeric_suite_fx.pyr=   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   )r>   r?   
isinstancetorchTensorr.   appenddetachtuplelenr/   )r@   xnew_ress      rB   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!!'*rC   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       rB   __repr__zOutputLogger.__repr__   sa     ++-
-1Zc): qD- 	 
 zl!,,
   #A
) )__name__
__module____qualname____doc__r'   rH   rI   __annotations__RNNReturnType
_is_impurestrintr(   r=   rP   r]   __classcell__rA   s   @rB   r-   r-      s     M"" J &(?%?% ?% 	?%
 ?%  #?% "?% ?% ?% ?% c]?% c]?%F$-rC   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)r<   r=   rH   aonsfxutilscompute_sqnrcomparison_fncomparison_fn_namecomparisons)r@   argskwargsrA   s      rB   r=   zOutputComparisonLogger.__init__  sE    $)&)"XX[[^^11>>"(rC   c                 $   | j                   s|S t        |t        j                        sJ d       | j                  r)| j
                  j                  |j                                | j                  j                  | j                  ||             |S )rE   z#non-tensor inputs not yet supported)
r>   rG   rH   rI   r?   r.   rJ   rK   rv   rt   )r@   rN   x_refs      rB   rP   zOutputComparisonLogger.forward  sq     ||H!U\\*Q,QQ*  JJahhj) 2 21e <=rC   c                     | j                   j                         D ci c]  \  }}|dk7  r|j                  d      s||  }}}d| dS c c}}w )NrR   rS   zOutputComparisonLogger(rT   rU   rY   s       rB   r]   zOutputComparisonLogger.__repr__  sa     ++-
-1Zc): qD- 	 
 )A66
r^   )r`   ra   rb   rc   r=   rP   r]   ri   rj   s   @rB   rl   rl      s    
7rC   rl   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 )rE   T)rG   rH   ro   quantizationObserverBaseFakeQuantizeBaser<   is_leaf_module)r@   r~   r   rA   s      rB   r   zNSTracer.is_leaf_module'  sR     a..;;<58800AABw%a)>??rC   )r`   ra   rb   rc   rH   nnModulerg   boolr   ri   rj   s   @rB   r}   r}   "  s5    @ @ @QU @ @rC   r}   r2   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)rH   _C_log_api_usage_oncer   WEIGHTvaluer	   )	r2   r   r   r   r   noder3   res_typeextracted_weights	            rB   _extract_weights_one_modelr   1  sy     
HH  !`a7h+22883%;=w&%-rN!7G6HGHh'
3 8rC   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)
rH   r   r   r   rW   rJ   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                  rB   _extract_weights_implr   C  s     
HH  ![\8d4
 ?A#>@#399;
E!&
J'..
0G0G/TU'..
0G0G/TU <  Gd;W*, d;W*,
 7# 6g|LGNrC   model_amodel_bc           	         t         j                  j                  d       |
t               }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)rH   r   r   r   r   r}   r   tracer   _node_name_to_scoper   )r   r   r   r   r   r   r   type_a_related_to_bskipped_module_namesskipped_module_classestracer_atracer_br    maybe_model_a_node_name_to_scoper    maybe_model_b_node_name_to_scopes                   rB   extract_weightsr   k  s    4 
HH  !UV'/02 	) 	  @A  ')-/,.DEH,.DEHww 78D'FwPd'e$'3#C ww 78D'FwPd'e$'3#C  dL$0PAC CrC   $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)rH   r   r   r
   )
r2   r   r   r   r   %node_to_instrument_inputs_to_ref_name&node_to_instrument_outputs_to_ref_namer   r3   ref_node_types
             rB   _add_loggers_one_modelr     s     
HH  !\] JL)JL*)M%h7?6O-d3 *N)N%h8@-7P.t4 *O !4.
JHE LrC   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)rH   r   r   r   rW   r   r   rJ   
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                       rB   _add_loggers_implr     sL    
HH  !WX8d(*?A .0*-/*.0+.0+0F0L0L0N,
,Z-j.E.EtL-j.E.EtL 299&&
ODF299&&
ODF 	066  *o>	@/66  *o>	@ 1O" )</=K )</=K %%rC   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   )	rH   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                   rB   add_loggersr     s    4 
HH  !QR&(-/,.DEH,.DEHww 78D'FwPd'e$'3#C ww 78D'FwPd'e$'3#C fdJ+)I3	5 5rC   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valuesr0   r5   r1   r4   r7   r8   r9   r:   rv   ru   r_   c                     | d    d| d    S )Nr8   :r7    )ress    rB   <lambda>z0_extract_logger_info_one_model.<locals>.<lambda>B  s    ~&'q-?)@(ABrC   )key)rH   r   r   named_modulesrG   jitRecursiveScriptModuleoriginal_namer3   r2   r6   r.   rM   r/   r0   r5   r1   r4   r7   r8   r9   r:   hasattrrv   ru   rJ   sort)	r   r   r   gm_namemod	is_loggerr   stats_to_usedatas	            rB   _extract_logger_info_one_modelr     s*   
 
HH  !de++- sJ' 3		 ? ?@ 8%%7	 	 ,,C'!!>>5 B>>""@AB5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>>:??C @ U .rC   !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)rH   r   r   r   r   r   )r   r   r   r   r   r   s         rB   extract_logger_infor   I  sV    ( 
HH  !YZG7#&ugzB $ 7#524GNrC   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   )rH   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   gm_a_shadows_bs              rB   _add_shadow_loggers_implr   i  sU     
HH  !^_8d4 (fd$:J+!9;N rC   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   )	rH   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                    rB   add_shadow_loggersr     s    0 
HH  !XY&(-/,.DEH,.DEHww 78D'FwPd'e$'3#C ww 78D'FwPd'e$'3#C #fdJ+)I!935 5rC   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)	rH   r   r   collectionsdefaultdictdictr   r   r   )r   r   r   r   s       rB   extract_shadow_logger_infor     sV    $ 
HH  !`a(44T:G"#4gzJ7#524G=rC   model_name_1model_name_2rt   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 resultsr7   r8   Nr   )r   ziprJ   )r   r   r   rt   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                        rB   %extend_logger_results_with_comparisonr    sE   * $+>>#3%<%C%C%E!#88 7. 5678#88 7. 5678 .l;I-l;I%%-.@%A"!).!9$-L)56H)I&%1.%AN+/AA'>9#/ %.  +++#H-#H-,.)(+Hh(?$GW(5gw(G%_-445FG )@' & &F $4rC   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QuantizationTracerrH   rq   r   r   r   r   r   	propagater   r   r   r   r   graphr   qconfig_mappings_listr   rJ   	enumeraterW   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                           rB   prepare_n_shadows_modelr&     s{   V //B7			eV\\%%8	9B#66B R.KK>* 2##U#;<G0@H.~> )+,.(*
'8%=!:<QSG 	W% 
 AC 0FF=?F4M4M O$++,@A G o++-. 	=;
$::j*@!779U4	
 / IrC   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  rH   rq   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                   rB   $_prepare_n_shadows_add_loggers_modelr(  a  s   N ++B3F			eV\\%%8	9B#66B R.KK>* 2##U#;<G0@H.~> )+,.(*
'8%=!:<QSG 	W%  :
GRXX0I0IK
 
O_.BD IrC   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           rB   _n_shadows_compare_weightsr/    sT     	556GH 	 ~4n
FB 	 	$B1"5rC   r>   c                 d    | j                         D ]  \  }}t        |t              s||_         y)z;
    Sets the `enabled` setting on a `model`'s loggers
    N)r   rG   r-   r>   )r   r>   namechilds       rB   loggers_set_enabledr3    s,     **,ee\*#EM -rC   r?   c                 d    | j                         D ]  \  }}t        |t              s||_         y)zD
    Sets the `save_activations` setting on a `model`'s loggers
    N)r   rG   r-   r?   )r   r?   r1  r2  s       rB   loggers_set_save_activationsr5    s-     **,ee\*%5E" -rC   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  nodesr1  rX   r   getattrrH   ro   r   r  
convert_fxsetattr)r   r6  r7  r   orig_modconverted_mods         rB   r+  r+    s     !! 99 ?@udii0H ( % 5 5 A A L L! )0,.) 1( T>S TE499m4 " LrC   c                 ,    i }t        | |t               |S )z/
    Extracts logger results from `model`.
    )r   r-   )r   r   s     rB   extract_results_n_shadows_modelr@    s      G"5'<@NrC   c                 F    t        |       }t        |      }t        |       y)z2
    Prints a summary of extracted `results`.
    N)r   r   r   )r   results_groupedresults_comparisons      rB   !print_comparisons_n_shadows_modelrD    s"     08O2?C./rC   )N)NNN)NN)FNN)FNNN)arc   r   rH   torch.nnr   !torch.ao.quantization.quantize_fxro   r   r  torch.fxr   torch.fx.graphr   torch.ao.ns.fx.mappingsr   torch.ao.ns.fx.graph_matcherr   r   fx.weight_utilsr	   fx.graph_passesr
   r   fx.utilsr   r   r   fx.ns_typesr   r   r   *torch.ao.quantization.backend_config.utilsr   $torch.ao.quantization.backend_configr   $torch.ao.quantization.fx.match_utilsr   %torch.ao.quantization.fx.graph_moduler   .torch.ao.quantization.fx.qconfig_mapping_utilsr   )torch.ao.quantization.fx.quantize_handlerr   torch.ao.quantization.qconfigr   torch.ao.quantizationr   torch.ao.ns.fx.n_shadows_utilsr   r   r   r   r   r   r    r!   r"   $torch.ao.ns.fx.qconfig_multi_mappingr#   typingr$   r%   r&   r'   r(   r)   r*   r+   rI   re   r   r-   rl   r  r}   rg   r   r   r   r   r   r   r   r   r   r   r   r   r  r&  r(  r/  r3  r5  r+  r@  rD  r   rC   rB   <module>rZ     s|  Tl    7 7   

  
 ^ > > Q Y W 4 0
 
 
 E H H HellE%,,*D$EEFf-299 f-R#7\ #7L@{-- @( Y]III $(dCi(8#9I 	I
 )1c4(@R;S6S1T(UI 
I. TXHLX\%%
% % 	%
 '/tC=M9N4N/O&P% $Dc2B.C)C$DE% )1c4(@R;S6S1T(U% %Z TXHLX\0C0CYY0C 0C YY	0C
 '/tC=M9N4N/O&P0C $Dc2B.C)C$DE0C )1c4(@R;S6S1T(U0C 0Cf +/uT3^/D*E ,0dCn0E+F	
  YY> TXHL)&)&
)& )& 	)&
 )& )& '/tC=M9N4N/O&P)& $Dc2B.C)C$DE)& 299bii )&d  %SWHL,5,5YY,5 ,5 YY	,5
 ,5 ,5 '/tC=M9N4N/O&P,5 $Dc2B.C)C$DE,5 299bii ,5^39933 3 
	3pYYYY  (+	
 N TXKOHL
  	
   '/tC=M9N4N/O&P 'tC5E1F,F'GH $Dc2B.C)C$DE YY8 $SWKOHL+5+5YY+5 +5 YY	+5
 +5 +5 '/tC=M9N4N/O&P+5 'tC5E1F,F'GH+5 $Dc2B.C)C$DE+5 YY+5\yy (+ 	:4H4H4H 4H U\\5<<8%,,FG	4H
 4H 
4Hv -16:^88??^^ /^ "	^
  )^ $DcN3^ ^ ^BI88??II $I "	I
 XX__IX88?? $ "	
 0$uxx $ $$ $	688??	6	6 
	6 -16:) $DcN3 	2588?? } 0} 0 0rC   