
    g?                        d dl Z d dlZd dlmZ d dlZd dlmZ d dlZd Zd Z	dej                  fdZ	 	 d*dej                  d	ed
eej                     dee j                     fdZej                   j"                  ddfdej                  dej                  dej                   dedef
dZdej(                  fdZdej(                  fdZdej(                  fdZdej(                  dedefdZdej(                  dedegfdZdej                  fdZded ed!ej:                  d"ej:                  fd#Zdej(                  ded efd$Zdej(                  fd%Z dejB                  fd&Z"d' Z# G d( d)      Z$y)+    N)Optional)version_converterc                     | j                   D ]E  } ||fi | |j                  D ]+  }|j                  d      st        |j                  |fi | - G y)a  
    Iterate the graph including subgraphs calling the per_node_func for each node.
    :param graph: Graph to iterate
    :param per_node_func: Function to call for each node. Signature is fn(node: onnx:NodeProto, **kwargs)
    :param func_args: The keyword args to pass through.
    gN)node	attributeHasFielditerate_graph_per_node_funcr   )graphper_node_func	func_argsr   attrs        W/var/www/openai/venv/lib/python3.12/site-packages/onnxruntime/tools/onnx_model_utils.pyr
   r
      sL     

d(i(NND}}S!+DFFMOYO #     c                      || fi | | j                   D ]<  }|j                  D ]+  }|j                  d      st        |j                  |fi | - > y)a#  
    Iterate the graph including subgraphs calling the per_graph_func for each Graph.
    :param graph: Graph to iterate
    :param per_graph_func: Function to call for each graph. Signature is fn(graph: onnx:GraphProto, **kwargs)
    :param func_args: The keyword args to pass through.
    r   N)r   r   r	   iterate_graph_per_graph_funcr   )r   per_graph_funcr   r   r   s        r   r   r      sL     5&I&

NND}}S!,TVV^QyQ # r   modelc                 j    i }| j                   D ]!  }|j                  xs d}|j                  ||<   # |S )zu
    Get the opsets imported by the model
    :param model: Model to check.
    :return: Map of domain to opset.
    zai.onnx)opset_importdomainversion)r   opsetsentryr   s       r   get_opsets_importedr   /   s;     F##*v $
 Mr   
model_pathopsetout_pathloggerc                 &   t        | j                  d            }|r|j                  d||       t        j                  |      }t        j                  ||      }|r3t        j                  |t        |             |r|j                  d|       |S )a  
    Helper to update the opset of a model using onnx version_converter. Target opset must be greater than current opset.
    :param model_path: Path to model to update
    :param opset: Opset to update model to
    :param out_path: Optional output path for updated model to be saved to.
    :param logger: Optional logger for diagnostic output
    :returns: Updated onnx.ModelProto
    TstrictzUpdating %s to opset %dzSaved updated model to %s)strresolveinfoonnxloadr   convert_versionsave)r   r   r   r   model_path_strr   	new_models          r   update_onnx_opsetr,   >   s}     ++4+89N-~uEIIn%E!11%?I		)S]+KK3X>r      Foutput_pathlevel	log_leveluse_external_initializersc                    t        j                         }t        |j                               |_        ||_        ||_        |rlt         j                  j                  dd      \  }}}t        |      t        |      fdk\  r|j                  dd       nt        dt         j                         t        j                  t        | j                  d            |d	g
      }	y)a  
    Optimize an ONNX model using ONNX Runtime to the specified level
    :param model_path: Path to ONNX model
    :param output_path: Path to save optimized model to.
    :param level: onnxruntime.GraphOptimizationLevel to use. Default is ORT_ENABLE_BASIC.
    :param log_level: Log level. Defaults to Error (3) so we don't get output about unused initializers being removed.
                      Warning (2) or Info (1) may be desirable in some scenarios.
    :param use_external_initializers: Set flag to write initializers to an external file. Required if model > 2GB.
                                      Requires onnxruntime 1.17+
    .r-   )      z7session.optimized_model_external_initializers_file_namezexternal_data.pbzONNX Runtime 1.17 or higher required to save initializers as external data when optimizing model. Current ONNX Runtime version is Tr!   CPUExecutionProvider)	providersN)ortSessionOptionsr#   r$   optimized_model_filepathgraph_optimization_levellog_severity_level__version__splitintadd_session_config_entry
ValueErrorInferenceSession)
r   r.   r/   r0   r1   somajorminorrest_s
             r   optimize_modelrH   ]   s    " 
			B"%k&9&9&;"<B"'B%B ! __223:udJE
#w.''(acuv336??2CE  	S!3!34!3!@A2RhQijAr   r   c                     |d   |d   fd} || j                           || j                          || j                         y )N	dim_paramvaluec                 &   | D ]  }|j                   j                  d      s|j                   j                  j                  }|sB|j                  D ];  }|j                  d      s|j
                  k(  s%|j                          |_        =  y )Ntensor_typerJ   )typer	   rM   shapedimrJ   Clear	dim_value)value_infosvirO   rP   param_to_replacerK   s       r   update_dim_valuesz6_replace_symbolic_dim_value.<locals>.update_dim_values   sm    Bww.++11$yy<<4JZ9ZIIK,1CM  )	 r   inputoutput
value_info)r   kwargsrV   rU   rK   s      @@r   _replace_symbolic_dim_valuer\      sD    k*7OE2 ekk"ell#e&&'r   c                     d }| j                   D ]
  } ||        | j                  D ]
  } ||        | j                  D ]
  } ||        y )Nc                    | j                   j                  d      rg| j                   j                  j                  }|rD|j                  D ]4  }|j                  d      s|j
                  dk  s%|j                          6 y y y )NrM   rR   r4   )rN   r	   rM   rO   rP   rR   rQ   )rK   rO   rP   s      r   clear_invalid_valuesz=_remove_invalid_dim_values_impl.<locals>.clear_invalid_values   sd    ::}-JJ**00E 99C||K0S]]Q5F		 %  .r   rW   )r   r_   iorT   s        r   _remove_invalid_dim_values_implrb      sQ    $ [[Q  \\Q  R  r   c                 $    t        | t               y)z
    Iterate the graph and subgraphs, unsetting any dim_value entries that have a value of less than 1.
    These are typically erroneously inserted by a converter to represent a dynamic dimension.
    :param graph: GraphProto to update
    N)r   rb   )r   s    r   remove_invalid_dim_valuesrd      s     !(GHr   
param_namerK   c                 *    t        | t        ||       y)z
    Iterate all values in the graph, replacing dim_param in a tensor shape with the provided value.
    :param graph: GraphProto to update
    :param param_name: dim_param to set
    :param value: value to use
    )rJ   rK   N)r   r\   )r   re   rK   s      r   make_dim_param_fixedrg      s     !(Czafgr   
input_namefixed_shapec                 r   t        |        | j                  D ]V  }|j                  |k(  s|j                  j	                  d      st        d| d      |j                  j                  j                  }t        |j                        t        |      k7  r-t        dt        |j                         dt        |             t        |j                        D ]  \  }}|j	                  d      r7|j                  ||   k7  s*t        d|j                   d||    d	|d
z          |j	                  d      rt        | |j                  ||          z|j                          ||   |_          y t        d| ddj                  | j                  D cg c]  }|j                   c}             c c}w )a  
    Update the named graph input to set shape to the provided value. This can be used to set unknown dims as well
    as to replace dim values.
    If setting the input shape replaces a dim_param, update any other values in the graph that use the dim_param.
    :param graph: Graph to update
    :param input_name: Name of graph input to update.
    :param fixed_shape: Shape to use.
    rM   zInput z is not a tensorzRank mismatch. Existing:z Replacement:rR   z%Can't replace existing fixed size of z with z for dimension r4   rJ   Nz7 was not found in graph inputs. Valid input names are: ,)rd   rX   namerN   r	   rA   rM   rO   lenrP   	enumeraterR   rg   rJ   rQ   join)r   rh   ri   r`   rO   idxrP   s          r   make_input_shape_fixedrq      s    e$[[66Z66??=1 6*5E!FGG FF&&,,E599~[!11 #;C		N;K=Y\]hYiXj!kll%eii0S<<,}}C(88(CCMM?RXYdehYiXj k--01WI7  \\+.({3?OP IIK$/$4CM 1  5 8 
 ""%((EKK+HKqAFFK+H"I!J	L +Hs   F4c                    t         j                  j                  |       }t         j                  j	                  |       t        | j                  j                        D ]  \  }}t        |      r|j                  j                  |   }t        |      s7|j                  j                  j                  j                  |j                  j                  j                          y)a
  
    Update the output shapesof a model where the input shape/s were made fixed, if possible.
    This is mainly to make the model usage clearer if the output shapes can be inferred from the new input shapes.
    :param model: Model that had input shapes fixed.
    N)r&   shape_inferenceinfer_shapescheckercheck_modelrn   r   rY   is_fixed_size_tensorrN   rM   rO   CopyFrom)r   m2rp   ra   new_os        r   fix_output_shapesr{      s     
			*	*5	1BLLR EKK../Q#A&HHOOC(E#E*""((11%**2H2H2N2NO	 0r   node_to_producersnode_to_consumersproducerconsumerc                     || vrt               | |<   ||vrt               ||<   | |   j                  |       ||   j                  |       y)a  
    Create links between two nodes for a value produced by one and consumed by the other.
    :param node_to_producers: Map of NodeProto to set of nodes that produce values the node consumes as inputs.
    :param node_to_consumers: Map of NodeProto to set of nodes that consume values the node produces as outputs.
    :param producer: Producer node
    :param consumer: Consumer node
    N)setadd)r|   r}   r~   r   s       r   _create_producer_consumer_linkr      sX     ((&)e(#((&)e(# h##H-h##H-r   c                 V   | j                   D ch c]  }|j                   c}| j                  D ch c]  }|j                   c}i t               }fd}| j                  D ]  }|j                   D cg c]  }| }}|j
                  D ]0  }|j                  d      st        |j                  ||      }	||	z  }2 |D ]7  }|s ||      r|v s|   }
t        |||
|       '|j                  |       9 |j                  D ]  }||<   	  |S c c}w c c}w c c}w )Nc                 $    | v xs
 | v xs | v S N )rK   graph_inputsinitializers	producerss    r   is_local_valuez._map_node_dependencies.<locals>.is_local_value  s"    	!SUl%:Se|>SSr   r   )rX   rl   initializerr   r   r   r	   _map_node_dependenciesr   r   r   rY   )r   r|   r}   r`   implicit_inputsr   r   inputsr   subgraph_implicit_inputsr~   ra   r   r   r   s               @@@r   r   r     s.   $)KK0KqAFFK0L$)$5$56$5qAFF$56L IeOT 

!ZZ(Z!Z(NND}}S!+A$&&J[]n+o(22 #
 Aa 	>(|H23DFWYacgh##A&  AIaL ) . E 16 )s   DD!<	D&c                     d t         j                  _        i }i }t        | ||      }|r&t	        ddj                  t        |                   ||fS )ab  
    Get maps for connections between the node that produces each value and the nodes that consume the value.
    Processing includes subgraphs. As the map key is a Node instance from the Graph there should be no ambiguity.
    :param graph: Graph to process.
    :return: Tuple with two maps.
             First is node_to_producers map of a node to set of all nodes producing input it consumes.
             Second is node_to_consumers map of a node to set of all nodes consuming output it creates.
             e.g. NodeA and NodeB provide inputs to NodeC. NodeC provides input to NodeD
             node_to_consumers[NodeA] = set([NodeC])
             node_to_consumers[NodeB] = set([NodeC])
             node_to_producers[NodeC] = set([NodeA, NodeB])
             node_to_consumers[NodeC] = set([NodeD])
             node_to_producers[NodeD] = set([NodeC])
    c                     t        |       S r   )idselfs    r   <lambda>z,get_producer_consumer_maps.<locals>.<lambda>J  s    2d8r   z;This appears to be an invalid model with missing inputs of rk   )r&   	NodeProto__hash__r   rA   ro   sorted)r   r|   r}   r   s       r   get_producer_consumer_mapsr   8  sg    $ 4DNN,U4EGXYO I#((SYZiSjJkIlm
 	
 ///r   c                     d}| j                   j                  d      rZ| j                   j                  j                  }|r8d}|j                  D ]'  }|j                  d      r|j
                  dkD  r$d} |S  |S )z
    Check if value is a tensor with a fixed shape.
    :param value: onnx.ValueInfoProto to check
    :return: True if value is a tensor, with a shape, where all dimensions have fixed values.
    FrM   TrR   r   )rN   r	   rM   rO   rP   rR   )rK   is_fixedrO   rP   s       r   rw   rw   Z  sv     Hzz=)

&&,,Hyy<<,1B !O ! Or   c                    | dk(  rt         j                  j                  S | dk(  rt         j                  j                  S | dk(  rt         j                  j                  S | dk(  rt         j                  j
                  S t        d| z         )z)Convert string to GraphOptimizationLevel.disablebasicextendedallzInvalid optimization level of )r8   GraphOptimizationLevelORT_DISABLE_ALLORT_ENABLE_BASICORT_ENABLE_EXTENDEDORT_ENABLE_ALLrA   )r/   s    r   get_optimization_levelr   q  sz    	))999)):::
))===~))888
5=
>>r   c                   6    e Zd ZdZdej
                  fdZd Zy)ModelProtoWithShapeInfoac  
    Class to load an ONNX model and run shape inferencing on it to populate the ValueInfo.
    The model_with_shape_info property will contain the updated model.
    If the model is > 2GB and uses external data a temporary file is required to run shape inferencing successfully.
    This helper class handles automatic removal of the temporary file.
    r   c                 p   || _         t        j                  t        |            }t        j                  j                  |d      | _        d| _        t        |j                  j                        dkD  rt        | j                  j                  j                        dk(  rt        j                  |      j                  d      | _        t        j                  j                  t        |      t        | j                        d       t        j                  t        | j                              | _        yyy)z]
        :param model_path: Path to ONNX model to load and run shape inferencing on.
        T)strict_modeNr   z.temp_with_shapeinf.onnx)r   r&   r'   r#   rs   rt   model_with_shape_info_tmp_model_pathrm   r   r   pathlibPathwith_suffixinfer_shapes_path)r   r   r   s      r   __init__z ModelProtoWithShapeInfo.__init__  s    
 %		#j/*%)%9%9%F%FuZ^%F%_"  $u{{ 1$T-G-G-M-M-R-R)SWX)X#*<<
#;#G#GHb#cD   223z?CH\H\D]ko2p)-3t7K7K3L)MD& *Y$r   c                 V    | j                   r| j                   j                  d       y y )NT)
missing_ok)r   unlinkr   s    r   __del__zModelProtoWithShapeInfo.__del__  s'      ''4'8  r   N)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   r     s    N7<< N$9r   r   )NN)%loggingr   typingr   r&   r   onnxruntimer8   r
   r   
ModelProtor   r   r?   Loggerr,   r   r   boolrH   
GraphProtor\   rb   rd   r#   rg   rq   r{   dictr   r   r   r   ValueInfoProtorw   r   r   r   r   r   <module>r      s       " P R"t $ (,'+	 w||$ W^^$	D ),(B(B(S(S&+"k"k"k %%"k 	"k
  $"kJ(t (&!4?? !&IT__ Ih hS h h,$// ,s ,RUQV ,^PT__ P$..04.@D.Z^ZhZh.,#$// #d #_c #L0doo 0D 3 3 .? 9 9r   