
    ^j{                    N   U d Z ddlmZ ddlZddlZddlmZmZ ddlZddl	m
c mZ ddlmZmZ ddlmZmZ ddlmZ ddlmZ dd	lmZmZmZ  e       Zg d
ZdZdZded<   	 	 	 	 	 	 	 	 	 	 	 	 ddZ ddZ!ddZ"	 	 	 	 	 	 ddZ# edddiddd      	 d	 	 	 	 	 	 	 d d       Z$d!dZ%y)"a8  Shared weight-loading and LoRA application utilities.

Provides the canonical implementations of pretrained checkpoint loading and LoRA adapter injection, used by both the L1
inference facade (``rfdetr.detr``) and the L2 LightningModule (``rfdetr.training.module_model``).

The weight-loading logic is taken from ``RFDETRModelModule._load_pretrain_weights`` in ``module_model.py`` (more
complete: Pydantic-aware user-override detection, auto-alignment for fine-tuned checkpoints) and augmented with class-
name extraction from ``detr.py:_load_pretrain_weights_into``.
    )annotationsN)AnyList)download_pretrain_weightsvalidate_pretrain_weights)ModelConfigTrainConfig)
deprecated)
get_logger)_ckpt_args_getremap_projector_to_cross_attn!validate_checkpoint_compatibility)load_pretrain_weights
apply_lorainterpolate_position_embeddingszembeddings.position_embeddings)zrefpoint_embed.weightzquery_feat.weightztuple[str, ...]_QUERY_PARAM_SUFFIXESc                   |dk  s|dk  s
|dk  s|dk  rt        d| d| d| d| d	      ||z  }| j                  d   |k7  r.t        j                  d|||| j                  d          | d||z   S ||k(  r||k(  r| S t	        ||      }t	        ||      }t        |      D cg c]  }| ||z  ||z  |z     }	}t        j                  |	d	      S c c}w )
u	  Slice a ``refpoint_embed`` / ``query_feat`` weight preserving per-group structure.

    ``LWDETR`` packs query embeddings as ``nn.Embedding(num_queries * group_detr, ...)`` where group ``g`` occupies the
    contiguous slot range ``[g * num_queries, (g + 1) * num_queries)`` (see ``LWDETR.__init__`` and ``LWDETR.forward``
    in ``models/lwdetr.py``).  When ``num_queries`` decreases and ``group_detr > 1``, a flat ``tensor[:
    target_num_queries * target_group_detr]`` slice silently scrambles groups: the tail of group 0 winds up in what
    should be group 1's slots, and so on.  At inference only group 0 is read so the bug is invisible, but for
    training-resume it corrupts groups 1+.

    This helper does the right thing per group:

    * ``num_queries`` decrease (``target_num_queries < ckpt_num_queries``) →
      keep the first ``target_num_queries`` slots of each retained group.
    * ``group_detr`` decrease (``target_group_detr < ckpt_group_detr``) →
      drop tail groups; retained groups stay pretrained.
    * Either dimension expands, or one shrinks while the other expands →
      return whatever per-group sub-tensor can be built (``min(target, ckpt)`` along each axis). The result has fewer
      rows than the model expects, so ``load_state_dict`` will raise a shape mismatch immediately.

    When the tensor's flat length disagrees with ``ckpt_num_queries * ckpt_group_detr`` (corrupt or unexpected
    checkpoint shape), fall back to the legacy flat slice so loading continues with the same behavior the codebase had
    before this fix.

    Args:
        tensor: The checkpoint tensor for ``refpoint_embed.weight`` or
            ``query_feat.weight``.
        ckpt_num_queries: ``num_queries`` recorded in the checkpoint's training args.
        ckpt_group_detr: ``group_detr`` recorded in the checkpoint's training args.
        target_num_queries: ``num_queries`` configured for the model.
        target_group_detr: ``group_detr`` configured for the model.

    Returns:
        A tensor whose layout matches the model's configured packing for the decrease-or-equal cases, or a per-group
        sub-tensor built from ``min(target, ckpt)`` along each axis for the expansion case (which ``load_state_dict``
        will then reject on shape mismatch).

    Raises:
        ValueError: If any of ``ckpt_num_queries``, ``ckpt_group_detr``,
            ``target_num_queries``, or ``target_group_detr`` is ≤ 0.
    r   zX_slice_query_param_per_group: all dimension args must be positive; got ckpt_num_queries=z, ckpt_group_detr=z, target_num_queries=z, target_group_detr=.u   _slice_query_param_per_group: checkpoint args claim %d × %d = %d rows but tensor has %d rows; falling back to flat slice. Per-group structure may be scrambled if group_detr > 1.Ndim)
ValueErrorshapeloggerwarningminrangetorchcat)
tensorckpt_num_queriesckpt_group_detrtarget_num_queriestarget_group_detrexpected_totalkeep_groupskeep_per_groupgpiecess
             `/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/rfdetr/models/weights.py_slice_query_param_per_groupr*   *   s7   ^ 11 48Ja8OSdhiSi$$4#55GGX Y""4!55IJ[I\\]_
 	
 &7N||A.(2 LLO	
 >*->>??--2C2V'9K+-=>N\abm\noWXfQ))A0@,@>,QRoFo99V## ps   #Cc                j    ddgt         dddfd}| D cg c]  } ||      r| c}S c c}w )u;  Return *keys* with intentional-reinit/trim entries removed.

    Matching is boundary-aware: a pattern matches a key when the pattern appears at the start of the key or immediately
    after a module separator (``.``).  This prevents substring collisions where a pattern like ``"class_embed."`` would
    inadvertently match a key belonging to an unrelated module (e.g. ``"class_embed_projection.weight"`` is safe because
    ``class_embed_projection.`` ≠ ``class_embed.``, but using a plain ``in`` check against longer ambiguous strings is
    fragile by design).
    zclass_embed.zbbox_embed.zenc_out_class_embed.zenc_out_bbox_embed.c                .     t         fdD              S )Nc              3  R   K   | ]  }j                  |      xs d | v    yw)r   N)
startswith).0patkeys     r)   	<genexpr>zD_filter_intentional_keys.<locals>._is_intentional.<locals>.<genexpr>   s-     [s3>>#&:AcU)s*::[s   $')any)r1   intentional_patternss   `r)   _is_intentionalz1_filter_intentional_keys.<locals>._is_intentional   s    [FZ[[[    )r1   strreturnbool)r   )keysr5   kr4   s      @r)   _filter_intentional_keysr<   w   sT     	- 
- 		-
 	-\ 6!?1#5A666s   00c                   t        | dd      }t        | dd      }	 |r|D cg c]  }t        |       c}ng }|r|D cg c]  }t        |       c}ng }t        |      }t        |      }|s|syg }	|rGdj	                  |dd       }
t        |      dkD  r|
dz  }
|	j                  t        |       d|
 d       |rGdj	                  |dd       }
t        |      dkD  r|
dz  }
|	j                  t        |       d	|
 d       t        j                  d
|dj	                  |	             yc c}w c c}w # t        $ r Y yw xY w)uP  Emit a ``logger.warning`` when ``load_state_dict`` left non-trivial gaps.

    ``load_state_dict(strict=False)`` silently ignores keys that the model has but the checkpoint does not
    (``missing_keys``) and keys present in the checkpoint but absent from the model (``unexpected_keys``).  When this
    happens for parameters outside the head / query embeddings — which the loader intentionally reinitialises or trims —
    the corresponding model weights were left at their random initial values and the user is silently getting a much
    weaker model. This helper surfaces that condition with a single, actionable warning. Same-key shape mismatches do
    not reach this function — they raise :class:`RuntimeError` directly from ``load_state_dict`` and are therefore
    impossible to miss.

    Args:
        incompatible: The ``_IncompatibleKeys`` namedtuple returned by
            :meth:`torch.nn.Module.load_state_dict`.
        pretrain_weights_path: Path to the checkpoint that was loaded; included
            in the warning so the user can identify which load partially succeeded.
    missing_keysNunexpected_keysz,    z, ...z> model parameter(s) not in checkpoint (left at random init): []z+ checkpoint key(s) not consumed by model: [u   Pretrained weights at %r loaded only partially — this typically produces lower accuracy. %s. Check that the model configuration (encoder, hidden_dim, out_feature_indexes, projector_scale, ...) matches the architecture the checkpoint was trained with. )	getattrr7   	TypeErrorr<   joinlenappendr   r   )incompatiblepretrain_weights_pathmissing_keys_rawunexpected_keys_rawr;   r>   r?   missing
unexpectedpartssamples              r)   _warn_on_partial_loadrP      sW   " |^TB!,0A4H=M(891A9SUCV+>?a3q6?\^ '|4G)/:J:E72A;'w<!gFG~%cdjckklmn:bq>*z?QgFJ((STZS[[\]^
NN	' 	- :? s,   D6 D,D6 D1D6 ,
D6 6	EEc           
        ||z  }| D cg c]  }|j                  t              s| }}|D ]  }| |   }|j                  d   dz
  }||k(  r!t        t	        j
                  |            }t        t	        j
                  |            }	||z  |k7  s|	|	z  |k7  r t        j                  d| d| d| d       |j                  d   }
|ddddf   }|ddddf   }|j                  d|||
      j                  dd	dd
      }t        j                  |j                         |	|	fdd|j                  j                  dk7        j                  |j                         }|j                  dd
d	d      j                  d||
      }t#        j$                  ||gd      | |<   t        j'                  d|t)        |j                        t)        | |   j                                yc c}w )ut  Interpolate DINOv2 positional embeddings in *checkpoint_state* to match *pe_size*.

    When the model is configured with a custom ``resolution`` that differs from the checkpoint's training resolution,
    the DINOv2 backbone's ``position_embeddings`` parameter has an incompatible shape.
    ``load_state_dict(strict=False)`` does **not** skip shape mismatches on matching keys — it raises ``RuntimeError``.

    This function bicubic-interpolates every PE tensor in the checkpoint whose shape differs from the target grid,
    modifying *checkpoint_state* in-place before ``load_state_dict`` is called.

    Args:
        checkpoint_state: The ``"model"`` sub-dict from a loaded checkpoint.
        pe_size: Target grid side length in patches (number of patches per spatial
            dimension, assuming a square grid).  Typically ``model_config.positional_encoding_size``.
       zSkipping PE interpolation for z,: grid size is not a perfect square (source z	, target z).Nr         bicubicFmps)sizemodealign_corners	antialiasr   u1   Interpolated positional embeddings %s: %s → %s.)endswith_PE_KEY_SUFFIXr   intmathisqrtr   r   reshapepermuteFinterpolatefloatdevicetypetodtyper   r   debugtuple)checkpoint_statepe_sizen_targetr;   pe_keysr1   ckpt_pen_sourceh_srch_tgtr   class_tokenpatch_pes                r)   r   r      s   $  H*IQajj.HqIGI #
"3'==#a'xDJJx()DJJx()5=H$(ANN0 6>>FZyQYPZZ\^ mmBa!en1ab5>##AueS9AA!Q1M==NNoo**e3
 "W]]
 	 ##Aq!Q/778SI %		;*Aq I?'-- "3'--.		
=#
 Js
   G%G%Ttrain_configz1.7.0z1.9.0rS   )targetargs_mappingdeprecated_in	remove_in	num_warnsc           	        |}|j                   }|g S g }t        |       t        j                  j	                  |      s#t
        j                  d       t        |dd       t        |d       	 t        j                  |dd      }d
|vrd|v rt
        j                  d       d}d}i }	|d   j                         D ]I  \  }
}|
j                  |      s|
t        |      d }|j                  |      r|t        |      d }||	|<   K |	st!        d|d      |	|d
<   d|vrd|v r|d   |d<   d|v rQt#        |d   d      }|r@t%        |t&              r|g}n,	 t)        |      }|D cg c]  }t%        |t&              s| }}t-        ||       dt/        |dt1                     v }|j2                  }|d
   d   j4                  d   }|dz   }||k7  r&||k  r|s|dz
  }|}||_        | j7                  |       |j9                  d      }|t#        |d      nd}|t#        |d      nd}	 |t;        |      nd}|t;        |      nd}|du |du k7  rt=        d |d
   D        d      }|s|d
   |   j4                  d   }d}||dkD  r||z  dk(  r||z  }d|d|f\  }}}}n||dkD  r||z  dk(  r||z  }d|d|f\  }}}}|t
        j                  d|||       |j>                  dkD  r$|| t
        j                  d|j>                         tA        |d
   jC                               D ]t  tE        fdtF        D              s|d
      }|-|+tI        ||||jJ                  |j>                         |d
   <   S|d|jJ                  |j>                  z   |d
   <   v tM        |d
   |       |d
<   d!t/        |dt1                     v } | s8t/        |d"d      r*tO        |d!      r|d
   j9                  d#      }!t%        |!t        jP                        r|!jR                  d$k(  r|!jU                  d%      jW                         D "cg c]  }"t;        |"       }#}"tA        t/        |d!g       xs g       }$tE        d& |#D              st
        j                  d'|#       ng|#|$k7  rbt
        j                  d(|$|#       |#|_,        nCt%        |!t        jP                        r)t
        j                  d)t[        |!j4                               tA        t/        |d!g       xs g       }%d}&d}'t/        |d"d      rtO        | d*      ru| j]                  |d
         }&|&r_t/        | d+d      }(t_        |(      r |(       n|%})|&|)k7  r9tO        | d,      r-t
        j                  d-|)|&       | ja                  |&       |&|%k7  }'|d
   j9                  d#      }*tO        | d      r| jc                         ni }+t%        |+td              r|+j9                  d#      nd},t%        |*t        jP                        rt%        |,t        jP                        rm|*j4                  |,j4                  k7  rT|'sRt
        j                  d.t[        |*j4                        t[        |,j4                               |d
   jg                  d#d       ti        |d
   |jj                         | jm                  |d
   d      }-to        |-|       |'r3tO        | d,      r't
        j                  d/|%       | ja                  |%       ||k  r|r| j7                  |       |dz   |k  r| j7                  |dz          |S # t        $ r? t
        j                  d	       t        |dd       t        j                  |dd      }Y w xY wc c}w # t*        $ r g }Y (w xY w# t*        t         f$ r t
        j                  d       d}d}Y w xY wc c}"w )0u  Load pretrained checkpoint weights into *nn_model* in-place.

    Canonical implementation shared by the L1 facade (``_build_model_context`` in ``rfdetr.detr``) and the L2
    LightningModule (``RFDETRModelModule.__init__`` in ``rfdetr.training.module_model``).

    Uses the Pydantic-aware logic from ``module_model.py``:

    - When the user did **not** explicitly set ``num_classes`` (it is left unset),
      the checkpoint class count is treated as authoritative and the model head is auto-aligned to it.
    - When the user **did** explicitly set ``num_classes`` (to any value, including the
      class default) larger than the checkpoint provides, the head is temporarily aligned to the checkpoint for
      loading, then expanded back to the configured size.
    - When the checkpoint has more classes than configured (backbone-pretrain
      scenario), both reinitializations are applied: expand to checkpoint size for loading, then trim to configured
      size.

    Class names stored in the checkpoint ``args`` are extracted and returned.

    Args:
        nn_model: The model whose weights will be updated in-place.
        model_config: Pydantic ``ModelConfig`` instance. Must have
            ``pretrain_weights``, ``num_classes``, ``num_queries``, and ``group_detr`` attributes.
        train_config: Deprecated since v1.7.0 — no longer used internally.
            Passing a non-``None`` value emits a ``DeprecationWarning``.
            Omit the argument; it will be removed in v1.9.0.

    Returns:
        List of class name strings from the checkpoint, or an empty list if none are present or if
        ``model_config.pretrain_weights`` is ``None``.

    Raises:
        Exception: If the checkpoint file cannot be loaded even after a re-download.
    NzSPretrain weights not found after initial download; retrying without MD5 validation.TF)
redownloadvalidate_md5)strictcpu)map_locationweights_onlyz/Failed to load pretrain weights, re-downloadingmodel
state_dictz=Normalizing PTL .ckpt checkpoint format (state_dict -> model)zmodel.z
_orig_mod.zThe checkpoint at z appears to be in PyTorch Lightning format ('state_dict' key present, 'model' key absent), but 'state_dict' contains no keys with the expected 'model.' prefix. The checkpoint may be corrupt or in an unsupported format.argshyper_parametersclass_namesnum_classesmodel_fields_setzclass_embed.biasr   rR   num_queries
group_detrz}load_pretrain_weights: checkpoint args.num_queries / args.group_detr not coercible to int; falling back to legacy flat slice.c              3  T   K   | ]  t        fd t        D              s ! yw)c              3  @   K   | ]  }j                  |        y wNr\   )r/   sr;   s     r)   r2   z2load_pretrain_weights.<locals>.<genexpr>.<genexpr>  s     2`Q1::a=2`   N)r3   r   )r/   r;   s    @r)   r2   z(load_pretrain_weights.<locals>.<genexpr>  s     a1s2`J_2`/`Qas   ((u]   load_pretrain_weights: args.%s absent; inferred ckpt_%s=%d from tensor rows %d ÷ ckpt_%s=%d.zload_pretrain_weights: checkpoint lacks args.num_queries / args.group_detr; falling back to flat slice. With group_detr=%d this may scramble per-group query structure if the checkpoint was trained with group_detr > 1.c              3  @   K   | ]  }j                  |        y wr   r   )r/   xnames     r)   r2   z(load_pretrain_weights.<locals>.<genexpr>  s     ?At}}Q?r   )r    r!   r"   r#   num_keypoints_per_classuse_grouppose_keypoints_kp_active_maskrU   r   c              3  &   K   | ]	  }|d kD    yw)r   N )r/   ns     r)   r2   z(load_pretrain_weights.<locals>.<genexpr>  s     6q1u6s   u   load_pretrain_weights: _kp_active_mask in checkpoint has no active slots (schema=%s) — skipping auto-align to avoid overwriting config with empty schema.u   load_pretrain_weights: auto-aligning num_keypoints_per_class %s → %s (inferred from checkpoint _kp_active_mask; user did not set explicitly).u   load_pretrain_weights: _kp_active_mask has unexpected shape %s (expected 2-D) — skipping auto-align; schema mismatch may cause AP≈0 on keypoint models.+get_num_keypoints_per_class_from_checkpointget_num_keypoints_per_classreinitialize_keypoint_headz\load_pretrain_weights: temporarily resizing keypoint schema from %s to checkpoint schema %s.zload_pretrain_weights: dropping checkpoint _kp_active_mask with shape %s because current model expects %s (derived from current keypoint schema).zUload_pretrain_weights: restoring configured keypoint schema %s after checkpoint load.)8pretrain_weightsr   ospathisfiler   r   r   r   load	Exceptioninforj   itemsr.   rF   r   r   
isinstancer7   iterrD   r   rC   setr   r   reinitialize_detection_headgetr^   nextr   listr:   r3   r   r*   r   r   hasattrTensorndimsumtolistr   rk   r   callabler   r   dictpopr   positional_encoding_sizeload_state_dictrP   ).nn_modelmodel_configrv   mcr   r   
checkpointprefixcompile_prefixmodel_stater;   vstrippedraw_class_namesiteratorr   user_overroder   checkpoint_num_classesconfigured_num_classes_plus_bg	ckpt_argsckpt_num_queries_rawckpt_group_detr_rawr    r!   _first_query_key_n_absent	_inferred_known
_known_valr   _user_overrode_kp_schema_early_kp_maskr   _ckpt_kp_schema_cfg_kp_schemaconfigured_keypoint_schemacheckpoint_keypoint_schema%should_restore_config_keypoint_schemaget_model_schemamodel_keypoint_schemackpt_kp_active_maskmodel_state_dictmodel_kp_active_maskrH   s.                  `                              r)   r   r     s   N 
B**	K ./ 77>>*+lm!"2tRWX.u=ZZZ 0uSXY
 j \Z%?TU &|,224 	*DAq||F#S[]+&&~6'N(;(=>H()H%	* $%5$8 9M M  *
7 #(:j(H!+,>!?Jv (F);]K /3/./W#O4H
 5="VD
4QT@U4"VK"V%j"5 "WR1CSU%KKM..K'01CDJJ1M%01_"!??!$BB  5q81G.!, 	,,-CD
 v&IGPG\>)]CbfENEZ.LA`d	8L8X334^b6I6U#12[_ 	D o&=>a
7+a
 'G$%56<<Q?B"&G+0@10DN^I^bcIc"$(8"89EXegw9w6FJ ,11DoI]abIb#%#8 9FHXZfhw9w6FJ"s 
}}q.6/:Q> MM	
 Z(--/0 U?)>??(.F+0K,H%5$3')~~&(mm-
7#D) -33SR^^bmm5S,T
7#D)#U& 8
78KXVJw  9GBHZ\_\a<bb$B159B12#G,001BCnell38K8Kq8P/=/A/Aa/A/H/O/O/QR!s1vROR!'".G"L"RPRSN6o66i#
 !N2_"#	 .=*5NN`n**+ "&gb2KR&P&VTV!W!%,1)r,e4?: &.%Y%YZdelZm%n"%&x1NPTU:BCS:T$4$6Zt!)-BBwxYuGvr).
 334NO8RVp8p5 %W-112CD07,0Ox**,UWFPQacgFh+//0ABnr&5+U\\:%%)=)C)CC5W%++,&,,-		
 	7 148#Jw$79T9TU++Jw,?+NL,(89,C_1`c&	
 	++,FG  >>=,,-KL Q//,,[1_=  ZEF!"2tRWXZZ 0uSXY
Zh #W	 ! %"$K%V z" 9	
  ^ SsI   1] ^  *^ ^,^2 
_!A^^ ^/.^/2(__c                    	 ddl m}m}  |dddg d      } || j                  d   j
                  |      | j                  d   _        y# t        $ r}t        d      |d}~ww xY w)	a  Apply LoRA adapters to the backbone encoder of *nn_model*.

    Replaces ``nn_model.backbone[0].encoder`` in-place with a PEFT-wrapped encoder using DoRA with rank 16 and alpha 16.

    Args:
        nn_model: LWDETR model whose backbone encoder will receive LoRA adapters.

    Raises:
        ImportError: If ``peft`` is not installed.
            Install via the RF-DETR extras, for example::

                pip install "rfdetr[lora]"
                # or
                pip install "rfdetr[train]"
    r   )
LoraConfigget_peft_modelzLoRA requires the 'peft' dependency. Install it via RF-DETR extras, e.g.: pip install "rfdetr[lora]" or pip install "rfdetr[train]".N   T)	q_projv_projk_projqkvqueryr1   value	cls_tokenregister_tokens)r
lora_alphause_doratarget_modules)peftr   r   ImportErrorbackboneencoder)r   r   r   exclora_configs        r)   r   r   =  s|     3 


	K  $2(2C2CA2F2N2NP[#\Ha /  I
 		s   A 	A%A  A%)r   torch.Tensorr    r^   r!   r^   r"   r^   r#   r^   r8   r   )r:   	list[str]r8   r   )rH   r   rI   r7   r8   None)rl   r   rm   r^   r8   r   r   )r   torch.nn.Moduler   r   rv   zTrainConfig | Noner8   z	List[str])r   r   r8   r   )&__doc__
__future__r   r_   r   typingr   r   r   torch.nn.functionalnn
functionalrc   rfdetr.assets.model_weightsr   r   rfdetr.configr   r	   rfdetr.utilities.decoratorsr
   rfdetr.utilities.loggerr   rfdetr.utilities.state_dictr   r   r   r   __all__r]   r   __annotations__r*   r<   rP   r   r   r   r   r6   r)   <module>r     s!   #  	     \ 2 2 . x x	
T1 *X  WJ$J$J$ J$ 	J$
 J$ J$Z781h8
8
8
 
8
v 4~t&<G_frtu (,www %w 	w vwt	)]r6   