Skip to content

Commit bb82e23

Browse files
committed
Record the expert LoRA layout in checkpoint metadata
1 parent 3780d98 commit bb82e23

5 files changed

Lines changed: 10 additions & 3 deletions

File tree

‎miles/tinker/core/input_validation.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,13 @@ def validate_checkpoint_compatibility(meta: dict, record: ModelRecord, config: G
130130
"base_model": record.base_model,
131131
"lora_rank": record.lora_rank,
132132
"lora_alpha": record.lora_alpha,
133+
"experts_shared_outer_loras": config.experts_shared_outer_loras,
133134
"train_attn": config.trains_attn,
134135
"train_mlp": config.trains_mlp,
135136
"train_unembed": config.trains_unembed,
136137
}
138+
# Checkpoints written before the layout was recorded are all per-expert.
139+
meta = {"experts_shared_outer_loras": False, **meta}
137140
for key, value in expected.items():
138141
if meta[key] != value:
139142
raise UserInputError(

‎miles/tinker/core/types.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class GatewayConfig:
5858
max_samples_per_request: int = 64
5959
max_lora_rank: int = 32 # the slot capacity the server was built with (--lora-rank)
6060
lora_alpha: float | None = None # None: 2 * rank
61+
experts_shared_outer_loras: bool = False
6162
# what the server-wide adapter layout trains; create_model rejects deviations
6263
trains_attn: bool = True
6364
trains_mlp: bool = True

‎miles/tinker/core/utils.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def build_checkpoint_metadata(record: ModelRecord, config: GatewayConfig) -> dic
3333
"base_model": record.base_model,
3434
"lora_rank": record.lora_rank,
3535
"lora_alpha": record.lora_alpha,
36+
"experts_shared_outer_loras": config.experts_shared_outer_loras,
3637
"train_attn": config.trains_attn,
3738
"train_mlp": config.trains_mlp,
3839
"train_unembed": config.trains_unembed,

‎serve_tinker.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ async def serve(args, *, disposer: Disposer):
7878
max_tokens_per_datum=max_tokens_per_datum,
7979
max_tokens_per_sample=max_tokens_per_sample,
8080
lora_alpha=args.lora_alpha,
81+
experts_shared_outer_loras=args.experts_shared_outer_loras,
8182
max_lora_rank=args.lora_rank,
8283
trains_attn="attn" in args.tinker_lora_groups,
8384
trains_mlp="mlp" in args.tinker_lora_groups,

‎tests/fast/tinker/core/test_service.py‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,8 @@ async def test_checkpoint_meta_stores_a_digest_not_the_credential(service):
676676
assert (info["train_attn"], info["train_mlp"], info["train_unembed"]) == (True, True, False)
677677

678678

679-
async def test_a_checkpoint_saved_under_other_settings_does_not_load(service):
679+
@pytest.mark.parametrize("field,value", [("lora_alpha", 99), ("experts_shared_outer_loras", True)])
680+
async def test_a_checkpoint_saved_under_other_settings_does_not_load(service, field, value):
680681
import json
681682
import os
682683

@@ -689,14 +690,14 @@ async def test_a_checkpoint_saved_under_other_settings_does_not_load(service):
689690
resolve_checkpoint_dir(service.config.checkpoint_root, model_id, "weights", "ck"), "META.json"
690691
)
691692
meta = json.loads(open(meta_path).read())
692-
meta["lora_alpha"] = meta["lora_alpha"] + 1 # the same tensors would be scaled differently
693+
meta[field] = value
693694
open(meta_path, "w").write(json.dumps(meta))
694695

695696
loaded = service.submit(
696697
"tenant", "load_state", {"model_id": model_id, "seq_id": 2, "path": path, "optimizer": True}
697698
)
698699
future = await await_settled(service, "tenant", loaded)
699-
assert (future.state, future.error_category) == (FAILED, "user") and "lora_alpha" in future.error
700+
assert (future.state, future.error_category) == (FAILED, "user") and field in future.error
700701
assert not service.backend.named("load_slot")[1:], "nothing may touch the slot on a mismatch"
701702

702703

0 commit comments

Comments
 (0)