
    Pi                         d Z ddlZddlZddlZddlZddlmZ ddlmZm	Z	 ddl
mZmZmZmZ ddlZddlmc 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 dd
lm Z  ddl!m"Z" ddl#m$Z$ g dZ%d Z&d Z'dede(defdZ)d Z*d Z+dej,        dej,        de-fdZ.de/de/de-dej0        de-de1e/e/f         fdZ2d Z3d  Z4d!ej        j5        d"ej        j5        dee(         fd#Z6d$ed%e7e(ef         de7e(ef         fd&Z8d$edd'fd(Z9d)ed%e7e(ef         dd'fd*Z:de/de/ddfd+Z;ej<        fdej,        dej,        de/de/dej0        d,ej,        de-d-ej=        de1ej,        ej,        f         fd.Z>d$ede/fd/Z?d0ej        j5        d1e1ed2f         de7e(e1ed2f         f         fd3Z@d4e(defd5ZA	 dbd6ej        j5        d7ed4e(d8ed9eejB                 defd:ZCejD        jE        jF        jG        ejD        jE        jF        jH        ejD        jE        jI        jG        gZJejD        jE        jK        jG        ejD        jE        jK        jH        ejD        jE        jL        jG        gZMd;ejN        j        d<ejN        j        de-fd=ZOd> ZPd? ZQd@efdAZRdBefdCZSdBefdDZTdBefdEZUdFefdGZVdBefdHZW	 dcdJedKedLee         dMedNedOe-ddfdPZXdNeddfdQZYd0ede7e(e1e(eZf         f         fdRZ[	 dcdSed1e1ed2f         dTe-defdUZ\dVeddfdWZ]dX Z^	 	 dddYejN        j        dZe-d[ee_e                  fd\Z`	 	 dedYejN        j        d[ee_e                  d]ee7eeae/e-ej0        f         e/f                  fd^Zbd0efd_Zcd@efd`Zdd@ejN        j        de_ejN        j                 fdaZedS )fz?
Utils shared by different modes of quantization (eager/graph)
    N)OrderedDict)getfullargspec	signature)AnyCallableOptionalUnion)quantized_decomposed_lib)_assign_attr	_AttrKind)GraphGraphModuleNode)fuse_conv_bn_weights)is_parametrized)LeafSpec)_assert_and_get_unique_device)is_per_tensoris_per_channelgetattr_from_fqnget_qparam_dictcheck_min_max_validcalculate_qmin_qmax)has_no_children_ignoring_parametrizationsget_fqn_to_example_inputsto_underlying_dtypedetermine_qparamsvalidate_qmin_qmaxget_new_attr_name_with_prefixcreate_getattr_from_value"_get_aten_graph_module_for_pattern_is_conv_node_is_conv_transpose_node_is_sym_size_node_filter_sym_size_usersc                 B    | t           j        k    p| t           j        k    S N)torchper_tensor_affineper_tensor_symmetricqschemes    s/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/torchao/quantization/pt2e/utils.pyr   r   :   s    e--VE<V1VV    c                 L    | t           j        t           j        t           j        fv S r'   )r(   per_channel_affine per_channel_affine_float_qparamsper_channel_symmetricr+   s    r-   r   r   >   s&     .#  r.   objfqnreturnc                 ^    t          j        t          |                    d          |           S )zO
    Given an obj and a fqn such as "foo.bar.baz", returns gm.foo.bar.baz.
    .)	functoolsreducegetattrsplit)r3   r4   s     r-   r   r   F   s#     GSYYs^^S999r.   c                 b   t           j        t           j        t           j        t           j        t           j        t           j        t           j        t           j        t           j        t           j        t           j        t           j        t           j        t           j        t           j	        t           j	        t           j
        t           j
        t           j        t           j        t           j        t           j        t           j        t           j        i}| |v sJ dt          |           z               ||          S )NzUnsupported dtype: )r(   quint8uint8qint8int8qint32int32quint4x2quint2x4uint16int16float8_e5m2float8_e4m3fnstr)qdtypeDTYPE_MAPPINGs     r-   r   r   M   s    ekUZekU[
EJelU[U[5,U0M ]"""$9CKK$G"""  r.   c                    ddl m} t          | dd           }| j        }||d}|rt	          | |          rd |dS t          |          rt          j        }nHt          |          r'|t          j	        k    rt          j
        }| j        |d<   nt          d|           ||d<   |                                 \  }}||d<   ||d<   t          | d	          r
| j        |d	<   t          | d
          r
| j        |d
<   |S )Nr   )PlaceholderObserverr,   )r,   dtypeaxiszUnrecognized qscheme: scale
zero_point	quant_min	quant_max)"torchao.quantization.pt2e.observerrM   r:   rN   
isinstancer   r(   r)   r   r2   r0   ch_axisRuntimeErrorcalculate_qparamshasattrrR   rS   )observer_or_fake_quantrM   r,   rN   qparamsrP   rQ   s          r-   r   r   `   sH   FFFFFF,i>>G"(E!E22G 1j!79LMM 1%000W 	?)		 	  ? e111.G08=G==>>> !GI.@@BBE:GG&GL%{33 @5?%{33 @5?Nr.   min_valmax_valc                    |                                  dk    s|                                 dk    rt          j        d           dS |                                 dk    s|                                dk    rS| t	          d          k    r)|t	          d          k    rt          j        d           dS | |k    sJ d|  d|             n(t          j        | |k              sJ d|  d|             dS )	zChecks if the given minimum and maximum values are valid, meaning that
    they exist and the min value is less than the max value.
    r   zMmust run observer before calling calculate_qparams. Returning default values.Finfz-infzmin z should be less than max T)numelwarningswarndimfloatr(   all)r\   r]   s     r-   r   r      s    }}!w}}!33*	
 	
 	
 u{{}}W[[]]a//eEll""w%--'?'?M.  
 5'!!!#U'#U#UG#U#U!!!!yG+,, 	
 	
>7>>W>>	
 	
, 4r.   rR   rS   has_customized_qrangerN   reduce_rangec                    |r|t           j        t           j        fv rd\  }}nd\  }}| |}}||||}}||z
  dz   }	|t           j        t           j        fv rd|	cxk     rdk    sn J d            n3|t           j        t           j        fv rd|	cxk     rdk    sn J d	            |r
| d
z  |d
z  }} n|t           j        t           j        fv r|rd\  } }n}d\  } }nw|t           j        t           j        fv r|rd\  } }nUd\  } }nO|t           j        t           j        fv rd\  } }n/|t           j        fv rd\  } }n|t           j        fv rd\  } }nd\  } }| |fS )ztCalculates actual qmin and qmax based on the quantization range,
    observer datatype and if range is reduced.
    )r   l    )r      N   r      zRquantization range should be positive and not exceed the maximum bit range (=256).l        zYquantization range should be positive and not exceed the maximum bit range (=4294967296).   )i?   )i   )r   rn   )i   i)r   i  )i i  )r      )	r(   rA   rB   r?   r@   r=   r>   rE   rF   )
rR   rS   rf   rN   rg   initial_quant_mininitial_quant_maxcustom_quant_mincustom_quant_max
qrange_lens
             r-   r   r      s     /) U\5;///3?0003900 .7	*',<,H    1
 ')::Q>
U[%*---z((((S(((((d )((( u|U[111z****U*****k +**  	B#,>9>yI U[%*--- 1'.$	99'0$	99u|U[111 .'-$	99'-$	99u|U[111#< Iyyu|n$$#/ Iyyu{m###6 Iyy#( Iyir.   c                     |                      dd          }t          |          dk    r
d|d         fS |d         |d         fS )z,
    Turn 'foo.bar' into ['foo', 'bar']
    r7   rj    r   )rsplitlen)targetrs     r-   _parent_namer{      sE     	c1A
1vv{{1Q4xtQqTzr.   c                     t          | j                  dk    rdS t          |           r!t          | j                  dk    od| j        v S dS )z
    Checks if module._modules is empty or
    if module is a parametrization, checks that module._modules only has
    the 'parametrizations' module
    r   Trj   parametrizationsF)rx   _modulesr   )modules    r-   r   r      sU     6?q  t		 	  6?##q(R-?6?-RRur.   root	submodulec                 J    |                                  D ]\  }}||u r|c S dS )aZ  Get the path (fully qualified name) of a submodule

    Example::

    >> class M(torch.nn.Module):
           def __init__(self) -> None:
               self.linear = torch.nn.Linear(5, 5)
           def forward(self, x):
               return self.linear(x)

    >> m = M()
    >> l = m.linear
    >> _get_path_of_module(m, l)
    "linear"
    N)named_modules)r   r   nps       r-   _get_path_of_moduler      s?    $ ""$$  1>>HHH 4r.   flocc                 D      fd|                                 D             S )zGet local keyword arguments

    Example::

    >> def f(self, a, b=9):
           pass
    >> loc = {"a": 6, "c": 7}
    >> _get_signature_locals(f, loc)
    {"a": 6}
    c                 H    i | ]\  }}|t                    j        v ||S  )r   
parameters).0kvr   s      r-   
<dictcomp>z)_get_signature_locals.<locals>.<dictcomp>  s2    IIITQA11H,H,HAq,H,H,Hr.   )items)r   r   s   ` r-   _get_signature_localsr     s(     JIIISYY[[IIIIr.   zOrderedDict[str, Any]c                     i }t          |           j                                        D ]E\  }}|j        |j        ur|j        ||<   |j        |j        u rd||<   2|j        |j        u ri ||<   Ft          |          S )zGet all default keyword arguments from function signature

    Example::

    >> def f(self, a, b=9):
           pass
    >> _get_default_kwargs(f)
    {"b": 9}
    r   )	r   r   r   defaultemptykindVAR_POSITIONALVAR_KEYWORDr   )r   kwargsnameparams       r-   _get_default_kwargsr     s     F ||.4466  e=++ =F4LLZ5///F4LLZ5,,,F4Lvr.   funcc                     t          |           }t          | |          }|                                }|                                D ]\  }}||v r|||<   |S )a(  Given a function and local function arguments, normalize the keyword
    arguments by filling in default arguments from function signature

    Example::

    >> def f(self, key1=3, key2=3):
           pass
    >> loc = {"key2": 6}
    >> _normalize_kwargs(f, loc)
    {"key1": 3, "key2": 6}
    )r   r   copyr   )r   r   default_kwargslocal_kwargsnormalized_kwargsattrvals          r-   _normalize_kwargsr   3  so     )..N(s33L&++--!'')) * *	c$$$&)d#r.   c                 X    | dcxk    r|k    sn J d            | |k     s
J d            dS )ae  Validates that the user-specified quantization range is properly initialized
    and within the given bound supported by the observer dtype.

    To accommodate lower-bit quantization with respect to the existing torch.qint8 and
    torch.quint8 datatypes, the user can choose to use dynamic quantization range by passing
    in a tuple of initial qmin and qmax values. One use case is these customized qmin and qmax
    values are used to calculate static estimates of the scale and zero point for aggressive lower-bit
    fake quantization. These estimates are compared against parameters learned through backpropagation.
    The related literatures for scale and zero point via backpropagation are as follows:

    Learned Step Size Quantization: https://openreview.net/pdf?id=rkgO66VKDS
    Trained Quantization Thresholds: https://arxiv.org/pdf/1903.08066.pdf
    r   z1Used-specified quantization range must include 0.zKqmin must be strictly less than qmax for user-specified quantization range.Nr   )rR   rS   s     r-   r   r   I  sX      &&&&Y&&&&&; '&& y   U !    r.   epsr,   c                    t          | |          sBt          j        dg| j        j                  t          j        dg| j        j                  fS t          j        | t          j        |                     }t          j        |t          j        |                    }	|j        }
t          j        |	                                t          j
        |
          }t          j        |	                                t          j        |
          }|                    |
          }|t          j        k    s|t          j        k    rt          j        | |	          }	|	t!          ||z
            dz  z  }t          j        ||          }|t          j        t          j        fv rZ|r0|                    |	                                ||z   dz            }n |                    |	                                d          }n|t          j        k    rM|| z
  t!          ||z
            z  }t          j        ||k    |t          j        |                    }d| z  |z  }nz|	|z
  t!          ||z
            z  }t          j        ||          }|t          j        ||z                                t          j                  z
  }t          j        |||          }t5          |j                  dk    r*t          j        t!          |          g|j        |
          }t5          |j                  dk    rdt          j        t1          |          g|j        |
          }|t          j        k    r*t          j        t!          |          g|j        |
          }|                    t          j
                  |                    t          j                  fS )ad  Calculates the quantization parameters, given min and max
    value tensors. Works for both per tensor and per channel cases

    Args:
        min_val: Minimum values per channel
        max_val: Maximum values per channel

    Returns:
        scales: Scales tensor of shape (#channels,)
        zero_points: Zero points tensor of shape (#channels,)
    g      ?devicer   )rN   r   rl      )r   r(   tensorr   typemin
zeros_likemaxonessizedoublezerosint64tor*   r2   rd   r>   r=   new_fullr1   where	ones_likeroundintclamprx   shaperN   )r\   r]   rR   rS   rN   r   rf   r,   min_val_negmax_val_posr   rP   rQ   s                r-   r   r   e  s^   * w00 
|SE'.*=>>>C+A
 A
 A
 
 	
 )GU%5g%>%>??K)GU%5g%>%>??KFJ{''))fMMME[--//u{6RRRJ
&&..C%,,,5;V0V0Vik::uY%:;;a?@	%%%U[%,///$ I'00OO%%	I(=!'C 

 (001B1BCHH
	E:	:	:7"eI	,A&B&BBECK0F0FGG
 '\E)

{*eI	4I.J.JJ	%%%[5-@!A!A!D!DUY!O!OO
[Y	BB
 5;1eEll^5;vNNN
:!!\__Z%5f
 
 

 e<<<z""#:+;F  J 88EL!!:==#=#===r.   c                 D    t          t          |           j                  S )zGet number of positional args for a function

    Example::

    >> def f(self, key1=3, key2=3):
           pass
    >> _get_num_pos_args(f)
    3
    )rx   r   args)r   s    r-   _get_num_pos_argsr     s     ~a  %&&&r.   modelexample_inputs.c                     | i fd}t           j        j        j        |t           j        j        _        	  | |  t           j        j        _        n# t           j        j        _        w xY wS )a  Given a model and its example inputs, return a dictionary from
    fully qualified name of submodules to example_inputs for that submodule,
    e.g. {"linear1": (tensor1,), "linear2": (tensor2,), "sub": (tensor3,),
          "sub.linear1": (tensor4,), ...}

    Used to make quantizing submodules easier now that FX Graph Mode Quantization requires
    example inputs.

    Also works for keyword arguments with default values, we would flatten keyword
    arguments as positional arguments and fill in the missing keyword args with default
    values, e.g. if we have a forward function:
    def forward(self, x, key1=3, key2=3):
        ...

    and we call it with self.submodule(x, key2=6)
    we'll get example_inputs: (x, 3, 6)

    user can also override `key1` with positional arguments as well:
    for self.submodule(x, 5, key2=6)
    we'll get: (x, 5, 6)

    variable positional arguments and variable positional keyword arguments in forward
    function are not supported currently, so please make sure no submodules is using
    them.
    c                    t          |                                          }t          | j        |          }t	          | j                  dz
  }|t          |          z
  }|r!|r|                    d           |dz  }|r||                    |                                           t          |          }t          |           }||	|<    
| g|R i |S )Nrj   F)last)listr   r   forwardr   rx   popitemextendvaluestupler   )selfr   r   submodule_example_inputsr   num_args
num_to_popsubmodule_example_inputs_tupler4   fqn_to_example_inputsorig_module_callr   s            r-   _patched_module_callz7get_fqn_to_example_inputs.<locals>._patched_module_call  s   #'::??#4#4 -dlFCC$T\22Q6$< = ==
 	. 	%%5%111!OJ  	. 	 	!''(9(@(@(B(BCCC)./G)H)H&!$--?)G!#&6t666v666r.   )r(   nnModule__call__)r   r   r   r   r   r   s      @@@r-   r   r     s    8 D7 7 7 7 7 7 7  x/3EHO4~ $4  #3 3333  s   A A0prefixc                 b                           dd           dt          j        j        f fd}|S )Nr7   _r   c                     dt           ffd}d} ||          }t          | |          r |dz  } ||          }t          | |           |S )Nic                 (    t          |           z   S r'   )rI   )r   r   s    r-   get_attr_namezOget_new_attr_name_with_prefix.<locals>.get_new_attr_name.<locals>.get_attr_name  s    CFF?"r.   r   rj   )r   rY   )r   r   r   	attr_namer   s       r-   get_new_attr_namez8get_new_attr_name_with_prefix.<locals>.get_new_attr_name  s    	#S 	# 	# 	# 	# 	# 	# !M!$$	fi(( 	)FA%a((I fi(( 	) r.   )replacer(   r   r   )r   r   s   ` r-   r   r     sG    ^^C%%F	%(/ 	 	 	 	 	 	 r.   r   graphvaluer   c                 `   t          |          } ||           }|t          |           }t          |t          j                  r&|                                                                nt          j        ||          }|                     ||           |	                    d|          }|S )z
    Given a value of any type, creates a getattr node corresponding to the value and
    registers the value as a buffer to the module.
    Nr   get_attr)
r   r   rU   r(   Tensordetachcloner   register_buffercreate_node)	r   r   r   r   r   r   r   	new_value	attr_nodes	            r-   r    r      s     6f==!!&))I~.v66 eU\**	0\%/// 
 9i000!!*i88Ir.   sourcedestc                 T   t           t          z   }|                    t          j        j        j        j                   |j        |v r]t          |j
        d         t          j        j                  st          d|j
        d                    |j
        d         }|j        |v ]|| k    S )z
    Assuming dest is one of the ops inserted by quant workflow, this function
    finds if source and dest are connected. Assumption is that only quant workflow
    inserted ops exist between source and dest
    r   z=expected arg[0] of quant workflow ops to be a node but found )_QUANTIZE_OPS_DEQUANTIZE_OPSappendr(   opsquantized_decomposedchoose_qparamsr   ry   rU   r   fxr   
ValueError)r   r   quant_workflow_opss      r-   _is_connectedr   7  s     '8ei<KRSSS
++
+
+$)A,66 	^PTPYZ[P\^^   y| ++
+
+ 6>r.   c           	      $   | d S | j         dk    sJ | j                            d          }|}t          |          D ]R\  }}t	          ||          s-t          dd                    |d |                              t          ||          }S|S )Nr   r7   z#Node referenced nonexistent target )opry   r;   	enumeraterY   rW   joinr:   )nodemtarget_atomsattr_itrr   atoms         r-   _get_tensor_constant_from_noder  H  s    |t7j    ;$$S))LH\** + +4x&& 	Rchh|BQB?O6P6PRR   8T**Or.   c                 (   g }t          |          D ]\  }}|j        |v r!|                    ||j                            /|j        s/|t	          |           k     r|                    | |                    e|                    |j                   |S r'   )r   r   r   
kwarg_onlyrx   default_value)	orig_argsorig_kwargsargs_schemaall_argsr   schemas         r-   _get_all_argumentsr  W  s    H{++ 2 2	6;+%%OOK45555" 	2q3y>>'9'9OOIaL))))OOF01111Or.   r   c                     t           j        j        j        j        t           j        j        j        j        t           j        j        j        j        t           j        j        j        j        g}| j        |v S )zU
    Return True if the given node refers to an aten batch norm op QAT supports.
    )	r(   r   aten
batch_normr   _native_batch_norm_legitcudnn_batch_normmiopen_batch_normry   )r   supported_opss     r-   %_is_supported_batch_norm_for_trainingr  c  sP    
 		!)	/7 		'/	(0M ;-''r.   r   c                 b   | j         dk    o| j        t          j        j        j        j        t          j        j        j        j        t          j        j        j        j        t          j        j        j        j        t          j        j        j	        j        t          j        j        j	        j        fv S )z<
    Return whether the node refers to an aten conv op.
    call_function)
r   ry   r(   r   r  conv1dr   paddingconv2dconv3dr   s    r-   r"   r"   s  st     4?" qx	%	%	%	%	%	%4 ( r.   c                 D   | j         dk    o| j        t          j        j        j        t          j        j        j        j        t          j        j        j        t          j        j        j        j        t          j        j        j	        t          j        j        j	        j        fv S )zF
    Return whether the node refers to an aten conv_transpose op.
    r  )
r   ry   r(   r   r  conv_transpose1dr   conv_transpose2dinputconv_transpose3dr  s    r-   r#   r#     sk     4?" qx	'	'/	'	'-	'	'-4 ( r.   c                 >    t          |           pt          |           S )zN
    Return whether the node refers to an aten conv or conv transpose op.
    )r"   r#   r  s    r-   _is_conv_or_conv_transpose_noder$    s      96q999r.   conv_fnc                 L    | t           j        t           j        t           j        fv S r'   )Fr  r   r"  )r%  s    r-   _is_conv_transpose_fnr(    s    q)1+=q?QRRRr.   c                 h    t          |           p#| j        t          j        j        j        j        k    S r'   )r  ry   r(   r   r  $_native_batch_norm_legit_no_trainingr   r  s    r-   _is_bn_noder+    s,    -a00 	S8uy~JRRr.   F	conv_nodeconv_weight_nodeconv_bias_nodebn_noder  	fake_fusec           
      :   t          ||          }t          ||          }t          |           }|j        j        j        }	t          |j        |j        |	          }
t          |
d         |          }t          |
d         |          }t          |
d         |          }t          |
d         |          }|j        t          j	        j
        j        j        k    rd}n't          |          rd}nt          d|j                  |
|         }t          ||||||||          \  }}t!          | j                  }t#          |          dk    r|                    d            |rKt          j                            ||j                  t          j                            ||j                  }}nt          ||||||||          \  }}|j        }t-          |t.                    sJ t1          |||t2          j                   |1|j        }t1          ||t/          |          t2          j                   nr|d	z   }t1          |||t2          j                   |j                            |           5  |j                            |          }d d d            n# 1 swxY w Y   ||d<   t=          |          | _        |j        t          j	        j
        j        j        k    r|                     |            nQ|j!        D ]I}|j"        d
k    s&|j        tF          j$        k    s|j        d         dk    r4|                     |            J|j        %                                 |j&        s4t#          |j!                  dk    r|j        '                    |           d S d S d S )Nrj   rl               zBN node target is unexpected )	transpose_biasr  r   )(r  r#   ry   _schema	argumentsr  r   r   r(   r   r  r*  r   r  r   r   r   rx   r   r   	Parameterrequires_gradrU   rI   r   r   	PARAMETERr   inserting_beforer   r   r  replace_all_uses_withusersr   operatorgetitemeliminate_dead_code_erased
erase_node)r,  r-  r.  r/  r  r0  conv_wconv_br6  bn_args_schemabn_argsbn_wbn_bbn_rmbn_rveps_arg_indexbn_epsfused_weight
fused_bias	conv_argsweight_attr_namebias_attr_nameget_bias_nodeusers                           r-   fold_bn_weights_into_conv_noderV    s    ,,<a@@F+NA>>F'	22I ^+5N w~~NNG)'!*a88D)'!*a88D*71:q99E*71:q99E~LTTT	.w	7	7 J8'.III]#F3ufdDI     L*
 Y^$$I
9~~ 
Hvv';<<Hvv';<< !
 $8FE5&$	$
 $
 $
 j
 (.&,,,,,q"2I4GHHH!'.ZC$7$79LMMMM)G3ZNI4GHHHW%%i00 	= 	=G,,^<<M	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= %	!9%%IN
 ~2::: 	%%i0000 M 	2 	2D?**;("2229Q<1$$&&y1111 G!!!? $s7=11Q66	7#####$ $66s   /JJJc           
      z   t          d | j        j        D                       }|sd S t                      }| j        j        D ]}|j        dk    s=|j        t          j        j        j	        j
        t          j        j        j        j
        fvrK|}|j        d         }t          |          sj|}|j        d         }t          |j                  dk    r|j        d         nd }t          ||||| ||v            |                    |           | j                                         |                                  d S )Nc              3   4   K   | ]}t          |          V  d S r'   )r+  )r   r   s     r-   	<genexpr>z!_fuse_conv_bn_.<locals>.<genexpr>  s(      77AQ777777r.   r  r   rj   rl   )anyr   nodessetr   ry   r(   r   r  r*  r   r  r   r$  rx   rV  addrB  	recompile)r  has_bnfused_convs_weight_nodesr   r/  r,  r-  r.  s           r-   _fuse_conv_bn_ra    sP   7777777F   #uuW] 7 74?""ahIN?GIN%-7
 '
 '
 LO.q11 		$>!,.1)..A.AA.E.E**4&!99	
 	
 	
 	!$$%56666G!!!KKMMMMMr.   c                 8   i }| j         j        D ]}|j                            dd           }dt	          d           f}|rPt          |                                          d         }|d                             d          d         |d         f}|||j        <   |S )Nnn_module_stackrv   r   r   r7   rj   )	r   r[  metagetr   r   r   r;   r   )r   node_name_to_scoper   rc  current_scopebts         r-   _get_node_name_to_scoperi  /  s    68[ 3 3&**%6==T$ZZ( 	:o,,..//3BU[[--b12a59M%216""r.   patternis_cudac                 P   |rt          d |D                       }t          j                            | ||d                                          }|j                                         |                                 |j        j        D ]c}|j        dk    rV|j	        t          j
        j        j        j        k    r2t          |j                  dk    r|j                            |           dt          j                            d          rlt'          |j        j                  D ]R}|j        dk    rE|j        dk    r:|j                            |           t+          |d          rt-          |d           S|j                                         |                                 |S )	zF
    Convert the pattern to an FX graph with decomposed aten ops.
    c                 n    g | ]2}t          |t          j                  r|                                n|3S r   )rU   r(   r   cuda)r   xs     r-   
<listcomp>z6_get_aten_graph_module_for_pattern.<locals>.<listcomp>G  s5    TTTAu|44;QVVXXX!TTTr.   T)strictr  r   z2.9call_module
_guards_fn)r   r(   exportr   r   rB  r^  r[  r   ry   r   r  copy_r   rx   r?  rD  __version__
startswithr   r   rY   delattr)rj  r   rk  r   aten_patternr   s         r-   r!   r!   <  s     
TT^TTT
 
 <&&	 '  
 fhh  **,,, "( 0 0G&&uy~3;;;DJ1$$))$///##E** 8 +122 	8 	8Dw-''DI,E,E"--d333<66 8L,777**,,,r.   match_patternc                    t           j        j        j        j        t           j        j        j        t           j        j        j        j        t           j        j        j        t           j        j        j        j        t           j        j        j        t           j        j        j        j        t           j        j        j        t           j        j        j        j        t           j        j        j        t           j        j        j        j        t           j        j        j        t           j        j        j        j        t           j        j        j        t           j        j        j	        j        t           j        j        j	        t           j        j
        j        j        t           j        j
        j        i	}| j        j        D ])}|j        dk    r|j        |v r||j                 |_        *dS )zRemove .tensor overload for quantize/dequantize ops so that we can
    use the match_pattern that we get from torchdynamo export to match the output of convert_pt2e
    r  N)r(   r   r   quantize_per_tensorr   dequantize_per_tensorr   tensor2quantize_per_channeldequantize_per_channelr  r   r   r   r[  r   ry   )rz  _MAPr   s      r-   "remove_tensor_overload_for_qdq_opsr  n  s-   
 		&:BEIDbDv	&<DeiFdFz	&:A59CaCu	&<CUYEcEy	&:BEIDbDv	&<DeiFdFz	&;CUYEcEx	&=EuyGeG|	#UY^%9
D  & & &4?""8tAH~AH	& &r.   c                     t          | t          t          f          rdS t          | t          t          f          r"t          t          t          |                     S dS )NTF)rU   r   rd   r   r   re   map_is_literal)args    r-   r  r    sP    #U|$$ t#t}%% *3{C(()))5r.   gm	merge_dupexclude_literalsc           	         d}d}i }|g }| j         }|j        d         }| j        j        D ]&}|j        dk    r|}|dz  }| j                            |          5  g }	|j        D ]}
t          |
          r|
|vr|r |
|v r|	                    ||
                    7| j        	                    dt          |          z             }|	                    |           |j                            t                                 |dz  }|r|||
<   |	                    |
           t          |	          }	ddd           n# 1 swxY w Y   |	|_        (|                                 |                                 | S )a  Replace the literals in the graph with placeholder nodes that's created on the fly while we
    traverse the graph, so that the literal arguments in the graph can be matched and replaced

    To use this, the pattern and replacement graph should have the exact same number of literal args
    and they should be used in the exact same order in the pattern and replacement graph.

    If the literal arguments are not used in the same order in pattern and replacement graph, please
    use `_replace_literals_with_existing_placeholders` instead

    Args:
        `gm`: input GraphModule that we'll transform
        `merge_dup`: boolean flag to indicate that if the same literal appears multiple times in
         the graph, whether they should correspond to the same placeholder or not
        `exclude_literals`: a list of literals that will not be replaced with placeholders

    Example:

    # 1. Original Graph
    def pattern(self, x):
        return x + 3

    def replacement(self, x):
        return x - 3

    example_inputs = (torch.randn(1, 3, 3, 3),)
    pattern_gm = _get_aten_graph_module_for_pattern(pattern, example_inputs)
    replacement_gm = _get_aten_graph_module_for_pattern(pattern, example_inptus)

    # 2. Before calling replace literals we'll see the following graph:
    def pattern(self, x):
        return x + 3

    def replacement(self, x):
        return x - 3

    pattern_gm = _replace_literals_with_new_placeholders(pattern_gm)
    replacement_gm = _replace_literals_with_new_placeholders(replacement_gm)

    # 3. After replacing literals with new placeholder nodes

    def pattern(self, x, new_ph):
        return x + new_ph

    def pattern(self, x, new_ph):
        return x - new_ph

    Nr   placeholderrj   r  )_in_specchildren_specsr   r[  r   inserting_afterr   r  r   r  rI   r   r   __post_init__)r  r  r  last_phcntliteral_to_phin_spec	args_specr   new_argsr  ph_nodes               r-   '_replace_literals_with_new_placeholdersr    s   h G
CFHMkG&q)I  7m##G1HCX%%g.. 	' 	'Hy ) )s## )3C(C(C  9SM%9%9 c(:;;;;"$("6"6us3xx7G"H"H 000!077

CCCq$ 918M#.OOC((((XH	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	'" 		 Is   CD??E	E	literal_to_ph_idxc                    |g }|i }d | j         j        D             }| j         j        D ]}|j        dk    rg }|j        D ]x}t	          |t
                    rt          |          }t          |          r.||vr*||v r&||         }||         }|                    |           c|                    |           yt          |          }||_        | S )a	  Replace the literals in the graph with **existing** placeholder nodes, so that the literal arguments
    in the graph can be matched and replaced

    To use this, all literal args in the graph should be unique and each of them should correspond
    to exactly one placeholder node

    # 1. Original Graph
    def pattern(self, x_i8, scale, zero_point, quant_min, quant_max):
        return torch.dequantize_per_tensor(x_i8, scale, zero_point, quant_min, quant_max)

    def replacement(x_i8, scale, zero_point, quant_min, quant_max):
        x_i8 = torch.clamp(x_i8, quant_min, quant_max)
        return ((x_i8.to(torch.float32) - zero_point) * scale).to(dtype=torch.float32)

    example_inputs = (
        torch.randn(1, 3, 3, 3),
        1.0,
        0,
        -128,
        127,
    )
    pattern_gm = _get_aten_graph_module_for_pattern(pattern, example_inputs)
    replacement_gm = _get_aten_graph_module_for_pattern(pattern, example_inptus)

    # 2. Before calling replace literals we'll see the following graph:
    def pattern(self, x_i8, scale, zero_point, quant_min, quant_max):
        # scale/zero_point/quant_min/quant_max are burnt in since they are scalar values
        return torch.dequantize_per_tensor(x_i8, 1.0, 0, -128, 127)

    def replacement(x_i8, scale, zero_point, quant_min, quant_max):
        # scale/zero_point/quant_min/quant_max are burnt in since they are scalar values
        x_i8 = torch.clamp(x_i8, -128, 127)
        return ((x_i8.to(torch.float32) - 0) * 1.0).to(dtype=torch.float32)

    # Note that literal args appear in different order in pattern and replacement graph, so
    # we can't use _replace_literals_with_new_placeholders

    literal_to_ph_idx = {1.0: 1, 0: 2, -128: 3, 127: 4}
    pattern_gm = _replace_literals_with_existing_placeholders(pattern_gm, literal_to_ph_idx)
    replacement_gm = _replace_literals_with_existing_placeholders(replacement_gm, literal_to_ph_idx)

    # 3. After replacing literals with existing placeholder nodes

    def pattern(self, x_i8, scale, zero_point, quant_min, quant_max):
        # scale/zero_point/quant_min/quant_max are burnt in since they are scalar values
        return torch.dequantize_per_tensor(x_i8, scale, zero_point, quant_min, quant_max)

    def replacement(x_i8, scale, zero_point, quant_min, quant_max):
        # scale/zero_point/quant_min/quant_max are burnt in since they are scalar values
        x_i8 = torch.clamp(x_i8, quant_min, quant_max)
        return ((x_i8.to(torch.float32) - zero_point) * scale).to(dtype=torch.float32)
    Nc                 (    g | ]}|j         d k    |S )r  )r   )r   r   s     r-   rp  z@_replace_literals_with_existing_placeholders.<locals>.<listcomp>%  s$    
G
G
GDdg.F.F4.F.F.Fr.   r  )	r   r[  r   r   rU   r   r   r  r   )	r  r  r  phsr   r  r  ph_idxr  s	            r-   ,_replace_literals_with_existing_placeholdersr    s   r  
G
GBHN
G
G
GC  7o%%9 	% 	%C#t$$ !CjjC  	%///,,,*3/f+(((($$$$??		Ir.   c                     dddt           ffd}ddt           ffd}t          j        ||           | _        t          j        ||           | _        | S )z
    Disallow calling `model.train()` or `model.eval()` on the given GraphModule.
    This is useful for exported models, where these methods don't actually behave as expected.
    ap  
        Calling train() or eval() is not supported for exported models.
        Please call `torchao.quantization.pt2e.move_exported_model_to_train(model)` (or eval) instead.

        If you cannot replace the calls to `model.train()` and `model.eval()`, you may override
        the behavior for these methods by calling `torchao.quantization.pt2e.allow_exported_model_train_eval(model)`,
        which does the above automatically for you. Note that this has limited effect on switching
        behavior between train and eval modes, and should be used only for special ops such as dropout
        and batchnorm.
        Tmodec                 "    t                    r'   NotImplementedErrorr   r  error_messages     r-   _trainz$_disallow_eval_train.<locals>._trainO      !-000r.   c                 "    t                    r'   r  r  s     r-   _evalz#_disallow_eval_train.<locals>._evalR  r  r.   )T)booltypes
MethodTypetraineval)r   r  r  r  s      @r-   _disallow_eval_trainr  ?  s    
	M1 14 1 1 1 1 1 11 1$ 1 1 1 1 1 1 "6511EK!%//EJLr.   c                 $   | j         dk    r$| j        t          j        j        j        j        k    pa| j        t          j        j        j        j        k    p=| j        t          j        j        j        k    p| j        t          j        j        j        k    S )Nr  )r   ry   r(   r   r  sym_sizer   	sym_numel)r   s    r-   r$   r$   Z  ss    ?" 	;K59>2::	2;%).2::	2 ;%).22	2 ;%).11r.   c                 L    t          t          d | j                            }|S )Nc                 $    t          |           du S )NF)r$   )ro  s    r-   <lambda>z(_filter_sym_size_users.<locals>.<lambda>e  s    ):1)=)=)F r.   )r   filterr?  )r   
node_userss     r-   r%   r%   d  s%    fGG$*UUVVJr.   r'   )F)FN)NN)f__doc__r8   r@  r  ra   collectionsr   inspectr   r   typingr   r   r   r	   r(   torch.nn.functionalr   
functionalr'  $torch.ao.quantization.fx._decomposedr
   torch.export.unflattenr   r   torch.fxr   r   r   torch.nn.utils.fusionr   torch.nn.utils.parametrizer   torch.utils._pytreer   torchao.utilsr   __all__r   r   rI   r   r   r   r   r  r   r   rN   r   r   r{   r   r   r   dictr   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+  rV  ra  r   ri  r!   r  r  r   r  rd   r  r  r$   r%   r   r.   r-   <module>r     s           # # # # # # - - - - - - - - 1 1 1 1 1 1 1 1 1 1 1 1           J I I I I I : : : : : : : : - - - - - - - - - - 6 6 6 6 6 6 6 6 6 6 6 6 ( ( ( ( ( ( 7 7 7 7 7 7  .W W W  :# :C :C : : : :! ! !&! ! !H      :; ; ;   ;  ;	; 
 ;  38_;  ;  ;  ; |    
(/&+hoc]   0JX JDcN JtCH~ J J J J8 (?    *H 4S> >U    ,# # $    H #4K> K>\K>\K> K> 	K>
 ;K> 
K>  K> ]K> 5<%&K> K> K> K>\
' 
'c 
' 
' 
' 
'6!8?6!,1#s(O6!	#uS#X
6! 6! 6! 6!|# (    , &* HO  	
 U\" 
   6 
I"6>	I"6=	I"7? 
I"8@	I"8?	I"9A%(- ux}     "  	 	 	( ( ( ( ( T    t    :t : : : :S8 S S S S4     i$ i$i$i$ TNi$ 	i$
 i$ i$ 
i$ i$ i$ i$Zk d    B
; 
4U39=M8M3N 
 
 
 
  / //#s(O/ /
 / / / /d&k &d & & & &,   ,0W WWW tCy)W W W Wx -1SWT TTtCy)T  U5#tU[+H%I3%N OPT T T Tr    6D     43F      r.   