o
    3Ih(                     @  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                      sF   e Zd Zd fddZdddZdddZdddZdddZ  ZS )
FusionGelumodelr   c                   s   t  |dd d S )NGeluErf)super__init__)selfr   	__class__ l/home/air/sanwanet/gpt-api/venv/lib/python3.10/site-packages/onnxruntime/quantization/fusions/fusion_gelu.pyr      s   zFusionGelu.__init__erf_nodeonnx.NodeProtoinput_name_to_nodesdict[str, list[onnx.NodeProto]]output_name_to_nodedict[str, onnx.NodeProto]c                 C  s@   |  |||s| |||s| |||r| jdd dS 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   set_opset_import)r   r   r   r   r   r   r   fuse   s   zFusionGelu.fusereturnboolc                 C  s  |j d |vr	dS ||j d  }t|dks|d jdkrdS |d }| |ds+dS |j d |vr4dS ||j d  }t|dksH|d jdkrJdS |d }| |dd|}|du r\dS | j|dd	d
dkrhdS |jd }|jd |j d krydnd}	||j|	 kr||j d  }t|dks|d jdkrdS |d }
| |
dsdS |
j d }n"| |d|	|}
|
du rdS | |
dsdS ||
jv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_inputanothermul_halfsubgraph_outputsubgraph_nodes
fused_noder   r   r   r   #   s^   


zFusionGelu.fuse_1c                 C  s  |j d |vr	dS ||j d  }t|dks|d jdkrdS |d }| |ds+dS |j d |vr4dS ||j d  }t|dksH|d jdkrJdS |d }| |dsVdS |j d |vr_dS ||j d  }t|dkss|d jdkrudS |d }| |dd|}|du rdS d}	| j|d	d
ddkr| |dd|}	|	du rdS | |	dsdS |jd }
|
|jvrd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%   Sqrtg       @r	   r(   r   T)r-   r.   r/   r0   r1   r2   r3   r=   r4   r5   r6   r7   r8   r9   r:   r;   r<   )r   r   r   r   r>   r?   r@   mulrA   	sqrt_noderB   rF   rG   r   r   r   r   z   s^   


zFusionGelu.fuse_2c                 C  s  |j d |vr	dS ||j d  }t|dks|d jdkrdS |d }| |ds+dS |j d |vr4dS ||j d  }t|dksH|d jdkrJdS |d }| |dsVdS | |dd|}|du rddS | j|dd	d
}|dk rrdS d| }	|j|	 }
|j d |vrdS ||j d  }t|dks|d jdkrdS |d }|jd |
ks|jd |
ksd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   r>   r?   rD   	first_muliroot_input_indexrB   last_mulrF   rG   r   r   r   r      s^   

zFusionGelu.fuse_3)r   r   )r   r   r   r   r   r   )r   r   r   r   r   r   r   r   )	__name__
__module____qualname__r   r   r   r   r   __classcell__r   r   r   r   r      s    


WLr   )
__future__r   r7   
onnx_modelr   fusionr   r   r   r   r   r   <module>   s
   