U
    ,-em                     @   s  U 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 d dl	m
Z
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 d dlmZmZ d dlmZ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l0m1Z1 d dl2Z2d dl3Z3dddddddddddddd d!d"d#d$d%d&d'd(gZ4ejj5j6ejj5j7ejj5j8hZ9e/G d)d( d(Z:ee)e;d*d+d$Z<ee)e;d*d,d#Z=e(ee(e-e-f f e'e) d-d.dZ>d/d Z?e%e%d0d1dZ@eAe%d2d3dZBee&e'e  d4d5dZCee'e ed6d7d ZDejjEe)d8d9dZFejjEeeAe)ed:d;dZGee(eAejjEf e(ee;f e;d<d=dZHee'eI d4d>dZJe'eI e%ege'eI f d?d@d'ZKe1d"dAZLeLdBdCej;eKdgeMeKdDgieLdBdEeIeJieLdBdFeIeJieLdBdGeIeJieLdBdHeIeKdgieLdBdIeIeJieLdBejNeIeJieLdBdJeIeKdgieLdBdKeIeKdgieLdBejOeIeKdgieLdBdLeIeJiiZPe(eLe(e,eQejRf e%ege'eI f f f eSd%< i ZTe(e,eQejRf e%ege'eI f f eSd< ee(e,eQejRf e%ege'eI f f d4dMdZUdoee(eAejEf e&e-ejE  e)e&e dNdOd!ZVee+e)dPf eedQdRdZWe!e;e+e'eA e'e-e)  f dSdTdZXdpee(eAejjEf ee&e) e;dUdVdWZYdqee(eAejjEf ee&e) e;dUdXdYZZee(eAejjEf e&ejjE dZd[d\Z[eejjEe(eAejjEf eed]d^d_Z\eejjEe(eAejjEf eed]d`daZ]ee(eAejjEf e&e dbdcddZ^ededfdgZ_e,ee
f edhdidjZ`dreee;e;dldmdnZadS )s    N)
QConfigAny	QuantType)DTypeWithConstraints)FakeQuantizeBaseFixedQParamsFakeQuantize)FixedQParamsObserverObserverBase)float16_static_qconfigfloat16_dynamic_qconfigqconfig_equals)DeQuantStub)"activation_is_statically_quantized)_is_activation_post_process)QConfigMapping)GraphModulemap_arg)GraphNode   )PrepareCustomConfig)quantized_decomposed_lib)	CallableOptionalListDictAnySetTupleUnionType)	dataclass)
namedtupleall_node_args_except_firstall_node_args_have_no_tensorsassert_and_get_unique_devicecollect_producer_nodescreate_getattr_from_value'create_node_from_old_node_preserve_metaEMPTY_ARG_DICTget_custom_module_class_keysget_linear_prepack_op_for_dtypeget_new_attr_name_with_prefix(get_non_observable_arg_indexes_and_typesget_qconv_prepack_op#get_skipped_module_name_and_classes graph_module_from_producer_nodesmaybe_get_next_moduleNodeInfonode_arg_is_biasnode_arg_is_weightNON_OBSERVABLE_ARG_DICTNON_QUANTIZABLE_WEIGHT_OPSreturn_arg_listObservedGraphModuleAttrsc                   @   s   e Zd ZU eeef ed< eeeeef f ed< e	ed< eee
f ed< eed< eed< ee ed< dZeed	< d
Zeee  ed< d
Zeee  ed< d
S )r7   Znode_name_to_qconfigZnode_name_to_scopeprepare_custom_configZ!equalization_node_name_to_qconfigZqconfig_mappingZis_qatZobserved_node_namesFis_observed_standalone_moduleN&standalone_module_input_quantized_idxs'standalone_module_output_quantized_idxs)__name__
__module____qualname__r   strr   __annotations__r   typer   r   r   boolr   r9   r:   r   r   intr;    rD   rD   _/var/www/html/Darija-Ai-Train/env/lib/python3.8/site-packages/torch/ao/quantization/fx/utils.pyr7   K   s   
)nodeargreturnc                 C   sX   d}d| j kr | j d dd}|dk	rH|t| jk rH| j| |krHdS | jd|kS )zReturns if node arg is weightNtarget_dtype_infoweight_indexTweightmetagetlenargskwargs)rF   rG   rJ   rD   rD   rE   r3   X   s    
$c                 C   sX   d}d| j kr | j d dd}|dk	rH|t| jk rH| j| |krHdS | jd|kS )zReturns if node arg is biasNrI   
bias_indexTZbiasrL   )rF   rG   rR   rD   rD   rE   r2   a   s    
$)custom_module_mappingrH   c                 C   sD   t  }tjtjtjfD ]$}| |i }t | }||O }qt|S )a   Get all the unique custom module keys in the custom config dict
    e.g.
    Input:
    {
        QuantType.STATIC: {
            CustomModule1: ObservedCustomModule
        },
        QuantType.DYNAMIC: {
            CustomModule2: DynamicObservedCustomModule
        },
        QuantType.WEIGHT_ONLY: {
            CustomModule3: WeightOnlyObservedCustomModule
        },
    }

    Output:
    # extract the keys across all inner STATIC, DYNAMIC, and WEIGHT_ONLY dicts
    [CustomModule1, CustomModule2, CustomModule3]
    )setr   ZSTATICZDYNAMICZWEIGHT_ONLYrN   keyslist)rS   Zfloat_custom_module_classesZ
quant_modeZquant_mode_custom_module_configZ quant_mode_custom_module_classesrD   rD   rE   r)   j   s    
c                 C   s6   | t jkrt jjjS | t jkr(t jjjS td| d S )Nz&can't get linear prepack op for dtype:)torchZfloat16ops	quantizedZlinear_prepack_fp16Zqint8Zlinear_prepack	Exception)dtyperD   rD   rE   r*      s
    



)conv_oprH   c                 C   s   t jjjt jjjt jjjt jjjt jjj	t jjj
t jjjt jjjt jjjt jjjt jjjt jjji}|| d }|std|  |S )NzDidn't find prepack op for )rW   nn
functionalZconv1drX   rY   Zconv1d_prepackZconv2dZconv2d_prepackZconv3dZconv3d_prepackZconv_transpose1dZconv_transpose1d_prepackZconv_transpose2dZconv_transpose2d_prepackZconv_transpose3dZconv_transpose3d_prepackrN   AssertionError)r\   Zprepack_opsZ
prepack_oprD   rD   rE   r-      s           )prefixrH   c                    s&     dd tjjd fdd}|S )N._)modulec                    s>   t d fdd}d}||}t| |r:|d7 }||}q|S )Nic                    s    t |  S N)r?   rd   r`   rD   rE   get_attr_name   s    zOget_new_attr_name_with_prefix.<locals>.get_new_attr_name.<locals>.get_attr_namer   r   )rC   hasattr)rc   rh   re   	attr_namerg   rD   rE   get_new_attr_name   s    

z8get_new_attr_name_with_prefix.<locals>.get_new_attr_name)replacerW   r]   Module)r`   rk   rD   rg   rE   r+      s    	rF   rH   c                 C   s   | g}| g}|r|  } t| jt| j  }|D ]H}t|tsDq4|jdkrT dS || |jdkrr|j	t
ks4|| q4q|S )a   Starting from a target node, trace back until we hit inpu or
    getattr node. This is used to extract the chain of operators
    starting from getattr to the target node, for example
    def forward(self, x):
      observed = self.observer(self.weight)
      return F.linear(x, observed)
    collect_producer_nodes(observed) will either return a list of nodes that
    produces the observed node or None if we can't extract a self contained
    graph without free variables(inputs of the forward function).
    placeholderNcall_function)poprV   rP   rQ   values
isinstancer   opappendtargetgetattr)rF   nodesZfrontierZall_argsrG   rD   rD   rE   r%      s    


)rootproducer_nodesrH   c                    sl   t |dkstd|  t }i   fdd}|D ]}||| |< q6|||d  t| |}|S )a-   Construct a graph module from extracted producer nodes
    from `collect_producer_nodes` function
    Args:
      root: the root module for the original graph
      producer_nodes: a list of nodes we use to construct the graph
    Return:
      A graph module constructed from the producer nodes
    r   z'list of producer nodes can not be emptyc                    s   t |  fddS )Nc                    s    |  S rf   rD   rF   envrD   rE   <lambda>       zDgraph_module_from_producer_nodes.<locals>.load_arg.<locals>.<lambda>)r   ar|   rD   rE   load_arg   s    z2graph_module_from_producer_nodes.<locals>.load_arg)rO   r_   reverser   Z	node_copyoutputr   )ry   rz   graphr   Zproducer_nodeZgraph_modulerD   r|   rE   r/      s    

)rc   rH   c                 C   s^   dd |   D dd |  D B }t|dks>td| t|dkrVtt|nd}|S )z
    Returns the unique device for a module, or None if no device is found.
    Throws an error if multiple devices are detected.
    c                 S   s   h | ]
}|j qS rD   device.0prD   rD   rE   	<setcomp>   s     z/assert_and_get_unique_device.<locals>.<setcomp>c                 S   s   h | ]
}|j qS rD   r   r   rD   rD   rE   r      s     r   zKprepare only works with cpu or single-device CUDA modules, but got devices r   N)
parametersbuffersrO   r_   nextiter)rc   Zdevicesr   rD   rD   rE   r$      s    )rc   r   r`   valuerH   c           	      C   sZ   t |}|| }t| }t|tjr0|  ntj||d}| || |	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.
    r   get_attr)
r+   r$   rs   rW   ZTensorclonedetachZtensorZregister_buffercreate_node)	rc   r   r`   r   rk   rj   r   	new_valueZ	attr_noderD   rD   rE   r&      s    )rF   modulescacherH   c           	      C   s  |r| |kr||  S d}t | ts*d}n| jdkr<d}n| jdkrzt | jtsVtt|| j rvt| jd ||}nb| jdkrd}nP| jdkr| jt	j
krt| jd ||}n$| jdkrd}n| jtkr| jd d	krd}n| jd
kr| jdkrd}nd}| jD ]}t |trx|D ]P}t |tr$t|||}|pJ| }|r$| }|rf||| < |    S q$nZt |trnLt |trt|||}|p| }|r| }|r||| < |  S nd}| }q|r||| < |S )z
    If we know for sure that all of this node's args have no
    tensors (are primitives), return True.  If we either
    find a tensor or are not sure, return False. Note: this
    function is not exact.
    FTro   call_moduler   rp   r   r   )ndimshapecall_methodsize)rs   r   rt   rv   r?   r_   r   r#   rP   operatorgetitemrw   rV   rC   )	rF   r   r   resultZfound_one_tensorrG   Zlist_elZ!this_list_el_args_have_no_tensorsZthis_arg_args_have_no_tensorsrD   rD   rE   r#      sj    








c                 C   s   t tdt| jS )z2
    Returns all node arg indices after first
    r   )rV   rangerO   rP   r{   rD   rD   rE   r"   I  s    )arg_indicesrH   c                    s   t tt d fdd}|S )zu
    Constructs a function that takes a node as arg and returns the arg_indices
    that are valid for node.args
    rn   c                    s    fddD S )Nc                    s   g | ]}|t  jk r|qS rD   )rO   rP   )r   re   r{   rD   rE   
<listcomp>U  s      z=return_arg_list.<locals>.arg_indices_func.<locals>.<listcomp>rD   r{   r   r{   rE   arg_indices_funcT  s    z)return_arg_list.<locals>.arg_indices_func)r   r   rC   )r   r   rD   r   rE   r6   O  s    z	op targetr   Zmasked_fill   ZpermuterepeatZreshaper   	transpose	unsqueezeZ
unsqueeze_viewc                 C   s   t | j| j}t|tS )z
    Returns a dict with of non float tensor types as keys and values which correspond to a
    function to retrieve the list (which takes the node as an argument)
    )r1   rt   rv   r4   rN   r(   )rF   inforD   rD   rE   r,     s    )rF   r   target_module_typetarget_functional_typerH   c                 C   sf   | j  D ]V}|jdkr<|dk	r<t|t|j |r<|  S |jdkr
|dk	r
|j|kr
|  S q
dS )a%   Gets the next module that matches what is needed in
    is_target_module_type if it exists

    Args:
        node: The node whose users we want to look at
        target_module_type: Module type that we want to check
        target_functional_type: Functional type that we want to check
    r   Nrp   )usersrU   rt   rs   r?   rv   )rF   r   r   r   userrD   rD   rE   r0     s    
.)quantized_graphcreate_node_argsold_noderH   c                 C   s   | j | }|j|_|S )zU
    Creates `new_node` and copies the necessary metadata to it from `old_node`.
    )r   Zstack_trace)r   r   r   new_noderD   rD   rE   r'     s    
)r8   is_standalone_modulerH   c                 C   sV   t  | j}t  | j}|sN|t| j 7 }|t| j 7 }|t| j7 }||fS rf   )	copyZnon_traceable_module_namesZnon_traceable_module_classesrV   Zstandalone_module_namesrU   Zstandalone_module_classesr)   Zfloat_to_observed_mapping)r8   r   Zskipped_module_namesZskipped_module_classesrD   rD   rE   r.     s    )rF   named_modulesqconfigqhandlerrH   c                 C   sf   t | |}|dk	rP|dk	rPt|tjjjjjs2tt|tj	j
oNt|oN| S t|tjj	jj
S dS )zD
    Return whether this refers to the custom module LSTM flow.
    N)_get_modulers   rW   aoquantizationfxquantize_handlerQuantizeHandlerr_   r]   ZLSTMr   is_custom_modulequantizablerF   r   r   r   modrD   rD   rE   _is_custom_module_lstm  s    

r   c                 C   sf   t | |}|dk	rP|dk	rPt|tjjjjjs2tt|tj	j
oNt|oN| S t|tjj	jj
S dS )zR
    Return whether this refers to the custom module MultiheadAttention flow.
    N)r   rs   rW   r   r   r   r   r   r_   r]   ZMultiheadAttentionr   r   r   r   rD   rD   rE   _is_custom_module_mha  s    

r   )rF   r   rH   c                 C   s.   | j dkr&t| j|kr&|t| j S dS dS )zO
    If `node` refers to a call_module node, return the module, else None.
    r   N)rt   r?   rv   )rF   r   rD   rD   rE   r     s    r   )rF   modelr   r   rH   c              
   C   s^   d}t |}||}t }t||| |||< ||  ||| fW  5 Q R  S Q R X dS )z
    Attach a `DeQuantStub` to the model and create a node that calls this
    `DeQuantStub` on the output of `node`, similar to how observers are inserted.
    Zdequant_stub_N)r+   r   setattrinserting_afterr   )rF   r   r   r   r`   Zget_new_dequant_stub_nameZdequant_stub_nameZdequant_stubrD   rD   rE   _insert_dequant_stub  s    
r   c              	   C   s\  | | & |tj| df}t||||}W 5 Q R X | | |tj| df}W 5 Q R X | |& |tj|df}t||||}W 5 Q R X | |& |tj|df}	t|	|||}
W 5 Q R X | |
 |t||
gf}W 5 Q R X | | |t||gf}W 5 Q R X t| j D ]&}||kr(||kr(|	| | q(t
| |S )a8  
    Insert DeQuantStubs after each internal output node of custom module LSTM.

    Custom module LSTM outputs are nested tuples of the structure (output, (hidden0, hidden1)),
    Since we cannot dequantize a tuple as a whole, we must first break down the tuple into its
    components through `getitem`. This function transforms the graph as follows:

      (1) Split the LSTM node into (output, (hidden0, hidden1))
      (2) Insert a DeQuantStub after each internal node
      (3) Recombine the DeQuantStubs into the same structure as before
      (4) Reroute all consumers of the original LSTM node and its sub-nodes
          (e.g. lstm[0])

    Before:
                   lstm_output
                        |
                        v
                  original_user(s)
    After:
                   lstm_output
                  /           \
                 /  (getitem)  \
                /               \
               v                 v
             output            hidden
               |               /   \
         (DeQuantStub)        (getitem)
               |             /       \
               v            v         v
           output_dq     hidden0    hidden1
               |            |         |
               |    (DeQuantStub) (DeQuantStub)
               |            |         |
               |            v         v
               |      hidden0_dq  hidden1_dq
               |            \       /
               |              (tuple)
               |              \   /
               |               v  v
               |             hidden_dq
               \               /
                \   (tuple)   /
                 v            v
                 lstm_output_dq
                       |
                       v
                original_user(s)

    For step (4), reroute all users of the original LSTM node(s) as follows:
      lstm_output -> lstm_output_dq
      lstm_output[0] -> output_dq
      lstm_output[1] -> hidden_dq
      lstm_output[1][0] -> hidden0_dq
      lstm_output[1][1] -> hidden1_dq

    Return the node `lstm_output_dq`.
    r   r   )r   rp   r   r   r   tuplerV   r   rU   replace_input_with_reroute_tuple_getitem_pattern)rF   r   r   r   r   Z	output_dqZhiddenZhidden0Z
hidden0_dqZhidden1Z
hidden1_dqZ	hidden_dqZlstm_output_dqr   rD   rD   rE   3_insert_dequant_stubs_for_custom_module_lstm_output  s(    Ar   )rG   r   rH   c           	         s   fdd}fdd}dd }dd t t tt d	 fd
d}|||g||||g||||g|||gg}|D ]}||}|dk	rv|  S qvdS )aC  
    Given an argument of a node, if the argument refers to the path through which the node
    is a consumer of custom module LSTM, return the custom module LSTM node, or None otherwise.

    This is used to determine whether a node is a consumer of custom module LSTM, and, if so,
    skip inserting input observers for this node. This is because custom module LSTM produces
    quantized outputs, so inserting an input observer for the consumer of custom module LSTM
    would unnecessarily quantize the outputs again.

      lstm -> consumer

    In practice, however, custom module LSTM outputs a tuple (output, (hidden0, hidden1)) with
    DeQuantStubs attached to each internal node (see `_insert_dequant_stubs_for_custom_module_lstm_output`).
    This tuple can be consumed in one of four ways:

      lstm -> getitem -> DeQuantStub -> consumer                       # consume lstm[0]
      lstm -> getitem -> getitem -> DeQuantStub -> tuple -> consumer   # consume lstm[1]
      lstm -> getitem -> getitem -> DeQuantStub -> consumer            # consume lstm[1][0] or lstm[1][1]
      lstm -> getitem -> DeQuantStub -> tuple -> consumer              # consume lstm

    Thus, we must match against the above patterns instead of simply checking the parent node
    to determine whether this node is a consumer of a custom module LSTM.
    c                    s   t t|  tS rf   )rs   r   r   r   r   rD   rE   match_dq{  s    z=_maybe_get_custom_module_lstm_from_node_arg.<locals>.match_dqc                    s
   t |  S rf   )r   r   r   rD   rE   
match_lstm~  s    z?_maybe_get_custom_module_lstm_from_node_arg.<locals>.match_lstmc                 S   s   | j dko| jtjkS Nrp   )rt   rv   r   r   r   rD   rD   rE   match_getitem  s    zB_maybe_get_custom_module_lstm_from_node_arg.<locals>.match_getitemc                 S   s   | j dko| jtkS r   )rt   rv   r   r   rD   rD   rE   match_tuple  s    z@_maybe_get_custom_module_lstm_from_node_arg.<locals>.match_tuple)match_patternrH   c                    sZ    }t | D ]H\}}||s" dS |t| d k r|krJ|jd d }q|jd }q|S )z
        Traverse up the graph and match the args one by one.
        If there is a match, return the last matched node, or None otherwise.
        Nr   r   )	enumeraterO   rP   )r   r   re   match)rG   r   rD   rE   _match_pattern  s    zC_maybe_get_custom_module_lstm_from_node_arg.<locals>._match_patternN)r   r   r   r   )	rG   r   r   r   r   r   Zall_match_patternsr   Zmatched_noderD   )rG   r   r   rE   +_maybe_get_custom_module_lstm_from_node_arg`  s    


r   )r   c           
   
      s   t tt tt  ttt   ttt ttdf f  d fdd g }t }| jD ]} |g g || qN|D ]~}|d }|d }|jdkr|jt	kst
|jdkr|jtjkst
|jd }|jd | }t|j D ]}	|	|| qqhd	S )
a  
    Search for patterns where N consecutive `tuple` call_function nodes are followed by
    N consecutive `getitem` call_function nodes that are "reverses" of the `tuple` nodes.
    If we find this pattern, reroute the consumers of the last `getitem` to skip these
    N `tuple` and `getitem` nodes.

    Before:

        a   b     c
        |   \   /
        \   tuple
         \   /
          tuple
            |
        getitem(1)
            |
        getitem(0)
            |
            d

    After:

        b
        |
        d
    .)rF   index_stackcurrent_patternmatched_patternsseenc           	         s  t |dkr0t |dkr0|t| |  | t|f}||krHdS || | jD ]}|jdkr|jtkrt	|j
d D ]4\}}|| kr~|| ||  ||||| q~qX|jdkrX|jtjkrXt |dkrX|j
d |d krX|  ||  ||||| qX|S )aP  
        Traverse the graph recursively to match for the N-tuple - N-getitem patterns,
        starting at the given node.

        We use a stack to keep track of the expected `getitem` indices, since these are
        reversed from the `tuple` indices. In the above example, the stack after
        (b -> tuple -> tuple) will be [0, 1], which will be popped by getitem(1) first
        and then by getitem(0).

        TODO: traverse upwards from the output and handle the case when tuple is not a
        separate node, e.g. graph.call_function(operator.getitem, args=(a, (b, c)))
        r   Nrp   r   r   )rO   ru   r   clearr   addr   rt   rv   r   rP   r   r   rq   )	rF   r   r   r   r   stater   re   Zuser_argfind_patternsrD   rE   r     s*    




z5_reroute_tuple_getitem_pattern.<locals>.find_patternsr   r   rp   r   N)r   r   rC   r   r   rT   rx   rt   rv   r   r_   r   r   rP   rV   r   rU   r   )
r   r   r   rF   patternZfirst_tupleZlast_getitemZlast_getitem_indexZ	new_inputr   rD   r   rE   r     s&    
-

r   )activation_post_processrH   c                 C   s&   t | tr| S t | tst| jS dS )z
    If `activation_post_process` is an observer, return the observer.
    If `activation_post_process` is a fake quantize, return the internal observer.
    N)rs   r   r   r_   r   )r   rD   rD   rE   *_get_observer_from_activation_post_process  s    
r   T)r   dtype_with_constraintsis_activationrH   c                    s   t ttf tttd fdd} dks2|jdkr6dS |r@ jn j}|rNdnd}d}|dk	r| }t	|spt
|j|jkrdS ||||}|S )a  
    Return whether `qconfig` satisfies the following constraints from the backend,
    specified through the activation and weight DTypeWithConstraints.

        1. QConfig specified a quantization range that falls within the backend's, if any
        2. QConfig specified a min scale value that is >= the backend's, if any
        3. QConfig specified a FixedQParamsObserver or FixedQParamsFakeQuantize that has
           scale and zero point that match the backend's, if any

    If `is_activation` is True, we check `qconfig.activation`, else we check `qconfig.weight`.
    If `qconfig` or `dtype_with_constraints.dtype` is None, or the dtypes do not match, return True.
    )r   r   debug_stringrH   c                    s  t | }t|dd }t|dd }t|dd }|j}|j}|j}	|j}
|j}|d k	r|d k	r|d ksj|d krtd| d   dS ||k s||krtd| d| d| d	| d| d
   dS |	d k	r"|d krtd| d   dS ||	k r"td| d| d|	 d
   dS |
d k	r|d k	rt	t
fD ]}t |r> dS q>d}t| tst| tstd  d|  dS |j|
ks|j|krtd|j d|j d|
 d| d
  d|  dS dS )NZ	quant_minZ	quant_maxZepszQConfig z4 must specify 'quant_min' and 'quant_max', ignoring FzE quantization range must fall within the backend's:
QConfig range = (z, z), BackendConfig range = (z), ignoring z must specify 'eps', ignoring z eps (zB) must be greater than or equal to the backend's min scale value (TzPlease use torch.ao.quantization.get_default_qconfig_mapping or torch.ao.quantization.get_default_qat_qconfig_mapping. Example:
    qconfig_mapping = get_default_qconfig_mapping("fbgemm")
    model = prepare_fx(model, qconfig_mapping, example_inputs)zjQConfig must specify a FixedQParamsObserver or a FixedQParamsFakeQuantize for fixed qparams ops, ignoring z.
zQConfig fixed scale (z) and zero point (z) do not match the backend's (z and )r   rw   Zquant_min_lower_boundZquant_max_upper_boundZscale_min_lower_boundZscale_exact_matchZzero_point_exact_matchwarningswarnr	   r
   r   rs   r   r   scaleZ
zero_point)r   r   r   ZobserverZapp_quant_minZapp_quant_maxZapp_scale_minZbackend_quant_minZbackend_quant_maxZbackend_scale_minZbackend_scale_exact_matchZbackend_zero_point_exact_matchZaccepted_qconfigZsuggestion_strr   rD   rE   ;_activation_post_process_satisfies_dtype_config_constraints  s\    &


*zp_qconfig_satisfies_dtype_config_constraints.<locals>._activation_post_process_satisfies_dtype_config_constraintsNT
activationrK   )r   r   r   r   r?   rB   r[   r   rK   r   r_   )r   r   r   r   Zactivation_post_process_ctrr   Zsatisfies_constraintsr   rD   r   rE   +_qconfig_satisfies_dtype_config_constraints  s*    
 D  r   )NN)NN)NN)T)br   rW   Ztorch.nnr]   Ztorch.ao.quantizationr   r   Z$torch.ao.quantization.backend_configr   Z#torch.ao.quantization.fake_quantizer   r   Ztorch.ao.quantization.observerr   r   Ztorch.ao.quantization.qconfigr	   r
   r   Ztorch.ao.quantization.stubsr   Ztorch.ao.quantization.utilsr   r   Z%torch.ao.quantization.qconfig_mappingr   Ztorch.fxr   r   Ztorch.fx.graphr   r   Zcustom_configr   Z_decomposedr   typingr   r   r   r   r   r   r   r   r   dataclassesr    collectionsr!   r   r   __all__r^   Z
layer_normZ
group_normZinstance_normr5   r7   rB   r3   r2   r)   r*   r-   r?   r+   r%   r/   rm   r$   r&   r#   rC   r"   r6   r1   floatr   r   r4   rA   r[   r@   r(   r,   r0   r'   r.   r   r   r   r   r   r   r   r   r   rD   rD   rD   rE   <module>   sb   ,		$  (K"	
       
   
  4%,0  
     &
_EZ
  