
    קgS                     
   d dl mZmZmZmZmZ d dlZd dlmZ d dl	m
Z
mZmZmZ d dlmZ d dlmZmZmZmZ d dl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gZ!dedeeef         defdZ"dededeeef         ddfdZ#dededeeef         fdZ$dedeeef         deeef         defdZ%dedefdZ&dedefdZ'dej(        j        deeef         fdZ)d Z*deeef         deee+f         fdZ,deee+f         deeef         d e-deeef         fd!Z.d"eeef         d#e d$edej/        j0        d%ee1ej/        j0        f         d&eeef         d e-de fd'Z2d"ed$edej/        j0        d%ee1ej/        j0        f         d&eeef         d e-ddfd(Z3d"edej/        j0        d%ee1ej/        j0        f         d)ed&eeef         d e-dee         fd*Z4d"edej(        j        d&eeef         d e-fd+Z5ded,ee1ee1e6f         f         d e-defd-Z7dS ).    )AnyDictOptionalTupleUnionN)
FakeTensor)
CUSTOM_KEYNUMERIC_DEBUG_HANDLE_KEYObserverOrFakeQuantizeQConfigMapping)PrepareCustomConfig)_create_obs_or_fq_from_qspec_insert_obs_or_fq _is_activation_post_process_node_save_state)
QConfigAny)
EdgeOrNodeQuantizationSpecBaseSharedQuantizationSpec)GraphGraphModuleNode)Argumentprepareedge_or_nodeshared_with_mapreturnc                 P    ||          }|| k    r| S t          ||          }||| <   |S )zFind the root node for the sharing tree
    Args:
        edge_or_node: edge/node that we want to find the root
        shared_with_map: each edge/node points to the parent, the root node will points to itself

    Returns:
        root edge/node
    _find_root_edge_or_node)r   r   parentroots       ^/var/www/html/ai-engine/env/lib/python3.11/site-packages/torch/ao/quantization/pt2e/prepare.pyr    r    #   s=     \*F"6?;;D$(OL!K    r!   childc                 P    t          | |          }t          ||          }|||<   dS )zHMerge the subtree for `child` with `parent`, the order is important hereNr   )r!   r%   r   root_parent
root_childs        r#   _unionr)   7   s2     *&/BBK(@@J"-OJr$   qspecc                 d    t          |t                    r|j        }t          || |           dS dS )a  Update the `shared_with_map` based on the qspec, this applies the `SharedQuantizationSpec`
    configuration and established the relationship between `edge_or_node` with the edge/node that it
    is pointing to, we'll use this information in the end to get the group id
    N)
isinstancer   r   r)   )r%   r*   r   r!   s       r#   _update_shared_withr-   C   sC     %/00 /# 	vuo.....	/ /r$   edge_or_node_to_qspecc                     t          | t                    r0| j        }t          ||          }||         } t	          | ||          S | S )a  Unwraps qspec to get the final root qspec (non SharedQuantizationSpec)
    if qspec is SharedQuantizationSpec
       (1). tries to find the root edge or node for the node that the qspec points to
       (2). recursively find the root qspec based on the qspec for the root node
    )r,   r   r   r    _unwrap_shared_qspec)r*   r.   r   sharing_withr"   s        r#   r0   r0   S   sQ     %/00 S)&|_EE%d+#E+@/RRRLr$   qspec_aqspec_bc                 b    t          | d          ot          |d          o| j        |j        k    S )Ndtype)hasattrr5   r2   r3   s     r#   _has_same_dtyper8   e   s7    !! 	+GW%%	+MW]*r$   c                 b    t          | d          ot          |d          o| j        |j        k    S )N
is_dynamic)r6   r:   r7   s     r#   _has_same_is_dynamicr;   m   s9    && 	5G\**	5'"44r$   modelc                     i }| j         j        D ]e}t          |d          rSd|j        v rJ|j        d         }|j                                        D ]\  }}||f}|||<   |j        |}|j        }|||<   f|S )zPGet a map from EdgeOrNode to quantization spec based on annotations on the nodesmetaquantization_annotation)graphnodesr6   r>   input_qspec_mapitemsoutput_qspec)r<   r.   nqa
input_to_nr*   
input_edgeoutput_nodes           r#   _get_edge_or_node_to_qspecrJ   u   s     EG[ 	; 	;1f 	;";qv"E"E12B%'%7%=%=%?%? : :!
E(!_
49%j11*5:%k2  r$   c                     d}||v r||         }t          |||          }|3t          ||          r%t          ||          rt          || |           dS dS dS dS )zUnion input edge with another edge or node, used in implicit sharing to point the current input
    edge to other user edges of the producer node, or the output of producer node since these are
    referring to the same Tensor
    N)r0   r8   r;   r)   )rH   input_edge_root_qspecr   r.   r   
root_qspecr*   s          r#   _union_input_edge_withrN      s     J,,,%l3)%1FXX
 	J(=>> 	 -BCC 	 	|Z99999 	r$   c           	         d |                                  D             }|                                 D ]\  }}t          |t          j        j                  r|}t          |||           9|}t          || |          }t          |t                    sJ |\  }}|j	        d         j
        rwt          |t
                    rt          |t
                    st          d||f           |j        D ]}	|	|u r||	f}
t          |||
| |           t          |||| |           t          |||           d}i }|                                 D ]+}t          ||          }||vr
|||<   |dz  }||         ||<   ,|S )a  Map from edge/node to the group ID, generated from quantization annotations,
    edge/node with the same group ID should use the same observer/fake_quant instance

    This is applying SharedQuantizationSpec configuration and map each edge/node to a group
    There is another implicit sharing that's built in the quantization, when we have the following:
       * op1 -> op2
       * output of op1: int8_qspec
       * (op1 -> op2) input edge: int8_qspec
    we'll assume sharing between the output of op1 and input of (op1 -> op2) since these are the same Tensor.

    Figuring out the correct group ID for all edge/node is a standard union find problem:
    https://www.geeksforgeeks.org/introduction-to-disjoint-set-data-structure-or-union-find-algorithm/

    Args:
        edge_or_node_to_qspec: Dictionary from edge_or_node to the qspec, derived from annotations
    Returns:
        edge_or_node_to_group_id: Dictionary from edge_or_node to group_id (int), all edge or node that
        belongs to the same group should have the same id

    Example:
        op2 -> cat1 -> cat2
           op1 /        /
                     op3
        edge_or_node_to_qspec: {
            op1: int8_qspec,
            op2: int8_qspec,
            (op1, cat1): int8_qspc,
            (op2, cat1): SharedQuantizationSpec((op1, cat1)),
            cat1: SharedQuantizationSpec((op1, cat1)),
            (op3, cat2): int8_qspec,
            (cat1, cat2): SharedQuantizationSpec((op3, cat2)),
            cat2: SharedQuantizationSpec((op3, cat2)),
        }

        edge_or_node_to_group_id = _get_edge_or_node_to_group_id(edge_or_node_to_qspec)
        edge_or_node_to_group_id: {
            op1: 1,
            op2: 1,
            (op1, cat1): 1,
            (op2, cat1): 1,
            cat1: 1,
            (op3, cat2): 1,
            (cat1, cat2): 1,
            cat2: 1,
        }
        # everything are in the same group because (cat1) and (cat1, cat2) are implicitly shared, which
        # connects the two sharing group around cat1 and cat2 op due to transitive sharing
    c                     i | ]}||S  rQ   ).0ks     r#   
<dictcomp>z1_get_edge_or_node_to_group_id.<locals>.<dictcomp>   s'     5 5 515 5 5r$   r?   z=Expected input_edge to have type Tuple[Node, Node], but got: r      )keysrC   r,   torchfxr   r-   r0   tupler>   allow_implicit_sharing	ExceptionusersrN   r    )r.   r   r   r*   rI   rH   rL   argrE   userarg_to_user_edgecur_group_idedge_or_node_to_group_idr"   s                 r#   _get_edge_or_node_to_group_idrb      s   j5 5+00225 5 5O  5::<< 7D 7DelEHM22 6	D&KUODDDD%J$8,o% %! j%00000FCv/0G )$ "#t,, Jq$4G4G #`X[]^W_``    I 
 
Dqyy (+T{$*"-(-'    '))#    
E?CCCC L68',,.. P P&|_EE///-9$T*AL1I$1O ..##r$   ra   is_qatc                     i }i }|                                 D ]0\  }}| |         }||vrt          |||          ||<   ||         ||<   1|S )zGenerates the EdgeOrNode to observer/fake_quant instances
    Makes sure that for EdgeOrNode that has the same group_id should have the same observer or fake quant
    instances
    )rC   r   )ra   r.   rc   obs_or_fq_mapgroup_id_to_obs_or_fqr   r*   group_ids           r#   _get_obs_or_fq_maprh   !  s     ?AM?A4::<< F Fe+L9000 /K}f/ /!(+ '<H&El##r$   noder]   qconfignamed_modulesre   c           
      |   t          |t          t          f          rIg }|D ],}t          | ||||||          }	|                    |	           - t          |          |          S t          |t                    s|S t          |t                    sJ |}
|}t          ||          r|j        d         }t          ||          t          |t                    sJ dt          |                       || f}||vr|
S ||         }||
S |	                    |d          }|"t          |          t          |          k    r|
S d}|j                                        D ]D}t          ||          s||j                 }t          |          t          |          k    r|c S Et          |||||j                  }
|
S )zk
    Given a `node` and an `arg`, inserts an input observer between
    `node` and `arg` if necessary.
    r   z0expect original argument to be a Node, but got: N)r,   listrY   -_maybe_insert_input_observer_for_arg_or_kwargappendtyper   r   argsgetidr\   rV   targetr   r@   )ri   r]   rj   r<   rk   re   rc   new_arg_to_return	inner_argnew_inner_argnew_argoriginal_argrH   input_edge_obs_or_fqarg_as_output_obs_or_fqexisting_obs_nodemaybe_obs_nodemaybe_obs_mods                     r#   rn   rn   8  sI    #e}%% , 
	4 
	4II M $$]3333tCyy*+++c4   
c4     G L
*<
G
G ,#(+ +<
G
G ,d  O ON$|:L:LNNO O O %J&&(4#+//dCC *r2I/J/JbO O 0 0   )..** " "/NN 	%n&;<m#7 8 888!!!! 9  !5- G Nr$   c           
         g }| j         D ],}t          | ||||||          }|                    |           -| j        t          j        j        j        j        k    sj| j        t          j        j        j	        j        k    sF| j        t          j        j        j
        j        k    s"t          | j                  dk    s
J d            t          |          | _         dS )a  
    If needed, inserts observers to the input args and kwargs of `node`.
    Note: modifies `node` inplace.

    For example, if cur_node needs an observer after prev_node, we change from

      prev_node -> cur_node

    To

      prev_node -> obs -> cur_node

    r   z, expecting kwargs for aten op IR to be emptyN)rq   rn   ro   rt   rW   opsatenclonedefault
zeros_likegelulenkwargsrY   )	ri   rj   r<   rk   re   rc   new_argsr]   rx   s	            r#   &_maybe_insert_input_observers_for_noder     s    . Hy 
! 
!?
 
 	     	uy~+333;%).3;;;;%).-555t{q   5 !   hDIIIr$   r@   c                    | |v r||          }t          | ||||          }t          | t                    rt          |t                    ryt          | j        v rkt
          | j        t                   v rRt          |j        vri |j        t          <   | j        t                   t
                   |j        t                   t
          <   |S d S N)r   r,   r   r	   r>   r
   )ri   r<   rk   r@   re   rc   output_act_obs_or_fq
new_outputs           r#   &_maybe_insert_output_observer_for_noder     s     },T2&&}e
 


 tT""
	(:t,,
	( di''(DIj,AAA00.0

+DHIE&E(JOJ'(@A 4r$   c                    d| j         v r| j         d         nd }|d S t          |                    d                    }t          | d ||||           d| j         v ot	          | j         d         t
                    }|sd S t          | |||j        ||          }|d S t          | j	        
                                          }|D ]}	|	|u r|	                    | |           d S )Nr?   F)remove_duplicateval)r>   dictrk   r   r,   r   r   r@   rm   r\   rV   replace_input_with)
ri   r<   re   rc   !this_node_quantization_annotationrk   output_is_a_tensormaybe_output_obs_node
orig_users	user_nodes
             r#   1_maybe_insert_input_and_output_observers_for_noder     s:    %	11 		+,, &
 )0,,e,DDEEM*   $)+X
49U;KZ0X0X  Ce]EK  $  djoo''((J B B	---$$T+@AAAAB Br$   node_name_to_scopec                 b   t          | j        j                  }t          |           }t	          |          }t          |||          }|D ]}t          || ||           t          | | j                  } t          | i |t                      i t                      |t                                 | S r   )rm   r@   rA   rJ   rb   rh   r   r   r   r   r   set)r<   r   rc   nodes_before_observationr.   ra   re   ri   s           r#   r   r     s      $EK$566 7u==<=RSS& "7 M ) 
 
9%	
 	
 	
 	
 u{++E

	 	 	 Lr$   )8typingr   r   r   r   r   rW   torch._subclassesr   torch.ao.quantizationr	   r
   r   r   &torch.ao.quantization.fx.custom_configr    torch.ao.quantization.fx.preparer   r   r   r   torch.ao.quantization.qconfigr   torch.ao.quantization.quantizerr   r   r   torch.fxr   r   r   torch.fx.noder   __all__r    r)   r-   r0   r8   r;   rX   rJ   rN   intrb   boolrh   nnModulestrrn   r   r   r   rp   r   rQ   r$   r#   <module>r      s   4 4 4 4 4 4 4 4 4 4 4 4 4 4  ( ( ( ( ( (            G F F F F F            5 4 4 4 4 4         
 . - - - - - - - - - " " " " " "
 
/3J
4J/K   (	.	.	. *j01	. 
		. 	. 	. 	./// *j01/ / / / 
,@ @A *j01 	   $1 <P    "6 AU    !8!	**
*+! ! ! !$: : :8{$
,@ @A{$	*c/{$ {$ {$ {$|":s?3
,@ @A  
*,
,-	   .Q
c	
Q	Q Q 8?	Q
 UX_,-Q 
$::;Q Q Q Q Q Qh/ 
/ /  8?/  UX_,-	/ 
 
$::;/  /  
/  /  /  / d
8? UX_,- 	
 
$::;  d^   :6B
6B86B 
$::;6B 	6B 6B 6B 6Br%%S%T	"223% % 	% % % % % %r$   