
    ^jZ                        d Z ddlZddlmZ ddlmZmZmZmZm	Z	m
Z
mZmZ ddlZddlmZ ddlmc mZ ddlmZmZ ddlmZmZmZmZmZ ddlmZ dd	lmZ dd
l m!Z!m"Z" ddl#m$Z$m%Z% ddl&m'Z' ddgZ( G d dejR                        Z*dejV                  dejV                  fdZ,	 dRdejV                  dejV                  dejV                  de-dejV                  f
dZ.	 	 dSdejV                  dejV                  dejV                  de-de-dejV                  fdZ/ G d dejR                        Z0 G d dejR                        Z1 G d dejR                        Z2 G d  d!ejR                        Z3 G d" d#ejR                        Z4 G d$ d%ejR                        Z5 G d& dejR                        Z6 G d' dejR                        Z7dTd)ejR                  d*e8d+e9ddfd,Z:dTd-e8d+e9defd.Z;d/ee8ejV                  f   d0e6dee8ejV                  f   fd1Z<d/ee8ejV                  f   d0ddee8ejV                  f   fd2Z=dUd4e8d5e9de6fd6Z>dUd4e8d5e9de7fd7Z?dVd8e8dee8ef   fd9Z@ e$ e@d:d;d<=       e@d>d;d<=       e@d?d<@       e@dAd<@      dB      ZA eBdCdDdEdFdGd3d(H      ZC eBdIdJdDdKdLd(M      ZDe%dUd5e9de7fdN       ZEe%dUd5e9de6fdO       ZFe%dUd5e9de7fdP       ZGe%dUd5e9de6fdQ       ZHy)WaM  Gemma4 Vision Transformer

Vision encoder from Google's Gemma 4 multimodal model.
Custom ViT with 2D RoPE, Gated MLP, QKV normalization, and 4-norm sandwich blocks.

Paper: https://ai.google.dev/gemma/docs/core/model_card_4
Reference impl: https://github.com/huggingface/transformers (Gemma4VisionModel)

Copyright 2025 Yonghye Kwon
    N)partial)AnyCallableDictListOptionalSetTupleUnion)IMAGENET_DEFAULT_MEANIMAGENET_DEFAULT_STD)RmsNormDropPath	to_2tupletrunc_normal_tf_use_fused_attn   )build_model_with_cfg)feature_take_indices)
checkpointnamed_apply)generate_default_cfgsregister_model)batch_patchifyGemma4VitEncoderGemma4VitClassifierc            	       |     e Zd ZdZ	 	 	 ddedededdf fdZddZd	ej                  dej                  fd
Z
 xZS )Gemma4ClippableLinearzLinear layer with optional input/output clamping.

    Used in Gemma4 E4B variant where clamp values are finite and affect output.
    When use_clipped=False, behaves as a standard nn.Linear (no buffers registered).
    Nin_featuresout_featuresuse_clippedreturnc                    ||d}t         |           || _        t        j                  ||fddi|| _        |r| j                  dt        j                  di |       | j                  dt        j                  di |       | j                  dt        j                  di |       | j                  dt        j                  di |       | j                          y y )	NdevicedtypebiasF	input_min	input_max
output_min
output_max) )
super__init__r!   nnLinearlinearregister_buffertorchemptyreset_parameters)selfr   r    r!   r%   r&   dd	__class__s          a/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/timm/models/gemma4_vit.pyr.   zGemma4ClippableLinear.__init__'   s     /&ii\LLL  ekk.C.CD  ekk.C.CD  u{{/D/DE  u{{/D/DE!!#     c                 B   | j                   r| j                  j                  t        d              | j                  j                  t        d             | j
                  j                  t        d              | j                  j                  t        d             y y )Ninf)r!   r(   fill_floatr)   r*   r+   r6   s    r9   r5   z&Gemma4ClippableLinear.reset_parameters;   sn     NN  %,/NN  u.OO!!5<-0OO!!%,/	 r:   xc                    | j                   r+t        j                  || j                  | j                        }| j                  |      }| j                   r+t        j                  || j                  | j                        }|S N)r!   r3   clampr(   r)   r1   r*   r+   r6   r@   s     r9   forwardzGemma4ClippableLinear.forwardD   sZ    At~~t~~>AKKNAt@Ar:   )FNNr"   N)__name__
__module____qualname____doc__intboolr.   r5   r3   TensorrE   __classcell__r8   s   @r9   r   r       s^     !&$$ $ 	$ 
$(0 %,, r:   r   r@   r"   c                     | dd| j                   d   dz  f   }| d| j                   d   dz  df   }t        j                  | |fd      S )z*Rotates half the hidden dims of the input..N   dim)shaper3   cat)r@   x1x2s      r9   rotate_halfrY   M   sZ    	
3"!''"+"""	#B	
3q ""	#B99rc2YB''r:   cossinunsqueeze_dimc                 n    |j                  |      }|j                  |      }| |z  t        |       |z  z   S )z0Apply rotary position embedding to input tensor.)	unsqueezerY   )r@   rZ   r[   r\   s       r9   apply_rotary_pos_embr_   T   s8     --
&C
--
&CGA,--r:   ndimc           	      f   | j                   d   }d|d|z  z  z  }|g|z  }t        j                  | |d      }t        j                  ||d      }	t        j                  ||d      }
t        |      D cg c]  }t	        ||   |	|   |
|   |       }}t        j
                  |d      S c c}w )zApply multidimensional RoPE to input tensor.

    Splits input along head_dim into ndim parts, applies RoPE to each,
    then concatenates back.
    rQ   rR   rS   )r\   )rU   r3   splitranger_   rV   )r@   rZ   r[   r`   r\   num_input_channelsnum_rotated_channels_per_dimsplit_sizesx_parts	cos_parts	sin_partsky_partss                r9   apply_multidimensional_roperl   `   s     #$(:q4x(H#I /047Kkk![b1GC"5IC"5I lqqukvfgWQZ1y|S`aG  99W"%%s   6B.c                        e Zd ZdZ	 	 	 ddededdf fdZddZddZdd	Z	d
e
j                  de
j                  dee
j                  e
j                  f   fdZ xZS )Gemma4RotaryEmbedding2Dz2D Rotary Position Embedding for Gemma4 vision encoder.

    Computes RoPE independently for each spatial dimension (x, y),
    using theta=100.0 and the partitioned head_dim.
    Nhead_dim
rope_thetar"   c                     t         |           || _        || _        |dz  dz  }| j	                  dt        j                  ||t
        j                        d       | j                          y )NrR   inv_freqr$   F)
persistent)	r-   r.   ro   rp   r2   r3   r4   r>   _init_buffers)r6   ro   rp   r%   r&   	num_freqsr8   s         r9   r.   z Gemma4RotaryEmbedding2D.__init__   si     	 $ ]q(	KK	&D 	 	
 	r:   c           	          | j                   dz  }d| j                  t        j                  d|dt        j                  | j
                  j                        |z  z  z  }| j
                  j                  |       y)z.Compute and fill non-persistent buffer values.rR         ?r   r&   r%   N)ro   rp   r3   aranger>   rr   r%   copy_)r6   spatial_dimrr   s      r9   rt   z%Gemma4RotaryEmbedding2D._init_buffers   sc    mmq(OOQQekk$--J^J^_bmmo
 	H%r:   c                 $    | j                          y rB   rt   r?   s    r9   r5   z(Gemma4RotaryEmbedding2D.reset_parameters   s    r:   c                 $    | j                          y)z"Initialize non-persistent buffers.Nr}   r?   s    r9   init_non_persistent_buffersz3Gemma4RotaryEmbedding2D.init_non_persistent_buffers   s    r:   r@   position_idsc                 \   t        j                         5  | j                  ddddf   j                         j	                  |j
                  d   dd      j                  |j                        }g }g }t        d      D ]  }|dddd|f   }|dddddf   j                         }|j                         |j                         z  j                  dd      }	t        j                  |	|	fd      }
|j                  |
j                                |j                  |
j                                 t        j                  |d      j                  |j                        }t        j                  |d      j                  |j                        }ddd       ||fS # 1 sw Y   fS xY w)z
        Args:
            x: Hidden states tensor, used only for dtype/device.
            position_ids: (B, N, 2) Gemma4-internal ``(x, y)`` patch coords.

        Returns:
            cos, sin: (B, N, head_dim) tensors for RoPE application.
        Nr   rQ   r   rR   rS   )r&   )r3   no_gradrr   r>   expandrU   tor%   rc   	transposerV   appendrZ   r[   r&   )r6   r@   r   inv_freq_expandedall_cosall_sinidim_posdim_pos_expandedfreqsembrZ   r[   s                r9   rE   zGemma4RotaryEmbedding2D.forward   sq     ]]_ 	? $dAtm < B B D K KLL^L^_`Lacegh i l lmnmumu v*,G*,G1X *&q!Qw/#*1dA:#6#<#<#> *0025E5K5K5MMXXYZ\]^iiB7swwy)swwy)* ))G,//agg/>C))G,//agg/>C	?  Cx!	?  Cxs   E>FF+)      Y@NNrF   )rG   rH   rI   rJ   rK   r>   r.   rt   r5   r   r3   rM   r
   rE   rN   rO   s   @r9   rn   rn   z   s~     !&  
,& ||   ,,  
u||U\\)	*	 r:   rn   c                       e Zd ZdZ	 	 	 	 	 	 ddeeeeef   f   dedededdf
 fdZdd	Zd
ededede	j                  dee	j                  e	j                  f   f
dZde	j                  de	j                  de	j                  fdZ	 	 ddee	j                  eee	j                  f   f   dee	j                     dee	j                     dee	j                  e	j                  e	j                  f   fdZ xZS )Gemma4PatchEmbedu  Linear patch embedding with a 2D position-embedding table.

    Unlike the standard ViT PatchEmbed (Conv2d), Gemma4 uses a Linear projection
    on flattened patches plus a separate 2D position-embedding table applied via
    one-hot lookup. Inputs may be supplied as:

      * ``(B, C, H, W)`` raw images — patchified inline in P-P-C flat order.
      * ``(B, N, P*P*C)`` pre-patchified P-P-C patches (NaFlex loader output).
      * ``(B, N, Ph, Pw, C)`` pre-patchified unflattened patches.
      * ``dict`` with keys ``patches`` / ``patch_coord`` / ``patch_valid``.

    All input-dispatch logic is owned by this module; the parent model simply
    calls ``self.patch_embed(x, patch_coord, patch_valid)`` and unpacks the
    returned tensors.
    N
patch_sizein_chans	embed_dimposition_embedding_sizer"   c                 N   ||d}t         
|           t        |      | _        || _        || _        | j                  \  }}	t        j                  ||z  |	z  |fddi|| _        t        j                  t        j                  d||fi |      | _        | j                          y )Nr$   r'   FrR   )r-   r.   r   r   r   r   r/   r0   
input_proj	Parameterr3   r4   position_embedding_tabler5   )r6   r   r   r   r   r%   r&   r7   phpwr8   s             r9   r.   zGemma4PatchEmbed.__init__   s     /#J/"'>$B))HrMB$6	TTQST(*KK2IDD)
% 	r:   c                 2    t        | j                  d       y )N{Gz?std)r   r   r?   s    r9   r5   z!Gemma4PatchEmbed.reset_parameters   s    66DAr:   
batch_sizepHpWr%   c                    t        j                  ||      }t        j                  ||      }t        j                  ||d      \  }}t        j                  |j	                         |j	                         gd      }	|	j                  d      j                  |dd      }	t        j                  |||z  t         j                  |      }
|	|
fS )z:Row-major grid coords in external NaFlex ``(y, x)`` order.)r%   ij)indexingrQ   rS   r   rx   )	r3   ry   meshgridstackflattenr^   r   onesrL   )r6   r   r   r   r%   ysxsgrid_ygrid_xpatch_coordpatch_valids              r9   _default_patch_coordz%Gemma4PatchEmbed._default_patch_coord   s     \\"V,\\"V,B>kk6>>#3V^^5E"FBO!++A.55j"bIjjR"WEJJvVK''r:   r   padding_positionsc                 T   |j                  d      }t        j                  || j                        }|j	                  dddd      j                  | j                        }|| j                  z  }|j                  d      }t        j                  |j                  d      d	|      }|S )
zCompute position embeddings via one-hot matmul against the 2D table.

        ``position_ids`` follows the Gemma4-internal ``(x, y)`` convention.
        r   minnum_classesrR   r      rS   rQ           )rC   Fone_hotr   permuter   r   sumr3   wherer^   )r6   r   r   clamped_positionsr   position_embeddingss         r9   _position_embeddingsz%Gemma4PatchEmbed._position_embeddings  s     )..1.5))-4;W;WX//!Q1-001N1NO%(E(EE155!5<#kk''+S2E
 #"r:   r@   r   r   c                    t        |t              r)|j                  d|      }|j                  d|      }|d   }| j                  \  }}|j                  dk(  rO|j
                  \  }}}}	|'| j                  |||z  |	|z  |j                        \  }}t        |||fdd      \  }}n|j                  dk(  rA|j                  d	d
ddd      j                  |j
                  d	   |j
                  d
   d      }nz|j                  dk(  rR|j
                  \  }}
}|||z  z  }|j                  ||
|||      j                  d	d
ddd      j                  ||
|      }nt        d|j                   d      |t        d      |f|dk(  j                  d      }|j                         r| }n=t        j                   |j
                  dd t        j"                  |j                        }d|dz
  z  }| j%                  |j'                  | j$                  j(                  j*                              }|j-                  d      }| }|| j/                  ||      z   }|||fS )a  Normalize inputs, patchify / project / position-embed.

        Accepts external NaFlex ``patch_coord`` (y, x) / ``patch_valid`` inputs
        and returns the internal (x, y) form used by the rest of the model.

        Returns:
            embeddings: (B, N, embed_dim) patch embeddings with position info added.
            position_ids: (B, N, 2) Gemma4-internal (x, y) coords.
            padding_positions: (B, N) True for padding tokens.
        r   r   patches   NF)padchannels_last   r   r   rR   r   rQ   z&Expected input ndim in (3, 4, 5); got .z1patch_coord is required for pre-patchified input.rS   rx         ?)rQ   )dims)
isinstancedictgetr   r`   rU   r   r%   r   r   reshapeview
ValueErrorallanyr3   r   rL   r   r   weightr&   flipr   )r6   r@   r   r   r   r   B_HWNPPCCsentinelr   r   s                   r9   rE   zGemma4PatchEmbed.forward  sS     a%%{;K%%{;K)AB66Q;JAq!Q"+/+D+DQRQRVXQXZ[ZbZb+c([!!b"X5NDAqVVq[ 		!Q1a(00QWWQZLAVVq[ IAq#R Aq!RQ'//1aA>FFq!SQA8B  PQQ#r)..2.6H||~'i#jj%%bq)KDVDV
 SMOOADD!7!7!=!=>? #''U'3(L)),8IJJ, 111r:   )   r       (  NNrF   NN)rG   rH   rI   rJ   r   rK   r
   r.   r5   r3   r%   rM   r   r   r   strr   rE   rN   rO   s   @r9   r   r      s_   $ 79 +0 c5c?23    	 
 &)  
 .B(( ( 	(
 LL( 
u||U\\)	*( #,,#  %||# 
	#. 3726	@2U\\4U\\(9#::;@2 "%,,/@2 "%,,/	@2
 
u||U\\5<<7	8@2r:   r   c                   &    e Zd ZU dZej
                  j                  e   ed<   	 	 	 	 	 	 	 	 	 dde	de	de	de
e	   ded	ed
ededdf fdZ	 ddej                  dej                  dej                  de
ej                     dej                  f
dZ xZS )Gemma4Attentiona  Gemma4 Vision Attention with QKV normalization and 2D RoPE.

    Key features:
    - Separate Q, K, V projections (not fused)
    - RMSNorm on Q, K (with scale) and V (without scale)
    - 2D RoPE applied after normalization
    - Attention scale = 1.0 (since QK are normalized)
    
fused_attnNrT   	num_headsro   num_kv_heads	attn_drop	proj_dropnorm_epsuse_clipped_linearsr"   c                 d   |	|
d}t         |           || _        || _        |xs || _        || j                  z  | _        t               | _        t        |||z  fd|i|| _	        t        || j                  |z  fd|i|| _
        t        || j                  |z  fd|i|| _        t        ||z  |fd|i|| _        t        |f|dd|| _        t        |f|dd|| _        t        |f|dd|| _        t#        j$                  |      | _        t#        j$                  |      | _        y )Nr$   r!   TepsaffineF)r-   r.   r   ro   r   num_kv_groupsr   r   r   q_projk_projv_projo_projr   q_normk_normv_normr/   Dropoutr   r   )r6   rT   r   ro   r   r   r   r   r   r%   r&   r7   r8   s               r9   r.   zGemma4Attention.__init__h  sB    /" (5I&$*;*;;(*+CX1EmSfmjlm+C1B1BX1Mu[nurtu+C1B1BX1Mu[nurtu+I,@#mSfmjlmhHHTHRHhHHTHRHhIHUIbII.I.r:   r@   rope_cosrope_sin	attn_maskc                    |j                   \  }}}| j                  |      j                  ||| j                  | j                        }| j                  |      j                  ||| j                  | j                        }	| j                  |      j                  ||| j                  | j                        }
| j                  |      }| j                  |	      }	| j                  |
      }
t        |||dd      }t        |	||dd      }	|j                  dd      }|	j                  dd      }	|
j                  dd      }
| j                  dkD  r:|	j                  | j                  d      }	|
j                  | j                  d      }
| j                  r>t!        j"                  ||	|
|| j$                  r| j&                  j(                  ndd      }nD||	j                  dd	      z  }|||z   }|j+                  d	      }| j'                  |      }||
z  }|j                  dd      j-                  ||d	      }| j/                  |      }| j1                  |      }|S )
NrR   )r`   r\   r   rS   r   rw   )r   	dropout_pscalerQ   )rU   r   r   r   ro   r   r   r   r   r   r   rl   r   r   repeat_interleaver   r   scaled_dot_product_attentiontrainingr   psoftmaxr   r   r   )r6   r@   r   r   r   r   r   r   qrj   vattns               r9   rE   zGemma4Attention.forward  s    ''1aKKN1dnndmmDKKN1d&7&7GKKN1d&7&7G KKNKKNKKN (8XAUVW'8XAUVW KK1KK1KK1 !##D$6$6A#>A##D$6$6A#>A??..#.2mm$..**A q{{2r**D$i'<<B<'D>>$'DqAKK1%%aB/KKNNN1r:   )	   @   Nr   r   ư>FNNrB   )rG   rH   rI   rJ   r3   jitFinalrL   __annotations__rK   r   r>   r.   rM   rE   rN   rO   s   @r9   r   r   \  s     		%%
  *."""(- / /  / 	 /
 #3- /  /  /  / "& / 
 /N 155||5 ll5 ll	5
  -5 
5r:   r   c                        e Zd ZdZ	 	 	 	 	 ddededee   dededdf fd	Z	d
e
j                  de
j                  fdZ xZS )Gemma4GatedMlpzGated MLP for Gemma4 Vision Encoder.

    Uses GELUTanh activation: output = down_proj(gelu_tanh(gate_proj(x)) * up_proj(x))
    Nr   hidden_features	act_layerdropr   r"   c                     ||d}t         	|           t        ||fd|i|| _        t        ||fd|i|| _        t        ||fd|i|| _        | |       nt        j                  d      | _        t        j                  |      | _
        y )Nr$   r!   tanhapproximate)r-   r.   r   	gate_projup_proj	down_projr/   GELUactr   r  )
r6   r   r  r  r  r   r%   r&   r7   r8   s
            r9   r.   zGemma4GatedMlp.__init__  s     /.{OsYlsprs,[/qWjqnpq.sYlsprs"+"79;RWWQW=XJJt$	r:   r@   c           	          | j                  | j                  | j                  | j                  |            | j	                  |      z              S rB   )r  r  r  r  r  rD   s     r9   rE   zGemma4GatedMlp.forward  s:    yy1B(CdllSTo(UVWWr:   )Nr   FNN)rG   rH   rI   rJ   rK   r   r   r>   rL   r.   r3   rM   rE   rN   rO   s   @r9   r  r    s{     -1(-%% !%  )	%
 % "&% 
%$X X%,, Xr:   r  c                        e Zd ZdZ	 	 	 	 	 	 	 	 	 ddededededee   ded	ed
ededee   deddf fdZ		 dde
j                  de
j                  de
j                  dee
j                     de
j                  f
dZ xZS )Gemma4Blocka  Gemma4 Vision Encoder Block with 4-norm sandwich pattern.

    Unlike standard ViT (pre-norm with 2 norms), Gemma4 uses:
    - input_layernorm (norm1) + post_attention_layernorm (norm2)
    - pre_feedforward_layernorm (norm3) + post_feedforward_layernorm (norm4)
    NrT   r   ro   intermediate_sizer   r   r   r   	drop_pathr  r   r"   c                 ~   ||d}t         |           t        |fd|i|| _        t	        d||||||||d|| _        t        |fd|i|| _        t        |fd|i|| _        t        d|||
|d|| _	        t        |fd|i|| _
        |	dkD  rt        |	      | _        y t        j                         | _        y )Nr$   r   )rT   r   ro   r   r   r   r   r   )r   r  r  r   r   r,   )r-   r.   r   norm1r   r  norm2norm3r  mlpnorm4r   r/   Identityr  )r6   rT   r   ro   r  r   r   r   r   r  r  r   r%   r&   r7   r8   s                  r9   r.   zGemma4Block.__init__  s      /S5h5"5
# 

% 3

 

	 S5h5"5
S5h5"5
! 
- 3	

 
 S5h5"5
09C),R[[]r:   r@   r   r   r   c                 2   |}| j                  |      }| j                  ||||      }| j                  |      }|| j                  |      z   }|}| j	                  |      }| j                  |      }| j                  |      }|| j                  |      z   }|S )Nr   )r   r  r!  r  r"  r#  r$  )r6   r@   r   r   r   residuals         r9   rE   zGemma4Block.forward  s     JJqMIIa8yIAJJqMt~~a(( JJqMHHQKJJqMt~~a((r:   )	Nr  r   r   r   NFNNrB   )rG   rH   rI   rJ   rK   r   r>   r   rL   r.   r3   rM   rE   rN   rO   s   @r9   r  r    s
    +/"""",0(-(S(S (S 	(S
  #(S #3-(S (S (S (S (S  )(S "&(S 
(S^ 15|| ll ll	
  - 
r:   r  c            
       "    e Zd ZdZddedef fdZdej                  dej                  deej                  ej                  f   fdZ	dej                  dej                  d	ej                  deej                  ej                  f   fd
Z
 xZS )Gemma4VisionPooleru   Spatial pooling for Gemma4 vision encoder output.

    Pools patches by averaging within k×k grid cells based on position coordinates.
    Output is scaled by sqrt(hidden_size).
    hidden_sizepooling_kernel_sizec                 R    t         |           || _        |dz  | _        || _        y )Nr   )r-   r.   r+  root_hidden_sizer,  )r6   r+  r,  r8   s      r9   r.   zGemma4VisionPooler.__init__.  s+    & +S 0#6 r:   hidden_statesr   r"   c           	      n   |j                   d   }| j                  }||z  }||z  dk7  rt        d| d| d| d      ||z  }|j                  d      }|d   j	                  d	d
      d   dz   }t        j                  ||d      }	|	d   ||z  |	d   z  z   }	t        j                  |	j                         |      j                         |z  }
|
j                  dd      |j                         z  }t        j                  |
dk(  j                  d            }|j                  |j                        |fS )u@  2D spatial pooling on a ``k × k`` grid (k = ``self.pooling_kernel_size``).

        ``N`` patches are binned into ``k^2``-sized cells, so the pool requires
        ``N % k^2 == 0`` (caller ensures both grid dims divide by k upstream).
        ``position_ids`` follows the Gemma4-internal ``(x, y)`` convention.
        r   r   zCannot pool z tokens with k=z: N must be divisible by k^2=z.. Both grid dimensions must be divisible by k.r   .r   rQ   TrT   keepdimfloor)rounding_mode.r   rR   rS   )rU   r,  r   rC   maxr3   divr   r   longr>   r   logical_notr   r   r&   )r6   r/  r   r   rj   	k_squaredoutput_lengthr   max_xkernel_idxsweightsoutputmasks                r9   _avg_pool_by_positionsz)Gemma4VisionPooler._avg_pool_by_positions4  sY    "$$E	y=Aqc3PQZP[ \? @  Y(..1.5!&)--"d-CAFJii 11GL!&)UaZ;v;N,NN))K,,.>DDFR""1a(=+>+>+@@  'Q,!3!3!3!:;yy,,-t33r:   r   c                     |j                  |j                  d      d      }| j                  ||      \  }}|| j                  z  }||fS )u  Spatial pool with ``pooling_kernel_size × pooling_kernel_size`` cells.

        Args:
            hidden_states: (B, N, D) encoder output.
            position_ids: (B, N, 2) Gemma4-internal ``(x, y)`` coords.
            padding_positions: (B, N) True for padding tokens.

        Returns:
            pooled hidden states (B, N // k^2, D) and validity mask (B, N // k^2).
        rQ   r   )masked_fillr^   rB  r.  )r6   r/  r   r   pooler_masks        r9   rE   zGemma4VisionPooler.forwardS  sV    " &112C2M2Mb2QSVW%)%@%@P\%]"{%(=(==k))r:   )r   )rG   rH   rI   rJ   rK   r.   r3   rM   r
   rB  rE   rN   rO   s   @r9   r*  r*  '  s    7C 7c 74 <<4  ,,4 
u||U\\)	*	4>* <<*  ,,*  %||	*
 
u||U\\)	**r:   r*  c            -       &    e Zd ZdZ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d<deeeeef   f   dededededed	ed
edee   dede	de	dedede
de
de	de	de	dee   deddf, fdZej                  j                  d=dede
ddfd       Zej                  j                  dee   fd       Zej                  j                  deeef   fd       Zej                  j                  d>de
deeef   fd        Zej                  j                  d?d!e
ddfd"       Zej                  j                  d?d#e
ddfd$       Zd%ej2                  ddfd&Z	 	 d@d%ej2                  d'ej2                  d(ej2                  d)eeeej2                  gdf      d*ee   dej2                  fd+Z	 	 d@d%eej2                  eeej2                  f   f   d,eej2                     d-eej2                     dej2                  fd.Zd>d%ej2                  d/e
dej2                  fd0Z	 	 d@d%eej2                  eeej2                  f   f   d,eej2                     d-eej2                     dej2                  fd1Z	 	 	 	 	 	 	 	 dAd%eej2                  eeej2                  f   f   d,eej2                     d-eej2                     d2eeeee   f      d3e
d4e
d5ed6e
d7e
deeej2                     eej2                  eej2                     f   eeef   f   fd8Z 	 	 	 dBd2eeee   f   d9e
d:e
dee   fd;Z! xZ"S )Cr   u#  Gemma4 Vision Encoder.

    The pure encoder from Google's Gemma 4 multimodal model. Custom ViT with 2D
    RoPE, gated MLP, QKV normalization, and 4-norm sandwich blocks.

    When ``standardize=True`` (31B variant), ``std_bias/std_scale`` are applied
    after the soft-token pooler (original contract). Other pool modes don't apply it.
    Output shape depends on ``global_pool``:

    - ``'soft'`` (default): spatial ``k×k`` pooler + ``√D`` scale + optional
      standardization. Output ``(B, num_soft_tokens, embed_dim)``
    - ``'avg'``: masked mean over patch tokens; skips the pooler's ``√D`` scale
      and standardization. Output ``(B, embed_dim)``.
    - ``'none'`` / ``''``: no pool — returns raw patch tokens
      ``(B, N, embed_dim)``. Useful for building custom pool heads.
    Nimg_sizer   r   global_poolr   depthr   ro   r   r  r   rp   r   r,  standardizer   proj_drop_rateattn_drop_ratedrop_path_rater  weight_initr"   c                 X   ||d}t         |           |dv s
J d|       || _        |x| _        x| _        | _        d| _        d| _        d| _        d| _	        t        |      | _        || _        || _        |xs t        t        j                   d      }t#        d| j                  |||d	|| _        t'        d||d
|| _        t+        j,                  d||      D cg c]  }|j/                          }}t        j0                  t3        |      D cg c]  }t5        d||||	|
|||||   ||d| c}      | _        t9        ||      | _        |rM| j=                  dt+        j>                  |fi |       | j=                  dt+        j>                  |fi |       nd | _         d | _!        tE        | j                        }t3        |      D cg c]  }tG        ||d|        c}| _$        |dk(  rdn|| _%        |dk7  r| jM                  d       y y c c}w c c}w c c}w )Nr$   )softavgnone z>global_pool must be one of 'soft', 'avg', 'none' (or ''); got r   NLCFr  r  )r   r   r   r   )ro   rp   )rT   r   ro   r   r  r   r   r   r  r  r   )r+  r,  std_bias	std_scaleblocks.)num_chs	reductionmoduleskipresetneeds_resetr,   )'r-   r.   rH  num_featureshead_hidden_sizer   r   
output_fmtnum_prefix_tokensgrad_checkpointingr   r   r,  r   r   r/   r  r   patch_embedrn   
rotary_embr3   linspaceitem
ModuleListrc   r  blocksr*  poolerr2   r4   rU  rV  r7  r   feature_infoweight_init_modeinit_weights)r6   rG  r   r   rH  r   rI  r   ro   r   r  r   rp   r   r,  rJ  r   rK  rL  rM  r  rN  r%   r&   r7   r@   dprr   _redr8   s                                r9   r.   zGemma4VitEncoder.__init__|  so   4 /99 	]L[O\	]9&ENNND1DN  !""' $J/#6 #6 Ef!E	 , 
$;	

 
 2 
!
 
 "'>5!IJAqvvxJJmm 5\%
   #!)"3!((a&#$7 %
 & )! 3
   U[[-Ib-IJ  ekk).Jr.JK DM!DN
 4??#dijodpq_`T)tgVWUXMZq+6&+@k& %0 !W K%
L rs   #H!H"H'moder^  c                 2   |xs | j                   }|dv sJ | j                  )t        j                  j	                  | j                         | j
                  )t        j                  j                  | j
                         t        t        ||      |        y)a  Initialize model weights.

        Args:
            mode: Init mode. '' applies trunc-normal-TF Linear init; 'reset'
                only calls ``reset_parameters`` on each sub-module.
            needs_reset: If True, call ``reset_parameters`` on modules that
                have one (for post-``to_empty()`` reinit). Set to False during
                ``__init__`` since modules already self-initialize there.
        )rS  r\  Nr]  )	rl  rU  r/   initzeros_rV  ones_r   get_init_weights_gemma4_vitr6   rp  r^  s      r9   rm  zGemma4VitEncoder.init_weights  ss     ,t,,}$$$ ==$GGNN4==)>>%GGMM$..)/+NPTUr:   c                     dhS )Nz$patch_embed.position_embedding_tabler,   r?   s    r9   no_weight_decayz Gemma4VitEncoder.no_weight_decay  s    677r:   c                     | j                   S zHReturn the 2-tuple patch size. For NaFlex dataloader / transform wiring.)r   r?   s    r9   get_patch_sizezGemma4VitEncoder.get_patch_size  s     r:   coarsec                      t        dddg      S )Nz^patch_embed|^rotary_emb)z^blocks\.(\d+)N)z^pooler|^std_)i stemri  r   r6   r|  s     r9   group_matcherzGemma4VitEncoder.group_matcher  s    ,-/KL
 	
r:   enablec                     || _         y rB   )rc  r6   r  s     r9   set_grad_checkpointingz'Gemma4VitEncoder.set_grad_checkpointing  s
    "(r:   enabledc                 ^    | j                         D ]  }t        |t              s||_         y)a  Toggle the ``Gemma4ClippableLinear`` clamp ops.

        Gemma4's pretrained E4B checkpoint ships finite clamp buffers on every
        projection, which can saturate and stall gradient flow during classifier
        fine-tuning. Setting ``enabled=False`` skips both the input and output
        clamps in the forward pass (buffers are left untouched so the call is
        reversible and checkpoint-safe).
        N)modulesr   r   r!   )r6   r  mods      r9   set_clamp_enabledz"Gemma4VitEncoder.set_clamp_enabled  s+     <<> 	*C#45")	*r:   r@   c                    |j                   dk7  s| j                  dk7  ry|j                  dd \  }}| j                  \  }}| j                  }||z  ||z  }}||z  dk7  s||z  dk7  rt        d| d| d| d| d	| d| d
      y)zWhen using the soft-token pooler, raw-image H/W must divide
        by ``patch_size * pooling_kernel_size`` so the pool cell grid is integral.
        Pre-patchified / NaFlex inputs are assumed to be conformant already.
        r   rP  Nr   r   zImage size (z, z=) must be divisible by (patch_size * pooling_kernel_size) = (z3) when global_pool='soft'. Resize to multiples of (z#), or use global_pool='avg'/'none'.)r`   rH  rU   r   r,  r   )	r6   r@   r   r   r   r   rj   cell_hcell_ws	            r9   _assert_raw_img_conformantz+Gemma4VitEncoder._assert_raw_img_conformant$  s    
 66Q;$**f4wwrs|1B$$aav:?a&jAoqcA3 '99?6( K++1("VH<_a  .r:   r   r   block_callbackmax_block_indexc                 .   |j                   dd \  }}| j                  ||      \  }}	d}
|j                         rUt        j                  |dd||j
                  |j                        }
|
j                  |ddddddf   t        d             || j                  }n| j                  d|dz    }t        |      D ]W  \  }}| j                  r.t        j                  j                         st        ||||	|
      }n ||||	|
      }|O |||       Y |S )z?RoPE + transformer-block pipeline over already-embedded tokens.NrR   r   r$   z-infr'  )rU   re  r   r3   zerosr%   r&   masked_fill_r>   ri  	enumeraterc  r	  is_scriptingr   )r6   r@   r   r   r  r  r   r   r   r   r   ri  r   blks                 r9   _encodezGemma4VitEncoder._encode6  s    wwr{1!__Q=(,0	  "Aq!QqxxqwwOI""#4QdA5E#FfV"[[F[[!5/A"56F' 	%FAs&&uyy/E/E/GsAx9E8XC)q!$	% r:   r   r   c                     | j                  t        |t              s|n|d          | j                  |||      \  }}}| j	                  |||      S )z9Raw patch tokens pre-pool. Returns ``(B, N, embed_dim)``.r   )r  r   r   rd  r  )r6   r@   r   r   r   r   s         r9   forward_featuresz!Gemma4VitEncoder.forward_featuresW  sQ     	''At1D!I,W-1-=-=ak-Z*<*||A|->??r:   
pre_logitsc                     t        d      )Nz;Gemma4VitEncoder does not support classification use cases.)NotImplementedError)r6   r@   r  s      r9   forward_headzGemma4VitEncoder.forward_headb  s    !"_``r:   c                 Z   | j                  t        |t              s|n|d          | j                  |||      \  }}}| j	                  |||      }| j
                  dk(  r@| j                  |||      \  }}| j                  || j                  z
  | j                  z  }|S | j
                  dk(  r||j                         rZ|j                  |j                  d      d      }|j                  d      | j                  dd	      j                  d
      z  }|S |j                  d      }|S )u  Encode + apply the configured pool.

        Output shape depends on ``self.global_pool``:
          ``'soft'`` → ``(B, num_soft_tokens, D)``
          ``'avg'``  → ``(B, D)``
          ``'none'`` → ``(B, N, D)`` (raw patch tokens, identical to forward_features)
        r   rP  rQ  rQ   r   r   rS   Tr2  r   )r  r   r   rd  r  rH  rj  rU  rV  r   rD  r^   r   rC   mean)r6   r@   r   r   r   r   r   s          r9   rE   zGemma4VitEncoder.forwarde  s+    	''At1D!I,W-1-=-=ak-Z*<*LLL*;<v%;;q,0ABDAq}}(&$..8  & $$&MM"3"="=b"A3GEEaEL%6$6#;#;4#;#P#V#V[\#V#]]
  FFqFM r:   indicesnorm
stop_earlyra  intermediates_onlyoutput_dictc
           	      j   |dv sJ |dk(  }
t        t        | j                        |      \  }t        |t              s|n|d   }|j
                  }| j                  |       | j                  |||      \  }}}g dt        dt        j                  ddffd}d}|r t        j                  j                         s|}| j                  |||||	      }|
r|d
k7  rt        d      |j                  d   }t        |d   j!                         j#                               dz   }t        |d   j!                         j#                               dz   }D cg c]6  }|j%                  |||d      j'                  dddd      j)                         8 c}|	rdi}|s||d<   | |d<   |S |rS |fS c c}w )a  Forward features returning intermediates.

        Args:
            x: Input tensor ``(B, C, H, W)`` or NaFlex pre-patchified tensor/dict.
            patch_coord: ``(B, N, 2)`` patch coords in NaFlex external (y, x) convention.
            patch_valid: ``(B, N)`` boolean mask, True for valid tokens.
            indices: Block indices to return intermediates for.
            norm: Not used (no final norm in Gemma4 encoder).
            stop_early: Stop iterating after last needed intermediate.
            output_fmt: Output format ('NCHW' or 'NLC'). NCHW requires a fixed full grid.
            intermediates_only: Only return intermediate features.
            output_dict: Return a dict matching the NaFlexVit intermediates contract:
                'image_intermediates' (+ 'image_features' unless ``intermediates_only``) and
                'patch_valid' aligned with the token sequence (all-True for dense image input;
                gemma4 has no patch dropout, so it always equals the input validity).
        )NCHWrT  r  r   r   yr"   Nc                 2    | v rj                  |       y y rB   )r   )r   r  intermediatestake_indicess     r9   _cbz3Gemma4VitEncoder.forward_intermediates.<locals>._cb  s    L $$Q' !r:   )r  r  r   z:output_fmt='NCHW' requires a raw image (B, C, H, W) input.r   r1  r   r6  rQ   r   rR   image_intermediatesimage_featuresr   )r   lenri  r   r   r`   r  rd  rK   r3   rM   r	  r  r  r   rU   r7  rg  r   r   
contiguous)r6   r@   r   r   r  r  r  ra  r  r  r   	max_indexrawraw_input_ndimr   r   r  r  r   r   r   r  result_dictr  r  s                          @@r9   forward_intermediatesz&Gemma4VitEncoder.forward_intermediates  s   8 _,,,&"6s4;;7G"Qi!!T*a)'',-1-=-=ak-Z*<*,.	(3 	(5<< 	(D 	( eii446'OLL+  
 " !]^^""1%A\&)--/4467!;B\&)--/4467!;B`mn[\QYYq"b"5==aAqITTVnM+@-*PK%01,-*;);K&  - os   ;F0
prune_norm
prune_headc                 x    t        t        | j                        |      \  }}| j                  d|dz    | _        |S )a  Prune layers not required for specified intermediates.

        ``prune_head`` is accepted for API compatibility; the encoder has no
        classifier head so it's a no-op here. (The wrapping ``Gemma4VitClassifier``
        handles its own head pruning.)
        Nr   )r   r  ri  )r6   r  r  r  r  r  s         r9   prune_intermediate_layersz*Gemma4VitEncoder.prune_intermediate_layers  s:     #7s4;;7G"Qikk.9q=1r:   )r   r   r   rP  r   r   r  r  N   r  r   r   r   FFr   r   r   NrS  NNrS  TFTr   )NNNFFr  FFr   FT)#rG   rH   rI   rJ   r   rK   r
   r   r   r>   rL   r   r.   r3   r	  ignorerm  r	   rx  r{  r   r   r  r  r  rM   r  r  r  r  rE   r   r  r  rN   rO   s   @r9   r   r   j  sI   & 58 % *.%)" %+0'( %(-$'$'$',0!1m1CsCx01m1 m1 	m1
 m1 m1 m1 m1 m1 #3-m1  #m1 m1 m1 &)m1 "%m1  !m1" "&#m1$ "%m1& "'m1( ")m1*  )+m1, -m12 
3m1^ YYV V V V V, YY8S 8 8 YYc3h   YY
D 
T#s(^ 
 
 YY)T )T ) ) YY* * * *ELL T . MQ-1||  ,,  %||	
 %XsELL.A4.G%HI &c] 
H 3726		@U\\4U\\(9#::;	@ "%,,/	@ "%,,/		@
 
	@aell a a a 3726	 U\\4U\\(9#::;  "%,,/  "%,,/	 
 
 J 37267;$$', %J U\\4U\\(9#::;J  "%,,/J  "%,,/	J 
 eCcN34J  J  J  J  !%J  J  
tELL!5tELL7I)I#JDQTVYQYNZ	[J \ ./$#	3S	>*  	
 
cr:   c            5           e Zd ZdZ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d;deeeeef   f   dededededed	ed
edededee   dede	de	dedede
de
de
de	de	de	de	dee   deddf4 fdZej                  j                  d<dede
ddfd        Zej                  j                  dee   fd!       Zej                  j                  d=d"e
deeef   fd#       Zej                  j                  d>d$e
ddfd%       Zej                  j                  d>d&e
ddfd'       Zej                  j                  deeef   fd(       Zej                  j                  dej4                  fd)       Zd?dedee   ddfd*Z	 	 d@d+eej:                  eeej:                  f   f   d,eej:                     d-eej:                     dej:                  fd.Z	 	 dAd+ej:                  d-eej:                     d/e
dej:                  fd0Z	 	 d@d+eej:                  eeej:                  f   f   d,eej:                     d-eej:                     dej:                  fd1Z 	 	 	 	 	 	 	 dBd+eej:                  eeej:                  f   f   d,eej:                     d-eej:                     d2eeee!e   f      d3e
d4e
d5ed6e
dee!ej:                     eej:                  e!ej:                     f   f   fd7Z"	 	 	 dCd2eee!e   f   d8e
d9e
de!e   fd:Z# xZ$S )Dr   u  Classification wrapper around ``Gemma4VitEncoder``.

    Holds:
        - ``encoder``: a ``Gemma4VitEncoder``. By default constructed with
          ``global_pool=''`` so the classifier does its own masked-mean pool
          over raw patch tokens in ``forward_head``. Pass
          ``encoder_pool='soft'`` to turn on the native VLM spatial ``k×k``
          soft-token pool inside the encoder; ``forward_features`` then
          returns ``(B, num_soft_tokens, D)`` already pooled (plus the ``√D``
          scale and, for the 31B variant, ``std_bias/std_scale``).
        - ``norm``: optional ``RmsNorm`` after pooling.
        - ``head``: linear classifier.

    Input/output contract matches timm convention: ``forward_features`` returns
    pre-head features (pre-pool ``(B, N, D)`` patch tokens by default, or
    ``(B, num_soft_tokens, D)`` post-soft-pool when ``encoder_pool='soft'``);
    ``forward_head`` does classifier pool + norm + head; ``forward`` =
    ``forward_features`` + ``forward_head``.
    NrG  r   r   r   rH  encoder_poolr   rI  r   ro   r   r  r   rp   r   r,  rJ  r   
final_norm	drop_raterK  rL  rM  r  rN  r"   c                 (   ||d}t         |           |dv sJ d|d       |dv sJ d|d       || _        || _        || _        t        d!i d|d	|d
|d|d|d|d|	d|
d|d|d|d|d|d|d|d|d|d|d|d|d||| _        |rt        |f|dd|nt        j                         | _
        t        j                  |      | _        |dkD  rt        j                  ||fi |nt        j                         | _        | j                  j                  x| _        | _        | j                  j"                  | _        | j                  j$                  | _        | j                  j&                  | _        | j                  j(                  | _        |d k7  rpt+        | j                  t        j                        rK| j                  j,                  4t        j.                  j1                  | j                  j,                         y y y y )"Nr$   rQ  rR  rS  BGemma4VitClassifier global_pool must be 'avg', 'none', or '' (got z>); use Gemma4VitEncoder directly for 'soft' VLM-style pooling.)rS  rR  rP  zDGemma4VitClassifier encoder_pool must be '', 'none', or 'soft' (got z).rG  r   r   rH  r   rI  r   ro   r   r  r   rp   r   r,  rJ  r   rK  rL  rM  r  rN  Fr   r   r[  r,   )r-   r.   r   rH  r  r   encoderr   r/   r%  r  r   	head_dropr0   headr_  r`  r   r   rk  rl  r   r'   rr  rs  )r6   rG  r   r   r   rH  r  r   rI  r   ro   r   r  r   rp   r   r,  rJ  r   r  r  rK  rL  rM  r  rN  r%   r&   r7   r8   s                                r9   r.   zGemma4VitClassifier.__init__  sz   < /11 	KPQ\P_ `J K	K1 33 	fRS_Rbbde	f3&&( ( 

!
 
 %	

  
 
  
 
 &
 0
 
 "
 %<
 !4
 $
  !4!
" *#
$ *%
& *'
(  )
* $-
0 MWGIH8EHRH\^\g\g\i	I.?JQBIIi;;TVT_T_Ta	 59LL4M4MMD1//,,11 LL55 $ = =& $))RYY/DIINN4Ntyy~~. 5O/ !r:   rp  r^  c                    | j                   j                  ||       t        | j                  t        j
                        rK| j                  j                  4t        j                  j                  | j                  j                         yyy)z>Init encoder + classifier-specific pieces (head bias to zero).rp  r^  N)	r  rm  r   r  r/   r0   r'   rr  rs  rv  s      r9   rm  z Gemma4VitClassifier.init_weightsL  s[     	!!t!Edii+		0JGGNN499>>* 1K+r:   c                 b    | j                   j                         D ch c]  }d| 	 c}S c c}w )Nencoder.)r  rx  )r6   rj   s     r9   rx  z#Gemma4VitClassifier.no_weight_decayS  s)    (,(D(D(FG1(1#GGGs   ,r|  c                     t        ddg      S )Nz*^encoder\.patch_embed|^encoder\.rotary_emb)z^encoder\.blocks\.(\d+)Nr~  r  r  s     r9   r  z!Gemma4VitClassifier.group_matcherW  s     >67
 	
r:   r  c                 :    | j                   j                  |       y rB   )r  r  r  s     r9   r  z*Gemma4VitClassifier.set_grad_checkpointing_  s    ++F3r:   r  c                 :    | j                   j                  |       y rB   )r  r  )r6   r  s     r9   r  z%Gemma4VitClassifier.set_clamp_enabledc  s    &&w/r:   c                 6    | j                   j                         S rz  )r  r{  r?   s    r9   r{  z"Gemma4VitClassifier.get_patch_sizeg  s     ||**,,r:   c                     | j                   S rB   )r  r?   s    r9   get_classifierz"Gemma4VitClassifier.get_classifierl  s    yyr:   c                    || _         ||dv sJ d|d       || _        |dkD  r t        j                  | j                  |      nt        j
                         | _        t        | j                  t        j                        rK| j                  j                  4t        j                  j                  | j                  j                         y y y )Nr  r  )r   )r   rH  r/   r0   r   r%  r  r   r'   rr  rs  )r6   r   rH  s      r9   reset_classifierz$Gemma4VitClassifier.reset_classifierp  s    &""55 fTU`Tccdef5*D>IAoBIIdnnk:SUS^S^S`	dii+		0JGGNN499>>* 1K+r:   r@   r   r   c                     | j                   dk(  r| j                  |||      S | j                  j                  |||      S )u]  Pre-head features.

        Shape depends on ``encoder_pool``:
          ``''`` / ``'none'``: raw patch tokens ``(B, N, embed_dim)``.
          ``'soft'``: spatial ``k×k`` soft-token pool output
              ``(B, num_soft_tokens, embed_dim)`` (with ``√D`` scale + optional
              ``std_bias/std_scale`` baked in by the encoder).
        rP  r   r   )r  r  r  )r6   r@   r   r   s       r9   r  z$Gemma4VitClassifier.forward_featuresz  sD     &<<{<TT||,,QKU`,aar:   r  c                    | j                   dk(  r|| j                  dk(  s||j                  d      }nX|j                  | j	                  d      d      }|j                  d      |j                  dd      j                  d	      z  }| j                  |      }| j                  |      }|r|S | j                  |      S )
u  Pool (if configured) → norm → head_drop → head.

        Args:
            x: pre-head features from ``forward_features``.
            patch_valid: ``(B, N)`` valid mask for masked mean over raw patch
                tokens. Ignored when ``encoder_pool='soft'`` (the soft pooler
                has already collapsed padding tokens, and the new token count
                no longer aligns with ``patch_valid``).
            pre_logits: If True, return pre-classifier features.
        rQ  rP  r   rS   rQ   r   Tr2  r   )
rH  r  r  rD  r^   r   rC   r  r  r  )r6   r@   r   r  s       r9   r  z Gemma4VitClassifier.forward_head  s      u$  F*k.AFFqFMMMK<":":2">DEEaEL;??q$?#G#M#MRS#M#TTIIaLNN1q0DIIaL0r:   c                    t        |t              r)|j                  d|      }|j                  d|      }|d   }|*|(|dk(  j                  d      }|j	                         r| }| j                  |||      }| j                  ||      S )Nr   r   r   rQ   rS   r  )r   )r   r   r   r   r   r  r  )r6   r@   r   r   r   featss         r9   rE   zGemma4VitClassifier.forward  s     a%%{;K%%{;K)A;#:#r)..2.6H||~'i%%a[k%Z  K @@r:   r  r  r  ra  r  c	           
      H    | j                   j                  ||||||||      S )N)r   r   r  r  r  ra  r  )r  r  )	r6   r@   r   r   r  r  r  ra  r  s	            r9   r  z)Gemma4VitClassifier.forward_intermediates  s8     ||11##!!1 2 	
 		
r:   r  r  c                 h    | j                   j                  ||d      }|r| j                  d       |S )NF)r  r  r   )r  r  r  )r6   r  r  r  r  s        r9   r  z-Gemma4VitClassifier.prune_intermediate_layers  s8     ||==gR\in=o!!!$r:   )r   r   r   i  rQ  rS  r   r   r  r  Nr  r  r   r   r   FFTr   r   r   r   NrS  NNr  r  r  rB   r   )NF)NNNFFr  Fr  )%rG   rH   rI   rJ   r   rK   r
   r   r   r>   rL   r   r.   r3   r	  r  rm  r	   rx  r   r   r  r  r  r{  r/   Moduler  r  rM   r  r  rE   r   r  r  rN   rO   s   @r9   r   r     s6   , 58 #$ " *.%)" %+0'( %(-#"$'$'$',0!9Q/CsCx01Q/ Q/ 	Q/
 Q/ Q/ Q/ Q/ Q/ Q/ Q/ #3-Q/  #Q/ Q/ Q/  &)!Q/" "%#Q/$ %Q/& "&'Q/( )Q/* +Q/, "-Q/. "/Q/0 "1Q/2  )3Q/4 5Q/: 
;Q/f YY+ + + + + YYHS H H YY
D 
T#s(^ 
 
 YY4T 4T 4 4 YY0 0 0 0 YY-c3h - - YY		  +C +hsm +W[ + 3726	bU\\4U\\(9#::;b "%,,/b "%,,/	b
 
b* 37$	1||1 "%,,/1 	1
 
1< 3726	AU\\4U\\(9#::;A "%,,/A "%,,/	A
 
A8 37267;$$',
U\\4U\\(9#::;
 "%,,/
 "%,,/	

 eCcN34
 
 
 
 !%
 
tELL!5tELL7I)I#JJ	K
0 ./$#		3S	>*	 	 		
 
c	r:   TrZ  namer^  c                 N   t        | t        j                        rNt        | j                  d       | j
                  *t        j                  j                  | j
                         yyt        | d      r| j                          y|rt        | d      r| j                          yyy)a  Per-module init for Gemma4Vit (trunc-normal-TF for Linear weights).

    Args:
        module: Module to initialize.
        name: Dotted module name (from ``named_apply``).
        needs_reset: If True, call ``reset_parameters`` on modules that define one.
    r   r   Nrm  r5   )r   r/   r0   r   r   r'   rr  rs  hasattrrm  r5   )rZ  r  r^  s      r9   init_weights_gemma4_vitr    sy     &"))$D1;;"GGNN6;;' #		(	);<! =r:   rp  c                 $    t        t        |      S )Nr]  )r   r  r  s     r9   ru  ru    s    *DDr:   
state_dictmodelc                    i }d}| j                         D ]  \  }}d}|D ]  }|j                  |      s|} n ||j                  d      r|||<   =|t        |      d }d|v rP|j                  dd      }|j                  dd      }|j                  d	d
      }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }|||<    |S )u  Convert HuggingFace Gemma4 vision encoder weights → ``Gemma4VitEncoder`` keys.

    Pure key remapping — no value transforms. The encoder consumes patches in
    HF's native C-P-P flat layout (via ``batch_patchify(channels_last=False)``
    in ``Gemma4PatchEmbed``), so ``input_proj.weight`` passes through unchanged.
    ``Gemma4ClippableLinear`` preserves HF's ``.linear.weight`` + clamp-buffer
    structure, so those pass through too.
    )zmodel.vision_tower.zmodel.vision_model.zvision_model.zvision_tower.N)patch_embed.rW  std_zpooler.zrotary_emb.re  zpatch_embedder.r  zencoder.layers.rW  z.input_layernorm.z.norm1.z.post_attention_layernorm.z.norm2.z.pre_feedforward_layernorm.z.norm3.z.post_feedforward_layernorm.z.norm4.z.self_attn.z.attn.)items
startswithr  replace)	r  r  out_dicthf_prefixesrj   r  matched_prefixprefixnew_ks	            r9   checkpoint_filter_fn_encoderr    s    HbK  " 1! 	F||F#!'	
 !||YZ#n%&' 5 /@/;19=:IF;YG<iHmX67: Or:   c                    d}| j                         D ci c]*  \  }}|j                  |      s|j                  d      r||, }}}| j                         D ci c]  \  }}||vs|| }}}t        ||j                        }|j                         D ci c]  \  }}d| | }}}|j	                  |       |S c c}}w c c}}w c c}}w )uZ  Convert HF or timm-encoder state dict → ``Gemma4VitClassifier`` keys.

    Runs the encoder filter, then prefixes every encoder-owned key with
    ``encoder.``. Top-level keys that belong to the classifier (``norm.*``,
    ``head.*``) pass through unchanged — they're absent from HF checkpoints, so
    the model's own init values stand.
    )znorm.zhead.r  )r  r  r  r  update)	r  r  classifier_local_prefixesrj   r  classifier_local	to_filterencoder_dictprefixeds	            r9   checkpoint_filter_fn_classifierr  (  s     !3)3)9)9); `A<<(ABallS]F^ 1 ` `","2"2"4R$!QAQ8QARIR/	5==IL.:.@.@.BCda(1#!CHCOO$%O`R Ds   /B?C(CCFvariant
pretrainedc                 p    |j                  dd      }t        t        | |ft        t	        |d      dd|S )Nout_indicesr   getterr  feature_clsr   )pretrained_filter_fnfeature_cfgkwargs_filter)popr   r   r  r   r  r  kwargsr  s       r9   _create_gemma4_vit_encoderr  @  sI    **]A.K :[hG&  r:   c                 n    |j                  dd      }t        t        | |ft        t	        |d      d|S )Nr  r   r  r  )r  r  )r  r   r   r  r   r  s       r9   _create_gemma4_vit_classifierr	  M  sF    **]A.K =[hG  r:   urlc                 $    | dddd dddddd	d
d|S )Nr   )r   r   r   )r   `   r  rw   bicubicF)r   r   r   )rw   rw   rw   zpatch_embed.input_projr  )r
  r   
input_sizemin_input_size	pool_sizecrop_pctinterpolationfixed_input_sizer  r   
first_conv
classifierr,   )r
  r  s     r9   _cfgr  Z  s>    # &"!
  .'( ) r:   z"timm/gemma4_vit_167m.gemma4_e4b_itzencoder.patch_embed.input_projz
apache-2.0)	hf_hub_idr  licensez"timm/gemma4_vit_570m.gemma4_31b_itz&timm/gemma4_vit_167m_enc.gemma4_e4b_it)r  r  z&timm/gemma4_vit_570m_enc.gemma4_31b_it)zgemma4_vit_167m.gemma4_e4b_itzgemma4_vit_570m.gemma4_31b_itz!gemma4_vit_167m_enc.gemma4_e4b_itz!gemma4_vit_570m_enc.gemma4_31b_itr   r   r  r  r  )r   rI  r   ro   r  rJ  r   i     H   i  )r   rI  r   ro   r  rJ  c           	      R    t        t        d      }t        dd| it        |fi |S )zGemma4 ~167M (E2B/E4B  vision tower) classifier.

    Masked mean pool over patch tokens + norm + linear classifier. Output:
    ``(B, num_classes)``. For the native VLM encoder interface (soft-token
    output), use ``gemma4_vit_167m_enc``.
    Tr  r  )gemma4_vit_167m)r   
_167M_ARCHr	  r  r  
model_argss      r9   r  r    s0     jT2J(pzpUYZdUohnUoppr:   c           	      R    t        t        d      }t        dd| it        |fi |S )u  Gemma4 ~167M (E2B/E4B vision tower) — native VLM encoder.

    ``global_pool='soft'`` applies the spatial ``k×k`` soft-token pool + √D
    scale; output: ``(B, num_soft_tokens, embed_dim)``. Bit-perfect with HF
    ``Gemma4VisionModel`` on matching weights.
    rP  rH  r  )gemma4_vit_167m_enc)r   r  r  r  s      r9   r#  r#    0     jf5J%q
qVZ[eVpioVpqqr:   c           	      R    t        t        d      }t        dd| it        |fi |S )ag  Gemma4 ~570M (26B/31B vision tower) classifier.

    Masked mean pool over patch tokens + norm + linear classifier. Output:
    ``(B, num_classes)``. The classifier uses ``encoder.forward_features`` and
    does its own pool + norm; the encoder's ``std_bias/std_scale`` (which only
    applies in ``'soft'`` pool mode) is not used on the classifier path.
    Tr  r  )gemma4_vit_570m)r   
_570M_ARCHr	  r  s      r9   r&  r&    s0     jT2J(pzpUYZdUohnUoppr:   c           	      R    t        t        d      }t        dd| it        |fi |S )u  Gemma4 ~570M (26B/31B vision tower) — native VLM encoder.

    ``global_pool='soft'`` output ``(B, num_soft_tokens, embed_dim)`` with
    ``std_bias/std_scale`` standardization applied post-pool (HF-native
    ordering — bit-perfect with ``Gemma4VisionModel``).
    rP  r"  r  )gemma4_vit_570m_enc)r   r'  r  r  s      r9   r)  r)    r$  r:   )rR   )rR   rR   r  r  )rS  )IrJ   math	functoolsr   typingr   r   r   r   r   r	   r
   r   r3   torch.nnr/   torch.nn.functional
functionalr   	timm.datar   r   timm.layersr   r   r   r   r   _builderr   	_featuresr   _manipulater   r   	_registryr   r   	naflexvitr   __all__r  r   rM   rY   rK   r_   rl   rn   r   r   r  r  r*  r   r   r   rL   r  ru  r  r  r  r	  r  default_cfgsr   r  r'  r  r#  r&  r)  r,   r:   r9   <module>r9     s  	   I I I     A V V * + 0 < %4
5*BII *Z(5<< (ELL ( 		.<<	.\\	. \\	. 		.
 \\	.  &<<&\\& \\& 	&
 & \\&4Mbii M`O2ryy O2dcbii cLXRYY X8F")) FR@* @*Fwryy wt{")) {|"BII "S "D "\` "$Ec ET EX E
,ell*+,, 
#u||
,^ell*+$ 
#u||
0
 
 
Td 

3 
D 
Wj 
c T#s(^ 2 %%)63&
 &*63& *.:* *.:*#& 0 

 

 q q;N q q rD r?O r r 	q 	q;N 	q 	q rD r?O r rr:   