Ë
    ëÓ^j”´  ã                  ó²  — U d Z ddlm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
mZ ddlZddlmZ ddlmZ  e«       Zh d£Zd	ed
<   dZded<    eh d£«      Zded<   dZded<   d d„Zd!d„Zd"d„Zej8                  d#d„«       Zej8                  d$d„«       Zef	 	 	 	 	 	 	 	 	 d%d„Zd&d„Z ef	 	 	 	 	 	 	 	 	 	 	 d'd„Z!d(d„Z"dddefddœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d)d„Z#y)*u�  ONNX â†’ TFLite conversion using the ``onnx2tf`` library.

``onnx2tf`` (PINTO0309) converts an ONNX graph to TFLite.  **Version 2.4.0 or later is required** â€” earlier 1.x releases
cannot lower three op patterns in the RF-DETR graph (constant Expand, 1-D TopK, rank-3 Tile). Although the onnx2tf 2.x
default backend is ``flatbuffer_direct``, RF-DETR unconditionally forces ``tflite_backend="tf_converter"`` to avoid a
runtime error in the TFLite TopK_V2 kernel (``flatbuffer_direct`` trips a "k > internal dimension" check at
``AllocateTensors()`` time).  ``Erf`` and ``GeLU`` activations are replaced with TFLite-native pseudo-operators
(``replace_to_pseudo_operators=["Erf", "GeLU"]``) so the produced model does not require the TensorFlow Flex delegate at
inference time.

GridSample rewrite
------------------
RF-DETR's deformable cross-attention uses :func:`torch.nn.functional.grid_sample` once per decoder layer (6 calls
total).  ``onnx2tf``'s built-in GridSample handler lowers the op to ``tf.gather_nd(batch_dims=1)``, which TFLite's
``GatherNd`` kernel does not support â€” the kernel silently accepts the call during ``AllocateTensors()`` but produces
numerically wrong output at inference time, causing all detection scores to collapse from ~0.6 to ~0.1. The
``replace_to_pseudo_operators=["GridSample"]`` pseudo-op path also produces numerically wrong logit magnitudes in both
FP32 and FP16 (the pseudo-op itself is broken, not a quantization issue).  An earlier ONNX-level rewrite using
``GatherElements(axis=2)`` was lowered to ``tf.gather_nd(batch_dims=2)``, which TFLite does not support and crashes with
index out-of-bounds at inference time.

Before invoking ``onnx2tf``, :func:`_replace_gridsample_for_tflite` rewrites every ``GridSample`` node in the ONNX graph
into an equivalent bilinear sampling subgraph built from ``Gather(axis=0)`` on a transposed and flattened
``(N*(H+2)*(W+2), C)`` image tensor.  ``onnx2tf`` lowers ``Gather(axis=0)`` to TFLite's ``GATHER`` op with no
``batch_dims`` â€” the only TFLite gather path that is unconditionally supported, neither crashing on
``AllocateTensors()`` nor producing wrong values.

The converter uses the ``onnx2tf`` Python API directly (rather than shelling out to the CLI) so that we can:

* Apply a compatibility shim for older ``onnx2tf`` releases that call
  :func:`numpy.load` on pickled data without ``allow_pickle=True``.
* Redirect ``onnx2tf``'s built-in ``download_test_image_data()`` to use
  locally-prepared calibration data instead of downloading from GitHub (which can fail in many environments).

``onnx2tf`` calls ``download_test_image_data()`` for its ONNX-vs-TF output validation.  ``_patch_validation_download()``
redirects that call to local data, avoiding the network dependency.

INT8 quantization
-----------------
``quantization="int8"`` produces a **dynamic-range** INT8 model (INT8 weights, float activations, roughly 4x smaller
than FP32, no calibration data needed), built from the ``onnx2tf`` SavedModel.

Static (full-integer) INT8 is not supported and raises ``ValueError``: RF-DETR's transformer activations do not survive
8-bit post-training quantization.

Note:
    The resulting ``.tflite`` model expects the same input normalization as the ONNX model: ImageNet mean/std
    (``mean=[0.485, 0.456, 0.406]``, ``std=[0.229, 0.224, 0.225]``).  The caller is responsible for applying this
    normalization at inference time.

Note:
    Segmentation models additionally emit a ``masks`` output.  FP32, FP16, and dynamic-range INT8 all match the PyTorch
    baseline closely (INT8 mask fidelity is marginally lower).  Verified on the non-plus segmentation
    variants: Nano, Small, Medium, Large, and Preview.
é    )ÚannotationsN)ÚPath)ÚAnyÚ	GeneratorÚcast)ÚNDArray)Ú
get_logger>   NÚfp16Úfp32Úint8zset[str | None]Ú_VALID_QUANTIZATIONSé   ÚintÚ_DEFAULT_CALIB_SAMPLES>   ú.bmpú.jpgú.pngú.jpegú.webpzfrozenset[str]Ú_IMAGE_EXTENSIONSéd   Ú_DEFAULT_DIR_CALIB_SAMPLESc          
     óz  ‡]‡^‡_‡`‡a‡b‡c‡d‡e‡f‡g‡h‡i‡j‡k‡l‡m— ddl Šeddl}ddlŠ`| j                  d   }| j                  d   }| j                  d   }| j
                  j                  dd«      }| j
                  j                  dd«      }| j
                  j                  dd«      }	|dk7  s
|dk7  s|	dk7  rt        d	|›d
|›d|	› �«      ‚|j                  �t        |j                  «      dk7  rt        d|j                  › �«      ‚|j                  �t        |j                  «      dk7  rt        d|j                  › �«      ‚d|› �ŠidgŠj‰ej                  dfdˆˆ`ˆiˆjfd„Šk‰ej                  dfd‰ˆ`ˆeˆiˆjfd„Š_g ŠddŠd‹ˆ`ˆdfd„Šgt        |j                  j                  «      Šat        |j                  j                  «      }
 ‰_ ‰ej                   d«      ‰ej                   d«      } ‰_ ‰ej                   d«      ‰ej                   d«      } ‰_ ‰ej                   d«      ‰ej                   d«      } ‰_ ‰ej                  d«      ‰ej                  d«      Šm ‰_ ‰ej                  d«      ‰ej                  d«      Šf ‰_ ‰ej                  d«      ‰ej                  d«      } ‰_ ‰ej                  d«      ‰ej                  d«      } ‰_dg‰ej                   d «      Š] ‰_d!g‰ej                   d"«      } ‰_d#g‰ej                   d$«      Šc ‰kd%‰ej                   dg¬&«      } ‰gd'|g|g«        ‰kd(‰ej                   dg¬&«      } ‰gd'|g|g«       dŒˆ_ˆeˆgˆkfd)„} ||dd*«      } ||dd+«      } ||dd,«      } ||d!d-«      } ||dd.«      } ||dd/«      } ‰kd0‰ej                   ¬1«      } ‰gd2||g|g«        ‰kd3‰ej                   ¬1«      Šh ‰gd2||g‰hg«        ‰kd4‰ej                   ¬1«      } ‰gd5|‰hg|g«        ‰kd6‰ej                   ¬1«      } ‰gd5||g|g«        ‰kd7‰ej                  ¬1«      } ‰gd8|g|gd9|
i«        ‰kd:‰ej                  ¬1«      } ‰gd8|g|gd9|
i«        ‰kd;‰ej                  ¬1«      } ‰gd8‰hg|gd9|
i«        ‰kd<‰ej                  ¬1«      }  ‰gd8|g| gd9|
i«        ‰kd=‰ej                  ¬1«      }! ‰gd>||g|!g«        ‰kd?‰ej                  ¬1«      }" ‰gd>||g|"g«        ‰kd@‰ej                  ¬1«      }# ‰gdA|‰fg|#g«        ‰kdB‰ej                  ¬1«      }$ ‰gdA| ‰fg|$g«       d�ˆ]ˆeˆgˆkfdC„}% |%|dD«      }& |%|dE«      }' |%|dF«      }( |%|dG«      }) |%|dH«      }* ‰kdI‰ej                   dg¬&«      }+ ‰gdJ|*|'g|+gdKdi«        ‰kdL‰ej                   dg¬&«      }, ‰gdJ|&|(|)|'g|,gdKdi«        ‰_g dM¢‰ej                   dN«      }- ‰kdO«      }. ‰gdP||-g|.g«        ‰kdQ«      }/ ‰gdR|.g|/gdSg dT¢i«        ‰kdU«      Šb ‰gdV|/|+g‰bg«        ‰kdW«      }0 ‰gdX| ‰_dg‰ej                   dY«       ‰_dg‰ej                   dZ«      |g|0g«        ‰kd[«      }1 ‰gd\|0|g|1g«        ‰kd]«      }2 ‰gdX| ‰_dg‰ej                   d^«       ‰_dg‰ej                   d_«      |g|2g«        ‰kd`«      }3 ‰gd\|2|g|3g«        ‰kda«      }4 ‰gd2|1‰fg|4g«        ‰kdb«      }5 ‰gd5|4|!g|5g«        ‰kdc«      }6 ‰gdA|5|g|6g«        ‰kdd«      }7 ‰gd2|3‰fg|7g«        ‰kde«      }8 ‰gd5|7|"g|8g«        ‰kdf«      }9 ‰gdA|8|g|9g«        ‰kdg«      }: ‰gdh|6g|:g«        ‰kdi«      }; ‰gdh|9g|;g«        ‰kdj«      }< ‰gd2|:‰fg|<g«        ‰kdk«      }= ‰gd2|;‰fg|=g«        ‰kdl«      }> ‰gdA|6|:g|>g«        ‰kdm«      }? ‰gdA|9|;g|?g«        ‰kdn«      }@ ‰gdA‰f|>g|@g«        ‰kdo«      }A ‰gdA‰f|?g|Ag«       dŽˆaˆeˆfˆgˆkˆmfdp„}B |B|:|#dq«      }C |B|<|#dr«      }D |B|;|$ds«      }E |B|=|$dt«      }F ‰kdu‰ej                   ¬1«      }G ‰gdv|||g|Gg«        ‰kdw‰ej                   ¬1«      }H ‰gd5|G|g|Hg«        ‰_g dx¢‰ej                   dy«      }I ‰kdz‰ej                   ¬1«      Š^ ‰gdV|H|Ig‰^g«       d�ˆ^ˆcˆeˆgˆhˆkfd{„}J |J|C|Ed|«      }K |J|D|Ed}«      }L |J|C|Fd~«      }M |J|D|Fd«      }Nd�ˆbˆgˆkfd€„}O |O|Kd|«      }P |O|Ld}«      }Q |O|Md~«      }R |O|Nd«      }S ‰_d#dg‰ej                   d�«      Šld‘ˆgˆkˆlfd‚„}T |T|P|@|Ad|«      }U |T|Q|>|Ad}«      }V |T|R|@|?d~«      }W |T|S|>|?d«      }X ‰kdƒ«      }Y ‰gd2|U|Vg|Yg«        ‰kd„«      }Z ‰gd2|Y|Wg|Zg«        ‰kd…«      }[ ‰gd2|Z|Xg|[g«        ‰kd†«      }\ ‰gdV|[|,g|\g«        ‰gdR|\g|gdSg d‡¢i«       | j                  j#                  «        | j                  j#                  «        |j$                  j'                  ‰d«       y)’u”  Rewrite one GridSample ONNX node into a TFLite-safe bilinear subgraph.

    Replaces ``GridSample(im, grid)`` with an equivalent bilinear sampling subgraph that performs four
    ``Gather(axis=0)`` lookups on a transposed and flattened ``(N*(H+2)*(W+2), C)`` image tensor.  ``onnx2tf`` lowers
    ``Gather(axis=0)`` to TFLite's ``GATHER`` op with no ``batch_dims`` â€” the only TFLite gather path that is
    unconditionally supported, neither crashing on ``AllocateTensors()`` nor producing wrong values. Per-sample batch
    offsets are added to the flat index so that a single rank-1 ``Gather`` covers the entire batch.

    The replacement is mathematically identical to PyTorch's ``F.grid_sample`` for ``mode="bilinear"``,
    ``padding_mode="zeros"``, ``align_corners=0``.  Out-of-bounds sample positions are clamped to the zero-padded
    border, which has the same effect as PyTorch's zero padding.

    Shape-dependent values are computed at runtime via ONNX Shape/Gather/ Concat/Cast ops so the subgraph works for any
    static or dynamic input shape.

    Args:
        node: The ``gs.Node`` to replace (must be a ``GridSample`` node).
        graph: The ``gs.Graph`` that owns *node*.
        index: Unique integer suffix used to namespace tensor/constant names.

    Raises:
        NotImplementedError: If the node has unsupported attributes.
        ValueError: If ``im`` or ``grid`` are not rank-4 tensors.
    r   Né   ÚmodeÚbilinearÚpadding_modeÚzerosÚalign_cornerszgGridSample TFLite patch only supports mode='bilinear', padding_mode='zeros', align_corners=0; got mode=z, padding_mode=z, align_corners=é   z9GridSample TFLite patch requires rank-4 im; got im.shape=z=GridSample TFLite patch requires rank-4 grid; got grid.shape=Ú_gsreplc                ó\   •— ‰dxx   dz  cc<   ‰j                  ‰› d‰d   › d| › �||¬«      S )Nr   r   Ú_©ÚdtypeÚshape)ÚVariable)Únamer%   r&   ÚgsÚpfxÚuids      €€€új/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/rfdetr/export/_tflite/converter.pyÚvz%_replace_single_gridsample.<locals>.vŽ   s:   ø€ ØˆA‹�!‰‹Ø�{‰{˜c˜U ! C¨¡F 8¨1¨T¨FÐ3¸5Èˆ{ÓNÐNó    Ú c                ó|   •— ‰dxx   dz  cc<   ‰j                  ‰› d‰d   › d|› � ‰j                  | |¬«      «      S )Nr   r   r#   Ú_c_©r%   )ÚConstantÚarray)Úvalr%   r(   r)   Únpr*   r+   s      €€€€r,   Úcz%_replace_single_gridsample.<locals>.c’   sC   ø€ ØˆA‹�!‰‹Ø�{‰{˜c˜U ! C¨¡F 8¨3¨t¨fÐ5°x°r·x±xÀÈ5Ô7QÓRÐRr.   c           	     óV   •— ‰j                  ‰j                  | |||xs i ¬«      «       y )N)ÚopÚinputsÚoutputsÚattrs)ÚappendÚNode)ÚkindÚinsÚoutsr<   r)   Únodess       €€r,   r9   z&_replace_single_gridsample.<locals>.op˜   s$   ø€ Ø�‰�R—W‘W ¨S¸$ÀeÂkÈr�WÓRÕSr.   Úzero_iÚone_ié   Útwo_ig        Úzero_fg      ð?Úone_fg       @Útwo_fg      à?Úhalf_fÚax0_1dé   Úax3_1déÿÿÿÿÚneg1_1dÚim_shaper$   ÚShapeÚ
grid_shapec                ó    •—  ‰|‰j                   ¬«      } ‰d|  ‰ ‰j                   |«      ‰j                   d|› d|› �«      g|gddi«       |S )Nr2   ÚGatherÚir#   Úaxisr   ©Úint64)Úshape_tÚaxis_idxr(   Úresultr7   r6   r9   r-   s       €€€€r,   Ú
gather_dimz._replace_single_gridsample.<locals>.gather_dim´   s[   ø€ Ù�4˜rŸx™xÔ(ˆÙ
ˆ8�g™q  §¡¨(Ó!3°R·X±XÀÀ8À*ÈAÈdÈVÐ?TÓUÐVÐY_ÐX`ÐciÐklÐbmÔnØˆr.   ÚNÚCÚHÚWÚH_outÚW_outÚpHr2   ÚAddÚpWÚpH_pWÚMulÚN_pH_pWÚW_fÚCastÚtoÚH_fÚpW_fÚpH_fÚW_halfÚDivÚH_halfÚpW_max_fÚSubÚpH_max_fc                óN   •—  ‰|‰j                   dg¬«      } ‰d| ‰g|g«       |S )z@Promote a 0-D int64 scalar to a 1-D [1] int64 vector for Concat.r   r$   Ú	UnsqueezerW   )Úscalar_tr(   r[   rK   r6   r9   r-   s      €€€€r,   Úunsq0z)_replace_single_gridsample.<locals>.unsq0ä   s/   ø€ á�4˜rŸx™x°¨sÔ3ˆÙ
ˆ;˜ 6Ð*¨V¨HÔ5Øˆr.   ÚN_1dÚC_1dÚH_out_1dÚW_out_1dÚ
N_pH_pW_1dÚ
flat_shapeÚConcatrV   Ú
nhwc_shape)r   r   r   r   r   r   r   r   ÚpadsÚim_padÚPadÚim_nhwcÚ	TransposeÚperm)r   rE   rL   r   Úim_flatÚReshapeÚgx_rawÚSliceÚs0_gxÚe1_gxÚgxÚSqueezeÚgy_rawÚs1_gyÚe2_gyÚgyÚgxp1ÚpxrÚpxÚgyp1ÚpyrÚpyÚx0_fÚFloorÚy0_fÚx1_fÚy1_fÚwx1Úwy1Úwx0Úwy0c                ó¶   •—  ‰
d|› �«      } ‰	d| ‰g|g«        ‰
d|› �«      } ‰	d|‰|g|g«        ‰
d|› �‰j                   ¬«      } ‰	d|g|gd‰i«       |S )	NÚsh_rd   Úcl_ÚClipÚca_r2   rj   rk   rW   )Úcoord_fÚ	clamp_maxr(   ÚshiftedÚclippedÚcast_intÚi64r6   rH   r9   r-   rG   s         €€€€€€r,   Úint_shifted_clampedz7_replace_single_gridsample.<locals>.int_shifted_clamped4  sz   ø€ Ù�c˜$˜�L“/ˆÙ
ˆ5�7˜EÐ" W IÔ.Ù�c˜$˜�L“/ˆÙ
ˆ6�G˜V YÐ/°'°Ô;Ù�s˜4˜&�\¨¯©Ô2ˆÙ
ˆ6�G�9˜x˜j¨4°¨+Ô6Øˆr.   Úx0cÚx1cÚy0cÚy1cÚbatch_rangeÚRangeÚbatch_offset_flat)rN   r   r   Úbatch_offset_shapeÚbatch_offsetc                ó(  •—  ‰d|› �‰	j                   ¬«      } ‰
d|‰g|g«        ‰d|› �‰	j                   ¬«      } ‰
d|| g|g«        ‰d|› �‰	j                   ¬«      } ‰
d|‰g|g«        ‰d|› �‰	j                   ¬«      } ‰
d|‰g|g«       |S )	NÚypw_r2   rg   Úlocal_rd   Úglob_Úgidx_rˆ   rW   )ÚxcÚycr(   ÚypwÚlocalÚ
global_idxÚflat1dr¶   rO   r6   r9   ÚpW_tr-   s          €€€€€€r,   Úflat_global_indexz5_replace_single_gridsample.<locals>.flat_global_indexQ  sª   ø€ Ù�$�t�f� R§X¡XÔ.ˆÙ
ˆ5�2�t�*˜s˜eÔ$Ù�F˜4˜&�/¨¯©Ô2ˆÙ
ˆ5�3˜�)˜e˜WÔ%Ù˜˜t˜f�~¨R¯X©XÔ6ˆ
Ù
ˆ5�5˜,Ð'¨*¨Ô6Ù�U˜4˜&�>¨¯©Ô2ˆÙ
ˆ9�z 7Ð+¨f¨XÔ6Øˆr.   ÚaaÚbaÚabÚbbc                ó>   •—  ‰d|› �«      } ‰d‰| g|gddi«       |S )NÚsamp_rT   rV   r   © )Úgidxr(   Úsampledr‡   r9   r-   s      €€€r,   Úgather_flatz/_replace_single_gridsample.<locals>.gather_flatc  s0   ø€ Ù�e˜D˜6�NÓ#ˆÙ
ˆ8�g˜t�_ w i°&¸!°Ô=Øˆr.   Úwflat_shapec                ó˜   •—  ‰d|› �«      } ‰d||g|g«        ‰d|› �«      } ‰d|‰	g|g«        ‰d|› �«      } ‰d| |g|g«       |S )NÚw2d_rg   Úwflat_rˆ   Úc_rÊ   )
ÚgatheredÚwxÚwyr(   Úw_2dÚw_flatÚout_contribr9   r-   rÎ   s
          €€€r,   Úcontribz+_replace_single_gridsample.<locals>.contribq  sp   ø€ Ù�4˜�v�ÓˆÙ
ˆ5�2�r�(˜T˜FÔ#Ù�V˜D˜6�?Ó#ˆÙ
ˆ9�t˜[Ð)¨F¨8Ô4Ù˜"˜T˜F˜“nˆÙ
ˆ5�8˜VÐ$ { mÔ4ØÐr.   Ús1Ús2ÚtotalÚ
total_nhwc)r   rL   r   rE   )r(   Ústrr%   r   r&   zlist[int] | NoneÚreturnr   )r5   r   r%   r   r(   rÞ   rß   r   ©N)
r?   rÞ   r@   ú	list[Any]rA   rá   r<   zdict[str, Any] | Nonerß   ÚNone)rY   r   rZ   r   r(   rÞ   rß   r   )rw   r   r(   rÞ   rß   r   )r§   r   r¨   r   r(   rÞ   rß   r   )r¼   r   r½   r   r(   rÞ   rß   r   )rË   r   r(   rÞ   rß   r   )
rÓ   r   rÔ   r   rÕ   r   r(   rÞ   rß   r   )ÚnumpyÚonnxÚonnx_graphsurgeonr:   r;   r<   ÚgetÚNotImplementedErrorr&   ÚlenÚ
ValueErrorÚfloat32r   ÚTensorProtoÚINT64ÚFLOATrX   ÚclearrB   Úextend)nÚnodeÚgraphÚindexrä   ÚimÚgridÚoutr   r   r   Úf32rC   rD   rF   rI   rJ   rM   Ú
im_shape_tÚgrid_shape_tr\   ÚN_tÚC_tÚH_tÚW_tÚH_out_tÚW_out_tÚpH_tÚpH_pW_tÚ	N_pH_pW_tri   rl   rm   rn   ro   rq   rr   rt   rx   ry   rz   r{   r|   r}   Úflat_shape_tÚnhwc_shape_tr�   r‚   r„   r‰   r�   r�   r’   r“   r”   r•   r–   r—   r˜   r™   r›   rœ   r�   rž   rŸ   r    r¡   r­   r®   r¯   r°   r±   r²   r´   rµ   rÃ   Úgidx_aaÚgidx_baÚgidx_abÚgidx_bbrÍ   ÚsaaÚsbaÚsabÚsbbrÙ   ÚcaaÚcbaÚcabÚcbbrÚ   rÛ   rÜ   rÝ   rK   r¶   r7   r)   r¬   r‡   rO   rB   r6   rH   r9   rÂ   r*   r+   r-   rÎ   rG   sn                                                                                                @@@@@@@@@@@@@@@@@r,   Ú_replace_single_gridsampler  Z   s›
  ÿÿø€ ó2 ÛÛ"à	�‰�Q‰€BØ�;‰;�q‰>€DØ
�,‰,�q‰/€Cà�:‰:�>‰>˜& *Ó-€DØ—:‘:—>‘> .°'Ó:€LØ—J‘J—N‘N ?°AÓ6€MàˆzÒ˜\¨WÒ4¸ÈÒ8JÜ!ðà�x˜¨|Ð.>Ð>NÈ}Èoð_ó
ð 	
ð 
‡x�xÐœ3˜rŸx™x›=¨AÒ-ÜÐTÐUW×U]ÑU]ÐT^Ð_Ó`Ð`Ø‡z�zÐœS §¡›_°Ò1ÜÐXÐY]×YcÑYcÐXdÐeÓfÐfà�E�7Ð
€CØ�S€Cà"$§*¡*È÷ Oð Oð "$§¡¸÷ Sñ Sð €E÷Tô ˆd×Ñ×$Ñ$Ó
%€CÜ
ˆd×Ñ×$Ñ$Ó
%€Cñ ˆxˆr�x‰x˜‹{˜BŸH™H hÓ/€FÙˆhˆb�h‰h�q‹k˜2Ÿ8™8 WÓ-€EÙˆhˆb�h‰h�q‹k˜2Ÿ8™8 WÓ-€Eáˆzˆr�z‰z˜#‹ §
¡
¨HÓ5€FÙˆjˆb�j‰j˜‹o˜rŸz™z¨7Ó3€EÙˆjˆb�j‰j˜‹o˜rŸz™z¨7Ó3€EÙˆzˆr�z‰z˜#‹ §
¡
¨HÓ5€Fá�ˆs�B—H‘H˜hÓ'€FÙ�ˆs�B—H‘H˜hÓ'€FÙ���b—h‘h 	Ó*€Gñ
 �: R§X¡X°a°SÔ9€JÙ€w���z�lÔ#Ù�\¨¯©¸!¸Ô=€LÙ€w��˜˜Ô'÷ð ñ �Z  CÓ
(€CÙ
�Z  CÓ
(€CÙ
�Z  CÓ
(€CÙ
�Z  CÓ
(€CÙ˜ q¨'Ó2€GÙ˜ q¨'Ó2€Gñ ˆT˜Ÿ™Ô"€DÙ€uˆs�Eˆl˜T˜FÔ#ÙˆT˜Ÿ™Ô"€DÙ€uˆs�Eˆl˜T˜FÔ#Ù�˜rŸx™xÔ(€GÙ€uˆt�Tˆl˜W˜IÔ&ñ �) 2§8¡8Ô,€IÙ€uˆs�Gˆn˜y˜kÔ*ñ ˆE˜Ÿ™Ô
$€CÙ€v�ˆu�s�e˜d C˜[Ô)Ù
ˆE˜Ÿ™Ô
$€CÙ€v�ˆu�s�e˜d C˜[Ô)ÙˆV˜2Ÿ:™:Ô&€DÙ€v�ˆv˜�v  c˜{Ô+ÙˆV˜2Ÿ:™:Ô&€DÙ€v�ˆv˜�v  c˜{Ô+áˆx˜rŸz™zÔ*€FÙ€uˆs�Eˆl˜V˜HÔ%Ùˆx˜rŸz™zÔ*€FÙ€uˆs�Eˆl˜V˜HÔ%á� 2§:¡:Ô.€HÙ€uˆt�Uˆm˜h˜ZÔ(Ù� 2§:¡:Ô.€HÙ€uˆt�Uˆm˜h˜ZÔ(÷ð ñ ��fÓ€DÙ��fÓ€DÙ�W˜jÓ)€HÙ�W˜jÓ)€HÙ�y ,Ó/€Jñ �\¨¯©¸!¸Ô=€LÙ€x�*˜dÐ# l ^°f¸a°[ÔAñ �\¨¯©¸!¸Ô=€LÙ€x�$˜ (¨DÐ1°L°>ÀFÈAÀ;ÔOñ Ò% r§x¡x°Ó8€DÙˆx‹[€FÙ€uˆr�4ˆj˜6˜(Ô#Ù�	‹l€GÙ€{�V�H˜w˜i¨&²,Ð)?Ô@Ù�	‹l€GÙ€y�7˜LÐ)¨G¨9Ô5ñ ˆx‹[€FÙ€w�‘q˜!˜˜bŸh™h¨Ó0±!°Q°C¸¿¹À7Ó2KÈVÐTÐW]ÐV^Ô_Ù	
ˆ4‹€BÙ€y�6˜6Ð" R DÔ)áˆx‹[€FÙ€w�‘q˜!˜˜bŸh™h¨Ó0±!°Q°C¸¿¹À7Ó2KÈVÐTÐW]ÐV^Ô_Ù	
ˆ4‹€BÙ€y�6˜6Ð" R DÔ)ñ ˆV‹9€DÙ€uˆr�5ˆk˜D˜6Ô"Ù
ˆE‹(€CÙ€uˆt�Vˆn˜s˜eÔ$Ù	
ˆ4‹€BÙ€uˆs�Fˆm˜b˜TÔ"áˆV‹9€DÙ€uˆr�5ˆk˜D˜6Ô"Ù
ˆE‹(€CÙ€uˆt�Vˆn˜s˜eÔ$Ù	
ˆ4‹€BÙ€uˆs�Fˆm˜b˜TÔ"ñ ˆV‹9€DÙ€w���t�fÔÙˆV‹9€DÙ€w���t�fÔÙˆV‹9€DÙ€uˆt�Uˆm˜d˜VÔ$ÙˆV‹9€DÙ€uˆt�Uˆm˜d˜VÔ$á
ˆE‹(€CÙ€uˆr�4ˆj˜3˜%Ô Ù
ˆE‹(€CÙ€uˆr�4ˆj˜3˜%Ô Ù
ˆE‹(€CÙ€uˆu�cˆl˜S˜EÔ"Ù
ˆE‹(€CÙ€uˆu�cˆl˜S˜EÔ"÷ò ñ ˜d H¨eÓ
4€CÙ
˜d H¨eÓ
4€CÙ
˜d H¨eÓ
4€CÙ
˜d H¨eÓ
4€Cñ
 �M¨¯©Ô2€KÙ€w�˜˜eÐ$ { mÔ4ÙÐ-°R·X±XÔ>ÐÙ€uˆ{˜GÐ$Ð'8Ð&9Ô:Ùš: r§x¡xÐ1EÓFÐÙ�^¨2¯8©8Ô4€LÙ€yÐ$Ð&8Ð9¸L¸>ÔJ÷	ò 	ñ    S¨$Ó/€GÙ  S¨$Ó/€GÙ  S¨$Ó/€GÙ  S¨$Ó/€G÷ñ
 �g˜tÓ
$€CÙ
�g˜tÓ
$€CÙ
�g˜tÓ
$€CÙ
�g˜tÓ
$€Cñ �R˜�G˜RŸX™X }Ó5€K÷ñ �#�s˜C Ó
&€CÙ
�#�s˜C Ó
&€CÙ
�#�s˜C Ó
&€CÙ
�#�s˜C Ó
&€Cá	
ˆ4‹€BÙ€uˆs�Cˆj˜2˜$ÔÙ	
ˆ4‹€BÙ€uˆr�3ˆi˜"˜ÔÙˆg‹J€EÙ€uˆr�3ˆi˜%˜Ô!ñ �<“€JÙ€y�5˜,Ð'¨*¨Ô6Ù€{�Z�L 3 %¨&²,Ð)?Ô@ð 	‡K�K×ÑÔØ‡L�L×ÑÔØ	‡K�K×Ñ�uÕr.   c                ó‚  — 	 ddl }ddl}ddl}|j	                  t        | «      «      }|j                  j                  |«      }|j                  |«      }|j                  D �cg c]  }|j                  dk(  sŒ|‘Œ }}|st        j                  d«       | S t        j                  dt        |«      «       t        |«      D ]  \  }	}
t!        |
||	¬«       Œ |j#                  «       j%                  «        	 |j                  j                  |j'                  |«      «      }|j(                  j+                  |«       || j0                  d	z   z  }|j3                  |t        |«      «       t        j                  d
|«       |S # t        $ r}t        d«      |‚d}~ww xY wc c}w # t,        $ r}t/        d|› �«      |‚d}~ww xY w)uÂ  Rewrite every GridSample node in *onnx_path* to use TFLite-safe ops.

    ``onnx2tf``'s built-in GridSample handler lowers to ``tf.gather_nd(batch_dims=1)``, which TFLite's ``GatherNd``
    kernel does not support â€” the kernel silently accepts the model during ``AllocateTensors()`` but produces
    numerically wrong output at inference time.  The ``replace_to_pseudo_operators=["GridSample"]`` pseudo-op path also
    produces wrong logit magnitudes in both FP32 and FP16 (the pseudo-op itself is broken, independent of quantization).
    This function rewrites the ONNX graph *before* calling ``onnx2tf.convert()``, replacing each ``GridSample`` node
    with an equivalent bilinear subgraph that performs four ``Gather(axis=0)`` lookups on a transposed and flattened
    ``(N*(H+2)*(W+2), C)`` image tensor.  ``onnx2tf`` lowers ``Gather(axis=0)`` to TFLite's ``GATHER`` op with no
    ``batch_dims`` â€” the only TFLite gather path that is unconditionally supported.

    Only ``mode="bilinear"``, ``padding_mode="zeros"``, ``align_corners=0`` nodes are patched â€” the only variant emitted
    by RF-DETR's exporter.

    Args:
        onnx_path: Path to the source ``.onnx`` file.
        output_dir: Directory where the patched ``.onnx`` is written.  Must
            already exist.

    Returns:
        Path to the patched ``.onnx`` file if any ``GridSample`` nodes were found; *onnx_path* unchanged if the graph
        contains no such nodes.

    Raises:
        ImportError: If ``onnx`` or ``onnx_graphsurgeon`` are not available.
        NotImplementedError: If a ``GridSample`` node has unsupported attrs.
        RuntimeError: If the patched graph fails ONNX shape-inference or
            model validation.
    r   Nzwonnx and onnx_graphsurgeon are required for the GridSample TFLite patch.  Install with: pip install rfdetr[onnx,tflite]Ú
GridSamplez6No GridSample nodes found; skipping TFLite-safe patch.uG   Patching %d GridSample node(s) â†’ TFLite-safe Gather(axis=0) subgraph.)rò   z1GridSample ONNX patch produced an invalid graph: z_gs_patched.onnxz$GridSample-patched ONNX saved to: %s)rä   Úonnx.shape_inferencerå   ÚImportErrorÚloadrÞ   Úshape_inferenceÚinfer_shapesÚimport_onnxrB   r9   ÚloggerÚdebugÚinforè   Ú	enumerater  ÚcleanupÚtoposortÚexport_onnxÚcheckerÚcheck_modelÚ	ExceptionÚRuntimeErrorÚstemÚsave)Ú	onnx_pathÚ
output_dirrä   r)   ÚexcÚmodelrñ   ÚnÚgs_nodesrU   rð   ÚpatchedÚout_paths                r,   Ú_replace_gridsample_for_tfliter.  ‘  s�  € ð<ÛÛ#Û&ð �I‰I”c˜)“nÓ%€EØ× Ñ ×-Ñ-¨eÓ4€EØ�N‰N˜5Ó!€Eà Ÿ;™;Ö?�a¨!¯$©$°,Ó*>’Ð?€HÐ?ÙÜ�‰ÐMÔNØÐä
‡K�KØQÜˆH‹ôô ˜XÓ&ò 9‰ˆˆ4Ü" 4¨°aÖ8ð9ð 
‡M�MƒO×ÑÔð_Ø×&Ñ&×3Ñ3°B·N±NÀ5Ó4IÓJˆØ�‰× Ñ  Ô)ð ˜YŸ^™^Ð.@Ñ@ÑA€HØ‡I�Iˆg”s˜8“}Ô%Ü
‡L�LÐ7¸ÔBØ€OøôC ò ÜðDó
ð ð	ûðüò @øô" ò _ÜÐNÈsÈeÐTÓUÐ[^Ð^ûð_ús<   ‚E? Á"FÁ7FÃ5AF! Å?	FÆFÆFÆ!	F>Æ*F9Æ9F>c                 ó  — 	 ddl } ddlm} ddlm} ddl }ddlm} 	  |d«      }|€J ‚ ||«       |d	«      k  rt        d
|› d�«      ‚y# t        $ r}t        d«      |‚d}~ww xY w# |$ r t        |dd«      }|€Y yY ŒZw xY w)uI  Verify that a compatible ``onnx2tf`` package is importable.

    onnx2tf 2.4.0 or later is required â€” earlier 1.x releases cannot lower the constant ``Expand``, 1-D ``TopK``, and
    rank-3 ``Tile`` ops present in RF-DETR's ONNX graph.

    Raises:
        ImportError: If ``onnx2tf`` cannot be imported or is below 2.4.0.
    r   Nz�onnx2tf is not installed. TFLite export requires both ONNX and TFLite export dependencies. Install them with: pip install rfdetr[onnx,tflite])ÚPackageNotFoundError)Úversion)ÚVersionÚonnx2tfÚ__version__z2.4.0zonnx2tf z± is installed but RF-DETR requires >= 2.4.0. Earlier 1.x releases cannot lower the Expand, TopK, and Tile ops in RF-DETR's ONNX graph. Upgrade with: pip install 'onnx2tf>=2.4.0')r3  r  Úimportlib.metadatar0  r1  Úpackaging.versionr2  Úgetattr)r3  r(  Ú_PkgNotFoundÚ_pkg_versionÚ_onnx2tf_modÚ_VersionÚ	installeds          r,   Ú_check_onnx2tf_availabler=  ×  sÄ   € ðÛõ HÝ:ã"Ý5ðÙ ,¨YÓ 7ˆ	ð Ð Ð Ð Ù�	Ó™X gÓ.Ò.ÜØ�y�kð "Rð Ró
ð 	
ð /øô1 ò Üð.ó
ð ð		ûðûð ò ô ˜L¨-¸Ó>ˆ	ØÐÙñ ðús(   ‚A
 �A' Á
	A$ÁAÁA$Á'B Á?B c               #  ó�   ‡K  — t         j                  Šdˆfd„} | t         _        	 d–— ‰t         _        y# ‰t         _        w xY w­w)u­  Temporarily patch :func:`numpy.load` to set ``allow_pickle=True``.

    ``onnx2tf`` 1.x calls ``np.load()`` on its bundled calibration data without passing ``allow_pickle=True``.  NumPy â‰¥
    1.16.3 defaults that flag to ``False`` and raises :class:`ValueError` for pickled files.

    This context manager monkey-patches ``np.load`` for the duration of the ``onnx2tf`` conversion and restores the
    original afterwards.
    c                 ó8   •— |j                  dd«        ‰| i |¤ŽS )NÚallow_pickleT)Ú
setdefault)ÚargsÚkwargsÚ_original_loads     €r,   Ú_patched_loadz*_numpy_allow_pickle.<locals>._patched_load  s#   ø€ Ø×Ñ˜.¨$Ô/Ù˜tÐ. vÑ.Ð.r.   N)rB  r   rC  r   rß   r   )r6   r  )rE  rD  s    @r,   Ú_numpy_allow_picklerF    s6   øè ø€ ô —W‘W€Nõ/ð „B„Gð!Ûà Œ�ø�.Œ�üs   ƒ"A¦6 ªA¶AÁAc              #  óú  ‡ K  — dˆ fd„}i }ddg}|D ]M  }t         j                  j                  |«      }|sŒ%t        |d«      sŒ2t	        |d«      ||<   t        |d|«       ŒO 	 d–— |j                  «       D ]4  \  }}t         j                  j                  |«      }|sŒ(t        |d|«       Œ6 y# |j                  «       D ]4  \  }}t         j                  j                  |«      }|sŒ(t        |d|«       Œ6 w xY w­w)ur  Redirect ``download_test_image_data()`` to use local calibration data.

    ``onnx2tf`` calls ``download_test_image_data()`` during conversion to fetch test images from GitHub.  The function
    is called in two places:

    1. **Validation** â€” compares ONNX-vs-TF outputs (all conversions).
    2. **INT8 calibration** â€” builds a representative dataset when
       ``output_integer_quantized_tflite=True``.

    This download can fail in many environments (firewalls, CI, air-gapped systems, or when the upstream file is
    unavailable).  This context manager monkey-patches the function in all known module locations to return the data
    from the calibration ``.npy`` file we already prepared.

    We intentionally do **not** use ``custom_input_op_name_np_data_path`` because that code path triggers a ``tf.tile``
    rank mismatch in onnx2tf
    1.x when processing models with DINOv2-style embeddings and N > 1
    calibration samples.  Patching the download function achieves the same goal without that issue.

    Args:
        npy_path: Path to the ``.npy`` file containing calibration data in
            NHWC format.
    c                 ó\   •— t        t        t           t        j                  ‰ d¬«      «      S )NF)r@  )r   r   r   r6   r  )Únpy_paths   €r,   Ú_replacementz0_patch_validation_download.<locals>._replacement2  s!   ø€ ô
 ”GœC‘L¤"§'¡'¨(ÀÔ"GÓHÐHr.   zonnx2tf.utils.common_functionszonnx2tf.onnx2tfÚdownload_test_image_dataN)rß   zNDArray[Any])ÚsysÚmodulesræ   Úhasattrr7  ÚsetattrÚitems)rI  rJ  Ú	originalsrM  Úmod_nameÚmodÚoriginals   `      r,   Ú_patch_validation_downloadrU    sù   øè ø€ õ2Ið !#€Ià(Øð€Gð ò CˆÜ�k‰k�o‰o˜hÓ'ˆÚ”7˜3Ð :Õ;Ü")¨#Ð/IÓ"JˆI�hÑÜ�CÐ3°\ÕBð	CðCÛà"+§/¡/Ó"3ò 	CÑˆH�hÜ—+‘+—/‘/ (Ó+ˆCÚÜ˜Ð7¸ÕBñ	Cø )§/¡/Ó"3ò 	CÑˆH�hÜ—+‘+—/‘/ (Ó+ˆCÚÜ˜Ð7¸ÕBñ	Cüs4   ƒ3C;·C;ÁC;Á#B/ Á'7C;ÂC;Â/8C8Ã(C8Ã8C;c                óX  — ddl m} | j                  «       st        d| › �«      ‚t	        d„ | j                  «       D «       «      }|st        d| › dt	        t        «      › �«      ‚|d| }t        j                  dt        |«      › d	| › d
|› d|› d�	«       g }|D ]‚  }	 |j                  |«      j                  d«      j                  ||f«      }t        j                  |t        j                  ¬«      }	|	t        j                  d«      z  }	|j!                  |	«       Œ„ |st        d| › �«      ‚t        j                  dt        |«      › d�«       t        j&                  |«      j)                  t        j                  d¬«      S # t"        $ r t        j%                  d|› �«       Y �Œw xY w)a  Load images from a directory and prepare them for calibration.

    Images are loaded, resized to ``(height, width)``, converted to ``float32`` in ``[0, 1]``, and stacked into an NHWC
    array.

    Args:
        image_dir: Directory containing image files (JPEG, PNG, etc.).
        height: Target image height matching the model input.
        width: Target image width matching the model input.
        max_images: Maximum number of images to load.  Files are sorted
            alphabetically and the first *max_images* are used.

    Returns:
        A ``float32`` NumPy array of shape ``(N, height, width, 3)`` with pixel values in ``[0, 1]``.

    Raises:
        FileNotFoundError: If *image_dir* does not exist or contains no
            supported image files.
    r   )ÚImagez'Calibration image directory not found: c              3  ób   K  — | ]'  }|j                   j                  «       t        v sŒ$|–— Œ) y ­wrà   )ÚsuffixÚlowerr   )Ú.0Úps     r,   ú	<genexpr>z+_load_calibration_images.<locals>.<genexpr>k  s#   è ø€ Òa˜q¸1¿8¹8¿>¹>Ó;KÔO`Ò;`œÑaùs   ‚%/¨/z"No supported image files found in z. Supported extensions: NzLoading z calibration images from z (resizing to Úxú)ÚRGBr2   g     ào@zSkipping unreadable image: zNo readable images found in zLoaded z calibration imagesF)Úcopy)ÚPILrW  Úis_dirÚFileNotFoundErrorÚsortedÚiterdirr   r  r  rè   ÚopenÚconvertÚresizer6   Úasarrayrê   r=   r"  r  ÚstackÚastype)
Ú	image_dirÚheightÚwidthÚ
max_imagesrW  Úimage_pathsÚarraysÚimg_pathÚimgÚimage_arrays
             r,   Ú_load_calibration_imagesrv  M  sœ  € õ2 à×ÑÔÜÐ"IÈ)ÈÐ UÓVÐVäÑa I×$5Ñ$5Ó$7ÔaÓa€KáÜØ0°°Ð;SÔTZÔ[lÓTmÐSnÐoó
ð 	
ð ˜k˜zÐ*€KÜ
‡K�K�(œ3˜{Ó+Ð,Ð,EÀiÀ[ÐP^Ð_eÐ^fÐfgÐhmÐgnÐnoÐpÔqà(*€FØò ˆð	Ø—*‘*˜XÓ&×.Ñ.¨uÓ5×<Ñ<¸eÀV¸_ÓMˆCÜŸ*™* S´·
±
Ô;ˆKØœ2Ÿ:™: eÓ,Ñ,ˆKØ�M‰M˜+Õ&ðñ ÜÐ">¸y¸kÐ JÓKÐKä
‡K�K�'œ#˜f›+˜Ð&9Ð:Ô;Ü�8‰8�FÓ×"Ñ"¤2§:¡:°EÐ"Ó:Ð:øô ò 	Ü�L‰LÐ6°x°jÐAÔBÚð	ús   ÂA?FÆ!F)Æ(F)c                óX  — 	 ddl }|j                  t        | «      «      }|j                  j
                  d   }|j                  }|j                  j                  j                  j                  D �cg c]  }|j                  ‘Œ }}||fS # t        $ r}t        d«      |‚d}~ww xY wc c}w )zùRead the first input tensor's name and shape from an ONNX model.

    Args:
        onnx_path: Path to the ``.onnx`` file.

    Returns:
        A ``(name, dims)`` tuple where *dims* is the NCHW shape list, e.g. ``("input", [1, 3, 560, 560])``.
    r   NzŠonnx is not installed. TFLite export requires both ONNX and TFLite export dependencies. Install them with: pip install rfdetr[onnx,tflite])rä   r  r  rÞ   rñ   Úinputr(   ÚtypeÚtensor_typer&   ÚdimÚ	dim_value)r&  rä   r(  r)  Úinpr(   ÚdÚdimss           r,   Ú_get_onnx_input_infor€  ‡  s    € ðÛð �I‰I”c˜)“nÓ%€EØ
�+‰+×
Ñ
˜AÑ
€CØ�8‰8€DØ!$§¡×!5Ñ!5×!;Ñ!;×!?Ñ!?Ö@˜AˆA�K‹KÐ@€DÐ@Ø�ˆ:Ðøô ò Üð.ó
ð ð		ûðüò As   ‚B
 Á1B'Â
	B$ÂBÂB$c                óÌ  — |€½|dk(  rt         j                  d«       t        | «      \  }}|\  }}}}	t        j                  j                  t        ||	|«      j                  t        j                  «      }
|dz  }t        j                  t        |«      |
«       t         j                  d|
j                  › d|› �«       |S t        |t        j                  «      rH|dz  }t        j                  t        |«      |«       t         j                  d|j                  › �«       |S t!        |«      }|j#                  «       rot        | «      \  }}|\  }}}}	t%        |||	|¬«      }
|dz  }t        j                  t        |«      |
«       t         j                  d|
j                  › d|› �«       |S |j'                  «       r|}t         j                  d	|› �«       |S t)        d
|› �«      ‚)uz  Prepare calibration data as a ``.npy`` file for ``onnx2tf``.

    The returned path points to a ``.npy`` file containing an NHWC float32 array with pixel values in ``[0, 1]``.  This
    file is loaded by the ``_patch_validation_download()`` context manager, which replaces ``onnx2tf``'s built-in
    ``download_test_image_data()`` call.  ``onnx2tf`` uses this data for both ONNX-vs-TF output validation and (when
    INT8 is requested) as a representative calibration dataset.

    Args:
        onnx_path: Path to the source ``.onnx`` file (used to read the
            input tensor NCHW shape for random data generation and for determining the target resolution when loading
            images from a directory).
        calibration_data: One of:

            * ``None`` â€” generate random calibration data.  Sufficient for
              fp32/fp16 but emits a warning for int8.
            * A **directory path** containing JPEG/PNG images â€” images are
              loaded, resized to the model input resolution, and converted to the correct format automatically.
            * A path to a ``.npy`` file containing an array of shape
              ``(N, H, W, 3)``, dtype float32, values in ``[0, 1]``.
            * A :class:`numpy.ndarray` with the same constraints.
        output_dir: Directory where a temporary ``.npy`` file may be
            written when *calibration_data* is ``None``, a directory, or an ndarray.
        quantization: The requested quantization mode (used only to decide
            whether to emit a warning).
        max_images: Maximum number of images to load when
            *calibration_data* is a directory path.  Ignored for other calibration data formats.

    Returns:
        Path to the ``.npy`` calibration data file.

    Raises:
        FileNotFoundError: If *calibration_data* is a path that does not
            exist, or a directory with no supported images.
    r   uÍ   No calibration_data provided for INT8 quantization. Using random data â€” this will produce poor quantization accuracy. For best results, pass calibration_data with representative images from your dataset.z_rfdetr_calib_data.npyz)Generated random calibration data: shape=z, saved to z(Using provided calibration array: shape=)rn  ro  rp  z6Prepared calibration data from image directory: shape=zUsing calibration data from: z!Calibration data path not found: )r  Úwarningr€  r6   ÚrandomÚrandr   rl  rê   r%  rÞ   r  r&   Ú
isinstanceÚndarrayr  r   rc  rv  Úis_filerd  )r&  Úcalibration_datar'  Úquantizationrp  r#   Ú
input_dimsr7   ÚhÚwÚcalibrI  Ú	data_pathÚ_cs                 r,   Ú_prepare_calibration_datar�     sÐ  € ðR ÐØ˜6Ò!Ü�N‰Nð,ôô -¨YÓ7‰ˆˆ:à‰
ˆˆ1ˆa�ä—	‘	—‘Ô5°q¸!¸QÓ?×FÑFÄrÇzÁzÓRˆØÐ 8Ñ8ˆÜ
�‰”�H“˜uÔ%Ü�‰Ð@ÀÇÁÀÈ[ÐYaÐXbÐcÔdð* €Oô) 
Ð$¤b§j¡jÔ	1ØÐ 8Ñ8ˆÜ
�‰”�H“Ð/Ô0Ü�‰Ð>Ð?O×?UÑ?UÐ>VÐWÔXð" €Oô Ð)Ó*ˆ	Ø×ÑÔä0°Ó;‰MˆAˆzØ$‰KˆAˆr�1�aÜ,¨Y¸qÈÐV`ÔaˆEØ!Ð$<Ñ<ˆHÜ�G‰G”C˜“M 5Ô)Ü�K‰KÐPÐQV×Q\ÑQ\ÐP]Ð]hÐiqÐhrÐsÔtð €Oð ×ÑÔ Ø ˆHÜ�K‰KÐ7¸°zÐBÔCð €Oô $Ð&GÈ	À{Ð$SÓTÐTr.   c                ó  — ddl }|j                  j                  j                  t	        | «      «      }|j                  j
                  j                  g|_        | |› d�z  }|j                  |j                  «       «       |S )aÀ  Build a dynamic-range INT8 TFLite model from the onnx2tf SavedModel.

    Dynamic-range quantization stores weights as INT8 and keeps activations in float, so it needs no calibration data.

    Args:
        saved_model_dir: Directory holding the SavedModel ``onnx2tf`` wrote.
        model_stem: Stem of the source ONNX file, used to name the output.

    Returns:
        Path to the written ``{model_stem}_dynamic_range_quant.tflite`` file.
    r   Nz_dynamic_range_quant.tflite)
Ú
tensorflowÚliteÚTFLiteConverterÚfrom_saved_modelrÞ   ÚOptimizeÚDEFAULTÚoptimizationsÚwrite_bytesrh  )Úsaved_model_dirÚ
model_stemÚtfÚ	converterr-  s        r,   Ú_quantize_dynamic_rangerž  ð  so   € ó à—‘×'Ñ'×8Ñ8¼¸_Ó9MÓN€IØ!Ÿw™w×/Ñ/×7Ñ7Ð8€IÔØ J <Ð/JÐ!KÑK€HØ×Ñ˜×*Ñ*Ó,Ô-Ø€Or.   ÚerrorF)Úverbosec               óV  — t        | «      } t        |«      }| j                  «       st        d| › �«      ‚|t        vr&t	        d|›dt        d„ t        D «       «      › d�«      ‚t        «        ddlm} ddl	m
c m} ~~|j                  dd¬	«       	 t        | |«      } t#        | ||||¬«      }
t        j%                  d|›d|›d| › �«       	 t'        «       5  t)        t+        |
«      «      5  ddlm} t+        | «      t+        |«      d| |ddgdœ}	  |d"i |¤ddi¤Ž ddd«       ddd«       | j6                  }|dk(  r&t9        ||«      }t        j%                  d|› �«       |S ||› d�z  }|j                  «       sht        |j;                  |› d�«      «      }|r8|d   }t        j!                  d||› d�z  › d|› d|› d|j<                  › d�	«       nt5        d |› d!|› �«      ‚t        j%                  d|› �«       |S # t        $ r!}	t        j!                  d
|	«       Y d}	~	�Œ†d}	~	ww xY w# t.        $ r! t        j!                  d«        |d"i |¤Ž Y �Œ7w xY w# 1 sw Y   �Œ=xY w# 1 sw Y   �ŒBxY w# t0        $ r,}	t        j3                  d|	› �«       t5        d|	› �«      |	‚d}	~	ww xY w)#u.  Convert an ONNX model to TFLite via ``onnx2tf``.

    Requires ``onnx2tf >= 2.4.0``.  Uses the Python API with a NumPy compatibility shim.

    Args:
        onnx_path: Path to the source ``.onnx`` file.
        output_dir: Directory where TFLite artifacts will be written.
            ``onnx2tf`` creates ``{stem}_float32.tflite`` and ``{stem}_float16.tflite``.  When ``quantization="int8"`` a
            ``{stem}_dynamic_range_quant.tflite`` is additionally written.
        quantization: Quantization mode.

            * ``None`` / ``"fp32"`` / ``"fp16"`` â€” FP32 + FP16 output
              (``onnx2tf`` always emits both).
            * ``"int8"`` â€” additionally produce a dynamic-range INT8 model
              (INT8 weights, float activations, ~4x smaller than FP32). Static / full-integer INT8 is not supported.
        calibration_data: Representative data used by ``onnx2tf`` for its
            ONNX-vs-TF output validation.  Accepts:

            * ``None`` â€” auto-generate random data.
            * A **directory path** containing JPEG/PNG images â€” images
              are loaded, resized, and converted automatically.
            * A path to a ``.npy`` file â€” shape ``(N, H, W, 3)``,
              dtype float32, pixel values in ``[0, 1]``.
            * A :class:`numpy.ndarray` with the same format.

            Dynamic-range INT8 needs no calibration data, so this argument does not affect the quantized weights â€” it
            only feeds onnx2tf's internal validation pass.
        verbosity: Log verbosity passed to ``onnx2tf``.  One of
            ``"debug"``, ``"info"``, ``"warn"``, ``"error"`` (default).
        max_images: Maximum number of images to load when
            *calibration_data* is a directory path.  Defaults to 100. Ignored for other calibration data formats.
        verbose: When ``True``, stream ``onnx2tf`` per-node progress â€”
            useful for monitoring long conversions (5â€“15 min on transformer-based models).  Defaults to ``False``
            (silent).

    Returns:
        Path to the primary artifact.  ``onnx2tf`` always writes both ``{stem}_float32.tflite`` and
        ``{stem}_float16.tflite`` to *output_dir*; ``quantization="int8"`` adds ``{stem}_dynamic_range_quant.tflite``.
        The returned path is the dynamic-range file for ``int8``, otherwise the float32 file.

    Raises:
        FileNotFoundError: If *onnx_path* does not exist or
            *calibration_data* points to a missing file.
        ImportError: If ``onnx2tf`` is not installed.
        ValueError: If *quantization* is not a recognized mode.
        RuntimeError: If the conversion fails.

    Note:
        This function is **not thread-safe**.  It globally monkey-patches :func:`numpy.load` (via
        :func:`_numpy_allow_pickle`) and ``onnx2tf.download_test_image_data`` (via :func:`_patch_validation_download`)
        for the duration of the conversion.  Concurrent calls from multiple threads will interfere with each other.  Run
        conversion in a subprocess if isolation is required.

        ``tf_converter`` backend is forced unconditionally (overriding onnx2tf's 2.x ``flatbuffer_direct`` default) to
        avoid a runtime error in the TFLite TopK_V2 kernel.  ``Erf`` and ``GeLU`` ops are substituted with TFLite-native
        pseudo-operators to avoid a missing TensorFlow Flex delegate at inference time.

        Segmentation models additionally emit a ``masks`` output, decoded by
        :func:`rfdetr.export._tflite.inference._run_inference`.  Verified on the non-plus segmentation variants (Nano,
        Small, Medium, Large, Preview).
    zONNX model not found: zUnsupported quantization mode z. Choose from: c              3  ó&   K  — | ]	  }|€Œ|–— Œ y ­wrà   rÊ   )r[  Úqs     r,   r]  z export_tflite.<locals>.<genexpr>U  s   è ø€ Ò"T¨ÀaÁm¤1Ñ"Tùs   ‚ŠzG. Static / full-integer INT8 is not supported; 'int8' is dynamic-range.r   NT)ÚparentsÚexist_okuÒ   GridSample TFLite patch skipped â€” onnx/onnx_graphsurgeon not available (%s). TFLite inference may produce incorrect scores if the model contains GridSample nodes. Install with: pip install rfdetr[onnx,tflite])rp  u)   Converting ONNX â†’ TFLite (quantization=z, verbosity=z): )rh  ÚErfÚGeLU)Úinput_onnx_file_pathÚoutput_folder_pathÚoutput_signaturedefsÚnon_verboseÚ	verbosityÚreplace_to_pseudo_operatorsÚtflite_backendÚtf_converteru”   onnx2tf does not support tflite_backend= â€” proceeding with default backend. If TFLite inference produces wrong results, upgrade to onnx2tf>=2.4.0.zonnx2tf conversion failed: r   zTFLite model exported to: z_float32.tflitez	_*.tflitezExpected TFLite output z not found; searched for 'z_*.tflite' in z and using z\ instead. The returned model may have a different dtype (e.g. int8) than the caller expects.z0onnx2tf completed but no .tflite file matching 'z_*.tflite' was found in rÊ   )r   r‡  rd  r   ré   re  r=  Úonnx2tf.onnx2tfr3  Úonnx2tf.utils.common_functionsÚutilsÚcommon_functionsÚmkdirr.  r  r  r‚  r�  r  rF  rU  rÞ   rh  Ú	TypeErrorr"  rŸ  r#  r$  rž  Úglobr(   )r&  r'  r‰  rˆ  r¬  rp  r   r:  Ú_onnx2tf_commonr(  Úcalib_npy_pathrh  Úconvert_kwargsr›  ÚprimaryÚtflite_filess                   r,   Úexport_tfliter¼    s  € ôN �Y“€IÜ�jÓ!€Jà×ÑÔÜÐ"8¸¸Ð DÓEÐEàÔ/Ñ/ÜØ,¨\Ð,<ð =Ü"Ñ"TÔ.BÔ"TÓTÐUð VTðTó
ð 	
ô Ôõ +ß<Ð<à�oà×Ñ˜T¨DÐÔ1ð
Ü2°9¸jÓIˆ	ô /ØÐ# Z°È*ô€Nô ‡K�KÐ;¸LÐ;KÈ<ÐXaÐWdÐdgÐhqÐgrÐsÔtð;Iô$  Ó!ñ&	*ä&¤s¨>Ó':Ó;ñ&	*õ (ô ),¨I«Ü&)¨*£oØ(,Ø#*˜{Ø&ð 16°v¨ñ.ˆNð0*ÙÑH˜.ÑH¸ÓH÷?&	*÷ &	*ð^ —‘€Jà�vÒä)¨*°jÓAˆÜ�‰Ð0°°	Ð:Ô;Øˆà˜j˜\¨Ð9Ñ9€Gà�?‰?Ôô ˜jŸo™o°°¸IÐ.FÓGÓHˆÙØ" 1‘oˆGÜ�N‰NØ)¨*¸*¸À_Ð7UÑ*UÐ)Vð W!Ø!+ ¨N¸:¸,ÀkÐRY×R^ÑR^ÐQ_ð `eðeõô ØBÀ:À,ÐNfÐgqÐfrÐsóð ô ‡K�KÐ,¨W¨IÐ6Ô7Ø€NøôU ò 
Ü�‰ð<ð ÷		
ò 	
ûð
ûô~ ò *Ü—‘ð1ôñ
 Ñ)˜.Õ)ð*ú÷A&	*ñ &	*ú÷ &	*ñ &	*ûôP ò IÜ�‰Ð2°3°%Ð8Ô9ÜÐ8¸¸Ð>Ó?ÀSÐHûðIús~   ÂG? Ã
I3 ÃI&Ã,%IÄH,ÄI&Ä&I3 Ç?	H)ÈH$È$H)È,&IÉIÉIÉIÉI#	ÉI&É&I0É+I3 É3	J(É<'J#Ê#J()rð   r   rñ   r   rò   r   rß   râ   )r&  r   r'  r   rß   r   )rß   râ   )rß   úGenerator[None, None, None])rI  rÞ   rß   r½  )
rm  r   rn  r   ro  r   rp  r   rß   zNDArray[np.float32])r&  r   rß   ztuple[str, list[int]])r&  r   rˆ  ú*str | os.PathLike[str] | np.ndarray | Noner'  r   r‰  ú
str | Nonerp  r   rß   r   )rš  r   r›  rÞ   rß   r   )r&  ústr | os.PathLike[str]r'  rÀ  r‰  r¿  rˆ  r¾  r¬  rÞ   rp  r   r   Úboolrß   r   )$Ú__doc__Ú
__future__r   Ú
contextlibÚosrL  Úpathlibr   Útypingr   r   r   rã   r6   Únumpy.typingr   Úrfdetr.utilities.loggerr	   r  r   Ú__annotations__r   Ú	frozensetr   r   r  r.  r=  ÚcontextmanagerrF  rU  rv  r€  r�  rž  r¼  rÊ   r.   r,   ú<module>rÍ     s¹  ðò6õp #ã Û 	Û 
Ý ß 'Ñ 'ã Ý  å .á	‹€ò )GÐ �oÓ Fð !Ð ˜Ó  ñ %.Ò.XÓ$YÐ �>Ó Yð #&Ð ˜CÓ %ótón	CóL(
ðV ×Ñò!ó ð!ð, ×Ñò0Có ð0Cðn 1ð	7;Øð7;àð7;ð ð7;ð ð	7;ð
 ó7;ótð< 1ðMØðMà@ðMð ðMð ð	Mð
 ðMð 
óMó`ð0  $ØCGØØ0ðSð ñSØ%ðSà&ðSð ðSð Að	Sð
 ðSð ðSð ðSð 
ôSr.   