Spaces:
Sleeping
Sleeping
Download model_loading.py from madhurr382/code-search-demo: direct link, hf CLI and curl.
- Browser
- Download file 4.62 kB
-
https://huggingface.co/spaces/madhurr382/code-search-demo/resolve/main/model_loading.py
- Command line
-
hf download hf://spaces/madhurr382/code-search-demo/model_loading.py
-
curl -L -o model_loading.py https://huggingface.co/spaces/madhurr382/code-search-demo/resolve/main/model_loading.py
4.62 kB
| """ | |
| Load a sentence-transformers model in fp32 and repair what transformers v5 breaks. | |
| Shared by eval_baseline.py, submission.py, finetune.py, precompute_corpus.py and the | |
| Hugging Face Space. space/model_loading.py is a byte-for-byte copy of this file | |
| (tests/test_space_sync.py checks it), so keep it free of repo-internal imports. | |
| """ | |
| from __future__ import annotations | |
| import contextlib | |
| import logging | |
| from typing import Any | |
| import torch | |
| import transformers | |
| from sentence_transformers import SentenceTransformer | |
| logger = logging.getLogger("model_loading") | |
| def restore_nonpersistent_buffers(st_model: SentenceTransformer) -> tuple[int, int]: | |
| """Recompute non-persistent buffers that transformers v5 leaves uninitialised. | |
| v5 builds the model on the meta device, refills every non-persistent buffer | |
| with torch.empty_like, and relies on `_init_weights` to restore them. Remote-code | |
| models compute such buffers in __init__ (rotary inv_freq / cos / sin caches, | |
| position_ids, attention norm_factor), and their `_init_weights` never touches | |
| them, so they hold garbage after loading. NomicBert (CodeRankEmbed) then | |
| silently gets wrong RoPE frequencies, and Alibaba new-impl models fail with a | |
| CUDA index-out-of-bounds assert (Alibaba-NLP/new-impl discussion #14). | |
| Fix: build a throwaway copy from the config (real construction, weight init | |
| skipped) and copy its buffers over. Returns (restored, differed). | |
| """ | |
| from transformers import PreTrainedModel | |
| hf = next((m for m in st_model.modules() if isinstance(m, PreTrainedModel)), None) | |
| if hf is None or not hasattr(hf, "named_non_persistent_buffers"): # v4 never trashes them | |
| return 0, 0 | |
| loaded = dict(hf.named_non_persistent_buffers()) | |
| if not loaded: | |
| return 0, 0 | |
| try: | |
| from transformers.initialization import no_init_weights | |
| except ImportError: | |
| no_init_weights = contextlib.nullcontext | |
| with torch.device("cpu"), no_init_weights(): | |
| fresh = dict(type(hf)(hf.config).named_non_persistent_buffers()) | |
| restored = differed = 0 | |
| for name, buf in loaded.items(): | |
| new = fresh.get(name) | |
| if new is None or new.shape != buf.shape: | |
| logger.warning("Cannot restore buffer %s (missing or shape mismatch in fresh model)", name) | |
| continue | |
| new = new.to(device=buf.device, dtype=buf.dtype) | |
| differed += not torch.equal(new, buf) | |
| parent, _, attr = name.rpartition(".") | |
| hf.get_submodule(parent).register_buffer(attr, new, persistent=False) | |
| restored += 1 | |
| return restored, differed | |
| def _is_nomic_bert(model_name: str, trust_remote_code: bool) -> bool: | |
| try: | |
| cfg = transformers.AutoConfig.from_pretrained(model_name, trust_remote_code=trust_remote_code) | |
| except Exception as e: # let SentenceTransformer raise the real loading error | |
| logger.warning("Could not read config of %s: %s", model_name, e) | |
| return False | |
| return cfg.model_type == "nomic_bert" | |
| def load_st_model(model_name: str, device: str, trust_remote_code: bool = True) -> tuple[SentenceTransformer, dict[str, int]]: | |
| """Load in fp32 and repair non-persistent buffers. | |
| To pin a Hub commit, snapshot_download(repo, revision=...) and pass the local dir: | |
| NomicBert's remote from_pretrained fetches Hub weights without a revision. | |
| """ | |
| # fp32: some checkpoints are stored in fp16/bf16, and transformers v5 | |
| # would otherwise load them in that dtype (slow and lossy on CPU). | |
| model_kwargs: dict[str, Any] = {"torch_dtype": torch.float32} | |
| # NomicBert's remote from_pretrained loads Hub ids through | |
| # state_dict_from_pretrained(safe_serialization=kwargs.get("safe_serialization", False)), | |
| # which only looks for pytorch_model.bin(.index.json); our Hub repo (like | |
| # nomic-ai/CodeRankEmbed) has only model.safetensors. Local dirs take a separate | |
| # branch that ignores the flag. Other architectures may reject the kwarg, so gate it. | |
| if _is_nomic_bert(model_name, trust_remote_code): | |
| model_kwargs["safe_serialization"] = True | |
| model = SentenceTransformer( | |
| model_name, | |
| device=device, | |
| trust_remote_code=trust_remote_code, | |
| model_kwargs=model_kwargs, | |
| ) | |
| restored, differed = restore_nonpersistent_buffers(model) | |
| logger.info("Restored %d non-persistent buffers (%d had uninitialised values after load)", | |
| restored, differed) | |
| return model, {"restored": restored, "differed": differed} | |