| |
| |
| |
| |
| |
| from __future__ import annotations |
| import torch |
| from typing import Callable, Dict, Optional |
| from safetensors.torch import load_file, save_file |
| from safetensors import safe_open |
|
|
|
|
| def _apply_metadata_ties_(model: torch.nn.Module, ckpt_path: str) -> None: |
| """ |
| Read safetensors metadata and copy tensors from source->target for tied weights. |
| Example metadata: |
| {'...embed_tokens.weight': '...lm_head.weight'} |
| """ |
| try: |
| with safe_open(ckpt_path, framework="pt", device="cpu") as f: |
| meta = f.metadata() or {} |
| if not meta: |
| return |
| sd = model.state_dict() |
| for tgt_key, src_key in meta.items(): |
| if tgt_key in sd and src_key in f.keys(): |
| src = f.get_tensor(src_key) |
| if sd[tgt_key].shape == src.shape: |
| with torch.no_grad(): |
| sd[tgt_key].copy_(src) |
| except Exception as e: |
| print(f"[compat] metadata ties skipped due to: {e}") |
|
|
|
|
| def load_model_compat( |
| model: torch.nn.Module, |
| weight_path: str, |
| rename_fn: Optional[Callable[[str], str]] = None, |
| extra_ties_fallback: Optional[Dict[str, str]] = None, |
| ): |
| """ |
| Shape-safe, metadata-aware loader. |
| |
| Steps: |
| 1) load_file -> (optional) key rename -> shape-equal filtering |
| 2) model.load_state_dict(..., strict=False) |
| 3) metadata-ties recovery (e.g., embed_tokens <- lm_head) |
| 4) fallback ties (explicit dict) if metadata not present |
| |
| Returns: IncompatibleKeys from torch.load_state_dict (for initial filtered load). |
| """ |
| raw = load_file(weight_path) |
| if rename_fn: |
| raw = {rename_fn(k): v for k, v in raw.items()} |
|
|
| sd = model.state_dict() |
| filtered = {k: v for k, v in raw.items() if k in sd and sd[k].shape == v.shape} |
| msg = model.load_state_dict(filtered, strict=False) |
|
|
| |
| _apply_metadata_ties_(model, weight_path) |
|
|
| |
| if extra_ties_fallback: |
| with safe_open(weight_path, framework="pt", device="cpu") as f: |
| for tgt_key, src_key in extra_ties_fallback.items(): |
| if tgt_key in sd and src_key in raw and sd[tgt_key].shape == raw[src_key].shape: |
| with torch.no_grad(): |
| sd[tgt_key].copy_(raw[src_key]) |
| print(f"[compat/fallback] {tgt_key} <- {src_key}") |
|
|
| |
| still_missing = [k for k in model.load_state_dict({}, strict=False).missing_keys] |
| if still_missing: |
| print(f"[compat] load done. remaining missing={len(still_missing)}") |
| for k in still_missing[:12]: |
| print(" missing:", k) |
| if len(still_missing) > 12: |
| print(f" ... (+{len(still_missing)-12} more)") |
| else: |
| print("[compat] load done. no missing keys.") |
| if msg.unexpected_keys: |
| print(f"[compat] unexpected={len(msg.unexpected_keys)} (ignored by strict=False)") |
| for k in msg.unexpected_keys[:12]: |
| print(" unexpected:", k) |
| if len(msg.unexpected_keys) > 12: |
| print(f" ... (+{len(msg.unexpected_keys)-12} more)") |
| return msg |
|
|
|
|
| def save_model_compat( |
| model: torch.nn.Module, |
| save_path: str, |
| ties: Optional[Dict[str, str]] = None, |
| write_full_state: bool = False, |
| ): |
| """ |
| Save with optional tied-weights metadata. |
| - write_full_state=True: write full state_dict (max compatibility, larger file; ignores `ties`) |
| - write_full_state=False & ties=None: write full state_dict, no metadata (default) |
| - write_full_state=False & ties=dict: remove tgt keys and write metadata mapping tgt->src (lighter file) |
| |
| Example ties: |
| { |
| "paligemma_with_expert.paligemma.model.language_model.embed_tokens.weight": |
| "paligemma_with_expert.paligemma.lm_head.weight" |
| } |
| """ |
| sd = model.state_dict() |
| if write_full_state: |
| save_file(sd, save_path, metadata=None) |
| print("[compat] saved full state (no metadata).") |
| return |
|
|
| meta = None |
| if ties: |
| sd = sd.copy() |
| for tgt, src in ties.items(): |
| if tgt in sd and src in sd: |
| |
| del sd[tgt] |
| meta = ties |
|
|
| save_file(sd, save_path, metadata=meta or None) |
| if meta: |
| print(f"[compat] saved with metadata ties: {len(meta)}") |
| else: |
| print("[compat] saved full state (no ties).") |
|
|