
    il]                     z   S SK r S SKrS SKJr  S SKJrJrJr  S SKrS SK	J
r
  S SKJrJrJr  S SKJr  S SKJr  S SKJr  S S	KJr  S S
KJr  S SKJrJr  S SKJr  S SKJr  S SK 7  S SK!J"r"  S SK#J$r$  S SK%J&r&  S SK'J(r(  S SK)J*r*J+r+J,r,  S SK-J.r.  S SK/J0r1  Sr2Sr3 " S S5      r40 \1Rj                  Rl                  Rn                  Rp                  \9_\1Rj                  Rl                  Rt                  Rp                  \;_\1Rj                  Rl                  Rx                  Rp                  \=_\1Rj                  Rl                  R|                  R~                  \@_\1Rj                  Rl                  R                  Rp                  \B_\1Rj                  Rl                  R                  Rp                  \D_\1Rj                  Rl                  R                  Rp                  \F_\1Rj                  Rl                  R                  Rp                  \H_\1Rj                  R                  R                  Rp                  \H_\1Rj                  Rl                  R                  Rp                  \L_\1Rj                  Rl                  R                  Rp                  \N_\1Rj                  Rl                  R                  Rp                  \P_\1Rj                  Rl                  R                  Rp                  \R_\1Rj                  Rl                  R                  Rp                  \T_\1Rj                  Rl                  R                  Rp                  \T_\1Rj                  Rl                  R                  R                  \X_\1Rj                  Rl                  R                  Rp                  \Z_\1Rj                  Rl                  R                  R~                  \\\1Rj                  Rl                  R                  Rp                  \^\1Rj                  Rl                  R                  Rp                  \`\1Rj                  Rl                  R                  Rp                  \b\1Rj                  Rl                  R                  Rp                  \d\1Rj                  Rl                  R                  Rp                  \f\1Rj                  Rl                  R                  R~                  \h\1Rj                  Rl                  R                  Rp                  \j\1Rj                  Rl                  R                  R~                  \l\1Rj                  Rl                  R                  Rp                  \n\1Rj                  Rl                  R                  R                  \q\1Rj                  Rl                  R                  R                  \s\1Rj                  Rl                  R                  Rp                  \u0Erv " S S\5      rw\ " S S\+5      5       rxg)    N)	dataclass)CallablefinalMapping)CustomDelegationOptions)DEQUANTIZE_OPERATORSis_no_op_on_neutronQUANTIZE_OPERATORS)EdgeProgramToIRConverter)logger)is_not_qdq_node)ExportedProgram)Graph)CapabilityBasedPartitioner	Partition)OperatorSupportBase)	Parameter)*)NeutronTargetSpec)NodeFormatInference)NeutronBackend)CompileSpec)DelegationSpecPartitionerPartitionResult)tag_constant_data)opsNXP_DO_NOT_DELEGATEdelegation_tagc                      \ rS rSrSr\ " S S5      5       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                  R                  R*                  R                  \	R                  R                  R,                  R                  \	R                  R.                  R0                  R                  /rS r\S\R:                  R<                  S\4S j5       r \S\R:                  R<                  S\4S	 j5       r!\S\R:                  R<                  S\4S
 j5       r"S\R:                  R<                  S\#\R:                  R<                     4S jr$S\R:                  R<                  S\#\R:                  R<                     4S jr%S\R:                  R<                  S\#\R:                  R<                     4S jr&S\#\R:                  R<                     S\'SS4S jr(S\#\R:                  R<                     4S jr)Sr*g)QDQClusterRecognizer2   a  
Implementation of the Quantize - Dequantize clustering.
The quantization is captured in the ExecuTorch program using the QDQ (Quantize - DeQuantize) representation. Here
the inputs to a node comes from some dequantize nodes and outputs goes to some quantize nodes.
The QDQClusterRecognizer identifies operator performing the quantized arithmetic represented in QDQ form, and the
corresponding QDQ cluster. The QDQ cluster consists of the:
- dequantize nodes producing the inputs to the compute node
- compute node (e.g. conv)
- auxiliary nodes, like getitem, view_copy, ... which does not perform a core computation
- quantize nodes processing the output of the compute node.
c                       \ rS rSr% Sr\R                  R                  \S'   \	\R                  R                     \S'   Sr
g)QDQClusterRecognizer.QDQCluster?   a  
Dataclass to hold the QDQ cluster instance. For the purpose of Partitioner we hold the list of operators,
in the QDQ cluster (`ops`) and the compute node what the QDQ cluster is built around.
The compute node is what is represented in the Neutron IR. the rest of nodes are helpers for data transformation,
and defines the quantization parameters. This gives the partitioner the ability to:
    - identify if the node is part of a QDQ cluster
    - reference the compute node in the QDQ cluster
compute_noder    N)__name__
__module____qualname____firstlineno____doc__torchfxNode__annotations__list__static_attributes__r'       j/var/www/html/ai-image-ml/venv/lib/python3.13/site-packages/executorch/backends/nxp/neutron_partitioner.py
QDQClusterr$   ?   s*    	 hhmm#%((--  r3   r5   c                     0 U l         g Ncluster_map)selfs    r4   __init__QDQClusterRecognizer.__init__[   s
    GIr3   nodereturnc                 (    U R                   [        ;   $ r7   )targetr
   r=   s    r4   is_quant_node"QDQClusterRecognizer.is_quant_node^   s    {{000r3   c                 (    U R                   [        ;   $ r7   )r@   r   rA   s    r4   is_dequant_node$QDQClusterRecognizer.is_dequant_nodeb   s    {{222r3   c                 <    U R                   [        R                  ;   $ r7   )r@   r!   AUXILIARY_OPSrA   s    r4   is_auxiliary_node&QDQClusterRecognizer.is_auxiliary_nodef   s    {{2@@@@r3   c                    U/n/ n[        U5      S:  a  UR                  5       nUR                  U5        U R                  U5      (       a  MH  UR                   Vs/ s H,  nU R                  U5      =(       d    U R                  U5      PM.     nn[        U5      (       a  UR                  UR                  5        O/ $ [        U5      S:  a  M  [        R                  " SU SU 35        U$ s  snf )a  
Return the list of nodes representing the input part of the QDQ cluster of the node `node`.
Those are various dequantization nodes (see DEQUANTIZE_OPERATORS) optionally followed by auxiliary
nodes.
If the `node` not meets the QDQ cluster schema, returns empty list.
r   zDequant Cluster for z is: )
lenpopappendrE   all_input_nodesrI   allextendloggingdebug)r:   r=   nodes_to_checkqdq_clusterni"input_nodes_from_dequant_or_helpers          r4   get_qdq_cluster_input_part/QDQClusterRecognizer.get_qdq_cluster_input_partj   s     .!A%""$Aq!##A&& **2*A %%a(ED,B,B1,EE* / 2 566%%a&7&78	 .!A% 	,TF%}EF2s   3C.c                    U/n/ n[        U5      S:  Ga  UR                  5       nUR                  U5        U R                  U5      (       a  MI  [	        UR
                  R                  5       Vs/ s H  oTUR                  ;   d  M  UPM     nn[        R                  " SU SU 35        U Vs/ s H+  opR                  U5      =(       d    U R                  U5      PM-     nn[        U5      (       a  UR                  U5        O/ $ [        U5      S:  a  GM  [        R                  " SU SU 35        U$ s  snf s  snf )z
Returns the list of nodes representing the output part of the QDQ cluster of the `node`.
Those are various quantize nodes (see QUANTIZE_OPERATORS) preceded by auxiliary nodes.
If the `node` not meets the QDQ cluster schema, returns empty list.
r   z	 Users for node z are: zQuant Cluster for z is )rL   rM   rN   rB   r1   graphnodesrO   rR   rS   rI   rP   rQ   )	r:   r=   rT   rU   rV   ngn	consumersrW   output_nodes_to_quant_or_helpers	            r4   get_qdq_cluster_output_part0QDQClusterRecognizer.get_qdq_cluster_output_part   s4    .!A%""$Aq!!!!$$#DJJ$4$455c>Q>Q9Q5   MM.qc	{CDNW/NW##A&C$*@*@*CCi , / 233%%i0	 .!A%" 	*4&[MBC/s   0D7D7/2D<c                     [         R                  " U5        U R                  U5      nU R                  U5      nU(       a*  U(       a#  [	        [        U5      R                  U5      5      $ / $ )zj
Returns the QDQ cluster of the operator, if quantized. If operator is not quantized, returns empty list.
)rR   rS   rY   ra   r1   setunion)r:   r=   input_qdq_clusteroutput_qdq_clusters       r4   get_qdq_cluster$QDQClusterRecognizer.get_qdq_cluster   sZ     	d ;;DA!==dC!3-.445GHIIIr3   r]   cluster_nameNc                 j    U H-  n[         R                  " SU SU 35        X#R                  S'   M/     g)zS
Tags a node and its related dequant and quant nodes with a specified cluster name
zTagging node z as clusterN)rR   infometa)r:   r]   rj   r=   s       r4   	tag_nodesQDQClusterRecognizer.tag_nodes   s3     DLL=d<.AB#/IIi  r3   c                 J   U H  nUR                   S:X  d  M  U R                  U5      (       a  M-  U R                  U5      (       a  ME  U R                  U5      nU(       d  M_  UR                   S3nU R                  X45        U R                  X#5      U R                  U'   M     g)zI
Identifies QDQ clusters and tag them based on compute operation inside.
call_function_clusterN)oprB   rE   rh   namero   r5   r9   )r:   r]   r=   rl   rj   s        r4   tag_qdq_clusters%QDQClusterRecognizer.tag_qdq_clusters   s    
 D?***400,,T22..t47&*ii[#9LNN7959__T5SD$$\2 r3   r8   )+r(   r)   r*   r+   r,   r   r5   operatorgetitemexir_opsedgeatenclonedefaulthardtanhpermute_copyrelusigmoidsqueeze_copydimstanhunsqueeze_copy	view_copydim_order_ops_clone_dim_orderrH   r;   staticmethodr-   r.   r/   boolrB   rE   rI   r1   rY   ra   rh   strro   rv   r2   r'   r3   r4   r!   r!   2   sn   
 ! ! ! 	  ((##++''//''""**'',,''))11$$,,##44<<MJ 1EHHMM 1d 1 1 3ehhmm 3 3 3 A A$ A Auxx}} ehhmmAT 8 $uxx}}BU <
EHHMM 
d588==6I 
0tEHHMM2 0# 0$ 0Td588==&9 Tr3   r!   c            
       J   \ rS rSrS\\\R                  4   S\S\	\   S\\\
4   S\4
S jrS\R                  R                  R                   4S	 jrS\R                  R                  R                   4S
 jrS\R                  R                  R                   4S jrS\R                  R                  R                   S\4S jrS\R                  R                  R                   S\4S jrS\\\R0                  R2                  4   S\R                  R                   S\4S jrSrg)NeutronSupportedOperators   qdq_clustersneutron_target_specoperators_not_to_delegateparameters_mappingcustom_delegation_optionsc                 @    Xl         X l        X0l        X@l        XPl        g r7   )r   r   r   r   r   )r:   r   r   r   r   r   s         r4   r;   "NeutronSupportedOperators.__init__   s"     )#6 )B&"4)B&r3   r=   c                      SUR                   ;   $ )Nrl   )rn   r:   r=   s     r4   _is_node_quantized,NeutronSupportedOperators._is_node_quantized   s    DII%%r3   c                      UR                   S:H  $ )Nrr   )rt   r   s     r4   _is_node_call_function0NeutronSupportedOperators._is_node_call_function   s    ww/))r3   c                 t   ^ U R                   S/:w  a&  [        U4S jU R                    5       5      nU(       + $ g)N c              3   @   >#    U  H  oTR                   ;   v   M     g 7fr7   )ru   ).0xr=   s     r4   	<genexpr>@NeutronSupportedOperators.is_node_delegatable.<locals>.<genexpr>  s      &(F1TYY(Fs   T)r   any)r:   r=   any_non_delegatables    ` r4   is_node_delegatable-NeutronSupportedOperators.is_node_delegatable  s?    ))bT1"% &(,(F(F& # +**r3   r>   c                    [        US5      (       a&  UR                  R                  [        S5      (       a  gU R	                  U5      (       d  g[
        R                  UR                  S5      =nc  gU R                  U5      =(       aJ    U R                  U5      =(       a2    UR                  UU R                  U R                  U R                  5      $ )z/
Operator checking function for compute nodes.
rn   FN)hasattrrn   getr   r   supported_opsr@   r   r   is_supportedr   r   r   )r:   r=   node_converters      r4   _is_node_supported_compute4NeutronSupportedOperators._is_node_supported_compute
  s    
 4  TYY]]3F%N%N''--+//TBBNK ''- ''-++((''..			
r3   c                     U R                  U5      =(       a5    U R                  U R                  UR                  S      R                  5      $ )z
If the node is a quantize, dequantize or auxiliary node inside a QDQ cluster, the support on Neutron
is determined by the support of the compute operator.
rl   )r   r   r   rn   r&   r   s     r4   _is_node_supported_non_compute8NeutronSupportedOperators._is_node_supported_non_compute&  sF    
 &&t, 
1P1Pdii	23@@2
 	
r3   
submodulesc                     [         R                  U5      (       d4  [         R                  U5      (       d  [         R                  U5      (       a  U R	                  U5      $ U R                  U5      $ )z5
Check if the Edge operator is supported on Neutron.
)r!   rB   rE   rI   r   r   )r:   r   r=   s      r4   is_node_supported+NeutronSupportedOperators.is_node_supported/  sY     !..t44#33D99#55d;;66t<<22488r3   )r   r   r   r   r   N)r(   r)   r*   r+   dictr   r!   r5   r   r1   r   r   r;   r-   r.   r=   r/   r   r   r   r   r   r   r   nnModuler   r2   r'   r3   r4   r   r      s"   C3 4 ? ??@C /C $(9	C
 !i0C $;C&uxx}}'9'9 &*588==+=+= *(:(: 
uxx}}/A/A 
d 
8
588==3E3E 
$ 
9!#uxx"679?Dxx}}9	9r3   r   c                     ^  \ rS rSr    SS\\   S\S\S-  S\\	\
4   S-  S\\R                  R                     S-  S\\R                  R                   /\4   S-  S	S4U 4S
 jjjr\S\S\\	\
4   S	\4S j5       rS\S\\   S\S\\	\
4   S	\4
S jrS\S	\4S jrS\S	\\\R                  R                     \\R                  R                   /\4   S-  4   4S jrSrU =r$ )NeutronPartitioneri@  Ncompile_specr   r   post_quantization_state_dictpreserve_opscheck_op_supportr>   c                    > [         TU ]  5         [        [        R                  U5      U l        U=(       d
    [        5       U l        X l        X@l	        U=(       d    / U l
        X`l        g)a  Class responsible for identifying partitions suited for delegation to the eIQ Neutron NPU.

:param compile_spec: A list of compile specifications for Neutron.
:param neutron_target_spec: Object for querying the target platform to retrieve its properties.
:param custom_delegation_options: Custom user options which affect node delegation.
:param post_quantization_state_dict: State-dict of the model right after quantization. During partitioning, the
                                      `edge_program` only contains fake tensors without any data. In this case,
                                      this state dict is used instead (if provided). Notice: It may potentially
                                      contain outdated data,
N)superr;   r   r   r(   delegation_specr   r   r   r   r   r   )r:   r   r   r   r   r   r   	__class__s          r4   r;   NeutronPartitioner.__init__B  sZ    & 	-n.E.E|T%B)@)B 	& $7 ,H)(.B 0r3   	partitionr   c                    ^ [        [        [        U R                  5      5      n[	        U4S jU 5       5      (       a  gg)Nc              3   <   >#    U  H  n[        UT5      v   M     g 7fr7   )r	   )r   r=   r   s     r4   r   GNeutronPartitioner._partition_contains_compute_nodes.<locals>.<genexpr>e  s#      
0  &8990s   FT)r1   filterr   r]   rP   )r   r   non_q_dq_partition_nodess    ` r4   !_partition_contains_compute_nodes4NeutronPartitioner._partition_contains_compute_nodes_  s=     $(	(P#Q  
0
 
 

 r3   r\   partition_listc                 T   [        U5      S:X  a  gSnUR                  (       dI  U HC  nU R                  Xd5      (       a  M  SnUR                   H  nSUR                  [
        '   M     ME     U VVs1 s H  ofR                    H  owiM     M     nnnUR                   H  nXx;   d  M
  [        US5      (       d  M  UR                  [        ;   d  M3  [        UR                     R                  UUUU R                  U5      (       a  Mj  SnSUR                  [
        '   M     U$ s  snnf )a  Verify that the result of the partitioning can be safely used for delegation.

:param graph: Original graph that was partitioned.
:param partition_list: List of the resulting partitions.
:param custom_delegation_options: Custom user options which affect node delegation.
:param parameters_mapping: Dict mapping tensor names to their static data. Should be inferred from the
                           `state_dict` attribute of an edge program.
:return: True, if the partitioning result is valid.
r   TFr@   )rL   allow_no_op_partitionsr   r]   rn   r   r   r@   r   supports_partitioning_resultr   )	r:   r\   r   r   r   partitioning_validr   r=   all_delegated_nodess	            r4   validate_partitioning_result/NeutronPartitioner.validate_partitioning_resultn  s     ~!#!(?? ,	==  */& )9=		"56 !0 , #1
"0Y__TD_D. 	 
 KKD+D(++KK=0$T[[1NN"-,,&  */&59DII12  " "!)
s   2D$exported_programc           
      Z   [         R                  " S5        0 n/ nUR                  n[        UR                  R
                  5      n[        5       nUR                  U5        UR                  5         U R                  S   S   R                  R                  5       R                  S5      n[         R                  " SU 35        [        R                  " XR                  5      n[!        UR                  [#        UR$                  U R&                  UUU R(                  5      SS9n	[+        U5      R-                  5         [        R                  " XR                  5      n[/        UR                  R
                  5      n
[1        U
5       HD  nU	R3                  5       nU R5                  UR                  UU R(                  U5      nU(       d  MD    O   U HE  nUR
                   H2  nSUR6                   3nXR8                  [:        '   U R                  X/'   M4     MG     [=        U5        [?        XS	9$ )
NzNeutronPartitioner::partition      ,zOperators not to delegate: T)allows_single_node_partitiontag)tagged_exported_programpartition_tags) rR   rm   graph_moduler1   r\   r]   r!   rv   	recompiler   valuedecodesplitr   map_inputs_to_parametersr   r   r   r9   r   r   r   identify_node_formatsrL   rangepropose_partitionsr   idrn   NXP_DELEGATION_TAGr   r   )r:   r   r   r   r   r]   qdq_cluster_recognizerr   r   capability_partitioneriteration_limit_r   r   r=   r   s                   r4   r   NeutronPartitioner.partition  s    	45'44\''--.!5!7//6 $($8$8$;A$>$D$D$K$K$M$S$STW$X!23L2MNO5NN??
 "<))%&22(()".. *.
"
 	,-CCE5NN??
 .44::;'A3FFHN "&!B!B &&.."	" "! (  (I!#&y||n!50>		,-151E1E. ( ( 	*+$4
 	
r3   epc                 $  ^ ^^ [         R                  " U5      m0 m[        R                  5        H  u  p#UTUR                  '   M     [        USS9R                  5         S[        R                  R                  4UUU 4S jjnT R                  U4$ )a  
Method to determine which operators SHOULD NOT be decomposed to edge dialect.

The method returns:
    a list of operators NOT to decompose
    optional callable - filter
If the operator is in the list and the evaluation of the callable is True (or the callable is not specified),
the operator should not be decomposed (i.e. it truly belongs to the list). Otherwise, it should be decomposed.
T)only_for_op_support_checkr=   c                 ~  > U R                   TR                  ;  a  gTR                  U R                   5      nUc1  [        R                  " S[        U R                   5       S3S-   5        gUR                  U TR                  TTR                  5      nTR                  c  SOTR                  U 5      nU=(       a    U$ )NFzNode of target z- might be decomposed to other edge operators z,because no appropriate NodeConverter exists.T)
r@   r   r   r   wr   r   r   r   r   )r=   r   	delegablebase_check_opaten_op_to_converterr   r:   s       r4   check_op_support_extendedJNeutronPartitioner.ops_to_not_decompose.<locals>.check_op_support_extended  s    {{$"3"33 255dkkBN%%c$++&6%77deDE &33(("..	I --54;P;PQU;V  ..r3   )r   r   r   items_opr   r   r-   r.   r/   r   )r:   r   exir_op	converterr   r   r   s   `    @@r4   ops_to_not_decompose'NeutronPartitioner.ops_to_not_decompose  s    " 6NNrR!"/"5"5"7G09 - #8 	B$?UUW	/EHHMM 	/ 	/8   ";;;r3   )r   r   r   r   r   r   )NNNN)r(   r)   r*   r+   r1   r   r   r   r   r   r   r-   _ops
OpOverloadr   r.   r/   r   r;   r   r   r   r   r   r   r   r   tupler   r2   __classcell__)r   s   @r4   r   r   @  s    EIDH;?CG1;'1 /1 $;T#A	1
 '+3	>&:T&A1 5::001D81 #EHHMM?D#89D@1 
1 1: 26sI~2F	 7"7" Y7" $;	7"
 !i07" 
7"rC
/ C
o C
J5<5< 
tEJJ))*Hehhmm_d5J,Kd,RR	S5< 5<r3   r   )yrR   rx   dataclassesr   typingr   r   r   r-   9executorch.backends.nxp.backend.custom_delegation_optionsr   +executorch.backends.nxp.backend.edge_helperr   r	   r
   6executorch.backends.nxp.backend.edge_program_converterr   "executorch.backends.nxp.backend.irr   ;executorch.backends.nxp.backend.ir.converter.node_converterr   torch.export.exported_programr   torch.fxr   !torch.fx.passes.infra.partitionerr   r    torch.fx.passes.operator_supportr   torch.nnr   Kexecutorch.backends.nxp.backend.ir.converter.node_converters.ops_converters3executorch.backends.nxp.backend.neutron_target_specr   5executorch.backends.nxp.backend.node_format_inferencer   #executorch.backends.nxp.nxp_backendr   +executorch.exir.backend.compile_spec_schemar   #executorch.exir.backend.partitionerr   r   r   executorch.exir.backend.utilsr   executorch.exir.dialects._opsr   rz   r   r   r!   r{   r|   absr~   AbsConverter_adaptive_avg_pool2dAdaptiveAvgPool2dConverteraddmmAddMMConverteraddTensorAddTensorConverter
avg_pool2dAvgPool2dConvertercatCatConverterclampClampConverterr}   CloneConverterr   r   constant_pad_ndConstantPadNDConverterconvolutionConvolutionConverterr   HardTanhConverter
leaky_reluLeakyReluConverter
max_pool2dMaxPool2dConvertermax_pool2d_with_indicesmeandimMeanDimConvertermmMMConvertermulMulTensorConverternegNegConverterr   PermuteCopyConverterpreluPReLUConverterr   ReLUConverterr   SigmoidConverter
slice_copySliceTensorConverter_softmaxSoftmaxConvertersubSubTensorConverterr   TanhConverterupsample_bilinear2dvecUpsampleBilinear2DConverterupsample_nearest2dUpsampleNearest2DConverterr   ViewCopyConverterr   r   r   r'   r3   r4   <module>rL     sm     ! + +  
 6 W 9  S @  Y Q U > C 
 < 9+ % UT UTpMM""LMM++335O MM$$n MM!!#5	
 MM!!))+= MM""L MM$$n MM$$n MM0088. MM&&..0F MM""**,@ MM''): MM!!))+= MM!!))+= MM..668J  MM!1!" MM!!;#$ MM!!#5MM""LMM##++-AMM$$nMM##]MM&&(8MM!!((*>MM'')9MM!!#5MM##]MM**..0KMM))--/IMM  ((*;=DQ9 3 Q9h `< `< `<r3   