Ë
    ÛÓ^jÛ‡  ã                  óŠ  — U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
Z
 ddlmZ ddlmZ ddlmZ  ej"                  e«      Z e«       rddlZdd	lmZ dd
lmZmZmZmZmZmZ i Zded<   i Z ded<   i Z!ded<   ejD                  d:d„«       Z#ejD                  d;d„«       Z$ejD                  d<d„«       Z%d<d„Z&d<d„Z'd=d„Z(d>d„Z)d?d„Z*d=d„Z+e,fZ-ded<    e«       r1e-ej\                  ej^                  ej`                  ejb                  fz  Z-d@d„Z2dAdBd„Z3dCd„Z4dDd„Z5dEd„Z6dFd „Z7dGd!„Z8d"Z9	 	 	 	 	 	 dHd#„Z:dId$„Z;i Z<d%ed&<   dJd'„Z= e=d(«      dKd)„«       Z> e=d*«      dKd+„«       Z? e=d,d-«      dKd.„«       Z@ e=d,d/«      dKd0„«       ZAdKd1„ZBejD                  dLd2„«       ZC	 	 	 	 	 	 dMd3„ZDd4ZEd5ZFdNd6„ZGdOd7„ZHdMd8„ZI	 	 	 	 	 	 dMd9„ZJy)Pué  Shared export utilities used by all exporter backends.

Organised into five sections (search for the `# â”€â”€ Name â”€â”€` banners):

- **Patch and fix registries** â€” backend-keyed `_PATCHES` / `_FX_NODE_FIXES` /
  `_FX_PROGRAM_FIXES` populated via `@register_patch(backend, *paths)` /
  `@register_fx_node_fix` / `@register_fx_program_fix`, applied via
  `apply_patches` / `apply_fx_node_fixes` / `apply_fx_program_fixes`.
- **Recursive structure traversal** â€” internal helpers (`_map_leaf_tensors`,
  `_iter_leaf_tensors`) that drive every other tensor utility.
- **Public tensor utilities** â€” `get_leaf_tensors`, `duplicate_leaf_tensors`,
  `cast_leaf_tensors`, and `prepare_for_export` (sets attention/experts impl,
  patches non-exportable patterns, strips output flags).
- **Export input preparers** â€” `@register_export_input_preparer(marker)`
  registry that precomputes the per-encoder kwargs (`cu_seqlens`, `position_ids`,
  audio chunks, â€¦) the model would otherwise need data-dependent ops for.
- **Decomposition** â€” `decompose_prefill_decode` (split a generative forward
  into prefill + decode) and `decompose_multimodal` + `is_multimodal` (split a
  multimodal forward into one entry per submodule), backed by `_capture_forward`.
é    )ÚannotationsN)ÚMutableMapping)ÚAnyé   )Úlogging)Úis_torch_available)ÚPreTrainedModel)Ú'get_vision_bilinear_indices_and_weightsÚget_vision_cu_seqlensÚget_vision_merged_shapeÚget_vision_nearest_position_idsÚget_vision_position_idsÚget_vision_window_indexz*dict[str, list[tuple[Any, str, callable]]]Ú_PATCHESzdict[str, list[callable]]Ú_FX_NODE_FIXESÚ_FX_PROGRAM_FIXESc              #  ó’   K  — t        | |«      }t        | | ||«      «       	 d–— t        | ||«       y# t        | ||«       w xY w­w)zNSwap `obj.<attribute>` with `factory(original)` for the duration of the block.N)ÚgetattrÚsetattr)ÚobjÚ	attributeÚfactoryÚoriginals       úg/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/transformers/exporters/utils.pyÚpatch_attributer   Q   sE   è ø€ ô �s˜IÓ&€HÜˆC�™G HÓ-Ô.ð*Ûä��Y Õ)øŒ��Y Õ)üs   ‚ A£5 §AµAÁAc           	   #  ó´   K  — t        j                  «       5 }| D ]"  \  }}}|j                  t        |||«      «       Œ$ d–— ddd«       y# 1 sw Y   yxY w­w)uñ   Install `(obj, attribute, factory)` patches for the duration of the block.

    Plural form of `patch_attribute` â€” each `factory(original)` returns the replacement
    callable. Originals are restored on exit, even if the body raises.
    N)Ú
contextlibÚ	ExitStackÚenter_contextr   )ÚpatchesÚstackr   r   r   s        r   Úpatch_attributesr"   \   s\   è ø€ ô 
×	Ñ	Ó	ð  5Ø'.ò 	JÑ#ˆC�˜GØ×Ñ¤°°YÀÓ HÕIð	Jã÷÷ ñ üs   ‚A—,AÁ	AÁAÁAc              #  ó|   K  — t        t        j                  | g «      «      5  d–— ddd«       y# 1 sw Y   yxY w­w)z:Install `_PATCHES[backend]` for the duration of the block.N)r"   r   Úget)Úbackends    r   Úapply_patchesr&   i   s2   è ø€ ô 
œ(Ÿ,™, w°Ó3Ó	4ñ Û÷÷ ñ üs   ‚ <¢0§	<°9µ<c                ó   ‡ — ˆ fd„}|S )zKAppend the decorated `(gm, node) -> bool` fix to `_FX_NODE_FIXES[backend]`.c                óR   •— t         j                  ‰g «      j                  | «       | S ©N)r   Ú
setdefaultÚappend©Úfnr%   s    €r   Ú	decoratorz'register_fx_node_fix.<locals>.decorators   s#   ø€ Ü×!Ñ! '¨2Ó.×5Ñ5°bÔ9Øˆ	ó    © ©r%   r.   s   ` r   Úregister_fx_node_fixr2   p   s   ø€ ôð Ðr/   c                ó   ‡ — ˆ fd„}|S )u  Append the decorated `(exported_program) -> None` fix to `_FX_PROGRAM_FIXES[backend]`.

    Use this for fixes that need program-level context (range_constraints, graph_signature,
    state_dict) â€” the per-node `_FX_NODE_FIXES` shape only sees one node at a time.
    c                óR   •— t         j                  ‰g «      j                  | «       | S r)   )r   r*   r+   r,   s    €r   r.   z*register_fx_program_fix.<locals>.decorator�   s#   ø€ Ü×$Ñ$ W¨bÓ1×8Ñ8¸Ô<Øˆ	r/   r0   r1   s   ` r   Úregister_fx_program_fixr5   z   s   ø€ ôð Ðr/   c                óJ   — t         j                  | g «      D ]
  } ||«       Œ y)zDApply `_FX_PROGRAM_FIXES[backend]` to `exported_program` (in place).N)r   r$   )r%   Úexported_programÚfixs      r   Úapply_fx_program_fixesr9   ˆ   s'   € ä ×$Ñ$ W¨bÓ1ò ˆÙÐÕñr/   c                ó   ‡ ‡— ˆ ˆfd„}|S )um  Append the decorated `factory(original)` to `_PATCHES[backend]`, once per `path`.

    Each `path` is a dotted Python path like `"torch.where"`, `"torch.Tensor.unsqueeze"`,
    or `"transformers.models.nllb_moe.modeling_nllb_moe.NllbMoeTop2Router._cast_classifier"`.
    The rightmost segment is the attribute to swap; the rest is the object that owns it.
    Paths are resolved at decoration time â€” submodules are imported as needed, falling
    back to `getattr` for class attributes. A path that fails to resolve (e.g. the backend
    isn't installed) is silently skipped so the module still imports.

    Passing multiple paths registers the SAME factory against each â€” useful for swapping
    the same method or torch op across several call sites (e.g. ``torch.unsqueeze`` +
    ``torch.Tensor.unsqueeze``, or one vision-attention forward across N model classes).
    c                ó¬   •— ‰D ]M  }|j                  d«      \  }}}t        |«      }|€Œ&t        j                  ‰g «      j	                  ||| f«       ŒO | S )Nú.)Ú
rpartitionÚ_resolve_dotted_pathr   r*   r+   )r-   ÚpathÚobj_pathÚ_r   r   r%   Úpathss         €€r   r.   z!register_patch.<locals>.decorator�   sd   ø€ Øò 	JˆDØ%)§_¡_°SÓ%9Ñ"ˆH�a˜Ü& xÓ0ˆCØˆ{ØÜ×Ñ ¨Ó,×3Ñ3°S¸)ÀRÐ4HÕIð	Jð ˆ	r/   r0   )r%   rB   r.   s   `` r   Úregister_patchrC   Ž   s   ù€ õð Ðr/   c                ó  — ddl }| j                  d«      }	 |j                  |d   «      }|dd D ]#  }	 |j                  |j                  › d|› �«      }Œ% |S # t        t
        f$ r t        ||«      }Y ŒEw xY w# t        t
        f$ r Y yw xY w)uù   Resolve a dotted Python path to the actual object â€” importing submodules where
    possible, falling back to `getattr` for class attributes (e.g. `torch.Tensor`).
    Returns `None` if the path can't be resolved (e.g. the backend isn't installed).r   Nr<   é   )Ú	importlibÚsplitÚimport_moduleÚ__name__ÚImportErrorÚAttributeErrorr   )r?   rF   Úpartsr   Úparts        r   r>   r>   ©   s§   € ó à�J‰J�s‹O€Eð	Ø×%Ñ% e¨A¡hÓ/ˆØ˜!˜"�Iò 	)ˆDð)Ø×-Ñ-°·±°¸aÀ¸vÐ.FÓG‘ð	)ð
 ˆ
øô  ¤Ð0ò )Ü˜c 4Ó(’ð)ûô œÐ(ò Ùðús4   —A9 ´ AÁA9 ÁA6Á3A9 Á5A6Á6A9 Á9BÂ
Bc                ó°  — t         j                  | g «      }|j                  «       D ]˜  }t        |t        j
                  j                  «      sŒ(t        |j                  j                  «      D ]$  }|j                  dk7  rŒ|D ]  } |||«      sŒ Œ$ Œ& 	 |j                  j                  «        |j                  «        Œš y# t        t        f$ r Y Œ­w xY w)u²  Walk every call_function node and apply the first matching `_FX_NODE_FIXES[backend]`
    fix, then DCE.

    Each fix has signature `(gm, node) -> bool`. Returning `True` means the fix consumed
    the node â€” no further fixes run against it. Fixes are expected to be disjoint by
    `node.target`; if multiple could apply, list order decides.

    After the walk, `Graph.eliminate_dead_code` runs on every sub-GraphModule and
    `gm.recompile()` is called once. PyTorch DCE occasionally raises `SystemError` /
    `KeyError` from `erase_node._update_args_kwargs` on orphaned symbolic-size nodes â€”
    we swallow both; any survivors are handled by the downstream backend optimizer.
    Úcall_functionN)r   r$   ÚmodulesÚ
isinstanceÚtorchÚfxÚGraphModuleÚlistÚgraphÚnodesÚopÚeliminate_dead_codeÚ	recompileÚSystemErrorÚKeyError)r%   Úgraph_moduleÚfixesÚgmÚnoder8   s         r   Úapply_fx_node_fixesra   ¼   sÂ   € ô ×Ñ˜w¨Ó+€EØ×"Ñ"Ó$ò ˆÜ˜"œeŸh™h×2Ñ2Ô3ØÜ˜Ÿ™Ÿ™Ó(ò 	ˆDØ�w‰w˜/Ò)ØØò �Ù�r˜4•=Ùñð	ð	Ø�H‰H×(Ñ(Ô*Ø�L‰L�Nñøô œXÐ&ò 	Ùð	ús   Â*CÃCÃCztuple[type, ...]Ú_LEAF_SKIP_TYPESc           	     óÊ  ‡— t        | t        «      r| S t        | t        j                  «      r ‰| «      S t        | t        t
        t        f«      r t        | «      ˆfd„| D «       «      S t        | t        «      r$t	        | «      D ]  }t        | |   ‰«      | |<   Œ | S t        | d«      r8t        | «      j                  «       D ]  \  }}t        | |t        |‰«      «       Œ | S )u•  Apply `fn` to every tensor in a nested structure, preserving container types.

    Mutates dicts and `__dict__`-bearing objects in place (preserving identity â€” callers
    rely on this so downstream pops/mutations propagate back to the original mapping);
    rebuilds lists/tuples/sets/frozensets (immutable or order-sensitive containers).
    Skips non-traversable leaf types (enum, SymInt, etc.).
    c              3  ó6   •K  — | ]  }t        |‰«      –— Œ y ­wr)   ©Ú_map_leaf_tensors)Ú.0Úitemr-   s     €r   ú	<genexpr>z$_map_leaf_tensors.<locals>.<genexpr>ó   s   øè ø€ ÒE¸Ô*¨4°×4ÑEùs   ƒÚ__dict__)rQ   rb   rR   ÚTensorrU   ÚtupleÚsetÚtypeÚdictrf   ÚhasattrÚvarsÚitemsr   )r   r-   ÚkÚattrÚattr_vals    `   r   rf   rf   æ   sÍ   ø€ ô �#Ô'Ô(Øˆ
Ü�#”u—|‘|Ô$Ù�#‹wˆÜ�#œœe¤SÐ)Ô*ØŒt�C‹yÓEÀÔEÓEÐEÜ�#”tÔÜ�c“ò 	3ˆAÜ& s¨1¡v¨rÓ2ˆC�ŠFð	3àˆ
Üˆs�JÔÜ" 3›iŸo™oÓ/ò 	@‰NˆD�(Ü�C˜Ô0°¸2Ó>Õ?ð	@à€Jr/   c              #  ó  K  — t        | t        «      ryt        | t        j                  «      r|xs d| f–— yt        | t        t
        t        f«      r<t        | «      D ]-  \  }}|r|› d|› �n
t        |«      }t        ||«      E d{  –—†  Œ/ yt        | t        «      r8| j                  «       D ]$  \  }}|r|› d|› �n|}t        ||«      E d{  –—†  Œ& yt        | d«      rt        t        | «      |«      E d{  –—†  yy7 Œz7 Œ47 Œ
­w)zEYield `(dotted_path, tensor)` for every tensor in a nested structure.NÚoutputr<   rj   )rQ   rb   rR   rk   rU   rl   rm   Ú	enumerateÚstrÚ_iter_leaf_tensorsro   rr   rp   rq   )r   ÚprefixÚindexrh   r?   ÚkeyÚvalues          r   rz   rz   þ   sÿ   è ø€ ä�#Ô'Ô(ØÜ�#”u—|‘|Ô$ØÒ ˜ #Ð%Ó%Ü	�Cœ$¤¤sÐ+Ô	,Ü$ S›>ò 	6‰KˆE�4Ù*0�f�X˜Q˜u˜gÑ&´c¸%³jˆDÜ)¨$°Ó5×5Ñ5ñ	6ô 
�CœÔ	ØŸ)™)›+ò 	7‰JˆC�Ù(.�f�X˜Q˜s˜eÑ$°CˆDÜ)¨%°Ó6×6Ñ6ñ	7ô 
��jÔ	!Ü%¤d¨3£i°Ó8×8Ñ8ð 
"ð 6øð 7øà8ús7   ‚BD	ÂDÂ	AD	ÃDÃ+D	Ã<DÃ=D	ÄD	ÄD	c                ó*   — t        t        | «      «      S )a  Recursively retrieve all leaf tensors from a potentially nested structure.

    Args:
        obj (`Any`):
            A tensor, dataclass, dict, list, tuple, or any nesting thereof.

    Returns:
        `dict[str, torch.Tensor]`: Flat mapping from dotted path strings to tensors.
    )ro   rz   )r   s    r   Úget_leaf_tensorsr€     s   € ô Ô" 3Ó'Ó(Ð(r/   c                ó<   ‡— t        «       Šdˆfd„}t        | |«      S )a”  Clone tensors that appear more than once in an output structure.

    When a model returns the same tensor under two output names (e.g. `last_hidden_state`
    and `hidden_states[0]`), the ONNX optimizer deduplicates the two output nodes and
    renames one, breaking the expected name mapping. Cloning duplicates gives each output
    leaf a distinct identity so the optimizer has nothing to merge.
    c                óv   •— t        | «      ‰v r| j                  «       S ‰j                  t        | «      «       | S r)   )ÚidÚcloneÚadd)ÚtensorÚseens    €r   Ú_dedupz&duplicate_leaf_tensors.<locals>._dedup+  s0   ø€ Üˆf‹:˜ÑØ—<‘<“>Ð!Ø�‰”�F“ÔØˆr/   ©r†   útorch.TensorÚreturnrŠ   )rm   rf   )r   rˆ   r‡   s     @r   Úduplicate_leaf_tensorsrŒ   !  s    ø€ ô ‹5€Dõô ˜S &Ó)Ð)r/   c                ó,   ‡‡— dˆˆfd„}t        | |«      S )zJRecursively cast all floating-point tensors to the given dtype and device.c                ón   •— | j                  «       r| j                  ‰‰¬«      S | j                  ‰¬«      S )N©ÚdtypeÚdevice)r‘   )Úis_floating_pointÚto)r†   r‘   r�   s    €€r   Ú_castz cast_leaf_tensors.<locals>._cast7  s6   ø€ Ø8>×8PÑ8PÔ8Rˆv�y‰y˜u¨VˆyÓ4ÐpÐX^×XaÑXaÐioÐXaÓXpÐpr/   r‰   re   )r   r�   r‘   r”   s    `` r   Úcast_leaf_tensorsr•   4  s   ù€ öqô ˜S %Ó(Ð(r/   c                ó˜   — t        | d«      r| j                  S 	 t        | j                  «       «      j                  S # t        $ r Y yw xY w)a#  `.device` for any `nn.Module`. `PreTrainedModel` exposes it directly via `ModuleUtilsMixin`;
    for plain submodules (e.g. a `Linear` or `MultiModalProjector` from a decomposed multimodal model)
    we fall back to the first parameter. Returns `None` if the module has no parameters at all.r‘   N)rp   r‘   ÚnextÚ
parametersÚStopIteration©Úmodels    r   Úmodule_devicerœ   =  sI   € ô ˆu�hÔØ�|‰|ÐðÜ�E×$Ñ$Ó&Ó'×.Ñ.Ð.øÜò Ùðúó   š"= ½	A	ÁA	c                ó˜   — t        | d«      r| j                  S 	 t        | j                  «       «      j                  S # t        $ r Y yw xY w)zE`.dtype` for any `nn.Module`. Same fallback story as `module_device`.r�   N)rp   r�   r—   r˜   r™   rš   s    r   Úmodule_dtyperŸ   I  sG   € äˆu�gÔØ�{‰{ÐðÜ�E×$Ñ$Ó&Ó'×-Ñ-Ð-øÜò Ùðúr�   )Ú	use_cacheÚoutput_attentionsÚoutput_hidden_statesÚreturn_dictÚreturn_lossc                ó  — dD ](  }|j                  |d«      }|€Œt        d|› d|› d�«      ‚ t        | d«      r"t        | j                  dd«      rt        d	«      ‚|j                  dd«      rt        d
«      ‚t        D �ci c]  }||v sŒ||j                  |«      “Œ }}t        j                  «       5  t        | |«       ddd«       t        | «      }t        | «      }|€|�t        |||¬«      }| ||fS c c}w # 1 sw Y   Œ;xY w)u6  Configure model and inputs for export. Mutates both `model` and `inputs` in place,
    returning `(model, inputs, output_flags)` where `output_flags` holds the values popped
    from `inputs` for `use_cache`, `return_dict`, etc. (to be applied reversibly onto
    `model.config` by `patch_model_config` during the trace).

    - Strips label inputs (`labels`, `future_values`) â€” loss computation is unsupported.
    - Pops output flags (`use_cache`, `return_dict`, â€¦) from `inputs` so they don't appear
      as traced kwargs; the values are returned for the trace block to apply onto
      `model.config`.
    - Pre-computes data-dependent vision/audio kwargs registered via
      `@register_export_input_preparer` and writes them into `inputs`.
    - Casts input tensors to match the model's `dtype` / `device`.
    )ÚlabelsÚfuture_valuesNzFound 'zM' in inputs. Loss computation is not supported during export. Please remove 'z+' from your inputs before calling export().Úconfigr¤   FzœFound 'model.config.return_loss=True'. Loss computation is not supported during export. Please set 'model.config.return_loss=False' before calling export().z•Found 'return_loss=True' in inputs. Loss computation is not supported during export. Please remove 'return_loss' from your inputs or set it to False.r�   )ÚpopÚ
ValueErrorrp   r   r¨   r$   Ú_OUTPUT_FLAGSrR   Úno_gradÚprecompute_export_inputsrŸ   rœ   r•   )r›   ÚinputsÚ	label_keyr~   ÚflagÚoutput_flagsr�   r‘   s           r   Úprepare_for_exportr²   W  s8  € ð" 1ò ˆ	Ø—
‘
˜9 dÓ+ˆØÑÜØ˜)˜ð %"Ø"+ Ð,WðYóð ðô ˆu�hÔ¤G¨E¯L©L¸-ÈÔ$OÜðSó
ð 	
ð ‡z�z�- Ô'ÜðOó
ð 	
ô 8EÖW¨tÈÐPVÊ�D˜&Ÿ*™* TÓ*Ñ*ÐW€LÐWô
 
�‰‹ñ 0Ü  ¨Ô/÷0ô
 ˜Ó€EÜ˜5Ó!€FØÐ˜FÐ.Ü" 6°¸vÔFˆà�&˜,Ð&Ð&ùò X÷
0ð 0ús   Â	C7ÂC7Â5C<Ã<Dc                óT   — | j                  «       D ]  }t        ||d«      x}€Œ|c S  y)zTReturn the first non-None value of `name` found on `model` or any of its submodules.N)rP   r   )r›   ÚnameÚmoduler~   s       r   Ú_find_submodule_attrr¶   •  s5   € à—-‘-“/ò ˆÜ˜V T¨4Ó0Ð0ˆEÑ=ØŠLðð r/   zdict[tuple[str, ...], callable]Ú_EXPORT_INPUT_PREPARERSc                 ó   ‡ — ˆ fd„}|S )u4  Register `fn(model, inputs) -> None`. Dispatched when every `marker` is a key in
    `inputs` with a non-`None` value â€” no model_type list to maintain. Use multiple
    markers to narrow the match when a single kwarg is too ambiguous (e.g.
    `("input_features", "feature_lens")` for omni audio encoders).c                ó   •— | t         ‰<   | S r)   )r·   )r-   Úmarkerss    €r   r.   z1register_export_input_preparer.<locals>.decorator¦  s   ø€ Ø+-Ô Ñ(Øˆ	r/   r0   )rº   r.   s   ` r   Úregister_export_input_preparerr»      s   ø€ ôð Ðr/   Úgrid_thwc                óX  — |d   }t        | d«      }|€|j                  dd«      }t        |«      |d<   t        | d«      du}t        |||¬«      |d	<   t        | d
«      }t        | d«      }|�|�t	        ||||«      \  |d<   |d<   t        | d«      }|�t        |||«      \  |d<   |d<   yy)aã  Precompute helpers driven by `grid_thw`: `cu_seqlens`, `position_ids`, plus optional
    `window_index`/`cu_window_seqlens` (XNet-style window attn) and
    `bilinear_indices`/`bilinear_weights` (interpolation-based merging).

    Optional helpers are gated by the presence of their config attribute on the encoder
    (`window_size`+`patch_size` for window attention, `num_grid_per_side` for bilinear),
    so a model that doesn't use that feature won't get its kwarg injected.
    r¼   Úspatial_merge_sizeNÚmerge_sizesrE   Ú
cu_seqlensÚaxis_dim)Úinclude_temporalÚposition_idsÚwindow_sizeÚ
patch_sizeÚwindow_indexÚcu_window_seqlensÚnum_grid_per_sideÚbilinear_indicesÚbilinear_weights)r¶   r$   r   r   r   r
   )r›   r®   r¼   r¾   rÂ   rÄ   rÅ   rÈ   s           r   Ú_prepare_grid_thw_vision_inputsrË   ­  sô   € ð �jÑ!€HÜ-¨eÐ5IÓJÐØÐ!ð $ŸZ™Z¨°qÓ9Ðä0°Ó:€Fˆ<Ñô ,¨E°:Ó>ÀdÐJÐÜ4°XÐ?QÐdtÔu€Fˆ>Ñä& u¨mÓ<€KÜ% e¨\Ó:€JØÐ :Ð#9Ü>UØÐ(¨+°zó?
Ñ;ˆˆ~Ñ Ð':Ñ ;ô -¨UÐ4GÓHÐØÐ$ÜAhØÐ'Ð);óB
Ñ>ˆÐ!Ñ" FÐ+=Ò$>ð %r/   Útarget_sizesc                ó  — |d   }t        | d«      }|�t        ||«      |d<   t        | d«      }|�Wt        j                  j                  j                  |dd¬«      }t        |d|d	   d¬
«      \  |d<   |d<   t        ||«      |d<   yy)a
  NaViT-style packed encoders carry per-image `(h, w)` as `target_sizes` instead of `grid_thw`.
    Synthesise `grid_thw = [1, h, w]` and run the nearest-position-id / window-index /
    merged-shape helpers so the per-image Python loops move outside the traced graph.rÌ   Únum_patches_per_sideNrÃ   Úwindow_kernel_size)rE   r   rE   )r~   r   )r¾   rÄ   rÅ   rÆ   rÇ   Úmerged_shape)r¶   r   rR   ÚnnÚ
functionalÚpadr   r   )r›   r®   rÌ   rÎ   rÏ   r¼   s         r   Ú_prepare_navit_vision_inputsrÔ   Ò  s¬   € ð
 ˜.Ñ)€LÜ/°Ð7MÓNÐØÐ'Ü!@ÀÐOcÓ!dˆˆ~Ñä-¨eÐ5IÓJÐØÐ%Ü—8‘8×&Ñ&×*Ñ*¨<¸ÀqÐ*ÓIˆÜ>UØ¨Ð8JÈ1Ñ8MÐZ[ô?
Ñ;ˆˆ~Ñ Ð':Ñ ;ô "9¸ÐGYÓ!Zˆˆ~Òð &r/   Úinput_featuresÚfeature_lensc                óÎ  — |d   }|d   }t         j                  t        | «      j                     }t	        |d«      }t	        |d«      }t	        |d«      } |||| j
                  «      \  }}	||d<   |	|d<   t        | d«      r9 ||	|| j                  | j
                  «      |d	<    ||	| j
                  «      |d
<   y ||	«      |d	<    ||	«      |d
<    t	        |d«      |«      |d<   y)uŽ  Replace `input_features`/`feature_lens` with precomputed `padded_feature`, `chunk_lengths`,
    `cu_seqlens`, `valid_indices` (+ `pool_indices` on Qwen2.5-Omni-style encoders) so the
    encoder's `.split(.tolist(), dim=0)` and related data-dependent ops happen outside the
    traced graph.

    The helpers (`chunk_and_pad_features`, `get_audio_cu_seqlens`, â€¦) all live in the model's
    own ``modeling_*.py`` module, so we resolve them via ``type(model).__module__`` rather than
    hard-coding one Omni variant. ``n_window_infer`` selects the Qwen3-Omni-style four-arg
    ``get_audio_cu_seqlens`` over the Qwen2.5-Omni-style single-arg form.
    rÖ   rÕ   Úchunk_and_pad_featuresÚget_audio_cu_seqlensÚget_valid_indicesÚpadded_featureÚchunk_lengthsÚn_window_inferrÀ   Úvalid_indicesÚget_pool_indicesÚpool_indicesN)ÚsysrP   rn   Ú
__module__r   Ún_windowrp   rÝ   )
r›   r®   rÖ   rÕ   rµ   rØ   rÙ   rÚ   rÛ   rÜ   s
             r   Ú_prepare_omni_audio_inputsrä   å  s  € ð ˜.Ñ)€LØÐ,Ñ-€NÜ�[‰[œ˜e›×/Ñ/Ñ0€Fä$ VÐ-EÓFÐÜ" 6Ð+AÓBÐÜ Ð(;Ó<Ðá$:¸>È<ÐY^×YgÑYgÓ$hÑ!€N�MØ-€FÐÑØ+€Fˆ?ÑÜˆuÐ&Ô'Ù3°MÀ<ÐQV×QeÑQeÐgl×guÑguÓvˆˆ|ÑÙ"3°MÀ5Ç>Á>Ó"RˆˆÒá3°MÓBˆˆ|ÑÙ"3°MÓ"BˆˆÑØ!D¤¨Ð1CÓ!DÀ\Ó!Rˆˆ~Òr/   Úinput_features_maskc                ó˜  — ddl m} t        | d«      }t        | d«      }|�|€y|d   }|j                  \  }}||dz  z  }|j	                  d«      j                  t        j                  «      }	|j                  ||d«      j	                  d¬«      j                  d«      j                  t        j                  «      }
 ||
|	||«      |d	<   y)
u4  Precompute `cu_seqlens` for Qwen3-ASR â€” the encoder's call to ``get_audio_cu_seqlens``
    has a data-dependent Python loop that we evaluate here so the encoder pops the result
    from ``kwargs``. Mirrors the few lines that build ``feature_lens``/``chunk_lengths`` in
    ``Qwen3ASREncoder.forward``.
    r   )rÙ   rã   rÝ   Nrå   éÿÿÿÿ)ÚdimrÀ   )
Ú#models.qwen3_asr.modeling_qwen3_asrrÙ   r¶   ÚshapeÚsumr“   rR   ÚlongÚviewÚreshape)r›   r®   rÙ   rã   rÝ   rå   Ú
batch_sizeÚpadded_feature_lengthÚ
num_chunksrÖ   rÜ   s              r   Ú_prepare_qwen3_asr_audio_inputsrò     sÐ   € õ Kä# E¨:Ó6€HÜ)¨%Ð1AÓB€NØÐ˜>Ð1Øà Ð!6Ñ7ÐØ(;×(AÑ(AÑ%€JÐ%Ø&¨8°a©<Ñ8€JØ&×*Ñ*¨2Ó.×1Ñ1´%·*±*Ó=€LØ'×,Ñ,¨Z¸ÀRÓH×LÑLÐQSÐLÓT×\Ñ\Ð]_Ó`×cÑcÔdi×dnÑdnÓo€MÙ/°¸|È^Ð]eÓf€Fˆ<Òr/   c                ó$  ‡— ‰j                  d«      €¿t        | d«      r³‰j                  d«      }‰j                  d«      }|du xs% |du xs |j                  d   |j                  d   k(  }|rdt        t	        j
                  | j                  «      j                  «      }|D �ci c]  }|‰v sŒ|‰|   “Œ }} | j                  di |¤Ž\  }}	|‰d<   t        j                  «       D ]#  \  }
}t        ˆfd„|
D «       «      sŒ || ‰«       Œ% yc c}w )	uî  Inject precomputed tensors for data-dependent ops the model would otherwise hit during tracing.

    Two layers:
    - Outer LLM rope index (`get_rope_index`) â€” generic `hasattr` probe; covers Qwen-VL / GLM-4V etc.
    - Per-encoder preparer dispatched by marker kwargs present in `inputs` (e.g. `grid_thw`,
      `target_sizes`, `(input_features, feature_lens)`) â€” see `register_export_input_preparer`.
      A preparer fires only when every one of its markers is present in `inputs`.
    rÃ   NÚget_rope_indexÚ	input_idsÚattention_maskrE   c              3  óD   •K  — | ]  }‰j                  |«      d u–— Œ y ­wr)   )r$   )rg   Úmr®   s     €r   ri   z+precompute_export_inputs.<locals>.<genexpr>3  s   øè ø€ Ò:¨Qˆv�z‰z˜!‹} DÔ(Ñ:ùs   ƒ r0   )r$   rp   rê   rm   ÚinspectÚ	signaturerô   r˜   r·   rr   Úall)r›   r®   rõ   Ú	attn_maskÚ
is_prefillÚrope_paramsrs   Úrope_inputsrÃ   rA   rº   Úpreparers    `          r   r­   r­     s  ø€ ð ‡z�z�.Ó!Ð)¬g°eÐ=MÔ.NØ—J‘J˜{Ó+ˆ	Ø—J‘JÐ/Ó0ˆ	Ø $Ð&Òg¨)°tÐ*;Òg¸y¿¹ÈqÑ?QÐU^×UdÑUdÐefÑUgÑ?gˆ
ÙÜœg×/Ñ/°×0DÑ0DÓE×PÑPÓQˆKØ1<ÖL¨AÀÀVÂ˜1˜f Q™i™<ÐLˆKÐLØ2˜e×2Ñ2ÑA°[ÑA‰OˆL˜!Ø%1ˆF�>Ñ"ô 5×:Ñ:Ó<ò $Ñˆ�ÜÓ:°'Ô:Õ:Ù�U˜FÕ#ñ$ùò Ms   Â$	DÂ.Dc              #  óÔ   ‡‡‡K  — g Š| j                   Št        j                  ‰«      Št        j                  ‰«      ˆˆˆfd„«       }|| _         	 ‰–— ‰| _         y# ‰| _         w xY w­w)zÞCapture forward call kwargs into a list (one dict per call).

    Positional args are normalised to kwargs via `inspect.signature` so the
    captured dicts can be passed directly as `kwargs=inputs` to `torch.export`.
    c                 óØ  •— i } ‰	j                   | i |¤Ž}|j                  j                  «       D ]   \  }}‰	j                  |   }|j                  t
        j                  j                  k(  r%|j                  t        j                  |«      «       Œa|j                  t
        j                  j                  k7  sŒ‰t        j                  |«      ||<   Œ¢ ‰j                  |«        ‰| i |¤ŽS r)   )ÚbindÚ	argumentsrr   r˜   Úkindrù   Ú	ParameterÚVAR_KEYWORDÚupdateÚcopyÚdeepcopyÚVAR_POSITIONALr+   )
ÚargsÚkwargsÚcapturedÚboundr´   r~   ÚparamÚcallsr   Úsigs
          €€€r   Úwrapperz!_capture_forward.<locals>.wrapperK  sÀ   ø€ àˆØ�—‘˜$Ð) &Ñ)ˆØ Ÿ?™?×0Ñ0Ó2ò 	6‰KˆD�%Ø—N‘N 4Ñ(ˆEØ�z‰zœW×.Ñ.×:Ñ:Ò:Ø—‘¤§¡¨eÓ 4Õ5Ø—‘œw×0Ñ0×?Ñ?Ó?Ü!%§¡¨uÓ!5�˜’ð	6ð 	�‰�XÔÙ˜Ð( Ñ(Ð(r/   N)Úforwardrù   rú   Ú	functoolsÚwraps)rµ   r  r  r   r  s     @@@r   Ú_capture_forwardr  ?  sc   úè ø€ ð €EØ�~‰~€HÜ
×
Ñ
˜HÓ
%€Cä‡_�_�XÓõ
)ó ð
)ð €F„Nð"ØŠà!ˆ�ø˜ˆ�üs   …A
A(ÁA ÁA(Á	A%Á%A(c           
     ó  — 	 t        | «      5 } | j                  di t        j                  |«      ¤dddœ¤Ž ddd«       t        «      dk  r.t        dt        | «      j                  › dt        |«      › d	�«      ‚t        j                  | «      |d
   ft        j                  | «      |d   fdœS # 1 sw Y   ŒzxY w# t        $ rB}t        dt        | «      j                  › dt        |j                  «       «      › d�«      |‚d}~ww xY w)u‘  Run `model.generate()` for 2 tokens and capture prefill and decode inputs.

    Reuses the full generation machinery so every architecture (decoder-only, SSM,
    encoder-decoder, multi-modal, â€¦) gets correct inputs without reimplementing the loop.

    Returns:
        `dict[str, tuple[torch.nn.Module, dict]]`:
        `{"prefill": (model, prefill_inputs), "decode": (model, decode_inputs)}`
    r   )Úmax_new_tokensÚmin_new_tokensNz$decompose_prefill_decode failed for ú. Inputs passed: z<. Make sure the inputs are compatible with model.generate().z6decompose_prefill_decode expected at least 2 calls to z;.forward() during generate(max_new_tokens=2), but captured z«. This likely means generate() bypasses the top-level forward() (e.g. delegates to an inner model), so prefill/decode decomposition is not supported for this architecture.r   rE   )ÚprefillÚdecoder0   )r  Úgenerater	  r
  Ú	ExceptionÚRuntimeErrorrn   rI   rU   ÚkeysÚlen)r›   r®   r  Úes       r   Údecompose_prefill_decoder$  _  s   € ðÜ˜eÓ$ð 	X¨ØˆE�N‰NÑWœTŸ]™]¨6Ó2ÐWÀ1ÐUVÔW÷	Xô ˆ5ƒz�A‚~ÜØDÄTÈ%Ã[×EYÑEYÐDZð [?Ü?BÀ5»z¸lð KVðVó
ð 	
ô —I‘I˜eÓ$ e¨A¡hÐ/Ü—9‘9˜UÓ# U¨1¡XÐ.ñð ÷#	Xð 	Xûäò ÜØ2´4¸³;×3GÑ3GÐ2Hð IÜ" 6§;¡;£=Ó1Ð2ð 3IðJó
ð ð		ûðús-   ‚B= �+B1¸B= Â1B:Â6B= Â=	DÃ=DÄD)Úmulti_modal_projectorÚ	connectorÚembed_visionÚembed_audio)Úlm_headc                ó8  — i }d}dD ]&  }| j                  |¬«      }|€Œ|| usŒ|||› d�<   d}Œ( | j                  «       }|�	|| ur||d<   | | j                  hD ]6  }t        t        z   D ]$  }||vsŒt        ||d«      €Œt        ||«      ||<   Œ& Œ8 |rd|vri S |S )u  Return `{attr_name: module}` for multi-modal submodules found on `model`.

    Uses the canonical `PreTrainedModel.get_encoder("image"/"audio")` and `get_decoder()`
    accessors for encoders and the language model. Projectors and `lm_head` are looked
    up by name on `model` and its `base_model` (e.g. `LlavaModel` under `LlavaForConditionalGeneration`).

    Only returns results when at least one modal encoder AND a language model are found â€”
    otherwise the model is not multi-modal and should be exported as a single unit.
    F)ÚimageÚaudio)ÚmodalityNÚ_encoderTÚlanguage_model)Úget_encoderÚget_decoderÚ
base_modelÚ_MULTIMODAL_PROJECTOR_NAMESÚ_MULTIMODAL_LM_HEAD_NAMESr   )r›   ÚfoundÚhas_encoderr-  ÚencoderÚdecoderÚrootr´   s           r   Ú_find_multimodal_submodulesr:  Š  sé   € ð )+€Eà€KØ&ò ˆØ×#Ñ#¨XÐ#Ó6ˆð Ñ 7°%Ò#7Ø+2ˆE�X�J˜hÐ'Ñ(Ø‰Kðð ×ÑÓ!€GØÐ˜w¨eÑ3Ø")ˆÐÑà˜×(Ñ(Ð)ò 2ˆÜ/Ô2KÑKò 	2ˆDØ˜5Ò ¤W¨T°4¸Ó%>Ñ%JÜ% d¨DÓ1��d’ñ	2ð2ñ
 Ð*°%Ñ7Øˆ	à€Lr/   c                ó*   — t        t        | «      «      S )zTReturns `True` if the model is multi-modal with modal encoders and a language model.)Úboolr:  rš   s    r   Úis_multimodalr=  ¯  s   € äÔ+¨EÓ2Ó3Ð3r/   c                óÈ  — t        | «      }|s"t        dt        | «      j                  › d�«      ‚	 t	        j
                  «       5 }t        j                  «       5  |j                  «       D ��ci c]   \  }}||j                  t        |«      «      “Œ" }}} | di t        j                  |«      ¤Ž ddd«       ddd«       |j                  «       D ��ci c]  \  }}|   r||||   d   f“Œ c}}S c c}}w # 1 sw Y   ŒHxY w# 1 sw Y   ŒLxY w# t        $ rB}t        dt        | «      j                  › dt        |j!                  «       «      › d�«      |‚d}~ww xY wc c}}w )	u‹  Capture inputs to each multi-modal submodule via a single forward pass.

    Detects all known multi-modal submodules by attribute name (vision tower, projector,
    language model, lm_head, â€¦) and captures their forward kwargs during one
    `model(**inputs)` call.

    Each submodule is returned as a separate `name: (module, inputs)` entry for
    independent export. The token-merge step (e.g. `masked_scatter` for multi-modal models)
    is intentionally left outside the exported graphs â€” it is the caller's responsibility
    to assemble `inputs_embeds` from the encoder outputs before running the decoder.

    Returns:
        `dict[str, tuple[torch.nn.Module, dict]]`: One `name: (module, inputs)`
        entry per detected submodule (image/audio encoder, projector, language model, lm_head).

    Raises:
        `ValueError`: if no known multi-modal submodules are found on the model.
    z8decompose_multimodal found no multi-modal submodules on zB. Expected an image/audio encoder + language model, found neither.Nz decompose_multimodal failed for r  r<   rç   r0   )r:  rª   rn   rI   r   r   rR   r¬   rr   r   r  r	  r
  r  r   rU   r!  )r›   r®   Ú
submodulesr!   r´   rµ   Úsubmodule_inputsr#  s           r   Údecompose_multimodalrA  ´  sw  € ô& -¨UÓ3€JÙÜØFÄtÈEÃ{×G[ÑG[ÐF\ð ]Oð Pó
ð 	
ð
	Ü×!Ñ!Ó#ð 	+ u¬e¯m©m«oñ 	+àXb×XhÑXhÓXj÷ ÙHTÈÈf��e×)Ñ)Ô*:¸6Ó*BÓCÑCð Ðñ  ñ Ñ*”D—M‘M &Ó)Ò*÷		+÷ 	+ð '×,Ñ,Ó.÷áˆD�&Ø˜DÒ!ð 	ˆvÐ'¨Ñ-¨bÑ1Ð2Ñ2óð ùó ÷	+ð 	+ú÷ 	+ð 	+ûô
 ò ÜØ.¬t°E«{×/CÑ/CÐ.DÐDUÔVZÐ[a×[fÑ[fÓ[hÓViÐUjÐjkÐló
àð	ûðüó
s_   ±D ÁDÁC8Á.%C2
ÂC8Â1DÂ9D ÃEÃ2C8Ã8D	Ã=DÄDÄ	D Ä	EÄ=EÅEc                óp   — t        | |«      }|d   \  }}t        |«      s|S t        ||«      }|d   |d<   |S )u  Decompose a generative model into independently exportable `(model, forward_inputs)` pairs.

    Runs `decompose_prefill_decode` to capture prefill and decode forward kwargs from a real
    `model.generate(**inputs, max_new_tokens=2)`. If the prefill is multi-modal (per `is_multimodal`),
    further splits it into one entry per submodule (vision/audio encoder, projector, language model,
    `lm_head`) via `decompose_multimodal`.

    Args:
        model: Generative model. Must support `model.generate(**inputs)`.
        inputs: **Generate** kwargs â€” what you'd pass to `model.generate(**inputs)`.

    Returns:
        `{component_name: (submodel, forward_inputs)}`. Keys are `"prefill"` / `"decode"` for
        plain generative models and `"<modality>_encoder"` / `"multi_modal_projector"` /
        `"language_model"` / `"lm_head"` / `"decode"` for multi-modal generative models.
    r  r  )r$  r=  rA  )r›   r®   ÚstagesÚprefill_modelÚprefill_inputsÚ
componentss         r   Údecompose_for_generationrG  à  sM   € ô& & e¨VÓ4€FØ$*¨9Ñ$5Ñ!€M�>ä˜Ô'Øˆä% m°^ÓD€JØ! (Ñ+€JˆxÑØÐr/   )r   r   r   ry   r   r   )r    zlist[tuple[Any, str, callable]])r%   ry   )r%   ry   r‹   ÚNone)r%   ry   rB   ry   )r?   ry   )r   r   r-   Úcallabler‹   r   )Ú )r   r   r{   ry   )r   r   r‹   zdict[str, torch.Tensor])r   r   r‹   r   )r   r   r�   ztorch.dtyper‘   ztorch.devicer‹   r   )r›   ú!PreTrainedModel | torch.nn.Moduler‹   ztorch.device | None)r›   rK  r‹   ztorch.dtype | None)r›   rK  r®   zMutableMapping[str, Any]r‹   zRtuple[PreTrainedModel | torch.nn.Module, MutableMapping[str, Any], dict[str, Any]])r›   útorch.nn.Moduler´   ry   r‹   z
Any | None)rº   ry   )r›   rL  r®   údict[str, Any]r‹   rH  )rµ   rL  )r›   r	   r®   rM  r‹   z'dict[str, tuple[torch.nn.Module, dict]])r›   r	   r‹   zdict[str, torch.nn.Module])r›   r	   r‹   r<  )KÚ__doc__Ú
__future__r   r   r	  Úenumr  rù   rá   Úcollections.abcr   Útypingr   Úutilsr   Úutils.import_utilsr   Ú
get_loggerrI   ÚloggerrR   Úmodeling_utilsr	   Úvision_utilsr
   r   r   r   r   r   r   Ú__annotations__r   r   Úcontextmanagerr   r"   r&   r2   r5   r9   rC   r>   ra   rn   rb   ÚEnumÚSymIntÚSymFloatÚSymBoolrf   rz   r€   rŒ   r•   rœ   rŸ   r«   r²   r¶   r·   r»   rË   rÔ   rä   rò   r­   r  r$  r3  r4  r:  r=  rA  rG  r0   r/   r   ú<module>r_     sv  ðò õ* #ã Û Û Û Û Û 
Ý *Ý å Ý 3ð 
ˆ×	Ñ	˜HÓ	%€ñ ÔÛå0÷÷ ð" 8:€Ð
4Ó 9Ø,.€Ð)Ó .Ø/1Ð Ð,Ó 1ð ×Ñò*ó ð*ð ×Ñò	ó ð	ð ×Ñòó ðóóóóó6ó&ðJ '+ WÐ Ð"Ó ,ÙÔØ˜Ÿ™ E§L¡L°%·.±.À%Ç-Á-ÐPÑPÐóô09ó,
)ó*ó&)ó	óð i€ð4'Ø,ð4'Ø6Nð4'àWó4'ó|ð <>Ð Ð8Ó =ó
ñ   
Ó+ò!
ó ,ð!
ñH   Ó/ò[ó 0ð[ñ$  Ð 0°.ÓAòSó BðSñ>  Ð 0Ð2GÓHògó Iðgó*$ðH ×Ñò"ó ð"ð>"Øð"àð"ð -ó"ðN dÐ Ø(Ð ó"óJ4ó
)ðXØðØ$2ðà,ôr/   