Manolorsea commited on
Commit
c2cf68a
·
verified ·
1 Parent(s): 6f499a8

Initial release: CENO-1B-base (Apache-2.0)

Browse files

CENO base, 1B params (stage2), bfloat16. Bundles trust_remote_code model code + tokenizer. Derived from NVIDIA Nemotron-H (Apache-2.0); tokenizer derived from Arc Institute Evo2 CharLevelTokenizer (Apache-2.0).

LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or Derivative
95
+ Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
NOTICE ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CENO Checkpoint — CENO-1B-base
2
+ Copyright (c) 2025-2026 CENO Authors. All rights reserved.
3
+
4
+ This directory bundles a trained model checkpoint (CENO base model) together with a
5
+ copy of the CENO model code (configuration, modeling, and tokenizer modules).
6
+
7
+ The bundled model code is derived from NVIDIA's Nemotron-H HuggingFace
8
+ implementation, which is licensed under the Apache License, Version 2.0.
9
+ Nemotron-H is © NVIDIA Corporation. The CENO model code is a derivative work
10
+ distributed under the same Apache License, Version 2.0, included in this
11
+ directory as the `LICENSE` file.
12
+
13
+ The tokenizer module (`ceno_tokenizer.py`) is derived from Arc Institute's
14
+ Evo2 CharLevelTokenizer, which is licensed under the Apache License, Version 2.0.
15
+
16
+ All upstream copyright notices and license terms (NVIDIA; Arc Institute) are
17
+ preserved in the corresponding source files as required by the Apache License,
18
+ Version 2.0.
README.md ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ library_name: transformers
4
+ tags: ["dna", "genomics", "dna-language-model", "mamba", "moe"]
5
+ pipeline_tag: text-generation
6
+ language:
7
+ - dna
8
+ ---
9
+
10
+ # CENO-1B-base
11
+
12
+ **CENO-1B-base** is a checkpoint of the CENO base DNA foundation model (base (stage 2)). It is a plain causal language model over genomic sequence on a Nemotron-H Mamba/Attention/MoE hybrid backbone, with no MSA inputs.
13
+
14
+ This checkpoint is part of the **CENO** DNA foundation model family. The model
15
+ code, VEP pipeline, and generation demo live in the sibling [CENO code repository](https://github.com/CladeTeam/CENO); this
16
+ directory is standalone-loadable via `trust_remote_code=True` (the model code is
17
+ bundled here).
18
+
19
+ ## Model details
20
+
21
+ | | |
22
+ |---|---|
23
+ | Family | CENO (base) |
24
+ | Stage | base (stage 2) |
25
+ | Parameters | 1302.4M |
26
+ | Precision | bfloat16 |
27
+ | Weights | `model.safetensors` |
28
+ | `model_type` | `ceno` |
29
+ | `architectures` | `CENOForCausalLM` |
30
+ | `auto_map` → model | `modeling_ceno.CENOForCausalLM` |
31
+ | `auto_map` → tokenizer | `ceno_tokenizer.CENOCharLevelTokenizer` |
32
+
33
+ ### Architecture
34
+
35
+ | Hidden layers | 38 |
36
+ | Context length | 1048576 |
37
+ | Vocab size | 512 |
38
+ | Attention heads | 16 |
39
+ | Intermediate size | 4096 |
40
+ | Num experts (MoE) | 8 |
41
+ | Experts per token | 2 |
42
+
43
+ The backbone is a Mamba / Attention / Mixture-of-Experts hybrid (Nemotron-H
44
+ architecture). The tokenizer is byte-level (character-level), mapping DNA
45
+ characters to their ASCII byte codes (vocab size 512).
46
+
47
+ ## Loading
48
+
49
+ ```python
50
+ from transformers import AutoModelForCausalLM, AutoTokenizer
51
+
52
+ ckpt = "CENO-1B-base" # path to this directory
53
+ model = AutoModelForCausalLM.from_pretrained(ckpt, trust_remote_code=True)
54
+ tokenizer = AutoTokenizer.from_pretrained(ckpt, trust_remote_code=True)
55
+
56
+ ids = tokenizer.encode("ATCGATCG", return_tensors="pt")
57
+ # out = model.generate(ids, max_new_tokens=128) # needs a GPU (Mamba kernels)
58
+ ```
59
+
60
+ > The Mamba layers require CUDA kernels, so forward / generation needs a GPU.
61
+ > Config, tokenizer, and weight loading are CPU-safe.
62
+
63
+ ## Intended use
64
+
65
+ - **Base checkpoints (CENO-*)**: genomic-sequence generation and embedding
66
+ extraction; downstream adaptation (fine-tuning, probing) on genomics tasks.
67
+ - **MSA checkpoints (CENO-P-*)**: variant effect prediction (VEP) by scoring
68
+ wild-type vs. variant sequences with delta log-likelihood, using the MSA
69
+ scoring path. See the TraitGym VEP example in the [CENO code repository](https://github.com/CladeTeam/CENO).
70
+
71
+ ## License
72
+
73
+ Apache-2.0. The bundled model code is derived from NVIDIA's Nemotron-H
74
+ HuggingFace implementation (Apache-2.0); the tokenizer is derived from Arc
75
+ Institute's Evo2 CharLevelTokenizer (Apache-2.0). See the `LICENSE` and `NOTICE`
76
+ files in this directory for full attribution.
ceno_tokenizer.py ADDED
@@ -0,0 +1,571 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright (c) 2025, Arc Institute. All rights reserved.
3
+ # Copyright (c) 2026, CENO Team. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """Byte-level (character-level) tokenizer for CENO."""
17
+
18
+ import json
19
+ import os
20
+ from typing import List, Optional, Tuple, Union, Dict, Any
21
+ import numpy as np
22
+ import torch
23
+ from transformers import PreTrainedTokenizer
24
+ from transformers.tokenization_utils_base import BatchEncoding
25
+ from transformers.utils import logging
26
+
27
+ logger = logging.get_logger(__name__)
28
+
29
+ VOCAB_FILES_NAMES = {"vocab_file": "vocab.json"}
30
+
31
+
32
+ class CENOCharLevelTokenizer(PreTrainedTokenizer):
33
+ """
34
+ HuggingFace-style byte-level (character-level) tokenizer for CENO.
35
+
36
+ This tokenizer converts text directly to byte values using numpy's fromstring,
37
+ which is perfect for DNA sequences and other character-level tasks.
38
+
39
+ Args:
40
+ vocab_size (int): Size of the vocabulary (default: 512)
41
+ eos_token (str): End of sequence token
42
+ pad_token (str): Padding token
43
+ unk_token (str): Unknown token
44
+ **kwargs: Additional arguments passed to PreTrainedTokenizer
45
+ """
46
+
47
+ vocab_files_names = VOCAB_FILES_NAMES
48
+
49
+ def __init__(
50
+ self,
51
+ vocab_size: int = 512,
52
+ eos_token: str = "<eos>",
53
+ pad_token: str = "<pad>",
54
+ unk_token: str = "<unk>",
55
+ **kwargs
56
+ ):
57
+ self._vocab_size = vocab_size
58
+ self.eod_id = 0
59
+ self.eos_id = 0
60
+ self.pad_id = 1
61
+ self.unk_id = 2
62
+
63
+ # Build vocabulary - builds the CENO character mapping
64
+ self._vocab = self._build_vocab()
65
+ self._id_to_token = {v: k for k, v in self._vocab.items()}
66
+
67
+ super().__init__(
68
+ eos_token=eos_token,
69
+ pad_token=pad_token,
70
+ unk_token=unk_token,
71
+ **kwargs
72
+ )
73
+
74
+ def _build_vocab(self) -> Dict[str, int]:
75
+ """Build vocabulary mapping characters to IDs"""
76
+ vocab = {}
77
+
78
+ # Add special tokens
79
+ vocab["<unk>"] = 2
80
+ vocab["<pad>"] = 1
81
+ vocab["<eos>"] = 0
82
+
83
+ # Add printable ASCII characters (32-126)
84
+ for i in range(32, min(127, self._vocab_size)):
85
+ vocab[chr(i)] = i
86
+
87
+ # Add extended byte values as special tokens
88
+ for i in range(127, self._vocab_size):
89
+ vocab[f"<byte_{i}>"] = i
90
+
91
+ return vocab
92
+
93
+ def clamp(self, n: int) -> int:
94
+ """Clamp token ID to valid range, matching the CENO tokenizer implementation"""
95
+ return max(0, min(n, self._vocab_size - 1))
96
+
97
+ @property
98
+ def vocab_size(self) -> int:
99
+ """Return vocabulary size"""
100
+ return self._vocab_size
101
+
102
+ def get_vocab(self) -> Dict[str, int]:
103
+ """Return vocabulary dictionary"""
104
+ return self._vocab.copy()
105
+
106
+ def _tokenize(self, text: str) -> List[int]:
107
+ """
108
+ Tokenize text using numpy's fromstring (byte-level tokenization).
109
+ Byte-level tokenization: text is converted directly to its ASCII byte IDs.
110
+ """
111
+ # Convert text to byte array using numpy (matches the CENO implementation)
112
+ token_ids = np.frombuffer(text.encode("utf-8"), dtype=np.uint8).tolist()
113
+ return token_ids
114
+
115
+ def _convert_token_to_id(self, token: Union[str, int]) -> int:
116
+ """Convert token to ID"""
117
+ if isinstance(token, int):
118
+ return self.clamp(token)
119
+
120
+ # Handle string tokens
121
+ if token in self._vocab:
122
+ return self._vocab[token]
123
+
124
+ # Handle single characters
125
+ if len(token) == 1:
126
+ return self.clamp(ord(token))
127
+
128
+ # Handle byte tokens
129
+ if token.startswith("<byte_") and token.endswith(">"):
130
+ try:
131
+ byte_val = int(token[6:-1])
132
+ return self.clamp(byte_val)
133
+ except ValueError:
134
+ pass
135
+
136
+ # Return unknown token ID
137
+ return self._vocab.get(self.unk_token, 0)
138
+
139
+ def _convert_id_to_token(self, index: int) -> str:
140
+ """Convert ID to token, CENO decode-token behavior"""
141
+ clamped_index = self.clamp(index)
142
+
143
+ # Handle special cases before interpreting byte values.
144
+ if clamped_index == self.eos_id:
145
+ return self.eos_token
146
+ if clamped_index == self.pad_id:
147
+ return self.pad_token
148
+ if clamped_index == self.unk_id:
149
+ return self.unk_token
150
+
151
+ # Convert to character if in printable range
152
+ if 32 <= clamped_index <= 126:
153
+ return chr(clamped_index)
154
+
155
+ # Return byte token for extended range
156
+ return f"<byte_{clamped_index}>"
157
+
158
+ def convert_tokens_to_string(self, tokens: List[str]) -> str:
159
+ """Convert tokens back to string"""
160
+ result = []
161
+ for token in tokens:
162
+ if token in [self.pad_token, self.eos_token, self.unk_token]:
163
+ continue
164
+ elif token.startswith("<byte_") and token.endswith(">"):
165
+ try:
166
+ byte_val = int(token[6:-1])
167
+ result.append(chr(self.clamp(byte_val)))
168
+ except (ValueError, OverflowError):
169
+ continue
170
+ else:
171
+ result.append(token)
172
+ return "".join(result)
173
+
174
+ def tokenize(self, text: str, **kwargs) -> List[str]:
175
+ """
176
+ Tokenize text and return string tokens.
177
+ This wraps the numeric tokenization for HuggingFace compatibility.
178
+ """
179
+ # Get numeric tokens
180
+ numeric_tokens = self._tokenize(text)
181
+
182
+ # Convert to string tokens
183
+ string_tokens = [self._convert_id_to_token(token_id) for token_id in numeric_tokens]
184
+
185
+ return string_tokens
186
+
187
+ def encode(
188
+ self,
189
+ text: str,
190
+ add_special_tokens: bool = True,
191
+ padding: bool = False,
192
+ truncation: bool = False,
193
+ max_length: Optional[int] = None,
194
+ return_tensors: Optional[str] = None,
195
+ **kwargs
196
+ ) -> Union[List[int], torch.Tensor]:
197
+ """
198
+ Encode text to token IDs.
199
+ Core tokenization functionality of the CENO byte-level tokenizer.
200
+ """
201
+ # Tokenize to get numeric IDs directly
202
+ token_ids = self._tokenize(text)
203
+
204
+ # Handle truncation
205
+ if truncation and max_length is not None:
206
+ token_ids = token_ids[:max_length]
207
+
208
+ # Handle padding
209
+ if padding and max_length is not None:
210
+ if len(token_ids) < max_length:
211
+ token_ids.extend([self.pad_id] * (max_length - len(token_ids)))
212
+
213
+ # Convert to tensors if requested
214
+ if return_tensors == "pt":
215
+ return torch.tensor([token_ids], dtype=torch.long)
216
+ elif return_tensors == "np":
217
+ return np.array([token_ids], dtype=np.int64)
218
+
219
+ return token_ids
220
+
221
+ def decode(
222
+ self,
223
+ token_ids: Union[List[int], torch.Tensor, np.ndarray],
224
+ skip_special_tokens: bool = False,
225
+ clean_up_tokenization_spaces: bool = True,
226
+ **kwargs
227
+ ) -> str:
228
+ """
229
+ Decode token IDs back to text.
230
+ CENO detokenization.
231
+ """
232
+ # Convert to list if tensor or numpy array
233
+ if isinstance(token_ids, torch.Tensor):
234
+ token_ids = token_ids.tolist()
235
+ elif isinstance(token_ids, np.ndarray):
236
+ token_ids = token_ids.tolist()
237
+
238
+ # Convert IDs to tokens
239
+ tokens = [self._convert_id_to_token(token_id) for token_id in token_ids]
240
+
241
+ # Filter special tokens if requested
242
+ if skip_special_tokens:
243
+ tokens = [
244
+ token for token in tokens
245
+ if token not in [self.pad_token, self.eos_token, self.unk_token]
246
+ ]
247
+
248
+ # Convert tokens to string
249
+ return self.convert_tokens_to_string(tokens)
250
+
251
+ def batch_encode_plus(
252
+ self,
253
+ batch_text_or_text_pairs: Union[List[str], List[Tuple[str, str]]],
254
+ add_special_tokens: bool = True,
255
+ padding: bool = False,
256
+ truncation: bool = False,
257
+ max_length: Optional[int] = None,
258
+ return_tensors: Optional[str] = None,
259
+ **kwargs
260
+ ) -> BatchEncoding:
261
+ """Batch encode multiple texts"""
262
+ batch_outputs = []
263
+
264
+ for text in batch_text_or_text_pairs:
265
+ if isinstance(text, tuple):
266
+ # Handle text pairs (not typically used for DNA sequences)
267
+ text = text[0] # Just use first text for now
268
+
269
+ encoded = self.encode(
270
+ text,
271
+ add_special_tokens=add_special_tokens,
272
+ padding=False, # We'll handle padding after
273
+ truncation=truncation,
274
+ max_length=max_length,
275
+ return_tensors=None,
276
+ )
277
+ batch_outputs.append(encoded)
278
+
279
+ # Handle batch padding
280
+ if padding and max_length is not None:
281
+ max_len = max_length
282
+ elif padding:
283
+ max_len = max(len(output) for output in batch_outputs)
284
+ else:
285
+ max_len = None
286
+
287
+ if max_len is not None:
288
+ for i, output in enumerate(batch_outputs):
289
+ if len(output) < max_len:
290
+ batch_outputs[i] = output + [self.pad_id] * (max_len - len(output))
291
+ elif len(output) > max_len:
292
+ batch_outputs[i] = output[:max_len]
293
+
294
+ # Convert to tensors if requested
295
+ if return_tensors == "pt":
296
+ batch_outputs = torch.tensor(batch_outputs, dtype=torch.long)
297
+ elif return_tensors == "np":
298
+ batch_outputs = np.array(batch_outputs)
299
+
300
+ return BatchEncoding({"input_ids": batch_outputs})
301
+
302
+ def batch_decode(
303
+ self,
304
+ sequences: Union[List[List[int]], torch.Tensor, np.ndarray],
305
+ skip_special_tokens: bool = False,
306
+ clean_up_tokenization_spaces: bool = True,
307
+ **kwargs
308
+ ) -> List[str]:
309
+ """Batch decode multiple sequences"""
310
+ # Convert to list format
311
+ if isinstance(sequences, torch.Tensor):
312
+ sequences = sequences.tolist()
313
+ elif isinstance(sequences, np.ndarray):
314
+ sequences = sequences.tolist()
315
+
316
+ return [
317
+ self.decode(
318
+ sequence,
319
+ skip_special_tokens=skip_special_tokens,
320
+ clean_up_tokenization_spaces=clean_up_tokenization_spaces,
321
+ **kwargs
322
+ )
323
+ for sequence in sequences
324
+ ]
325
+
326
+ def save_pretrained(
327
+ self,
328
+ save_directory: str,
329
+ legacy_format: Optional[bool] = None,
330
+ filename_prefix: Optional[str] = None,
331
+ push_to_hub: bool = False,
332
+ **kwargs
333
+ ) -> Tuple[str]:
334
+ """
335
+ Save the tokenizer to a directory.
336
+
337
+ Args:
338
+ save_directory (str): Directory to save the tokenizer
339
+ legacy_format (bool, optional): Whether to save in legacy format
340
+ filename_prefix (str, optional): Prefix for filenames
341
+ push_to_hub (bool): Whether to push to HuggingFace Hub
342
+ **kwargs: Additional arguments
343
+
344
+ Returns:
345
+ Tuple[str]: Tuple of saved file paths
346
+ """
347
+ if not os.path.isdir(save_directory):
348
+ os.makedirs(save_directory, exist_ok=True)
349
+
350
+ # Save vocabulary
351
+ vocab_file = os.path.join(
352
+ save_directory,
353
+ (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]
354
+ )
355
+
356
+ with open(vocab_file, "w", encoding="utf-8") as f:
357
+ f.write(json.dumps(self._vocab, indent=2, sort_keys=True, ensure_ascii=False) + "\n")
358
+
359
+ # Save tokenizer configuration
360
+ config_file = os.path.join(
361
+ save_directory,
362
+ (filename_prefix + "-" if filename_prefix else "") + "tokenizer_config.json"
363
+ )
364
+
365
+ tokenizer_config = {
366
+ "tokenizer_class": "CENOCharLevelTokenizer",
367
+ "vocab_size": self._vocab_size,
368
+ "eos_token": self.eos_token,
369
+ "pad_token": self.pad_token,
370
+ "unk_token": self.unk_token,
371
+ "eod_id": self.eod_id,
372
+ "eos_id": self.eos_id,
373
+ "pad_id": self.pad_id,
374
+ "model_max_length": getattr(self, 'model_max_length', 1000000),
375
+ "clean_up_tokenization_spaces": True,
376
+ "tokenize_chinese_chars": False,
377
+ "strip_accents": None,
378
+ "do_lower_case": False,
379
+ "do_basic_tokenize": False,
380
+ "never_split": None,
381
+ "tokenizer_type": "CharLevelTokenizer",
382
+ "name_or_path": save_directory,
383
+ }
384
+
385
+ with open(config_file, "w", encoding="utf-8") as f:
386
+ json.dump(tokenizer_config, f, indent=2, ensure_ascii=False)
387
+
388
+ # Save special tokens map
389
+ special_tokens_file = os.path.join(
390
+ save_directory,
391
+ (filename_prefix + "-" if filename_prefix else "") + "special_tokens_map.json"
392
+ )
393
+
394
+ special_tokens_map = {
395
+ "eos_token": self.eos_token,
396
+ "pad_token": self.pad_token,
397
+ "unk_token": self.unk_token,
398
+ }
399
+
400
+ with open(special_tokens_file, "w", encoding="utf-8") as f:
401
+ json.dump(special_tokens_map, f, indent=2, ensure_ascii=False)
402
+
403
+ logger.info(f"Tokenizer saved to {save_directory}")
404
+
405
+ return (vocab_file, config_file, special_tokens_file)
406
+
407
+ @classmethod
408
+ def from_pretrained(
409
+ cls,
410
+ pretrained_model_name_or_path: Union[str, os.PathLike],
411
+ cache_dir: Optional[str] = None,
412
+ force_download: bool = False,
413
+ local_files_only: bool = False,
414
+ token: Optional[str] = None,
415
+ revision: str = "main",
416
+ **kwargs
417
+ ):
418
+ """
419
+ Load a tokenizer from a pretrained model.
420
+
421
+ Args:
422
+ pretrained_model_name_or_path (str): Path to directory containing tokenizer files
423
+ or name of a model on HuggingFace Hub
424
+ cache_dir (str, optional): Directory to cache downloaded files
425
+ force_download (bool): Whether to force download even if cached
426
+ local_files_only (bool): Whether to only use local files
427
+ token (str, optional): HuggingFace access token
428
+ revision (str): Model revision to use
429
+ **kwargs: Additional arguments
430
+
431
+ Returns:
432
+ CENOCharLevelTokenizer: Loaded tokenizer instance
433
+ """
434
+ # Handle local directory
435
+ if os.path.isdir(pretrained_model_name_or_path):
436
+ model_path = pretrained_model_name_or_path
437
+ else:
438
+ # Try to download from HuggingFace Hub
439
+ try:
440
+ from huggingface_hub import snapshot_download
441
+
442
+ model_path = snapshot_download(
443
+ repo_id=pretrained_model_name_or_path,
444
+ cache_dir=cache_dir,
445
+ force_download=force_download,
446
+ local_files_only=local_files_only,
447
+ token=token,
448
+ revision=revision,
449
+ )
450
+ except ImportError:
451
+ raise ImportError(
452
+ "huggingface_hub is required to download models from the Hub. "
453
+ "Install it with: pip install huggingface_hub"
454
+ )
455
+ except Exception as e:
456
+ logger.warning(f"Failed to download from HuggingFace Hub: {e}")
457
+ logger.warning("Falling back to local initialization...")
458
+ return cls(**kwargs)
459
+
460
+ # Load tokenizer configuration
461
+ config_file = os.path.join(model_path, "tokenizer_config.json")
462
+ config = {}
463
+
464
+ if os.path.exists(config_file):
465
+ with open(config_file, "r", encoding="utf-8") as f:
466
+ config = json.load(f)
467
+ logger.info(f"Loaded tokenizer config from {config_file}")
468
+
469
+ # Load special tokens map
470
+ special_tokens_file = os.path.join(model_path, "special_tokens_map.json")
471
+ special_tokens = {}
472
+
473
+ if os.path.exists(special_tokens_file):
474
+ with open(special_tokens_file, "r", encoding="utf-8") as f:
475
+ special_tokens = json.load(f)
476
+ logger.info(f"Loaded special tokens from {special_tokens_file}")
477
+
478
+ # Load vocabulary
479
+ vocab_file = os.path.join(model_path, VOCAB_FILES_NAMES["vocab_file"])
480
+ vocab = None
481
+
482
+ if os.path.exists(vocab_file):
483
+ with open(vocab_file, "r", encoding="utf-8") as f:
484
+ vocab = json.load(f)
485
+ logger.info(f"Loaded vocabulary from {vocab_file}")
486
+
487
+ # Merge configurations (kwargs override file config)
488
+ init_kwargs = {
489
+ "vocab_size": config.get("vocab_size", 512),
490
+ "eos_token": special_tokens.get("eos_token", config.get("eos_token", "<eos>")),
491
+ "pad_token": special_tokens.get("pad_token", config.get("pad_token", "<pad>")),
492
+ "unk_token": special_tokens.get("unk_token", config.get("unk_token", "<unk>")),
493
+ }
494
+
495
+ # Override with any provided kwargs
496
+ init_kwargs.update(kwargs)
497
+
498
+ # Create tokenizer instance
499
+ tokenizer = cls(**init_kwargs)
500
+
501
+ # Load custom vocabulary if available
502
+ if vocab is not None:
503
+ tokenizer._vocab = vocab
504
+ tokenizer._id_to_token = {v: k for k, v in vocab.items()}
505
+ logger.info("Loaded custom vocabulary")
506
+
507
+ # Set additional attributes from config
508
+ if config:
509
+ tokenizer.eod_id = config.get("eod_id", 0)
510
+ tokenizer.eos_id = config.get("eos_id", 0)
511
+ tokenizer.pad_id = config.get("pad_id", 1)
512
+ if hasattr(tokenizer, 'model_max_length'):
513
+ tokenizer.model_max_length = config.get("model_max_length", 1000000)
514
+
515
+ tokenizer.name_or_path = pretrained_model_name_or_path
516
+ logger.info(f"Successfully loaded tokenizer from {pretrained_model_name_or_path}")
517
+
518
+ return tokenizer
519
+
520
+ def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> Tuple[str]:
521
+ """Save vocabulary to file (legacy method)"""
522
+ if not os.path.isdir(save_directory):
523
+ logger.error(f"Vocabulary path ({save_directory}) should be a directory")
524
+ return
525
+
526
+ vocab_file = os.path.join(
527
+ save_directory,
528
+ (filename_prefix + "-" if filename_prefix else "") + VOCAB_FILES_NAMES["vocab_file"]
529
+ )
530
+
531
+ with open(vocab_file, "w", encoding="utf-8") as f:
532
+ f.write(json.dumps(self._vocab, indent=2, sort_keys=True, ensure_ascii=False) + "\n")
533
+
534
+ return (vocab_file,)
535
+
536
+ @property
537
+ def unique_identifiers(self) -> Dict[str,Any]:
538
+ """
539
+ Megatron will call .unique_identifiers when it encounters
540
+ this object during its JSON‐dump of the dataset config.
541
+ Must be JSON-serializable.
542
+ """
543
+ return {
544
+ "tokenizer_class": self.__class__.__name__,
545
+ "name_or_path": getattr(self, "name_or_path", None),
546
+ "vocab_size": self.vocab_size,
547
+ }
548
+ # Compatibility methods for the CENO tokenizer interface
549
+ def tokenize_batch(self, text_batch: Union[List[str], str]) -> Union[List[List[int]], List[int]]:
550
+ """Batch tokenization matching the CENO tokenizer interface"""
551
+ if isinstance(text_batch, str):
552
+ return self._tokenize(text_batch)
553
+ return [self._tokenize(text) for text in text_batch]
554
+
555
+ def detokenize(self, token_ids: Union[List[int], torch.Tensor]) -> str:
556
+ """Alias for decode method matching the CENO tokenizer interface"""
557
+ return self.decode(token_ids, skip_special_tokens=True)
558
+
559
+ def detokenize_batch(self, token_ids_batch: Union[List[List[int]], torch.Tensor]) -> List[str]:
560
+ """Batch detokenization matching the CENO tokenizer interface"""
561
+ return self.batch_decode(token_ids_batch, skip_special_tokens=True)
562
+
563
+ @property
564
+ def eod(self) -> int:
565
+ """End of document token ID"""
566
+ return self.eod_id
567
+
568
+ @property
569
+ def eos(self) -> int:
570
+ """End of sequence token ID"""
571
+ return self.eos_id
config.json ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "CENOForCausalLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "attention_head_dim": null,
8
+ "auto_map": {
9
+ "AutoConfig": "configuration_ceno.CENOConfig",
10
+ "AutoModelForCausalLM": "modeling_ceno.CENOForCausalLM",
11
+ "AutoTokenizer": [
12
+ "ceno_tokenizer.CENOCharLevelTokenizer",
13
+ null
14
+ ]
15
+ },
16
+ "bos_token_id": 0,
17
+ "chunk_size": 128,
18
+ "conv_kernel": 4,
19
+ "eos_token_id": 0,
20
+ "expand": 2,
21
+ "head_dim": 64,
22
+ "hidden_dropout": 0.0,
23
+ "hidden_size": 1024,
24
+ "hybrid_override_pattern": "MEMEM*EMEMEM*EMEMEMEMEM*EMEMEM*EMEMEME",
25
+ "initializer_range": 0.02,
26
+ "intermediate_size": 4096,
27
+ "layer_norm_epsilon": 1e-05,
28
+ "mamba_head_dim": 64,
29
+ "mamba_hidden_act": "silu",
30
+ "mamba_in_proj_layernorm": true,
31
+ "mamba_num_heads": 32,
32
+ "mamba_proj_bias": false,
33
+ "mamba_ssm_cache_dtype": "bfloat16",
34
+ "max_position_embeddings": 1048576,
35
+ "mlp_bias": false,
36
+ "mlp_fc1_layernorm": false,
37
+ "mlp_hidden_act": "relu2",
38
+ "mlp_use_swiglu": false,
39
+ "model_type": "ceno",
40
+ "moe_intermediate_size": 4096,
41
+ "moe_router_dtype": "bfloat16",
42
+ "moe_router_pre_softmax": false,
43
+ "moe_shared_expert_intermediate_size": 4096,
44
+ "moe_top_k": 2,
45
+ "n_group": 1,
46
+ "n_groups": 8,
47
+ "n_routed_experts": 8,
48
+ "n_shared_experts": 0,
49
+ "norm_topk_prob": true,
50
+ "num_attention_heads": 16,
51
+ "num_experts": 8,
52
+ "num_experts_per_tok": 2,
53
+ "num_hidden_layers": 38,
54
+ "num_key_value_heads": 16,
55
+ "num_logits_to_keep": 1,
56
+ "pad_token_id": 1,
57
+ "qkv_layernorm": true,
58
+ "rescale_prenorm_residual": true,
59
+ "residual_in_fp32": false,
60
+ "routed_scaling_factor": 1.0,
61
+ "sliding_window": null,
62
+ "ssm_state_size": 128,
63
+ "tie_word_embeddings": false,
64
+ "time_step_floor": 0.0001,
65
+ "time_step_limit": [
66
+ 0.0,
67
+ 1e30
68
+ ],
69
+ "time_step_max": 0.1,
70
+ "time_step_min": 0.001,
71
+ "topk_group": 1,
72
+ "torch_dtype": "bfloat16",
73
+ "transformers_version": "4.48.3",
74
+ "use_bias": false,
75
+ "use_cache": true,
76
+ "use_conv_bias": true,
77
+ "use_mamba_kernels": true,
78
+ "vocab_size": 512
79
+ }
configuration_ceno.py ADDED
@@ -0,0 +1,333 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2024 AI21 Labs Ltd. and the HuggingFace Inc. team. All rights reserved.
3
+ # Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
4
+ # Copyright (c) 2026, CENO Team. All rights reserved.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ """CENO model configuration"""
18
+
19
+ import re
20
+
21
+ from transformers.configuration_utils import PretrainedConfig
22
+ from transformers.utils import logging
23
+
24
+
25
+ logger = logging.get_logger(__name__)
26
+
27
+
28
+ class CENOConfig(PretrainedConfig):
29
+ r"""
30
+ This is the configuration class to store the configuration of a [`CENOModel`]. It is used to instantiate a
31
+ CENO model according to the specified arguments, defining the model architecture. Instantiating a configuration
32
+ with the defaults will yield a similar configuration to that of the CENO-v0.1 model.
33
+
34
+ [todo](todo)
35
+
36
+ Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
37
+ documentation from [`PretrainedConfig`] for more information.
38
+
39
+
40
+ Args:
41
+ vocab_size (`int`, *optional*, defaults to 131072):
42
+ Vocabulary size of the CENO model. Defines the number of different tokens that can be represented by the
43
+ `inputs_ids` passed when calling [`CENOModel`]
44
+ tie_word_embeddings (`bool`, *optional*, defaults to `False`):
45
+ Whether the model's input and output word embeddings should be tied. Note that this is only relevant if the
46
+ model has a output word embedding layer.
47
+ hidden_size (`int`, *optional*, defaults to 4096):
48
+ Dimension of the hidden representations.
49
+ intermediate_size (`int`, *optional*, defaults to 21504):
50
+ Dimension of the MLP representations.
51
+ num_hidden_layers (`int`, *optional*, defaults to 52):
52
+ Number of hidden layers in the Transformer encoder.
53
+ hybrid_override_pattern (`str`, *optional*, defaults to `"MMMM*MMMMM*MMMMM*MMMMM*MMMMMM"`):
54
+ The pattern of the hybrid model. The pattern is a string of characters where each character represents one layer: M=Mamba, *=Attention, -=MLP, E=MoE
55
+ num_attention_heads (`int`, *optional*, defaults to 32):
56
+ Number of attention heads for each attention layer in the Transformer encoder.
57
+ attention_head_dim (`int`, *optional*, defaults to 128):
58
+ Dimension of each attention head.
59
+ num_key_value_heads (`int`, *optional*, defaults to 8):
60
+ This is the number of key_value heads that should be used to implement Grouped Query Attention. If
61
+ `num_key_value_heads=num_attention_heads`, the model will use Multi Head Attention (MHA), if
62
+ `num_key_value_heads=1` the model will use Multi Query Attention (MQA) otherwise GQA is used.
63
+ mlp_hidden_act (`str`, *optional*, defaults to "relu2"):
64
+ The non-linear activation function in the MLP layers.
65
+ mlp_use_swiglu (`bool`, *optional*, defaults to `False`):
66
+ Whether to use SwiGLU activation (gated linear unit) in MLP layers.
67
+ num_experts (`int`, *optional*, defaults to 8):
68
+ Number of experts for MoE layers.
69
+ top_k (`int`, *optional*, defaults to 2):
70
+ Number of experts to select for each token in MoE layers.
71
+ attention_bias (`bool`, *optional*, defaults to `False`):
72
+ Whether to use bias in attention layers.
73
+ mlp_bias (`bool`, *optional*, defaults to `False`):
74
+ Whether to use bias in MLP layers.
75
+ use_bias (`bool`, *optional*, defaults to `False`):
76
+ Whether to use bias in the model.
77
+ initializer_range (`float`, *optional*, defaults to 0.02):
78
+ The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
79
+ layer_norm_epsilon (`float`, *optional*, defaults to 1e-5):
80
+ The epsilon used by the layer normalization layers.
81
+ residual_in_fp32 (`bool`, *optional*, defaults to `False`):
82
+ Whether or not residuals should be in `float32`. If set to `False` residuals will keep the same `dtype` as the rest of the model.
83
+ use_cache (`bool`, *optional*, defaults to `True`):
84
+ Whether or not the model should return the last key/values attentions (not used by all models). Only
85
+ relevant if `config.is_decoder=True`.
86
+ num_logits_to_keep (`int` or `None`, *optional*, defaults to 1):
87
+ Number of prompt logits to calculate during generation. If `None`, all logits will be calculated. If an
88
+ integer value, only last `num_logits_to_keep` logits will be calculated.
89
+ pad_token_id (`int`, *optional*, defaults to 0):
90
+ The id of the padding token.
91
+ bos_token_id (`int`, *optional*, defaults to 1):
92
+ The id of the "beginning-of-sequence" token.
93
+ eos_token_id (`int`, *optional*, defaults to 2):
94
+ The id of the "end-of-sequence" token.
95
+ sliding_window (`int`, *optional*, defaults to None):
96
+ Sliding window attention window size.
97
+ max_position_embeddings (`int`, *optional*, defaults to 4096):
98
+ The maximum sequence length that this model might ever be used with.
99
+ attention_dropout (`float`, *optional*, defaults to 0.0):
100
+ The dropout ratio for the attention probabilities.
101
+ hidden_dropout (`float`, *optional*, defaults to 0.0):
102
+ The dropout ratio for the hidden states.
103
+ use_mamba_kernels (`bool`, *optional*, defaults to `True`):
104
+ Flag indicating whether or not to use the fast mamba kernels. These are available only if `mamba-ssm` and
105
+ `causal-conv1d` are installed, and the mamba modules are running on a CUDA device.
106
+ ssm_state_size (`int`, *optional*, defaults to 128):
107
+ The dimension of the mamba state space latents.
108
+ mamba_num_heads (`int`, *optional*, defaults to 128):
109
+ Number of heads in Mamba layers.
110
+ mamba_n_groups (`int`, *optional*, defaults to 8):
111
+ Number of groups in Mamba layers.
112
+ mamba_head_dim (`int`, *optional*, defaults to 64):
113
+ Dimension of each Mamba head.
114
+ mamba_d_conv (`int`, *optional*, defaults to 4):
115
+ The size of the mamba convolution kernel.
116
+ mamba_expand (`int`, *optional*, defaults to 2):
117
+ Expanding factor used to determine the mamba intermediate size.
118
+ mamba_hidden_act (`str`, *optional*, defaults to "silu"):
119
+ The non-linear activation function in the Mamba layers.
120
+ mamba_dt_min (`float`, *optional*, defaults to 0.001):
121
+ Minimum value for the time step in Mamba.
122
+ mamba_dt_max (`float`, *optional*, defaults to 0.1):
123
+ Maximum value for the time step in Mamba.
124
+ mamba_dt_limit (`tuple`, *optional*, defaults to (0.0, float("inf"))):
125
+ Limits for the time step in Mamba.
126
+ mamba_dt_init_floor (`float`, *optional*, defaults to 1e-4):
127
+ Floor value for time step initialization in Mamba.
128
+ mamba_conv_bias (`bool`, *optional*, defaults to `True`):
129
+ Whether to use bias in the convolution layer of the mamba mixer block.
130
+ mamba_proj_bias (`bool`, *optional*, defaults to `False`):
131
+ Whether to use bias in the input and output projections of the mamba mixer block.
132
+ mamba_in_proj_layernorm (`bool`, *optional*, defaults to `False`):
133
+ Whether to apply an additional RMSNorm before the Mamba in-projection. This matches
134
+ Megatron's TELayerNormColumnParallelLinear fused Mamba in_proj norm when enabled.
135
+ mamba_chunk_size (`int`, *optional*, defaults to 256):
136
+ Size of chunks for Mamba processing.
137
+ rescale_prenorm_residual (`bool`, *optional*, defaults to `True`):
138
+ Whether to rescale the pre-normalization residual connections.
139
+ num_experts (`int`, *optional*, defaults to 8):
140
+ Number of experts in MoE layers.
141
+ moe_top_k (`int`, *optional*, defaults to 2):
142
+ Number of experts to route to in MoE layers (renamed from top_k to avoid generation config conflicts).
143
+ qkv_layernorm (`bool`, *optional*, defaults to `False`):
144
+ Whether to apply an additional RMSNorm before QKV projections in attention layers. This matches
145
+ Megatron's TELayerNormColumnParallelLinear fused QKV norm when enabled.
146
+ intra_encoding_pattern (`str`, *optional*, defaults to `None`):
147
+ Per-layer switch (length must equal `num_hidden_layers`) to control which layers use intra-sequence
148
+ isolation. Characters in `{1, Y, y, S, s, T, t, +}` enable isolation; `{0, N, n, F, f, ., -}` disable.
149
+ If omitted, intra-sequence isolation is disabled (legacy behavior).
150
+ """
151
+
152
+ model_type = "ceno"
153
+ keys_to_ignore_at_inference = ["past_key_values"]
154
+
155
+ def __init__(
156
+ self,
157
+ vocab_size=131072,
158
+ tie_word_embeddings=False,
159
+ hidden_size=4096,
160
+ intermediate_size=21504,
161
+ num_hidden_layers=52,
162
+ hybrid_override_pattern="MMMM*MMMMM*MMMMM*MMMMM*MMMMMM",
163
+ num_attention_heads=32,
164
+ attention_head_dim=128,
165
+ num_key_value_heads=8, # nemo: num_query_groups
166
+ mlp_hidden_act="relu2",
167
+ mlp_use_swiglu=False,
168
+ num_experts=8,
169
+ moe_top_k=2,
170
+ moe_router_pre_softmax=False,
171
+ attention_bias=False,
172
+ qkv_layernorm=False,
173
+ mlp_bias=False,
174
+ use_bias=False,
175
+ initializer_range=0.02, # nemo: init_method_std
176
+ layer_norm_epsilon=1e-5, # nemo: layernorm_epsilon
177
+ residual_in_fp32=False, # Megatron Core default value
178
+ use_cache=True,
179
+ num_logits_to_keep=1,
180
+ pad_token_id=1,
181
+ bos_token_id=0,
182
+ eos_token_id=0,
183
+ sliding_window=None,
184
+ max_position_embeddings=4096,
185
+ attention_dropout=0.0,
186
+ hidden_dropout=0.0, # * ADDED
187
+ use_mamba_kernels=True,
188
+ ssm_state_size=128, # mamba_state_size
189
+ mamba_num_heads=128,
190
+ mamba_n_groups=8, # nemo: mamba_ssm_ngroups = num_heads
191
+ mamba_head_dim=64,
192
+ mamba_d_conv=4,
193
+ mamba_expand=2,
194
+ mamba_hidden_act="silu",
195
+ mamba_dt_min=0.001,
196
+ mamba_dt_max=0.1,
197
+ mamba_dt_limit=(0.0, float("inf")),
198
+ mamba_dt_init_floor=1e-4,
199
+ mamba_conv_bias=True,
200
+ mamba_proj_bias=False,
201
+ mamba_in_proj_layernorm=False,
202
+ mamba_chunk_size=256,
203
+ rescale_prenorm_residual=True,
204
+ intra_encoding_pattern=None,
205
+ **kwargs,
206
+ ):
207
+ self.vocab_size = vocab_size
208
+ self.tie_word_embeddings = tie_word_embeddings
209
+ self.hidden_size = hidden_size
210
+ self.intermediate_size = intermediate_size
211
+ self.num_hidden_layers = num_hidden_layers
212
+ self.hybrid_override_pattern = hybrid_override_pattern
213
+ self.num_attention_heads = num_attention_heads
214
+ self.attention_head_dim = attention_head_dim
215
+ self.sliding_window = sliding_window
216
+ self.max_position_embeddings = max_position_embeddings
217
+ self.attention_dropout = attention_dropout
218
+ self.hidden_dropout = hidden_dropout
219
+ self.qkv_layernorm = qkv_layernorm
220
+
221
+ # Validate and process hybrid_override_pattern
222
+ # M: Mamba, *: Attention, -: MLP, E: MoE
223
+ if self.hybrid_override_pattern is None:
224
+ # Default pattern with even distribution of attention layers
225
+ self.hybrid_override_pattern = self._generate_default_pattern()
226
+
227
+ # Pattern should be a string where each character represents one layer
228
+ # No processing needed since '-' represents MLP layers, not separators
229
+
230
+ # For the default pattern, adjust it if num_hidden_layers doesn't match
231
+ if len(self.hybrid_override_pattern) != self.num_hidden_layers:
232
+ # If using default pattern and layers don't match, regenerate
233
+ if self.hybrid_override_pattern == "MMMM*MMMMM*MMMMM*MMMMM*MMMMMM":
234
+ self.hybrid_override_pattern = self._generate_default_pattern()
235
+ else:
236
+ # Only assert if it's a user-provided pattern
237
+ assert len(self.hybrid_override_pattern) == self.num_hidden_layers, f"hybrid_override_pattern length ({len(self.hybrid_override_pattern)}) must match num_hidden_layers ({self.num_hidden_layers})"
238
+
239
+ assert re.match(r"^[M*\-E]+$", self.hybrid_override_pattern), "hybrid_override_pattern must only contain characters 'M', '*', '-', or 'E'"
240
+
241
+ # for backward compatibility
242
+ if num_key_value_heads is None:
243
+ num_key_value_heads = num_attention_heads
244
+
245
+ self.num_key_value_heads = num_key_value_heads
246
+ self.mlp_hidden_act = mlp_hidden_act
247
+ self.mlp_use_swiglu = mlp_use_swiglu
248
+ self.num_experts = num_experts
249
+ self.moe_top_k = moe_top_k
250
+ # Megatron MoE routing: default is post-topk softmax (i.e., softmax after selecting top-k experts).
251
+ # This flag mirrors Megatron's `--moe-router-pre-softmax`.
252
+ self.moe_router_pre_softmax = moe_router_pre_softmax
253
+ self.attention_bias = attention_bias
254
+ self.mlp_bias = mlp_bias
255
+ self.use_bias = use_bias
256
+ self.initializer_range = initializer_range
257
+ self.layer_norm_epsilon = layer_norm_epsilon
258
+ self.residual_in_fp32 = residual_in_fp32
259
+
260
+ self.use_cache = use_cache
261
+ self.num_logits_to_keep = num_logits_to_keep
262
+
263
+ self.use_mamba_kernels = use_mamba_kernels
264
+ self.n_groups = mamba_n_groups
265
+ self.mamba_head_dim = mamba_head_dim
266
+ self.ssm_state_size = ssm_state_size
267
+ self.mamba_num_heads = mamba_num_heads
268
+ self.conv_kernel = mamba_d_conv
269
+ self.expand = mamba_expand
270
+ self.mamba_hidden_act = mamba_hidden_act
271
+ self.time_step_min = mamba_dt_min
272
+ self.time_step_max = mamba_dt_max
273
+ self.time_step_limit = mamba_dt_limit
274
+ self.time_step_floor = mamba_dt_init_floor
275
+ self.use_conv_bias = mamba_conv_bias
276
+ self.mamba_proj_bias = mamba_proj_bias
277
+ self.mamba_in_proj_layernorm = mamba_in_proj_layernorm
278
+ self.chunk_size = mamba_chunk_size
279
+ self.rescale_prenorm_residual = rescale_prenorm_residual
280
+ self.intra_encoding_pattern = intra_encoding_pattern
281
+
282
+ # MoE parameters
283
+ self.num_experts = num_experts
284
+ self.moe_top_k = moe_top_k
285
+
286
+ super().__init__(
287
+ pad_token_id=pad_token_id,
288
+ bos_token_id=bos_token_id,
289
+ eos_token_id=eos_token_id,
290
+ tie_word_embeddings=tie_word_embeddings,
291
+ **kwargs,
292
+ )
293
+
294
+ def _generate_default_pattern(self):
295
+ """Generate default hybrid pattern with even distribution of attention layers"""
296
+ # Default to mostly Mamba with some attention layers evenly distributed
297
+ pattern = ["M"] * self.num_hidden_layers
298
+
299
+ # Place attention layers at roughly even intervals
300
+ if self.num_hidden_layers >= 4:
301
+ # For larger models, place attention every 4-5 layers
302
+ attention_interval = max(4, self.num_hidden_layers // 8)
303
+ for i in range(attention_interval - 1, self.num_hidden_layers, attention_interval):
304
+ pattern[i] = "*"
305
+
306
+ return ''.join(pattern)
307
+
308
+ @property
309
+ def layers_block_type(self):
310
+ return [
311
+ "mamba" if self.hybrid_override_pattern[i] == "M" else
312
+ "attention" if self.hybrid_override_pattern[i] == "*" else
313
+ "mlp" if self.hybrid_override_pattern[i] == "-" else "moe"
314
+ for i in range(self.num_hidden_layers)]
315
+
316
+ @property
317
+ def intra_encoding_mask(self):
318
+ """
319
+ Per-layer boolean mask for intra-sequence isolation.
320
+ If `intra_encoding_pattern` is provided, it is used; otherwise isolation is disabled.
321
+ """
322
+ if getattr(self, "intra_encoding_pattern", None) is not None:
323
+ pat = self.intra_encoding_pattern
324
+ if len(pat) != self.num_hidden_layers:
325
+ raise ValueError(
326
+ f"intra_encoding_pattern length ({len(pat)}) must match num_hidden_layers ({self.num_hidden_layers})"
327
+ )
328
+ enable_set = {"1", "Y", "y", "S", "s", "T", "t", "+"}
329
+ disable_set = {"0", "N", "n", "F", "f", ".", "-"}
330
+ return [c in enable_set if c in enable_set.union(disable_set) else True for c in pat]
331
+
332
+ # Default/legacy: no intra-sequence isolation
333
+ return [False for _ in range(self.num_hidden_layers)]
generation_config.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 0,
4
+ "eos_token_id": 0,
5
+ "pad_token_id": 1,
6
+ "transformers_version": "4.48.3"
7
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6db638cac1731df53026df9f9ffe9820ec72c30a55894f5847eaf7103989eba4
3
+ size 2604919096
modeling_ceno.py ADDED
@@ -0,0 +1,2002 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2024 HuggingFace Inc. team.
3
+ # Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
4
+ # Copyright (c) 2026, CENO Team. All rights reserved.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ """PyTorch CENO model."""
18
+
19
+ import math
20
+ from dataclasses import dataclass
21
+ from typing import Any, Dict, Optional, Tuple, Union
22
+
23
+ import torch
24
+ import torch.utils.checkpoint
25
+ from torch import nn
26
+ from torch.nn import CrossEntropyLoss
27
+
28
+ from transformers.activations import ACT2FN
29
+ from transformers.cache_utils import DynamicCache # we need __iter__ and __len__ of pkv
30
+
31
+ # Define squared_relu / relu2 activation if not already in ACT2FN
32
+ def squared_relu(x: torch.Tensor) -> torch.Tensor:
33
+ """Squared ReLU activation: (max(0, x))^2"""
34
+ return torch.pow(torch.relu(x), 2)
35
+
36
+ # Register relu2/squared_relu in ACT2FN if not present
37
+ if "relu2" not in ACT2FN:
38
+ ACT2FN["relu2"] = squared_relu
39
+ if "squared_relu" not in ACT2FN:
40
+ ACT2FN["squared_relu"] = squared_relu
41
+ from transformers.generation.utils import GenerationMixin
42
+ from transformers.modeling_attn_mask_utils import (
43
+ AttentionMaskConverter,
44
+ )
45
+ from transformers.modeling_utils import PreTrainedModel
46
+ from transformers.utils import (
47
+ ModelOutput,
48
+ add_code_sample_docstrings,
49
+ add_start_docstrings,
50
+ add_start_docstrings_to_model_forward,
51
+ logging,
52
+ )
53
+ from transformers.utils.import_utils import (
54
+ is_causal_conv1d_available,
55
+ is_flash_attn_2_available,
56
+ is_flash_attn_greater_or_equal_2_10,
57
+ is_mamba_2_ssm_available,
58
+ )
59
+ try:
60
+ # Preferred import when using this repo as a package.
61
+ from ceno_hf.configuration_ceno import CENOConfig
62
+ except Exception:
63
+ try:
64
+ # Fallback for relative import contexts.
65
+ from .configuration_ceno import CENOConfig
66
+ except Exception:
67
+ # Last resort for running from within the directory.
68
+ from configuration_ceno import CENOConfig
69
+
70
+
71
+ logger = logging.get_logger(__name__)
72
+
73
+
74
+ # Copied from transformers.models.mamba.modeling_mamba2.modeling_mamba2.py with MAMBA2->CENO,Mamba2->CENO
75
+ # For Mamba2 components Mamba2->CENOMamba2
76
+ if is_mamba_2_ssm_available():
77
+ from mamba_ssm.ops.triton.selective_state_update import selective_state_update
78
+ from mamba_ssm.ops.triton.ssd_combined import mamba_chunk_scan_combined, mamba_split_conv1d_scan_combined
79
+ else:
80
+ mamba_chunk_scan_combined, mamba_split_conv1d_scan_combined, selective_state_update = None, None, None
81
+
82
+ try:
83
+ #from mamba_ssm.ops.triton.layernorm_gated import RMSNorm as RMSNormGated
84
+ from mamba_ssm.ops.triton.layernorm_gated import rmsnorm_fn
85
+ except Exception:
86
+ # mamba_ssm is optional at import time (it may fail to initialize on a
87
+ # GPU-less machine, e.g. triton driver init). The kernel is only needed
88
+ # inside MambaRMSNormGated.forward, so defer the hard error to call time.
89
+ rmsnorm_fn = None
90
+
91
+ if is_causal_conv1d_available():
92
+ from causal_conv1d import causal_conv1d_fn, causal_conv1d_update
93
+ else:
94
+ causal_conv1d_update, causal_conv1d_fn = None, None
95
+
96
+ if is_flash_attn_2_available():
97
+ from transformers.modeling_flash_attention_utils import _flash_attention_forward
98
+
99
+ is_fast_path_available = all(
100
+ (
101
+ selective_state_update,
102
+ mamba_chunk_scan_combined,
103
+ mamba_split_conv1d_scan_combined,
104
+ causal_conv1d_fn,
105
+ causal_conv1d_update,
106
+ )
107
+ )
108
+
109
+
110
+ def _supports_cuda_fast_path(device: torch.device) -> bool:
111
+ if not is_fast_path_available or device.type != "cuda" or not torch.cuda.is_available():
112
+ return False
113
+ try:
114
+ major, minor = torch.cuda.get_device_capability(device)
115
+ except Exception:
116
+ return False
117
+ return major >= 8
118
+
119
+
120
+ _CHECKPOINT_FOR_DOC = "nvidia/Nemotron-H-56B-Base-8K"
121
+ _CONFIG_FOR_DOC = "CENOConfig"
122
+
123
+
124
+ # Helper methods for segment sum computation
125
+
126
+
127
+ def pad_tensor_by_size(input_tensor: torch.Tensor, pad_size: int):
128
+ """
129
+ Padding x tensor with `pad_size` on the seq_len dim (dim=1)
130
+
131
+ Assumes that we only have tensors of either size 4 or 3
132
+ """
133
+ pad_shape = (0, 0, 0, 0, 0, pad_size, 0, 0) if len(input_tensor.shape) == 4 else (0, 0, 0, pad_size, 0, 0)
134
+
135
+ return torch.nn.functional.pad(input_tensor, pad_shape, mode="constant", value=0)
136
+
137
+
138
+ def reshape_into_chunks(input_tensor, pad_size, chunk_size):
139
+ """
140
+ Padding input_tensor with `pad_size` on the seq_len dim (dim=1) and
141
+ simultaneously splitting it into chunk sequences.
142
+
143
+ Assumes that we only have tensors of either size 4 or 3
144
+ """
145
+ # [bsz, seq_len, ...] -> [bsz, seq_len multiple of chunk_size, ...]
146
+ input_tensor = pad_tensor_by_size(input_tensor, pad_size)
147
+
148
+ if len(input_tensor.shape) == 3:
149
+ # [bsz, seq_len multiple of chunk_size, num_heads] -> [bsz, -1, chunk_size, num_heads]
150
+ return input_tensor.reshape(input_tensor.shape[0], -1, chunk_size, input_tensor.shape[2])
151
+ else:
152
+ # [bsz, seq_len multiple of chunk_size, num_heads, head_dim or state_size] -> [bsz, -1, chunk_size, num_heads, head_dim or state_size]
153
+ return input_tensor.reshape(
154
+ input_tensor.shape[0], -1, chunk_size, input_tensor.shape[2], input_tensor.shape[3]
155
+ )
156
+
157
+
158
+ def segment_sum(input_tensor):
159
+ """
160
+ More stable segment sum calculation. Uses cumulative sums and masking instead of direct subtractions.
161
+ """
162
+ chunk_size = input_tensor.size(-1)
163
+ # 1. expand input tensor to have an additional dimension and repeat along that dimension
164
+ # [..., chunk_size] -> [..., chunk_size, chunk_size]
165
+ input_tensor = input_tensor[..., None].expand(*input_tensor.size(), chunk_size)
166
+ # 2. create a lower triangular mask with the diagonal set to 0 to 0 out elements above diag
167
+ mask = torch.tril(torch.ones(chunk_size, chunk_size, device=input_tensor.device, dtype=torch.bool), diagonal=-1)
168
+ input_tensor = input_tensor.masked_fill(~mask, 0)
169
+ # 3. compute actual cumsum
170
+ tensor_segsum = torch.cumsum(input_tensor, dim=-2)
171
+
172
+ # 4. apply mask to keep only the lower triangular part of the cumulative sum result (incl diagonal this time)
173
+ mask = torch.tril(torch.ones(chunk_size, chunk_size, device=input_tensor.device, dtype=torch.bool), diagonal=0)
174
+ tensor_segsum = tensor_segsum.masked_fill(~mask, -torch.inf)
175
+ return tensor_segsum
176
+
177
+
178
+ def apply_mask_to_padding_states(hidden_states, attention_mask):
179
+ """
180
+ Tunes out the hidden states for padding tokens, see https://github.com/state-spaces/mamba/issues/66
181
+ """
182
+ if attention_mask is not None and attention_mask.shape[1] > 1 and attention_mask.shape[0] > 1:
183
+ dtype = hidden_states.dtype
184
+ hidden_states = (hidden_states * attention_mask[:, :, None]).to(dtype)
185
+
186
+ return hidden_states
187
+
188
+ # Copied from https://github.com/huggingface/transformers/blob/main/src/transformers/models/jamba/modeling_jamba.py
189
+ class HybridMambaAttentionDynamicCache(DynamicCache):
190
+ """
191
+ A dynamic cache that can handle both the attention cache (which has a seq_len dimension) and the mamba cache
192
+ (which has a constant shape regardless of seq_len).
193
+
194
+ This cache has two sets of lists of tensors: `key_cache` and `value_cache` for attention cache and `conv_states`
195
+ and `ssm_states` for mamba cache. Each of these lists has `num_layers` tensors. The expected shape for each tensor
196
+ For attention layers, `key_cache` and `value_cache` have a shape of `(batch_size, num_heads, seq_len, head_dim)`,
197
+ while `conv_states` and `ssm_states` have a shape of `(batch_size, 0)` (empty tensors).
198
+ For mamba layers, `key_cache` and `value_cache` have a shape of `(batch_size, 0)` (empty tensors),
199
+ while `conv_states` represents the convolution state and has a shape of `(batch_size, d_inner, d_conv)`,
200
+ and `ssm_states` represents the ssm state and has a shape of `(batch_size, d_inner, d_state)`.
201
+ """
202
+
203
+ def __init__(self, config, batch_size, dtype=torch.float16, device=None):
204
+ super().__init__()
205
+ self.dtype = dtype
206
+ self.hybrid_override_pattern = config.hybrid_override_pattern
207
+ self.has_previous_state = False # only used by mamba
208
+ intermediate_size = config.expand * config.hidden_size
209
+ ssm_state_size = config.ssm_state_size
210
+ conv_kernel_size = config.conv_kernel
211
+ self.conv_kernel_size = conv_kernel_size
212
+ self.conv_states = []
213
+ self.ssm_states = []
214
+ self.transformer_layers = []
215
+ self.attention_layers = []
216
+ for i in range(config.num_hidden_layers):
217
+ if self.hybrid_override_pattern[i] == "M":
218
+ # Mamba layer
219
+ self.conv_states += [
220
+ torch.zeros(batch_size, intermediate_size, conv_kernel_size, device=device, dtype=dtype)
221
+ ]
222
+ self.ssm_states += [
223
+ torch.zeros(batch_size, intermediate_size, ssm_state_size, device=device, dtype=dtype)
224
+ ]
225
+ else:
226
+ # Attention or MLP layer
227
+ self.conv_states += [torch.tensor([[]] * batch_size, device=device)]
228
+ self.ssm_states += [torch.tensor([[]] * batch_size, device=device)]
229
+ self.transformer_layers.append(i)
230
+ if self.hybrid_override_pattern[i] == "*":
231
+ self.attention_layers.append(i)
232
+
233
+ self.key_cache = [torch.tensor([[]] * batch_size, device=device) for _ in range(config.num_hidden_layers)]
234
+ self.value_cache = [torch.tensor([[]] * batch_size, device=device) for _ in range(config.num_hidden_layers)]
235
+
236
+ def update(
237
+ self,
238
+ key_states: torch.Tensor,
239
+ value_states: torch.Tensor,
240
+ layer_idx: int,
241
+ cache_kwargs: Optional[Dict[str, Any]] = None,
242
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
243
+ # Update the cache
244
+ if self.key_cache[layer_idx].shape[-1] == 0:
245
+ self.key_cache[layer_idx] = key_states
246
+ self.value_cache[layer_idx] = value_states
247
+ else:
248
+ self.key_cache[layer_idx] = torch.cat([self.key_cache[layer_idx], key_states], dim=2)
249
+ self.value_cache[layer_idx] = torch.cat([self.value_cache[layer_idx], value_states], dim=2)
250
+
251
+ return self.key_cache[layer_idx], self.value_cache[layer_idx]
252
+
253
+ def reorder_cache(self, beam_idx: torch.LongTensor):
254
+ """Reorders the cache for beam search, given the selected beam indices."""
255
+ for layer_idx in range(len(self.key_cache)):
256
+ device = self.key_cache[layer_idx].device
257
+ self.key_cache[layer_idx] = self.key_cache[layer_idx].index_select(0, beam_idx.to(device))
258
+ device = self.value_cache[layer_idx].device
259
+ self.value_cache[layer_idx] = self.value_cache[layer_idx].index_select(0, beam_idx.to(device))
260
+
261
+ device = self.conv_states[layer_idx].device
262
+ self.conv_states[layer_idx] = self.conv_states[layer_idx].index_select(0, beam_idx.to(device))
263
+ device = self.ssm_states[layer_idx].device
264
+ self.ssm_states[layer_idx] = self.ssm_states[layer_idx].index_select(0, beam_idx.to(device))
265
+
266
+ def get_seq_length(self, layer_idx: Optional[int] = 0) -> int:
267
+ """Returns the sequence length of the cached states. A layer index can be optionally passed."""
268
+ if self.attention_layers:
269
+ # Prefer an attention layer with a populated cache.
270
+ if layer_idx in self.attention_layers and self.key_cache[layer_idx].numel() > 0:
271
+ return self.key_cache[layer_idx].shape[-2]
272
+ for attn_idx in self.attention_layers:
273
+ if self.key_cache[attn_idx].numel() > 0:
274
+ return self.key_cache[attn_idx].shape[-2]
275
+ return 0
276
+ # Fallback for models without attention layers.
277
+ if layer_idx in self.transformer_layers:
278
+ return self.key_cache[layer_idx].shape[-2] if self.key_cache[layer_idx].numel() > 0 else 0
279
+ if self.transformer_layers:
280
+ idx = self.transformer_layers[0]
281
+ return self.key_cache[idx].shape[-2] if self.key_cache[idx].numel() > 0 else 0
282
+ return 0
283
+
284
+ def to_legacy_cache(self) -> Tuple[Tuple[torch.Tensor], Tuple[torch.Tensor]]:
285
+ raise NotImplementedError("HybridMambaAttentionDynamicCache does not have a legacy cache equivalent.")
286
+
287
+ @classmethod
288
+ def from_legacy_cache(cls, past_key_values: Optional[Tuple[Tuple[torch.FloatTensor]]] = None) -> "DynamicCache":
289
+ raise NotImplementedError("HybridMambaAttentionDynamicCache does not have a legacy cache equivalent.")
290
+
291
+ # Copied from modeling_mamba2.py
292
+ def update_conv_state(
293
+ self, layer_idx: int, new_conv_state: torch.Tensor, cache_init: bool = False
294
+ ) -> torch.Tensor:
295
+ if cache_init:
296
+ target_device = self.conv_states[layer_idx].device
297
+ self.conv_states[layer_idx] = new_conv_state.to(target_device)
298
+ else:
299
+ self.conv_states[layer_idx] = self.conv_states[layer_idx].roll(shifts=-1, dims=-1)
300
+ target_device = self.conv_states[layer_idx].device
301
+ self.conv_states[layer_idx][:, :, -1] = new_conv_state[:, 0, :].to(target_device)
302
+ return self.conv_states[layer_idx]
303
+
304
+ def update_ssm_state(self, layer_idx: int, new_ssm_state: torch.Tensor):
305
+ target_device = self.ssm_states[layer_idx].device
306
+ self.ssm_states[layer_idx] = new_ssm_state.to(target_device)
307
+ return self.ssm_states[layer_idx]
308
+
309
+ def reset(self):
310
+ self.conv_states.zero_()
311
+ self.ssm_states.zero_()
312
+
313
+ class MambaRMSNormGated(torch.nn.Module):
314
+ def __init__(self, hidden_size, group_size, eps=1e-5):
315
+ super().__init__()
316
+ self.weight = nn.Parameter(torch.ones(hidden_size))
317
+ self.variance_epsilon = eps
318
+ self.group_size = group_size
319
+
320
+ # jan28b version
321
+ def forward(self, hidden_states, gate=None):
322
+ if rmsnorm_fn is None:
323
+ input_dtype = hidden_states.dtype
324
+ x = hidden_states.float()
325
+ if gate is not None:
326
+ x = x * torch.nn.functional.silu(gate.float())
327
+ if self.group_size and x.shape[-1] % self.group_size == 0:
328
+ x = x.reshape(*x.shape[:-1], -1, self.group_size)
329
+ x = x * torch.rsqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.variance_epsilon)
330
+ x = x.reshape(*x.shape[:-2], -1)
331
+ else:
332
+ x = x * torch.rsqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.variance_epsilon)
333
+ return (x * self.weight.float()).to(input_dtype)
334
+ return rmsnorm_fn(x=hidden_states,
335
+ weight=self.weight,
336
+ bias=None, # No bias
337
+ z=gate,
338
+ eps=self.variance_epsilon,
339
+ group_size=self.group_size,
340
+ norm_before_gate=False
341
+ )
342
+
343
+ class CENOMamba2Mixer(nn.Module):
344
+ """
345
+ Compute ∆, A, B, C, and D the state space parameters and compute the `contextualized_states`.
346
+ A, D are input independent (see Mamba paper [1] Section 3.5.2 "Interpretation of A" for why A isn't selective)
347
+ ∆, B, C are input-dependent (this is a key difference between Mamba and the linear time invariant S4,
348
+ and is why Mamba is called **selective** state spaces)
349
+ """
350
+
351
+ def __init__(self, config: CENOConfig, layer_idx: int):
352
+ super().__init__()
353
+ self.config = config
354
+ self.num_heads = config.mamba_num_heads
355
+ self.hidden_size = config.hidden_size
356
+ self.ssm_state_size = config.ssm_state_size
357
+ self.conv_kernel_size = config.conv_kernel
358
+ self.intermediate_size = config.mamba_num_heads * config.mamba_head_dim
359
+ self.layer_idx = layer_idx
360
+ self.use_conv_bias = config.use_conv_bias
361
+ self.activation = config.mamba_hidden_act
362
+ self.act = ACT2FN[config.mamba_hidden_act]
363
+
364
+ self.layer_norm_epsilon = config.layer_norm_epsilon
365
+ self.in_proj_norm = None
366
+ if getattr(config, "mamba_in_proj_layernorm", False):
367
+ self.in_proj_norm = CENORMSNorm(config.hidden_size, eps=config.layer_norm_epsilon)
368
+
369
+ self.n_groups = config.n_groups
370
+ self.head_dim = config.mamba_head_dim
371
+ self.chunk_size = config.chunk_size
372
+
373
+ self.time_step_limit = config.time_step_limit
374
+ self.time_step_min = config.time_step_min
375
+ self.time_step_max = config.time_step_max
376
+
377
+ self.conv_dim = self.intermediate_size + 2 * self.n_groups * self.ssm_state_size
378
+ self.conv1d = nn.Conv1d(
379
+ in_channels=self.conv_dim,
380
+ out_channels=self.conv_dim,
381
+ bias=config.use_conv_bias,
382
+ kernel_size=config.conv_kernel,
383
+ groups=self.conv_dim,
384
+ padding=config.conv_kernel - 1,
385
+ )
386
+
387
+ # projection of the input hidden states
388
+ projection_size = self.intermediate_size + self.conv_dim + self.num_heads
389
+ self.in_proj = nn.Linear(
390
+ self.hidden_size,
391
+ projection_size,
392
+ bias=config.use_bias,
393
+ )
394
+ # selective projection used to make dt, B and C input dependant
395
+
396
+ # time step projection (discretization)
397
+ # instantiate once and copy inv_dt in init_weights of PretrainedModel
398
+ self.dt_bias = nn.Parameter(torch.ones(self.num_heads))
399
+
400
+ # S4D real initialization. These are not discretized!
401
+ # The core is to load them, compute the discrete states, then write the updated state. Keeps the memory bounded
402
+ A = torch.arange(1, self.num_heads + 1)
403
+ self.A_log = nn.Parameter(torch.log(A))
404
+ self.A_log._no_weight_decay = True
405
+ self.norm = MambaRMSNormGated(self.intermediate_size, eps=self.layer_norm_epsilon, group_size=self.intermediate_size // self.n_groups)
406
+ self.D = nn.Parameter(torch.ones(self.num_heads))
407
+ self.D._no_weight_decay = True
408
+
409
+ self.out_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=config.use_bias)
410
+ self.use_bias = config.use_bias
411
+
412
+ if not is_fast_path_available:
413
+ logger.warning_once(
414
+ "The fast path is not available because on of `(selective_state_update, causal_conv1d_fn, causal_conv1d_update)`"
415
+ " is None. Falling back to the naive implementation. To install follow https://github.com/state-spaces/mamba/#installation and"
416
+ " https://github.com/Dao-AILab/causal-conv1d"
417
+ )
418
+
419
+ def _maybe_apply_in_proj_norm(self, hidden_states: torch.Tensor) -> torch.Tensor:
420
+ if self.in_proj_norm is None:
421
+ return hidden_states
422
+ return self.in_proj_norm(hidden_states.to(dtype=self.in_proj_norm.weight.dtype))
423
+
424
+ def cuda_kernels_forward(
425
+ self,
426
+ hidden_states: torch.Tensor,
427
+ cache_params: Optional[HybridMambaAttentionDynamicCache] = None,
428
+ cache_position: Optional[torch.LongTensor] = None,
429
+ attention_mask: Optional[torch.Tensor] = None,
430
+ seq_idx: Optional[torch.Tensor] = None,
431
+ ):
432
+ # 1. Gated MLP's linear projection
433
+ hidden_states = apply_mask_to_padding_states(hidden_states, attention_mask)
434
+ hidden_states = self._maybe_apply_in_proj_norm(hidden_states)
435
+ projected_states = self.in_proj(hidden_states)
436
+
437
+ # Set up dimensions for reshapes later
438
+ batch_size, seq_len, _ = hidden_states.shape
439
+ groups_time_state_size = self.n_groups * self.ssm_state_size
440
+ d_mlp = (
441
+ projected_states.shape[-1]
442
+ - 2 * self.intermediate_size
443
+ - 2 * self.n_groups * self.ssm_state_size
444
+ - self.num_heads
445
+ ) // 2
446
+
447
+ # Single step calculations via cache
448
+ if cache_params is not None and cache_position is not None and cache_position[0] > 0:
449
+ _, _, gate, hidden_states_B_C, dt = projected_states.squeeze(1).split(
450
+ [d_mlp, d_mlp, self.intermediate_size, self.conv_dim, self.num_heads], dim=-1
451
+ )
452
+
453
+ # 2. Convolution sequence transformation
454
+ hidden_states_B_C = causal_conv1d_update(
455
+ hidden_states_B_C,
456
+ cache_params.conv_states[self.layer_idx],
457
+ self.conv1d.weight.squeeze(1),
458
+ self.conv1d.bias,
459
+ self.activation,
460
+ )
461
+
462
+ hidden_states, B, C = torch.split(
463
+ hidden_states_B_C,
464
+ [self.intermediate_size, groups_time_state_size, groups_time_state_size],
465
+ dim=-1,
466
+ )
467
+
468
+ # 3. SSM transformation
469
+ A = -torch.exp(self.A_log.float()) # (nheads,)
470
+ A = A[:, None, ...][:, :, None].expand(-1, self.head_dim, self.ssm_state_size).to(dtype=torch.float32)
471
+ dt = dt[:, :, None].expand(-1, -1, self.head_dim)
472
+ dt_bias = self.dt_bias[:, None, ...].expand(-1, self.head_dim)
473
+ D = self.D[:, None, ...].expand(-1, self.head_dim)
474
+ B = B.view(batch_size, self.n_groups, B.shape[1] // self.n_groups)
475
+ C = C.view(batch_size, self.n_groups, C.shape[1] // self.n_groups)
476
+ hidden_states_reshaped = hidden_states.view(batch_size, self.num_heads, self.head_dim)
477
+ hidden_states = selective_state_update(
478
+ cache_params.ssm_states[self.layer_idx],
479
+ hidden_states_reshaped,
480
+ dt,
481
+ A,
482
+ B,
483
+ C,
484
+ D,
485
+ z=None,
486
+ dt_bias=dt_bias,
487
+ dt_softplus=True,
488
+ )
489
+ hidden_states = hidden_states.view(batch_size, self.num_heads * self.head_dim)
490
+ hidden_states = self.norm(hidden_states, gate)
491
+
492
+ # 4. Final linear projection
493
+ out = self.out_proj(hidden_states)[:, None, ...]
494
+
495
+ # Fused calculations or step by step if no initialized cache is found
496
+ else:
497
+ A = -torch.exp(self.A_log.float()) # (num_heads) or (intermediate_size, state_size)
498
+ dt_limit_kwargs = {} if self.time_step_limit == (0.0, float("inf")) else {"dt_limit": self.time_step_limit}
499
+
500
+ # 2-4. Fused kernel for conv1d, SSM, and the final projection
501
+ if self.training and cache_params is None:
502
+ out = mamba_split_conv1d_scan_combined(
503
+ projected_states,
504
+ self.conv1d.weight.squeeze(1),
505
+ self.conv1d.bias,
506
+ self.dt_bias,
507
+ A,
508
+ D=self.D,
509
+ chunk_size=self.chunk_size,
510
+ seq_idx=seq_idx,
511
+ activation=self.activation,
512
+ rmsnorm_weight=self.norm.weight,
513
+ rmsnorm_eps=self.norm.variance_epsilon,
514
+ outproj_weight=self.out_proj.weight,
515
+ outproj_bias=self.out_proj.bias,
516
+ headdim=self.head_dim,
517
+ ngroups=self.n_groups,
518
+ norm_before_gate=False,
519
+ return_final_states=False,
520
+ **dt_limit_kwargs,
521
+ )
522
+
523
+ else:
524
+ _, _, gate, hidden_states_B_C, dt = projected_states.split(
525
+ [d_mlp, d_mlp, self.intermediate_size, self.conv_dim, self.num_heads], dim=-1
526
+ )
527
+
528
+ # 2. Convolution sequence transformation
529
+ # Init cache
530
+ if cache_params is not None:
531
+ hidden_states_B_C_transposed = hidden_states_B_C.transpose(1, 2)
532
+ conv_states = nn.functional.pad(
533
+ hidden_states_B_C_transposed,
534
+ (cache_params.conv_kernel_size - hidden_states_B_C_transposed.shape[-1], 0),
535
+ )
536
+ cache_params.update_conv_state(
537
+ layer_idx=self.layer_idx, new_conv_state=conv_states, cache_init=True
538
+ )
539
+
540
+ if self.activation not in ["silu", "swish"]:
541
+ hidden_states_B_C = self.act(
542
+ self.conv1d(hidden_states_B_C.transpose(1, 2))[..., :seq_len].transpose(1, 2)
543
+ )
544
+ else:
545
+ hidden_states_B_C = causal_conv1d_fn(
546
+ x=hidden_states_B_C.transpose(1, 2),
547
+ weight=self.conv1d.weight.squeeze(1),
548
+ bias=self.conv1d.bias,
549
+ activation=self.activation,
550
+ ).transpose(1, 2)
551
+ hidden_states_B_C = apply_mask_to_padding_states(hidden_states_B_C, attention_mask)
552
+ hidden_states, B, C = torch.split(
553
+ hidden_states_B_C,
554
+ [self.intermediate_size, groups_time_state_size, groups_time_state_size],
555
+ dim=-1,
556
+ )
557
+
558
+ # 3. SSM transformation
559
+ scan_output, ssm_state = mamba_chunk_scan_combined(
560
+ hidden_states.view(batch_size, seq_len, -1, self.head_dim),
561
+ dt,
562
+ A,
563
+ B.view(batch_size, seq_len, self.n_groups, -1),
564
+ C.view(batch_size, seq_len, self.n_groups, -1),
565
+ chunk_size=self.chunk_size,
566
+ D=self.D,
567
+ z=None,
568
+ seq_idx=seq_idx,
569
+ return_final_states=True,
570
+ dt_bias=self.dt_bias,
571
+ dt_softplus=True,
572
+ **dt_limit_kwargs,
573
+ )
574
+
575
+ # Init cache
576
+ if ssm_state is not None and cache_params is not None:
577
+ cache_params.update_ssm_state(layer_idx=self.layer_idx, new_ssm_state=ssm_state)
578
+
579
+ scan_output = scan_output.view(batch_size, seq_len, -1)
580
+
581
+ # Multiply "gate" branch and apply extra normalization layer
582
+ scan_output = self.norm(scan_output, gate)
583
+
584
+ # 4. Final linear projection
585
+ out = self.out_proj(scan_output)
586
+ return out
587
+
588
+ # fmt: off
589
+ def torch_forward(self, input_states, cache_params: Optional[HybridMambaAttentionDynamicCache]=None, cache_position:Optional[torch.LongTensor]=None, attention_mask: Optional[torch.Tensor]=None):
590
+ batch_size, seq_len, _ = input_states.shape
591
+ dtype = input_states.dtype
592
+
593
+ # 1. Gated MLP's linear projection
594
+ input_states = apply_mask_to_padding_states(input_states, attention_mask)
595
+ input_states = self._maybe_apply_in_proj_norm(input_states)
596
+ projected_states = self.in_proj(input_states)
597
+ d_mlp = (projected_states.shape[-1] - 2 * self.intermediate_size - 2 * self.n_groups * self.ssm_state_size-self.num_heads) // 2
598
+ _, _, gate, hidden_states_B_C, dt = projected_states.split(
599
+ [d_mlp, d_mlp, self.intermediate_size, self.conv_dim, self.num_heads], dim=-1
600
+ )
601
+
602
+ # 2. Convolution sequence transformation
603
+ if cache_params is not None and cache_position is not None and cache_position[0] > 0:
604
+ cache_params.update_conv_state(layer_idx=self.layer_idx, new_conv_state=hidden_states_B_C, cache_init=False)
605
+
606
+ # We need to guarantee that anything regarding the cache is on the same device
607
+ conv_states = cache_params.conv_states[self.layer_idx].to(device=self.conv1d.weight.device)
608
+
609
+ hidden_states_B_C = torch.sum(
610
+ conv_states * self.conv1d.weight.squeeze(1), dim=-1
611
+ )
612
+ if self.use_conv_bias:
613
+ hidden_states_B_C = hidden_states_B_C + self.conv1d.bias
614
+ hidden_states_B_C = self.act(hidden_states_B_C)
615
+ else:
616
+ # Init cache
617
+ if cache_params is not None:
618
+ hidden_states_B_C_transposed = hidden_states_B_C.transpose(1, 2)
619
+ conv_states = nn.functional.pad(
620
+ hidden_states_B_C_transposed, (cache_params.conv_kernel_size - hidden_states_B_C_transposed.shape[-1], 0)
621
+ )
622
+ cache_params.update_conv_state(layer_idx=self.layer_idx, new_conv_state=conv_states, cache_init=True)
623
+
624
+ hidden_states_B_C = self.act(self.conv1d(hidden_states_B_C.transpose(1, 2))[..., :seq_len].transpose(1, 2))
625
+
626
+ hidden_states_B_C = apply_mask_to_padding_states(hidden_states_B_C, attention_mask)
627
+ hidden_states, B, C = torch.split(
628
+ hidden_states_B_C,
629
+ [self.intermediate_size, self.n_groups * self.ssm_state_size, self.n_groups * self.ssm_state_size],
630
+ dim=-1
631
+ )
632
+
633
+ # 3. SSM transformation
634
+ A = -torch.exp(self.A_log.float()) # [num_heads]
635
+ if cache_params is not None and cache_position is not None and cache_position[0] > 0:
636
+ # We need to guarantee that anything regarding the cache is on the same device
637
+ cache_device = cache_params.ssm_states[self.layer_idx].device
638
+
639
+ # Note: there is no need to pad parameter matrices here, as there is just one new token
640
+ # for batched generation
641
+ dt = dt[:, 0, :][:, None, ...]
642
+ dt = dt.transpose(1, 2).expand(batch_size, dt.shape[-1], self.head_dim)
643
+ # [num_heads] -> [num_heads, head_dim]
644
+ dt_bias = self.dt_bias[..., None].expand(self.dt_bias.shape[0], self.head_dim)
645
+
646
+ dt = torch.nn.functional.softplus(dt + dt_bias.to(dt.dtype))
647
+ dt = torch.clamp(dt, self.time_step_limit[0], self.time_step_limit[1])
648
+ A = A[..., None, None].expand(self.num_heads, self.head_dim, self.ssm_state_size).to(dtype=torch.float32)
649
+ # [bsz, num_heads, head_dim, state_size]
650
+ dA = (torch.exp(dt[..., None] * A)).to(device=cache_device)
651
+
652
+ # Discretize B
653
+ # [bsz, n_groups * state_size] -> [bsz, n_groups, 1, state_size] ->
654
+ # -> [bsz, n_groups, group to head repetition factor, state_size] -> [bsz, num_heads, state_size]
655
+ B = B.reshape(batch_size, self.n_groups, -1)[..., None, :]
656
+ B = B.expand(batch_size, self.n_groups, self.num_heads // self.n_groups, B.shape[-1]).contiguous()
657
+ B = B.reshape(batch_size, -1, B.shape[-1])
658
+ # [bsz, num_heads, head_dim, state_size]
659
+ dB = dt[..., None] * B[..., None, :]
660
+
661
+ # Discretize x into dB
662
+ # [bsz, intermediate_size] -> [bsz, num_heads, head_dim]
663
+ hidden_states = hidden_states.reshape(batch_size, -1, self.head_dim)
664
+ dBx = (dB * hidden_states[..., None]).to(device=cache_device)
665
+
666
+ # State calculation
667
+ cache_params.update_ssm_state(
668
+ layer_idx=self.layer_idx,
669
+ new_ssm_state=cache_params.ssm_states[self.layer_idx] * dA + dBx
670
+ )
671
+
672
+ # Subsequent output
673
+ # [bsz, n_groups * state_size] -> [bsz, num_heads, state_size]
674
+ C = C.reshape(batch_size, self.n_groups, -1)[..., None, :]
675
+ C = C.expand(batch_size, self.n_groups, self.num_heads // self.n_groups, C.shape[-1]).contiguous()
676
+ C = C.reshape(batch_size, -1, C.shape[-1])
677
+ # [bsz, num_heads, head_dim]
678
+
679
+ ssm_states = cache_params.ssm_states[self.layer_idx].to(device=C.device, dtype=C.dtype) # Shape: [b, h, d, n]
680
+ # Reshape ssm_states to merge the first two dimensions
681
+ ssm_states_reshaped = ssm_states.view(batch_size * self.num_heads, self.head_dim, self.ssm_state_size) # Shape: [b*h, d, n]
682
+ C_reshaped = C.view(batch_size * self.num_heads, self.ssm_state_size, 1) # Shape: [b*h, n, 1]
683
+ y = torch.bmm(ssm_states_reshaped, C_reshaped)
684
+ y = y.view(batch_size, self.num_heads, self.head_dim)
685
+
686
+ # D skip connection
687
+ # [num_heads] -> [num_heads, head_dim]
688
+ D = self.D[..., None].expand(self.D.shape[0], self.head_dim)
689
+ y = (y + hidden_states * D).to(y.dtype)
690
+
691
+ # [bsz, num_heads, head_dim] -> [bsz, 1, intermediate_size]
692
+ y = y.reshape(batch_size, -1)[:, None, ...]
693
+ else:
694
+ # begin ssd naive implementation without einsums
695
+ dt = nn.functional.softplus(dt + self.dt_bias)
696
+ dt = torch.clamp(dt, self.time_step_limit[0], self.time_step_limit[1])
697
+ hidden_states = hidden_states.reshape(batch_size, seq_len, -1, self.head_dim).float()
698
+ B = B.reshape(batch_size, seq_len, -1, self.ssm_state_size).float()
699
+ C = C.reshape(batch_size, seq_len, -1, self.ssm_state_size).float()
700
+ B = B.repeat_interleave(self.num_heads // self.n_groups, dim=2, output_size=self.num_heads)
701
+ C = C.repeat_interleave(self.num_heads // self.n_groups, dim=2, output_size=self.num_heads)
702
+ pad_size = (self.chunk_size - seq_len % self.chunk_size) % self.chunk_size
703
+
704
+ D_residual = self.D[..., None] * pad_tensor_by_size(hidden_states, pad_size)
705
+
706
+ # Discretize x and A
707
+ hidden_states = hidden_states * dt[..., None]
708
+ A = A.to(hidden_states.dtype) * dt
709
+
710
+ # Rearrange into blocks/chunks
711
+ hidden_states, A, B, C = [reshape_into_chunks(t, pad_size, self.chunk_size) for t in (hidden_states, A, B, C)]
712
+
713
+ # [bsz, -1, chunk_size, num_heads] -> [bsz, num_heads, -1, chunk_size]
714
+ A = A.permute(0, 3, 1, 2)
715
+ A_cumsum = torch.cumsum(A, dim=-1)
716
+
717
+ # 1. Compute the output for each intra-chunk (diagonal blocks)
718
+ # This is the analog of a causal mask
719
+ L = torch.exp(segment_sum(A))
720
+
721
+ # Contraction of C and B to get G (attention-weights like)
722
+ G_intermediate = C[:, :, :, None, :, :] * B[:, :, None, :, :, :] # shape: (b, c, l, s, h, n)
723
+ G = G_intermediate.sum(dim=-1) # shape: (b, c, l, s, h)
724
+
725
+ # Compute M, equivalent to applying attention mask to weights
726
+ M_intermediate = G[..., None] * L.permute(0, 2, 3, 4, 1)[..., None]
727
+ M = M_intermediate.sum(dim=-1)
728
+
729
+ # Compute Y_diag (apply to values)
730
+ Y_diag = (M[..., None] * hidden_states[:, :, None]).sum(dim=3)
731
+
732
+ # 2. Compute the state for each intra-chunk
733
+ # (right term of low-rank factorization of off-diagonal blocks; B terms)
734
+ decay_states = torch.exp((A_cumsum[:, :, :, -1:] - A_cumsum))
735
+ B_decay = B * decay_states.permute(0, -2, -1, 1)[..., None]
736
+ states = (B_decay[..., None, :] * hidden_states[..., None]).sum(dim=2)
737
+
738
+ # 3. Compute the inter-chunk SSM recurrence; produces correct SSM states at chunk boundaries
739
+ # (middle term of factorization of off-diag blocks; A terms)
740
+ if cache_params is not None and cache_position is not None and cache_position[0] > 0:
741
+ previous_states = cache_params.ssm_states[self.layer_idx][:, None, ...].to(device=states.device)
742
+ else:
743
+ previous_states = torch.zeros_like(states[:, :1])
744
+ states = torch.cat([previous_states, states], dim=1)
745
+ decay_chunk = torch.exp(segment_sum(nn.functional.pad(A_cumsum[:, :, :, -1], (1, 0))))
746
+ decay_chunk = decay_chunk.transpose(1, 3)
747
+ new_states = (decay_chunk[..., None, None] * states[:, :, None, ...]).sum(dim=1)
748
+ states, ssm_state = new_states[:, :-1], new_states[:, -1]
749
+
750
+ # 4. Compute state -> output conversion per chunk
751
+ # (left term of low-rank factorization of off-diagonal blocks; C terms)
752
+ state_decay_out = torch.exp(A_cumsum)
753
+ C_times_states = (C[..., None, :] * states[:, :, None, ...])
754
+ state_decay_out_permuted = state_decay_out.permute(0, 2, 3, 1)
755
+ Y_off = (C_times_states.sum(-1) * state_decay_out_permuted[..., None])
756
+
757
+ # Add output of intra-chunk and inter-chunk terms (diagonal and off-diagonal blocks)
758
+ y = Y_diag + Y_off
759
+ # [bsz, -1, self.chunk_size, num_heads, head_dim] -> [bsz, (padded) seq_len, num_heads, head_dim]
760
+ y = y.reshape(batch_size, -1, self.num_heads, self.head_dim)
761
+
762
+ y = y + D_residual
763
+ # Cutting off padded chunks
764
+ if pad_size > 0:
765
+ y = y[:, :seq_len, :, :]
766
+ y = y.reshape(batch_size, seq_len, -1)
767
+
768
+ # Init cache
769
+ if ssm_state is not None and cache_params is not None:
770
+ cache_params.update_ssm_state(layer_idx=self.layer_idx, new_ssm_state=ssm_state)
771
+
772
+ scan_output = self.norm(y, gate)
773
+
774
+ # end ssd naive
775
+
776
+ # 4. Final linear projection
777
+ contextualized_states = self.out_proj(scan_output.to(dtype)) # [batch, seq_len, hidden_size]
778
+ return contextualized_states
779
+ # fmt: on
780
+
781
+ def forward(
782
+ self,
783
+ hidden_states,
784
+ cache_params: Optional[HybridMambaAttentionDynamicCache] = None,
785
+ cache_position: Optional[torch.LongTensor] = None,
786
+ attention_mask: Optional[torch.Tensor] = None,
787
+ seq_idx: Optional[torch.Tensor] = None,
788
+ ):
789
+ if self.config.use_mamba_kernels and _supports_cuda_fast_path(self.in_proj.weight.device):
790
+ return self.cuda_kernels_forward(hidden_states, cache_params, cache_position, attention_mask, seq_idx=seq_idx)
791
+ dtype = hidden_states.dtype
792
+ if attention_mask is not None and attention_mask.shape[1] > 1 and attention_mask.shape[0] > 1:
793
+ # tune out hidden states for pad tokens, see https://github.com/state-spaces/mamba/issues/66
794
+ hidden_states = (hidden_states * attention_mask[:, :, None]).to(dtype)
795
+
796
+ return self.torch_forward(hidden_states, cache_params, cache_position, attention_mask)
797
+
798
+
799
+ class CENORMSNorm(nn.Module):
800
+ def __init__(self, hidden_size, eps=1e-6):
801
+ """
802
+ CENORMSNorm is equivalent to T5LayerNorm and LlamaRMSNorm
803
+ """
804
+ super().__init__()
805
+ self.weight = nn.Parameter(torch.ones(hidden_size))
806
+ self.variance_epsilon = eps
807
+
808
+ def forward(self, hidden_states):
809
+ input_dtype = hidden_states.dtype
810
+ hidden_states = hidden_states.to(torch.float32)
811
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
812
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
813
+ # Weights are in float32
814
+ return (self.weight.to(torch.float32) * hidden_states).to(input_dtype)
815
+
816
+ class CENOBlock(nn.Module):
817
+ def __init__(self, config, layer_idx):
818
+ super().__init__()
819
+ self.config = config
820
+ self.layer_idx = layer_idx
821
+ self.residual_in_fp32 = config.residual_in_fp32
822
+ # Optional second norm to mirror Megatron pre_mlp_layernorm for non-Mamba blocks
823
+ self.pre_mlp_norm = None
824
+
825
+ # M: Mamba, *: Attention, -: MLP, E: MoE
826
+ self.block_type = config.layers_block_type[layer_idx]
827
+ if self.block_type == "mamba" and getattr(config, "mamba_in_proj_layernorm", False):
828
+ self.norm = None
829
+ else:
830
+ self.norm = CENORMSNorm(config.hidden_size, eps=config.layer_norm_epsilon)
831
+ if self.block_type == "mamba":
832
+ self.mixer = CENOMamba2Mixer(config, layer_idx=layer_idx)
833
+ elif self.block_type == "attention":
834
+ self.mixer = CENO_ATTENTION_CLASSES[config._attn_implementation](config, layer_idx=layer_idx)
835
+ self.pre_mlp_norm = CENORMSNorm(config.hidden_size, eps=config.layer_norm_epsilon)
836
+ elif self.block_type == "mlp":
837
+ self.mixer = CENOMLP(
838
+ config,
839
+ layer_idx=layer_idx,
840
+ use_fc1_norm=True,
841
+ )
842
+ self.pre_mlp_norm = CENORMSNorm(config.hidden_size, eps=config.layer_norm_epsilon)
843
+ elif self.block_type == "moe":
844
+ self.mixer = CENOMoE(config, layer_idx=layer_idx)
845
+ self.pre_mlp_norm = CENORMSNorm(config.hidden_size, eps=config.layer_norm_epsilon)
846
+ else:
847
+ raise ValueError(f"Invalid layer pattern {config.hybrid_override_pattern[layer_idx]}")
848
+
849
+ def forward(
850
+ self,
851
+ hidden_states,
852
+ cache_params: Optional[HybridMambaAttentionDynamicCache] = None,
853
+ cache_position: Optional[torch.LongTensor] = None,
854
+ attention_mask: Optional[torch.Tensor] = None,
855
+ seq_idx: Optional[torch.Tensor] = None,
856
+ ):
857
+ with torch.cuda.stream(torch.cuda.default_stream(hidden_states.device)):
858
+ # * Use torch.cuda.stream() to avoid NaN issues when using multiple GPUs
859
+
860
+ if self.block_type == "mamba":
861
+ # Mamba block: residual = x, output = x + mamba(norm(x))
862
+ residual = hidden_states
863
+ if self.norm is not None:
864
+ hidden_states = self.norm(hidden_states.to(dtype=self.norm.weight.dtype))
865
+ if self.residual_in_fp32:
866
+ residual = residual.to(torch.float32)
867
+ hidden_states = self.mixer(
868
+ hidden_states,
869
+ cache_params=cache_params,
870
+ cache_position=cache_position,
871
+ attention_mask=attention_mask,
872
+ seq_idx=seq_idx,
873
+ )
874
+ hidden_states = residual + hidden_states
875
+
876
+ elif self.block_type == "attention":
877
+ # Attention block in Megatron (TransformerLayer with mlp=IdentityOp):
878
+ # 1. input_ln_out = input_layernorm(x)
879
+ # 2. attn_out = self_attention(input_ln_out)
880
+ # 3. hidden = residual + attn_out (self_attn_bda applies residual)
881
+ # 4. residual = hidden
882
+ # 5. pre_mlp_out = pre_mlp_layernorm(hidden)
883
+ # 6. mlp_out = IdentityOp(pre_mlp_out) = pre_mlp_out
884
+ # 7. final = IdentityFuncOp(...)(mlp_out, residual, ...) = mlp_out (no residual!)
885
+ # So final output = pre_mlp_layernorm(x + attention(input_layernorm(x)))
886
+ #
887
+ # self.norm = input_layernorm
888
+ # self.pre_mlp_norm = pre_mlp_layernorm
889
+ residual = hidden_states
890
+ input_ln_out = self.norm(hidden_states.to(dtype=self.norm.weight.dtype))
891
+ if self.residual_in_fp32:
892
+ residual = residual.to(torch.float32)
893
+ attn_out, _, _ = self.mixer(
894
+ input_ln_out,
895
+ attention_mask=attention_mask,
896
+ past_key_value=cache_params,
897
+ use_cache=cache_params is not None,
898
+ cache_position=cache_position,
899
+ )
900
+ hidden_after_attn = residual + attn_out
901
+ # Apply pre_mlp_layernorm and that's the final output (no second residual)
902
+ hidden_states = self.pre_mlp_norm(hidden_after_attn.to(dtype=self.pre_mlp_norm.weight.dtype))
903
+
904
+ elif self.block_type == "mlp":
905
+ # MLP block in Megatron: residual = input_ln_out, output = input_ln_out + mlp(pre_mlp_ln(input_ln_out))
906
+ input_ln_out = self.norm(hidden_states.to(dtype=self.norm.weight.dtype))
907
+ residual = input_ln_out
908
+ if self.residual_in_fp32:
909
+ residual = residual.to(torch.float32)
910
+ pre_mlp_out = self.pre_mlp_norm(input_ln_out.to(dtype=self.pre_mlp_norm.weight.dtype))
911
+ mlp_out = self.mixer(pre_mlp_out)
912
+ hidden_states = residual + mlp_out
913
+
914
+ elif self.block_type == "moe":
915
+ # MoE block in Megatron: uses TransformerLayer structure
916
+ # When self_attention=IdentityOp:
917
+ # 1. input_ln_out = input_layernorm(x)
918
+ # 2. hidden = input_ln_out (no residual add)
919
+ # 3. residual = hidden = input_ln_out
920
+ # 4. pre_mlp_out = pre_mlp_layernorm(hidden)
921
+ # 5. moe_out = MoE(pre_mlp_out)
922
+ # 6. output = residual + moe_out = input_ln(x) + MoE(pre_mlp_ln(input_ln(x)))
923
+ #
924
+ # self.norm = input_layernorm
925
+ # self.pre_mlp_norm = pre_mlp_layernorm
926
+ input_ln_out = self.norm(hidden_states.to(dtype=self.norm.weight.dtype))
927
+ # In Megatron, residual is set to input_ln_out (not original x)
928
+ # because IdentityFuncOp for self_attn_bda skips residual addition
929
+ residual = input_ln_out
930
+ if self.residual_in_fp32:
931
+ residual = residual.to(torch.float32)
932
+ # Apply pre_mlp_layernorm before MoE
933
+ pre_mlp_out = self.pre_mlp_norm(input_ln_out.to(dtype=self.pre_mlp_norm.weight.dtype))
934
+ moe_out = self.mixer(pre_mlp_out)
935
+ hidden_states = residual + moe_out
936
+
937
+ else:
938
+ raise ValueError(f"Invalid block_type: {self.block_type}")
939
+
940
+ return hidden_states
941
+
942
+
943
+ # Updated to support SwiGLU activation and per-token scaling (for MoE routing weights)
944
+ class CENOMLP(nn.Module):
945
+ def __init__(self, config, layer_idx: Optional[int] = None, use_fc1_norm: bool = True):
946
+ super().__init__()
947
+ self.config = config
948
+ self.layer_idx = layer_idx
949
+ if layer_idx is None:
950
+ logger.warning_once(
951
+ f"Instantiating {self.__class__.__name__} without passing a `layer_idx` is not recommended and will "
952
+ "lead to errors during the forward call if caching is used. Please make sure to provide a `layer_idx` "
953
+ "when creating this class."
954
+ )
955
+ self.hidden_size = config.hidden_size
956
+ self.intermediate_size = config.intermediate_size
957
+
958
+ self.fc1_norm = None
959
+ if use_fc1_norm:
960
+ self.fc1_norm = CENORMSNorm(self.hidden_size, eps=config.layer_norm_epsilon)
961
+
962
+ # Check if using SwiGLU (gated activation)
963
+ self.use_swiglu = getattr(config, 'mlp_use_swiglu', False)
964
+
965
+ if self.use_swiglu:
966
+ # For SwiGLU, we need both gate and up projections
967
+ # Note: In Megatron, these are combined in fc1 with 2*intermediate_size output
968
+ # Here we split them into separate projections for clarity
969
+ self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=config.mlp_bias)
970
+ self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=config.mlp_bias)
971
+ self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=config.mlp_bias)
972
+ self.act_fn = ACT2FN[config.mlp_hidden_act]
973
+ else:
974
+ # Standard MLP
975
+ self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=config.mlp_bias)
976
+ self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=config.mlp_bias)
977
+ self.act_fn = ACT2FN[config.mlp_hidden_act]
978
+
979
+ def _maybe_apply_fc1_norm(self, hidden_states: torch.Tensor) -> torch.Tensor:
980
+ if self.fc1_norm is None:
981
+ return hidden_states
982
+ return self.fc1_norm(hidden_states.to(dtype=self.fc1_norm.weight.dtype))
983
+
984
+ def forward(self, x, per_token_scale=None):
985
+ """
986
+ Forward pass with optional per-token scaling (for MoE routing weights).
987
+
988
+ In Megatron MoE, routing weights are applied AFTER activation but BEFORE fc2/down_proj.
989
+ This is different from applying after the full MLP, and is critical for numerical equivalence.
990
+
991
+ Args:
992
+ x: input hidden states
993
+ per_token_scale: optional [num_tokens, 1] tensor of routing weights
994
+ """
995
+ x = self._maybe_apply_fc1_norm(x)
996
+
997
+ if self.use_swiglu:
998
+ # SwiGLU: act_fn(gate_proj(x)) * up_proj(x)
999
+ intermediate = self.act_fn(self.gate_proj(x)) * self.up_proj(x)
1000
+ else:
1001
+ # Standard MLP: act_fn(up_proj(x))
1002
+ up_out = self.up_proj(x)
1003
+ intermediate = self.act_fn(up_out)
1004
+
1005
+ # Apply per-token scaling AFTER activation, BEFORE down_proj (Megatron behavior)
1006
+ if per_token_scale is not None:
1007
+ intermediate = intermediate * per_token_scale
1008
+
1009
+ output = self.down_proj(intermediate)
1010
+ return output
1011
+
1012
+
1013
+ # Standard HuggingFace-style MoE implementation for CENO
1014
+ class CENOMoE(nn.Module):
1015
+ def __init__(self, config, layer_idx: Optional[int] = None):
1016
+ super().__init__()
1017
+ self.config = config
1018
+ self.layer_idx = layer_idx
1019
+ self.num_experts = getattr(config, 'num_experts', 8)
1020
+ self.top_k = getattr(config, 'moe_top_k', 2)
1021
+ self.hidden_size = config.hidden_size
1022
+ self.intermediate_size = config.intermediate_size
1023
+
1024
+ # Router/gate
1025
+ self.gate = nn.Linear(self.hidden_size, self.num_experts, bias=False)
1026
+
1027
+ # Expert networks
1028
+ self.experts = nn.ModuleList([
1029
+ CENOMLP(config, layer_idx, use_fc1_norm=False) for _ in range(self.num_experts)
1030
+ ])
1031
+
1032
+ def forward(self, hidden_states):
1033
+ batch_size, seq_len, hidden_dim = hidden_states.shape
1034
+
1035
+ # Flatten for easier processing
1036
+ hidden_states_flat = hidden_states.view(-1, hidden_dim)
1037
+
1038
+ # Router logits
1039
+ # Megatron default behavior (when --moe-router-pre-softmax is NOT set):
1040
+ # - select top-k on logits
1041
+ # - compute softmax *within* the selected top-k logits (post-topk softmax)
1042
+ # If moe_router_pre_softmax=True, we instead do global softmax then take top-k (legacy HF behavior).
1043
+ #
1044
+ # NOTE: For strict HF-vs-Megatron validation, it's sometimes necessary to compute router logits
1045
+ # in fp32 (matmul in fp32) to avoid bf16 GEMM rounding drift that can be amplified by routing
1046
+ # and the squared-relu expert MLP. This is controlled by config.moe_router_dtype.
1047
+ router_dtype = str(getattr(self.config, "moe_router_dtype", "")).lower()
1048
+ if router_dtype == "fp32":
1049
+ # bias=False; use explicit fp32 matmul for reproducibility across backends.
1050
+ router_logits = torch.nn.functional.linear(
1051
+ hidden_states_flat.to(torch.float32),
1052
+ self.gate.weight.to(torch.float32),
1053
+ bias=None,
1054
+ ) # [T, num_experts] fp32
1055
+ else:
1056
+ # default: run the module in the model dtype, then cast logits to fp32 for softmax/topk
1057
+ router_logits = self.gate(hidden_states_flat).to(torch.float32) # [T, num_experts]
1058
+ pre_softmax = bool(getattr(self.config, "moe_router_pre_softmax", False))
1059
+
1060
+ if pre_softmax:
1061
+ # Pre-softmax routing: softmax over all experts, then take top-k.
1062
+ probs = torch.nn.functional.softmax(router_logits, dim=-1)
1063
+ routing_weights, selected_experts = torch.topk(probs, self.top_k, dim=-1)
1064
+ routing_weights = routing_weights / (routing_weights.sum(dim=-1, keepdim=True) + 1e-20)
1065
+ else:
1066
+ # Post-topk softmax routing: take top-k logits first, then softmax over top-k.
1067
+ topk_logits, selected_experts = torch.topk(router_logits, self.top_k, dim=-1)
1068
+ routing_weights = torch.nn.functional.softmax(topk_logits, dim=-1)
1069
+
1070
+ # Initialize output
1071
+ final_hidden_states = torch.zeros_like(hidden_states_flat)
1072
+
1073
+ # Route tokens to experts
1074
+ expert_mask = torch.nn.functional.one_hot(selected_experts, num_classes=self.num_experts).permute(2, 1, 0)
1075
+
1076
+ # Process each expert
1077
+ for expert_idx in range(self.num_experts):
1078
+ expert_layer = self.experts[expert_idx]
1079
+
1080
+ # Get tokens for this expert from all top-k positions
1081
+ idx, top_x = torch.where(expert_mask[expert_idx])
1082
+
1083
+ if top_x.shape[0] == 0:
1084
+ continue
1085
+
1086
+ # Index the correct hidden states
1087
+ current_state = hidden_states_flat[top_x] # [num_selected, hidden_dim]
1088
+
1089
+ # Get the routing weights for these tokens
1090
+ # Shape: [num_selected, 1] for per-token scaling inside the MLP
1091
+ current_weights = routing_weights[top_x, idx].unsqueeze(-1).to(current_state.dtype)
1092
+
1093
+ # Pass routing weights to expert MLP - they are applied AFTER activation, BEFORE down_proj
1094
+ # This matches Megatron's MoE behavior for numerical equivalence
1095
+ current_hidden_states = expert_layer(
1096
+ current_state,
1097
+ per_token_scale=current_weights
1098
+ )
1099
+
1100
+ # Accumulate outputs
1101
+ final_hidden_states.index_add_(0, top_x, current_hidden_states.to(hidden_states.dtype))
1102
+
1103
+ # Reshape back
1104
+ return final_hidden_states.view(batch_size, seq_len, hidden_dim)
1105
+
1106
+
1107
+ # Copied from transformers.models.llama.modeling_llama.repeat_kv
1108
+ def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
1109
+ """
1110
+ This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
1111
+ num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
1112
+ """
1113
+ batch, num_key_value_heads, slen, head_dim = hidden_states.shape
1114
+ if n_rep == 1:
1115
+ return hidden_states
1116
+ hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
1117
+ return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
1118
+
1119
+
1120
+ class CENOAttention(nn.Module):
1121
+ """Multi-headed attention from 'Attention Is All You Need' paper"""
1122
+
1123
+ def __init__(self, config: CENOConfig, layer_idx: Optional[int] = None):
1124
+ super().__init__()
1125
+ self.config = config
1126
+ self.layer_idx = layer_idx
1127
+ if layer_idx is None:
1128
+ logger.warning_once(
1129
+ f"Instantiating {self.__class__.__name__} without passing a `layer_idx` is not recommended and will "
1130
+ "lead to errors during the forward call if caching is used. Please make sure to provide a `layer_idx` "
1131
+ "when creating this class."
1132
+ )
1133
+
1134
+ self.attention_dropout = config.attention_dropout
1135
+ self.hidden_size = config.hidden_size
1136
+ self.num_heads = config.num_attention_heads
1137
+ if config.attention_head_dim is not None:
1138
+ self.head_dim = config.attention_head_dim
1139
+ else:
1140
+ self.head_dim = config.hidden_size // config.num_attention_heads
1141
+ self.num_key_value_heads = config.num_key_value_heads
1142
+ self.num_key_value_groups = self.num_heads // self.num_key_value_heads
1143
+ self.max_position_embeddings = config.max_position_embeddings
1144
+ self.is_causal = True
1145
+
1146
+ self.qkv_norm = None
1147
+ if getattr(config, "qkv_layernorm", False):
1148
+ self.qkv_norm = CENORMSNorm(config.hidden_size, eps=config.layer_norm_epsilon)
1149
+
1150
+ self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=config.attention_bias)
1151
+ self.k_proj = nn.Linear(self.hidden_size, self.num_key_value_heads * self.head_dim, bias=config.attention_bias)
1152
+ self.v_proj = nn.Linear(self.hidden_size, self.num_key_value_heads * self.head_dim, bias=config.attention_bias)
1153
+ self.o_proj = nn.Linear(self.head_dim * self.num_heads, self.hidden_size, bias=config.attention_bias)
1154
+
1155
+ def _maybe_apply_qkv_norm(self, hidden_states: torch.Tensor) -> torch.Tensor:
1156
+ if self.qkv_norm is None:
1157
+ return hidden_states
1158
+ return self.qkv_norm(hidden_states.to(dtype=self.qkv_norm.weight.dtype))
1159
+
1160
+ def forward(
1161
+ self,
1162
+ hidden_states: torch.Tensor,
1163
+ # position_embeddings: Tuple[torch.Tensor, torch.Tensor], #TODO
1164
+ attention_mask: Optional[torch.Tensor] = None,
1165
+ position_ids: Optional[torch.LongTensor] = None,
1166
+ past_key_value: Optional[HybridMambaAttentionDynamicCache] = None,
1167
+ output_attentions: bool = False,
1168
+ use_cache: bool = False,
1169
+ cache_position: Optional[torch.LongTensor] = None,
1170
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
1171
+ bsz, q_len, _ = hidden_states.size()
1172
+
1173
+ hidden_states = self._maybe_apply_qkv_norm(hidden_states)
1174
+ query_states = self.q_proj(hidden_states)
1175
+ key_states = self.k_proj(hidden_states)
1176
+ value_states = self.v_proj(hidden_states)
1177
+
1178
+ query_states = query_states.view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
1179
+ key_states = key_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
1180
+ value_states = value_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
1181
+
1182
+ if past_key_value is not None:
1183
+ key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx)
1184
+
1185
+ key_states = repeat_kv(key_states, self.num_key_value_groups)
1186
+ value_states = repeat_kv(value_states, self.num_key_value_groups)
1187
+
1188
+ causal_mask = attention_mask
1189
+ if attention_mask is not None: # no matter the length, we just slice it
1190
+ causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]
1191
+
1192
+ if query_states.device.type == "cuda" and attention_mask is not None:
1193
+ query_states = query_states.contiguous()
1194
+ key_states = key_states.contiguous()
1195
+ value_states = value_states.contiguous()
1196
+
1197
+ is_causal = True if causal_mask is None and q_len > 1 else False
1198
+
1199
+ attn_output = torch.nn.functional.scaled_dot_product_attention(
1200
+ query_states,
1201
+ key_states,
1202
+ value_states,
1203
+ attn_mask=causal_mask,
1204
+ dropout_p=self.attention_dropout if self.training else 0.0,
1205
+ is_causal=is_causal,
1206
+ )
1207
+ attn_output = attn_output.transpose(1, 2).contiguous()
1208
+ #attn_output = attn_output.view(bsz, q_len, self.hidden_size)
1209
+ attn_output = attn_output.view(bsz, q_len, self.num_heads * self.head_dim)
1210
+
1211
+ attn_output = self.o_proj(attn_output)
1212
+
1213
+ return attn_output, None, past_key_value
1214
+
1215
+
1216
+ # Adapted from transformers.models.mistral.modeling_mistral.MistralFlashAttention2 with Mistral->Jamba
1217
+ #class JambaFlashAttention2(JambaAttention):
1218
+ class CENOFlashAttention2(CENOAttention):
1219
+ """
1220
+ Jamba flash attention module. This module inherits from `JambaAttention` as the weights of the module stays
1221
+ untouched. The only required change would be on the forward pass where it needs to correctly call the public API of
1222
+ flash attention and deal with padding tokens in case the input contains any of them.
1223
+ """
1224
+ def __init__(self, *args, **kwargs):
1225
+ super().__init__(*args, **kwargs)
1226
+
1227
+ # TODO: Should be removed once Flash Attention for RoCm is bumped to 2.1.
1228
+ # flash_attn<2.1 generates top-left aligned causal mask, while what is needed here is bottom-right alignement, that was made default for flash_attn>=2.1. This attribute is used to handle this difference. Reference: https://github.com/Dao-AILab/flash-attention/releases/tag/v2.1.0.
1229
+ # Beware that with flash_attn<2.1, using q_seqlen != k_seqlen (except for the case q_seqlen == 1) produces a wrong mask (top-left).
1230
+ self._flash_attn_uses_top_left_mask = not is_flash_attn_greater_or_equal_2_10()
1231
+
1232
+ def forward(
1233
+ self,
1234
+ hidden_states: torch.Tensor,
1235
+ attention_mask: Optional[torch.Tensor] = None,
1236
+ position_ids: Optional[torch.LongTensor] = None,
1237
+ past_key_value: Optional[HybridMambaAttentionDynamicCache] = None,
1238
+ output_attentions: bool = False,
1239
+ use_cache: bool = False,
1240
+ cache_position: Optional[torch.LongTensor] = None,
1241
+ **kwargs,
1242
+ ):
1243
+ bsz, q_len, _ = hidden_states.size()
1244
+
1245
+ hidden_states = self._maybe_apply_qkv_norm(hidden_states)
1246
+ query_states = self.q_proj(hidden_states)
1247
+ key_states = self.k_proj(hidden_states)
1248
+ value_states = self.v_proj(hidden_states)
1249
+
1250
+ # Flash attention requires the input to have the shape
1251
+ # batch_size x seq_length x head_dim x hidden_dim
1252
+ # therefore we just need to keep the original shape
1253
+ query_states = query_states.view(bsz, q_len, self.num_heads, self.head_dim)
1254
+ key_states = key_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
1255
+ value_states = value_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
1256
+
1257
+ if past_key_value is not None:
1258
+ key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx)
1259
+
1260
+ # repeat k/v heads if n_kv_heads < n_heads
1261
+ key_states = repeat_kv(key_states, self.num_key_value_groups)
1262
+ value_states = repeat_kv(value_states, self.num_key_value_groups)
1263
+ dropout_rate = 0.0 if not self.training else self.attention_dropout
1264
+
1265
+ # In PEFT, usually we cast the layer norms in float32 for training stability reasons
1266
+ # therefore the input hidden states gets silently casted in float32. Hence, we need
1267
+ # cast them back in float16 just to be sure everything works as expected.
1268
+ input_dtype = query_states.dtype
1269
+ if input_dtype == torch.float32:
1270
+ if torch.is_autocast_enabled():
1271
+ target_dtype = torch.get_autocast_gpu_dtype()
1272
+ # Handle the case where the model is quantized
1273
+ elif hasattr(self.config, "_pre_quantization_dtype"):
1274
+ target_dtype = self.config._pre_quantization_dtype
1275
+ else:
1276
+ target_dtype = self.q_proj.weight.dtype
1277
+
1278
+ logger.warning_once(
1279
+ f"The input hidden states seems to be silently casted in float32, this might be related to"
1280
+ f" the fact you have upcasted embedding or layer norm layers in float32. We will cast back the input in"
1281
+ f" {target_dtype}."
1282
+ )
1283
+
1284
+ query_states = query_states.to(target_dtype)
1285
+ key_states = key_states.to(target_dtype)
1286
+ value_states = value_states.to(target_dtype)
1287
+
1288
+ # Reashape to the expected shape for Flash Attention
1289
+ key_states = key_states.transpose(1, 2)
1290
+ value_states = value_states.transpose(1, 2)
1291
+
1292
+ attn_output = _flash_attention_forward(
1293
+ query_states,
1294
+ key_states,
1295
+ value_states,
1296
+ attention_mask,
1297
+ q_len,
1298
+ dropout=dropout_rate,
1299
+ sliding_window=getattr(self.config, "sliding_window", None),
1300
+ is_causal=self.is_causal,
1301
+ use_top_left_mask=self._flash_attn_uses_top_left_mask,
1302
+ )
1303
+
1304
+ #attn_output = attn_output.reshape(bsz, q_len, self.hidden_size).contiguous()
1305
+ attn_output = attn_output.reshape(bsz, q_len, self.num_heads * self.head_dim).contiguous()
1306
+ attn_output = self.o_proj(attn_output)
1307
+
1308
+ if not output_attentions:
1309
+ attn_weights = None
1310
+
1311
+ return attn_output, attn_weights, past_key_value
1312
+
1313
+
1314
+ # Adapted from transformers.models.mistral.modeling_mistral.MistralSdpaAttention with Mistral->Jamba
1315
+ #class JambaSdpaAttention(JambaAttention):
1316
+ class CENOSdpaAttention(CENOAttention):
1317
+ """
1318
+ Jamba attention module using torch.nn.functional.scaled_dot_product_attention. This module inherits from
1319
+ `JambaAttention` as the weights of the module stays untouched. The only changes are on the forward pass to adapt to
1320
+ SDPA API.
1321
+ """
1322
+
1323
+ # Adapted from CENOAttention.forward
1324
+ def forward(
1325
+ self,
1326
+ hidden_states: torch.Tensor,
1327
+ attention_mask: Optional[torch.Tensor] = None,
1328
+ position_ids: Optional[torch.LongTensor] = None,
1329
+ past_key_value: Optional[HybridMambaAttentionDynamicCache] = None,
1330
+ output_attentions: bool = False,
1331
+ use_cache: bool = False,
1332
+ cache_position: Optional[torch.LongTensor] = None,
1333
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
1334
+ if output_attentions:
1335
+ # TODO: Improve this warning with e.g. `model.config.attn_implementation = "manual"` once this is implemented.
1336
+ logger.warning_once(
1337
+ "CENOModel is using CENOSdpaAttention, but `torch.nn.functional.scaled_dot_product_attention` does not support `output_attentions=True`. Falling back to the manual attention implementation, "
1338
+ 'but specifying the manual implementation will be required from Transformers version v5.0.0 onwards. This warning can be removed using the argument `attn_implementation="eager"` when loading the model.'
1339
+ )
1340
+ return super().forward(
1341
+ hidden_states=hidden_states,
1342
+ attention_mask=attention_mask,
1343
+ position_ids=position_ids,
1344
+ past_key_value=past_key_value,
1345
+ output_attentions=output_attentions,
1346
+ use_cache=use_cache,
1347
+ )
1348
+
1349
+ bsz, q_len, _ = hidden_states.size()
1350
+
1351
+ hidden_states = self._maybe_apply_qkv_norm(hidden_states)
1352
+ query_states = self.q_proj(hidden_states)
1353
+ key_states = self.k_proj(hidden_states)
1354
+ value_states = self.v_proj(hidden_states)
1355
+
1356
+ query_states = query_states.view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
1357
+ key_states = key_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
1358
+ value_states = value_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
1359
+
1360
+ if past_key_value is not None:
1361
+ key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx)
1362
+
1363
+ key_states = repeat_kv(key_states, self.num_key_value_groups)
1364
+ value_states = repeat_kv(value_states, self.num_key_value_groups)
1365
+
1366
+ causal_mask = attention_mask
1367
+ if attention_mask is not None:
1368
+ causal_mask = causal_mask[:, :, :, : key_states.shape[-2]]
1369
+
1370
+ # SDPA with memory-efficient backend is currently (torch==2.1.2) bugged with non-contiguous inputs with custom attn_mask,
1371
+ # Reference: https://github.com/pytorch/pytorch/issues/112577.
1372
+ if query_states.device.type == "cuda" and attention_mask is not None:
1373
+ query_states = query_states.contiguous()
1374
+ key_states = key_states.contiguous()
1375
+ value_states = value_states.contiguous()
1376
+
1377
+ # We dispatch to SDPA's Flash Attention or Efficient kernels via this `is_causal` if statement instead of an inline conditional assignment
1378
+ # in SDPA to support both torch.compile's dynamic shapes and full graph options. An inline conditional prevents dynamic shapes from compiling.
1379
+ # The q_len > 1 is necessary to match with AttentionMaskConverter.to_causal_4d that does not create a causal mask in case q_len == 1.
1380
+ is_causal = True if self.is_causal and causal_mask is None and q_len > 1 else False
1381
+
1382
+ attn_output = torch.nn.functional.scaled_dot_product_attention(
1383
+ query_states,
1384
+ key_states,
1385
+ value_states,
1386
+ attn_mask=causal_mask,
1387
+ dropout_p=self.attention_dropout if self.training else 0.0,
1388
+ is_causal=is_causal,
1389
+ )
1390
+
1391
+ attn_output = attn_output.transpose(1, 2).contiguous()
1392
+ attn_output = attn_output.view(bsz, q_len, self.hidden_size)
1393
+
1394
+ attn_output = self.o_proj(attn_output)
1395
+
1396
+ return attn_output, None, past_key_value
1397
+
1398
+
1399
+ CENO_ATTENTION_CLASSES = {
1400
+ "eager": CENOAttention,
1401
+ "flash_attention_2": CENOFlashAttention2,
1402
+ "sdpa": CENOSdpaAttention,
1403
+ }
1404
+
1405
+ # Copied from transformers.models.mamba.modeling_mamba2.Mamba2PreTrainedModel
1406
+ class CENOPreTrainedModel(PreTrainedModel):
1407
+ """
1408
+ An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained
1409
+ models.
1410
+ """
1411
+
1412
+ config_class = CENOConfig
1413
+ base_model_prefix = "backbone"
1414
+ _no_split_modules = ["CENOBlock"]
1415
+ supports_gradient_checkpointing = True
1416
+ _is_stateful = True
1417
+ _supports_flash_attn_2 = True
1418
+ _supports_sdpa = True
1419
+
1420
+ def _init_weights(self, module):
1421
+ """Initialize the weights."""
1422
+ if isinstance(module, CENOMamba2Mixer):
1423
+ module.A_log._no_weight_decay = True
1424
+ module.D._no_weight_decay = True
1425
+
1426
+ dt = torch.exp(
1427
+ torch.rand(self.config.mamba_num_heads)
1428
+ * (math.log(self.config.time_step_max) - math.log(self.config.time_step_min))
1429
+ + math.log(self.config.time_step_min)
1430
+ ).clamp(min=self.config.time_step_floor)
1431
+
1432
+ # # Inverse of softplus: https://github.com/pytorch/pytorch/issues/72759
1433
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
1434
+ with torch.no_grad():
1435
+ module.dt_bias.copy_(inv_dt)
1436
+ module.dt_bias._no_reinit = True
1437
+
1438
+ if isinstance(module, nn.Linear):
1439
+ if module.bias is not None:
1440
+ if not getattr(module.bias, "_no_reinit", False):
1441
+ nn.init.zeros_(module.bias)
1442
+ elif isinstance(module, nn.Embedding):
1443
+ nn.init.normal_(module.weight, std=self.config.initializer_range)
1444
+
1445
+ # TODO: Check
1446
+ if self.config.rescale_prenorm_residual:
1447
+ # Reinitialize selected weights subject to the OpenAI GPT-2 Paper Scheme:
1448
+ # > A modified initialization which accounts for the accumulation on the residual path with model depth. Scale
1449
+ # > the weights of residual layers at initialization by a factor of 1/√N where N is the # of residual layers.
1450
+ # > -- GPT-2 :: https://openai.com/blog/better-language-models/
1451
+ #
1452
+ # Reference (Megatron-LM): https://github.com/NVIDIA/Megatron-LM/blob/main/megatron/model/gpt_model.py
1453
+ for name, p in module.named_parameters():
1454
+ if name in ["out_proj.weight"]:
1455
+ # Special Scaled Initialization --> There are 2 Layer Norms per Transformer Block
1456
+ # Following Pytorch init, except scale by 1/sqrt(2 * n_layer)
1457
+ # We need to reinit p since this code could be called multiple times
1458
+ # Having just p *= scale would repeatedly scale it down
1459
+ nn.init.kaiming_uniform_(p, a=math.sqrt(5))
1460
+ with torch.no_grad():
1461
+ p /= math.sqrt(self.config.num_hidden_layers)
1462
+
1463
+
1464
+ @dataclass
1465
+ # Copied from transformers.models.mamba.modeling_mamba2.Mamba2Output with MAMBA2->CENO,Mamba2->CENO
1466
+ class CENOOutput(ModelOutput):
1467
+ """
1468
+ Class for the CENO model outputs.
1469
+
1470
+ Args:
1471
+ last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
1472
+ Sequence of hidden-states at the output of the last layer of the model.
1473
+ cache_params (`HybridMambaAttentionDynamicCache`):
1474
+ The state of the model at the last time step. Can be used in a forward method with the next `input_ids` to
1475
+ avoid providing the old `input_ids`.
1476
+
1477
+ Includes both the State space model state matrices after the selective scan, and the Convolutional states
1478
+ hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
1479
+ Tuple of `torch.FloatTensor` (one for the output of the embeddings, if the model has an embedding layer, +
1480
+ one for the output of each layer) of shape `(batch_size, sequence_length, hidden_size)`.
1481
+
1482
+ Hidden-states of the model at the output of each layer plus the optional initial embedding outputs.
1483
+ """
1484
+
1485
+ last_hidden_state: Optional[torch.FloatTensor] = None
1486
+ cache_params: Optional[HybridMambaAttentionDynamicCache] = None
1487
+ hidden_states: Optional[Tuple[torch.FloatTensor]] = None
1488
+ attentions: Optional[Tuple[torch.FloatTensor]] = None
1489
+
1490
+
1491
+ @dataclass
1492
+ # Copied from transformers.models.mamba2.modeling_mamba2.MambaCausalLMOutput with Mamba2->CENO
1493
+ class CENOCausalLMOutput(ModelOutput):
1494
+ """
1495
+ Base class for causal language model (or autoregressive) outputs.
1496
+
1497
+ Args:
1498
+ loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `labels` is provided):
1499
+ Language modeling loss (for next-token prediction).
1500
+ logits (`torch.FloatTensor` of shape `(batch_size, sequence_length, config.vocab_size)`):
1501
+ Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
1502
+ cache_params (`HybridMambaAttentionDynamicCache`):
1503
+ The state of the model at the last time step. Can be used in a forward method with the next `input_ids` to
1504
+ avoid providing the old `input_ids`.
1505
+
1506
+ Includes both the State space model state matrices after the selective scan, and the Convolutional states
1507
+ hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
1508
+ Tuple of `torch.FloatTensor` (one for the output of the embeddings, if the model has an embedding layer, +
1509
+ one for the output of each layer) of shape `(batch_size, sequence_length, hidden_size)`.
1510
+
1511
+ Hidden-states of the model at the output of each layer plus the optional initial embedding outputs.
1512
+ """
1513
+
1514
+ loss: Optional[torch.FloatTensor] = None
1515
+ logits: Optional[torch.FloatTensor] = None
1516
+ cache_params: Optional[HybridMambaAttentionDynamicCache] = None
1517
+ past_key_values: Optional[HybridMambaAttentionDynamicCache] = None
1518
+ hidden_states: Optional[Tuple[torch.FloatTensor]] = None
1519
+ attentions: Optional[Tuple[torch.FloatTensor]] = None
1520
+
1521
+
1522
+ CENO_START_DOCSTRING = r"""
1523
+
1524
+ This model inherits from [`PreTrainedModel`]. Check the superclass documentation for the generic methods the
1525
+ library implements for all its model (such as downloading or saving, resizing the input embeddings, pruning heads
1526
+ etc.)
1527
+
1528
+ This model is also a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) subclass.
1529
+ Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage
1530
+ and behavior.
1531
+
1532
+ Parameters:
1533
+ config ([`CENOConfig`]): Model configuration class with all the parameters of the model.
1534
+ Initializing with a config file does not load the weights associated with the model, only the
1535
+ configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights.
1536
+ """
1537
+
1538
+ CENO_INPUTS_DOCSTRING = r"""
1539
+ Args:
1540
+ input_ids (`torch.LongTensor` of shape `(batch_size, input_ids_length)`, *optional*):
1541
+ Indices of input sequence tokens in the vocabulary.
1542
+
1543
+ If `cache_params.seqlen_offset>0`, only `input_ids` that do not have their past calculated should be passed as
1544
+ `input_ids`.
1545
+
1546
+ Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and
1547
+ [`PreTrainedTokenizer.__call__`] for details.
1548
+
1549
+ [What are input IDs?](../glossary#input-ids)
1550
+ inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
1551
+ Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. This
1552
+ is useful if you want more control over how to convert `input_ids` indices into associated vectors than the
1553
+ model's internal embedding lookup matrix.
1554
+ position_ids (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
1555
+ Indices of positions of each input sequence tokens in the position embeddings.
1556
+ cache_params (`HybridMambaAttentionDynamicCache`, *optional*):
1557
+ If passed along, the model uses the previous state in all the blocks (which will give the output for the
1558
+ `input_ids` provided as if the model add `state_input_ids + input_ids` as context).
1559
+ use_cache (`bool`, *optional*):
1560
+ If set to `True`, the `cache_params` is returned and can be used to quickly generate the next logits.
1561
+ output_attentions (`bool`, *optional*):
1562
+ Whether or not to return the attentions tensors of all attention layers.
1563
+ output_hidden_states (`bool`, *optional*):
1564
+ Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for
1565
+ more detail.
1566
+ return_dict (`bool`, *optional*):
1567
+ Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple.
1568
+ cache_position (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
1569
+ The position of the current input in the cache. This is used to ensure that the cache is correctly updated.
1570
+ If `cache_params` is passed, `cache_position` should also be passed.
1571
+ attention_mask (`torch.FloatTensor` of shape `(batch_size, sequence_length)`, *optional*):
1572
+ Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`:
1573
+
1574
+ - 1 for tokens that are **not masked**,
1575
+ - 0 for tokens that are **masked**.
1576
+
1577
+ [What are attention masks?](../glossary#attention-mask)
1578
+ seq_idx (`torch.IntTensor` of shape `(batch_size, sequence_length)`, *optional*):
1579
+ Optional per-token sequence ids used to isolate different sub-sequences. Tokens sharing the same id are
1580
+ allowed to attend to each other; different ids are blocked. If omitted, no intra-sequence isolation is used.
1581
+ """
1582
+
1583
+
1584
+ @add_start_docstrings(
1585
+ "The bare CENO Model transformer outputting raw hidden-states without any specific head on top.",
1586
+ CENO_START_DOCSTRING,
1587
+ )
1588
+ class CENOModel(CENOPreTrainedModel):
1589
+ def __init__(self, config):
1590
+ super().__init__(config)
1591
+
1592
+ self.embeddings = nn.Embedding(config.vocab_size, config.hidden_size)
1593
+ self.layers = nn.ModuleList([CENOBlock(config, layer_idx=idx) for idx in range(config.num_hidden_layers)])
1594
+
1595
+ self.gradient_checkpointing = False
1596
+ self.norm_f = CENORMSNorm(config.hidden_size, eps=config.layer_norm_epsilon)
1597
+ # Initialize weights and apply final processing
1598
+ self._register_load_state_dict_pre_hook(self.load_hook)
1599
+ self.post_init()
1600
+
1601
+ def load_hook(self, state_dict, prefix, *args):
1602
+ for k in state_dict:
1603
+ if "embedding." in k:
1604
+ state_dict[k.replace("embedding.", "embeddings.")] = state_dict.pop(k)
1605
+ break
1606
+
1607
+ def get_input_embeddings(self):
1608
+ return self.embeddings
1609
+
1610
+ def set_input_embeddings(self, new_embeddings):
1611
+ self.embeddings = new_embeddings
1612
+
1613
+ @add_start_docstrings_to_model_forward(CENO_INPUTS_DOCSTRING)
1614
+ @add_code_sample_docstrings(
1615
+ checkpoint=_CHECKPOINT_FOR_DOC,
1616
+ output_type=CENOOutput,
1617
+ config_class=_CONFIG_FOR_DOC,
1618
+ )
1619
+ def forward(
1620
+ self,
1621
+ input_ids: Optional[torch.LongTensor] = None,
1622
+ inputs_embeds: Optional[torch.LongTensor] = None,
1623
+ position_ids: Optional[torch.LongTensor] = None,
1624
+ cache_params: Optional[HybridMambaAttentionDynamicCache] = None,
1625
+ use_cache: Optional[bool] = None,
1626
+ output_attentions: Optional[bool] = None,
1627
+ output_hidden_states: Optional[bool] = None,
1628
+ return_dict: Optional[bool] = None,
1629
+ cache_position: Optional[torch.LongTensor] = None,
1630
+ attention_mask: Optional[torch.Tensor] = None,
1631
+ seq_idx: Optional[torch.Tensor] = None,
1632
+ **kwargs,
1633
+ ) -> Union[Tuple, CENOOutput]:
1634
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
1635
+ output_hidden_states = (
1636
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
1637
+ )
1638
+ # use_cache = use_cache if use_cache is not None else self.config.use_cache
1639
+ use_cache = use_cache if use_cache is not None else (self.config.use_cache if not self.training else False)
1640
+
1641
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
1642
+
1643
+ if (input_ids is None) ^ (inputs_embeds is not None): # ^ is python for xor
1644
+ raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
1645
+
1646
+ if inputs_embeds is None:
1647
+ inputs_embeds = self.embeddings(input_ids)
1648
+
1649
+ if self.gradient_checkpointing and self.training and use_cache:
1650
+ logger.warning_once(
1651
+ "`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`."
1652
+ )
1653
+ use_cache = False
1654
+
1655
+ # From zamba_modeling.py
1656
+ if use_cache and cache_params is None:
1657
+ logger.warning_once(
1658
+ "CENO requires an initialized `CENOHybridDynamicCache` to return a cache. None was "
1659
+ "provided, so no cache will be returned."
1660
+ )
1661
+
1662
+ hidden_states = inputs_embeds
1663
+
1664
+ if cache_position is None:
1665
+ cache_position = torch.arange(hidden_states.shape[1], device=hidden_states.device)
1666
+ if position_ids is None:
1667
+ position_ids = cache_position.unsqueeze(0)
1668
+
1669
+ causal_mask = self._update_causal_mask(attention_mask, inputs_embeds, cache_position)
1670
+ mamba_mask = self._update_mamba_mask(attention_mask, cache_position)
1671
+ if seq_idx is not None:
1672
+ seq_idx = seq_idx.to(device=hidden_states.device, dtype=torch.int32)
1673
+ if seq_idx.shape[1] > hidden_states.shape[1]:
1674
+ # seq_idx may be longer (extended for generate decode steps);
1675
+ # truncate to current hidden_states length (prefill or decode step)
1676
+ seq_idx = seq_idx[:, :hidden_states.shape[1]]
1677
+ if seq_idx.shape[1] != hidden_states.shape[1]:
1678
+ raise ValueError(
1679
+ f"seq_idx shape {seq_idx.shape[:2]} must match hidden_states shape {hidden_states.shape[:2]}"
1680
+ )
1681
+ intra_encoding_mask = getattr(self.config, "intra_encoding_mask", None)
1682
+ if intra_encoding_mask is None:
1683
+ intra_encoding_mask = [False for _ in range(len(self.layers))]
1684
+
1685
+ all_hidden_states = () if output_hidden_states else None
1686
+ all_self_attns = () if output_attentions else None
1687
+ # Until HERE
1688
+
1689
+ for layer_idx, mixer_block in enumerate(self.layers):
1690
+ use_seq_idx = False
1691
+ if seq_idx is not None:
1692
+ use_seq_idx = bool(intra_encoding_mask[layer_idx])
1693
+
1694
+ current_layer_seq_idx = seq_idx if use_seq_idx else None
1695
+ # Depending on the layer type we opt for 2D base attention mask (Mamba) or 4D causal mask (Attention)
1696
+ if mixer_block.block_type == "mamba":
1697
+ layer_mask = mamba_mask
1698
+ elif mixer_block.block_type == "attention":
1699
+ if current_layer_seq_idx is not None:
1700
+ layer_mask = self._merge_seq_idx_attention_mask(
1701
+ current_layer_seq_idx, causal_mask, hidden_states.shape[1], hidden_states.dtype
1702
+ )
1703
+ else:
1704
+ layer_mask = causal_mask
1705
+ elif mixer_block.block_type == "mlp":
1706
+ layer_mask = None
1707
+ elif mixer_block.block_type == "moe":
1708
+ layer_mask = None
1709
+ else:
1710
+ raise ValueError(f"Invalid block_type: {mixer_block.block_type}")
1711
+
1712
+ if output_hidden_states:
1713
+ all_hidden_states += (hidden_states,)
1714
+
1715
+ if self.gradient_checkpointing and self.training:
1716
+ hidden_states = self._gradient_checkpointing_func(
1717
+ mixer_block.__call__, hidden_states, cache_params, cache_position, layer_mask, current_layer_seq_idx
1718
+ )
1719
+ else:
1720
+ hidden_states = mixer_block(
1721
+ hidden_states,
1722
+ cache_params=cache_params,
1723
+ cache_position=cache_position,
1724
+ attention_mask=layer_mask,
1725
+ seq_idx=current_layer_seq_idx,
1726
+ )
1727
+
1728
+ # TODO: Store attentions
1729
+ # if output_attentions:
1730
+ # if layer_outputs[1] is not None:
1731
+ # # append attentions only of attention layers. Mamba layers return `None` as the attention weights
1732
+ # all_self_attns += (layer_outputs[1],)
1733
+
1734
+ # TODO (Check): should it happen before the forward pass?
1735
+ # if output_hidden_states:
1736
+ # all_hidden_states = all_hidden_states + (hidden_states,)
1737
+
1738
+ hidden_states = self.norm_f(hidden_states)
1739
+
1740
+ if output_hidden_states:
1741
+ all_hidden_states = all_hidden_states + (hidden_states,)
1742
+
1743
+ if not return_dict:
1744
+ return tuple(v for v in [hidden_states, cache_params, all_hidden_states] if v is not None)
1745
+
1746
+ return CENOOutput(
1747
+ last_hidden_state=hidden_states,
1748
+ cache_params=cache_params if use_cache else None,
1749
+ hidden_states=all_hidden_states,
1750
+ attentions=all_self_attns,
1751
+ )
1752
+
1753
+ # Copied from transformers.models.jamba.modeling_jamba.JambaModel._update_causal_mask
1754
+ def _update_causal_mask(self, attention_mask, input_tensor, cache_position):
1755
+ if self.config._attn_implementation == "flash_attention_2":
1756
+ if attention_mask is not None and 0.0 in attention_mask:
1757
+ return attention_mask
1758
+ return None
1759
+
1760
+ dtype, device = input_tensor.dtype, input_tensor.device
1761
+ min_dtype = torch.finfo(dtype).min
1762
+ sequence_length = input_tensor.shape[1]
1763
+ target_length = cache_position[-1] + 1
1764
+
1765
+ causal_mask = torch.full((sequence_length, target_length), fill_value=min_dtype, dtype=dtype, device=device)
1766
+ if sequence_length != 1:
1767
+ causal_mask = torch.triu(causal_mask, diagonal=1)
1768
+ causal_mask *= torch.arange(target_length, device=device) > cache_position.reshape(-1, 1)
1769
+ causal_mask = causal_mask[None, None, :, :].expand(input_tensor.shape[0], 1, -1, -1)
1770
+ if attention_mask is not None:
1771
+ causal_mask = causal_mask.clone() # copy to contiguous memory for in-place edit
1772
+ if attention_mask.dim() == 2:
1773
+ mask_length = attention_mask.shape[-1]
1774
+ padding_mask = causal_mask[..., :mask_length].eq(0.0) * attention_mask[:, None, None, :].eq(0.0)
1775
+ causal_mask[..., :mask_length] = causal_mask[..., :mask_length].masked_fill(padding_mask, min_dtype)
1776
+
1777
+ if (
1778
+ self.config._attn_implementation == "sdpa"
1779
+ and attention_mask is not None
1780
+ and attention_mask.device.type == "cuda"
1781
+ ):
1782
+ # Attend to all tokens in fully masked rows in the causal_mask, for example the relevant first rows when
1783
+ # using left padding. This is required by F.scaled_dot_product_attention memory-efficient attention path.
1784
+ # Details: https://github.com/pytorch/pytorch/issues/110213
1785
+ causal_mask = AttentionMaskConverter._unmask_unattended(causal_mask, min_dtype)
1786
+
1787
+ return causal_mask
1788
+
1789
+ def _update_mamba_mask(self, attention_mask, cache_position):
1790
+ """
1791
+ No need for zeroing states when
1792
+ 1. Cached forward
1793
+ 2. Attending to all inputs
1794
+ """
1795
+ mamba_mask = attention_mask
1796
+ if cache_position[0] > 0 or (attention_mask is not None and torch.all(attention_mask == 1)):
1797
+ mamba_mask = None
1798
+ return mamba_mask
1799
+
1800
+ def _merge_seq_idx_attention_mask(
1801
+ self,
1802
+ seq_idx: torch.Tensor,
1803
+ base_mask: Optional[torch.Tensor],
1804
+ target_len: int,
1805
+ dtype: torch.dtype,
1806
+ ):
1807
+ """
1808
+ Build an intra-sequence visibility mask from seq_idx and merge with an existing causal/padding mask.
1809
+ """
1810
+ seq_idx = seq_idx[:, :target_len]
1811
+ same_segment = seq_idx[:, None, :, None] == seq_idx[:, None, None, :]
1812
+ seg_mask = torch.where(
1813
+ same_segment,
1814
+ torch.zeros_like(same_segment, dtype=dtype),
1815
+ torch.full_like(same_segment, torch.finfo(dtype).min, dtype=dtype),
1816
+ )
1817
+ if base_mask is None:
1818
+ return seg_mask
1819
+ return base_mask[..., :target_len] + seg_mask
1820
+
1821
+
1822
+ @add_start_docstrings(
1823
+ """
1824
+ The CENO Model transformer with a language modeling head on top (linear layer with weights not tied to the input
1825
+ embeddings).
1826
+ """,
1827
+ CENO_START_DOCSTRING,
1828
+ )
1829
+ class CENOForCausalLM(CENOPreTrainedModel, GenerationMixin):
1830
+ _tied_weights_keys = ["lm_head.weight"]
1831
+
1832
+ def __init__(self, config):
1833
+ super().__init__(config)
1834
+ self.backbone = CENOModel(config)
1835
+ self.vocab_size = config.vocab_size
1836
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
1837
+
1838
+ # Initialize weights and apply final processing
1839
+ self.post_init()
1840
+
1841
+ def get_input_embeddings(self):
1842
+ return self.backbone.get_input_embeddings()
1843
+
1844
+ def set_input_embeddings(self, new_embeddings):
1845
+ return self.backbone.set_input_embeddings(new_embeddings)
1846
+
1847
+ def get_output_embeddings(self):
1848
+ return self.lm_head
1849
+
1850
+ def set_output_embeddings(self, new_embeddings):
1851
+ self.lm_head = new_embeddings
1852
+
1853
+ def get_decoder(self):
1854
+ return self.backbone
1855
+
1856
+ def set_decoder(self, decoder):
1857
+ self.backbone = decoder
1858
+
1859
+ def prepare_inputs_for_generation(
1860
+ self,
1861
+ input_ids,
1862
+ past_key_values=None,
1863
+ attention_mask=None,
1864
+ seq_idx=None,
1865
+ inputs_embeds=None,
1866
+ cache_position=None,
1867
+ position_ids=None,
1868
+ use_cache=True,
1869
+ **kwargs,
1870
+ ):
1871
+ # Copy from https://github.com/huggingface/transformers/blob/main/src/transformers/models/jamba/modeling_jamba.py
1872
+ # Overwitten -- uses `cache_params` as opposed to `past_key_values`
1873
+ empty_past_kv = past_key_values is None
1874
+
1875
+ # If we have cache: let's slice `input_ids` through `cache_position`, to keep only the unprocessed tokens
1876
+ # Exception 1: when passing input_embeds, input_ids may be missing entries
1877
+ # Exception 2: some generation methods do special slicing of input_ids, so we don't need to do it here
1878
+ # Exception 3: with synced GPUs cache_position may go out of bounds, but we only want dummy token in that case.
1879
+ # (we can't check exception 3 while compiling)
1880
+ if not empty_past_kv:
1881
+ if (
1882
+ inputs_embeds is not None # Exception 1
1883
+ or cache_position[-1] >= input_ids.shape[1] # Exception 3
1884
+ ):
1885
+ input_ids = input_ids[:, -cache_position.shape[0] :]
1886
+ if seq_idx is not None:
1887
+ seq_idx = seq_idx[:, -cache_position.shape[0] :]
1888
+ elif input_ids.shape[1] != cache_position.shape[0]: # Default case (the "else", a no op, is Exception 2)
1889
+ input_ids = input_ids[:, cache_position]
1890
+ if seq_idx is not None:
1891
+ seq_idx = seq_idx[:, cache_position]
1892
+ else:
1893
+ past_key_values = HybridMambaAttentionDynamicCache(
1894
+ self.config, input_ids.shape[0], self.dtype, device=self.device
1895
+ )
1896
+
1897
+ if attention_mask is not None and position_ids is None:
1898
+ # create position_ids on the fly for batch generation
1899
+ position_ids = attention_mask.long().cumsum(-1) - 1
1900
+ position_ids.masked_fill_(attention_mask == 0, 1)
1901
+ if not empty_past_kv:
1902
+ position_ids = position_ids[:, -input_ids.shape[1] :]
1903
+
1904
+ # if `inputs_embeds` are passed, we only want to use them in the 1st generation step
1905
+ if inputs_embeds is not None and empty_past_kv:
1906
+ model_inputs = {"inputs_embeds": inputs_embeds}
1907
+ else:
1908
+ model_inputs = {"input_ids": input_ids.contiguous()} # `contiguous()` needed for compilation use cases
1909
+
1910
+ model_inputs.update(
1911
+ {
1912
+ "position_ids": position_ids,
1913
+ "past_key_values": past_key_values,
1914
+ "use_cache": use_cache,
1915
+ "attention_mask": attention_mask,
1916
+ "seq_idx": seq_idx,
1917
+ "logits_to_keep": self.config.num_logits_to_keep,
1918
+ "cache_position": cache_position,
1919
+ }
1920
+ )
1921
+ return model_inputs
1922
+
1923
+ @add_start_docstrings_to_model_forward(CENO_INPUTS_DOCSTRING)
1924
+ @add_code_sample_docstrings(
1925
+ checkpoint=_CHECKPOINT_FOR_DOC,
1926
+ output_type=CENOCausalLMOutput,
1927
+ config_class=_CONFIG_FOR_DOC,
1928
+ )
1929
+ def forward(
1930
+ self,
1931
+ input_ids: Optional[torch.LongTensor] = None,
1932
+ inputs_embeds: Optional[torch.FloatTensor] = None,
1933
+ position_ids: Optional[torch.LongTensor] = None,
1934
+ cache_params: Optional[HybridMambaAttentionDynamicCache] = None,
1935
+ past_key_values: Optional[HybridMambaAttentionDynamicCache] = None,
1936
+ labels: Optional[torch.LongTensor] = None,
1937
+ output_attentions: Optional[bool] = None,
1938
+ output_hidden_states: Optional[bool] = None,
1939
+ return_dict: Optional[bool] = None,
1940
+ use_cache: Optional[bool] = None,
1941
+ cache_position: Optional[torch.Tensor] = None,
1942
+ attention_mask: Optional[torch.Tensor] = None,
1943
+ seq_idx: Optional[torch.Tensor] = None,
1944
+ **kwargs, # for now we need this for generation
1945
+ ) -> Union[Tuple, CENOCausalLMOutput]:
1946
+ r"""
1947
+ labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
1948
+ Labels for language modeling. Note that the labels **are shifted** inside the model, i.e. you can set
1949
+ `labels = input_ids` Indices are selected in `[-100, 0, ..., config.vocab_size]` All labels set to `-100`
1950
+ are ignored (masked), the loss is only computed for labels in `[0, ..., config.vocab_size]`
1951
+ """
1952
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
1953
+
1954
+ output_hidden_states = (
1955
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
1956
+ )
1957
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
1958
+
1959
+ if cache_params is None and past_key_values is not None:
1960
+ cache_params = past_key_values
1961
+
1962
+ ceno_outputs = self.backbone(
1963
+ input_ids,
1964
+ cache_params=cache_params,
1965
+ inputs_embeds=inputs_embeds,
1966
+ output_attentions=output_attentions,
1967
+ output_hidden_states=output_hidden_states,
1968
+ return_dict=return_dict,
1969
+ use_cache=use_cache,
1970
+ cache_position=cache_position,
1971
+ attention_mask=attention_mask,
1972
+ seq_idx=seq_idx,
1973
+ )
1974
+ hidden_states = ceno_outputs[0]
1975
+
1976
+ # TODO: Check zamba_modeling.py: https://github.com/huggingface/transformers/blob/d7188ba600e36d3fd191b12e19f1b3bb81a8404f/src/transformers/models/zamba/modeling_zamba.py#L1284C1-L1286C2
1977
+ #logits = self.lm_head(hidden_states.to(self.lm_head.weight.dtype)).float()
1978
+ logits = self.lm_head(hidden_states.to(self.lm_head.weight.dtype)).float()
1979
+
1980
+ loss = None
1981
+ if labels is not None:
1982
+ # move labels to correct device to enable model parallelism
1983
+ labels = labels.to(logits.device)
1984
+ # Shift so that tokens < n predict n
1985
+ shift_logits = logits[..., :-1, :].contiguous()
1986
+ shift_labels = labels[..., 1:].contiguous()
1987
+ # Flatten the tokens
1988
+ loss_fct = CrossEntropyLoss()
1989
+ loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
1990
+
1991
+ if not return_dict:
1992
+ output = (logits,) + ceno_outputs[1:]
1993
+ return ((loss,) + output) if loss is not None else output
1994
+
1995
+ return CENOCausalLMOutput(
1996
+ loss=loss,
1997
+ logits=logits,
1998
+ cache_params=ceno_outputs.cache_params,
1999
+ past_key_values=ceno_outputs.cache_params,
2000
+ hidden_states=ceno_outputs.hidden_states,
2001
+ attentions=ceno_outputs.attentions,
2002
+ )
special_tokens_map.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "eos_token": "<eos>",
3
+ "pad_token": "<pad>",
4
+ "unk_token": "<unk>"
5
+ }
tokenizer_config.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tokenizer_class": "CENOCharLevelTokenizer",
3
+ "vocab_size": 512,
4
+ "eos_token": "<eos>",
5
+ "pad_token": "<pad>",
6
+ "unk_token": "<unk>",
7
+ "eod_id": 0,
8
+ "eos_id": 0,
9
+ "pad_id": 1,
10
+ "unk_id": 2,
11
+ "model_max_length": 1000000000000000019884624838656,
12
+ "clean_up_tokenization_spaces": true,
13
+ "tokenize_chinese_chars": false,
14
+ "strip_accents": null,
15
+ "do_lower_case": false,
16
+ "do_basic_tokenize": false,
17
+ "never_split": null,
18
+ "tokenizer_type": "CharLevelTokenizer",
19
+ "name_or_path": "./ceno_tokenizer",
20
+ "auto_map": {
21
+ "AutoTokenizer": [
22
+ "ceno_tokenizer.CENOCharLevelTokenizer",
23
+ null
24
+ ]
25
+ }
26
+ }
vocab.json ADDED
@@ -0,0 +1,485 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ " ": 32,
3
+ "!": 33,
4
+ "\"": 34,
5
+ "#": 35,
6
+ "$": 36,
7
+ "%": 37,
8
+ "&": 38,
9
+ "'": 39,
10
+ "(": 40,
11
+ ")": 41,
12
+ "*": 42,
13
+ "+": 43,
14
+ ",": 44,
15
+ "-": 45,
16
+ ".": 46,
17
+ "/": 47,
18
+ "0": 48,
19
+ "1": 49,
20
+ "2": 50,
21
+ "3": 51,
22
+ "4": 52,
23
+ "5": 53,
24
+ "6": 54,
25
+ "7": 55,
26
+ "8": 56,
27
+ "9": 57,
28
+ ":": 58,
29
+ ";": 59,
30
+ "<": 60,
31
+ "<byte_127>": 127,
32
+ "<byte_128>": 128,
33
+ "<byte_129>": 129,
34
+ "<byte_130>": 130,
35
+ "<byte_131>": 131,
36
+ "<byte_132>": 132,
37
+ "<byte_133>": 133,
38
+ "<byte_134>": 134,
39
+ "<byte_135>": 135,
40
+ "<byte_136>": 136,
41
+ "<byte_137>": 137,
42
+ "<byte_138>": 138,
43
+ "<byte_139>": 139,
44
+ "<byte_140>": 140,
45
+ "<byte_141>": 141,
46
+ "<byte_142>": 142,
47
+ "<byte_143>": 143,
48
+ "<byte_144>": 144,
49
+ "<byte_145>": 145,
50
+ "<byte_146>": 146,
51
+ "<byte_147>": 147,
52
+ "<byte_148>": 148,
53
+ "<byte_149>": 149,
54
+ "<byte_150>": 150,
55
+ "<byte_151>": 151,
56
+ "<byte_152>": 152,
57
+ "<byte_153>": 153,
58
+ "<byte_154>": 154,
59
+ "<byte_155>": 155,
60
+ "<byte_156>": 156,
61
+ "<byte_157>": 157,
62
+ "<byte_158>": 158,
63
+ "<byte_159>": 159,
64
+ "<byte_160>": 160,
65
+ "<byte_161>": 161,
66
+ "<byte_162>": 162,
67
+ "<byte_163>": 163,
68
+ "<byte_164>": 164,
69
+ "<byte_165>": 165,
70
+ "<byte_166>": 166,
71
+ "<byte_167>": 167,
72
+ "<byte_168>": 168,
73
+ "<byte_169>": 169,
74
+ "<byte_170>": 170,
75
+ "<byte_171>": 171,
76
+ "<byte_172>": 172,
77
+ "<byte_173>": 173,
78
+ "<byte_174>": 174,
79
+ "<byte_175>": 175,
80
+ "<byte_176>": 176,
81
+ "<byte_177>": 177,
82
+ "<byte_178>": 178,
83
+ "<byte_179>": 179,
84
+ "<byte_180>": 180,
85
+ "<byte_181>": 181,
86
+ "<byte_182>": 182,
87
+ "<byte_183>": 183,
88
+ "<byte_184>": 184,
89
+ "<byte_185>": 185,
90
+ "<byte_186>": 186,
91
+ "<byte_187>": 187,
92
+ "<byte_188>": 188,
93
+ "<byte_189>": 189,
94
+ "<byte_190>": 190,
95
+ "<byte_191>": 191,
96
+ "<byte_192>": 192,
97
+ "<byte_193>": 193,
98
+ "<byte_194>": 194,
99
+ "<byte_195>": 195,
100
+ "<byte_196>": 196,
101
+ "<byte_197>": 197,
102
+ "<byte_198>": 198,
103
+ "<byte_199>": 199,
104
+ "<byte_200>": 200,
105
+ "<byte_201>": 201,
106
+ "<byte_202>": 202,
107
+ "<byte_203>": 203,
108
+ "<byte_204>": 204,
109
+ "<byte_205>": 205,
110
+ "<byte_206>": 206,
111
+ "<byte_207>": 207,
112
+ "<byte_208>": 208,
113
+ "<byte_209>": 209,
114
+ "<byte_210>": 210,
115
+ "<byte_211>": 211,
116
+ "<byte_212>": 212,
117
+ "<byte_213>": 213,
118
+ "<byte_214>": 214,
119
+ "<byte_215>": 215,
120
+ "<byte_216>": 216,
121
+ "<byte_217>": 217,
122
+ "<byte_218>": 218,
123
+ "<byte_219>": 219,
124
+ "<byte_220>": 220,
125
+ "<byte_221>": 221,
126
+ "<byte_222>": 222,
127
+ "<byte_223>": 223,
128
+ "<byte_224>": 224,
129
+ "<byte_225>": 225,
130
+ "<byte_226>": 226,
131
+ "<byte_227>": 227,
132
+ "<byte_228>": 228,
133
+ "<byte_229>": 229,
134
+ "<byte_230>": 230,
135
+ "<byte_231>": 231,
136
+ "<byte_232>": 232,
137
+ "<byte_233>": 233,
138
+ "<byte_234>": 234,
139
+ "<byte_235>": 235,
140
+ "<byte_236>": 236,
141
+ "<byte_237>": 237,
142
+ "<byte_238>": 238,
143
+ "<byte_239>": 239,
144
+ "<byte_240>": 240,
145
+ "<byte_241>": 241,
146
+ "<byte_242>": 242,
147
+ "<byte_243>": 243,
148
+ "<byte_244>": 244,
149
+ "<byte_245>": 245,
150
+ "<byte_246>": 246,
151
+ "<byte_247>": 247,
152
+ "<byte_248>": 248,
153
+ "<byte_249>": 249,
154
+ "<byte_250>": 250,
155
+ "<byte_251>": 251,
156
+ "<byte_252>": 252,
157
+ "<byte_253>": 253,
158
+ "<byte_254>": 254,
159
+ "<byte_255>": 255,
160
+ "<byte_256>": 256,
161
+ "<byte_257>": 257,
162
+ "<byte_258>": 258,
163
+ "<byte_259>": 259,
164
+ "<byte_260>": 260,
165
+ "<byte_261>": 261,
166
+ "<byte_262>": 262,
167
+ "<byte_263>": 263,
168
+ "<byte_264>": 264,
169
+ "<byte_265>": 265,
170
+ "<byte_266>": 266,
171
+ "<byte_267>": 267,
172
+ "<byte_268>": 268,
173
+ "<byte_269>": 269,
174
+ "<byte_270>": 270,
175
+ "<byte_271>": 271,
176
+ "<byte_272>": 272,
177
+ "<byte_273>": 273,
178
+ "<byte_274>": 274,
179
+ "<byte_275>": 275,
180
+ "<byte_276>": 276,
181
+ "<byte_277>": 277,
182
+ "<byte_278>": 278,
183
+ "<byte_279>": 279,
184
+ "<byte_280>": 280,
185
+ "<byte_281>": 281,
186
+ "<byte_282>": 282,
187
+ "<byte_283>": 283,
188
+ "<byte_284>": 284,
189
+ "<byte_285>": 285,
190
+ "<byte_286>": 286,
191
+ "<byte_287>": 287,
192
+ "<byte_288>": 288,
193
+ "<byte_289>": 289,
194
+ "<byte_290>": 290,
195
+ "<byte_291>": 291,
196
+ "<byte_292>": 292,
197
+ "<byte_293>": 293,
198
+ "<byte_294>": 294,
199
+ "<byte_295>": 295,
200
+ "<byte_296>": 296,
201
+ "<byte_297>": 297,
202
+ "<byte_298>": 298,
203
+ "<byte_299>": 299,
204
+ "<byte_300>": 300,
205
+ "<byte_301>": 301,
206
+ "<byte_302>": 302,
207
+ "<byte_303>": 303,
208
+ "<byte_304>": 304,
209
+ "<byte_305>": 305,
210
+ "<byte_306>": 306,
211
+ "<byte_307>": 307,
212
+ "<byte_308>": 308,
213
+ "<byte_309>": 309,
214
+ "<byte_310>": 310,
215
+ "<byte_311>": 311,
216
+ "<byte_312>": 312,
217
+ "<byte_313>": 313,
218
+ "<byte_314>": 314,
219
+ "<byte_315>": 315,
220
+ "<byte_316>": 316,
221
+ "<byte_317>": 317,
222
+ "<byte_318>": 318,
223
+ "<byte_319>": 319,
224
+ "<byte_320>": 320,
225
+ "<byte_321>": 321,
226
+ "<byte_322>": 322,
227
+ "<byte_323>": 323,
228
+ "<byte_324>": 324,
229
+ "<byte_325>": 325,
230
+ "<byte_326>": 326,
231
+ "<byte_327>": 327,
232
+ "<byte_328>": 328,
233
+ "<byte_329>": 329,
234
+ "<byte_330>": 330,
235
+ "<byte_331>": 331,
236
+ "<byte_332>": 332,
237
+ "<byte_333>": 333,
238
+ "<byte_334>": 334,
239
+ "<byte_335>": 335,
240
+ "<byte_336>": 336,
241
+ "<byte_337>": 337,
242
+ "<byte_338>": 338,
243
+ "<byte_339>": 339,
244
+ "<byte_340>": 340,
245
+ "<byte_341>": 341,
246
+ "<byte_342>": 342,
247
+ "<byte_343>": 343,
248
+ "<byte_344>": 344,
249
+ "<byte_345>": 345,
250
+ "<byte_346>": 346,
251
+ "<byte_347>": 347,
252
+ "<byte_348>": 348,
253
+ "<byte_349>": 349,
254
+ "<byte_350>": 350,
255
+ "<byte_351>": 351,
256
+ "<byte_352>": 352,
257
+ "<byte_353>": 353,
258
+ "<byte_354>": 354,
259
+ "<byte_355>": 355,
260
+ "<byte_356>": 356,
261
+ "<byte_357>": 357,
262
+ "<byte_358>": 358,
263
+ "<byte_359>": 359,
264
+ "<byte_360>": 360,
265
+ "<byte_361>": 361,
266
+ "<byte_362>": 362,
267
+ "<byte_363>": 363,
268
+ "<byte_364>": 364,
269
+ "<byte_365>": 365,
270
+ "<byte_366>": 366,
271
+ "<byte_367>": 367,
272
+ "<byte_368>": 368,
273
+ "<byte_369>": 369,
274
+ "<byte_370>": 370,
275
+ "<byte_371>": 371,
276
+ "<byte_372>": 372,
277
+ "<byte_373>": 373,
278
+ "<byte_374>": 374,
279
+ "<byte_375>": 375,
280
+ "<byte_376>": 376,
281
+ "<byte_377>": 377,
282
+ "<byte_378>": 378,
283
+ "<byte_379>": 379,
284
+ "<byte_380>": 380,
285
+ "<byte_381>": 381,
286
+ "<byte_382>": 382,
287
+ "<byte_383>": 383,
288
+ "<byte_384>": 384,
289
+ "<byte_385>": 385,
290
+ "<byte_386>": 386,
291
+ "<byte_387>": 387,
292
+ "<byte_388>": 388,
293
+ "<byte_389>": 389,
294
+ "<byte_390>": 390,
295
+ "<byte_391>": 391,
296
+ "<byte_392>": 392,
297
+ "<byte_393>": 393,
298
+ "<byte_394>": 394,
299
+ "<byte_395>": 395,
300
+ "<byte_396>": 396,
301
+ "<byte_397>": 397,
302
+ "<byte_398>": 398,
303
+ "<byte_399>": 399,
304
+ "<byte_400>": 400,
305
+ "<byte_401>": 401,
306
+ "<byte_402>": 402,
307
+ "<byte_403>": 403,
308
+ "<byte_404>": 404,
309
+ "<byte_405>": 405,
310
+ "<byte_406>": 406,
311
+ "<byte_407>": 407,
312
+ "<byte_408>": 408,
313
+ "<byte_409>": 409,
314
+ "<byte_410>": 410,
315
+ "<byte_411>": 411,
316
+ "<byte_412>": 412,
317
+ "<byte_413>": 413,
318
+ "<byte_414>": 414,
319
+ "<byte_415>": 415,
320
+ "<byte_416>": 416,
321
+ "<byte_417>": 417,
322
+ "<byte_418>": 418,
323
+ "<byte_419>": 419,
324
+ "<byte_420>": 420,
325
+ "<byte_421>": 421,
326
+ "<byte_422>": 422,
327
+ "<byte_423>": 423,
328
+ "<byte_424>": 424,
329
+ "<byte_425>": 425,
330
+ "<byte_426>": 426,
331
+ "<byte_427>": 427,
332
+ "<byte_428>": 428,
333
+ "<byte_429>": 429,
334
+ "<byte_430>": 430,
335
+ "<byte_431>": 431,
336
+ "<byte_432>": 432,
337
+ "<byte_433>": 433,
338
+ "<byte_434>": 434,
339
+ "<byte_435>": 435,
340
+ "<byte_436>": 436,
341
+ "<byte_437>": 437,
342
+ "<byte_438>": 438,
343
+ "<byte_439>": 439,
344
+ "<byte_440>": 440,
345
+ "<byte_441>": 441,
346
+ "<byte_442>": 442,
347
+ "<byte_443>": 443,
348
+ "<byte_444>": 444,
349
+ "<byte_445>": 445,
350
+ "<byte_446>": 446,
351
+ "<byte_447>": 447,
352
+ "<byte_448>": 448,
353
+ "<byte_449>": 449,
354
+ "<byte_450>": 450,
355
+ "<byte_451>": 451,
356
+ "<byte_452>": 452,
357
+ "<byte_453>": 453,
358
+ "<byte_454>": 454,
359
+ "<byte_455>": 455,
360
+ "<byte_456>": 456,
361
+ "<byte_457>": 457,
362
+ "<byte_458>": 458,
363
+ "<byte_459>": 459,
364
+ "<byte_460>": 460,
365
+ "<byte_461>": 461,
366
+ "<byte_462>": 462,
367
+ "<byte_463>": 463,
368
+ "<byte_464>": 464,
369
+ "<byte_465>": 465,
370
+ "<byte_466>": 466,
371
+ "<byte_467>": 467,
372
+ "<byte_468>": 468,
373
+ "<byte_469>": 469,
374
+ "<byte_470>": 470,
375
+ "<byte_471>": 471,
376
+ "<byte_472>": 472,
377
+ "<byte_473>": 473,
378
+ "<byte_474>": 474,
379
+ "<byte_475>": 475,
380
+ "<byte_476>": 476,
381
+ "<byte_477>": 477,
382
+ "<byte_478>": 478,
383
+ "<byte_479>": 479,
384
+ "<byte_480>": 480,
385
+ "<byte_481>": 481,
386
+ "<byte_482>": 482,
387
+ "<byte_483>": 483,
388
+ "<byte_484>": 484,
389
+ "<byte_485>": 485,
390
+ "<byte_486>": 486,
391
+ "<byte_487>": 487,
392
+ "<byte_488>": 488,
393
+ "<byte_489>": 489,
394
+ "<byte_490>": 490,
395
+ "<byte_491>": 491,
396
+ "<byte_492>": 492,
397
+ "<byte_493>": 493,
398
+ "<byte_494>": 494,
399
+ "<byte_495>": 495,
400
+ "<byte_496>": 496,
401
+ "<byte_497>": 497,
402
+ "<byte_498>": 498,
403
+ "<byte_499>": 499,
404
+ "<byte_500>": 500,
405
+ "<byte_501>": 501,
406
+ "<byte_502>": 502,
407
+ "<byte_503>": 503,
408
+ "<byte_504>": 504,
409
+ "<byte_505>": 505,
410
+ "<byte_506>": 506,
411
+ "<byte_507>": 507,
412
+ "<byte_508>": 508,
413
+ "<byte_509>": 509,
414
+ "<byte_510>": 510,
415
+ "<byte_511>": 511,
416
+ "<eos>": 0,
417
+ "<pad>": 1,
418
+ "<unk>": 2,
419
+ "=": 61,
420
+ ">": 62,
421
+ "?": 63,
422
+ "@": 64,
423
+ "A": 65,
424
+ "B": 66,
425
+ "C": 67,
426
+ "D": 68,
427
+ "E": 69,
428
+ "F": 70,
429
+ "G": 71,
430
+ "H": 72,
431
+ "I": 73,
432
+ "J": 74,
433
+ "K": 75,
434
+ "L": 76,
435
+ "M": 77,
436
+ "N": 78,
437
+ "O": 79,
438
+ "P": 80,
439
+ "Q": 81,
440
+ "R": 82,
441
+ "S": 83,
442
+ "T": 84,
443
+ "U": 85,
444
+ "V": 86,
445
+ "W": 87,
446
+ "X": 88,
447
+ "Y": 89,
448
+ "Z": 90,
449
+ "[": 91,
450
+ "\\": 92,
451
+ "]": 93,
452
+ "^": 94,
453
+ "_": 95,
454
+ "`": 96,
455
+ "a": 97,
456
+ "b": 98,
457
+ "c": 99,
458
+ "d": 100,
459
+ "e": 101,
460
+ "f": 102,
461
+ "g": 103,
462
+ "h": 104,
463
+ "i": 105,
464
+ "j": 106,
465
+ "k": 107,
466
+ "l": 108,
467
+ "m": 109,
468
+ "n": 110,
469
+ "o": 111,
470
+ "p": 112,
471
+ "q": 113,
472
+ "r": 114,
473
+ "s": 115,
474
+ "t": 116,
475
+ "u": 117,
476
+ "v": 118,
477
+ "w": 119,
478
+ "x": 120,
479
+ "y": 121,
480
+ "z": 122,
481
+ "{": 123,
482
+ "|": 124,
483
+ "}": 125,
484
+ "~": 126
485
+ }