handwoven8588 commited on
Commit
22d2b3c
·
verified ·
1 Parent(s): 4cce5bd

CodeRankEmbed with native flash-attn varlen forward (derivative of nomic-ai/CodeRankEmbed; identical weights; flash-vs-fp32 parity cosine 0.99999, eager fallback bit-identical)

Browse files
1_Pooling/config.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "word_embedding_dimension": 768,
3
+ "pooling_mode_cls_token": true,
4
+ "pooling_mode_mean_tokens": false,
5
+ "pooling_mode_max_tokens": false,
6
+ "pooling_mode_mean_sqrt_len_tokens": false,
7
+ "pooling_mode_weightedmean_tokens": false,
8
+ "pooling_mode_lasttoken": false,
9
+ "include_prompt": true
10
+ }
NOTICE ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CodeRankEmbed-flash-attn
2
+ ========================
3
+
4
+ This repository is a derivative of nomic-ai/CodeRankEmbed (MIT).
5
+
6
+ It contains:
7
+ - model weights, tokenizer, and configuration copied verbatim from
8
+ nomic-ai/CodeRankEmbed (commit 3c4b60807d71f79b43f3c4363786d9493691f8b1);
9
+ - a modified modeling_hf_nomic_bert.py that adds a native flash-attention varlen
10
+ path to NomicBertAttention.forward / NomicBertModel.forward. The remainder of
11
+ that file is the upstream nomic implementation unchanged.
12
+
13
+ Upstream lineage and attribution:
14
+ - CodeRankEmbed was trained by the CoRNStack team
15
+ (Suresh et al., "CoRNStack: High-Quality Contrastive Data for Text and Code
16
+ Retrieval", 2025; https://gangiswag.github.io/cornstack/).
17
+ - The model and its trust_remote_code modeling file are published by Nomic
18
+ (nomic-ai/CodeRankEmbed) under the MIT license.
19
+ - The BERT modeling implementation is based on Tri Dao's MLPerf BERT code
20
+ (https://github.com/mlcommons/training_results_v2.0), per the upstream file header.
21
+
22
+ License: MIT. The flash-attention modification added by this repository is also
23
+ released under MIT.
24
+
25
+ NO NEW TRAINING WAS PERFORMED. The model weights are identical to
26
+ nomic-ai/CodeRankEmbed; only the attention forward code differs.
README.md ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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:
8
+ - flash-attention
9
+ - code-retrieval
10
+ - sentence-transformers
11
+ - nomic-bert
12
+ ---
13
+
14
+ # CodeRankEmbed-flash-attn
15
+
16
+ A drop-in derivative of [`nomic-ai/CodeRankEmbed`](https://huggingface.co/nomic-ai/CodeRankEmbed)
17
+ with **flash-attention baked natively into the modeling file**. Same weights, same tokenizer,
18
+ same config — **identical embeddings** — but attention runs via `flash_attn` varlen (unpadded
19
+ packing) instead of the original eager `O(seq²)` matmul.
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 on a
25
+ 24 GB card even though the model is only 137M params. `flash_attn`'s varlen path computes the
26
+ same attention in `O(N)` memory by packing unpadded sequences, so you can run the large batches
27
+ that OOM the eager path — with **parity embeddings** (no quality change).
28
+
29
+ This repo exists so you get that flash path **without a runtime monkeypatch**: the
30
+ `modeling_hf_nomic_bert.py` here is one we own, with the flash-varlen forward written in
31
+ directly. Load it like any other model; `trust_remote_code` now runs *this* audited file.
32
+
33
+ ## Behavior (works everywhere)
34
+
35
+ - **CUDA + `flash_attn` installed** → flash-varlen path (fast, low VRAM).
36
+ - **CPU, or no `flash_attn`** → the original eager path, **byte-for-byte unchanged**, so the
37
+ model loads and encodes correctly on any host. The forward picks the path automatically.
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
+
45
+ Identical to the original. The query prompt **must** include the task-instruction prefix
46
+ `"Represent this query for searching relevant code: "`; documents need no prefix.
47
+
48
+ ```python
49
+ from sentence_transformers import SentenceTransformer
50
+
51
+ model = SentenceTransformer("handwoven8588/CodeRankEmbed-flash-attn", trust_remote_code=True)
52
+ queries = ["Represent this query for searching relevant code: Calculate the n-th factorial"]
53
+ codes = ["def fact(n):\n if n < 0:\n raise ValueError\n return 1 if n == 0 else n * fact(n - 1)"]
54
+
55
+ q = model.encode(queries, normalize_embeddings=True)
56
+ d = model.encode(codes, normalize_embeddings=True)
57
+ ```
58
+
59
+ ## Parity vs `nomic-ai/CodeRankEmbed`
60
+
61
+ Same weights + tokenizer, so embeddings match the original. Measured (RTX 4060, `flash_attn`
62
+ 2.8.3, CLS pooling, L2-normalized):
63
+
64
+ | path | comparison | cosine (same input) |
65
+ | --- | --- | --- |
66
+ | flash-varlen (this repo, CUDA) | vs original fp32 eager | **0.99999** |
67
+ | eager fallback (this repo, CPU) | vs original fp32 eager | **1.000000** (bit-identical) |
68
+
69
+ The eager fallback is byte-for-byte the original code, so on CPU the two repos are numerically
70
+ identical. On CUDA the only difference is bf16 rounding inside attention (cosine 0.99999) —
71
+ retrieval-quality-neutral.
72
+
73
+ ## What changed vs the source repo
74
+
75
+ Only two methods were modified in `modeling_hf_nomic_bert.py`; everything else is the upstream
76
+ file unchanged:
77
+
78
+ - `NomicBertModel.forward` — skips `get_extended_attention_mask` on the flash path (flash derives
79
+ sequence lengths from `cu_seqlens`, not an additive mask); calls it as before on the eager path.
80
+ - `NomicBertAttention.forward` — adds the `unpad → flash_attn_varlen_qkvpacked_func(causal=False)
81
+ → repad` branch; keeps the original eager block as the fallback.
82
+
83
+ Rotary embeddings are applied to the dense `[B, S, 3, H, D]` tensor **before** unpadding — the
84
+ correctness keystone (unpadding first would corrupt per-sequence positions).
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
+ itself derives from Tri Dao's BERT implementation, and `CodeRankEmbed` was trained by the CoRNStack
91
+ team (Suresh et al., 2025). If you find the model useful, please cite their work:
92
+
93
+ ```bibtex
94
+ @misc{suresh2025cornstackhighqualitycontrastivedata,
95
+ title = {CoRNStack: High-Quality Contrastive Data for Text and Code Retrieval},
96
+ author = {Suresh, K N Q and Wang, Xiang and Khan, Saqib and others},
97
+ year = {2025},
98
+ }
99
+ ```
config.json ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_name_or_path": "nomic-uiuc/CodeEmbed",
3
+ "activation_function": "swiglu",
4
+ "architectures": [
5
+ "NomicBertModel"
6
+ ],
7
+ "attn_pdrop": 0.0,
8
+ "auto_map": {
9
+ "AutoConfig": "configuration_hf_nomic_bert.NomicBertConfig",
10
+ "AutoModel": "modeling_hf_nomic_bert.NomicBertModel"
11
+ },
12
+ "bos_token_id": null,
13
+ "causal": false,
14
+ "dense_seq_output": true,
15
+ "embd_pdrop": 0.1,
16
+ "eos_token_id": null,
17
+ "fused_bias_fc": true,
18
+ "fused_dropout_add_ln": true,
19
+ "initializer_range": 0.02,
20
+ "layer_norm_epsilon": 1e-12,
21
+ "max_trained_positions": 2048,
22
+ "mlp_fc1_bias": false,
23
+ "mlp_fc2_bias": false,
24
+ "model_type": "nomic_bert",
25
+ "n_embd": 768,
26
+ "n_head": 12,
27
+ "n_inner": 3072,
28
+ "n_layer": 12,
29
+ "n_positions": 8192,
30
+ "pad_vocab_size_multiple": 64,
31
+ "parallel_block": false,
32
+ "parallel_block_tied_norm": false,
33
+ "prenorm": false,
34
+ "qkv_proj_bias": false,
35
+ "reorder_and_upcast_attn": false,
36
+ "resid_pdrop": 0.1,
37
+ "rotary_emb_base": 1000,
38
+ "rotary_emb_fraction": 1.0,
39
+ "rotary_emb_interleaved": false,
40
+ "rotary_emb_scale_base": null,
41
+ "rotary_scaling_factor": null,
42
+ "scale_attn_by_inverse_layer_idx": false,
43
+ "scale_attn_weights": true,
44
+ "summary_activation": null,
45
+ "summary_first_dropout": 0.1,
46
+ "summary_proj_to_labels": true,
47
+ "summary_type": "cls_index",
48
+ "summary_use_proj": true,
49
+ "torch_dtype": "float32",
50
+ "transformers_version": "4.45.1",
51
+ "type_vocab_size": 2,
52
+ "use_cache": true,
53
+ "use_flash_attn": true,
54
+ "use_rms_norm": false,
55
+ "use_xentropy": true,
56
+ "vocab_size": 30528
57
+ }
config_sentence_transformers.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "__version__": {
3
+ "sentence_transformers": "2.7.0.dev0",
4
+ "transformers": "4.39.3",
5
+ "pytorch": "2.1.0+cu121"
6
+ },
7
+ "prompts": {
8
+ "query": "Represent this query for searching relevant code: "
9
+ },
10
+ "default_prompt_name": null
11
+ }
configuration_hf_nomic_bert.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import GPT2Config
2
+
3
+
4
+ class NomicBertConfig(GPT2Config):
5
+ model_type = "nomic_bert"
6
+
7
+ def __init__(
8
+ self,
9
+ prenorm=False,
10
+ parallel_block=False,
11
+ parallel_block_tied_norm=False,
12
+ rotary_emb_fraction=0.0,
13
+ fused_dropout_add_ln=False,
14
+ fused_bias_fc=False,
15
+ use_flash_attn=False,
16
+ use_xentropy=False,
17
+ qkv_proj_bias=True,
18
+ rotary_emb_base=1000,
19
+ rotary_emb_scale_base=None,
20
+ rotary_emb_interleaved=False,
21
+ mlp_fc1_bias=True,
22
+ mlp_fc2_bias=True,
23
+ use_rms_norm=False,
24
+ causal=False,
25
+ type_vocab_size=2,
26
+ dense_seq_output=True,
27
+ pad_vocab_size_multiple=1,
28
+ tie_word_embeddings=True,
29
+ rotary_scaling_factor=1.0,
30
+ max_trained_positions=2048,
31
+ **kwargs,
32
+ ):
33
+ self.prenorm = prenorm
34
+ self.parallel_block = parallel_block
35
+ self.parallel_block_tied_norm = parallel_block_tied_norm
36
+ self.rotary_emb_fraction = rotary_emb_fraction
37
+ self.tie_word_embeddings = tie_word_embeddings
38
+ self.fused_dropout_add_ln = fused_dropout_add_ln
39
+ self.fused_bias_fc = fused_bias_fc
40
+ self.use_flash_attn = use_flash_attn
41
+ self.use_xentropy = use_xentropy
42
+ self.qkv_proj_bias = qkv_proj_bias
43
+ self.rotary_emb_base = rotary_emb_base
44
+ self.rotary_emb_scale_base = rotary_emb_scale_base
45
+ self.rotary_emb_interleaved = rotary_emb_interleaved
46
+ self.mlp_fc1_bias = mlp_fc1_bias
47
+ self.mlp_fc2_bias = mlp_fc2_bias
48
+ self.use_rms_norm = use_rms_norm
49
+ self.causal = causal
50
+ self.type_vocab_size = type_vocab_size
51
+ self.dense_seq_output = dense_seq_output
52
+ self.pad_vocab_size_multiple = pad_vocab_size_multiple
53
+ self.rotary_scaling_factor = rotary_scaling_factor
54
+ self.max_trained_positions = max_trained_positions
55
+
56
+ super().__init__(**kwargs)
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:827529bcd58aef0d9082e66eeff7e7d53a02f62bd005f841a26b3d3e2fb17ebe
3
+ size 546938168
modeling_hf_nomic_bert.py ADDED
@@ -0,0 +1,1298 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2022, Tri Dao.
2
+ # This BERT implementation is based on our MLPerf 2.0 and MLPerf 2.1 BERT implementation.
3
+ # https://github.com/mlcommons/training_results_v2.0/blob/main/HazyResearch/benchmarks/bert/implementations/pytorch/modeling.py
4
+ # https://github.com/mlcommons/training_results_v2.1/blob/main/Azure-HazyResearch/benchmarks/bert/implementations/ND96amsr_A100_v4/modeling.py
5
+
6
+ import logging
7
+
8
+ # Inspired by https://github.com/huggingface/transformers/blob/main/src/transformers/models/bert/modeling_bert.py
9
+ import os
10
+ import re
11
+ from collections import OrderedDict
12
+ from functools import partial
13
+ from typing import List, Optional, Tuple, Union
14
+
15
+ import torch
16
+ import torch.nn as nn
17
+ import torch.nn.functional as F
18
+ from einops import rearrange, repeat
19
+ from safetensors.torch import load_file as safe_load_file
20
+ from transformers import GPT2Config, PreTrainedModel
21
+ from transformers.models.bert.modeling_bert import (
22
+ BaseModelOutputWithPoolingAndCrossAttentions,
23
+ MaskedLMOutput,
24
+ SequenceClassifierOutput,
25
+ )
26
+ from transformers.utils import SAFE_WEIGHTS_INDEX_NAME, SAFE_WEIGHTS_NAME, WEIGHTS_INDEX_NAME, WEIGHTS_NAME
27
+ from transformers.utils.hub import cached_file, get_checkpoint_shard_files
28
+
29
+ # Flash-attention varlen path (optional). When ``flash_attn`` is importable and
30
+ # the tensors live on CUDA, attention runs as unpadded varlen packing — O(N)
31
+ # activation memory instead of the eager path's O(seq^2). When flash_attn is
32
+ # unavailable (CPU-only hosts, or builds without it) the original eager path
33
+ # runs byte-for-byte unchanged, so this model loads and encodes everywhere.
34
+ try: # pragma: no cover - import guard, exercised by environment
35
+ from flash_attn import flash_attn_varlen_qkvpacked_func
36
+ from flash_attn.bert_padding import pad_input, unpad_input
37
+
38
+ _FLASH_AVAILABLE = True
39
+ except Exception: # pragma: no cover
40
+ flash_attn_varlen_qkvpacked_func = None # type: ignore[assignment]
41
+ pad_input = None # type: ignore[assignment]
42
+ unpad_input = None # type: ignore[assignment]
43
+ _FLASH_AVAILABLE = False
44
+
45
+ from .configuration_hf_nomic_bert import NomicBertConfig
46
+
47
+ logger = logging.getLogger(__name__)
48
+
49
+
50
+ # adapted from flash attention, added safe serialization option for hf models
51
+ def state_dict_from_pretrained(model_name, safe_serialization=False, device=None, dtype=None):
52
+ # If not fp32, then we don't want to load directly to the GPU
53
+ mapped_device = "cpu" if dtype not in [torch.float32, None] else device
54
+ is_sharded = False
55
+ load_safe = False
56
+ resolved_archive_file = None
57
+
58
+ weights_path = os.path.join(model_name, WEIGHTS_NAME)
59
+ weights_index_path = os.path.join(model_name, WEIGHTS_INDEX_NAME)
60
+ safe_weights_path = os.path.join(model_name, SAFE_WEIGHTS_NAME)
61
+ safe_weights_index_path = os.path.join(model_name, SAFE_WEIGHTS_INDEX_NAME)
62
+
63
+ if os.path.isfile(weights_path):
64
+ resolved_archive_file = cached_file(model_name, WEIGHTS_NAME, _raise_exceptions_for_missing_entries=False)
65
+ elif os.path.isfile(weights_index_path):
66
+ resolved_archive_file = cached_file(model_name, WEIGHTS_INDEX_NAME, _raise_exceptions_for_missing_entries=False)
67
+ is_sharded = True
68
+ elif os.path.isfile(safe_weights_path):
69
+ resolved_archive_file = cached_file(model_name, SAFE_WEIGHTS_NAME, _raise_exceptions_for_missing_entries=False)
70
+ load_safe = True
71
+ elif os.path.isfile(safe_weights_index_path):
72
+ resolved_archive_file = cached_file(
73
+ model_name, SAFE_WEIGHTS_INDEX_NAME, _raise_exceptions_for_missing_entries=False
74
+ )
75
+ is_sharded = True
76
+ load_safe = True
77
+ else: # Try loading from HF hub instead of from local files
78
+ weight_name = WEIGHTS_NAME if not safe_serialization else SAFE_WEIGHTS_NAME
79
+ resolved_archive_file = cached_file(model_name, weight_name, _raise_exceptions_for_missing_entries=False)
80
+ if resolved_archive_file is None:
81
+ weight_index = WEIGHTS_INDEX_NAME if not safe_serialization else SAFE_WEIGHTS_INDEX_NAME
82
+ resolved_archive_file = cached_file(model_name, weight_index, _raise_exceptions_for_missing_entries=False)
83
+ if resolved_archive_file is not None:
84
+ is_sharded = True
85
+
86
+ load_safe = safe_serialization
87
+
88
+ if resolved_archive_file is None:
89
+ raise EnvironmentError(f"Model name {model_name} was not found.")
90
+
91
+ if load_safe:
92
+ loader = partial(safe_load_file, device=mapped_device)
93
+ else:
94
+ loader = partial(torch.load, map_location=mapped_device)
95
+
96
+ if is_sharded:
97
+ # resolved_archive_file becomes a list of files that point to the different
98
+ # checkpoint shards in this case.
99
+ resolved_archive_file, sharded_metadata = get_checkpoint_shard_files(model_name, resolved_archive_file)
100
+ state_dict = {}
101
+ for sharded_file in resolved_archive_file:
102
+ state_dict.update(loader(sharded_file))
103
+ else:
104
+ state_dict = loader(resolved_archive_file)
105
+ # Convert dtype before moving to GPU to save memory
106
+ if dtype is not None:
107
+ state_dict = {k: v.to(dtype=dtype) for k, v in state_dict.items()}
108
+ state_dict = {k: v.to(device=device) for k, v in state_dict.items()}
109
+ return state_dict
110
+
111
+
112
+ def filter_shapes(state_dict, model):
113
+ """
114
+ Filters the state dict to match the current model shape.
115
+ """
116
+ filtered_state_dict = {}
117
+ for key, value in state_dict.items():
118
+ if key in model.state_dict():
119
+ if value.shape == model.state_dict()[key].shape:
120
+ filtered_state_dict[key] = value
121
+ return filtered_state_dict
122
+
123
+
124
+ def remap_bert_state_dict(state_dict, config, remove_bert=False, remove_cls_weights=False, add_pooling_layer=False):
125
+ """
126
+ Map the state_dict of a Huggingface BERT model to be flash_attn compatible.
127
+ """
128
+
129
+ def add_bert_prefix(key):
130
+ # prepend bert. to the key
131
+ if key.startswith("bert.") or key.startswith("cls."):
132
+ return key
133
+ return f"bert.{key}"
134
+
135
+ state_dict = OrderedDict((add_bert_prefix(k), v) for k, v in state_dict.items())
136
+
137
+ # LayerNorm
138
+ def key_mapping_ln_gamma_beta(key):
139
+ key = re.sub(r"LayerNorm.gamma$", "LayerNorm.weight", key)
140
+ key = re.sub(r"LayerNorm.beta$", "LayerNorm.bias", key)
141
+ return key
142
+
143
+ state_dict = OrderedDict((key_mapping_ln_gamma_beta(k), v) for k, v in state_dict.items())
144
+
145
+ # Layers
146
+ def key_mapping_layers(key):
147
+ return re.sub(r"^bert.encoder.layer\.", "bert.encoder.layers.", key)
148
+
149
+ state_dict = OrderedDict((key_mapping_layers(k), v) for k, v in state_dict.items())
150
+
151
+ # LayerNorm
152
+ def key_mapping_ln(key):
153
+ key = re.sub(r"^bert.embeddings.LayerNorm.", "bert.emb_ln.", key)
154
+ key = re.sub(
155
+ r"^bert.encoder.layers.(\d+).attention.output.LayerNorm.(weight|bias)",
156
+ r"bert.encoder.layers.\1.norm1.\2",
157
+ key,
158
+ )
159
+ key = re.sub(
160
+ r"^bert.encoder.layers.(\d+).output.LayerNorm.(weight|bias)",
161
+ r"bert.encoder.layers.\1.norm2.\2",
162
+ key,
163
+ )
164
+ key = re.sub(
165
+ r"^cls.predictions.transform.LayerNorm.(weight|bias)",
166
+ r"cls.predictions.transform.layer_norm.\1",
167
+ key,
168
+ )
169
+ return key
170
+
171
+ state_dict = OrderedDict((key_mapping_ln(k), v) for k, v in state_dict.items())
172
+
173
+ # MLP
174
+ def key_mapping_mlp(key):
175
+ key = re.sub(
176
+ r"^bert.encoder.layers.(\d+).intermediate.dense.(weight|bias)",
177
+ r"bert.encoder.layers.\1.mlp.fc1.\2",
178
+ key,
179
+ )
180
+ key = re.sub(
181
+ r"^bert.encoder.layers.(\d+).output.dense.(weight|bias)",
182
+ r"bert.encoder.layers.\1.mlp.fc2.\2",
183
+ key,
184
+ )
185
+ return key
186
+
187
+ state_dict = OrderedDict((key_mapping_mlp(k), v) for k, v in state_dict.items())
188
+
189
+ # Attention
190
+ last_layer_subset = getattr(config, "last_layer_subset", False)
191
+ for d in range(config.num_hidden_layers):
192
+ if f"bert.encoder.layers.{d}.attention.self.query.weight" not in state_dict:
193
+ continue
194
+ Wq = state_dict.pop(f"bert.encoder.layers.{d}.attention.self.query.weight")
195
+ Wk = state_dict.pop(f"bert.encoder.layers.{d}.attention.self.key.weight")
196
+ Wv = state_dict.pop(f"bert.encoder.layers.{d}.attention.self.value.weight")
197
+ bq = state_dict.pop(f"bert.encoder.layers.{d}.attention.self.query.bias")
198
+ bk = state_dict.pop(f"bert.encoder.layers.{d}.attention.self.key.bias")
199
+ bv = state_dict.pop(f"bert.encoder.layers.{d}.attention.self.value.bias")
200
+ if not (last_layer_subset and d == config.num_hidden_layers - 1):
201
+ state_dict[f"bert.encoder.layers.{d}.attn.Wqkv.weight"] = torch.cat([Wq, Wk, Wv], dim=0)
202
+ state_dict[f"bert.encoder.layers.{d}.attn.Wqkv.bias"] = torch.cat([bq, bk, bv], dim=0)
203
+ else:
204
+ state_dict[f"bert.encoder.layers.{d}.attn.Wq.weight"] = Wq
205
+ state_dict[f"bert.encoder.layers.{d}.attn.Wkv.weight"] = torch.cat([Wk, Wv], dim=0)
206
+ state_dict[f"bert.encoder.layers.{d}.attn.Wq.bias"] = bq
207
+ state_dict[f"bert.encoder.layers.{d}.attn.Wkv.bias"] = torch.cat([bk, bv], dim=0)
208
+
209
+ def key_mapping_attn(key):
210
+ return re.sub(
211
+ r"^bert.encoder.layers.(\d+).attention.output.dense.(weight|bias)",
212
+ r"bert.encoder.layers.\1.attn.out_proj.\2",
213
+ key,
214
+ )
215
+
216
+ state_dict = OrderedDict((key_mapping_attn(k), v) for k, v in state_dict.items())
217
+
218
+ def key_mapping_decoder_bias(key):
219
+ return re.sub(r"^cls.predictions.bias", "cls.predictions.decoder.bias", key)
220
+
221
+ # remove nsp weights, we don't use
222
+ state_dict.pop("cls.seq_relationship.weight", None)
223
+ state_dict.pop("cls.seq_relationship.bias", None)
224
+ state_dict.pop("bert.embeddings.position_ids", None)
225
+
226
+ state_dict = OrderedDict((key_mapping_decoder_bias(k), v) for k, v in state_dict.items())
227
+
228
+ if remove_cls_weights:
229
+ cls_weights = [
230
+ "cls.predictions.decoder.bias",
231
+ "cls.predictions.transform.dense.weight",
232
+ "cls.predictions.transform.dense.bias",
233
+ "cls.predictions.transform.layer_norm.weight",
234
+ "cls.predictions.transform.layer_norm.bias",
235
+ "cls.predictions.decoder.weight",
236
+ ]
237
+ for weight in cls_weights:
238
+ state_dict.pop(weight, None)
239
+
240
+ # Word embedding
241
+ pad_vocab_size_multiple = getattr(config, "pad_vocab_size_multiple", 1)
242
+ if pad_vocab_size_multiple > 1:
243
+ word_embeddings = state_dict["bert.embeddings.word_embeddings.weight"]
244
+ state_dict["bert.embeddings.word_embeddings.weight"] = F.pad(
245
+ word_embeddings, (0, 0, 0, config.vocab_size - word_embeddings.shape[0])
246
+ )
247
+ if not remove_cls_weights:
248
+ decoder_weight = state_dict["cls.predictions.decoder.weight"]
249
+ state_dict["cls.predictions.decoder.weight"] = F.pad(
250
+ decoder_weight, (0, 0, 0, config.vocab_size - decoder_weight.shape[0])
251
+ )
252
+ # If the vocab was padded, we want to set the decoder bias for those padded indices to be
253
+ # strongly negative (i.e. the decoder shouldn't predict those indices).
254
+ # TD [2022-05-09]: I don't think it affects the MLPerf training.
255
+ if "cls.predictions.decoder.bias" in state_dict:
256
+ decoder_bias = state_dict["cls.predictions.decoder.bias"]
257
+ state_dict["cls.predictions.decoder.bias"] = F.pad(
258
+ decoder_bias, (0, config.vocab_size - decoder_bias.shape[0]), value=-100.0
259
+ )
260
+
261
+ if add_pooling_layer is False:
262
+ pooler_weights = [
263
+ "bert.pooler.dense.weight",
264
+ "bert.pooler.dense.bias",
265
+ ]
266
+ for key in pooler_weights:
267
+ state_dict.pop(key, None)
268
+
269
+ if remove_bert:
270
+
271
+ def remove_bert_prefix(key):
272
+ key = re.sub(r"^bert.", "", key)
273
+ return key
274
+
275
+ state_dict = OrderedDict((remove_bert_prefix(k), v) for k, v in state_dict.items())
276
+
277
+ return state_dict
278
+
279
+
280
+ class NomicBertPreTrainedModel(PreTrainedModel):
281
+ """An abstract class to handle weights initialization and
282
+ a simple interface for dowloading and loading pretrained models.
283
+ """
284
+
285
+ config_class = NomicBertConfig
286
+ base_model_prefix = "model"
287
+ supports_gradient_checkpointing = True
288
+ _no_split_modules = ["Block"]
289
+ _skip_keys_device_placement = "past_key_values"
290
+
291
+ def __init__(self, config, *inputs, **kwargs):
292
+ super().__init__(config)
293
+ if not isinstance(config, GPT2Config):
294
+ raise ValueError(
295
+ "Parameter config in `{}(config)` should be an instance of class `GPT2Config`. "
296
+ "To create a model from a Google pretrained model use "
297
+ "`model = {}.from_pretrained(PRETRAINED_MODEL_NAME)`".format(
298
+ self.__class__.__name__, self.__class__.__name__
299
+ )
300
+ )
301
+ self.config = config
302
+
303
+ @classmethod
304
+ def from_pretrained(cls, model_name, config=None, *inputs, **kwargs):
305
+ """
306
+ Instantiate a NomicBertPreTrainedModel from a pre-trained model file or a pytorch state dict.
307
+ Download and cache the pre-trained model file if needed.
308
+ Params:
309
+ pretrained_model_name_or_path: either:
310
+ - a path or url to a pretrained model archive containing:
311
+ . `bert_config.json` a configuration file for the model
312
+ . `pytorch_model.bin` a PyTorch dump of a NomicBertForPretraining instance
313
+ - a path or url to a pretrained model archive containing:
314
+ . `bert_config.json` a configuration file for the model
315
+ . `model.chkpt` a TensorFlow checkpoint
316
+ *inputs, **kwargs: additional input for the specific NomicBert class
317
+ (ex: num_labels for NomicBertForSequenceClassification)
318
+ """
319
+ # Instantiate model.
320
+ if config is None:
321
+ config = cls.config_class.from_pretrained(model_name)
322
+ remove_cls = cls != NomicBertForPreTraining
323
+ remove_bert_prefix = cls != NomicBertForPreTraining
324
+ ignore_mismatched_shapes = kwargs.pop("ignore_mismatched_sizes", False)
325
+ num_labels = kwargs.pop("num_labels", None)
326
+ rotary_scaling_factor = kwargs.pop("rotary_scaling_factor", None)
327
+ if rotary_scaling_factor:
328
+ config.rotary_scaling_factor = rotary_scaling_factor
329
+
330
+ if config.n_positions <= 0 and config.rotary_emb_fraction > 0:
331
+ config.n_positions = 2048
332
+ if num_labels:
333
+ config.num_labels = num_labels
334
+
335
+ if "add_pooling_layer" in kwargs:
336
+ model = cls(config, *inputs, add_pooling_layer=kwargs.pop("add_pooling_layer"))
337
+ else:
338
+ if cls == NomicBertModel:
339
+ model = cls(config, *inputs, add_pooling_layer=False)
340
+ else:
341
+ model = cls(config, *inputs)
342
+ # TODO: fix this
343
+ # Assuming we know what we're doing when loading from disk
344
+ # Prob a bad assumption but i'm tired and want to train this asap
345
+ if os.path.exists(model_name):
346
+ model_path = f"{model_name}/pytorch_model.bin"
347
+ if os.path.exists(model_path):
348
+ state_dict = torch.load(f"{model_name}/pytorch_model.bin")
349
+ else:
350
+ model_path = f"{model_name}/model.safetensors"
351
+ if not os.path.exists(model_path):
352
+ raise ValueError(f"Model path {model_path} not found")
353
+ state_dict = safe_load_file(model_path)
354
+
355
+ if ignore_mismatched_shapes:
356
+ state_dict = filter_shapes(state_dict, model)
357
+ load_return = model.load_state_dict(state_dict, strict=False)
358
+ else:
359
+ # TODO: can probably check config class and see if we need to remap from a bert model
360
+ state_dict = state_dict_from_pretrained(model_name, safe_serialization=kwargs.get("safe_serialization", False))
361
+ state_dict = remap_bert_state_dict(
362
+ state_dict,
363
+ config,
364
+ remove_bert=remove_bert_prefix,
365
+ remove_cls_weights=remove_cls,
366
+ add_pooling_layer=getattr(config, "add_pooling_layer", False),
367
+ )
368
+ if ignore_mismatched_shapes:
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
+
375
+ def _set_gradient_checkpointing(self, module, value=False):
376
+ if isinstance(module, NomicBertEncoder):
377
+ module.gradient_checkpointing = value
378
+
379
+
380
+ # https://github.com/huggingface/transformers/blob/7032e0203262ebb2ebf55da8d2e01f873973e835/src/transformers/models/bert/modeling_bert.py#L748
381
+ def _init_weights(module, initializer_range=0.02):
382
+ if isinstance(module, nn.Linear):
383
+ nn.init.normal_(module.weight, std=initializer_range)
384
+ if module.bias is not None:
385
+ nn.init.zeros_(module.bias)
386
+ elif isinstance(module, nn.Embedding):
387
+ nn.init.normal_(module.weight, std=initializer_range)
388
+ if module.padding_idx is not None:
389
+ nn.init.zeros_(module.weight[module.padding_idx])
390
+
391
+
392
+ class NomicBertEmbeddings(nn.Module):
393
+ def __init__(self, config):
394
+ """
395
+ If max_position_embeddings <= 0, there's no position embeddings
396
+ If type_vocab_size <= 0, there's no token type embeddings
397
+ """
398
+ super().__init__()
399
+ self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=config.pad_token_id)
400
+ self.max_position_embeddings = config.max_position_embeddings if config.rotary_emb_fraction <= 0 else 0
401
+ self.type_vocab_size = config.type_vocab_size
402
+ if self.max_position_embeddings > 0 and config.rotary_emb_fraction <= 0:
403
+ self.position_embeddings = nn.Embedding(
404
+ config.max_position_embeddings,
405
+ config.hidden_size,
406
+ )
407
+ if self.type_vocab_size > 0:
408
+ self.token_type_embeddings = nn.Embedding(config.type_vocab_size, config.hidden_size)
409
+
410
+ def forward(self, input_ids, position_ids=None, token_type_ids=None):
411
+ """
412
+ input_ids: (batch, seqlen)
413
+ position_ids: (batch, seqlen)
414
+ token_type_ids: (batch, seqlen)
415
+ """
416
+ batch_size, seqlen = input_ids.shape
417
+ embeddings = self.word_embeddings(input_ids)
418
+
419
+ if self.type_vocab_size > 0:
420
+ if token_type_ids is None:
421
+ token_type_ids = torch.zeros(seqlen, dtype=torch.long, device=input_ids.device)
422
+ token_type_embeddings = self.token_type_embeddings(token_type_ids)
423
+ embeddings = embeddings + token_type_embeddings
424
+
425
+ if self.max_position_embeddings > 0:
426
+ if position_ids is None:
427
+ position_ids = torch.arange(seqlen, dtype=torch.long, device=input_ids.device)
428
+ position_embeddings = self.position_embeddings(position_ids)
429
+ embeddings = embeddings + position_embeddings
430
+ return embeddings
431
+
432
+
433
+ class NomicBertMLP(nn.Module):
434
+ def __init__(
435
+ self,
436
+ in_features,
437
+ hidden_features=None,
438
+ out_features=None,
439
+ activation=F.gelu,
440
+ bias1=True,
441
+ bias2=True,
442
+ return_residual=False,
443
+ fused_bias_fc=False,
444
+ ):
445
+ super().__init__()
446
+ out_features = out_features if out_features is not None else in_features
447
+ hidden_features = hidden_features if hidden_features is not None else in_features * 4
448
+ self.return_residual = return_residual
449
+ self.fc1 = nn.Linear(in_features, hidden_features, bias=bias1)
450
+ approximate = "tanh" if activation in ["gelu_new", "gelu_fast", "gelu_pytorch_tanh"] else "none"
451
+ self.activation = nn.GELU(approximate=approximate) if activation == "gelu" else activation
452
+ self.fc2 = nn.Linear(hidden_features, out_features, bias=bias2)
453
+
454
+ def forward(self, x):
455
+ y = self.fc1(x)
456
+ y = self.activation(y)
457
+ y = self.fc2(y)
458
+ return y if not self.return_residual else (y, x)
459
+
460
+
461
+ class NomciBertGatedMLP(nn.Module):
462
+ def __init__(
463
+ self,
464
+ in_features,
465
+ hidden_features=None,
466
+ out_features=None,
467
+ activation=F.sigmoid,
468
+ bias1=True,
469
+ bias2=True,
470
+ multiple_of=256,
471
+ return_residual=False,
472
+ fused_bias_fc=True,
473
+ device=None,
474
+ dtype=None,
475
+ ):
476
+ super().__init__()
477
+ out_features = out_features if out_features is not None else in_features
478
+ hidden_features = hidden_features if hidden_features is not None else int(8 * in_features / 3)
479
+ hidden_features = (hidden_features + multiple_of - 1) // multiple_of * multiple_of
480
+ self.return_residual = return_residual
481
+
482
+ self.fc11 = nn.Linear(in_features, hidden_features, bias=bias1)
483
+ self.fc12 = nn.Linear(in_features, hidden_features, bias=bias1)
484
+ self.activation = activation
485
+ self.fc2 = nn.Linear(hidden_features, out_features, bias=bias2)
486
+
487
+ def forward(self, x):
488
+ y = self.fc11(x)
489
+ gate = self.fc12(x)
490
+ if self.activation == F.sigmoid: # Special case for GLU
491
+ y = F.glu(torch.cat([y, gate], dim=-1), dim=-1)
492
+ else:
493
+ y = y * self.activation(gate)
494
+ y = self.fc2(y)
495
+ return y if not self.return_residual else (y, x)
496
+
497
+
498
+ def rotate_half(x, interleaved=False):
499
+ if not interleaved:
500
+ x1, x2 = x.chunk(2, dim=-1)
501
+ return torch.cat((-x2, x1), dim=-1)
502
+ else:
503
+ x1, x2 = x[..., ::2], x[..., 1::2]
504
+ return rearrange(torch.stack((-x2, x1), dim=-1), "... d two -> ... (d two)", two=2)
505
+
506
+
507
+ def apply_rotary_emb(x, cos, sin, offset=0, interleaved=False):
508
+ """
509
+ x: (batch_size, seqlen, nheads, headdim)
510
+ cos, sin: (seqlen, rotary_dim / 2) or (batch_size, seqlen, rotary_dim / 2)
511
+ """
512
+ ro_dim = cos.shape[-1] * 2
513
+ assert ro_dim <= x.shape[-1]
514
+ cos, sin = (
515
+ cos[offset : offset + x.shape[1]],
516
+ sin[offset : offset + x.shape[1]],
517
+ )
518
+ cos = repeat(cos, "... d -> ... 1 (2 d)" if not interleaved else "... d -> ... 1 (d 2)")
519
+ sin = repeat(sin, "... d -> ... 1 (2 d)" if not interleaved else "... d -> ... 1 (d 2)")
520
+ return torch.cat(
521
+ [x[..., :ro_dim] * cos + rotate_half(x[..., :ro_dim], interleaved) * sin, x[..., ro_dim:]],
522
+ dim=-1,
523
+ )
524
+
525
+
526
+ class NomicBertRotaryEmbedding(nn.Module):
527
+ def __init__(
528
+ self,
529
+ dim: int,
530
+ base=10000.0,
531
+ interleaved=False,
532
+ scale_base=None,
533
+ pos_idx_in_fp32=True,
534
+ device=None,
535
+ ):
536
+ """
537
+ interleaved: if True, rotate pairs of even and odd dimensions (GPT-J style) instead
538
+ of 1st half and 2nd half (GPT-NeoX style).
539
+ pos_idx_in_fp32: if True, the position indices [0.0, ..., seqlen - 1] are in fp32,
540
+ otherwise they might be in lower precision.
541
+ This option was added because previously (before 2023-07-02), when we construct
542
+ the position indices, we use the dtype of self.inv_freq. In most cases this would
543
+ be fp32, but if the model is trained in pure bf16 (not mixed precision), then
544
+ self.inv_freq would be bf16, and the position indices are also in bf16.
545
+ Because of the limited precision of bf16 (e.g. 1995.0 is rounded to 2000.0), the
546
+ embeddings for some positions will coincide.
547
+ To maintain compatibility with models previously trained in pure bf16,
548
+ we add this option.
549
+ """
550
+ super().__init__()
551
+ self.dim = dim
552
+ self.base = float(base)
553
+ self.pos_idx_in_fp32 = pos_idx_in_fp32
554
+ # Generate and save the inverse frequency buffer (non trainable)
555
+ inv_freq = self._compute_inv_freq(device)
556
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
557
+ self.interleaved = interleaved
558
+ self.scale_base = scale_base
559
+ scale = (
560
+ (torch.arange(0, dim, 2, device=device, dtype=torch.float32) + 0.4 * dim) / (1.4 * dim)
561
+ if scale_base is not None
562
+ else None
563
+ )
564
+ self.register_buffer("scale", scale, persistent=False)
565
+
566
+ self._seq_len_cached = 0
567
+ self._cos_cached = None
568
+ self._sin_cached = None
569
+ self._cos_k_cached = None
570
+ self._sin_k_cached = None
571
+
572
+ def _compute_inv_freq(self, device=None):
573
+ return 1.0 / (self.base ** (torch.arange(0, self.dim, 2, device=device, dtype=torch.float32) / self.dim))
574
+
575
+ def _update_cos_sin_cache(self, seqlen, device=None, dtype=None):
576
+ # Reset the tables if the sequence length has changed,
577
+ # if we're on a new device (possibly due to tracing for instance),
578
+ # or if we're switching from inference mode to training
579
+ if (
580
+ seqlen > self._seq_len_cached
581
+ or self._cos_cached is None
582
+ or self._cos_cached.device != device
583
+ or self._cos_cached.dtype != dtype
584
+ or (self.training and self._cos_cached.is_inference())
585
+ ):
586
+ self._seq_len_cached = seqlen
587
+ # We want fp32 here, not self.inv_freq.dtype, since the model could be loaded in bf16
588
+ # And the output of arange can be quite large, so bf16 would lose a lot of precision.
589
+ # However, for compatibility reason, we add an option to use the dtype of self.inv_freq.
590
+ if self.pos_idx_in_fp32:
591
+ t = torch.arange(seqlen, device=device, dtype=torch.float32)
592
+ # We want fp32 here as well since inv_freq will be multiplied with t, and the output
593
+ # will be large. Having it in bf16 will lose a lot of precision and cause the
594
+ # cos & sin output to change significantly.
595
+ # We want to recompute self.inv_freq if it was not loaded in fp32
596
+ if self.inv_freq.dtype != torch.float32:
597
+ inv_freq = self._compute_inv_freq(device=device)
598
+ else:
599
+ inv_freq = self.inv_freq
600
+ else:
601
+ t = torch.arange(seqlen, device=device, dtype=self.inv_freq.dtype)
602
+ inv_freq = self.inv_freq
603
+ # Don't do einsum, it converts fp32 to fp16 under AMP
604
+ # freqs = torch.einsum("i,j->ij", t, self.inv_freq)
605
+ freqs = torch.outer(t, inv_freq)
606
+ self._cos_cached = torch.cos(freqs).to(dtype)
607
+ self._sin_cached = torch.sin(freqs).to(dtype)
608
+
609
+ def forward(
610
+ self,
611
+ qkv: torch.Tensor,
612
+ kv: Optional[torch.Tensor] = None,
613
+ seqlen_offset: Union[int, torch.Tensor] = 0,
614
+ max_seqlen: Optional[int] = None,
615
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
616
+ """
617
+ qkv: (batch, seqlen, 3, nheads, headdim) if kv is none,
618
+ else it's just q of shape (batch, seqlen, nheads, headdim)
619
+ kv: (batch, seqlen, 2, nheads, headdim)
620
+ seqlen_offset: (batch_size,) or int. Each sequence in x is shifted by this amount.
621
+ Most commonly used in inference when we have KV cache.
622
+ If it's a tensor of shape (batch_size,), then to update the cos / sin cache, one
623
+ should pass in max_seqlen, which will update the cos / sin cache up to that length.
624
+ Apply rotary embedding *inplace* to qkv and / or kv.
625
+ """
626
+ seqlen = qkv.shape[1]
627
+ if seqlen > self._seq_len_cached:
628
+ self._update_cos_sin_cache(seqlen, device=qkv.device, dtype=qkv.dtype)
629
+ elif max_seqlen is not None:
630
+ self._update_cos_sin_cache(max_seqlen, device=qkv.device, dtype=qkv.dtype)
631
+ elif isinstance(seqlen_offset, int):
632
+ self._update_cos_sin_cache(seqlen + seqlen_offset, device=qkv.device, dtype=qkv.dtype)
633
+
634
+ q_rot = apply_rotary_emb(qkv[:, :, 0], self._cos_cached, self._sin_cached, seqlen_offset, self.interleaved)
635
+ k_rot = apply_rotary_emb(qkv[:, :, 1], self._cos_cached, self._sin_cached, seqlen_offset, self.interleaved)
636
+ return torch.stack((q_rot, k_rot, qkv[:, :, 2]), dim=2)
637
+
638
+
639
+ class NomicBertDynamicNTKRotaryEmbedding(NomicBertRotaryEmbedding):
640
+ def __init__(self, rotary_scaling_factor, max_position_embeddings, **kwargs):
641
+ super().__init__(**kwargs)
642
+ self.rotary_scaling_factor = rotary_scaling_factor
643
+ self.max_position_embeddings = max_position_embeddings
644
+
645
+ def _compute_inv_freq(self, base=None, device=None):
646
+ if base is None:
647
+ base = self.base
648
+ return 1.0 / (base ** (torch.arange(0, self.dim, 2, device=device, dtype=torch.float32) / self.dim))
649
+
650
+ def _update_cos_sin_cache(self, seqlen, device=None, dtype=None):
651
+ # Reset the tables if the sequence length has changed,
652
+ # if we're on a new device (possibly due to tracing for instance),
653
+ # or if we're switching from inference mode to training
654
+ if seqlen > self.max_position_embeddings:
655
+ base = self.base * (
656
+ (self.rotary_scaling_factor * seqlen / self.max_position_embeddings) - (self.rotary_scaling_factor - 1)
657
+ ) ** (self.dim / (self.dim - 2))
658
+ inv_freq = self._compute_inv_freq(base=base, device=device)
659
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
660
+
661
+ if (
662
+ seqlen > self._seq_len_cached
663
+ or self._cos_cached is None
664
+ or self._cos_cached.device != device
665
+ or self._cos_cached.dtype != dtype
666
+ or (self.training and self._cos_cached.is_inference())
667
+ ):
668
+ self._seq_len_cached = seqlen
669
+ # We want fp32 here, not self.inv_freq.dtype, since the model could be loaded in bf16
670
+ # And the output of arange can be quite large, so bf16 would lose a lot of precision.
671
+ # However, for compatibility reason, we add an option to use the dtype of self.inv_freq.
672
+ if self.pos_idx_in_fp32:
673
+ t = torch.arange(seqlen, device=device, dtype=torch.float32)
674
+ # We want fp32 here as well since inv_freq will be multiplied with t, and the output
675
+ # will be large. Having it in bf16 will lose a lot of precision and cause the
676
+ # cos & sin output to change significantly.
677
+ # We want to recompute self.inv_freq if it was not loaded in fp32
678
+ if self.inv_freq.dtype != torch.float32:
679
+ if seqlen > self.max_position_embeddings:
680
+ base = self.base * (
681
+ (self.scaling_factor * seqlen / self.max_position_embeddings) - (self.scaling_factor - 1)
682
+ ) ** (self.dim / (self.dim - 2))
683
+ else:
684
+ base = self.base
685
+ inv_freq = self._compute_inv_freq(device=device, base=base)
686
+ else:
687
+ inv_freq = self.inv_freq
688
+ else:
689
+ t = torch.arange(seqlen, device=device, dtype=self.inv_freq.dtype)
690
+ inv_freq = self.inv_freq
691
+ # Don't do einsum, it converts fp32 to fp16 under AMP
692
+ # freqs = torch.einsum("i,j->ij", t, self.inv_freq)
693
+ freqs = torch.outer(t, inv_freq)
694
+ if self.scale is None:
695
+ self._cos_cached = torch.cos(freqs).to(dtype)
696
+ self._sin_cached = torch.sin(freqs).to(dtype)
697
+ else:
698
+ power = (
699
+ torch.arange(seqlen, dtype=self.scale.dtype, device=self.scale.device) - seqlen // 2
700
+ ) / self.scale_base
701
+ scale = self.scale.to(device=power.device) ** rearrange(power, "s -> s 1")
702
+ # We want the multiplication by scale to happen in fp32
703
+ self._cos_cached = (torch.cos(freqs) * scale).to(dtype)
704
+ self._sin_cached = (torch.sin(freqs) * scale).to(dtype)
705
+ self._cos_k_cached = (torch.cos(freqs) / scale).to(dtype)
706
+ self._sin_k_cached = (torch.sin(freqs) / scale).to(dtype)
707
+
708
+
709
+ class NomicBertAttention(nn.Module):
710
+ """Multi-head self-attention and cross-attention"""
711
+
712
+ def __init__(
713
+ self,
714
+ config,
715
+ ) -> None:
716
+ """
717
+ num_heads_kv: can be used to toggle MQA / GQA. If None, use num_heads.
718
+ return_residual: whether to return the input x along with the output. This is for
719
+ performance reason: for post-norm architecture, returning the input allows us
720
+ to fuse the backward of nn.Linear with the residual connection.
721
+ """
722
+ super().__init__()
723
+ self.embed_dim = config.n_embd
724
+ self.use_flash_attn = config.use_flash_attn
725
+ self.fused_bias_fc = config.fused_bias_fc
726
+
727
+ self.num_heads = config.n_head
728
+ self.num_heads_kv = config.num_heads_kv if getattr(config, "num_heads_kv", None) is not None else self.num_heads
729
+ assert self.embed_dim % self.num_heads == 0, "embed_dim must be divisible by num_heads"
730
+ self.head_dim = self.embed_dim // self.num_heads
731
+ # we don't really support mqa / gqa for now
732
+ qkv_dim = self.head_dim * (self.num_heads + 2 * self.num_heads_kv)
733
+
734
+ self.register_buffer(
735
+ "norm_factor",
736
+ torch.sqrt(torch.tensor(self.head_dim, dtype=torch.float32)).to(torch.get_default_dtype()),
737
+ persistent=False,
738
+ )
739
+
740
+ self.rotary_emb_dim = self.head_dim * config.rotary_emb_fraction
741
+ if self.rotary_emb_dim > 0:
742
+ if config.rotary_scaling_factor:
743
+ self.rotary_emb = NomicBertDynamicNTKRotaryEmbedding(
744
+ dim=self.rotary_emb_dim,
745
+ base=config.rotary_emb_base,
746
+ scale_base=config.rotary_emb_scale_base,
747
+ interleaved=config.rotary_emb_interleaved,
748
+ rotary_scaling_factor=config.rotary_scaling_factor,
749
+ max_position_embeddings=config.max_trained_positions,
750
+ )
751
+ else:
752
+ self.rotary_emb = NomicBertRotaryEmbedding(
753
+ dim=self.rotary_emb_dim,
754
+ base=config.rotary_emb_base,
755
+ scale_base=config.rotary_emb_scale_base,
756
+ interleaved=config.rotary_emb_interleaved,
757
+ )
758
+ # bug in xformers: https://github.com/facebookresearch/xformers/issues/841
759
+ # uses the head dimension instead of the sequence dimension
760
+ self.rotary_head_dim = getattr(config, "rotary_head_dim", False)
761
+
762
+ self.Wqkv = nn.Linear(self.embed_dim, qkv_dim, bias=config.qkv_proj_bias)
763
+
764
+ self.out_proj = nn.Linear(self.embed_dim, self.embed_dim, bias=config.qkv_proj_bias)
765
+ self.causal = config.causal
766
+ self.drop = nn.Dropout(config.attn_pdrop)
767
+
768
+ def forward(
769
+ self,
770
+ hidden_states: torch.Tensor,
771
+ attention_mask: Optional[torch.Tensor] = None,
772
+ position_ids: Optional[torch.LongTensor] = None,
773
+ past_key_value: Optional[Tuple[torch.Tensor]] = None,
774
+ output_attentions: bool = False,
775
+ use_cache: bool = False,
776
+ is_padded_inputs: Optional[bool] = True,
777
+ cu_seqlens: Optional[torch.Tensor] = None,
778
+ max_seq_len: Optional[int] = None,
779
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
780
+
781
+ has_layer_past = past_key_value is not None
782
+
783
+ if has_layer_past:
784
+ past_key_value = past_key_value[0]
785
+ past_len = past_key_value[1]
786
+ else:
787
+ past_len = 0
788
+
789
+ qkv = self.Wqkv(hidden_states)
790
+ qkv = rearrange(qkv, "... (three h d) -> ... three h d", three=3, d=self.head_dim)
791
+
792
+ past_key_value = (past_key_value, past_len + qkv.size(1)) if use_cache else None
793
+
794
+ if self.rotary_emb_dim > 0:
795
+ if self.rotary_head_dim:
796
+ qkv = rearrange(qkv, "b s three h d -> b h three s d")
797
+ qkv = self.rotary_emb(qkv, seqlen_offset=past_len)
798
+
799
+ if self.rotary_head_dim:
800
+ qkv = rearrange(qkv, "b h three s d -> b s three h d")
801
+
802
+ if _FLASH_AVAILABLE and hidden_states.is_cuda:
803
+ # --- Flash-attention varlen path ---
804
+ # flash_attn derives per-sequence lengths from ``cu_seqlens`` (built by
805
+ # unpad_input), so it consumes the raw bool [B, S] mask — NOT the
806
+ # additive [B, 1, 1, S] mask that get_extended_attention_mask makes.
807
+ # NomicBertModel.forward skips get_extended_attention_mask when flash is
808
+ # active and passes the bool mask straight through.
809
+ #
810
+ # Correctness keystone: RoPE was already applied above, on the dense
811
+ # [B, S, 3, H, D] tensor, BEFORE unpadding — so per-sequence positions
812
+ # stay correct. Applying RoPE after unpad would hand sequence 2 the
813
+ # absolute positions of sequence 1's tail and silently drift embeddings.
814
+ B, S = qkv.shape[0], qkv.shape[1]
815
+
816
+ # flash_attn requires fp16/bf16 inputs. sentence-transformers loads the
817
+ # weights as fp32 by default (it silently drops config.torch_dtype), so
818
+ # if the model is fp32 we cast qkv to bf16 for the flash call and cast
819
+ # the result back to the model dtype before out_proj. This makes the
820
+ # model work regardless of how it was loaded — no external cast needed.
821
+ orig_dtype = qkv.dtype
822
+ flash_dtype = (
823
+ orig_dtype if orig_dtype in (torch.float16, torch.bfloat16) else torch.bfloat16
824
+ )
825
+ if flash_dtype != orig_dtype:
826
+ qkv = qkv.to(flash_dtype)
827
+
828
+ if attention_mask is None:
829
+ bool_mask = torch.ones(B, S, device=qkv.device, dtype=torch.bool)
830
+ elif attention_mask.ndim == 4:
831
+ # Additive [B, 1, 1, S] mask leaked through (valid=0.0, pad≈finfo.min).
832
+ bool_mask = attention_mask.squeeze(1).squeeze(1) >= 0
833
+ else:
834
+ bool_mask = attention_mask.to(torch.bool)
835
+
836
+ qkv_u, indices, cu_s, max_s, *_ = unpad_input(qkv, bool_mask)
837
+ if max_s == 0:
838
+ raise RuntimeError(
839
+ "NomicBertAttention.forward: every sequence is empty (max_s == 0); "
840
+ "pre-filter empty inputs before encoding."
841
+ )
842
+ # causal=False: bidirectional encoder. Default softmax_scale is
843
+ # 1/sqrt(head_dim), numerically identical to / self.norm_factor above.
844
+ out_u = flash_attn_varlen_qkvpacked_func(
845
+ qkv_u, cu_s, max_s, dropout_p=0.0, causal=False
846
+ )
847
+ attn_output = pad_input(out_u, indices, B, S) # [B, S, H, D]
848
+ attn_output = attn_output.to(orig_dtype) # restore model dtype for out_proj
849
+ attn_output = rearrange(attn_output, "... h d -> ... (h d)")
850
+ return self.out_proj(attn_output)
851
+
852
+ # --- Eager path (fallback: CPU, or flash_attn unavailable) ---
853
+ # Byte-for-byte identical to nomic-ai/CodeRankEmbed upstream.
854
+ query, key, value = qkv[:, :, 0], qkv[:, :, 1], qkv[:, :, 2]
855
+
856
+ query = query.permute(0, 2, 1, 3)
857
+ key = key.permute(0, 2, 1, 3)
858
+ value = value.permute(0, 2, 1, 3)
859
+
860
+ attention_scores = torch.matmul(query, key.transpose(-1, -2)) / self.norm_factor
861
+ if attention_mask is not None:
862
+ attention_scores = attention_scores + attention_mask
863
+
864
+ attentions_probs = F.softmax(attention_scores, dim=-1)
865
+ attentions_probs = self.drop(attentions_probs)
866
+
867
+ attn_output = torch.matmul(attentions_probs, value)
868
+ attn_output = rearrange(attn_output.permute(0, 2, 1, 3), "... h d -> ... (h d)")
869
+
870
+ attn_output = self.out_proj(attn_output)
871
+
872
+ return attn_output
873
+
874
+
875
+ class NomicBertBlock(nn.Module):
876
+ def __init__(
877
+ self,
878
+ config,
879
+ ):
880
+ super().__init__()
881
+ self.prenorm = config.prenorm
882
+ self.fused_dropout_add_ln = config.fused_dropout_add_ln
883
+
884
+ self.attn = NomicBertAttention(config)
885
+ activation = (
886
+ F.sigmoid
887
+ if config.activation_function == "glu"
888
+ else (F.silu if config.activation_function == "swiglu" else F.gelu)
889
+ )
890
+ if config.activation_function in ["glu", "swiglu", "geglu"]:
891
+ self.mlp = NomciBertGatedMLP(
892
+ config.n_embd,
893
+ hidden_features=config.n_inner,
894
+ bias1=config.mlp_fc1_bias,
895
+ bias2=config.mlp_fc2_bias,
896
+ activation=activation,
897
+ fused_bias_fc=config.fused_bias_fc,
898
+ )
899
+ else:
900
+ self.mlp = NomicBertMLP(
901
+ config.n_embd,
902
+ hidden_features=config.n_inner,
903
+ bias1=config.mlp_fc1_bias,
904
+ bias2=config.mlp_fc2_bias,
905
+ activation=activation,
906
+ fused_bias_fc=config.fused_bias_fc,
907
+ )
908
+
909
+ self.dropout1 = nn.Dropout(config.resid_pdrop)
910
+ self.norm1 = nn.LayerNorm(config.n_embd, eps=config.layer_norm_epsilon)
911
+ self.norm2 = nn.LayerNorm(config.n_embd, eps=config.layer_norm_epsilon)
912
+ self.dropout2 = nn.Dropout(config.resid_pdrop)
913
+
914
+ def forward(
915
+ self,
916
+ hidden_states: torch.Tensor,
917
+ hidden_states2: torch.Tensor,
918
+ residual: Optional[torch.Tensor] = None,
919
+ attention_mask: Optional[torch.Tensor] = None,
920
+ position_ids: Optional[torch.LongTensor] = None,
921
+ past_key_value: Optional[Tuple[torch.Tensor]] = None,
922
+ is_padded_inputs: Optional[bool] = True,
923
+ output_attentions: Optional[bool] = False,
924
+ use_cache: Optional[bool] = False,
925
+ cu_seqlens: Optional[torch.Tensor] = None,
926
+ max_seq_len: Optional[int] = None,
927
+ ):
928
+ r"""Pass the input through the encoder layer.
929
+ Args:
930
+ hidden_states: the sequence to the encoder layer (required).
931
+ residual: if postnorm, residual=None, If prenorm, hidden_states = Attn/MLP(LN(residual))
932
+ mixer_subset: for cross-attention only. If not None, will take a subset of x
933
+ before applying the query projection. Useful for e.g., ViT where we only care
934
+ about the CLS token in the last layer.
935
+ """
936
+ if self.prenorm:
937
+ dropped = self.dropout1(hidden_states)
938
+ residual = (dropped + residual) if residual is not None else dropped
939
+ hidden_states = self.norm1(residual.to(dtype=self.norm1.weight.dtype))
940
+ hidden_states = self.attn(
941
+ hidden_states,
942
+ attention_mask=attention_mask,
943
+ is_padded_inputs=is_padded_inputs,
944
+ cu_seqlens=cu_seqlens,
945
+ max_seq_len=max_seq_len,
946
+ )
947
+
948
+ dropped = self.dropout2(hidden_states)
949
+ residual = (dropped + residual) if residual is not None else dropped
950
+ hidden_states = self.norm2(residual.to(dtype=self.norm2.weight.dtype))
951
+ hidden_states = self.mlp(hidden_states)
952
+
953
+ return hidden_states, None, residual
954
+ else:
955
+ assert residual is None
956
+ attn_outputs = self.attn(
957
+ hidden_states,
958
+ attention_mask=attention_mask,
959
+ is_padded_inputs=is_padded_inputs,
960
+ cu_seqlens=cu_seqlens,
961
+ max_seq_len=max_seq_len,
962
+ )
963
+ hidden_states = self.norm1((self.dropout1(attn_outputs) + hidden_states).to(dtype=self.norm1.weight.dtype))
964
+ mlp_out = self.mlp(hidden_states)
965
+
966
+ hidden_states = self.norm2((self.dropout2(mlp_out) + hidden_states).to(dtype=self.norm2.weight.dtype))
967
+ return hidden_states, None, None
968
+
969
+
970
+ class NomicBertEncoder(nn.Module):
971
+ def __init__(self, config: GPT2Config):
972
+ super().__init__()
973
+ self.layers = nn.ModuleList([NomicBertBlock(config) for _ in range(config.n_layer)])
974
+ self.gradient_checkpointing = False
975
+ self.config = config
976
+
977
+ def forward(
978
+ self,
979
+ hidden_states: torch.LongTensor = None,
980
+ attention_mask: Optional[torch.Tensor] = None,
981
+ position_ids: Optional[torch.LongTensor] = None,
982
+ past_key_values: Optional[List[torch.FloatTensor]] = None,
983
+ inputs_embeds: Optional[torch.FloatTensor] = None,
984
+ use_cache: Optional[bool] = None,
985
+ output_attentions: Optional[bool] = None,
986
+ output_hidden_states: Optional[bool] = None,
987
+ return_dict: Optional[bool] = None,
988
+ is_padded_inputs: Optional[bool] = True,
989
+ ):
990
+ """If subset_mask is not None, we only want output for the subset of the sequence.
991
+ This means that we only compute the last layer output for these tokens.
992
+ subset_mask: (batch, seqlen), dtype=torch.bool
993
+ """
994
+ hidden_states2 = None
995
+ residual = None
996
+
997
+ for _, layer in enumerate(self.layers):
998
+ if self.gradient_checkpointing and self.training:
999
+
1000
+ def create_custom_forward(module):
1001
+ def custom_forward(*inputs):
1002
+ # None for past_key_value
1003
+ return module(*inputs)
1004
+
1005
+ return custom_forward
1006
+
1007
+ hidden_states, hidden_states2, residual = torch.utils.checkpoint.checkpoint(
1008
+ create_custom_forward(layer),
1009
+ hidden_states,
1010
+ hidden_states2,
1011
+ residual,
1012
+ attention_mask,
1013
+ None,
1014
+ None,
1015
+ is_padded_inputs,
1016
+ # if you freeze ANY layers, you need `use_reentrant=False`
1017
+ # https://github.com/huggingface/transformers/issues/21381
1018
+ # https://discuss.pytorch.org/t/checkpoint-with-no-grad-requiring-inputs-problem/19117/7
1019
+ use_reentrant=False,
1020
+ )
1021
+
1022
+ else:
1023
+ hidden_states, hidden_states2, residual = layer(
1024
+ hidden_states,
1025
+ hidden_states2,
1026
+ residual,
1027
+ attention_mask,
1028
+ position_ids,
1029
+ None,
1030
+ is_padded_inputs,
1031
+ output_attentions,
1032
+ use_cache,
1033
+ )
1034
+ return hidden_states
1035
+
1036
+
1037
+ class NomicBertPooler(nn.Module):
1038
+ def __init__(self, config):
1039
+ super().__init__()
1040
+ self.dense = nn.Linear(config.n_embd, config.n_embd)
1041
+ self.activation = nn.Tanh()
1042
+
1043
+ def forward(self, hidden_states, pool=True):
1044
+ # We "pool" the model by simply taking the hidden state corresponding
1045
+ # to the first token.
1046
+ first_token_tensor = hidden_states[:, 0] if pool else hidden_states
1047
+ pooled_output = self.dense(first_token_tensor)
1048
+ pooled_output = self.activation(pooled_output)
1049
+ return pooled_output
1050
+
1051
+
1052
+ class NomicBertPredictionHeadTransform(nn.Module):
1053
+ def __init__(self, config):
1054
+ super().__init__()
1055
+ self.dense = nn.Linear(config.n_embd, config.n_embd, bias=config.mlp_fc1_bias)
1056
+ approximate = "tanh" if config.activation_function in ["gelu_new", "gelu_fast", "gelu_pytorch_tanh"] else "none"
1057
+ if config.activation_function == "swiglu":
1058
+ self.transform_act_fn = F.silu
1059
+ else:
1060
+ self.transform_act_fn = nn.GELU(approximate=approximate)
1061
+
1062
+ self.layer_norm = nn.LayerNorm(config.n_embd, eps=config.layer_norm_epsilon)
1063
+
1064
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
1065
+ hidden_states = self.dense(hidden_states)
1066
+ hidden_states = self.transform_act_fn(hidden_states)
1067
+ hidden_states = self.layer_norm(hidden_states)
1068
+
1069
+ return hidden_states
1070
+
1071
+
1072
+ class NomicBertLMPredictionHead(nn.Module):
1073
+ def __init__(self, config):
1074
+ super().__init__()
1075
+
1076
+ self.transform = NomicBertPredictionHeadTransform(config)
1077
+
1078
+ self.decoder = nn.Linear(config.n_embd, config.vocab_size, bias=config.mlp_fc1_bias)
1079
+
1080
+ def forward(self, hidden_states):
1081
+ hidden_states = self.transform(hidden_states)
1082
+ hidden_states = self.decoder(hidden_states)
1083
+ return hidden_states
1084
+
1085
+
1086
+ class NomicBertPreTrainingHeads(nn.Module):
1087
+ def __init__(self, config):
1088
+ super().__init__()
1089
+ self.predictions = NomicBertLMPredictionHead(config)
1090
+
1091
+ def forward(self, sequence_output):
1092
+ prediction_scores = self.predictions(sequence_output)
1093
+ return prediction_scores
1094
+
1095
+
1096
+ class NomicBertModel(NomicBertPreTrainedModel):
1097
+ def __init__(self, config: GPT2Config, add_pooling_layer=True):
1098
+ super().__init__(config)
1099
+ self.pad_vocab_size_multiple = getattr(config, "pad_vocab_size_multiple", 1)
1100
+ if config.vocab_size % self.pad_vocab_size_multiple != 0:
1101
+ config.vocab_size += self.pad_vocab_size_multiple - (config.vocab_size % self.pad_vocab_size_multiple)
1102
+
1103
+ assert config.activation_function in [
1104
+ "gelu",
1105
+ "gelu_new",
1106
+ "gelu_fast",
1107
+ "gelu_pytorch_tanh",
1108
+ "swiglu",
1109
+ "geglu",
1110
+ "glu",
1111
+ ]
1112
+
1113
+ self.embeddings = NomicBertEmbeddings(config)
1114
+ self.emb_drop = nn.Dropout(config.resid_pdrop)
1115
+ self.emb_ln = nn.LayerNorm(config.n_embd, eps=config.layer_norm_epsilon)
1116
+ self.encoder = NomicBertEncoder(config)
1117
+ self.pooler = NomicBertPooler(config) if add_pooling_layer else None
1118
+
1119
+ self.apply(partial(_init_weights, initializer_range=config.initializer_range))
1120
+
1121
+ def forward(
1122
+ self,
1123
+ input_ids,
1124
+ attention_mask=None,
1125
+ token_type_ids=None,
1126
+ position_ids=None,
1127
+ return_dict=None,
1128
+ ):
1129
+ if token_type_ids is None:
1130
+ token_type_ids = torch.zeros_like(input_ids)
1131
+ hidden_states = self.embeddings(input_ids, position_ids=position_ids, token_type_ids=token_type_ids)
1132
+ hidden_states = self.emb_ln(hidden_states)
1133
+ hidden_states = self.emb_drop(hidden_states)
1134
+
1135
+ if _FLASH_AVAILABLE and hidden_states.is_cuda:
1136
+ # Flash-varlen path: pass the raw bool [B, S] mask straight through.
1137
+ # Do NOT call get_extended_attention_mask here — it produces an
1138
+ # additive [B, 1, 1, S] mask that flash_attn (which derives lengths
1139
+ # from cu_seqlens via unpad_input) cannot consume.
1140
+ sequence_output = self.encoder(
1141
+ hidden_states, attention_mask=attention_mask, return_dict=return_dict
1142
+ )
1143
+ else:
1144
+ # Eager path: original additive [B, 1, 1, S] extended mask.
1145
+ attention_mask = self.get_extended_attention_mask(attention_mask, input_ids.shape)
1146
+ sequence_output = self.encoder(
1147
+ hidden_states, attention_mask=attention_mask, return_dict=return_dict
1148
+ )
1149
+
1150
+ pooled_output = self.pooler(sequence_output) if self.pooler is not None else None
1151
+
1152
+ return BaseModelOutputWithPoolingAndCrossAttentions(
1153
+ last_hidden_state=sequence_output,
1154
+ pooler_output=pooled_output,
1155
+ )
1156
+
1157
+
1158
+ class NomicBertForPreTraining(NomicBertPreTrainedModel):
1159
+ _tied_weights_keys = ["predictions.decoder.bias", "cls.predictions.decoder.weight"]
1160
+
1161
+ def __init__(self, config: GPT2Config):
1162
+ super().__init__(config)
1163
+
1164
+ self.bert = NomicBertModel(config, add_pooling_layer=getattr(config, "add_pooling_layer", False))
1165
+ self.cls = NomicBertPreTrainingHeads(config)
1166
+ self.mlm_loss = nn.CrossEntropyLoss()
1167
+
1168
+ # Initialize weights and apply final processing
1169
+ self.apply(partial(_init_weights, initializer_range=config.initializer_range))
1170
+ self.tie_weights()
1171
+
1172
+ def tie_weights(self):
1173
+ self.cls.predictions.decoder.weight = self.bert.embeddings.word_embeddings.weight
1174
+
1175
+ def forward(
1176
+ self,
1177
+ input_ids,
1178
+ position_ids=None,
1179
+ token_type_ids=None,
1180
+ attention_mask=None,
1181
+ labels=None,
1182
+ ):
1183
+ """
1184
+ If labels are provided, they must be -100 for masked out tokens (as specified in the attention
1185
+ mask).
1186
+ Outputs:
1187
+ if `labels` and `next_sentence_label` are not `None`:
1188
+ Outputs the total_loss which is the sum of the masked language modeling loss and the next
1189
+ sentence classification loss.
1190
+ if `labels` or `next_sentence_label` is `None`:
1191
+ Outputs a tuple comprising
1192
+ - the masked language modeling logits of shape [batch_size, sequence_length, vocab_size], and
1193
+ - the next sentence classification logits of shape [batch_size, 2].
1194
+ """
1195
+ outputs = self.bert(
1196
+ input_ids,
1197
+ position_ids=position_ids,
1198
+ token_type_ids=token_type_ids,
1199
+ attention_mask=attention_mask.bool() if attention_mask is not None else None,
1200
+ )
1201
+ sequence_output, _ = outputs.last_hidden_state, outputs.pooler_output
1202
+
1203
+ prediction_scores = self.cls(sequence_output)
1204
+
1205
+ total_loss = None
1206
+ if labels is not None:
1207
+ masked_lm_loss = self.mlm_loss(
1208
+ rearrange(prediction_scores, "... v -> (...) v"),
1209
+ rearrange(labels, "... -> (...)"),
1210
+ )
1211
+ total_loss = masked_lm_loss.float()
1212
+
1213
+ return MaskedLMOutput(
1214
+ loss=total_loss,
1215
+ logits=prediction_scores,
1216
+ hidden_states=outputs.hidden_states,
1217
+ attentions=None,
1218
+ )
1219
+
1220
+
1221
+ class NomicBertForSequenceClassification(NomicBertPreTrainedModel):
1222
+ def __init__(self, config):
1223
+ super().__init__(config)
1224
+ self.num_labels = config.num_labels
1225
+ self.config = config
1226
+
1227
+ self.bert = NomicBertModel(config)
1228
+ classifier_dropout = getattr(config, "classifier_dropout", config.embd_pdrop)
1229
+ self.dropout = nn.Dropout(classifier_dropout)
1230
+ self.classifier = nn.Linear(config.n_embd, config.num_labels)
1231
+
1232
+ # Initialize weights and apply final processing
1233
+ self.post_init()
1234
+
1235
+ def forward(
1236
+ self,
1237
+ input_ids: Optional[torch.Tensor] = None,
1238
+ attention_mask: Optional[torch.Tensor] = None,
1239
+ token_type_ids: Optional[torch.Tensor] = None,
1240
+ position_ids: Optional[torch.Tensor] = None,
1241
+ head_mask: Optional[torch.Tensor] = None,
1242
+ inputs_embeds: Optional[torch.Tensor] = None,
1243
+ labels: Optional[torch.Tensor] = None,
1244
+ output_attentions: Optional[bool] = None,
1245
+ output_hidden_states: Optional[bool] = None,
1246
+ return_dict: Optional[bool] = None,
1247
+ ):
1248
+ r"""
1249
+ labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
1250
+ Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
1251
+ config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
1252
+ `config.num_labels > 1` a classification loss is computed (Cross-Entropy).
1253
+ """
1254
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
1255
+ outputs = self.bert(
1256
+ input_ids,
1257
+ position_ids=position_ids,
1258
+ token_type_ids=token_type_ids,
1259
+ attention_mask=attention_mask.bool() if attention_mask is not None else None,
1260
+ )
1261
+
1262
+ pooled_output = outputs[1]
1263
+
1264
+ pooled_output = self.dropout(pooled_output)
1265
+ logits = self.classifier(pooled_output)
1266
+
1267
+ loss = None
1268
+ if labels is not None:
1269
+ if self.config.problem_type is None:
1270
+ if self.num_labels == 1:
1271
+ self.config.problem_type = "regression"
1272
+ elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int):
1273
+ self.config.problem_type = "single_label_classification"
1274
+ else:
1275
+ self.config.problem_type = "multi_label_classification"
1276
+
1277
+ if self.config.problem_type == "regression":
1278
+ loss_fct = nn.MSELoss()
1279
+ if self.num_labels == 1:
1280
+ loss = loss_fct(logits.squeeze(), labels.squeeze())
1281
+ else:
1282
+ loss = loss_fct(logits, labels)
1283
+ elif self.config.problem_type == "single_label_classification":
1284
+ loss_fct = nn.CrossEntropyLoss()
1285
+ loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
1286
+ elif self.config.problem_type == "multi_label_classification":
1287
+ loss_fct = nn.BCEWithLogitsLoss()
1288
+ loss = loss_fct(logits, labels)
1289
+ if not return_dict:
1290
+ output = (logits,) + outputs[2:]
1291
+ return ((loss,) + output) if loss is not None else output
1292
+
1293
+ return SequenceClassifierOutput(
1294
+ loss=loss,
1295
+ logits=logits,
1296
+ hidden_states=outputs.hidden_states,
1297
+ attentions=outputs.attentions,
1298
+ )
modules.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "idx": 0,
4
+ "name": "0",
5
+ "path": "",
6
+ "type": "sentence_transformers.models.Transformer"
7
+ },
8
+ {
9
+ "idx": 1,
10
+ "name": "1",
11
+ "path": "1_Pooling",
12
+ "type": "sentence_transformers.models.Pooling"
13
+ }
14
+ ]
sentence_bert_config.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "max_seq_length": 8192,
3
+ "do_lower_case": false,
4
+ "model_args": {
5
+ "add_pooling_layer": false,
6
+ "safe_serialization": true
7
+ }
8
+ }
special_tokens_map.json ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": {
3
+ "content": "[CLS]",
4
+ "lstrip": false,
5
+ "normalized": false,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "mask_token": {
10
+ "content": "[MASK]",
11
+ "lstrip": false,
12
+ "normalized": false,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "pad_token": {
17
+ "content": "[PAD]",
18
+ "lstrip": false,
19
+ "normalized": false,
20
+ "rstrip": false,
21
+ "single_word": false
22
+ },
23
+ "sep_token": {
24
+ "content": "[SEP]",
25
+ "lstrip": false,
26
+ "normalized": false,
27
+ "rstrip": false,
28
+ "single_word": false
29
+ },
30
+ "unk_token": {
31
+ "content": "[UNK]",
32
+ "lstrip": false,
33
+ "normalized": false,
34
+ "rstrip": false,
35
+ "single_word": false
36
+ }
37
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "[PAD]",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "100": {
12
+ "content": "[UNK]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "101": {
20
+ "content": "[CLS]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "102": {
28
+ "content": "[SEP]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "103": {
36
+ "content": "[MASK]",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "additional_special_tokens": [],
45
+ "clean_up_tokenization_spaces": true,
46
+ "cls_token": "[CLS]",
47
+ "do_lower_case": true,
48
+ "mask_token": "[MASK]",
49
+ "max_length": 512,
50
+ "model_max_length": 8192,
51
+ "pad_to_multiple_of": null,
52
+ "pad_token": "[PAD]",
53
+ "pad_token_type_id": 0,
54
+ "padding_side": "right",
55
+ "sep_token": "[SEP]",
56
+ "stride": 0,
57
+ "strip_accents": null,
58
+ "tokenize_chinese_chars": true,
59
+ "tokenizer_class": "BertTokenizer",
60
+ "truncation_side": "right",
61
+ "truncation_strategy": "longest_first",
62
+ "unk_token": "[UNK]"
63
+ }
vocab.txt ADDED
The diff for this file is too large to render. See raw diff