@@ -71,6 +71,35 @@ def _vit_config() -> ViTConfig:
7171 )
7272
7373
74+ def _bart_config () -> BartConfig :
75+ return BartConfig (
76+ vocab_size = 32 ,
77+ d_model = 16 ,
78+ encoder_layers = 1 ,
79+ decoder_layers = 1 ,
80+ encoder_attention_heads = 4 ,
81+ decoder_attention_heads = 4 ,
82+ encoder_ffn_dim = 32 ,
83+ decoder_ffn_dim = 32 ,
84+ max_position_embeddings = 16 ,
85+ )
86+
87+
88+ def _hubert_config () -> HubertConfig :
89+ return HubertConfig (
90+ vocab_size = 32 ,
91+ hidden_size = 16 ,
92+ num_hidden_layers = 1 ,
93+ num_attention_heads = 4 ,
94+ intermediate_size = 32 ,
95+ conv_dim = (8 ,),
96+ conv_stride = (2 ,),
97+ conv_kernel = (3 ,),
98+ num_conv_pos_embeddings = 4 ,
99+ num_conv_pos_embedding_groups = 2 ,
100+ )
101+
102+
74103ARCHITECTURE_CASES = (
75104 ArchitectureCase (
76105 "gpt2-joint-qkv" ,
@@ -163,17 +192,7 @@ def _vit_config() -> ViTConfig:
163192 ArchitectureCase (
164193 "bart-encoder-decoder" ,
165194 BartForConditionalGeneration ,
166- lambda : BartConfig (
167- vocab_size = 32 ,
168- d_model = 16 ,
169- encoder_layers = 1 ,
170- decoder_layers = 1 ,
171- encoder_attention_heads = 4 ,
172- decoder_attention_heads = 4 ,
173- encoder_ffn_dim = 32 ,
174- decoder_ffn_dim = 32 ,
175- max_position_embeddings = 16 ,
176- ),
195+ _bart_config ,
177196 "BartForConditionalGeneration" ,
178197 ),
179198 ArchitectureCase (
@@ -202,18 +221,7 @@ def _vit_config() -> ViTConfig:
202221 ArchitectureCase (
203222 "hubert-audio" ,
204223 HubertForCTC ,
205- lambda : HubertConfig (
206- vocab_size = 32 ,
207- hidden_size = 16 ,
208- num_hidden_layers = 1 ,
209- num_attention_heads = 4 ,
210- intermediate_size = 32 ,
211- conv_dim = (8 ,),
212- conv_stride = (2 ,),
213- conv_kernel = (3 ,),
214- num_conv_pos_embeddings = 4 ,
215- num_conv_pos_embedding_groups = 2 ,
216- ),
224+ _hubert_config ,
217225 "HubertForCTC" ,
218226 ),
219227 ArchitectureCase (
@@ -234,6 +242,8 @@ def _vit_config() -> ViTConfig:
234242 ),
235243)
236244
245+ ARCHITECTURE_CASE_BY_NAME = {case .name : case for case in ARCHITECTURE_CASES }
246+
237247
238248def _named_identities (named_values : Any ) -> dict [int , str ]:
239249 return {id (value ): name for name , value in named_values }
@@ -274,17 +284,7 @@ def test_parent_and_direct_traversal_have_identical_state(case: ArchitectureCase
274284
275285
276286def test_parent_dtype_conversion_updates_container_owned_state () -> None :
277- bart_config = BartConfig (
278- vocab_size = 32 ,
279- d_model = 16 ,
280- encoder_layers = 1 ,
281- decoder_layers = 1 ,
282- encoder_attention_heads = 4 ,
283- decoder_attention_heads = 4 ,
284- encoder_ffn_dim = 32 ,
285- decoder_ffn_dim = 32 ,
286- max_position_embeddings = 16 ,
287- )
287+ bart_config = _bart_config ()
288288 bridge = build_bridge_from_module (
289289 BartForConditionalGeneration (bart_config ),
290290 "BartForConditionalGeneration" ,
@@ -305,17 +305,7 @@ def test_parent_dtype_conversion_updates_container_owned_state() -> None:
305305
306306
307307def test_parent_assign_load_updates_container_owned_state () -> None :
308- bart_config = BartConfig (
309- vocab_size = 32 ,
310- d_model = 16 ,
311- encoder_layers = 1 ,
312- decoder_layers = 1 ,
313- encoder_attention_heads = 4 ,
314- decoder_attention_heads = 4 ,
315- encoder_ffn_dim = 32 ,
316- decoder_ffn_dim = 32 ,
317- max_position_embeddings = 16 ,
318- )
308+ bart_config = _bart_config ()
319309 bridge = build_bridge_from_module (
320310 BartForConditionalGeneration (bart_config ),
321311 "BartForConditionalGeneration" ,
@@ -336,3 +326,72 @@ def test_parent_assign_load_updates_container_owned_state() -> None:
336326 assert id (bridge .original_model .final_logits_bias ) in {
337327 id (buffer ) for buffer in parent .buffers ()
338328 }
329+
330+
331+ @pytest .mark .parametrize (
332+ ("case_name" , "container_path" , "state_name" , "state_key" ),
333+ (
334+ ("bart-encoder-decoder" , "" , "final_logits_bias" , "final_logits_bias" ),
335+ ("hubert-audio" , "hubert" , "masked_spec_embed" , "hubert.masked_spec_embed" ),
336+ ),
337+ )
338+ def test_direct_assign_load_stays_current_after_apply (
339+ case_name : str , container_path : str , state_name : str , state_key : str
340+ ) -> None :
341+ case = ARCHITECTURE_CASE_BY_NAME [case_name ]
342+ config = case .config_factory ()
343+ bridge = build_bridge_from_module (
344+ case .model_type (config ),
345+ case .architecture ,
346+ hf_config = config ,
347+ dtype = torch .float32 ,
348+ device = "cpu" ,
349+ model_name = f"tiny-{ case .name } -direct-assign" ,
350+ )
351+ original_container = (
352+ bridge .original_model .get_submodule (container_path )
353+ if container_path
354+ else bridge .original_model
355+ )
356+ owner_container = (
357+ bridge ._container_state_owners .get_submodule (container_path )
358+ if container_path
359+ else bridge ._container_state_owners
360+ )
361+ replacement = torch .full_like (getattr (original_container , state_name ), 7 )
362+
363+ bridge .load_state_dict ({state_key : replacement }, strict = False , assign = True )
364+
365+ assert getattr (owner_container , state_name ) is getattr (original_container , state_name )
366+ bridge .cpu ()
367+ assert torch .equal (getattr (original_container , state_name ), replacement )
368+
369+
370+ @pytest .mark .parametrize (
371+ ("case_name" , "key_fragment" , "expected_keys" ),
372+ (
373+ ("bert-nsp" , "pooler" , {"pooler.weight" , "pooler.bias" }),
374+ ("vit-bare-pooler" , "pooler" , {"pooler.weight" , "pooler.bias" }),
375+ (
376+ "ast-audio-classifier" ,
377+ "classifier" ,
378+ {"classifier_ln.weight" , "classifier_ln.bias" },
379+ ),
380+ ),
381+ )
382+ def test_task_head_state_dict_keys_are_not_reexpanded (
383+ case_name : str , key_fragment : str , expected_keys : set [str ]
384+ ) -> None :
385+ case = ARCHITECTURE_CASE_BY_NAME [case_name ]
386+ config = case .config_factory ()
387+ bridge = build_bridge_from_module (
388+ case .model_type (config ),
389+ case .architecture ,
390+ hf_config = config ,
391+ dtype = torch .float32 ,
392+ device = "cpu" ,
393+ model_name = f"tiny-{ case .name } -state-dict-keys" ,
394+ )
395+
396+ actual_keys = {key for key in bridge .state_dict () if key_fragment in key }
397+ assert actual_keys == expected_keys
0 commit comments