
     Ngc                         d dl mZ d dlmZmZmZmZmZ d dlm	Z	 d dl
mZ d dlmZmZmZ d dlmZ  ee          Z G d de	          Z G d	 d
e          ZdS )    )	getLogger)DictListOptionalTupleUnion)Fusion)FusionUtils)	NodeProtoTensorProtohelper)	OnnxModelc                   L    e Zd ZdZd"dedef fdZdedede	eef         f         fd	Z
d
edeeee         f         dedefdZd Zd Zd Zd Zd Zdede	eedef         f         fdZ	 	 	 d#ded
ededededef         dee         fdZd Zd Z	 d$dZd Zd  Zd! Z xZS )%FusionEmbedLayerNoMaskz
    Fuse embedding layer into one node (EmbedLayerNormalization).
    It supports the following model types: BERT, DistilBert, ALBert.
    no maskmodeldescriptionc                     t                                          |dddg|           t          |          | _        d | _        d| _        d | _        d | _        d S )NEmbedLayerNormalizationLayerNormalizationSkipLayerNormalizationF)super__init__r
   utilsshape_infershape_infer_done	attention
embed_node)selfr   r   	__class__s      f/var/www/html/ai-engine/env/lib/python3.11/site-packages/onnxruntime/transformers/fusion_embedlayer.pyr   zFusionEmbedLayerNoMask.__init__   sf    %!#;<		
 	
 	
 !''
 %     addreturnNc                     | j                             |dgdg          }|d S | j                             |dgdg          }|d S |d         |d         fS )NGatherr      )r   match_parent_path)r   r#   gather_0_pathgather_1_paths       r!   match_two_gatherz'FusionEmbedLayerNoMask.match_two_gather&   sg    
44S8*qcJJ 4
44S8*qcJJ 4Qq!111r"   	layernorminput_name_to_nodesis_distil_bertc                 $   | j                             |d|d          | _        | j        dS |j        d         |vrdS ||j        d                  }t	          d |D                       }|g dk    rd|D ]a}|j        d	k    rT| j                             |g d
g d          }|2|d         j        d         |j        d         k    r|d         | _         dS bt          |          dk    r|d         j        dk    r|d         j        d         |v r||d         j        d                  }t          |          dk    rr|d         j        dk    ra|d         j        d         |v rL||d         j        d                  }	|	D ]}|j        dk    r
|| _         dS t	          d |	D                       }|r5|g dk    r,|g dk    r$|g dk    rt                              d           dS n,|g dk    r$|g dk    rt                              d           dS dS )a  Check that LayerNormalization has a child of Attention node or subgraph like Attention.

        Args:
            layernorm (NodeProto): LayerNormalization node
            input_name_to_nodes (Dict[str, List[NodeProto]]): map from input name to nodes
            is_distil_bert (bool): whether it is DistilBert or not

        Returns:
            bool: whether there is Attention node or subgraph like Attention
        	AttentionF)	recursiveNTr   c                     g | ]	}|j         
S  op_type.0childs     r!   
<listcomp>zCFusionEmbedLayerNoMask.check_attention_subgraph.<locals>.<listcomp>K   s     E E E5 E E Er"   )MatMulr:   r:   r   r   )Addr:   MultiHeadAttentionr:   )NNr   r      r'   r:   r;   c                     g | ]	}|j         
S r3   r4   r6   s     r!   r9   zCFusionEmbedLayerNoMask.check_attention_subgraph.<locals>.<listcomp>h   s    (J(J(J5(J(J(Jr"   )r:   r:   r:   Shaper   )r;   r:   r:   r:   r@   r@   )r;   r:   r:   r:   r@   z<No Attention like subgraph in children of LayerNormalization)r;   r:   r:   r:   )r   find_first_child_by_typer   outputsortedr5   r(   inputcross_attentionlenloggerdebug)
r   r,   r-   r.   childrenchildren_typesnodepath1grandchildrennodess
             r!   check_attention_subgraphz/FusionEmbedLayerNoMask.check_attention_subgraph1   s     <<{$75 = 
 
 >%4A&9995&y'7':; E EH E E EFF UUUUU  	$ 	$<#;;; J88III*** E
 (U2Y_Q-?9CSTUCV-V-V/4Qx,#tt x==A(1+"5"A"AhqkFXYZF[_rFrFr/0B10EFMM""a''!!$,55!!$+A.2EEE+M!,<,CA,FG! $ $D|{22)-#tt 3 "((J(JE(J(J(J!K!K  	 "c"c"ccc"&]&]&]]]"&T&T&TTT[\\\u " " "  
 ! % % %   [\\\utr"   c                 B   | j                             |ddgddg          }|$| j                             |g dg d          }|dS |d         |d	         }}|j        d         |k    rdS | j                             |g d
g dfg dg dfg|          \  }}}|dS |d         }	| j                            |	dd          r| j                            |	dd          sdS |d         }
| j                            |
dd          sdS |d	         }|j        d         |k    rdS dS )az    Match position embedding path from input_ids to Gather for DistilBert.

        Pattern is like the following:
                 (input_ids)
                      |
                     Shape
                       |                          |    Gather (indices=1)
                       |       |
                       |      Cast (optional)
                       |       |
                       |      Range (start=0, end=*, delta=1)
                       |       |
                       |    Unsqueeze
                       |    /
                      Expand
                        |
                      Gather
        Expandr@   r'   N)rQ   WhereReshaper@   )r'   r'   r>   r   Fr   r=   )	UnsqueezeRangeCastr&   r@   )r   r   r'   r   r   )rT   rU   r&   r@   )r   r   r'   r   r>   T)r   r(   rD   match_parent_pathsr   check_node_input_value)r   position_embedding_gather	input_idsoutput_name_to_noderL   expandshape_path2
range_nodegather_node
shape_nodes               r!   #match_position_embedding_distilbertz:FusionEmbedLayerNoMask.match_position_embedding_distilbert   s   * 
,,-FSZH[^_ab]cdd=J00)777 E
 }ua%);q>Y&&5j33BBBOOOT:::LLLI  
 
5! =51X
J--j!Q??	DHJDeDefprsuvDwDw	 5Bi
11+q!DD 	52Y
A)++5tr"   c                     dS )aY  Match position embedding path from input_ids to Gather for Roberta.

        Roberta Embedding Layer Pattern (* is optional since it might be removed by ORT, ? is the padding word id):
          (input_ids) --> Equal(B=?) -- Not -- Cast(to=6) -- CumSum(axis=1) -- Mul -- Cast(to=7) -- Add(B=1) -- Cast(to=7)* --> Gather
                                                |                              ^
                                                V                              |
                                                +------------------------------+

        Roberta new pattern from transformers v4.9:
           (input_ids) --> Equal(B=?) -- Not -- Cast(to=6) -- CumSum(axis=1) -- Add(B=0) -- Mul -- Cast(to=7) -- Add(B=1) --> Gather
                                                |                                           ^
                                                V                                           |
                                                +-------------------------------------------+

        start_node = position_embedding_gather
        start_index = 1

        # match optional Cast node.
        parent = self.model.get_parent(start_node, start_index, output_name_to_node)
        if parent is None:
            return
        if parent.op_type == "Cast":
            if OnnxModel.get_node_attribute(parent, "to") != 7:
                return
            start_node = parent
            start_index = 0

        i, path, return_indices = self.model.match_parent_paths(
            start_node,
            [ (['Add', 'Cast', 'Mul', 'CumSum', 'Cast', 'Not', 'Equal'], [start_index, 0, 0, 0, 0, 0, 0]),
              (['Add', 'Cast', 'Mul', 'Add', 'CumSum', 'Cast', 'Not', 'Equal'], [start_index, 0, 0, 0, 0, 0, 0, 0])],
            output_name_to_node)

        if path is not None:
            # constant input of Add shall be 1.
            i, value = self.model.get_constant_input(path[0])
            if value != 1:
                return False

            _, self.padding_word_id = self.model.get_constant_input(path[-1])

            return input_ids == path[-1].input[0]
        Fr3   r   rZ   r[   r\   s       r!    match_position_embedding_robertaz7FusionEmbedLayerNoMask.match_position_embedding_roberta   s
    Z ur"   c                 *   | j                             |ddgddg|          }|dS |\  }}| j                             |j        d                   }|t	          |j                  dk    r|j        d         dk    ro| j                            |ddg          rR| j                            |ddg          r5t	          |j                  d	k    s| j                            |d	dg          sdS | j                                         }|d
k     rt          j
        |ddg          sdS n| j                            |ddg          sdS | j                             |d|          }	|	dS |	j        dk    r;| j                            |	dd          sdS | j                             |	d|          }
n|	}
|
|
j        dk    rdS | j                            |
dd          sdS | j                             |
d|          }||j        dk    rdS ||j        d         k    S )a	    Match position embedding path from input_ids to Gather for BERT.

        BERT Embedding Layer Pattern:
                                    (input_ids)
                                   /                                          /          Shape
                                /              |
                              /              Gather (indices=1)
                             /                  |
                            /                  Add (optional, B=0)
                           /                    |
                        Gather (segment_ids) Unsqueeze (axes=0)
                           \        |           |
                            \     Gather      Slice (data[1,512], starts=0, ends=*, axes=1, steps=1)
                              \    /            |
                                Add          Gather
                                   \       /
                                      Add
                                       |
                                LayerNormalization
        SlicerT   r'   r>   NFr            axesr;   r&   r@   )r   r(   get_constant_valuerD   rF   r^   r   rY   get_opset_versionr
   check_node_attribute
get_parentr5   )r   rZ   r[   r\   pathslice	unsqueezeslice_weightopset_versionrK   gatherr^   s               r!   match_position_embedding_bertz4FusionEmbedLayerNoMask.match_position_embedding_bert   sW   , z++%k"F	
 
 <5yz44U[^DD$L&''1,,"1%**
11%QC@@ +
11%QC@@ + U[!!Q&&$**K*KESTWXVY*Z*Z&5
446623IvsKK u :44YA3GG uz$$Y3FGG<5<5  :44T1a@@ uZ**44GHHFFF>V^x775
11&!Q?? 	5
%%fa1DEE=EMW445EKN**r"   c                 j    |                      |||          rdS |                     |||          rdS dS )NTF)rx   rd   rf   s       r!   match_position_embeddingz/FusionEmbedLayerNoMask.match_position_embedding:  sK    --.GTghh 	4 334MyZmnn 	4ur"   c                    |j         d         }|r|j         d         nd}|j         d         }| j        s'| j                            d          | _        d| _        | j        | j                            |          }| j                            |          }|r|sJ t          |          dk    r%t          |          dk    r|d         |d         k    s"t                              d| d|            dS |rU| j        	                    ||          s:t                              d	| d
| j                            |                      dS | j        
                    |j         d                   }	|	t          |	j                  dk    rt                              d           dS | j        
                    |j         d                   }
|
4t          |
j                  dk    s|	j        d         |
j        d         k    rt                              d           dS |rw| j        
                    |j         d                   }|4t          |j                  dk    s|	j        d         |j        d         k    rt                              d           dS |	j        d         |
j        d         k    rRt                              d|j         d          d|	j        d          d|j         d          d|
j        d                     |r|	j        d         |j        d         k    rRt                              d|j         d          d|	j        d          d|j         d          d|j        d                     |
j        d         |j        d         k    rRt                              d|j         d          d|
j        d          d|j         d          d|j        d                     dS )zXSanity check of embedding weights, and match hidden_size of weights and shape of inputs.r'   NT)updater>   z^Cannot fuse EmbedLayerNormalization: input_ids and position_ids not matched in 2nd dimension: z vs FzYCannot fuse EmbedLayerNormalization: input_ids and segment_ids does not have same shape: z != r   zICannot fuse EmbedLayerNormalization: word embedding table is not expectedzMCannot fuse EmbedLayerNormalization: position embedding table is not expectedzLCannot fuse EmbedLayerNormalization: segment embedding table is not expectedzword_embedding_table (z) size z <= position_embedding_table (z <= segment_embedding_table (zposition_embedding_table ()rD   r   r   infer_runtime_shaper   get_edge_shaperF   rG   infocompare_shapern   r^   warning)r   word_embedding_gathersegment_embedding_gatherrZ   r[   segment_idsposition_idsinput_ids_shapeposition_ids_shapeword_embedding_tableposition_embedding_tablesegment_embedding_tables               r!   check_embeddingz&FusionEmbedLayerNoMask.check_embeddingH  s>   )/2	;S].4Q77Y]06q9$ 	)#z==T=JJD$(D!'".==iHHO!%!1!@!@!N!N"9'9999O$$))*++q00#A&*<Q*??? _  vE  _  _  K]  _  _   u 4#3#A#A)[#Y#Y  tp  t  t  FJ  FV  Fe  Fe  fq  Fr  Fr  t  t   u#z<<=R=XYZ=[\\'3/C/I+J+Ja+O+OKKcddd5#':#@#@AZA`abAc#d#d $,+122a77$*1-1I1OPQ1RRRKKghhh5 	&*j&C&CD\DbcdDe&f&f#'/.455::(.q15L5RST5UUUjkkku  %a(,D,J1,MMMNN \)>)DQ)G  \  \PdPjklPm  \  \  Ng  Nm  no  Np  \  \  yQ  yW  XY  yZ  \  \    		#)!,0G0Ma0PPP ]-B-H-K  ]  ]ThTnopTq  ]  ]  Qi  Qo  pq  Qr  ]  ]  {R  {X  YZ  {[  ]  ]   (-a04K4QRS4TTT i1J1PQR1S  i  i\t\z{|\}  i  i  ]u  ]{  |}  ]~  i  i  G^  Gd  ef  Gg  i  i   tr"   
input_namec                     d}| j                             |          }|@|j        j        j        t
          j        k    r| j                            |          \  }}n |}n| j                            |          \  }}||fS )a  Cast a graph input or node input to int32.

        Args:
            input_name (str): name of graph input or node input

        Returns:
            A tuple of casted input name and the cast node.
            int32_output (str): If input is int32, it is the input name, Otherwise it is output name of Cast node.
            input_cast_node (Union[None, NodeProto]): Cast node. It could be None if input is int32.
        N)	r   find_graph_inputtypetensor_type	elem_typer   INT32r   cast_input_to_int32)r   r   input_cast_nodegraph_inputint32_outputs        r!   cast_to_int32z$FusionEmbedLayerNoMask.cast_to_int32  s     j11*=="+59JJJ04
0N0Nz0Z0Z-oo),0J,J,J:,V,V)L/_,,r"   Fr[   r   rZ   r   r   c	                 t   g }	|                      |          \  }}
| j                            d          }|j        dk    r|j        d         }|j        d         }n|j        d         }|j        d         }d}|N|                      |j        d                   \  }}
|||j        d         |j        d         |j        d         ||g}n|d|j        d         |j        d         d||g}|B|                    d           |                      |          \  }}
|                    |           |d	z   |d
z   g}|r||n|dz   }|                    |           t          j        d|||          }d|_        |j	        D ](}|j
        dk    r|j	                            |g           )t          |j	                  dk    r.|j	                            t          j        dd          g           |	                    |           |	D ]}| j        | j        |j
        <   | j                            |	           || _        |S )ag  Create an EmbedLayerNormalization node. Note that segment embedding is optional.

        Args:
            input_ids (str): input_ids for word embeddings
            layernorm (NodeProto): LayerNormalization or SkipLayerNormalization node.
            word_embedding_gather (NodeProto): the Gather node for word embedding
            position_embedding_gather (NodeProto): the Gather node for position embedding
            segment_embedding_gather (Union[None, NodeProto]): the Gather node for segment embedding, or None.

        Returns:
            NodeProto: the EmbedLayerNormalization node created.
        r   r   r'   r>   rj   Nr    _output_dummy_mask_index_embedding_sum)outputsnamezcom.microsoftepsilong-q=)r   r   create_node_namer5   rD   appendr   	make_nodedomain	attributer   extendrF   make_attributethis_graph_namenode_name_to_graph_namenodes_to_addr   )r   r[   r,   r   rZ   r   r   embedding_sum_outputembedding_sum_namer   r_   	node_namegammabetaembed_node_inputsr   embed_node_outputsr   r   attrK   s                        r!   create_fused_nodez(FusionEmbedLayerNoMask.create_fused_node  s   . )))44	1J//0IJJ	 444OA&E?1%DDOA&E?1%D #/!//0H0Nq0QRRNK %+A.)/2(.q1! %+A.)/2! #$$R((("00>>OL!$$\222')3YAT5TU 	,);)G%%YYiMiD%%d+++%%&	
 
 

 ,
 & 	3 	3Cx9$$$++SE222 z#$$)) '')>y')R)R(STTT 	J'''  	K 	KD6:6JD(33  ...$r"   c                 v    | j                             |j        d         |j        d                    d| _        d S )Nr   T)r   replace_input_of_all_nodesrB   prune_graph)r   r,   r   s      r!   finish_fusionz$FusionEmbedLayerNoMask.finish_fusion  s9    
--i.>q.A:CTUVCWXXXr"   c                     |j         dk    o5t          |j                  dk    ot          |j        d                   dk    S )Nr   rj   r   )r5   rF   rB   )r   rK   s     r!   "is_skip_layer_norm_with_sum_outputz9FusionEmbedLayerNoMask.is_skip_layer_norm_with_sum_output  sC     88nc$+>N>NQR>RnWZ[_[fgh[iWjWjmnWnnr"   c           
      r   |                      |          }|dS |\  }}|j        d         }	|j        d         }
|                     ||d          sdS |                     |d |          sdS |j        dk    rK|                     |          }d}|}|r|j        d         nd }|d uo| j                            |          d u}n|}|j        dk    rdnd}t          |j                  |k    r|j        |         nd }|d uo| j                            |          d u}|o||v ot          ||                   dk    }|d uo|j        dk    p|p|}| 
                    |	|||||
||r|nd           }|r2d	|j        |<   |s&| j                            ||j        d
                    |                     ||           dS )NFr'   r.   r   rj   r;   r   )r   r   _no_use__to_be_removed_r>   T)r+   rD   rO   r   r5   r   rB   r   find_graph_outputrF   r   r   r   )r   r,   add_before_layernormr-   r\   optional_segment_gather
two_gatherr   rZ   r[   r   need_embedding_sum_outputsum_output_indexnode_with_sum_output
sum_outputis_sum_graph_outputis_sum_used_by_multiple_nodesr   s                     r!   	fuse_gpt2z FusionEmbedLayerNoMask.fuse_gpt2  sn   ( **+?@@
5;E88)/2	06q9,,Y8K\a,bb 	5##$94AZ[[ 	5  888(,(O(OPY(Z(Z% #, 0IS)!,,tJ#-T#9"u
@\@\]g@h@hpt@t#7 $8$@E$I$Iqqq +2336FFF %+,<== 
 $.T#9"u
@\@\]g@h@hpt@to
.A AosK^_iKjGkGknoGo * *44)? )$,5m9LmPm &
 ++!%#!:-@Jzzd , 	
 	

 % 	X<U '(89& X
55j*BSTUBVWWW9j111tr"   c                 R   |                      |          }|dS |\  }}|j        d         }|                     ||d          sdS |                     |||          sdS |                     |d|          sdS |                     ||||d          }	|                     ||	           dS )a  Fuse embedding layer for DistilBert
        Args:
            layernorm (NodeProto): node of LayerNormalization or SkipLayerNormalization
            add_before_layernorm (NodeProto): the Add node before LayerNormalization, or the SkipLayerNormalization itself
            input_name_to_nodes (Dict[str, List[NodeProto]]): map from input name to nodes
            output_name_to_node (Dict[str, List[NodeProto]]): map from output name to nodes
        NFr'   Tr   )r+   rD   rO   rz   r   r   r   )
r   r,   r   r-   r\   r   r   rZ   r[   r   s
             r!   fuse_distilbertz&FusionEmbedLayerNoMask.fuse_distilbertd  s    & **+?@@
5;E88)/2	,,Y8K\`,aa 	5,,-F	Sfgg 	5##$94AZ[[ 	5++y"79RTX
 

 	9j111tr"   c                 0   | j                             |dgdg          }|dS |                     |d                   }|dS |\  }}|j        d         }	|                     ||d          sdS | j                             |dgdg          }
|
dS |
d         }|                     ||	|          s|                     ||	|          sdS |}|}|}|                     |||          sdS |                     |	||||          }|                     ||           dS )	a  Fuse embedding layer for Bert
        Args:
            layernorm (NodeProto): node of LayerNormalization or SkipLayerNormalization
            add_before_layernorm (NodeProto): the Add node before LayerNormalization, or the SkipLayerNormalization itself
            input_name_to_nodes (Dict[str, List[NodeProto]]): map from input name to nodes
            output_name_to_node (Dict[str, List[NodeProto]]): map from output name to nodes
        r;   r   NFr'   r   r&   T)	r   r(   r+   rD   rO   rz   r   r   r   )r   r,   r   r-   r\   add_2_gatherr   r   r   r[   position_embedding_pathrZ   tempr   s                 r!   	fuse_bertz FusionEmbedLayerNoMask.fuse_bert  sx    z334H5'TUSVWW5**<?;;
5:D77)/2	,,Y8K\a,bb 	5"&*">">?SV^U_bcad"e"e"*5$;A$>!,,-F	Sfgg 	-001I9Vijj u+D'@$(,%##$9;SUnoo 	5++!%$
 

 	9j111tr"   c                 4   | j                             |dgdg          }|j        dk    r|d S |d         }d }n| j                             |dgdg          }| j                             |dgdg          }|||d S |d         }|d         }n;|5|3| j                             |dgdg          }|d S |d         }|d         }n|}d }|                     |||||          rd S |                     ||||          rd S |                     ||||          rd S d S )Nr;   r   r   r&   r'   )r   r(   r5   r   r   r   )	r   rK   r-   r\   first_add_pathr   r   r)   r*   s	            r!   fusezFusionEmbedLayerNoMask.fuse  s   55dUGaSII<///%#1!#4 &*## J88zA3OOM J88zA3OOM$)B!)F'5a'8$*7*:''*}/D!%!=!=dUGaS!Q!Q!)F'5a'8$*7*:'''+$*.'>>&(;=PRi
 
 	 F&:<OQdee 	F>>$ 46IK^__ 	F	 	r"   )r   )NFN)N)__name__
__module____qualname____doc__r   strr   r   r   r   r+   r   r   boolrO   rd   rg   rx   rz   r   r   r   r   r   r   r   r   r   r   __classcell__r    s   @r!   r   r      sR        
 i c      	2I 	2%eIyDX>Y8Y2Z 	2 	2 	2 	2RR "#tI"67R 	R
 
R R R Rh< < <|- - -^F+ F+ F+P  H H HT- -c5y;Q6Q0R - - - -< '+"` `` `  )	`
 $-` #(i"8` sm` ` ` `D     
o o o rvO O O Ob' ' 'R0 0 0d" " " " " " "r"   r   c                   6     e Zd Zddef fdZd Z fdZ xZS )FusionEmbedLayerNormalizationFr   c                 Z    t                                          |d           || _        d S )Nz	with mask)r   r   use_mask_index)r   r   r   r    s      r!   r   z&FusionEmbedLayerNormalization.__init__  s+    ,,,,r"   c                 j   | j         }t          |j                  dk    r;|j                            |           t                              d|j                   nrt          |j                  dk    r8|j        d         s+||j        d<   t                              d|j                   n"t                              d|j                   d S |D ]c}t                              d|j                   |j        dk    r|j        d         |j        d<   C|j        d	k    r|j        d         |j        d
<   dd S )N   zappend mask to %szreplace mask in %szskip mask in %szupdate mask_index in %sr0   r'   rj   r<   rk   )	r   rF   rD   r   rG   rH   r   r5   rB   )r   
mask_int32attention_nodesr   attention_nodes        r!   replace_maskz*FusionEmbedLayerNormalization.replace_mask  s4    _
z  A%%##J///LL,jo>>>>!""Q&&z/?/B&",JQLL-z????LL*JO<<<F- 	? 	?NLL2N4GHHH%44*4*;A*>$Q'''+???*4*;A*>$Q'	? 	?r"   c                 *   d | _         d | _        d | _        t                                          |||           | j        d S | j        s1t                              d           |                     d           d S | j         8| j        1t                              d           |                     d           d S | j         r| j         j	        d         }n| j        j	        d         }||         }| j
                            |          r9d |D             }|                     ||           |                     d           d S ||vr2t                              d|           |                     d           d S ||         }|j        d	v rd
 |D             }|j        dk    rG|j	        d         }t          |          t          |          k    r| j                            |           |                     ||           |                     d           d S d S )NzG--use_mask_index is not set: EmbedLayerNormalization will not have maskz EmbedLayerNormalization(no mask)zLEmbedLayerNormalization will not have mask since attention node is not foundrj   rk   c                 $    g | ]}|j         d v |S )r0   r<   r4   r7   rK   s     r!   r9   z6FusionEmbedLayerNormalization.fuse.<locals>.<listcomp>  %    vvv$,RuBuButBuBuBur"   z"EmbedLayerNormalization(with mask)zHEmbedLayerNormalization will not have mask since %s is not a node output)	ReduceSumrV   c                 $    g | ]}|j         d v |S r   r4   r   s     r!   r9   z6FusionEmbedLayerNormalization.fuse.<locals>.<listcomp>%  r   r"   r   r   )r   rE   r   r   r   r   rG   rH   increase_counterrD   r   r   r   r5   rF   nodes_to_remover   )r   rK   r-   r\   r   children_nodesr   r    s          r!   r   z"FusionEmbedLayerNormalization.fuse  s1   #T.0CDDD?"F" 	LLbccc!!"DEEEF>!d&:&BLLghhh!!"DEEEF> 	7-a0JJ-3A6J,Z8:&&z22 	vvvvvOj/:::!!"FGGGF000LLceoppp!!"DEEEF":.<000vvvvvO|{**!Z]
~&&#o*>*>>>(//555j/:::!!"FGGGGG 10r"   )F)r   r   r   r   r   r   r   r   r   s   @r!   r   r     sz        - -i - - - - - -? ? ?*-H -H -H -H -H -H -H -H -Hr"   r   N)loggingr   typingr   r   r   r   r   fusion_baser	   fusion_utilsr
   onnxr   r   r   
onnx_modelr   r   rG   r   r   r3   r"   r!   <module>r      s"         5 5 5 5 5 5 5 5 5 5 5 5 5 5       $ $ $ $ $ $ / / / / / / / / / /            	8		P P P P PV P P PfGH GH GH GH GH$: GH GH GH GH GHr"   