o
    eU                     @   s*  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	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mZmZ d dlmZ d dlZd dlmZ d dlZd dlmZ d dlZ d dl!Z!d dlZdZ"e #e$Z%G dd deZ&G dd deZ'G dd deZ(G dd de)Z*dS )    )	GraphNodeGraph)SymbolicShapeInference)ValidationError)check_model)helpershape_inference)get_attribute_valuemake_attribute)infer_shapes)TENSOR_TYPE_TO_NP_TYPE)to_array)AttributeProtoTensorProto
GraphProto)OrderedDictN)ValueInfoProto)deepcopyzai.onnxc                       sb   e Zd Zd fdd	Zdd Zdd Zedd	 Zed
d Zdd Z	dddZ
dddZ  ZS )ONNXGraphNodeNc                    sZ   |d u rt t| ||j n	t t| || |j| _|  | _t | _	d | _
i | _d S N)superr   __init__nameop_type
layer_typeget_attr_mapattr_maplist
out_shapesdtypewhich_child)selflayer
layer_name	__class__ MD:\Projects\ConvertPro\env\Lib\site-packages\x2paddle/decoder/onnx_decoder.pyr   '   s   

zONNXGraphNode.__init__c                 C   s8   d}t t| jjD ]}|| jj| kr|} |S q
|S )zl
        get the index of input_name in layer.input
        -1 means input_name is not in the input
        )rangelenr"   input)r!   
input_nameindexir&   r&   r'   get_input_index2   s   zONNXGraphNode.get_input_indexc                    s    fdd j jD S )z6
        convert ONNX node attributes to dict
        c                    s   i | ]	}|j  |qS r&   )r   r	   ).0attrr!   r&   r'   
<dictcomp>B   s    z.ONNXGraphNode.get_attr_map.<locals>.<dictcomp>)r"   	attributer2   r&   r2   r'   r   >   s   
zONNXGraphNode.get_attr_mapc                 C   s*   d| j v s	J dd| jvrd S | jd S )NConstantz/Only Constant | ConstantOfShape node has value.value)r   r   r2   r&   r&   r'   r6   G   s   

zONNXGraphNode.valuec                 C   s    t | drd| j| jS | jS )Nr-   z{}_p{})hasattrformatr#   r-   r2   r&   r&   r'   r   N   s   
zONNXGraphNode.namec                 C   s   |j tjjkr#tt|jj }|jj	}tj
||t||j d}|S |j tjjkr<|j}t|tr8| }|S |}|S t|}|S )z.
        get_attribute_value enhanced
        )r   count)typeonnxr   ZTENSORnpr   r   t	data_typeraw_dataZ
frombufferr*   itemsizeSTRINGs
isinstancebytesdecoder	   )r!   r1   r   datar6   r&   r&   r'   r	   T   s   z!ONNXGraphNode.get_attribute_valuec                 C   s   || j vr|S | j | S )z3
        get_attribute_value from attr_map
        )r   )r!   r   defaultr&   r&   r'   get_attrd   s   

zONNXGraphNode.get_attrr   c                 C   s@   |dkrt | jj|krtd| jt | jj|| jj| S )Nr   z+Output numbers of Node:{} is {} <= index:{})r*   r"   output
IndexErrorr8   r#   )r!   r-   r&   r&   r'   rI   l   s   zONNXGraphNode.outputr   )r   )__name__
__module____qualname__r   r/   r   propertyr6   r   r	   rH   rI   __classcell__r&   r&   r$   r'   r   &   s    	


r   c                       sB   e Zd Zd fdd	Zedd Zedd Zed	d
 Z  ZS )ONNXGraphDataNodeNFc                    s^   |d u rt t| ||j n	t t| || |rd| _nd| _|| _d | _d | _i | _d S )NZplace_holderZcreate_parameter)	r   rP   r   r   r   r#   weight
embeded_asr    )r!   r"   r#   is_global_inputr$   r&   r'   r   u   s   
zONNXGraphDataNode.__init__c                 C   s   t | jtr0| jjjjj}t }t }|D ]}|jdkr"|	d q|	|j q|	| |S t | jt
r[| jj}t }t }|D ]}|dkrN|	d qB|	| qB|	| |S | jj}t }|	| |S )Nr   r(   )rC   r"   r   r:   tensor_typeshapedimr   	dim_valueappendr   dims)r!   valuesr   rU   rV   r&   r&   r'   r      s0   



zONNXGraphDataNode.out_shapesc                 C   s   | j S r   )r#   r2   r&   r&   r'   r      s   zONNXGraphDataNode.namec                 C   s0   t | jtr| jjjj}t| S | jj}t| S r   )rC   r"   r   r:   rT   	elem_typer   r>   )r!   r   r&   r&   r'   r      s
   zONNXGraphDataNode.dtype)NF)	rK   rL   rM   r   rN   r   r   r   rO   r&   r&   r$   r'   rP   t   s    

rP   c                       s   e Zd Zd fdd	Zdd Zdd Zdd	 Zd
d Zdd Z fddZ	dd Z
d fdd	Zdd Zdd Zdd Z  ZS )	ONNXGraphNc                    s   t t| | i | _|d ur!t| D ]\}}|| jd| < qi | _t | _i | _	|j
| _
|   td ztj|| jd| _
W n   td t|}|j
| _
Y td |   |   |   d| _d S )N	x2paddle_zShape inferencing ...)fixed_input_shapez4[WARNING] Shape inference by ONNX offical interface.zShape inferenced.Z	ONNXModel)r   r\   r   r^   evalitemsinitializerr   place_holder_nodesvalue_infosgraphget_place_holder_nodesprintr   r   r   buildcollect_value_infosallocate_shapesZ
graph_name)r!   
onnx_modelinput_shape_dictkvr$   r&   r'   r      s0   


zONNXGraph.__init__c                 C   sB   g }t | jtjstd dS | jjD ]
}|j}|| q|S )z3
        generate inner node of ONNX model
        "graph is not a GraphProto instanceN)	rC   rd   r;   r   loggererrorra   r   rX   )r!   inner_nodesra   r   r&   r&   r'   get_inner_nodes   s   
zONNXGraph.get_inner_nodesc                 C   s6   g }|D ]}| dr||j q||j q|S )N	dim_param)ZHasFieldrX   rs   rW   )r!   rY   rU   rV   r&   r&   r'   get_symbolic_shape   s   
zONNXGraph.get_symbolic_shapec                 C   s2   |   }| jjD ]}|j|vr| j|j qdS )z:
        generate place_holder node of ONNX model
        N)rr   rd   r+   r   rb   rX   )r!   rq   Zipt_vir&   r&   r'   re      s   
z ONNXGraph.get_place_holder_nodesc                 C   s   dd | j jD | _dS )z:
        generate output_nodes node of ONNX model
        c                 S      g | ]}|j qS r&   r   )r0   r6   r&   r&   r'   
<listcomp>       z.ONNXGraph.get_output_nodes.<locals>.<listcomp>N)rd   rI   Zoutput_nodesr2   r&   r&   r'   get_output_nodes   s   zONNXGraph.get_output_nodesc                 C   s   || j v rdS dS )z:
        return layer is or not place_holder node
        TF)rb   )r!   r"   r&   r&   r'   is_place_holder_nodes   s   
zONNXGraph.is_place_holder_nodesc                    s&  | j jD ]}t|}|| j|j< q| j jD ]}|j| jvr/| |j}t||j|d| j|j< q| j jD ]9}|j}t	|}|| jv rWt
| j| trV|| j| _g | j| _q4t||dd| j|< || j| _g | j| _q4| j D ]\}}t
|tr| || qstt|   t| j| _dS )z/
        build topo_sort of ONNX model
        )r#   rS   FN)rd   noder   node_mapr   r+   rz   rP   ra   r   rC   rQ   rR   r`   build_connectionr   r\   rg   copyr   rb   Zinput_nodes)r!   r"   r{   Zis_place_holderra   r   rQ   r#   r$   r&   r'   rg      s>   

zONNXGraph.buildc                 C   sZ  t |jjD ]\}}|dkrq|| jvrd}| jjD ]|}t |jD ]n\}}||kr| |j| d}|j|j	v r`t |j
D ]!\}}	|
|krFq=|	|jkr^d|j|}||j	vr^||j	|<  nq=n&|j
|j}
| j|j j|dkrd|j|}||j	|< n||j	|j< d| j|j _ nq!|dkr nq|dkrtd||q| || qdS )z+
        find connection for nodes
         r      {}/{}z0input[{}] of node[{}] does not exist in node_mapN)	enumerater"   r+   r|   rd   r{   rI   connectr   r    inputsr8   r-   Zoutputsr9   	Exception)r!   r#   r{   idxZin_nodeflagndoptZn_iZn_iptZfirst_iZnew_nd_nameZnew_child_namer&   r&   r'   r}     s^   



zONNXGraph.build_connectionr   Fc                    s   t |jdkrtt| |j| |}|S tt| |j| |}d|j|}||jv r5|j| |_|S |j|jv rB|j|j |_|S )Nr   r   )	r*   r    r   r\   Zget_noder   r8   r#   r-   )r!   r{   r   r~   Zipt_nodeZnew_ipt_namer$   r&   r'   get_input_nodeJ  s   
zONNXGraph.get_input_nodec                 c   sH    t | jtjstd dS | jjD ]}|j}t|}||fV  qdS )z'
        generator for weights
        rn   N)	rC   rd   r;   r   ro   rp   ra   r   r   )r!   ra   r   rQ   r&   r&   r'   graph_weightsY  s   
zONNXGraph.graph_weightsc                 C   sX   t | jtjsJ d| jjD ]}t|jjj dd |jjj	j
D dd| j|j< qdS )z;
        collect value/type info for an ONNX model
        z"model is not a ModelProto instancec                 S   ru   r&   )rW   )r0   rV   r&   r&   r'   rw   s  rx   z1ONNXGraph.collect_value_infos.<locals>.<listcomp>F)r   rU   ZexternalN)rC   rd   r;   r   
value_infor   r:   rT   r[   rU   rV   rc   r   )r!   itemr&   r&   r'   rh   g  s   zONNXGraph.collect_value_infosc                 C   s   | j jD ]A}| j|j }|jD ]5}|| jv r>| j| }|d }tt|D ]}|| dkr1d||< q%|j	| |d |_
q|j	g  qqdS )z%
        run shape inference
        rU   r   r(   r   N)rd   r{   r|   r   rI   rc   r)   r*   r   rX   r   )r!   r"   r{   r   r   rU   r   r&   r&   r'   ri   w  s   


zONNXGraph.allocate_shapesr   )r   F)rK   rL   rM   r   rr   rt   re   ry   rz   rg   r}   r   r   rh   ri   rO   r&   r&   r$   r'   r\      s    		'-r\   c                   @   sR   e Zd ZdddZdd Zdd Zdd	 Zdd
dZdddZdd Z	dd Z
dS )ONNXDecoderNc                 C   sb   t |}td|j|jd j |jd j| _|rt| | 	|}| 
|}t||| _d S )Nz$model ir_version: {}, op version: {}r   )r;   loadrf   r8   Z
ir_versionZopset_importversionZop_setr   optimize_model_skip_opoptimize_node_namer\   rd   )r!   rj   Zenable_onnx_checkerrk   r&   r&   r'   r     s   


zONNXDecoder.__init__c                 C   sf   t  }t  }t|D ]$\}}|jD ]}||t | q|jD ]}||t | q!q
||fS )z:
        build op reference of inputs and outputs
        )Dictr   r+   
setdefaultsetaddrI   )r!   nodes
input_refsoutput_refsr   r{   Zval_namer&   r&   r'   build_value_refs  s   

zONNXDecoder.build_value_refsc           
      C   L   d}|| D ]}|| }t |jD ]\}}	|	|kr"||j|< |d7 }qq|S )z\
        skip nodes between src_output_name -> dst_input_name and connect this pair
        r   r   )r   r+   )
r!   r   Zsrc_output_nameZdst_input_namer   	processedZnext_idxZ	next_nodeval_idxZnext_input_namer&   r&   r'   skip_node_forward     
zONNXDecoder.skip_node_forwardc           
      C   r   )z\
        skip nodes between dst_output_name -> src_input_name and connect this pair
        r   r   )r   rI   )
r!   r   Zsrc_input_nameZdst_output_namer   r   Zprev_idxZ	prev_noder   Zprev_output_namer&   r&   r'   skip_node_backward  r   zONNXDecoder.skip_node_backwardc                 C   s  |j j}|du rdg}| |\}}t| }|| |j j}g }t|D ]\}	}
|
jtks5|
jdks5q&|
j}||vr=q&|dv rL|
j	d }|
j
d }n t|
j	dkrZt|
j
dksbtd|	|
j q&|
j	d }|
j
d }||v ry| ||||}n||v r| ||||}nd}|dkr||	 |j jD ]}|
j
D ]}|j|kr|j j| qqtd	|	||
j| q&|dkrtd
 q&td|	||
j| q&|jdd |D ]}	||	 q|S )z8
        skip ops can be bypassed for inference
        NDropoutr   )r   r   r   zBcurrently only 1-input-1-output op supported, skip required %d: %sr(   zskip op {}: {} -> {} -> {}zweird, no node processedz,standalone op {}: {} -> {} -> {} not skippedT)reverse)rd   r{   r   r:   CopyFromr   domaindefault_op_domainr   r+   rI   r*   rf   r   r   rX   r   r   remover8   sortpop)r!   modelop_listr   r   r   retZ	ret_nodesZnodes_to_removeZnode_idxr{   r   r,   Zoutput_namer   r   rI   r&   r&   r'   r     sl   










z"ONNXDecoder.optimize_model_skip_opTc                 C   s   |j j}| |\}}dd |j jD }t| }|| |j d |j j}|j jD ]$}	|	j}
|
|v r=|	 |	 q,|sK|
|v rK|	 |	 q,t
|	j }q,|j d |j j}|j jD ]}|j}
|
|v sl|
|v rs|	 | q_|S )z-
        strip weights for inference
        c                 S   ru   r&   rv   )r0   valr&   r&   r'   rw     rx   z@ONNXDecoder.optimize_model_strip_initializer.<locals>.<listcomp>ra   r+   )rd   r{   r   rI   r:   r   Z
ClearFieldra   r   r   r   r>   r+   )r!   r   Zkeep_input_onlyr   r   r   Z	out_namesr   Zret_initializersra   r   r   Z
ret_inputsr   r&   r&   r'    optimize_model_strip_initializer  s,   

z,ONNXDecoder.optimize_model_strip_initializerc                 C   s.   |dkrt ddD ]}||d}q
d| S )z6
        make a valid code name for ParamAttr
        r   zname should not be emptyz	 .*?\/-:;_r]   )
ValueErrorreplace)r!   r   rB   r&   r&   r'   make_variable_name  s
   zONNXDecoder.make_variable_namec           	      C   sX  |j }|jD ]	}| |j|_q|jD ]	}| |j|_q|jD ]	}| |j|_q |jD ]	}| |j|_q-|jD ]o}|jd |_d|jv rVt|jdkrV|j	dd|_d|jv rpt|jdkrp|j
dkrp|jdd |_| |j|_tt|jD ]}|j| dkrq~| |j| |j|< q~tt|jD ]}| |j| |j|< qq:|S )z=
        standardize variable name for paddle's code
        r   z::r   r   :ZLSTMr   )rd   ra   r   r   r+   rI   r   r{   r*   r   r   splitr)   )	r!   r   rd   ra   ZiptrI   r   r{   r.   r&   r&   r'   r   '  s:   





zONNXDecoder.optimize_node_namer   )T)rK   rL   rM   r   r   r   r   r   r   r   r   r&   r&   r&   r'   r     s    


:
r   )+Zx2paddle.core.graphr   r   Z%x2paddle.decoder.onnx_shape_inferencer   Zonnx.checkerr   r   r;   r   r   Zonnx.helperr	   r
   Zonnx.shape_inferencer   Zonnx.mappingr   Zonnx.numpy_helperr   r   r   r   collectionsr   r   r   numpyr<   r~   r   loggingZ_loggingosr   	getLoggerrK   Z_loggerr   rP   r\   objectr   r&   r&   r&   r'   <module>   s2   
N; _