o
    ;ήcK                     @   s<  d dl mZ d dlmZmZ d dlmZmZ d dlm	Z	 d dl
mZ d dlmZ d dlmZ d dlmZ d d	lmZmZ d d
lmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlm Z  d dl!m"Z" d dl#m$Z$m%Z% d dl&m'Z' d dl(m)Z)m*Z*m+Z+m,Z,m-Z- d dl.m/Z/ ee0Z1G dd deZ2G dd de/Z3dS )    )	getLogger)ListOptional)AttentionMaskFusionAttention)FusionBiasGelu)FusionEmbedLayerNormalization)FusionFastGelu)
FusionGelu)FusionGeluApproximation)FusionLayerNormalizationFusionLayerNormalizationTF)FusionOptions)FusionQOrderedAttention)FusionQOrderedGelu) FusionQOrderedLayerNormalization)FusionQOrderedMatMul)FusionReshape)FusionShape) FusionBiasSkipLayerNormalizationFusionSkipLayerNormalization)FusionUtils)
GraphProto
ModelProtoTensorProtoValueInfoProtohelper)	OnnxModelc                       s    e Zd ZdZ fddZ  ZS )BertOptimizationOptionszThis class is deprecatedc                    s   t d t | d S )NzIBertOptimizationOptions is depreciated. Please use FusionOptions instead.)loggerwarningsuper__init__)self
model_type	__class__ O/tmp/pip-target-vg8gfxp4/lib/python/onnxruntime/transformers/onnx_model_bert.pyr"   "   s   
z BertOptimizationOptions.__init__)__name__
__module____qualname____doc__r"   __classcell__r'   r'   r%   r(   r      s    r   c                       s"  e Zd ZdAdededef fddZdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdedee defd d!Zdefd"d#Zejfd$ed%ed&efd'd(Zd)d* ZdBd-d.Zd/d0 Zd1d2 Zd3d4 Zd5d6 Z dCd9e!e" d:efd;d<Z#d=d> Z$d?d@ Z%  Z&S )DBertOnnxModelr   model	num_headshidden_sizec                    s   |dkr|dks|dkr|| dksJ t  | || _|| _t| | _t| | j| j| j| _t| | j| j| j| _	t
| | _dS )aG  Initialize BERT ONNX Model.

        Args:
            model (ModelProto): the ONNX model
            num_heads (int, optional): number of attention heads. Defaults to 0 (detect the parameter automatically).
            hidden_size (int, optional): hidden dimension. Defaults to 0 (detect the parameter automatically).
        r   N)r!   r"   r0   r1   r   attention_maskr   attention_fusionr   qordered_attention_fusionr   utils)r#   r/   r0   r1   r%   r'   r(   r"   (   s   (
zBertOnnxModel.__init__c                 C   s   | j   | j  d S N)r3   applyr4   r#   r'   r'   r(   fuse_attention=   s   
zBertOnnxModel.fuse_attentionc                 C   4   t | }|  t| }|  t| }|  d S r6   )r
   r7   r	   r   r#   fusionr'   r'   r(   	fuse_geluB   s   zBertOnnxModel.fuse_geluc                 C   s   t | |}|  d S r6   )r   r7   )r#   is_fastgelur<   r'   r'   r(   fuse_bias_geluK   s   
zBertOnnxModel.fuse_bias_geluc                 C      t | }|  d S r6   )r   r7   r;   r'   r'   r(   gelu_approximationO      z BertOnnxModel.gelu_approximationc                 C   r@   r6   )r   r7   r;   r'   r'   r(   fuse_add_bias_skip_layer_normS   rB   z+BertOnnxModel.fuse_add_bias_skip_layer_normc                 C   r@   r6   )r   r7   r;   r'   r'   r(   fuse_reshapeW   rB   zBertOnnxModel.fuse_reshapec                 C   r@   r6   )r   r7   r;   r'   r'   r(   
fuse_shape[   rB   zBertOnnxModel.fuse_shapec                 C   r@   r6   )r   r7   r;   r'   r'   r(   fuse_embed_layer_   rB   zBertOnnxModel.fuse_embed_layerc                 C   r:   r6   )r   r7   r   r   r;   r'   r'   r(   fuse_layer_normc   s   zBertOnnxModel.fuse_layer_normc                 C   r@   r6   )r   r7   r;   r'   r'   r(   fuse_skip_layer_normn   rB   z"BertOnnxModel.fuse_skip_layer_normc                 C   r@   r6   )r   r7   r;   r'   r'   r(   fuse_qordered_mamtuls   rB   z"BertOnnxModel.fuse_qordered_mamtulop_typeinput_indicescastedc           
         s   g }|   }| |}|D ]>  fdd|D }|D ]0}| |r)|s(|| q||v rJ|| }	|	jdkrJ| |	jd durJ|rJ||	jd  qq|S )z
        Get graph inputs that feed into node type (like EmbedLayerNormalization or Attention).
        Returns a list of the graph input names based on the filter whether it is casted or not.
        c                    s$   g | ]}|t  jk r j| qS r'   )leninput).0inoder'   r(   
<listcomp>   s   $ zABertOnnxModel.get_graph_inputs_from_node_type.<locals>.<listcomp>Castr   N)output_name_to_nodeget_nodes_by_op_typefind_graph_inputappendrJ   rN   )
r#   rJ   rK   rL   graph_inputsrU   nodesbert_inputs
bert_inputparentr'   rQ   r(   get_graph_inputs_from_node_typew   s$   


	z-BertOnnxModel.get_graph_inputs_from_node_typec                 C   s*   |  dg d|}||  ddg|7 }|S )NEmbedLayerNormalization)r         	Attention   )r^   )r#   rL   inputsr'   r'   r(   !get_graph_inputs_from_fused_nodes   s   z/BertOnnxModel.get_graph_inputs_from_fused_nodesgraphgraph_inputnew_typec                 C   sx  t |tsJ t |tsJ | |jsJ |jjjt|kr#dg fS d}g }| 	 }|j|v r||j }dd |D }|r}| 
d}	|	d |j }
|j }|| |
|_tjd|jg|
gt|jjj|	d}|j|g |D ]
}t||j|
 qrdd |D }|D ]#}t|dt|kr| |jd	 |j | |jd	 s|| q|r| | t||jj_||fS )
a  Change graph input type, and add Cast node if needed.

        Args:
            graph (GraphProto): graph
            graph_input (TensorProto): input of the graph
            new_type (int, optional): new data type. Defaults to TensorProto.INT32.

        Returns:
            NodeProto: a new Cast node that added. None if Cast node is not added.
            List[NodeProto]: Cast nodes that have been removed.
        Nc                 S   s   g | ]	}|j d kr|qS rT   rJ   rO   rR   r'   r'   r(   rS          z9BertOnnxModel.change_graph_input_type.<locals>.<listcomp>rT   _)tonamec                 S   s   g | ]	}|j d kr|qS ri   rj   rk   r'   r'   r(   rS      rl   rn   r   )
isinstancer   r   rW   ro   typetensor_type	elem_typeintinput_name_to_nodescreate_node_name
value_infoaddCopyFromr   	make_noderR   extendr   replace_node_inputget_node_attributereplace_input_of_all_nodesoutputfind_graph_outputrX   remove_nodes)r#   rf   rg   rh   new_cast_nodenodes_to_removeru   rZ   nodes_not_cast	node_nameoutput_namenew_value_inforR   
nodes_castr'   r'   r(   change_graph_input_type   sL   






z%BertOnnxModel.change_graph_input_typec                 C   sd   |   }d}d}|jD ]}| ||tj\}}|r|d7 }|t|7 }qtd| d| d dS )zPChange data type of all graph inputs to int32 type, and add Cast node if needed.r   r`   z)Graph inputs are changed to int32. Added z Cast nodes, and removed z Cast nodes.N)rf   rN   r   r   INT32rM   r   info)r#   rf   add_cast_countremove_cast_countrg   new_noderemoved_nodesr'   r'   r(   change_graph_inputs_to_int32   s   
z*BertOnnxModel.change_graph_inputs_to_int32
batch_sizemax_seq_lenc                 C   s   | j dd| j dd }i }| jjjD ]!}|j|v r4|jjjjd }||_	|dur4|jjjjd }||_	q| jjj
D ]}|jjjjd }||_	q:dS )zD
        Update input and output shape to use dynamic axes.
        T)rL   Fr   Nr`   )re   r/   rf   rN   ro   rq   rr   shapedim	dim_paramr   )r#   dynamic_batch_dimdynamic_seq_lenbert_graph_inputsdynamic_batch_inputsrN   	dim_protor   r'   r'   r(   use_dynamic_axes   s$   

zBertOnnxModel.use_dynamic_axesc                 C   s   |    d S r6   )adjust_reshape_and_expandr8   r'   r'   r(   
preprocess   s   zBertOnnxModel.preprocessc           
      C   s2  g }|   D ]}}|jdkr| |jd }|d ur1|jdkr1||g | |jd |jd  q| |g dg d| 	 }|d ur|d }| |jd }|d }| |jd }|d }	|d ur|d urt
|d	krt
|dkr|d |d kr|	jd |jd< q|r| | td
t
|  d S d S )NReshaper`   r   )Expandr   r   Slice)r   r   r   r      z"Removed Reshape and Expand count: )rZ   rJ   get_constant_valuerN   sizer{   r~   r   match_parent_pathrU   rM   r   r   r   )
r#   r   rR   reshape_shapereshape_pathexpand_nodeexpand_shape_valuereshape_before_expandshape_value
slice_noder'   r'   r(   r      sH   



z'BertOnnxModel.adjust_reshape_and_expandc                 C   sd  |   }g }|  D ]}dddd}|j|v rQ||j }| |g d|dddddg|}|d urQ|\}}}	}
}}|jd |  jd jkrQ|jd |jd< |   }|jdkr| |g dg d|}|d ur|d	 jd |  jd jkrtj	d|jdt
|jd  |j|jd
 d}d|_|jtd| jg | || |j || q
| | d S )Nr`   r   rc   )r_   	ReduceSumrb   )rT   ConstantOfShapeConcat	UnsqueezeGatherShaperb   )r   rT   r   r   )rc   r   r   r   r   _remove_mask)rd   outputsro   zcom.microsoftr0   )rU   rZ   rJ   r   rN   rf   ro   r   r   rz   rM   domain	attributer{   make_attributer0   add_nodeget_graph_by_noderX   r   )r#   rU   r   rR   op_input_idrP   parent_nodescastconstantOfShapeconcat	unsqueezegatherr   attention_noder'   r'   r(   clean_graph#  sZ   	



zBertOnnxModel.clean_graphc                 C   s   |    |   d S r6   )r   prune_graphr8   r'   r'   r(   postprocesse  rB   zBertOnnxModel.postprocessNFoptionsadd_dynamic_axesc                 C   sl  |d ur|j s|   | j  | j  |d u s|jr |   |d u s'|jr+|   | 	  | 
  |d u s:|jr>|   |d u sE|jrT|d urP| j|j |   |d u s[|jr_|   |   |d u sj|jrn|   | j  |   |d u s~|jr| jdd | jdd |d u s|jr|   |d ur|jr|   |   |r|    t!"d| #   d S )NT)r>   Fzopset version: )$enable_shape_inferencedisable_shape_inferencer5   remove_identity_nodesremove_useless_cast_nodesenable_layer_normrG   enable_gelur=   r   rD   enable_skip_layer_normrH   enable_attentionr2   set_mask_formatattention_mask_formatr9   enable_qordered_matmulrI   rE   enable_embed_layer_normrF   remove_useless_reshape_nodesr   enable_bias_gelur?   enable_bias_skip_layer_normrC   enable_gelu_approximationrA   remove_unused_constantr   r   r   get_opset_version)r#   r   r   r'   r'   r(   optimizei  sD   


zBertOnnxModel.optimizec                 C   s@   i }g d}|D ]}|  |}t|||< qtd|  |S )z8
        Returns node count of fused operators.
        )r_   rb   QOrderedAttentionGeluQOrderedGeluFastGeluBiasGeluLayerNormalizationQOrderedLayerNormalizationSkipLayerNormalizationQOrderedMatMulzOptimized operators:)rV   rM   r   r   )r#   op_countopsoprZ   r'   r'   r(   get_fused_operator_statistics  s   
z+BertOnnxModel.get_fused_operator_statisticsc                 C   s   |   }|d }|d |d  }|d |d  |d  }|d |d  }|d	ko5|d	ko5||ko5|d
| k}|d	kr?td |d	krHtd |d	krQtd |d	krZtd |S )zA
        Returns True when the model is fully optimized.
        r_   rb   r   r   r   r   r   r   r   r   zLayer Normalization not fusedzGelu/FastGelu not fusedzEmbed Layer not fusedzAttention not fused)r   r   debugr    )r#   r   embed	attentiongelu
layer_norm
is_perfectr'   r'   r(   is_fully_optimized  s   $



z BertOnnxModel.is_fully_optimized)r   r   )r   r   )NF)'r)   r*   r+   r   rt   r"   r9   r=   r?   rA   rC   rD   rE   rF   rG   rH   rI   strr   boolr^   re   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r-   r'   r'   r%   r(   r.   '   s@    		
A
)B?r.   N)4loggingr   typingr   r   fusion_attentionr   r   fusion_biasgelur   fusion_embedlayerr   fusion_fastgelur	   fusion_gelur
   fusion_gelu_approximationr   fusion_layernormr   r   fusion_optionsr   fusion_qordered_attentionr   fusion_qordered_gelur   fusion_qordered_layernormr   fusion_qordered_matmulr   fusion_reshaper   fusion_shaper   fusion_skiplayernormr   r   fusion_utilsr   onnxr   r   r   r   r   
onnx_modelr   r)   r   r   r.   r'   r'   r'   r(   <module>   s.   