o
    ;ήcDK                     @   sd  d dl Z d dlZd dlmZ d dlmZ d dlZd dlZd dlmZ d dlm	Z
 d dlmZmZmZ dZdZd	Zd
ZdZdZdZdZdZdddddddddddddddd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e
jjed(e
jj ed)iZ!dtd*d+Z"dud-d.Z#dud/d0Z$dvd1d2Z%dvd3d4Z&G d5d6 d6Z'G d7d8 d8Z(G d9d: d:Z)d;d< Z*d=d> Z+d?d@ Z,dAdB Z-dCedDe.dEefdFdGZ/dHdI Z0dJdK Z1dwdMdNZ2dOefdPdQZ3dOedRefdSdTZ4dUdV Z5dWdX Z6dYdZ Z7d[d\ Z8dOefd]d^Z9dOed_e:fd`daZ;dbdc Z<ddde Z=dfdg Z>dhdi Z?djdk Z@dldm ZAdndo ZBdpdq ZCdrds ZDdS )x    N)Enum)Path)external_data_helper)onnx_pb)GraphOptimizationLevelInferenceSessionSessionOptionszonnx.quantizez0.1.0zai.onnxzcom.microsoftQuantizeLinear_QuantizeLinear_InputDequantizeLinear_DequantizeLinear_Output
_quantizedFLOATUINT8INT8UINT16INT16INT32INT64STRINGBOOLFLOAT16DOUBLEUINT32UINT64	COMPLEX64
COMPLEX128)                        	   
                  c                   @   (   e Zd ZdZdZdd Zedd ZdS )QuantizationModer   r   c                 C      | j S Nnameself r4   K/tmp/pip-target-vg8gfxp4/lib/python/onnxruntime/quantization/quant_utils.py__str__3      zQuantizationMode.__str__c                 C       zt |  W S  ty   t w r/   )r-   KeyError
ValueError)moder4   r4   r5   from_string6   
   
zQuantizationMode.from_stringN)__name__
__module____qualname__
IntegerOps
QLinearOpsr6   staticmethodr<   r4   r4   r4   r5   r-   /       r-   c                   @   r,   )QuantizedValueTyper   r   c                 C   r.   r/   r0   r2   r4   r4   r5   r6   B   r7   zQuantizedValueType.__str__c                 C   r8   r/   )rE   r9   r:   )vr4   r4   r5   r<   E   r=   zQuantizedValueType.from_stringN)r>   r?   r@   InputInitializerr6   rC   r<   r4   r4   r4   r5   rE   >   rD   rE   c                   @   r,   )	QuantTyper   r   c                 C   r.   r/   r0   r2   r4   r4   r5   r6   Q   r7   zQuantType.__str__c                 C   r8   r/   )rI   r9   r:   )tr4   r4   r5   r<   T   r=   zQuantType.from_stringN)r>   r?   r@   QInt8QUInt8r6   rC   r<   r4   r4   r4   r5   rI   M   rD   rI   c                   @   r,   )QuantFormatr   r   c                 C   r.   r/   r0   r2   r4   r4   r5   r6   `   r7   zQuantFormat.__str__c                 C   r8   r/   )rM   r9   r:   )formatr4   r4   r5   r<   c   r=   zQuantFormat.from_stringN)r>   r?   r@   	QOperatorQDQr6   rC   r<   r4   r4   r4   r5   rM   \   rD   rM   int8uint8c           
      C   s   | t v sJ d| t |  }t|tjkrdnd|d u rdn|}t|tjkr)dnd|d u r0dn|}t|tj| 	 | }	tj
|	|||	d |	|S )NEUnexpected data type {} requested. Only INT8 and UINT8 are supported.r         )out)ONNX_TYPE_TO_NP_TYPErN   maxnumpyrR   minasarrayastypefloat32roundclip)
qTypearrscale
zero_pointlowhighdtypecliplowcliphigharr_fp32r4   r4   r5   quantize_nparrayq   s   $$
rk   Fc                 C   s   |dks|dk rt d| d| t| d} t|d}|r-tt| t|}| } |
 }||  t||  }|ttjjk rHd}d}||gS t	|| |  }||gS )a  Calculate the scale s and zero point z for the quantization relation
    r = s(q-z), where r are the original values and q are the corresponding
    quantized values.

    r and z are calculated such that every value within [rmin,rmax] has an
    approximate representation within [qmin,qmax]. In addition, qmin <= z <=
    qmax is enforced. If the symmetric flag is set to True, the interval
    [rmin,rmax] is symmetrized to [-absmax, +absmax], where
    absmax = max(abs(rmin), abs(rmax)).

    :parameter rmin: minimum value of r
    :parameter rmax: maximum value of r
    :parameter qmin: minimum value representable by the target quantization data type
    :parameter qmax: maximum value representable by the target quantization data type
    :return: zero and scale [z, s]

    r   zBqmin and qmax must meet requirement: qmin <= 0 <= qmax while qmin:z, qmmax:      ?)
r:   r[   rY   absfloatrZ   finfor^   tinyr_   )rminrmaxqminqmax	symmetricabsmaxrc   rd   r4   r4   r5   compute_scale_zp}   s   

rw   c                 C   sp   d}d}d}d}t | r't| }t| }t|||d\}}	t||||	|\}}t|t| ||}
|||||
fS )a  
    :param data: data to quantize
    :param qType: data type to quantize to. Supported types UINT8 and INT8
    :param symmetric: whether symmetric quantization is used or not. This is applied to INT8.
    :return: minimum, maximum, zero point, scale, and quantized weights

    To pack weights, we compute a linear transformation

    - when data `type == uint8` mode, from `[rmin, rmax]` -> :math:`[0, 2^{b-1}]` and
    - when data `type == int8`, from `[-m , m]` -> :math:`[-(2^{b-1}-1), 2^{b-1}-1]` where
        `m = max(abs(rmin), abs(rmax))`

    and add necessary intermediate nodes to trasnform quantized weight to full weight using the equation

    :math:`r = S(q-z)`, where

    - *r*: real original value
    - *q*: quantized value
    - *S*: scale
    - *z*: zero point
    r   rl   ru   )lenr[   rY   get_qmin_qmax_for_qTyperw   rk   rZ   r\   )datara   ru   reduce_rangerq   rr   rd   rc   rs   rt   quantized_datar4   r4   r5   quantize_data   s   r~   c                 C   sr   | t jjkr|r
dnd\}}||fS | t jjkr2|r&|rdnd\}}||fS |r*dnd\}}||fS td| )z
    Return qmin and qmax, the minimum and maximum value representable by the given qType
    :parameter qType: onnx.onnx_pb.TensorProto.UINT8 or onnx.onnx_pb.TensorProto.UINT8
    :return: qmin, qmax
    )r   rV   )r   rU   )i@   )rT   rV   )irV   rS   )
onnx_protoTensorProtor   r   r:   rN   ra   r|   ru   rs   rt   r4   r4   r5   rz      s   rz   c                 C   s   t | ||d\}}|| S )z
    Helper function to get the quantization range for a type.
        parameter qType: quantization type.
        return: quantization range.
    rx   )rz   r   r4   r4   r5   get_qrange_for_qType   s   r   c                   @   s    e Zd ZdZg g dfddZdS )QuantizedInitializerzJ
    Represents a linearly quantized weight input from ONNX operators
    Nc
           
      C   s:   || _ || _|| _|| _|| _|| _|| _|| _|	| _d S r/   )	r1   initializerrminsrmaxszero_pointsscalesr{   r}   axis)
r3   r1   r   r   r   r   r   r{   r}   r   r4   r4   r5   __init__   s   
zQuantizedInitializer.__init__r>   r?   r@   __doc__r   r4   r4   r4   r5   r      s    r   c                   @   s   e Zd ZdZ	dddZdS )QuantizedValuezI
    Represents a linearly quantized value (input\output\intializer)
    Nc                 C   s(   || _ || _|| _|| _|| _|| _d S r/   )original_nameq_name
scale_namezp_name
value_typer   )r3   r1   new_quantized_namer   zero_point_namequantized_value_typer   r4   r4   r5   r     s   	
zQuantizedValue.__init__r/   r   r4   r4   r4   r5   r   
  s    r   c                   @   s   e Zd ZdZdd ZdS )BiasToQuantizez+
    Represents a bias to be quantized
    c                 C   s   || _ || _|| _d S r/   )	bias_name
input_nameweight_name)r3   r   r   r   r4   r4   r5   r   %  s   
zBiasToQuantize.__init__Nr   r4   r4   r4   r5   r      s    r   c                 C   s   | j dkrtd| j| j dkr| j}n[| j dkr| j}nR| j dkr(| j}nI| j dkr1| j}n@| j dkr:| j}n7| j dkrC| j	}n.| j d	krL| j
}n%| j d
krU| j}n| j dkr^| j}n| j dkrg| j}n
td| j| j | j|iS )z
    Convert attribute to kwarg format for use with onnx.helper.make_node.
        :parameter attribute: attribute in AttributeProto format.
        :return: attribute in {key: value} format.
    r   z*attribute {} does not have type specified.r   r   r   r    r!   r"   r#   r$   r%   r&   z%attribute {} has unsupported type {}.)typer:   rN   r1   fisrJ   gfloatsintsstringstensorsgraphs)	attributevaluer4   r4   r5   attribute_to_kwarg+  s0   











r   c                    s*    fdd|D }t |dkr|d S dS )z
    Helper function to find item by name in a list.
        parameter item_name: name of the item.
        parameter item_list: list of items.
        return: item if found. None otherwise.
    c                    s   g | ]	}|j  kr|qS r4   r0   ).0item	item_namer4   r5   
<listcomp>W  s    z find_by_name.<locals>.<listcomp>r   N)ry   )r   	item_listitemsr4   r   r5   find_by_nameP  s   r   c                 C   s,   d}t dt|D ]
}|| | kr|}q	|S )zC
    Helper function to return index of an item in a node list
    r   )rangery   )	elem_name	elem_listelem_idxr   r4   r4   r5   get_elem_index[  s   r   c                 C   s   t jd| |g|S )z
    Helper function to create a Mul node.
        parameter inputs: list of input names.
        parameter output: output name.
        parameter name: name of the node.
        return: Mul node in NodeProto format.
    Mul)onnxhelper	make_node)inputsoutputr1   r4   r4   r5   get_mul_nodef  s   r   filename
identifierreturnc                 C   s   | j | j| | j S )zp
    Helper function to generate a identifiable filepath by concatenating the given identifier as a suffix.
    )parentjoinpathstemsuffix)r   r   r4   r4   r5   generate_identified_filenameq  s   r   c                 C   s   dd l }dd lm} dd l}|j|jd td t|  td t| |j| |dd |d |	d |
d	 |  d S )
Nr   )	thresholdz
Histogram:zHistogram Edges:T)fillzTensor valueCountszTensor value V.S. Counts)sysmatplotlib.pyplotpyplotrZ   set_printoptionsmaxsizeprintstairsxlabelylabeltitleshow)hist
hist_edgesr   pltrZ   r4   r4   r5   
apply_plotx  s   


r   c              	   C   s4  ddl }ddl}ddlm  m  m} ddlm  m  m} t	d
|  tdd}|||  W d   n1 s@w   Y  |d}g }t|  D ]:}| | }	ttt|	d t|	d }
||}||
}|| ||| ||| ||}|| qR||t| |D ]}|| q| }|| ||| | |}|!| |" }tdd	}|| W d   n1 sw   Y  	 tdd3}t|  D ]#}| | }
|d ttt|
d t|
d  }|| |d qW d   dS 1 sw   Y  dS )z>
    Helper function to write calibration table to files.
    r   Nzcalibration cache: {}zcalibration.jsonwi   r   zcalibration.flatbufferswbFzcalibration.cache 
))jsonflatbuffers5onnxruntime.quantization.CalTableFlatBuffers.KeyValuequantizationCalTableFlatBuffersKeyValue5onnxruntime.quantization.CalTableFlatBuffers.TrtTableTrtTablelogginginforN   openwritedumpsBuildersortedkeysstrrY   rm   CreateStringKeyValueStartKeyValueAddKeyKeyValueAddValueKeyValueEndappendTrtTableStartDictVectorry   PrependUOffsetTRelative	EndVectorTrtTableStartTrtTableAddDictTrtTableEndFinishOutputGetRootAsTrtTable
DictLengthr   DictKeyValue)calibration_cacher   r   r   r   filebuilderkey_value_listkeyvaluesr   flat_key
flat_value	key_value	main_dict	cal_tablebufdict_lenr   r   r4   r4   r5   write_calibration_table  sR   







	&
$r  -C6?c           	      C   s   ddl }| dk|j}| dk|j}| }| j| }|s!dS |t| t| }|dk s8J d|||f | |j}||| | |  7 }|dk dksSJ |S )a~  Given a discrete distribution (may have not been normalized to 1),
    smooth it by replacing zeros with eps multiplied by a scaling factor
    and taking the corresponding amount off the non-zero values.
    Ref: http://web.engr.illinois.edu/~hanj/cs412/bk3/KL-divergence.pdf
         https://github.com//apache/incubator-mxnet/blob/master/python/mxnet/contrib/quantization.py
    r   Nr   rl   z"n_zeros=%d, n_nonzeros=%d, eps1=%f)rZ   r]   r^   sumsizern   )	pepsnpis_zerosis_nonzerosn_zeros
n_nonzeroseps1r   r4   r4   r5   smooth_distribution  s"   
r  
model_pathc                 C   s4   t j|  dd}|jjD ]
}t|r dS qdS )NF)load_external_dataT)r   loadas_posixgraphr   r   uses_external_data)r  model
intializerr4   r4   r5   model_has_external_data  s   
r!  opt_model_pathc                 C   s0   t  }| |_tj|_t|  |dgd}dS )z
        Generate model that applies graph optimization (constant folding, etc.)
        parameter model_path: path to the original onnx model
        parameter opt_model_path: path to the optimized onnx model
    :return: optimized onnx model
    CPUExecutionProvider)	providersN)r   r  optimized_model_filepathr   ORT_ENABLE_BASICgraph_optimization_levelr   )r  r"  sess_option_r4   r4   r5   optimize_model  s   
r*  c                 C   s>   ddi}| j r| j D ]}||j|ji q
tj| | dS )z>Tag the model that it went through quantization pre-processingonnx.quant.pre_processonnxruntime.quantNmetadata_propsupdater  r   r   r   set_model_props)r  r.  propr4   r4   r5   add_pre_process_metadata  s
   
r2  c                 C   0   | j r| j D ]}|jdkr|jdkr dS qdS )zCCheck the model whether it went through quantization pre-processingr+  r,  TFr.  r  r   )r  r1  r4   r4   r5   model_has_pre_process_metadata
  s   
r5  c                 C   s>   ddi}| j r| j D ]}||j|ji q
tj| | d S )N
onnx.inferr,  r-  )r  r.  r  r4   r4   r5   add_infer_metadata  s
   
r7  c                 C   r3  )Nr6  r,  TFr4  )r  r  r4   r4   r5   model_has_infer_metadata  s   
r8  c                 C   s:   t | d}tjt| t| t| }|  |S )Nz	-inferred)r   r   shape_inferenceinfer_shapes_pathr   r  r  unlink)r  inferred_model_pathr  r4   r4   r5   load_model_with_shape_infer#  s
   
r=  need_optimizec                 C   sl   t jdd&}|rt| st|d}t| | |} t| }t| |W  d    S 1 s/w   Y  d S )N
ort.quant.prefix
model.onnx)tempfileTemporaryDirectoryr!  r   r   r*  r=  r7  )r  r>  quant_tmp_dirr"  r  r4   r4   r5   
load_model+  s   
$rF  c                 C   sh   t jdd$}t|d}tjj| dd t| |  t	|dW  d    S 1 s-w   Y  d S )Nr?  r@  rB  T)all_tensors_to_one_fileF)
rC  rD  r   r   r   r   convert_model_to_external_data
save_modelr  rF  )r  rE  r  r4   r4   r5   save_and_reload_model7  s   $rJ  c                 C   s*   t | rt }||  |S t| }|S r/   )r8  r   
ModelProtoCopyFromrJ  )r  cloned_modelr4   r4   r5   clone_model_with_shape_infer?  s   
rN  c                 C   s6   | j tjjkrtj| S td| j dt	| j   )Nz&Only float type is supported. Weights z is )
	data_typer   r   r   r   numpy_helperto_arrayr:   r1   type_to_name)r   r4   r4   r5   tensor_proto_to_arrayH  s
   rS  c                 C      | d S )N_QuantizeLinearr4   tensor_namer4   r4   r5   add_quant_suffixQ     rX  c                 C      | t  S r/   )QUANT_INPUT_SUFFIXrV  r4   r4   r5   add_quant_input_suffixU  rY  r\  c                 C   rT  )N_QuantizeLinear_Outputr4   rV  r4   r4   r5   add_quant_output_suffixY  rY  r^  c                 C   rT  )N_DequantizeLinearr4   rV  r4   r4   r5   add_dequant_suffix]  rY  r`  c                 C   rT  )N_DequantizeLinear_Inputr4   rV  r4   r4   r5   add_dequant_input_suffixa  rY  rb  c                 C   rZ  r/   )DEQUANT_OUTPUT_SUFFIXrV  r4   r4   r5   add_dequant_output_suffixe  rY  rd  )NN)F)FF)r  )Er   rC  enumr   pathlibr   rZ   r   r   r   r   onnxruntimer   r   r   __producer____version__onnx_domain	ms_domainQUANT_OP_NAMEr[  DEQUANT_OP_NAMErc  TENSOR_NAME_QUANT_SUFFIXrR  r-   rE   rI   rM   r   r   rg   r   rX   rk   rw   r~   rz   r   r   r   r   r   r   r   r   r   r   r   r  r  r!  r*  r2  r5  r7  r8  r=  boolrF  rJ  rN  rS  rX  r\  r^  r`  rb  rd  r4   r4   r4   r5   <module>   s    


+
'

%
C				