o
    )wiO                     @   sp   d dl mZ d dlmZ d dlmZmZ d dlmZ ee	Z
G dd deZG dd deZG d	d
 d
eZdS )    )	getLogger)Fusion)TensorProtohelper)	OnnxModelc                       s>   e Zd Zddededef fddZded	efd
dZ  ZS )FusionLayerNormalizationTFmodelcheck_constant_and_dimensionforcec                    s    t  |dd || _|| _d S NLayerNormalization
ReduceMean)super__init__r	   r
   )selfr   r	   r
   	__class__ f/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/onnxruntime/transformers/fusion_layernorm.pyr      s   
z!FusionLayerNormalization.__init__input_name_to_nodesoutput_name_to_nodec              	   C   s  g }| j ||}t|dkst|dkrdS |jd }|d jdks,|d jd |kr.dS t|dkrF|d jdksD|d jd |krFdS d}|D ]'}| j j|d|dd}	|	dur^|	} n| j |d	dg}
|
durq|
d
 } nqJ|du rxdS | j |g dg dfg dg dfg|\}}}|du rdS |d
 }||vrdS |d }| j |\}}|du s|dks|dkrt	
d|  dS |d }| j |ddkrdS |jd |vrdS ||jd  }|D ]}|jd	kr|| |jd |vrq||jd  d }n|}|jdkrq|jd |vrq||jd  d }|jdkr%q|| || ||dd
  ||||g |jd	krH|n|}|jd| j |jd |  }| jrg| j |ddsgq|jd| j |jd |  }| jr| j |ddsq|jd }| j ||j||s| jrd| _nt	
d q| j| tjd|jd ||g|g| j jdddd}|jtdt|g | j| | j| j|j< qdS )a  
        Fuse Layer Normalization subgraph into one node LayerNormalization:
              +----------------------+
              |                      |
              |                      v
          [Root] --> ReduceMean -->  Sub  --> Pow --> ReduceMean --> Add --> Sqrt --> Div --> Mul --> Add
                     (axis=2 or -1)  |      (Y=2)   (axis=2 or -1)  (B=E-6 or E-12)    ^
                                     |                                                 |
                                     +-------------------------------------------------+

         It also handles cases of duplicated sub nodes exported from older version of PyTorch:
              +----------------------+
              |                      v
              |           +-------> Sub-----------------------------------------------+
              |           |                                                           |
              |           |                                                           v
          [Root] --> ReduceMean -->  Sub  --> Pow --> ReduceMean --> Add --> Sqrt --> Div  --> Mul --> Add
              |                      ^
              |                      |
              +----------------------+
        r      NSub   DivF	recursiveCastSqrtAddr   Powr   r   r   r   r   r   )r    r!   r   r"   r   r   )r   r   r   r   r   r   -C6?Hskip SkipLayerNormalization fusion since epsilon value is not expected:           @Mulr!   layernorm weightlayernorm biasT4It is not safe to fuse LayerNormalization node. Skipr   	LayerNormname_prefixinputsoutputsnameepsilon) r   get_childrenleninputop_typefind_first_child_by_typematch_child_pathmatch_parent_pathsget_constant_inputloggerdebugfind_constant_inputoutputappendextendinput_indexr	   $is_constant_with_specified_dimensionis_safe_to_fuse_nodesr
   prune_graphnodes_to_remover   	make_nodecreate_node_name	attributemake_attributefloatnodes_to_addthis_graph_namenode_name_to_graph_namer2   )r   noder   r   subgraph_nodeschildren
root_inputdiv_nodechild
div_node_1
div_node_2_path_idparent_nodes_sub_nodeadd_eps_nodeir3   pow_nodediv_children	temp_nodemul_nodelast_add_nodenode_before_weightweight_input
bias_inputlayer_norm_outputnormalize_noder   r   r   fuse   s   
  




	
zFusionLayerNormalization.fuse)TF)	__name__
__module____qualname__r   boolr   dictrg   __classcell__r   r   r   r   r      s    r   c                       sT   e Zd Zdef fddZdd Zddedee fd	d
Z	de
de
fddZ  ZS )FusionLayerNormalizationNCHWr   c                    s   t  |dd d S r   r   r   r   r   r   r   r   r      s   z%FusionLayerNormalizationNCHW.__init__c                 C   s   | j |}|d u rt| d| d d S t|jdks,|jd dks,|jd dkr<t| d| d|j  d S ||jd gS )N z is not initializer.r&   r   r   z* shall have 3 dimensions Cx1x1. Got shape r   )r   get_constant_valuer<   r=   r5   shapereshape)r   output_namedescriptionvaluer   r   r   get_weight_or_bias   s   *z/FusionLayerNormalizationNCHW.get_weight_or_biasN
input_namepermc                 C   sT   | j d}|du r|d d | }tjd|g|g|d}|jtd|g |S )z&Append a Transpose node after an input	TransposeN_out-r/   rz   )r   rH   r   rG   rI   rA   rJ   )r   ry   rz   ru   	node_nametranspose_noder   r   r   create_transpose_node   s   z2FusionLayerNormalizationNCHW.create_transpose_noder   r   c           !      C   s  t |d}t|tr|dgkrdS g }| j||}t|dkr#dS |jd }|d jdks8|d jd |kr:dS |d }| jj	|d|dd}	|	du rNdS | j
|	g d	g d
|}
|
du radS |
\}}}}}||krndS | j|\}}|du s|dks|dkrtd|  dS t |d}t|tsJ |dgkrdS | j|ddkrdS ||	jd  d }|}|jdkrdS ||jd  d }|jdkrdS || ||
 ||||	g | j||j||std dS |jdkr|	n|}|jd| j|jd |  }| |d}|du rdS |jd| j|jd |  }| |d}|du r1dS t|d tj|j|}t|d tj|j|}| j|| j | j|| j | j| | |jd g d}| jjddd}| |d g d|jd }tjd|jd |d |d g|d g|d}|j t!dt"|g | j#| | j#| | j#| | j| j$|j%< | j| j$|j%< | j| j$|j%< d} | &|  dS )a*  
        Fuse Layer Normalization subgraph into one node LayerNormalization:
              +----------------------+
              | NxCxHxW              |
              |                      v                                                     (Cx1x1)  (Cx1x1)
          [Root] --> ReduceMean -->  Sub --> Pow --> ReduceMean --> Add --> Sqrt --> Div --> Mul --> Add -->
                     (axes=1)        |      (Y=2)     (axes=1)     (E-6)             ^
                                     |                                               |
                                     +-----------------------------------------------+

        Fused subgraph:
                       (0,2,3,1)                            (0,3,1,2)
            [Root] --> Transpose --> LayerNormalization --> Transpose -->
        axesr   Nr   r   r   Fr   r   r#   r$   r%   r'   r(   r!   r+   r   r)   r*   _NHWC)r   r   r&   r   r   r,   r-   	_out_nhwc)r   r&   r   r   r/   r3   zLayerNormalization(NHWC))'r   get_node_attribute
isinstancelistr   r4   r5   r6   r7   r8   match_parent_pathr;   r<   r=   r>   r?   r@   rA   rD   rB   rx   r   make_tensorr   FLOATrs   add_initializerrM   rF   r   rH   rG   rI   rJ   rK   rL   rN   r2   increase_counter)!r   rO   r   r   r   rP   rQ   rR   subrS   rX   
_sqrt_nodesecond_add_nodereduce_mean_noder]   rZ   r\   r3   r_   r`   ra   rb   rc   weightrd   biasweight_nhwc	bias_nhwctranspose_inputlayernorm_node_nametranspose_outputrf   counter_namer   r   r   rg      s   
 







z!FusionLayerNormalizationNCHW.fuse)N)rh   ri   rj   r   r   rx   strr   intr   rl   rg   rm   r   r   r   r   rn      s
    rn   c                       s4   e Zd Zdef fddZdedefddZ  ZS )FusionLayerNormalizationTFr   c                    s   t  |ddd d S )Nr   r!   TFro   rp   r   r   r   r   G  s   z#FusionLayerNormalizationTF.__init__r   r   c                 C   s(  g }| j |g dg dfg dg dfg|\}}}|du r!dS t|dks)J |d dv r;|d	 dv r;|d
 dv sBtd dS |dd \}}}	}
}}|dd \}}}}d}t|dkrk|d }|jdkskJ | j |dd|}|du rtd dS | j |d|}|du r|n| j |d|}|du rtd dS | j |\}}|du s|dks|dkr|du rtd dS |du r|j	d |j	vs|j	d |j	vrtd dS |dur|j	d |j	vs|j	d |j	vrtd dS |j	d |j	d	 krtd dS ||||	|
|||||||g}|dur7| j |dd|}|du r/td dS |
|||g | j ||j| j  | j  sOtd dS | j
| |	j	d	 }|j	d }tjd|j	d ||g|jd g| j jdddd}|j
tdt|g | j| | j| j|j< dS )aU  
         Layer Norm from Tensorflow model(using keras2onnx or tf2onnx):
          +------------------------------------+
          |                                    |
          |                                    |
        (Cast_1)                               |
          |                                    |
          |                                    v                                           (B)                             (B)             (A)
         Add --> (Cast_1) --> ReduceMean -->  Sub  --> Mul --> ReduceMean --> (Cast_3) --> Add --> Sqrt --> Reciprocol --> Mul --> Mul --> Sub --> Add
          |                       |                                                                                         |       ^              ^
          |                       |                                                                                         |       |              |
          |                       +--------------------------------------------------(Cast_2)-------------------------------|-------+              |
          |                                                                                                                 v                      |
          +---------------------------------------------------------------------------------------------------------------> Mul--------------------+
        )
r   r(   r(   
Reciprocalr    r!   r   r(   r   r   )
r   r   Nr   r   r   Nr   r   N)r   r(   r(   r   r    r!   r   r   r(   r   r   )r   r   Nr   r   r   r   Nr   r   NNr&   r   )r   r   r   r   z=return indice is exepected in [0, 1], but got {return_indice}      r   r(   zmul_node_3 not foundzroot node is nonegh㈵>zepsilon is not matchedz;reduce_mean_node_1 and mul_node_3 shall link from root nodez%mul_node_2 shall have two same inputszcast_node_2 not foundz$not safe to fuse layer normalizationr   r,   r-   r/   r3   )r   r:   r5   r<   r=   r7   match_parent
get_parentr;   r6   rA   rD   r?   r   r   rF   r   rG   rH   rI   rJ   rK   rL   r@   rM   rN   r2   )r   rO   r   r   return_indicerY   rX   
sub_node_0
mul_node_0
mul_node_1reciprocol_node	sqrt_node
add_node_0reduce_mean_node_0
mul_node_2
sub_node_1reduce_mean_node_1cast_node_3
mul_node_3node_before_reduce	root_noder\   r3   rP   cast_node_2rc   rd   
fused_noder   r   r   rg   J  s   !
&$

	

 
 
 








zFusionLayerNormalizationTF.fuse)rh   ri   rj   r   r   rl   rg   rm   r   r   r   r   r   F  s    r   N)loggingr   fusion_baser   onnxr   r   
onnx_modelr   rh   r<   r   rn   r   r   r   r   r   <module>   s     