sentence-transformers
Safetensors
English
nomic_bert
flash-attention
code-retrieval
nomic-bert
bf16
custom_code
Instructions to use handwoven8588/CodeRankEmbed-flash-attn with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- sentence-transformers
How to use handwoven8588/CodeRankEmbed-flash-attn with sentence-transformers:
from sentence_transformers import SentenceTransformer model = SentenceTransformer("handwoven8588/CodeRankEmbed-flash-attn", trust_remote_code=True) sentences = [ "The weather is lovely today.", "It's so sunny outside!", "He drove to the stadium." ] embeddings = model.encode(sentences) similarities = model.similarity(embeddings, embeddings) print(similarities.shape) # [3, 3] - Notebooks
- Google Colab
- Kaggle
v2: bf16 weights (547->274MB) + from_pretrained torch_dtype fix (loads bf16 natively) + corrected model tree (base_model=nomic-ai/CodeRankEmbed only) + bf16-derivative README
Browse files- README.md +54 -43
- config.json +2 -2
- model.safetensors +2 -2
- modeling_hf_nomic_bert.py +14 -0
README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
---
|
| 2 |
base_model:
|
| 3 |
- nomic-ai/CodeRankEmbed
|
| 4 |
-
- Snowflake/snowflake-arctic-embed-m-long
|
| 5 |
library_name: sentence-transformers
|
| 6 |
license: mit
|
| 7 |
tags:
|
|
@@ -9,36 +8,46 @@ tags:
|
|
| 9 |
- code-retrieval
|
| 10 |
- sentence-transformers
|
| 11 |
- nomic-bert
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
---
|
| 13 |
|
| 14 |
# CodeRankEmbed-flash-attn
|
| 15 |
|
| 16 |
-
A
|
| 17 |
-
with **flash-attention baked natively into
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
## Why
|
| 22 |
|
| 23 |
`nomic-ai/CodeRankEmbed` loads through `trust_remote_code`, and its attention path is **eager
|
| 24 |
-
only** — activation memory grows as `batch × heads × seq²`, which OOMs at large batches
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
- **CPU, or no `flash_attn`** → the original eager path, **byte-for-byte unchanged**, so the
|
| 37 |
-
model loads and encodes
|
| 38 |
-
|
| 39 |
-
`flash_attn` requires half precision; if the model is loaded as fp32 (sentence-transformers'
|
| 40 |
-
default — it drops `config.torch_dtype`), the flash branch casts the attention tensors to bf16
|
| 41 |
-
internally and casts the result back, so **no external dtype cast is required**.
|
| 42 |
|
| 43 |
## Usage
|
| 44 |
|
|
@@ -56,39 +65,41 @@ q = model.encode(queries, normalize_embeddings=True)
|
|
| 56 |
d = model.encode(codes, normalize_embeddings=True)
|
| 57 |
```
|
| 58 |
|
| 59 |
-
## Parity
|
| 60 |
|
| 61 |
-
Same weights
|
| 62 |
-
2.8.3, CLS pooling, L2-normalized
|
| 63 |
|
| 64 |
-
|
|
| 65 |
| --- | --- | --- |
|
| 66 |
-
|
|
| 67 |
-
|
|
|
|
|
| 68 |
|
| 69 |
-
The
|
| 70 |
-
|
| 71 |
-
|
| 72 |
|
| 73 |
## What changed vs the source repo
|
| 74 |
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
|
|
|
| 85 |
|
| 86 |
## License & attribution
|
| 87 |
|
| 88 |
MIT — same license as `nomic-ai/CodeRankEmbed` (see `NOTICE`). The weights, tokenizer, and the
|
| 89 |
bulk of the modeling file are a verbatim derivative of `nomic-ai/CodeRankEmbed`; the modeling file
|
| 90 |
-
|
| 91 |
-
|
| 92 |
|
| 93 |
```bibtex
|
| 94 |
@misc{suresh2025cornstackhighqualitycontrastivedata,
|
|
|
|
| 1 |
---
|
| 2 |
base_model:
|
| 3 |
- nomic-ai/CodeRankEmbed
|
|
|
|
| 4 |
library_name: sentence-transformers
|
| 5 |
license: mit
|
| 6 |
tags:
|
|
|
|
| 8 |
- code-retrieval
|
| 9 |
- sentence-transformers
|
| 10 |
- nomic-bert
|
| 11 |
+
- bf16
|
| 12 |
+
language:
|
| 13 |
+
- en
|
| 14 |
+
pipeline_tag: feature-extraction
|
| 15 |
---
|
| 16 |
|
| 17 |
# CodeRankEmbed-flash-attn
|
| 18 |
|
| 19 |
+
A **bf16 derivative of [`nomic-ai/CodeRankEmbed`](https://huggingface.co/nomic-ai/CodeRankEmbed)**
|
| 20 |
+
with **flash-attention baked natively into a modeling file we own.** Not a finetune —
|
| 21 |
+
the weights are the original CodeRankEmbed weights cast to bf16 (no further training), and the
|
| 22 |
+
`modeling_hf_nomic_bert.py` here is a derivative that runs attention via `flash_attn` varlen
|
| 23 |
+
instead of the original eager `O(seq²)` path.
|
| 24 |
+
|
| 25 |
+
> **About the model tree:** this repo is a derivative of `nomic-ai/CodeRankEmbed` (same weights,
|
| 26 |
+
> bf16-cast + owned flash-attn code), **not** a finetune of `Snowflake/snowflake-arctic-embed-m-long`.
|
| 27 |
+
> The Snowflake model is CodeRankEmbed's *grandparent* (nomic-ai initialized from it); we derive
|
| 28 |
+
> directly from nomic-ai/CodeRankEmbed, which is also where the fp32 reference weights live.
|
| 29 |
|
| 30 |
## Why
|
| 31 |
|
| 32 |
`nomic-ai/CodeRankEmbed` loads through `trust_remote_code`, and its attention path is **eager
|
| 33 |
+
only** — activation memory grows as `batch × heads × seq²`, which OOMs at large batches even
|
| 34 |
+
though the model is only 137M params. `flash_attn`'s varlen path computes the same attention in
|
| 35 |
+
`O(N)` memory by packing unpadded sequences, so you can run the large batches that OOM the eager
|
| 36 |
+
path — with **parity embeddings** (no quality change). This repo ships that flash path in the
|
| 37 |
+
modeling file itself, so you get it **without a runtime monkeypatch**.
|
| 38 |
+
|
| 39 |
+
## Behavior
|
| 40 |
+
|
| 41 |
+
- **Loads bf16 by default.** Weights are stored bf16 (half the download: 274 MB vs 547 MB) and
|
| 42 |
+
`config.json` declares `torch_dtype: bfloat16`. We patched the upstream `from_pretrained`
|
| 43 |
+
(which silently dropped `torch_dtype` and always loaded fp32) to honor it — so the model now
|
| 44 |
+
loads bf16 natively, like any normal HF model. Pass `torch_dtype=torch.float32` if you want
|
| 45 |
+
fp32 (note: the stored weights are bf16-precision, so this only widens the dtype, not the
|
| 46 |
+
precision).
|
| 47 |
+
- **CUDA + `flash_attn`** → flash-varlen path (fast, low VRAM). The forward casts attention
|
| 48 |
+
tensors to bf16 internally as a safety net, but with the default bf16 load this is a no-op.
|
| 49 |
- **CPU, or no `flash_attn`** → the original eager path, **byte-for-byte unchanged**, so the
|
| 50 |
+
model loads and encodes on any host. The forward picks the path automatically.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
## Usage
|
| 53 |
|
|
|
|
| 65 |
d = model.encode(codes, normalize_embeddings=True)
|
| 66 |
```
|
| 67 |
|
| 68 |
+
## Parity & performance
|
| 69 |
|
| 70 |
+
Same weights (bf16-cast) → embeddings match the fp32 original. Measured on an RTX 3090 Ti,
|
| 71 |
+
`flash_attn` 2.8.3, CLS pooling, L2-normalized, batch size 64:
|
| 72 |
|
| 73 |
+
| metric | `nomic-ai/CodeRankEmbed` (fp32, eager) | this repo (bf16, flash-varlen) |
|
| 74 |
| --- | --- | --- |
|
| 75 |
+
| cosine vs fp32 reference | 1.000000 | **0.9987** |
|
| 76 |
+
| peak VRAM | _measuring_ | _measuring_ |
|
| 77 |
+
| throughput (tok/s) | _measuring_ | _measuring_ |
|
| 78 |
|
| 79 |
+
The cosine is hardware-independent (the flash-varlen forward is numerically identical to the
|
| 80 |
+
merged penstock #264 monkeypatch, verified at parity > 0.997). VRAM and throughput rows are
|
| 81 |
+
populated from a 3090 Ti sweep — see the model card history for the commit that fills them in.
|
| 82 |
|
| 83 |
## What changed vs the source repo
|
| 84 |
|
| 85 |
+
1. **Weights**: fp32 → bf16 (lossy cast, but parity-neutral — the production serving path was
|
| 86 |
+
already bf16). Halves the download.
|
| 87 |
+
2. **`from_pretrained` fix**: the upstream custom `from_pretrained` instantiated the model fp32
|
| 88 |
+
and `load_state_dict`-ed the checkpoint into fp32 params, **ignoring `torch_dtype`** (it was
|
| 89 |
+
swallowed in `**kwargs`). We added the standard transformers dtype resolution (explicit arg →
|
| 90 |
+
`config.torch_dtype` → checkpoint dtype) so the model loads in its declared dtype.
|
| 91 |
+
3. **Flash-varlen forward**: `NomicBertAttention.forward` gains an `unpad →
|
| 92 |
+
flash_attn_varlen_qkvpacked_func(causal=False) → repad` branch (CUDA+flash_attn); the original
|
| 93 |
+
eager block is kept verbatim as the fallback. `NomicBertModel.forward` skips
|
| 94 |
+
`get_extended_attention_mask` on the flash path. Rotary embeddings are applied to the dense
|
| 95 |
+
`[B, S, 3, H, D]` tensor **before** unpadding — the correctness keystone.
|
| 96 |
|
| 97 |
## License & attribution
|
| 98 |
|
| 99 |
MIT — same license as `nomic-ai/CodeRankEmbed` (see `NOTICE`). The weights, tokenizer, and the
|
| 100 |
bulk of the modeling file are a verbatim derivative of `nomic-ai/CodeRankEmbed`; the modeling file
|
| 101 |
+
derives from Tri Dao's BERT implementation, and `CodeRankEmbed` was trained by the CoRNStack team
|
| 102 |
+
(Suresh et al., 2025). Cite their work:
|
| 103 |
|
| 104 |
```bibtex
|
| 105 |
@misc{suresh2025cornstackhighqualitycontrastivedata,
|
config.json
CHANGED
|
@@ -46,7 +46,7 @@
|
|
| 46 |
"summary_proj_to_labels": true,
|
| 47 |
"summary_type": "cls_index",
|
| 48 |
"summary_use_proj": true,
|
| 49 |
-
"torch_dtype": "
|
| 50 |
"transformers_version": "4.45.1",
|
| 51 |
"type_vocab_size": 2,
|
| 52 |
"use_cache": true,
|
|
@@ -54,4 +54,4 @@
|
|
| 54 |
"use_rms_norm": false,
|
| 55 |
"use_xentropy": true,
|
| 56 |
"vocab_size": 30528
|
| 57 |
-
}
|
|
|
|
| 46 |
"summary_proj_to_labels": true,
|
| 47 |
"summary_type": "cls_index",
|
| 48 |
"summary_use_proj": true,
|
| 49 |
+
"torch_dtype": "bfloat16",
|
| 50 |
"transformers_version": "4.45.1",
|
| 51 |
"type_vocab_size": 2,
|
| 52 |
"use_cache": true,
|
|
|
|
| 54 |
"use_rms_norm": false,
|
| 55 |
"use_xentropy": true,
|
| 56 |
"vocab_size": 30528
|
| 57 |
+
}
|
model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:919b7d8b4352a2ede5c99e43c856d935173882471b4332bd61568d239e222676
|
| 3 |
+
size 273474944
|
modeling_hf_nomic_bert.py
CHANGED
|
@@ -369,6 +369,20 @@ class NomicBertPreTrainedModel(PreTrainedModel):
|
|
| 369 |
state_dict = filter_shapes(state_dict, model)
|
| 370 |
|
| 371 |
load_return = model.load_state_dict(state_dict, strict=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 372 |
logger.warning(load_return)
|
| 373 |
return model
|
| 374 |
|
|
|
|
| 369 |
state_dict = filter_shapes(state_dict, model)
|
| 370 |
|
| 371 |
load_return = model.load_state_dict(state_dict, strict=True)
|
| 372 |
+
# Honor torch_dtype like transformers' native from_pretrained does. Our custom
|
| 373 |
+
# override above bypassed it (it instantiates fp32 and load_state_dict upcasts
|
| 374 |
+
# the checkpoint into the fp32 params, ignoring torch_dtype). Resolve explicit
|
| 375 |
+
# kwarg > config.torch_dtype > checkpoint dtype, then cast the model.
|
| 376 |
+
import torch as _torch
|
| 377 |
+
_td = kwargs.get("torch_dtype")
|
| 378 |
+
if _td is None:
|
| 379 |
+
_td = getattr(config, "torch_dtype", None)
|
| 380 |
+
if _td == "auto" or _td is None:
|
| 381 |
+
_td = next(iter(state_dict.values())).dtype
|
| 382 |
+
if isinstance(_td, str):
|
| 383 |
+
_td = getattr(_torch, _td)
|
| 384 |
+
if _td is not None:
|
| 385 |
+
model = model.to(_td)
|
| 386 |
logger.warning(load_return)
|
| 387 |
return model
|
| 388 |
|