Taykhoom commited on
Commit
fed32ee
·
0 Parent(s):

Initial gLM2 Hugging Face port

Browse files
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ library_name: transformers
3
+ tags:
4
+ - biology
5
+ - genomics
6
+ - protein
7
+ - dna
8
+ - language-model
9
+ license: apache-2.0
10
+ datasets:
11
+ - tattabio/OMG
12
+ ---
13
+
14
+ # gLM-650M
15
+
16
+ Minimal HuggingFace port of the **650M** parameter variant of
17
+ [gLM2](https://huggingface.co/tattabio/gLM2_650M) -- a mixed-modality genomic
18
+ language model that encodes a genomic scaffold using both amino-acid and DNA
19
+ tokens. Pretrained with masked language modeling on the
20
+ [OMG dataset](https://huggingface.co/datasets/tattabio/OMG).
21
+
22
+ ## Architecture
23
+
24
+ | Parameter | Value |
25
+ |---|---|
26
+ | Layers | 33 |
27
+ | Attention heads | 20 |
28
+ | Embedding dimension | 1280 |
29
+ | FFN hidden dimension | 3584 (SwiGLU, multiple_of=256) |
30
+ | Vocabulary size | 37 |
31
+ | Positional encoding | RoPE (base=10000, non-interleaved) |
32
+ | Normalization | RMSNorm |
33
+ | Architecture | Pre-LN Transformer with SwiGLU FFN |
34
+ | Max sequence length | 4096 |
35
+
36
+ **Vocabulary:** `<cls>`, `<pad>`, `<eos>`, `<unk>`, the 25 amino-acid
37
+ letters (`L A G V S E R T I D P K Q N F Y M H W C X B U Z O`, uppercase),
38
+ the 4 DNA nucleotides (`a t c g`, lowercase), strand markers `<+>` / `<->`,
39
+ and `<mask>` / `<sep>`. Amino-acid and nucleotide tokens share the alphabet
40
+ by case (uppercase = amino acid, lowercase = nucleotide).
41
+
42
+ ## Pretraining
43
+
44
+ - **Objective:** Masked language modeling (30% mask rate)
45
+ - **Data:** [OMG dataset](https://huggingface.co/datasets/tattabio/OMG) (open
46
+ metagenomic corpus, semantically-deduplicated)
47
+ - **Pretraining tokens:** 315B (bfloat16, context length 4096)
48
+ - **Source checkpoint:** `tattabio/gLM2_650M`
49
+
50
+ ## Parity Verification
51
+
52
+ All 34 representation levels (embedding + 33 transformer blocks) verified to
53
+ be bit-exact (max abs diff = 0.00) against the original `tattabio/gLM2_650M`
54
+ weights with `attn_implementation="sdpa"`. The added eager and
55
+ `flash_attention_2` backends agree within fp32 kernel drift (maximum
56
+ full-network eager difference 1.22e-3) and bf16 cosine similarity >= 0.9997,
57
+ respectively. Verified on an NVIDIA H100 with PyTorch 2.7 / CUDA 12.
58
+
59
+ ## Related Models
60
+
61
+ See the full [gLM2 collection](https://huggingface.co/collections/Taykhoom/glm2-6a2e19be671ba44c163c617f).
62
+
63
+ | Model | Parameters | Notes |
64
+ |---|---|---|
65
+ | [gLM-150M](https://huggingface.co/Taykhoom/gLM-150M) | 150M | Smaller variant |
66
+ | **[gLM-650M](https://huggingface.co/Taykhoom/gLM-650M)** | 650M | This model |
67
+
68
+ ## Usage
69
+
70
+ ### Embedding generation
71
+
72
+ ```python
73
+ import torch
74
+ from transformers import AutoTokenizer, AutoModel
75
+
76
+ tokenizer = AutoTokenizer.from_pretrained("Taykhoom/gLM-650M", trust_remote_code=True)
77
+ model = AutoModel.from_pretrained("Taykhoom/gLM-650M", trust_remote_code=True)
78
+ model.eval()
79
+
80
+ # Canonical gLM2 input: amino acids (uppercase) + DNA (lowercase) + strand markers.
81
+ sequence = (
82
+ "<+>MALTKVEKRNRIKRRVRGKISGTQASPRLSVYKSNK"
83
+ "<+>aatttaaggaa"
84
+ "<->MLGIDNIERVKPGGLELVDRLVAVNRVTKVTKGGRAFGFSAIVVVGNED"
85
+ )
86
+ enc = tokenizer([sequence], return_tensors="pt")
87
+
88
+ with torch.no_grad():
89
+ out = model(**enc)
90
+
91
+ token_emb = out.last_hidden_state # (batch, seq_len, 1280)
92
+ mask = enc.attention_mask.unsqueeze(-1).to(token_emb.dtype)
93
+ mean_emb = (token_emb * mask).sum(1) / mask.sum(1) # masked mean pooling
94
+
95
+ # Intermediate layers
96
+ out_all = model(**enc, output_hidden_states=True)
97
+ layer16_emb = out_all.hidden_states[16] # after block 16
98
+ ```
99
+
100
+ The default tokenizer exactly preserves upstream case-sensitive semantics:
101
+ uppercase letters are amino acids, lowercase letters are nucleotides, and no
102
+ CLS or EOS token is inserted. Plain DNA/RNA preparation is available as an
103
+ opt-in convenience; it lowercases, replaces `U`/`u` with `t`, and prepends
104
+ `<+>`. The three calls below produce identical token sequences:
105
+
106
+ ```python
107
+ dna_tokenizer = AutoTokenizer.from_pretrained(
108
+ "Taykhoom/gLM-650M", trust_remote_code=True, auto_prepare_dna=True
109
+ )
110
+ dna_tokenizer(["ATCGATCG", "atcgatcg", "AUCGAUCG"], return_tensors="pt")
111
+ ```
112
+
113
+ ### MLM logits
114
+
115
+ ```python
116
+ from transformers import AutoTokenizer, AutoModelForMaskedLM
117
+
118
+ tokenizer = AutoTokenizer.from_pretrained("Taykhoom/gLM-650M", trust_remote_code=True)
119
+ model = AutoModelForMaskedLM.from_pretrained("Taykhoom/gLM-650M", trust_remote_code=True)
120
+ model.eval()
121
+
122
+ enc = tokenizer(["<+>MA<mask>K"], return_tensors="pt")
123
+ with torch.no_grad():
124
+ logits = model(**enc).logits # (1, seq_len, 37)
125
+ ```
126
+
127
+ ### Faster attention backends
128
+
129
+ ```python
130
+ # SDPA (PyTorch 2.0+, default upstream backend) -- recommended for fp32
131
+ model = AutoModel.from_pretrained("Taykhoom/gLM-650M", trust_remote_code=True,
132
+ attn_implementation="sdpa")
133
+
134
+ # Flash Attention 2 (requires flash-attn package) -- fastest on long sequences
135
+ model = AutoModel.from_pretrained("Taykhoom/gLM-650M", trust_remote_code=True,
136
+ attn_implementation="flash_attention_2",
137
+ dtype=torch.bfloat16)
138
+ ```
139
+
140
+ ### Fine-tuning
141
+
142
+ Standard HF conventions. For sequence-level tasks, pool over non-padding
143
+ positions before applying a prediction head. The tokenizer does not
144
+ automatically add a CLS token.
145
+
146
+ ## Implementation Notes
147
+
148
+ The original gLM2 implementation uses PyTorch SDPA as the only attention
149
+ backend. This HF port adds eager and `flash_attention_2` as separate
150
+ implementations selectable via `attn_implementation`, with eager falling back
151
+ automatically when `output_attentions=True` is requested.
152
+
153
+ The eager kernel computes the QK matmul and softmax in fp32 even when the
154
+ model is loaded in bf16, matching the numerical behaviour of SDPA and
155
+ `flash_attention_2` in mixed precision. When `output_attentions=True`, all
156
+ backends use eager attention and return fp32 post-softmax probabilities.
157
+
158
+ The tokenizer preserves the upstream mixed-modality and case-sensitive
159
+ behavior by default. Optional `auto_prepare_dna=True` is provided only for
160
+ callers that explicitly want plain DNA/RNA normalization. Strand markers are
161
+ exposed as additional special tokens so downstream masking utilities can
162
+ exclude them.
163
+
164
+ ## Citation
165
+
166
+ ```bibtex
167
+ @article{cornman2024_glm2,
168
+ title = {The {OMG} dataset: An Open MetaGenomic corpus for mixed-modality genomic language modeling},
169
+ author = {Cornman, Andre and West-Roberts, Jacob and Camargo, Antonio Pedro and Roux, Simon and Beracochea, Martin and Mirdita, Milot and Ovchinnikov, Sergey and Hwang, Yunha},
170
+ journal = {bioRxiv},
171
+ year = {2024},
172
+ doi = {10.1101/2024.08.14.607850}
173
+ }
174
+ ```
175
+
176
+ ## Credits
177
+
178
+ Original model and code by Cornman et al. (Tatta Bio). Source:
179
+ [GitHub](https://github.com/TattaBio/gLM2),
180
+ [`tattabio/gLM2_650M` on the Hub](https://huggingface.co/tattabio/gLM2_650M).
181
+ The HF conversion code was authored primarily by [Claude Code](https://claude.ai/code)
182
+ and reviewed manually by Taykhoom Dalal.
183
+
184
+ ## License
185
+
186
+ Apache 2.0, following the original repository.
config.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "gLM2ForMaskedLM"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_glm2.gLM2Config",
7
+ "AutoModel": "modeling_glm2.gLM2Model",
8
+ "AutoModelForMaskedLM": "modeling_glm2.gLM2ForMaskedLM"
9
+ },
10
+ "cls_token_id": 0,
11
+ "depth": 33,
12
+ "dim": 1280,
13
+ "dtype": "float32",
14
+ "eos_token_id": 2,
15
+ "ffn_dim_multiplier": null,
16
+ "heads": 20,
17
+ "initializer_range": 0.02,
18
+ "mask_token_id": 35,
19
+ "max_position_embeddings": 4096,
20
+ "model_type": "gLM2",
21
+ "norm_eps": 1e-05,
22
+ "pad_token_id": 1,
23
+ "swiglu_multiple_of": 256,
24
+ "tie_word_embeddings": false,
25
+ "transformers_version": "4.57.6",
26
+ "vocab_size": 37
27
+ }
configuration_glm2.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """gLM2 model configuration."""
2
+
3
+ from typing import Optional
4
+
5
+ from transformers import PretrainedConfig
6
+ from transformers.utils import logging
7
+
8
+ logger = logging.get_logger(__name__)
9
+
10
+
11
+ class gLM2Config(PretrainedConfig):
12
+ """Configuration class for gLM2.
13
+
14
+ Mirrors the hyperparameters in the official `tattabio/gLM2_*` checkpoints
15
+ plus the standard HuggingFace `PretrainedConfig` knobs.
16
+ """
17
+
18
+ model_type = "gLM2"
19
+
20
+ def __init__(
21
+ self,
22
+ dim: int = 640,
23
+ depth: int = 30,
24
+ heads: int = 10,
25
+ vocab_size: int = 37,
26
+ swiglu_multiple_of: int = 256,
27
+ ffn_dim_multiplier: Optional[float] = None,
28
+ norm_eps: float = 1e-5,
29
+ pad_token_id: int = 1,
30
+ cls_token_id: int = 0,
31
+ eos_token_id: int = 2,
32
+ mask_token_id: int = 35,
33
+ max_position_embeddings: int = 4096,
34
+ initializer_range: float = 0.02,
35
+ tie_word_embeddings: bool = False,
36
+ **kwargs,
37
+ ):
38
+ super().__init__(
39
+ pad_token_id=pad_token_id,
40
+ tie_word_embeddings=tie_word_embeddings,
41
+ **kwargs,
42
+ )
43
+ self.dim = dim
44
+ self.depth = depth
45
+ self.heads = heads
46
+ self.vocab_size = vocab_size
47
+ self.swiglu_multiple_of = swiglu_multiple_of
48
+ self.ffn_dim_multiplier = ffn_dim_multiplier
49
+ self.norm_eps = norm_eps
50
+ self.cls_token_id = cls_token_id
51
+ self.eos_token_id = eos_token_id
52
+ self.mask_token_id = mask_token_id
53
+ self.max_position_embeddings = max_position_embeddings
54
+ self.initializer_range = initializer_range
55
+
56
+ self.auto_map = {
57
+ "AutoConfig": "configuration_glm2.gLM2Config",
58
+ "AutoModel": "modeling_glm2.gLM2Model",
59
+ "AutoModelForMaskedLM": "modeling_glm2.gLM2ForMaskedLM",
60
+ }
glm_tokenizer.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tokenizer for gLM2.
2
+
3
+ Wraps a BPE-style fast tokenizer with the upstream `tattabio/gLM2_*` vocabulary
4
+ (amino acids, nucleotides, strand markers). The default behavior is identical
5
+ to upstream. Optional DNA preparation lets callers explicitly normalize plain
6
+ DNA/RNA strings without changing gLM2's case-sensitive mixed-modality syntax.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import re
12
+ from typing import List, Optional, Sequence, Union
13
+
14
+ from tokenizers import Tokenizer
15
+ from tokenizers.models import BPE
16
+ from transformers import PreTrainedTokenizerFast
17
+
18
+
19
+ _NUC_CHARS = set("acgtuACGTU")
20
+ _DNA_PREFIX_RE = re.compile(r"^\s*(<\+>|<->)")
21
+
22
+
23
+ def _is_pure_dna(seq: str) -> bool:
24
+ """True if `seq` only contains DNA/RNA characters (ATCGU, any case)."""
25
+ return len(seq) > 0 and all(c in _NUC_CHARS for c in seq)
26
+
27
+
28
+ def prepare_dna_sequence(seq: str, strand: str = "+") -> str:
29
+ """Normalize a plain DNA/RNA sequence for gLM2.
30
+
31
+ - Lower-cases nucleotides so they are tokenized as DNA (gLM2 uses
32
+ lower-case `a/t/c/g` for nucleotides; upper-case letters are amino
33
+ acids).
34
+ - Replaces `U`/`u` with `t` (gLM2's vocab has no uracil token).
35
+ - Prepends the strand marker (`<+>` or `<->`) if not already present.
36
+ """
37
+ if strand not in ("+", "-"):
38
+ raise ValueError(f"strand must be '+' or '-', got {strand!r}")
39
+ if _DNA_PREFIX_RE.match(seq):
40
+ return seq
41
+ cleaned = seq.lower().replace("u", "t")
42
+ return f"<{strand}>{cleaned}"
43
+
44
+
45
+ class gLM2Tokenizer(PreTrainedTokenizerFast):
46
+ """gLM2 fast tokenizer with opt-in automatic DNA preparation."""
47
+
48
+ model_input_names = ["input_ids", "attention_mask"]
49
+ VOCAB = [
50
+ "<cls>", "<pad>", "<eos>", "<unk>",
51
+ "L", "A", "G", "V", "S", "E", "R", "T", "I", "D", "P", "K",
52
+ "Q", "N", "F", "Y", "M", "H", "W", "C", "X", "B", "U", "Z",
53
+ "O", "a", "t", "c", "g", "<+>", "<->", "<mask>", "<sep>",
54
+ ]
55
+
56
+ def __init__(
57
+ self,
58
+ unk_token: str = "<unk>",
59
+ cls_token: str = "<cls>",
60
+ pad_token: str = "<pad>",
61
+ mask_token: str = "<mask>",
62
+ eos_token: str = "<eos>",
63
+ sep_token: str = "<sep>",
64
+ pos_token: str = "<+>",
65
+ neg_token: str = "<->",
66
+ additional_special_tokens: Optional[Sequence[str]] = None,
67
+ auto_prepare_dna: bool = False,
68
+ model_max_length: int = 4096,
69
+ **kwargs,
70
+ ):
71
+ additional_special_tokens = list(additional_special_tokens or [])
72
+ for strand_token in (pos_token, neg_token):
73
+ if strand_token not in additional_special_tokens:
74
+ additional_special_tokens.append(strand_token)
75
+ all_tokens = self.VOCAB
76
+ token_to_id = {tok: ind for ind, tok in enumerate(all_tokens)}
77
+
78
+ bpe = BPE(token_to_id, merges=[], unk_token=str(unk_token))
79
+ tokenizer = Tokenizer(bpe)
80
+ special_tokens = [
81
+ cls_token, pad_token, mask_token, eos_token, sep_token, pos_token, neg_token,
82
+ ]
83
+ tokenizer.add_special_tokens(special_tokens)
84
+
85
+ super().__init__(
86
+ tokenizer_object=tokenizer,
87
+ unk_token=unk_token,
88
+ cls_token=cls_token,
89
+ pad_token=pad_token,
90
+ mask_token=mask_token,
91
+ eos_token=eos_token,
92
+ sep_token=sep_token,
93
+ additional_special_tokens=additional_special_tokens,
94
+ model_max_length=model_max_length,
95
+ **kwargs,
96
+ )
97
+ self.auto_prepare_dna = auto_prepare_dna
98
+ self.init_kwargs["auto_prepare_dna"] = auto_prepare_dna
99
+
100
+ def _maybe_prepare(
101
+ self, text: Union[str, Sequence[str]]
102
+ ) -> Union[str, List[str]]:
103
+ if not self.auto_prepare_dna:
104
+ return text # type: ignore[return-value]
105
+ if isinstance(text, str):
106
+ return prepare_dna_sequence(text) if _is_pure_dna(text) else text
107
+ out: List[str] = []
108
+ for s in text:
109
+ if isinstance(s, str) and _is_pure_dna(s):
110
+ out.append(prepare_dna_sequence(s))
111
+ else:
112
+ out.append(s)
113
+ return out
114
+
115
+ def __call__(
116
+ self,
117
+ text: Union[str, Sequence[str], None] = None,
118
+ text_pair=None,
119
+ text_target=None,
120
+ text_pair_target=None,
121
+ *args,
122
+ **kwargs,
123
+ ):
124
+ if text is not None:
125
+ text = self._maybe_prepare(text)
126
+ return super().__call__(
127
+ text,
128
+ text_pair=text_pair,
129
+ text_target=text_target,
130
+ text_pair_target=text_pair_target,
131
+ *args,
132
+ **kwargs,
133
+ )
134
+
135
+ def encode(
136
+ self, text: Union[str, Sequence[str]], *args, **kwargs
137
+ ) -> List[int]:
138
+ text = self._maybe_prepare(text)
139
+ return super().encode(text, *args, **kwargs)
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5fe88d1327accf1480a9c410f667c499387c141ec777a3f77d8635d28efc524e
3
+ size 2682482800
modeling_glm2.py ADDED
@@ -0,0 +1,537 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """PyTorch gLM2 model.
2
+
3
+ Minimal HuggingFace port of tattabio/gLM2 with three attention implementations
4
+ (eager, sdpa, flash_attention_2) and standard HF outputs.
5
+
6
+ Architecture is unchanged from the upstream `tattabio/gLM2_*` checkpoints
7
+ (RMSNorm, rotary position embeddings, fused QKV, SwiGLU MLP). Weight names
8
+ match upstream so the same `model.safetensors` loads cleanly.
9
+ """
10
+
11
+ import math
12
+ from typing import Optional, Tuple, Union
13
+
14
+ import torch
15
+ import torch.nn.functional as F
16
+ from torch import nn
17
+ from torch.nn import CrossEntropyLoss
18
+
19
+ from transformers.modeling_outputs import BaseModelOutput, MaskedLMOutput
20
+ from transformers.modeling_utils import PreTrainedModel
21
+ from transformers.utils import logging
22
+
23
+ from .configuration_glm2 import gLM2Config
24
+
25
+ logger = logging.get_logger(__name__)
26
+
27
+
28
+ def rotate_half(x: torch.Tensor) -> torch.Tensor:
29
+ x1, x2 = x.chunk(2, dim=-1)
30
+ return torch.cat((-x2, x1), dim=-1)
31
+
32
+
33
+ def apply_rotary_emb_torch(
34
+ x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor
35
+ ) -> torch.Tensor:
36
+ """Apply rotary embeddings to `x`.
37
+
38
+ Args:
39
+ x: (batch, seqlen, nheads, headdim)
40
+ cos, sin: (seqlen, rotary_dim / 2) - rotary_dim must equal headdim.
41
+ """
42
+ seqlen = x.shape[1]
43
+ cos = cos[:seqlen]
44
+ sin = sin[:seqlen]
45
+ cos = cos.to(x.dtype)
46
+ sin = sin.to(x.dtype)
47
+ cos = cos.repeat_interleave(2, dim=-1) if False else torch.cat([cos, cos], dim=-1)
48
+ sin = torch.cat([sin, sin], dim=-1)
49
+ cos = cos.unsqueeze(-2)
50
+ sin = sin.unsqueeze(-2)
51
+ return x * cos + rotate_half(x) * sin
52
+
53
+
54
+ class RotaryEmbedding(nn.Module):
55
+ """Rotary position embeddings.
56
+
57
+ Identical numerics to the upstream `tattabio/gLM2_*` `RotaryEmbedding`
58
+ (non-interleaved, base 10000, no scaling), simplified to the path actually
59
+ used by the released checkpoints.
60
+ """
61
+
62
+ def __init__(self, dim: int, base: float = 10000.0):
63
+ super().__init__()
64
+ self.dim = dim
65
+ self.base = float(base)
66
+ inv_freq = 1.0 / (
67
+ self.base
68
+ ** (torch.arange(0, dim, 2, dtype=torch.float32) / dim)
69
+ )
70
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
71
+
72
+ self._seq_len_cached = 0
73
+ self._cos_cached: Optional[torch.Tensor] = None
74
+ self._sin_cached: Optional[torch.Tensor] = None
75
+
76
+ def _update_cache(self, seqlen: int, device: torch.device, dtype: torch.dtype) -> None:
77
+ if (
78
+ seqlen > self._seq_len_cached
79
+ or self._cos_cached is None
80
+ or self._cos_cached.device != device
81
+ or self._cos_cached.dtype != dtype
82
+ ):
83
+ self._seq_len_cached = seqlen
84
+ inv_freq = self.inv_freq
85
+ if inv_freq.dtype != torch.float32:
86
+ inv_freq = 1.0 / (
87
+ self.base
88
+ ** (
89
+ torch.arange(0, self.dim, 2, device=device, dtype=torch.float32)
90
+ / self.dim
91
+ )
92
+ )
93
+ t = torch.arange(seqlen, device=device, dtype=torch.float32)
94
+ freqs = torch.outer(t, inv_freq.to(device=device, dtype=torch.float32))
95
+ self._cos_cached = torch.cos(freqs).to(dtype)
96
+ self._sin_cached = torch.sin(freqs).to(dtype)
97
+
98
+ def forward(self, qkv: torch.Tensor) -> torch.Tensor:
99
+ """Apply rotary embeddings to q and k. v is left untouched.
100
+
101
+ Args:
102
+ qkv: (batch, seqlen, 3, nheads, headdim)
103
+ """
104
+ seqlen = qkv.shape[1]
105
+ self._update_cache(seqlen, device=qkv.device, dtype=qkv.dtype)
106
+ cos = self._cos_cached
107
+ sin = self._sin_cached
108
+ q_rot = apply_rotary_emb_torch(qkv[:, :, 0], cos, sin)
109
+ k_rot = apply_rotary_emb_torch(qkv[:, :, 1], cos, sin)
110
+ return torch.stack((q_rot, k_rot, qkv[:, :, 2]), dim=2)
111
+
112
+
113
+ def rmsnorm_func(
114
+ hidden_states: torch.Tensor, weight: torch.Tensor, variance_epsilon: torch.Tensor
115
+ ) -> torch.Tensor:
116
+ input_dtype = hidden_states.dtype
117
+ hidden_states = hidden_states.to(torch.float32)
118
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
119
+ hidden_states = hidden_states * torch.rsqrt(variance + variance_epsilon)
120
+ return (weight * hidden_states).to(input_dtype)
121
+
122
+
123
+ class RMSNorm(nn.Module):
124
+ """Root-mean-square layer norm."""
125
+
126
+ def __init__(self, dim: int, eps: float = 1e-6):
127
+ super().__init__()
128
+ self.weight = nn.Parameter(torch.ones(dim))
129
+ self.register_buffer(
130
+ "variance_epsilon", torch.tensor(eps), persistent=False
131
+ )
132
+
133
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
134
+ return rmsnorm_func(hidden_states, self.weight, self.variance_epsilon)
135
+
136
+
137
+ class gLM2Attention(nn.Module):
138
+ """Eager multi-head attention with rotary embeddings."""
139
+
140
+ def __init__(self, config: gLM2Config):
141
+ super().__init__()
142
+ self.n_heads = config.heads
143
+ self.head_dim = config.dim // config.heads
144
+ self.dim = config.dim
145
+
146
+ self.wqkv = nn.Linear(config.dim, self.n_heads * self.head_dim * 3, bias=False)
147
+ self.wo = nn.Linear(self.n_heads * self.head_dim, config.dim, bias=False)
148
+ self.rotary_emb = RotaryEmbedding(self.head_dim)
149
+
150
+ def _qkv(self, x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
151
+ bsz, seqlen, _ = x.shape
152
+ qkv = self.wqkv(x).view(bsz, seqlen, 3, self.n_heads, self.head_dim)
153
+ qkv = self.rotary_emb(qkv)
154
+ # qkv: (B, S, 3, H, D) -> (B, H, S, D) for q,k,v
155
+ qkv = qkv.permute(0, 3, 2, 1, 4) # (B, H, 3, S, D)
156
+ q = qkv[:, :, 0]
157
+ k = qkv[:, :, 1]
158
+ v = qkv[:, :, 2]
159
+ return q, k, v
160
+
161
+ def _output(self, attn_out: torch.Tensor) -> torch.Tensor:
162
+ # attn_out: (B, H, S, D) -> (B, S, H*D)
163
+ bsz, _, seqlen, _ = attn_out.shape
164
+ out = attn_out.permute(0, 2, 1, 3).contiguous().view(bsz, seqlen, self.n_heads * self.head_dim)
165
+ return self.wo(out)
166
+
167
+ def forward(
168
+ self,
169
+ x: torch.Tensor,
170
+ attention_mask: Optional[torch.Tensor] = None,
171
+ output_attentions: bool = False,
172
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
173
+ q, k, v = self._qkv(x)
174
+ scale = 1.0 / math.sqrt(self.head_dim)
175
+ # (B, H, S, S). Compute in fp32 for numerical stability under bf16/fp16
176
+ # (matches what flash-attn / SDPA do internally).
177
+ scores = torch.matmul(q.float(), k.float().transpose(-2, -1)) * scale
178
+ if attention_mask is not None:
179
+ mask = attention_mask[:, None, None, :]
180
+ scores = scores.masked_fill(mask == 0, torch.finfo(scores.dtype).min)
181
+ attn = scores.softmax(dim=-1)
182
+ # Keep returned probabilities in fp32 so their rows remain normalized
183
+ # under bf16/fp16. The context path below still returns activation dtype.
184
+ attn_for_return = attn if output_attentions else None
185
+ context = torch.matmul(attn, v.float()).to(q.dtype)
186
+ return self._output(context), attn_for_return
187
+
188
+
189
+ class gLM2SdpaAttention(gLM2Attention):
190
+ """SDPA-backed attention. Falls back to eager when output_attentions=True."""
191
+
192
+ def forward(
193
+ self,
194
+ x: torch.Tensor,
195
+ attention_mask: Optional[torch.Tensor] = None,
196
+ output_attentions: bool = False,
197
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
198
+ if output_attentions:
199
+ return super().forward(x, attention_mask=attention_mask, output_attentions=True)
200
+
201
+ q, k, v = self._qkv(x)
202
+ attn_mask = None
203
+ if attention_mask is not None:
204
+ # SDPA wants (B, 1, 1, S) bool mask where True = attend.
205
+ attn_mask = attention_mask[:, None, None, :].bool()
206
+ out = F.scaled_dot_product_attention(q, k, v, attn_mask=attn_mask)
207
+ return self._output(out), None
208
+
209
+
210
+ class gLM2FlashAttention2(gLM2Attention):
211
+ """flash-attn 2 backed attention. Falls back to eager when output_attentions=True."""
212
+
213
+ def forward(
214
+ self,
215
+ x: torch.Tensor,
216
+ attention_mask: Optional[torch.Tensor] = None,
217
+ output_attentions: bool = False,
218
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
219
+ if output_attentions:
220
+ return super().forward(x, attention_mask=attention_mask, output_attentions=True)
221
+
222
+ try:
223
+ from flash_attn import flash_attn_func, flash_attn_varlen_func
224
+ from flash_attn.bert_padding import pad_input, unpad_input
225
+ except ImportError as e:
226
+ raise ImportError(
227
+ "flash_attn is required for attn_implementation='flash_attention_2'. "
228
+ "Install with: pip install flash-attn --no-build-isolation"
229
+ ) from e
230
+
231
+ bsz, seqlen, _ = x.shape
232
+ qkv = self.wqkv(x).view(bsz, seqlen, 3, self.n_heads, self.head_dim)
233
+ qkv = self.rotary_emb(qkv)
234
+ # flash-attn wants (B, S, H, D) per q/k/v.
235
+ q = qkv[:, :, 0]
236
+ k = qkv[:, :, 1]
237
+ v = qkv[:, :, 2]
238
+
239
+ orig_dtype = q.dtype
240
+ if q.dtype not in (torch.float16, torch.bfloat16):
241
+ q = q.to(torch.bfloat16)
242
+ k = k.to(torch.bfloat16)
243
+ v = v.to(torch.bfloat16)
244
+
245
+ if attention_mask is not None and (attention_mask == 0).any():
246
+ attention_mask_bool = attention_mask.bool() # True = attend
247
+ q_unpad, indices_q, cu_q, max_q, _ = unpad_input(q, attention_mask_bool)
248
+ k_unpad, _, cu_k, max_k, _ = unpad_input(k, attention_mask_bool)
249
+ v_unpad, _, _, _, _ = unpad_input(v, attention_mask_bool)
250
+ out_unpad = flash_attn_varlen_func(
251
+ q_unpad,
252
+ k_unpad,
253
+ v_unpad,
254
+ cu_seqlens_q=cu_q,
255
+ cu_seqlens_k=cu_k,
256
+ max_seqlen_q=max_q,
257
+ max_seqlen_k=max_k,
258
+ causal=False,
259
+ )
260
+ out = pad_input(out_unpad, indices_q, bsz, seqlen)
261
+ else:
262
+ out = flash_attn_func(q, k, v, causal=False)
263
+
264
+ out = out.to(orig_dtype)
265
+ out = out.contiguous().view(bsz, seqlen, self.n_heads * self.head_dim)
266
+ return self.wo(out), None
267
+
268
+
269
+ GLM2_ATTENTION_CLASSES = {
270
+ "eager": gLM2Attention,
271
+ "sdpa": gLM2SdpaAttention,
272
+ "flash_attention_2": gLM2FlashAttention2,
273
+ }
274
+
275
+
276
+ class FeedForward(nn.Module):
277
+ """SwiGLU MLP."""
278
+
279
+ def __init__(
280
+ self,
281
+ dim: int,
282
+ hidden_dim: int,
283
+ multiple_of: int,
284
+ ffn_dim_multiplier: Optional[float],
285
+ ):
286
+ super().__init__()
287
+ hidden_dim = int(2 * hidden_dim / 3)
288
+ if ffn_dim_multiplier is not None:
289
+ hidden_dim = int(ffn_dim_multiplier * hidden_dim)
290
+ hidden_dim = multiple_of * ((hidden_dim + multiple_of - 1) // multiple_of)
291
+
292
+ self.w1 = nn.Linear(dim, hidden_dim, bias=False)
293
+ self.w2 = nn.Linear(hidden_dim, dim, bias=False)
294
+ self.w3 = nn.Linear(dim, hidden_dim, bias=False)
295
+
296
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
297
+ return self.w2(F.silu(self.w1(x)) * self.w3(x))
298
+
299
+
300
+ class TransformerBlock(nn.Module):
301
+ """Pre-norm transformer block."""
302
+
303
+ def __init__(self, config: gLM2Config):
304
+ super().__init__()
305
+ attn_impl = getattr(config, "_attn_implementation", "eager")
306
+ attn_cls = GLM2_ATTENTION_CLASSES[attn_impl]
307
+ self.attention = attn_cls(config)
308
+ self.feed_forward = FeedForward(
309
+ dim=config.dim,
310
+ hidden_dim=4 * config.dim,
311
+ multiple_of=config.swiglu_multiple_of,
312
+ ffn_dim_multiplier=config.ffn_dim_multiplier,
313
+ )
314
+ self.attention_norm = RMSNorm(config.dim, eps=config.norm_eps)
315
+ self.ffn_norm = RMSNorm(config.dim, eps=config.norm_eps)
316
+
317
+ def forward(
318
+ self,
319
+ x: torch.Tensor,
320
+ attention_mask: Optional[torch.Tensor] = None,
321
+ output_attentions: bool = False,
322
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
323
+ attn_out, attn_weights = self.attention(
324
+ self.attention_norm(x),
325
+ attention_mask=attention_mask,
326
+ output_attentions=output_attentions,
327
+ )
328
+ h = x + attn_out
329
+ out = h + self.feed_forward(self.ffn_norm(h))
330
+ return out, attn_weights
331
+
332
+
333
+ class TransformerLayers(nn.Module):
334
+ def __init__(self, config: gLM2Config):
335
+ super().__init__()
336
+ self.config = config
337
+ self.layers = nn.ModuleList(
338
+ [TransformerBlock(config) for _ in range(config.depth)]
339
+ )
340
+
341
+ def forward(
342
+ self,
343
+ x: torch.Tensor,
344
+ attention_mask: Optional[torch.Tensor] = None,
345
+ output_hidden_states: bool = False,
346
+ output_attentions: bool = False,
347
+ ) -> Tuple[torch.Tensor, Optional[Tuple[torch.Tensor, ...]], Optional[Tuple[torch.Tensor, ...]]]:
348
+ if x.shape[-1] != self.config.dim:
349
+ raise ValueError(
350
+ f"Input feature dim should be {self.config.dim}, but input has shape {x.shape}"
351
+ )
352
+ all_hidden_states: list = []
353
+ all_attentions: list = []
354
+ if output_hidden_states:
355
+ all_hidden_states.append(x)
356
+ for layer in self.layers:
357
+ x, attn_weights = layer(
358
+ x, attention_mask=attention_mask, output_attentions=output_attentions
359
+ )
360
+ if output_hidden_states:
361
+ all_hidden_states.append(x)
362
+ if output_attentions:
363
+ all_attentions.append(attn_weights)
364
+ hidden_tuple = tuple(all_hidden_states) if output_hidden_states else None
365
+ attn_tuple = tuple(all_attentions) if output_attentions else None
366
+ return x, hidden_tuple, attn_tuple
367
+
368
+
369
+ class gLM2PreTrainedModel(PreTrainedModel):
370
+ """Base class for gLM2 weight init / from_pretrained dispatch."""
371
+
372
+ config_class = gLM2Config
373
+ base_model_prefix = "glm2"
374
+ supports_gradient_checkpointing = False
375
+ _supports_sdpa = True
376
+ _supports_flash_attn_2 = True
377
+
378
+ def _init_weights(self, module):
379
+ std = getattr(self.config, "initializer_range", 0.02)
380
+ if isinstance(module, nn.Linear):
381
+ nn.init.normal_(module.weight, std=std)
382
+ if module.bias is not None:
383
+ nn.init.zeros_(module.bias)
384
+ elif isinstance(module, nn.Embedding):
385
+ nn.init.normal_(module.weight, std=std)
386
+ if module.padding_idx is not None:
387
+ with torch.no_grad():
388
+ module.weight[module.padding_idx].zero_()
389
+ elif isinstance(module, RotaryEmbedding):
390
+ inv_freq = 1.0 / (
391
+ module.base
392
+ ** (
393
+ torch.arange(
394
+ 0, module.dim, 2, device=module.inv_freq.device, dtype=torch.float32
395
+ )
396
+ / module.dim
397
+ )
398
+ )
399
+ with torch.no_grad():
400
+ module.inv_freq.copy_(inv_freq)
401
+ elif isinstance(module, RMSNorm):
402
+ with torch.no_grad():
403
+ module.variance_epsilon.fill_(self.config.norm_eps)
404
+
405
+
406
+ class gLM2Model(gLM2PreTrainedModel):
407
+ """gLM2 backbone (token embedding + transformer encoder)."""
408
+
409
+ def __init__(self, config: gLM2Config):
410
+ super().__init__(config)
411
+ self.config = config
412
+ self.tok_embeddings = nn.Embedding(config.vocab_size, config.dim)
413
+ self.encoder = TransformerLayers(config)
414
+ self.post_init()
415
+
416
+ def get_input_embeddings(self) -> nn.Embedding:
417
+ return self.tok_embeddings
418
+
419
+ def set_input_embeddings(self, value: nn.Embedding) -> None:
420
+ self.tok_embeddings = value
421
+
422
+ def forward(
423
+ self,
424
+ input_ids: torch.Tensor,
425
+ attention_mask: Optional[torch.Tensor] = None,
426
+ output_hidden_states: Optional[bool] = None,
427
+ output_attentions: Optional[bool] = None,
428
+ return_dict: Optional[bool] = None,
429
+ ) -> Union[Tuple[torch.Tensor, ...], BaseModelOutput]:
430
+ output_hidden_states = (
431
+ output_hidden_states
432
+ if output_hidden_states is not None
433
+ else self.config.output_hidden_states
434
+ )
435
+ output_attentions = (
436
+ output_attentions
437
+ if output_attentions is not None
438
+ else self.config.output_attentions
439
+ )
440
+ return_dict = (
441
+ return_dict if return_dict is not None else self.config.use_return_dict
442
+ )
443
+
444
+ h = self.tok_embeddings(input_ids)
445
+ sequence_output, all_hidden_states, all_attentions = self.encoder(
446
+ h,
447
+ attention_mask=attention_mask,
448
+ output_hidden_states=bool(output_hidden_states),
449
+ output_attentions=bool(output_attentions),
450
+ )
451
+
452
+ if not return_dict:
453
+ return tuple(
454
+ v
455
+ for v in (sequence_output, all_hidden_states, all_attentions)
456
+ if v is not None
457
+ )
458
+
459
+ return BaseModelOutput(
460
+ last_hidden_state=sequence_output,
461
+ hidden_states=all_hidden_states,
462
+ attentions=all_attentions,
463
+ )
464
+
465
+
466
+ class gLM2LMHead(nn.Module):
467
+ def __init__(self, config: gLM2Config):
468
+ super().__init__()
469
+ self.norm = RMSNorm(config.dim, eps=config.norm_eps)
470
+ self.proj_output = nn.Linear(config.dim, config.vocab_size, bias=False)
471
+
472
+ def forward(self, features: torch.Tensor) -> torch.Tensor:
473
+ return self.proj_output(self.norm(features))
474
+
475
+
476
+ class gLM2ForMaskedLM(gLM2PreTrainedModel):
477
+ """gLM2 with the masked-language-modeling head."""
478
+
479
+ _tied_weights_keys = []
480
+
481
+ def __init__(self, config: gLM2Config):
482
+ super().__init__(config)
483
+ self.glm2 = gLM2Model(config)
484
+ self.lm_head = gLM2LMHead(config)
485
+ self.post_init()
486
+
487
+ def get_output_embeddings(self) -> nn.Linear:
488
+ return self.lm_head.proj_output
489
+
490
+ def set_output_embeddings(self, new_embeddings: nn.Linear) -> None:
491
+ self.lm_head.proj_output = new_embeddings
492
+
493
+ def forward(
494
+ self,
495
+ input_ids: torch.Tensor,
496
+ attention_mask: Optional[torch.Tensor] = None,
497
+ labels: Optional[torch.LongTensor] = None,
498
+ output_hidden_states: Optional[bool] = None,
499
+ output_attentions: Optional[bool] = None,
500
+ return_dict: Optional[bool] = None,
501
+ ) -> Union[Tuple[torch.Tensor, ...], MaskedLMOutput]:
502
+ return_dict = (
503
+ return_dict if return_dict is not None else self.config.use_return_dict
504
+ )
505
+
506
+ outputs = self.glm2(
507
+ input_ids,
508
+ attention_mask=attention_mask,
509
+ output_hidden_states=output_hidden_states,
510
+ output_attentions=output_attentions,
511
+ return_dict=True,
512
+ )
513
+ sequence_output = outputs.last_hidden_state
514
+ prediction_scores = self.lm_head(sequence_output)
515
+
516
+ masked_lm_loss = None
517
+ if labels is not None:
518
+ loss_fct = CrossEntropyLoss()
519
+ labels = labels.to(prediction_scores.device)
520
+ masked_lm_loss = loss_fct(
521
+ prediction_scores.view(-1, self.config.vocab_size), labels.view(-1)
522
+ )
523
+
524
+ if not return_dict:
525
+ output = (prediction_scores,)
526
+ if outputs.hidden_states is not None:
527
+ output = output + (outputs.hidden_states,)
528
+ if outputs.attentions is not None:
529
+ output = output + (outputs.attentions,)
530
+ return ((masked_lm_loss,) + output) if masked_lm_loss is not None else output
531
+
532
+ return MaskedLMOutput(
533
+ loss=masked_lm_loss,
534
+ logits=prediction_scores,
535
+ hidden_states=outputs.hidden_states,
536
+ attentions=outputs.attentions,
537
+ )
special_tokens_map.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "<cls>",
3
+ "eos_token": "<eos>",
4
+ "mask_token": "<mask>",
5
+ "pad_token": "<pad>",
6
+ "sep_token": "<sep>",
7
+ "unk_token": "<unk>",
8
+ "additional_special_tokens": [
9
+ "<+>",
10
+ "<->"
11
+ ]
12
+ }
tokenizer.json ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "1.0",
3
+ "truncation": null,
4
+ "padding": null,
5
+ "added_tokens": [
6
+ {
7
+ "id": 0,
8
+ "content": "<cls>",
9
+ "single_word": false,
10
+ "lstrip": false,
11
+ "rstrip": false,
12
+ "normalized": false,
13
+ "special": true
14
+ },
15
+ {
16
+ "id": 1,
17
+ "content": "<pad>",
18
+ "single_word": false,
19
+ "lstrip": false,
20
+ "rstrip": false,
21
+ "normalized": false,
22
+ "special": true
23
+ },
24
+ {
25
+ "id": 2,
26
+ "content": "<eos>",
27
+ "single_word": false,
28
+ "lstrip": false,
29
+ "rstrip": false,
30
+ "normalized": false,
31
+ "special": true
32
+ },
33
+ {
34
+ "id": 3,
35
+ "content": "<unk>",
36
+ "single_word": false,
37
+ "lstrip": false,
38
+ "rstrip": false,
39
+ "normalized": false,
40
+ "special": true
41
+ },
42
+ {
43
+ "id": 33,
44
+ "content": "<+>",
45
+ "single_word": false,
46
+ "lstrip": false,
47
+ "rstrip": false,
48
+ "normalized": false,
49
+ "special": true
50
+ },
51
+ {
52
+ "id": 34,
53
+ "content": "<->",
54
+ "single_word": false,
55
+ "lstrip": false,
56
+ "rstrip": false,
57
+ "normalized": false,
58
+ "special": true
59
+ },
60
+ {
61
+ "id": 35,
62
+ "content": "<mask>",
63
+ "single_word": false,
64
+ "lstrip": false,
65
+ "rstrip": false,
66
+ "normalized": false,
67
+ "special": true
68
+ },
69
+ {
70
+ "id": 36,
71
+ "content": "<sep>",
72
+ "single_word": false,
73
+ "lstrip": false,
74
+ "rstrip": false,
75
+ "normalized": false,
76
+ "special": true
77
+ }
78
+ ],
79
+ "normalizer": null,
80
+ "pre_tokenizer": null,
81
+ "post_processor": null,
82
+ "decoder": null,
83
+ "model": {
84
+ "type": "BPE",
85
+ "dropout": null,
86
+ "unk_token": "<unk>",
87
+ "continuing_subword_prefix": null,
88
+ "end_of_word_suffix": null,
89
+ "fuse_unk": false,
90
+ "byte_fallback": false,
91
+ "ignore_merges": false,
92
+ "vocab": {
93
+ "<cls>": 0,
94
+ "<pad>": 1,
95
+ "<eos>": 2,
96
+ "<unk>": 3,
97
+ "L": 4,
98
+ "A": 5,
99
+ "G": 6,
100
+ "V": 7,
101
+ "S": 8,
102
+ "E": 9,
103
+ "R": 10,
104
+ "T": 11,
105
+ "I": 12,
106
+ "D": 13,
107
+ "P": 14,
108
+ "K": 15,
109
+ "Q": 16,
110
+ "N": 17,
111
+ "F": 18,
112
+ "Y": 19,
113
+ "M": 20,
114
+ "H": 21,
115
+ "W": 22,
116
+ "C": 23,
117
+ "X": 24,
118
+ "B": 25,
119
+ "U": 26,
120
+ "Z": 27,
121
+ "O": 28,
122
+ "a": 29,
123
+ "t": 30,
124
+ "c": 31,
125
+ "g": 32,
126
+ "<+>": 33,
127
+ "<->": 34,
128
+ "<mask>": 35,
129
+ "<sep>": 36
130
+ },
131
+ "merges": []
132
+ }
133
+ }
tokenizer_config.json ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "<cls>",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "1": {
12
+ "content": "<pad>",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "2": {
20
+ "content": "<eos>",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "3": {
28
+ "content": "<unk>",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "33": {
36
+ "content": "<+>",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ },
43
+ "34": {
44
+ "content": "<->",
45
+ "lstrip": false,
46
+ "normalized": false,
47
+ "rstrip": false,
48
+ "single_word": false,
49
+ "special": true
50
+ },
51
+ "35": {
52
+ "content": "<mask>",
53
+ "lstrip": false,
54
+ "normalized": false,
55
+ "rstrip": false,
56
+ "single_word": false,
57
+ "special": true
58
+ },
59
+ "36": {
60
+ "content": "<sep>",
61
+ "lstrip": false,
62
+ "normalized": false,
63
+ "rstrip": false,
64
+ "single_word": false,
65
+ "special": true
66
+ }
67
+ },
68
+ "auto_map": {
69
+ "AutoTokenizer": [
70
+ "glm_tokenizer.gLM2Tokenizer",
71
+ null
72
+ ]
73
+ },
74
+ "clean_up_tokenization_spaces": true,
75
+ "cls_token": "<cls>",
76
+ "eos_token": "<eos>",
77
+ "mask_token": "<mask>",
78
+ "model_max_length": 4096,
79
+ "pad_token": "<pad>",
80
+ "sep_token": "<sep>",
81
+ "tokenizer_class": "gLM2Tokenizer",
82
+ "unk_token": "<unk>",
83
+ "auto_prepare_dna": false,
84
+ "additional_special_tokens": [
85
+ "<+>",
86
+ "<->"
87
+ ]
88
+ }