U
    U?h(                     @  s@   d dl mZ d dlZddlmZ ddlmZ G dd deZdS )	    )annotationsN   )	ONNXModel   )Fusionc                      sp   e Zd Zdd fddZddddd	d
ZdddddddZdddddddZdddddddZ  ZS )
FusionGelur   )modelc                   s   t  |dd d S )NGeluZErf)super__init__)selfr   	__class__ ^/var/www/html/venv/lib/python3.8/site-packages/onnxruntime/quantization/fusions/fusion_gelu.pyr      s    zFusionGelu.__init__zonnx.NodeProtozdict[str, list[onnx.NodeProto]]zdict[str, onnx.NodeProto])erf_nodeinput_name_to_nodesoutput_name_to_nodec                 C  s<   |  |||s*| |||s*| |||r8| jdd dS )z
        Interface function that tries to fuse a node sequence containing an Erf node into a single
        Gelu node.
        com.microsoftr   N)fuse_1fuse_2fuse_3r   Zset_opset_import)r   r   r   r   r   r   r   fuse   s    zFusionGelu.fusebool)r   r   r   returnc                 C  s
  |j d |krdS ||j d  }t|dks:|d jdkr>dS |d }| |dsVdS |j d |krhdS ||j d  }t|dks|d jdkrdS |d }| |dd|}|dkrdS | j|dd	d
dkrdS |jd }|jd |j d krdnd}	||j|	 kr\||j d  }t|dks2|d jdkr6dS |d }
| |
dsPdS |
j d }nJ| |d|	|}
|
dkrzdS | |
dsdS ||
jkrdS |j d }|||||
g}| ||g||sdS | j	| t
jjd|  |g|gd}d|_| j| dS )ay  
        This pattern is from PyTorch model
        Fuse Gelu with Erf into one node:
        Pattern 1:
                       +-------Mul(0.5)---------------------+
                       |                                    |
                       |                                    v
                    [root] --> Div -----> Erf  --> Add --> Mul -->
                              (B=1.4142...)       (1)

        Pattern 2:
                       +------------------------------------+
                       |                                    |
                       |                                    v
                    [root] --> Div -----> Erf  --> Add --> Mul -->Mul -->
                              (B=1.4142...)       (1)            (0.5)

        Note that constant input for Add and Mul could be first or second input: like either A=0.5 or B=0.5 is fine.
        r   Fr   AddMulDivN-?MbP?delta      ?r	   nameinputsoutputsr   Toutputlenop_typehas_constant_inputmatch_parentfind_constant_inputinputis_safe_to_fuse_nodesnodes_to_removeextendonnxhelper	make_nodecreate_unique_node_namedomainnodes_to_addappend)r   r   r   r   childrenadd_after_erfmul_after_erfdivsubgraph_inputZanothermul_halfZsubgraph_outputsubgraph_nodes
fused_noder   r   r   r   #   sd    


   zFusionGelu.fuse_1c                 C  s  |j d |krdS ||j d  }t|dks:|d jdkr>dS |d }| |dsVdS |j d |krhdS ||j d  }t|dks|d jdkrdS |d }| |dsdS |j d |krdS ||j d  }t|dks|d jdkrdS |d }| |dd|}|dkrdS d}	| j|d	d
ddkrZ| |dd|}	|	dkrHdS | |	dsZdS |jd }
|
|jkrtdS |||||g}|	r||	 | ||j d g||sdS | j	
| tjjd|  |
g|j d gd}d|_| j| dS )a&  
        This pattern is from Keras model
        Fuse Gelu with Erf into one node:
                       +------------------------------------------+
                       |                                          |
                       |                                          v
                    [root] --> Div -----> Erf  --> Add --> Mul -->Mul
                              (B=1.4142...)       (A=1)   (A=0.5)

        Note that constant input for Add and Mul could be first or second input: like either A=0.5 or B=0.5 is fine.
        r   Fr   r   r   r"   r   Nr   r   r    ZSqrtg       @r	   r#   r   T)r(   r)   r*   r+   r,   r-   r.   r8   r/   r0   r1   r2   r3   r4   r5   r6   r7   )r   r   r   r   r9   r:   r;   mulr<   Z	sqrt_noder=   r?   r@   r   r   r   r   z   sd    



   
zFusionGelu.fuse_2c                 C  s  |j d |krdS ||j d  }t|dks:|d jdkr>dS |d }| |dsVdS |j d |krhdS ||j d  }t|dks|d jdkrdS |d }| |dsdS | |dd|}|dkrdS | j|dd	d
}|dk rdS d| }	|j|	 }
|j d |kr
dS ||j d  }t|dks6|d jdkr:dS |d }|jd |
ksf|jd |
ksfdS |||||g}| ||j d g||sdS | j	| t
jjd|  |
g|j d gd}d|_| j| dS )a?  
        This pattern is from TensorFlow model
        Fuse Gelu with Erf into one node:
                       +----------------------------------------------+
                       |                                              |
                       |                                              v
                    [root] --> Mul -----> Erf    -->   Add --> Mul -->Mul
                               (A=0.7071067690849304)  (B=1)  (B=0.5)

        Note that constant input for Add and Mul could be first or second input: like either A=0.5 or B=0.5 is fine.
        r   Fr   r   r   r"   Ng   `?r   r    r	   r#   r   Tr'   )r   r   r   r   r9   r:   r>   Z	first_muliZroot_input_indexr=   Zlast_mulr?   r@   r   r   r   r      sd    
 
   
zFusionGelu.fuse_3)	__name__
__module____qualname__r   r   r   r   r   __classcell__r   r   r   r   r      s
   WLr   )
__future__r   r2   Z
onnx_modelr   Zfusionr   r   r   r   r   r   <module>   s   