U
    qh.                  	   @  s  d dl mZ d dlZd dlZd dlZd dlZd dlmZ d dlm	Z	m
Z
 d dlm  mZ d dlmZmZmZmZmZ G dd dZdd	d
dddZdd	d
dddZdDdd	ddddd
dddZdEdd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(Zd)d*d%d+d,d-Zd.d%d/d0d1Zdd%d&d2d3Zd.d%d/d4d5Z dd%d&d6d7Z!d	dd8d9d:Z"ddd;d<d=Z#dd	d
d>d?d@Z$dd	ddAdBdCZ%dS )F    )annotationsN)chain)CallableIterable)AttributeProtoFunctionProto
GraphProto
ModelProtoTensorProtoc                   @  s   e Zd ZdddddZdS )ExternalDataInfor
   Nonetensorreturnc                 C  sb   d| _ d | _d | _d | _d| _|jD ]}t| |j|j q$| jrLt	| j| _| jr^t	| j| _d S )N )
locationoffsetlengthchecksumbasepathexternal_datasetattrkeyvalueint)selfr   entry r   =/tmp/pip-unpacked-wheel-xnis5xre/onnx/external_data_helper.py__init__   s    
zExternalDataInfo.__init__N)__name__
__module____qualname__r   r   r   r   r   r      s   r   r
   strr   )r   base_dirr   c              	   C  sf   t | }t||j| j}t|d8}|jr8||j |jrN|	|j| _
n
|	 | _
W 5 Q R X dS )zLoads data from an external file for tensor.
    Ideally TensorProto should not hold any raw data but if it does it will be ignored.

    Arguments:
        tensor: a TensorProto object.
        base_dir: directory that contains the external data.
    rbN)r   	c_checkerZ_resolve_external_data_locationr   nameopenr   seekr   readraw_data)r   r$   infoexternal_data_file_path	data_filer   r   r   load_external_data_for_tensor)   s      r/   r	   )modelr$   r   c                 C  s8   t | D ]*}t|rt|| tj|_|jdd= qdS )zLoads external tensors into model

    Arguments:
        model: ModelProto to load external data to
        base_dir: directory that contains external data
    N)_get_all_tensorsuses_external_datar/   r
   DEFAULTdata_locationr   )r0   r$   r   r   r   r   load_external_data_for_model?   s
    
r5   z
int | Nonez
str | None)r   r   r   r   r   r   r   c           	      C  s   |  dstd| j d | jd d = tj| _||d k	rBt|nd |d k	rTt|nd ||d D ]*\}}|d k	rd| j	 }||_
t||_qdd S )Nr+   zTensor zGdoes not have raw_data field. Cannot set external data for this tensor.)r   r   r   r   r   )HasField
ValueErrorr'   r   r
   EXTERNALr4   r   itemsaddr   r#   r   )	r   r   r   r   r   r   kvr   r   r   r   set_external_dataO   s(    

r=   T   Fboolr   )r0   all_tensors_to_one_filer   size_thresholdconvert_attributer   c           	      C  s   t | }|rt| }|rptt }|r@tj|r<td|}|D ](}|	drDt
|j|krDt|| qDnH|D ]B}|	drtt
|j|krt|j}t|stt }t|| qtdS )a  Call to set all tensors with raw data as external data. This call should precede 'save_model'.
    'save_model' saves all the tensors data as external data after calling this function.

    Arguments:
        model (ModelProto): Model to be converted.
        all_tensors_to_one_file (bool): If true, save all tensors to one external file specified by location.
            If false, save each tensor to a file named with the tensor name.
        location: specify the external file relative to the model that all tensors to save to.
            Path is relative to the model path.
            If not specified, will use the model name.
        size_threshold: Threshold for size of data. Only when tensor's data is >= the size_threshold
            it will be converted to external data. To convert every tensor with raw data to external data set size_threshold=0.
        convert_attribute (bool): If true, convert all tensors to external data
                       If false, convert only non-attribute tensors to external data
    zDlocation must be a relative path that is relative to the model path.r+   N)_get_initializer_tensorsr1   r#   uuidZuuid1ospathisabsr7   r6   sys	getsizeofr+   r=   r'   _is_valid_filename)	r0   r@   r   rA   rB   tensors	file_namer   Ztensor_locationr   r   r   convert_model_to_external_datam   s4    rM   )r0   r   c                 C  s@   t | D ]2}t|r|ds&td|jdd= tj|_qdS )zCall to set all tensors which use external data as embedded data.
    save_model saves all the tensors data as embedded data after
    calling this function.

    Arguments:
        model (ModelProto): Model to be converted.
    r+   raw_data field doesn't exist.N)r1   r2   r6   r7   r   r
   r3   r4   )r0   r   r   r   r    convert_model_from_external_data   s    
rO   )r   	base_pathr   c              	   C  s   t | }tj||j}| ds*tdtj|sLt|d W 5 Q R X t|dz}|	dd |j
dk	r| }|j
|kr|d|j
|   |	|j
 | }|| j t| |j|| |  W 5 Q R X dS )	zWrites tensor data to an external file according to information in the `external_data` field.

    Arguments:
        tensor (TensorProto): Tensor object to be serialized
        base_path: System path of a folder where tensor data is to be stored
    r+   rN   abzr+br      N    )r   rE   rF   joinr   r6   r7   isfiler(   r)   r   tellwriter+   r=   )r   rP   r,   r-   r.   	file_sizer   r   r   r   save_external_data   s"    



rY   zIterable[TensorProto])onnx_model_protor   c                 C  s   t t| t| S )z=Scan an ONNX model for all tensors and return as an iterator.)r   rC   _get_attribute_tensors)rZ   r   r   r   r1      s    r1   r   z-Callable[[GraphProto], Iterable[TensorProto]])	attributefuncr   c                 c  sF   | j tjkr|| jE dH  | j tjkrB| jD ]}||E dH  q.dS )zICreate an iterator through processing ONNX model attributes with functor.N)typer   ZGRAPHgZGRAPHSZgraphs)r\   r]   graphr   r   r   _recursive_attribute_processor   s
    
ra   zGraphProto | FunctionProto)graph_or_functionr   c                c  sB   t | tr| jE dH  | jD ] }|jD ]}t|tE dH  q&qdS )zICreate an iterator of initializer tensors from ONNX model graph/function.N)
isinstancer   Zinitializernoder\   ra   #_get_initializer_tensors_from_graphrb   rd   r\   r   r   r   re      s    


 re   c                 c  s.   t | jE dH  | jD ]}t|E dH  qdS )z:Create an iterator of initializer tensors from ONNX model.N)re   r`   	functions!_get_attribute_tensors_from_graphrZ   functionr   r   r   rC      s    
rC   c                c  sJ   | j D ]>}|jD ]2}|dr&|jV  |jE dH  t|tE dH  qqdS )zSCreate an iterator of tensors from node attributes of an ONNX model graph/function.tN)rd   r\   r6   rk   rK   ra   rh   rf   r   r   r   rh      s    


 rh   c                 c  s.   t | jE dH  | jD ]}t |E dH  qdS )zDCreate an iterator of tensors from node attributes of an ONNX model.N)rh   r`   rg   ri   r   r   r   r[     s    
r[   )filenamer   c                 C  s   t d}|| }t|S )z8Utility to check whether the provided filename is valid.z^[^<>:;,?"*|/]+$)recompilematchr?   )rl   expro   r   r   r   rJ     s    

rJ   r   c                 C  s   |  do| jtjkS )z?Returns true if the tensor stores data in an external location.r4   )r6   r4   r
   r8   )r   r   r   r   r2     s    

r2   )r   	field_keyr   c                 C  s*   t | jD ]\}}|j|kr
| j|= q
dS )a  Removes a field from a Tensor's external_data key-value store.

    Modifies tensor object in place.

    Arguments:
        tensor (TensorProto): Tensor object from which value will be removed
        field_key (string): The key of the field to be removed
    N)	enumerater   r   )r   rq   ifieldr   r   r   remove_external_data_field  s    	
ru   )r0   filepathr   c                 C  s8   t | D ]*}t|r|drt|| |d q| S )a  Serializes data for all the tensors which have data location set to TensorProto.External.

    Note: This function also strips basepath information from all tensors' external_data fields.

    Arguments:
        model (ModelProto): Model object which is the source of tensors to serialize.
        filepath: System path to the directory which should be treated as base path for external data.

    Returns:
        ModelProto: The modified model object.
    r+   )r1   r2   r6   rY   Z
ClearField)r0   rv   r   r   r   r   write_external_data_tensors,  s
    
rw   )NNNN)TNr>   F)&
__future__r   rE   rm   rH   rD   	itertoolsr   typingr   r   Zonnx.onnx_cpp2py_export.checkerZonnx_cpp2py_exportcheckerr&   Zonnx.onnx_pbr   r   r   r	   r
   r   r/   r5   r=   rM   rO   rY   r1   ra   re   rC   rh   r[   rJ   r2   ru   rw   r   r   r   r   <module>   sB   	         4"