Skip to content

Commit 628ac1e

Browse files
committed
43≈Fix test
1 parent 7b1d88d commit 628ac1e

2 files changed

Lines changed: 46 additions & 17 deletions

File tree

bionemo-recipes/recipes/evo2_megatron/src/bionemo/evo2/models/evo2_lora.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,21 +157,39 @@ def _validate_tied_weight_config(self, model: ModelType) -> None:
157157
``output_layer`` share the same weight tensor. Both lists must treat the
158158
tied pair as a unit: list both layers or neither. Listing only one side
159159
raises ``ValueError``.
160+
161+
The check walks the actual model so that wildcard patterns (e.g.
162+
``"embedding.*"``) are evaluated against real module paths rather than
163+
synthetic names.
160164
"""
161165
if not self._get_is_tied(model):
162166
return
163167

164-
target_word_emb = self._matches_lora_target("word_embeddings", "word_embeddings")
165-
target_output = self._matches_lora_target("output_layer", "output_layer")
168+
targeted_short_names: set[str] = set()
169+
skip_frozen_short_names: set[str] = set()
170+
171+
def _collect(module: nn.Module, name: str | None = None, prefix: str | None = None) -> nn.Module:
172+
full_name = f"{prefix}.{name}" if prefix else (name or "")
173+
short_name = name or ""
174+
if self._matches_lora_target(short_name, full_name):
175+
targeted_short_names.add(short_name)
176+
if self._matches_skip_freeze(short_name, full_name):
177+
skip_frozen_short_names.add(short_name)
178+
return module
179+
180+
self._walk_model(model, _collect)
181+
182+
target_word_emb = "word_embeddings" in targeted_short_names
183+
target_output = "output_layer" in targeted_short_names
166184
if target_word_emb != target_output:
167185
raise ValueError(
168186
"share_embeddings_and_output_weights is enabled: target_modules must "
169187
"include both word_embeddings and output_layer, or neither. "
170188
f"word_embeddings matched: {target_word_emb}, output_layer matched: {target_output}."
171189
)
172190

173-
skip_word_emb = self._matches_skip_freeze("word_embeddings", "word_embeddings")
174-
skip_output = self._matches_skip_freeze("output_layer", "output_layer")
191+
skip_word_emb = "word_embeddings" in skip_frozen_short_names
192+
skip_output = "output_layer" in skip_frozen_short_names
175193
if skip_word_emb != skip_output:
176194
raise ValueError(
177195
"share_embeddings_and_output_weights is enabled: skip_freeze_modules must "

bionemo-recipes/recipes/evo2_megatron/tests/bionemo/evo2/models/test_evo2_lora_1.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,16 @@ class TestEvo2LoRAWeightTyingValidation:
253253

254254
@pytest.mark.parametrize(
255255
"target_modules",
256-
[["word_embeddings"], ["output_layer"]],
257-
ids=["word_embeddings_only", "output_layer_only"],
256+
[["word_embeddings"], ["output_layer"], ["embedding.*"], ["output_*"]],
257+
ids=["word_embeddings_only", "output_layer_only", "embedding_wildcard", "output_wildcard"],
258258
)
259259
def test_target_modules_one_side_raises_asymmetry_with_tying(self, wt_models, target_modules: list[str]) -> None:
260260
"""With weight tying, listing only one side of the tied pair raises our symmetry ValueError.
261261
262262
Evo2LoRA catches the asymmetry before handing off to Megatron Bridge.
263+
The wildcard cases verify the model-walk approach: ``embedding.*`` matches
264+
the real path ``embedding.word_embeddings`` and ``output_*`` matches
265+
``output_layer``; neither would be detected by a synthetic-name check.
263266
"""
264267
tied, _ = wt_models
265268
lora = Evo2LoRA(target_modules=target_modules, dim=4, alpha=8, dropout=0.0)
@@ -307,11 +310,16 @@ def test_target_modules_output_layer_accepted_without_tying(self, wt_models) ->
307310

308311
@pytest.mark.parametrize(
309312
"skip_freeze",
310-
[["word_embeddings"], ["output_layer"]],
311-
ids=["word_embeddings_only", "output_layer_only"],
313+
[["word_embeddings"], ["output_layer"], ["embedding.*"], ["output_*"]],
314+
ids=["word_embeddings_only", "output_layer_only", "embedding_wildcard", "output_wildcard"],
312315
)
313316
def test_skip_freeze_one_side_raises_with_tying(self, wt_models, skip_freeze: list[str]) -> None:
314-
"""Listing only one side of a tied pair in skip_freeze_modules must raise ValueError."""
317+
"""Listing only one side of a tied pair in skip_freeze_modules must raise ValueError.
318+
319+
The wildcard cases verify the model-walk approach: ``embedding.*`` matches
320+
the real path ``embedding.word_embeddings`` and ``output_*`` matches
321+
``output_layer``; neither would be detected by a synthetic-name check.
322+
"""
315323
tied, _ = wt_models
316324
lora = Evo2LoRA(
317325
target_modules=_DEFAULT_LORA_TARGETS,
@@ -517,19 +525,22 @@ def test_lora_checkpoint_excludes_frozen_embeddings(self, tmp_path: Path, base_c
517525
assert len(adapter_keys) > 0, "Checkpoint should still contain LoRA adapter keys."
518526

519527
@pytest.mark.parametrize(
520-
"skip_module, expected_key_substr, lora_targets",
528+
"skip_freeze, expected_key_substr, lora_targets",
521529
[
522-
("word_embeddings", "word_embeddings", None),
523-
("final_norm", "final_norm", None),
524-
("dense", "mixer.dense.", None),
525-
("linear_fc2", "mlp.linear_fc2.", ["dense_projection", "linear_qkv", "linear_proj", "linear_fc1"]),
530+
# word_embeddings and output_layer share a weight tensor when tying is enabled;
531+
# both must appear in skip_freeze to satisfy the symmetry contract.
532+
(["word_embeddings", "output_layer"], "word_embeddings", None),
533+
(["final_norm"], "final_norm", None),
534+
(["dense"], "mixer.dense.", None),
535+
(["linear_fc2"], "mlp.linear_fc2.", ["dense_projection", "linear_qkv", "linear_proj", "linear_fc1"]),
526536
],
537+
ids=["word_embeddings", "final_norm", "dense", "linear_fc2"],
527538
)
528539
def test_lora_skip_freeze_saves_and_trains_module(
529540
self,
530541
tmp_path: Path,
531542
base_ckpt: Path,
532-
skip_module: str,
543+
skip_freeze: list[str],
533544
expected_key_substr: str,
534545
lora_targets: list[str] | None,
535546
):
@@ -538,12 +549,12 @@ def test_lora_skip_freeze_saves_and_trains_module(
538549

539550
from bionemo.evo2.models.evo2_provider import hyena_forward_step
540551

541-
lora_dir = tmp_path / f"lora_{skip_module}"
552+
lora_dir = tmp_path / f"lora_{skip_freeze[0]}"
542553
cfg = _build_pretrain_config(
543554
lora_dir,
544555
train_iters=1,
545556
lora=True,
546-
skip_freeze=[skip_module],
557+
skip_freeze=skip_freeze,
547558
lora_target_modules=lora_targets,
548559
pretrained_ckpt_dir=str(base_ckpt),
549560
)

0 commit comments

Comments
 (0)