
    h                         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  \" \5      r " S S\5      r " S S	\5      rg
)    )	getLogger)Fusion)FusionUtils)	NodeProtoTensorProtohelper)	OnnxModelc                   *  ^  \ rS rSrSrS"S\S\4U 4S jjjrS\SS\	\\4   -  4S	 jr
S
\S\\\\   4   S\S\4S jrS rS rS rS rS rS\S\	\S\-  4   4S jr   S#S\S
\S\S\SS\-  S\S-  4S jjrS rS r S$S jrS rS rS  rS!rU =r$ )%FusionEmbedLayerNoMask   z
Fuse embedding layer into one node (EmbedLayerNormalization).
It supports the following model types: BERT, DistilBert, ALBert.
modeldescriptionc                    > [         TU ]  USSS/U5        [        U5      U l        S U l        SU l        S U l        S U l        g )NEmbedLayerNormalizationLayerNormalizationSkipLayerNormalizationF)super__init__r   utilsshape_infershape_infer_done	attention
embed_node)selfr   r   	__class__s      d/var/www/fran/franai/venv/lib/python3.13/site-packages/onnxruntime/transformers/fusion_embedlayer.pyr   FusionEmbedLayerNoMask.__init__   sP    %!#;<		
 !'
 %     addreturnNc                     U R                   R                  US/S/5      nUc  g U R                   R                  US/S/5      nUc  g US   US   4$ )NGatherr      )r   match_parent_path)r   r   gather_0_pathgather_1_paths       r   match_two_gather'FusionEmbedLayerNoMask.match_two_gather%   sa    

44S8*qcJ 

44S8*qcJ Qq!111r   	layernorminput_name_to_nodesis_distil_bertc                 n   U R                   R                  USUSS9U l        U R                  b  gUR                  S   U;  a  gX!R                  S      n[	        U Vs/ s H  oUR
                  PM     sn5      nU/ SQ:X  ap  U Hj  nUR
                  S:X  d  M  U R                   R                  U/ SQ/ S	Q5      nUc  M;  US
   R                  S   UR                  S   :X  d  M`  US   U l          g   [        U5      S:X  a  US   R
                  S:X  a  US   R                  S   U;   a  X$S   R                  S      n	[        U	5      S:X  a  U	S   R
                  S:X  ap  U	S   R                  S   U;   aZ  X)S   R                  S      n
U
 H  nUR
                  S:X  d  M  Xpl          g   [	        U
 Vs/ s H  oUR
                  PM     sn5      nU(       a/  U/ SQ:w  a&  U/ SQ:w  a  U/ SQ:w  a  [        R                  S5        ggU/ SQ:w  a  U/ SQ:w  a  [        R                  S5        ggs  snf s  snf )ao  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)	recursiveTr   )MatMulr/   r/   r   r   )Addr/   MultiHeadAttentionr/   )NNr   r      r#   r/   r0   )r/   r/   r/   Shaper   )r0   r/   r/   r/   r4   r4   )r0   r/   r/   r/   r4   z<No Attention like subgraph in children of LayerNormalization)r0   r/   r/   r/   )r   find_first_child_by_typer   outputsortedop_typer$   inputcross_attentionlenloggerdebug)r   r)   r*   r+   childrenchildchildren_typesnodepath1grandchildrennodess              r   check_attention_subgraph/FusionEmbedLayerNoMask.check_attention_subgraph0   sD     <<{$75 = 
 >>%A&99&'7'7':;H EH5H EF UU <<#;; JJ88I*E
 (U2Y__Q-?9CSCSTUCV-V/4Qx,# ! x=A(1+"5"5"AhqkFXFXYZF[_rFr/0B0B10EFMM"a'!!$,,5!!$++A.2EE+!,<,C,CA,FG!D||{2)-# " "(E(JE5E(J!K  "cc"&]]"&TT[\    " 
 ! %  [\q !F: )Ks   H-4H2c                 J   U R                   R                  USS/SS/5      nUc%  U R                   R                  U/ SQ/ SQ5      nUc  gUS   US   peUR                  S   U:w  a  gU R                   R                  U/ S	Q/ S
Q4/ SQ/ SQ4/U5      u  pxnUc  gUS   n	U R                  R                  U	SS5      (       a"  U R                  R                  U	SS5      (       d  gUS   n
U R                  R                  U
SS5      (       d  gUS   nUR                  S   U:w  a  gg)a  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
Expandr4   r#   )rH   WhereReshaper4   )r#   r#   r3   r   Fr   r2   )	UnsqueezeRangeCastr"   r4   )r   r   r#   r   r   )rK   rL   r"   r4   )r   r   r#   r   r3   T)r   r$   r9   match_parent_pathsr   check_node_input_value)r   position_embedding_gather	input_idsoutput_name_to_noderB   expandshape_path2
range_nodegather_node
shape_nodes               r   #match_position_embedding_distilbert:FusionEmbedLayerNoMask.match_position_embedding_distilbert   s>   * 

,,-FSZH[^_ab]cd=JJ00)7E
 }a%);;q>Y&jj33BOT:LI  
! =1X
JJ--j!Q??DJJDeDefprsuvDwDwBi

11+q!DD2Y
A)+r   c                     g)aI  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]
F r   rQ   rR   rS   s       r    match_position_embedding_roberta7FusionEmbedLayerNoMask.match_position_embedding_roberta   s    Z r   c                    U R                   R                  USS/SS/U5      nUc  gUu  pVU R                   R                  UR                  S   5      nUb  [	        UR
                  5      S:X  a  UR
                  S   S:X  a  U R                  R                  USS/5      (       a_  U R                  R                  USS/5      (       a<  [	        UR                  5      S:X  d$  U R                  R                  USS/5      (       d  gU R                   R                  5       nUS	:  a   [        R                  " US
S/5      (       d  gO$U R                  R                  USS/5      (       d  gU R                   R                  USU5      n	U	c  gU	R                  S:X  aA  U R                  R                  U	SS5      (       d  gU R                   R                  U	SU5      n
OU	n
U
b  U
R                  S:w  a  gU R                  R                  U
SS5      (       d  gU R                   R                  U
SU5      nUb  UR                  S:w  a  gX+R                  S   :H  $ )aw  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
SlicerK   r#   r3   Fr            axesr0   r"   r4   )r   r$   get_constant_valuer9   r;   rU   r   rP   get_opset_versionr   check_node_attribute
get_parentr8   )r   rQ   rR   rS   pathslice	unsqueezeslice_weightopset_versionrA   gatherrU   s               r   match_position_embedding_bert4FusionEmbedLayerNoMask.match_position_embedding_bert   s   , zz++%k"F	
 <zz44U[[^D$L&&'1,""1%*

11%QC@@

11%QC@@U[[!Q&$***K*KESTWXVY*Z*Z

446233IvsKK L ::44YA3GGzz$$Y3FG<<<5 ::44T1a@@ZZ**44GHFF>V^^x7

11&!Q??

%%fa1DE=EMMW4KKN**r   c                 d    U R                  XU5      (       a  gU R                  XU5      (       a  gg)NTF)rr   r[   r_   s       r   match_position_embedding/FusionEmbedLayerNoMask.match_position_embedding9  s7    --.GTghh 334MZmnnr   c                 <   UR                   S   nU(       a  UR                   S   OSnUR                   S   nU R                  (       d%  U R                  R                  SS9U l        SU l        U R                  b  U R                  R                  U5      nU R                  R                  U5      nU(       a  U(       d   e[        U5      S:X  a  [        U5      S:X  a  US   US   :X  d  [        R                  SU SU 35        gU(       aU  U R                  R                  XE5      (       d5  [        R                  S	U S
U R                  R                  U5       35        gU R                  R                  UR                   S   5      n	U	b  [        U	R                  5      S:w  a  [        R                  S5        gU R                  R                  UR                   S   5      n
U
b9  [        U
R                  5      S:w  d   U	R                  S   U
R                  S   :w  a  [        R                  S5        gU(       az  U R                  R                  UR                   S   5      nUb9  [        UR                  5      S:w  d   U	R                  S   UR                  S   :w  a  [        R                  S5        gU	R                  S   U
R                  S   ::  aU  [        R                  SUR                   S    SU	R                  S    SUR                   S    SU
R                  S    35        U(       a  U	R                  S   WR                  S   ::  aU  [        R                  SUR                   S    SU	R                  S    SUR                   S    SUR                  S    35        U
R                  S   UR                  S   ::  aU  [        R                  SUR                   S    SU
R                  S    SUR                   S    SUR                  S    35        g)zXSanity check of embedding weights, and match hidden_size of weights and shape of inputs.r#   NT)updater3   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 ()r9   r   r   infer_runtime_shaper   get_edge_shaper;   r<   infocompare_shaperh   rU   warning)r   word_embedding_gathersegment_embedding_gatherrQ   rR   segment_idsposition_idsinput_ids_shapeposition_ids_shapeword_embedding_tableposition_embedding_tablesegment_embedding_tables               r   check_embedding&FusionEmbedLayerNoMask.check_embeddingG  s   )//2	;S.44Q7Y]066q9$$#zz==T=JD$(D!'"..==iHO!%!1!1!@!@!N"'999O$)*+q0#A&*<Q*??t  vE  uF  FJ  K]  J^  _ 4#3#3#A#A)#Y#Yop  pA  AE  FJ  FV  FV  Fe  Fe  fq  Fr  Es  t #zz<<=R=X=XYZ=[\'3/C/I/I+Ja+OKKcd#'::#@#@AZA`A`abAc#d $,+112a7$**1-1I1O1OPQ1RRKKgh&*jj&C&CD\DbDbcdDe&f#'/.445:(..q15L5R5RST5UUjk  %%a(,D,J,J1,MMNN()>)D)DQ)G(HPdPjPjklPmOn  oM  Ng  Nm  Nm  no  Np  Mq  qx  yQ  yW  yW  XY  yZ  x[  \ #))!,0G0M0Ma0PP,-B-H-H-K,LGThTnTnopTqSr  sP  Qi  Qo  Qo  pq  Qr  Ps  sz  {R  {X  {X  YZ  {[  z\  ] (--a04K4Q4QRS4TT01J1P1PQR1S0TT[\t\z\z{|\}[~  \  ]u  ]{  ]{  |}  ]~  \  F  G^  Gd  Gd  ef  Gg  Fh  i r   
input_namec                 2   SnU R                   R                  U5      nUbX  UR                  R                  R                  [
        R                  :w  a   U R                  R                  U5      u  pBXB4$ Un XB4$ U R                  R                  U5      u  pBXB4$ )ap  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_int32$FusionEmbedLayerNoMask.cast_to_int32  s     jj11*="++559J9JJ04

0N0Nz0Z- ,,	  * ,, -1JJ,J,J:,V)L,,r   rR   r~   rQ   r   r   c	                    / n	U R                  U5      u  pU R                  R                  S5      nUR                  S:X  a  UR                  S   nUR                  S   nOUR                  S   nUR                  S   nSnUbQ  U R                  UR                  S   5      u  pUUUR                  S   UR                  S   UR                  S   UU/nO#USUR                  S   UR                  S   SUU/nUb5  UR                  S5        U R                  U5      u  pjUR                  U5        US	-   US
-   /nU(       a  Ub  UOUS-   nUR                  U5        [        R                  " SUUUS9nSUl        UR                   H1  nUR                  S:X  d  M  UR                  R                  U/5        M3     [        UR                  5      S:X  a1  UR                  R                  [        R                  " SS5      /5        U	R                  U5        U	 H&  nU R                  U R                  UR                  '   M(     U R                   R                  U	5        UU l        U$ )a  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#   r3   rd   Nr    _output_dummy_mask_index_embedding_sum)outputsnamezcom.microsoftepsilong-q=)r   r   create_node_namer8   r9   appendr   	make_nodedomain	attributer   extendr;   make_attributethis_graph_namenode_name_to_graph_namenodes_to_addr   )r   rR   r)   r~   rQ   r   r   embedding_sum_outputembedding_sum_namer   rV   	node_namegammabetaembed_node_inputsr   embed_node_outputsr   r   attrA   s                        r   create_fused_node(FusionEmbedLayerNoMask.create_fused_node  sn   . )))4	JJ//0IJ	 44OOA&E??1%DOOA&E??1%D #/!//0H0N0Nq0QRNK %++A.)//2(..q1! %++A.)//2! #$$R("00>OL$$\2')3YAT5TU);)G%YYiMiD%%d+%%%&	

 ,
 &&Cxx9$$$++SE2 ' z##$)  '')>)>y')R(ST 	J' D6:6J6JD((3 !  .$r   c                 ~    U R                   R                  UR                  S   UR                  S   5        SU l        g )Nr   T)r   replace_input_of_all_nodesr6   prune_graph)r   r)   r   s      r   finish_fusion$FusionEmbedLayerNoMask.finish_fusion
  s5    

--i.>.>q.A:CTCTUVCWXr   c                     UR                   S:H  =(       a:    [        UR                  5      S:  =(       a    [        UR                  S   5      S:  $ )Nr   rd   r   )r8   r;   r6   )r   rA   s     r   "is_skip_layer_norm_with_sum_output9FusionEmbedLayerNoMask.is_skip_layer_norm_with_sum_output  sD     88nc$++>NQR>RnWZ[_[f[fgh[iWjmnWnnr   c                    U R                  U5      nUc  gUu  pxUR                  S   n	UR                  S   n
U R                  XSS9(       d  gU R                  US U5      (       d  gUR                  S:X  aV  U R                  U5      nSnUnU(       a  UR                  S   OS nUS L=(       a    U R                  R                  U5      S LnOUnUR                  S:X  a  SOSn[        UR                  5      U:  a  UR                  U   OS nUS L=(       a    U R                  R                  U5      S LnU=(       a    X;   =(       a    [        X>   5      S:  nUS L=(       a!    UR                  S:g  =(       d    U=(       d    UnU R                  U	UUUUU
UU(       a  UOS S9nU(       a?  S	UR                  U'   U(       d)  U R                  R                  UUR                  S
   5        U R                  UU5        g)NFr#   r+   r   rd   r0   r   )r   r   _no_use__to_be_removed_r3   T)r'   r9   rE   r   r8   r   r6   r   find_graph_outputr;   r   r   r   )r   r)   add_before_layernormr*   rS   optional_segment_gather
two_gatherr~   rQ   rR   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_gpt2 FusionEmbedLayerNoMask.fuse_gpt2  s&   ( **+?@
;E8)//2	066q9,,Y\a,b##$94AZ[[  88(,(O(OPY(Z% #, 0I))!,tJ#-T#9"u

@\@\]g@hpt@t#7 $8$@$@E$Iqq +2236FF %++,<= 
 $.T#9"u

@\@\]g@hpt@to
 AosK^KjGknoGo * *44)? )$,,5m9LmPm &
 ++!%#!:-@zd , 	

 %<U ''(89&

55j*BSBSTUBVW9j1r   c                 *   U R                  U5      nUc  gUu  pgUR                  S   nU R                  XSS9(       d  gU R                  XxU5      (       d  gU R	                  USU5      (       d  gU R                  XXgS5      n	U R                  X5        g)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'   r9   rE   ru   r   r   r   )
r   r)   r   r*   rS   r   r~   rQ   rR   r   s
             r   fuse_distilbert&FusionEmbedLayerNoMask.fuse_distilbertc  s    & **+?@
;E8)//2	,,Y\`,a,,-FSfgg##$94AZ[[++"7TX

 	91r   c                    U R                   R                  US/S/5      nUc  gU R                  US   5      nUc  gUu  pxUR                  S   n	U R	                  XSS9(       d  gU R                   R                  US/S/5      n
U
c  gU
S   nU R                  XU5      (       d  U R                  XU5      (       d  gUnUnUnU R                  XxU5      (       d  gU R                  U	UUUU5      nU R                  X5        g)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
r0   r   Fr#   r   r"   T)	r   r$   r'   r9   rE   ru   r   r   r   )r   r)   r   r*   rS   add_2_gatherr   r~   r   rR   position_embedding_pathrQ   tempr   s                 r   	fuse_bert FusionEmbedLayerNoMask.fuse_bert  s7    zz334H5'TUSVW**<?;
:D7)//2	,,Y\a,b"&**">">?SV^U_bcad"e"*$;A$>!,,-FSfgg001IVijj+D'@$(,%##$9Unoo++!%$

 	91r   c                 "   U R                   R                  US/S/5      nUR                  S:X  a  Uc  g US   nS nOU R                   R                  US/S/5      nU R                   R                  US/S/5      nUc  Ub  Uc  g US   nUS   nO8Ub1  Uc.  U R                   R                  US/S/5      nUc  g US   nUS   nOUnS nU R                  XX#U5      (       a  g U R	                  XX#5      (       a  g U R                  XX#5      (       a  g g )Nr0   r   r   r"   r#   )r   r$   r8   r   r   r   )	r   rA   r*   rS   first_add_pathr   r   r%   r&   s	            r   fuseFusionEmbedLayerNoMask.fuse  sJ   55dUGaSI<<//%#1!#4 &*# JJ88zA3OM JJ88zA3OM$)B!)'5a'8$*7*:'*}/D!%!=!=dUGaS!Q!)'5a'8$*7*:''+$*.'>>(;Ri
 
 <Oee>>$6I__ `r   )r   r:   r   r   r   r   r   )zno mask)NFN)N)__name__
__module____qualname____firstlineno____doc__r	   strr   r   tupler'   dictlistboolrE   r[   r`   rr   ru   r   r   r   r   r   r   r   r   r   __static_attributes____classcell__r   s   @r   r   r      sL   
i c  	2I 	2$y)?S9T2T 	2RR "#tI"67R 	R
 
Rh<|-^F+PHT- -c4);K6K0L -< $("`` `  )	`
 $-` #'"2` Dj`D 
o rvOb'R0d" "r   r   c                   F   ^  \ rS rSrSS\4U 4S jjjrS rU 4S jrSrU =r	$ )FusionEmbedLayerNormalizationi  r   c                 2   > [         TU ]  US5        X l        g )Nz	with mask)r   r   use_mask_index)r   r   r   r   s      r   r   &FusionEmbedLayerNormalization.__init__  s    ,,r   c                    U R                   n[        UR                  5      S:X  a<  UR                  R                  U5        [        R                  SUR                  5        O}[        UR                  5      S:  aC  UR                  S   (       d/  XR                  S'   [        R                  SUR                  5        O![        R                  SUR                  5        g U H  n[        R                  SUR                  5        UR                  S:X  a  UR                  S   UR                  S'   MQ  UR                  S	:X  d  Mc  UR                  S   UR                  S
'   M     g )N   zappend mask to %szreplace mask in %szskip mask in %szupdate mask_index in %sr-   r#   rd   r1   re   )	r   r;   r9   r   r<   r=   r   r8   r6   )r   
mask_int32attention_nodesr   attention_nodes        r   replace_mask*FusionEmbedLayerNormalization.replace_mask  s    __
z A%##J/LL,joo>!!"Q&z/?/?/B",QLL-z?LL*JOO<-NLL2N4G4GH%%4*4*;*;A*>$$Q'''+??*4*;*;A*>$$Q' .r   c                   > S U l         S U l        S U l        [        TU ]  XU5        U R                  c  g U R
                  (       d'  [        R                  S5        U R                  S5        g U R                   c4  U R                  c'  [        R                  S5        U R                  S5        g U R                   (       a  U R                   R                  S   nOU R                  R                  S   nX$   nU R                  R                  U5      (       aF  U Vs/ s H  oR                  S;   d  M  UPM     nnU R                  XF5        U R                  S5        g XC;  a(  [        R                  SU5        U R                  S5        g X4   nUR                  S	;   a  U Vs/ s H  oR                  S;   d  M  UPM     nnWR                  S
:X  aB  UR                  S   n[        U5      [        U5      :X  a  U R                  R!                  U5        U R                  XF5        U R                  S5        g g s  snf s  snf )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 foundrd   re   )r-   r1   z"EmbedLayerNormalization(with mask)zHEmbedLayerNormalization will not have mask since %s is not a node output)	ReduceSumrM   r   r   )r   r:   r   r   r   r   r<   r=   increase_counterr9   r   r   r8   r   r;   nodes_to_remover   )r   rA   r*   rS   r   children_nodesr   r   s          r   r   "FusionEmbedLayerNormalization.fuse  s   #T0CD??"""LLbc!!"DE>>!d&:&:&BLLgh!!"DE>>--a0J--33A6J,8::&&z220>v,,RuButOvj:!!"FG0LLceop!!"DE".<<000>v,,RuButOv||{*!ZZ]
~&#o*>>((//5j:!!"FG 1 w ws   H61H6!H;8H;)r   r:   r   r   )F)
r   r   r   r   r	   r   r   r   r   r   r   s   @r   r   r     s%    -i - -?*-H -Hr   r   N)loggingr   fusion_baser   fusion_utilsr   onnxr   r   r   
onnx_modelr	   r   r<   r   r   r^   r   r   <module>r      sC      $ / /  	8	PV PfGH$: GHr   