U
    ,-eQ                  
   @   s  d dl 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 d dlmZmZ d dlmZmZ d dlmZ d d	lmZmZmZ ed
Zdddddddddg	ZG dd deZeeedddZedddZdd Zeeee
e e
e e	ef ddd Z d@eeeee ed!d"d#Z!ee"ee#d$d%d&Z$ee"ed'd(d)Z%dAeeee"ee e#ed+d,d-Z&eed.d/d0Z'eed.d1d2Z(ed3d4d5Z)e*d6kre Z+e+, Z-ee-j./ e-_.ze0d7 e&e-j1e-j2e-j.e-j3e-j4e-j5e-j e-j(r,ee e-j1d8kre0d9 e0d: e'e-j.e-_6e(e-j6e-_7e-j8rre0d; e)e-j. e9e-d<r\e)e-j6 e9e-d=rre)e-j7 W n: e:k
r Z; ze0d>e;  e<d? W 5 dZ;[;X Y nX dS )B    N)ArgumentParser)listdirmakedirs)Path)DictListOptionalTuple)Versionparse)Pipelinepipeline)BatchEncoding)ModelOutputis_tf_availableis_torch_availablez1.4.0feature-extractionZnerzsentiment-analysisz	fill-maskzquestion-answeringztext-generationZtranslation_en_to_frZtranslation_en_to_deZtranslation_en_to_roc                       s    e Zd ZdZ fddZ  ZS )OnnxConverterArgumentParserz[
    Wraps all the script arguments supported to export transformers models to ONNX IR
    c                    s   t  d | jdttdd | jdtddd | jd	td
d | jdtddgdd | jdtddd | jdddd | jdddd | jdddd | d d S )NzONNX Converterz
--pipeliner   )typechoicesdefaultz--modelTz(Model's id or path (ex: bert-base-cased))r   requiredhelpz--tokenizerz,Tokenizer's id or path (ex: bert-base-cased))r   r   z--frameworkpttfzFramework for loading the model)r   r   r   z--opset   zONNX opset to use)r   r   r   z--check-loading
store_truez$Check ONNX is able to load the model)actionr   z--use-external-formatz!Allow exporting model >= than 2Gbz
--quantizez/Quantize the neural network to be run with int8output)super__init__add_argumentstrSUPPORTED_PIPELINESint)self	__class__ c/var/www/html/Darija-Ai-Train/env/lib/python3.8/site-packages/transformers/convert_graph_to_onnx.pyr    3   sJ    z$OnnxConverterArgumentParser.__init__)__name__
__module____qualname____doc__r    __classcell__r(   r(   r&   r)   r   .   s   r   )filename
identifierreturnc                 C   s   | j | j| | jS )aE  
    Append a string-identifier at the end (before the extension, if any) to the provided filepath

    Args:
        filename: pathlib.Path The actual path object we would like to add an identifier suffix
        identifier: The suffix to add

    Returns: String with concatenated identifier at the end of the filename
    )parentjoinpathstemwith_suffixsuffix)r/   r0   r(   r(   r)   generate_identified_filename\   s    
r7   )minimum_versionc                 C   sX   z6ddl }t|j}|tk r4td|j d|  dW n tk
rR   tdY nX dS )z
    Check onnxruntime is installed and if the installed version match is recent enough

    Raises:
        ImportError: If onnxruntime is not installed or too old version is found
    r   Nz*We found an older version of onnxruntime (z&) but we require onnxruntime to be >= zp to enable all the conversions options.
Please update onnxruntime by running `pip install --upgrade onnxruntime`zonnxruntime doesn't seem to be currently installed. Please install the onnxruntime by running `pip install onnxruntime` and relaunch the conversion.)onnxruntimer   __version__ORT_QUANTIZE_MINIMUM_VERSIONImportError)r8   r9   Zort_versionr(   r(   r)   check_onnxruntime_requirementsi   s    
r=   c                 C   s|   t d | jjj}g g  }}|dd D ]8}||krN|| |||  q(t | d  qbq(t d|  |t|fS )a  
    Ensure inputs are presented in the correct order, without any Non

    Args:
        model: The model used to forward the input data
        tokens: BatchEncoding holding the input data
        input_names: The name of the inputs

    Returns: Tuple

    z$Ensuring inputs are in correct order   Nz, is not present in the generated input list.zGenerated inputs order: )printforward__code__co_varnamesappendtuple)modeltokensinput_namesZmodel_args_name
model_argsordered_input_namesarg_namer(   r(   r)   ensure_valid_input   s    


rK   )nlp	frameworkr1   c                    s  t ttd fdd | jd|d}|jjd |dkrD| jf |n| |}t|tr`|	 }t|t
tfst|f}t
| } fdd	| D }g }|D ](}t|tt
fr|| q|| qd
d tt|D } fdd	t||D }	t|f|	}
|||
|fS )a?  
    Attempt to infer the static vs dynamic axes for each input and output tensors for a specific model

    Args:
        nlp: The pipeline object holding the model to be exported
        framework: The framework identifier to dispatch to the correct inference scheme (pt/tf)

    Returns:

        - List of the inferred input variable names
        - List of the inferred output variable names
        - Dictionary with input/output variables names as key and shape tensor as value
        - a BatchEncoding reference which was used to infer all the above information
    )nameis_inputseq_lenc                    s   t |ttfr& fdd|D S dd t|jD d di} rvt|jdkr^d|d< qtd	t|j d
n,fddt|jD }|dd |D  td rdnd d d|  |S )Nc                    s   g | ]} |qS r(   r(   ).0t)build_shape_dictrO   rN   rP   r(   r)   
<listcomp>   s     z:infer_shapes.<locals>.build_shape_dict.<locals>.<listcomp>c                 S   s   g | ]\}}|d kr|qS )r>   r(   )rQ   ZaxisZnumelr(   r(   r)   rT      s      r   batch   sequencer>   zUnable to infer tensor axes ()c                    s   g | ]\}}| kr|qS r(   r(   )rQ   dimshape)rP   r(   r)   rT      s      c                 S   s   i | ]
}|d qS )rW   r(   )rQ   rY   r(   r(   r)   
<dictcomp>   s      z:infer_shapes.<locals>.build_shape_dict.<locals>.<dictcomp>zFound inputr    z with shape: )	
isinstancerD   list	enumeraterZ   len
ValueErrorupdater?   )rN   tensorrO   rP   ZaxesZseq_axes)rS   )rO   rN   rP   r)   rS      s    
"z&infer_shapes.<locals>.build_shape_dictzThis is a sample output)Zreturn_tensorsr   c                    s    i | ]\}}| ||d qS )Tr(   rQ   kvrS   rP   r(   r)   r[      s      z infer_shapes.<locals>.<dictcomp>c                 S   s   g | ]}d | qS )Zoutput_r(   )rQ   ir(   r(   r)   rT      s     z infer_shapes.<locals>.<listcomp>c                    s    i | ]\}}| ||d qS )Fr(   rf   ri   r(   r)   r[      s      )r"   boolr$   	tokenizerZ	input_idsrZ   rE   r^   r   Zto_tupler_   rD   keysitemsextendrC   rangera   zipdict)rL   rM   rF   outputsZ
input_varsZinput_dynamic_axesZoutputs_flatr   output_namesZoutput_dynamic_axesdynamic_axesr(   ri   r)   infer_shapes   s&    
rv   )pipeline_namerM   rE   rl   r1   c                 K   s`   |dkr|}|dkr"t  s"td|dkr8t s8tdtd| d| d t| ||||d	S )
a  
    Convert the set of arguments provided through the CLI to an actual pipeline reference (tokenizer + model

    Args:
        pipeline_name: The kind of pipeline to use (ner, question-answering, etc.)
        framework: The actual model to convert the pipeline from ("pt" or "tf")
        model: The model name which will be loaded by the pipeline
        tokenizer: The tokenizer name which will be loaded by the pipeline, default to the model's value

    Returns: Pipeline object

    Nr   LCannot convert because PyTorch is not installed. Please install torch first.r   LCannot convert because TF is not installed. Please install tensorflow first.zLoading pipeline (model: z, tokenizer: rX   )rE   rl   rM   model_kwargs)r   	Exceptionr   r?   r   )rw   rM   rE   rl   Zmodels_kwargsr(   r(   r)   load_graph_from_args   s    r|   )rL   opsetr   use_external_formatc                 C   s   t  stdddl}ddlm} ddlm} td|j  |	 p t
| d\}}}	}
t| j|
|\}}|r|| j|| |||	d|d|d	
 n|| j|| |||	d|d
 W 5 Q R X dS )a  
    Export a PyTorch backed pipeline to ONNX Intermediate Representation (IR

    Args:
        nlp: The pipeline to be exported
        opset: The actual version of the ONNX operator set to use
        output: Path where will be stored the generated ONNX model
        use_external_format: Split the model definition from its parameters to allow model bigger than 2GB

    Returns:

    rx   r   N)export)is_torch_less_than_1_11zUsing framework PyTorch: r   T)frG   rt   ru   do_constant_foldingZuse_external_data_formatZenable_onnx_checkeropset_version)r   rG   rt   ru   r   r   )r   r{   torchZ
torch.onnxr   Ztransformers.pytorch_utilsr   r?   r:   Zno_gradrv   rK   rE   as_posix)rL   r}   r   r~   r   r   r   rG   rt   ru   rF   rI   rH   r(   r(   r)   convert_pytorch  s@    
r   )rL   r}   r   c              
      s   t  stdtd zddl ddl}ddlm} td jj d|  t| d\}}}}| j	
|j  fd	d
| D }	|jj| j	|	|| d\}
}W n@ tk
r } z"td|j d|j d| W 5 d}~X Y nX dS )av  
    Export a TensorFlow backed pipeline to ONNX Intermediate Representation (IR)

    Args:
        nlp: The pipeline to be exported
        opset: The actual version of the ONNX operator set to use
        output: Path where will be stored the generated ONNX model

    Notes: TensorFlow cannot export model bigger than 2GB due to internal constraint from TensorFlow

    ry   zD/!\ Please note TensorFlow doesn't support exporting model > 2Gb /!\r   N)r:   zUsing framework TensorFlow: z, tf2onnx: r   c                    s    g | ]\}} j j||d qS ))rN   )Z
TensorSpecZfrom_tensor)rQ   keyrd   r   r(   r)   rT   U  s     z&convert_tensorflow.<locals>.<listcomp>)r}   Zoutput_pathzCannot import z6 required to convert TF model to ONNX. Please install z first. )r   r{   r?   Z
tensorflowtf2onnxr:   versionVERSIONrv   rE   Zpredictdatarn   convertZ
from_kerasr   r<   rN   )rL   r}   r   r   Zt2ovrG   rt   ru   rF   Zinput_signatureZmodel_proto_er(   r   r)   convert_tensorflow8  s*       r   F)rM   rE   r   r}   rl   r~   rw   c           	      K   s   t dt td|  t|| ||f|}|j sVtd|j  t|j  n,t	t
|j dkrtd|j  d| dkrt|||| nt||| dS )	a  
    Convert the pipeline object to the ONNX Intermediate Representation (IR) format

    Args:
        framework: The framework the pipeline is backed by ("pt" or "tf")
        model: The name of the model to load for the pipeline
        output: The path where the ONNX graph will be stored
        opset: The actual version of the ONNX operator set to use
        tokenizer: The name of the model to load for the pipeline, default to the model's name if not provided
        use_external_format:
            Split the model definition from its parameters to allow model bigger than 2GB (PyTorch only)
        pipeline_name: The kind of pipeline to instantiate (ner, question-answering, etc.)
        model_kwargs: Keyword arguments to be forwarded to the model constructor

    Returns:

    zoThe `transformers.convert_graph_to_onnx` package is deprecated and will be removed in version 5 of TransformerszONNX opset version set to: zCreating folder r   zFolder z" is not empty, aborting conversionr   N)warningswarnFutureWarningr?   r|   r2   existsr   r   ra   r   r{   r   r   )	rM   rE   r   r}   rl   r~   rw   rz   rL   r(   r(   r)   r   `  s    
r   )onnx_model_pathr1   c                 C   sT   ddl m}m} t| d}| }| |_||  |}td| d td |S )a>  
    Load the model at the specified path and let onnxruntime look at transformations on the graph to enable all the
    optimizations possible

    Args:
        onnx_model_path: filepath where the model binary description is stored

    Returns: Path where the optimized model binary description has been saved

    r   InferenceSessionSessionOptionsz
-optimizedz$Optimized model has been written at    : ✔zY/!\ Optimized model contains hardware specific operators which might not be portable. /!\)r9   r   r   r7   r   Zoptimized_model_filepathr?   )r   r   r   Zopt_model_pathZsess_optionr   r(   r(   r)   optimize  s    

r   c                 C   s  ddl }ddl}ddlm} ddlm} ddlm} ddlm	} |
|  }t|jtdk rhtd | }|| t|jtd	k r||d
d
|jd
dd
dddt|d}	n$||d
d
|jd
dd
dddt|d}	|	  t| d}
td|
 d ||	jj|
  |
S )z
    Quantize the weights of the model from float32 to in8 to allow very efficient inference on modern CPU

    Args:
        onnx_model_path: Path to location the exported ONNX model is stored

    Returns: The Path generated for the quantized
    r   N)
ModelProto)QuantizationMode)ONNXQuantizer)IntegerOpsRegistryz1.5.0zpModels larger than 2GB will fail to quantize due to protobuf constraint.
Please upgrade to onnxruntime >= 1.5.0.z1.13.1FT)rE   per_channelreduce_rangemodestaticweight_qTypeZinput_qTypetensors_rangenodes_to_quantizenodes_to_excludeop_types_to_quantize)rE   r   r   r   r   r   Zactivation_qTyper   r   r   r   z
-quantizedz$Quantized model has been written at r   )onnxr9   Zonnx.onnx_pbr   Zonnxruntime.quantizationr   Z'onnxruntime.quantization.onnx_quantizerr   Z!onnxruntime.quantization.registryr   loadr   r   r:   r?   ZCopyFromZ
IntegerOpsr_   Zquantize_modelr7   Z
save_modelrE   )r   r   r9   r   r   r   r   Z
onnx_modelZ
copy_modelZ	quantizerZquantized_model_pathr(   r(   r)   quantize  sZ    	

r   )pathc              
   C   s   ddl m}m} ddlm} td|  d z.| }||  |dgd}td|  d	 W n2 |k
r } ztd
| d W 5 d }~X Y nX d S )Nr   r   )RuntimeExceptionz"Checking ONNX model loading from: z ...ZCPUExecutionProvider)	providerszModel u    correctly loaded: ✔zError while loading the model u   : ✘)r9   r   r   Z+onnxruntime.capi.onnxruntime_pybind11_stater   r?   r   )r   r   r   r   Zonnx_optionsr   rer(   r(   r)   verify  s    r   __main__z'
====== Converting model to ONNX ======r   aV  	 Using TensorFlow might not provide the same optimization level compared to PyTorch.
	 For TensorFlow users you can try optimizing the model directly through onnxruntime_tools.
	 For more information, please refer to the onnxruntime documentation:
		https://github.com/microsoft/onnxruntime/tree/master/onnxruntime/python/tools/transformers
z$
====== Optimizing ONNX model ======z+
====== Check exported ONNX model(s) ======optimized_outputquantized_outputz"Error while converting the model: r>   )N)NFr   )=r   argparser   osr   r   pathlibr   typingr   r   r   r	   Zpackaging.versionr
   r   Ztransformers.pipelinesr   r   Ztransformers.tokenization_utilsr   Ztransformers.utilsr   r   r   r;   r#   r   r"   r7   r=   rK   rv   r|   r$   rk   r   r   r   r   r   r   r*   parser
parse_argsargsr   absoluter?   rM   rE   r}   rl   r~   r   r   Zcheck_loadinghasattrr{   r   exitr(   r(   r(   r)   <module>   s   .&A    7-   2K



