U
    qh9                     @  s   d dl mZ d dlZd dlmZmZmZmZm	Z	m
Z
mZ d dlmZmZmZmZmZmZmZmZmZ d dlmZ dddd	d
ddZdddddZddddddZdddddddddZdS )    )annotationsN)AttributeProtoFunctionProto
GraphProto
ModelProto	NodeProtoSparseTensorProtoTensorProto)	make_attributemake_function
make_graph
make_model	make_nodemake_tensormake_tensor_value_infoset_model_propstensor_dtype_to_np_dtype)
from_arrayr   intfloatzlist[NodeProto])node	thresholdvalue_constant_of_shapereturnc              
   C  s   | j dkrtd| j d| jD ]}|jdkrBtd| jd|jdkr|j}|j d}|j}t|}||kr| g  S t	tj
t|tjd	|d
}t|j}	tdg |g|d}
td|g| jt	tj
|g|	d	d}|
|g  S td|jq"| gS )zReplaces a Constant node with a large tensor (with more than threshold elements) by a sequence of nodes that produces a dummy constant of same shape as original tensor.Constantz!Node type must be 'Constant' not .Zsparse_valuezEThis feature is not yet implemented for a sparse constant (node name=).value__SHAPEdtypenamer   ConstantOfShapez'Replacement of constant with attribute )op_type	TypeError	attributer"   NotImplementedErrortdimsnpprodr   arraylistint64r   	data_typer   output)r   r   r   attr   new_namer*   sizeinitr    Z
node_shapenew_node r7   @/tmp/pip-unpacked-wheel-xnis5xre/onnx/tools/replace_constants.py_replace_constant   sB    







r9   zGraphProto | FunctionProto)onxr   c                   s  t | trt| j}n*t | tr,t| j}ntdt|  dt  |D ] } t|jO   t|j	O  qJ fdd}t
dg |dgdd}t
dg |d	gd
d}i }t|D ]*\}}|jdkrq|jd }t
d|g|| dg}	t
d|j	d |	j	d |j	d g|| dg}
t|jd
kr:|jd jj}ntj}t
d|
j	d g|| dg|d}t
d|	j	d g|| dg|d}t
d|j	d |j	d g|| dg}t
d|j	d |g|j	}|	|
||||g||< qt| ddD ]\}}||||d
 < q|d| |d
| t | trPt|| j| j| j	| j| jd}|S t | tr~t| j| j| j| j	|| jd}|S tdt|  ddS )zReplaces all *ConstantOfShape* by node *Range* to avoid constant tensors.

    The function is not recursive. The recursivity is done by
    *replace_initializer_by_constant_of_shape*.
    Not implemented for type r   c                   sT   |  kr  |  | S d}|  d| }| kr>  | |S |d7 }qtdd S )N   _   z/The function should never go through that line.)addRuntimeError)prefixir"   existing_namesr7   r8   
_find_name[   s    


z9_replace_constant_of_shape_with_range.<locals>._find_namer   Zzeror   )Z	value_intZoner>   r$   Z
ReduceProdZ_NZRangeZ_RANGEZCastZ_RANGEf)toZ_NfZDivZ_FLATZReshapeT)reverseinitializersparse_initializerZopset_importsN)
isinstancer   r.   r   r   r&   typesetinputr1   r   	enumerater%   lenr'   r)   r0   r	   FLOATsorteditemsinsertr   r"   rI   rJ   r   domainopset_import)r:   nodesr   rE   Zcst0Zcst1updateinodeshapenarF   acZcldZreshupgraphnew_onxr7   rC   r8   %_replace_constant_of_shape_with_rangeG   sx    



$$  rc   )r:   r   r   c                 C  sv  t | trt| j}n*t | tr,t| j}ntdt|  dt }|D ] }|t|jO }|t|j	O }qJi }t
|D ]n\}}|jdkrqx|jd j}t|j|jdg|g}td|j|j	}	t|jd j|d}
|	j|
 |	||< qx| D ]\}}|||< qt | tr0t|| j| j| j	| j| jd}|S t | tr^t| j| j| j| j	|| jd}|S tdt|  dd	S )
z7Replaces all fill value of all nodes *ConstantOfShape*.r;   r   r$   r   r>   r#   rH   rK   N)rL   r   r.   r   r   r&   rM   rN   rO   r1   rP   r%   r'   r)   r   r"   r0   r   r
   appendrT   r   rI   rJ   r   rV   rW   )r:   r   rX   rD   r   rY   rZ   ZtensorZ
new_tensorr6   r2   r`   ra   rb   r7   r7   r8    _replace_constant_of_shape_value   s^    


   

re      F      ?z'FunctionProto | GraphProto | ModelProtoz
int | Nonebool)r:   r   
ir_version	use_ranger   c               
     s  t trd}g }jD ]@}|jdkrNt|}t|dkrBd}|| q|| q|rtj	j
jj|jd}	rt|	S dkrt|	S |	S rtS dkrtS S t trtj pڈjd}
 fdd	jD }t|
|jj pjjj	jd
}tjdkrVdd jD }t|| |jdd= jD ]z}|j }|j	dkr|jdk rrtd|j d|j	dkr|jdk rtd|j d|j	|_	|j|_qh|S t tst dt! dd}g }t" g }g }j#D ]}t$|j%}t&'|}|krT|| q$|d7 }|j
 d}|t(t&j)t*|t&j+d|d t,|j-}t.d|g|j
gt(t&j)dg|dd}|| |j
  dk	r$ dkr$|t/|t0j1t|g q$g }j2D ]P}t$|j%}t&'|}|kr<|| qt3d|j4j
d|j5j
dqjD ]}|jdkrt|}t|dkr|d7 }|| qdd}g }|j6D ]n}|j!t7j8krt9|d r|j:dk	rt|j: d!}t;|t;|j:krd}t<|j
|}|| q|r\t.|j|j|j}|j6| || |d7 }n
|| qd|dkrt=|j
fd"d	jD | j||d#}rt|S dkrt|S |S rtS dkrtS S )$a  Replace initializers or constant node by nodes *ConstantOfShape* to reduce the size.

    This reduce the cost to write a unit test about a specific graph structure.

    Args:
        onx: ModelProto
        threshold: every initializer under this threshold is not
            impacted
        ir_version: initializer must be specified as input for
            `ir_version <= 3`, this must be specified if onx is
            :class:`FunctionProto` or :class:`GraphProto`
        use_range: if uses operator *Range* instead of *ConstantOfShape*
            to avoid constant tensors
        value_constant_of_shape: value to use as a value for all nodes
            *ConstantOfShape*, a high value may produce nan or inf
            predictions

    Returns:
        onx, modified ModelProto

    The function is designed so that the function can be reapplied on a modified model
    and either replace *ConstantOfShape* with *Range* operators, either replace the fill value
    for every *ConstantOfShape*.
    Fr   r<   TrK   r>   )ri   r   rj   r   c              	     s$   g | ]}t | pjd qS )r   ri   rj   r   )(replace_initializer_by_constant_of_shaperi   ).0f)ri   r:   r   rj   r   r7   r8   
<listcomp>  s   z<replace_initializer_by_constant_of_shape.<locals>.<listcomp>)	functionsproducer_nameproducer_versionri   
doc_stringrV   model_versionr   c                 S  s   i | ]}|j |jqS r7   )keyr   )rm   pr7   r7   r8   
<dictcomp>3  s      z<replace_initializer_by_constant_of_shape.<locals>.<dictcomp>N    z.Range was introduced in opset 11 but opset is r   	   z7ConstantOfShape was introduced in opset 9 but opset is z-onx should be a GraphProto at this stage not r   r   r!   r$   rg   r#      zKThis feature is not yet implemented for a sparse initializer (indices.name=z, values.name=r   grk   c                   s   g | ]}|j  kr|qS r7   r!   )rm   rB   )removedr7   r8   ro     s     
 rH   )>rL   r   r   r%   r9   rQ   extendrd   r   rV   r"   rO   r1   rW   rc   re   r   rl   ra   ri   rp   r   rq   rr   rs   rt   Zmetadata_propsr   r?   versionr@   r   r&   rM   rN   rI   tupler*   r+   r,   r   r-   r.   r/   r   r0   r   r   r	   ZINT64rJ   r(   indicesvaluesr'   r   ZGRAPHhasattrr|   idr
   r   ) r:   r   ri   rj   r   modifiedZ	new_nodesr   Z	cst_nodesrb   Z	new_graphZnew_functionsmodelr   ZoimpZop_setZn_modificationsZadditional_inputsZ	new_initsr5   r*   r4   r3   r    Znew_sparse_initsZsp_initZshape_nodesZattsr2   r|   r6   ra   r7   )ri   r:   r}   r   rj   r   r8   rl      sH   



 




























rl   )rf   NFrg   )
__future__r   Znumpyr+   Zonnxr   r   r   r   r   r   r	   Zonnx.helperr
   r   r   r   r   r   r   r   r   Zonnx.numpy_helperr   r9   rc   re   rl   r7   r7   r7   r8   <module>   s   $	,(X9    