Text Generation
Transformers
Safetensors
English
fabric
efficient
0.7b
causal-lm
chunked-memory
conversational
custom_code
tudor-iustin22 commited on
Commit
ea1882d
·
verified ·
1 Parent(s): a7dacaf

Upload 17 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ banner_fabric.png filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Fabric AI Open License v1.0
2
+
3
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
4
+
5
+ 1. Definitions.
6
+
7
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by this document.
8
+
9
+ "Licensor" shall mean Fabric AI.
10
+
11
+ "You" (or "Your") shall mean an individual or legal entity exercising permissions granted by this License.
12
+
13
+ "Work" shall mean the work of authorship, whether in source or object form, made available under this License.
14
+
15
+ "Derivative Works" shall mean any work that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.
16
+
17
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, Licensor hereby grants You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and Derivative Works in source or object form.
18
+
19
+ 3. Grant of Patent License. Licensor hereby grants You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License shall terminate as of the date such litigation is filed.
20
+
21
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in source or object form, provided that You meet the following conditions:
22
+
23
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
24
+
25
+ (b) You must cause any modified files to carry prominent notices stating that You changed them; and
26
+
27
+ (c) You must retain, in the source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the source form of the Work; and
28
+
29
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works You distribute must include a readable copy of the attribution notices contained within such NOTICE file.
30
+
31
+ 5. Attribution. Any use, reproduction, or distribution of the Work or Derivative Works must include the following attribution in a reasonable manner:
32
+
33
+ "Based on Fabric 1.5 by Fabric AI."
34
+
35
+ You may add Your own attribution to Your modifications, but the above attribution to Fabric AI must remain intact.
36
+
37
+ 6. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including without limitation any warranties of merchantability, fitness for a particular purpose, or non-infringement.
38
+
39
+ 7. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall Licensor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages arising as a result of this License or out of the use or inability to use the Work, even if Licensor has been advised of the possibility of such damages.
40
+
41
+ 8. Termination. This License will terminate automatically and immediately if You fail to comply with any of its terms and conditions. Upon termination, You must cease all use of the Work and any Derivative Works.
42
+
43
+ END OF TERMS AND CONDITIONS
README.md ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ language:
4
+ - en
5
+ library_name: transformers
6
+ pipeline_tag: text-generation
7
+ tags:
8
+ - fabric
9
+ - efficient
10
+ - 0.7b
11
+ - causal-lm
12
+ - chunked-memory
13
+ base_model: FabricAI/Fabric1.5-0.7B-Base
14
+ datasets:
15
+ - HuggingFaceTB/smoltalk2
16
+ - open-r1/Mixture-of-Thoughts
17
+ - nvidia/Nemotron-Post-Training-Dataset-v1
18
+ extra:
19
+ model_name: Fabric1.5-0.7B-Instruct
20
+ model_creator: Fabric AI
21
+ developer: Fabric AI
22
+ model_type: fabric
23
+ context_length: 32768
24
+ ---
25
+
26
+ ![Fabric 1.5 Banner](banner_fabric.png)
27
+
28
+ # Fabric 1.5 — 0.7B Instruct
29
+
30
+ **Fabric 1.5** is a lightweight, high-capability language model developed by **Fabric AI**. It introduces a novel chunked memory architecture and demonstrates that a 0.7B parameter model can achieve meaningful performance on reasoning, knowledge, and instruction-following tasks.
31
+
32
+ ## Model Details
33
+
34
+ - **Type:** Causal Language Model
35
+ - **Parameters:** 742M (0.7B)
36
+ - **Hidden Dimension:** 1,536
37
+ - **Vocabulary Size:** 65,536
38
+ - **Layers:** 24 (16 LocalBlock + 8 FabricMemoryBlock)
39
+ - **Attention:** GQA (24 query heads, 6 KV heads), RoPE (theta=1M)
40
+ - **Context Length:** 32,768 tokens native
41
+ - **Precision:** FP16
42
+ - **License:** Fabric AI Open License v1.0
43
+
44
+ ## Architecture
45
+
46
+ Fabric 1.5 employs a **Chunked Fabric Memory** architecture — every 3rd block splits attention into two parallel branches:
47
+ - **Local causal window:** exact attention over the last 2,048 tokens
48
+ - **Chunked memory:** learned summaries (4 per 512-token chunk) of earlier completed chunks
49
+
50
+ A per-token scalar gate blends the outputs, giving the model 256 summary vectors of long-range memory at full 32K context without quadratic memory growth.
51
+
52
+ ## Benchmark Results
53
+
54
+ Evaluated on an **NVIDIA A100-SXM4-40GB** using `lm-eval` harness with FP16 weights.
55
+
56
+ | Benchmark | Accuracy | Type |
57
+ |---|---|---|
58
+ | **ARC Easy** (0-shot) | **54.97%** | Loglikelihood |
59
+ | **ARC Challenge** (0-shot) | **26.88%** | Loglikelihood |
60
+ | **HellaSwag** (0-shot) | **35.00%** | Loglikelihood |
61
+ | **MMLU** (0-shot) | **28.96%** | Loglikelihood |
62
+ | **C-Eval** (0-shot) | **27.12%** | Loglikelihood |
63
+
64
+ ### Comparison vs Qwen3.5-0.8B
65
+
66
+ | Benchmark | Fabric 1.5 | Qwen3.5-0.8B | Delta |
67
+ |---|---|---|---|
68
+ | **MMLU** (0-shot) | **28.96%** | 29.7% | -0.74% |
69
+ | **C-Eval** (0-shot) | **27.12%** | 46.4% | -19.28% |
70
+
71
+ Fabric 1.5 performs within **0.74% of Qwen3.5-0.8B** on MMLU despite being 12% smaller (0.7B vs 0.8B) and having no vision encoder.
72
+
73
+ ## Quickstart
74
+
75
+ ```python
76
+ import torch
77
+ from transformers import AutoModelForCausalLM, AutoTokenizer
78
+
79
+ model_id = "FabricAI/Fabric1.5-0.7B-Instruct"
80
+
81
+ tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
82
+ model = AutoModelForCausalLM.from_pretrained(
83
+ model_id,
84
+ trust_remote_code=True,
85
+ torch_dtype=torch.float16,
86
+ device_map="auto",
87
+ )
88
+
89
+ messages = [{"role": "user", "content": "What is gravity?"}]
90
+ text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
91
+ inputs = tokenizer(text, return_tensors="pt").to(model.device)
92
+
93
+ with torch.no_grad():
94
+ output_ids = model.generate(
95
+ **inputs,
96
+ max_new_tokens=256,
97
+ do_sample=True,
98
+ temperature=0.65,
99
+ top_p=0.9,
100
+ repetition_penalty=1.05,
101
+ use_cache=True,
102
+ )
103
+
104
+ response = tokenizer.decode(output_ids[0, inputs["input_ids"].shape[1]:], skip_special_tokens=True).strip()
105
+ print(response)
106
+ ```
107
+
108
+ ## Chat Template
109
+
110
+ ```
111
+ <|bos|><|system|>
112
+ You are Fabric, a large language model developed by Fabric AI.<|end|>
113
+ <|user|>
114
+ Hello!<|end|>
115
+ <|assistant|>
116
+ Hi! How can I help you?<|end|>
117
+ ```
118
+
119
+ Special tokens: `<bos>`, `<pad>`, `<|end|>`, `<|system|>`, `<|user|>`, `<|assistant|>`
120
+
121
+ ## Sampling Parameters
122
+
123
+ | Mode | Temperature | Top-p | Top-k | Repetition Penalty |
124
+ |------|------------|-------|-------|-------------------|
125
+ | General chat | 0.65 | 0.90 | 50 | 1.05 |
126
+ | Creative writing | 0.80 | 0.95 | 50 | 1.00 |
127
+ | Factual/knowledge | 0.40 | 0.85 | 30 | 1.05 |
128
+ | Code generation | 0.30 | 0.90 | 40 | 1.02 |
129
+
130
+ ## Training Data & Process
131
+
132
+ **Pre-training (18B tokens, 1× NVIDIA DGX H100 8-GPU):**
133
+
134
+ | Source | Weight | Description |
135
+ |---|---|---|
136
+ | FineWeb-Edu | 60% | High-quality educational web text |
137
+ | DCLM-Baseline | 25% | Deduplicated Common Crawl subset |
138
+ | OpenWebMath | 10% | Math-focused web text |
139
+ | Cosmopedia-v2 | 5% | Instruction-tuned educational data |
140
+
141
+ - **Optimizer:** AdamW (β1=0.9, β2=0.95, ε=1e-8)
142
+ - **Learning rate:** 3e-4 with cosine decay to 3e-5, 180M token warmup
143
+ - **Weight decay:** 0.1
144
+ - **Gradient clipping:** 1.0
145
+ - **Precision:** FP16
146
+ - **Distributed:** NCCL, 8 ranks, 4 sequences per GPU
147
+
148
+ **Post-training (SFT):**
149
+ 1. Identity tuning — system prompt alignment and persona training
150
+ 2. General SFT — diverse instruction-following datasets
151
+
152
+ ## Hardware Notes
153
+
154
+ Fabric 1.5 was trained on a **single NVIDIA DGX H100** node with 8× H100 80GB GPUs. The model runs efficiently on:
155
+
156
+ | Hardware | Precision | Batch Size | Context |
157
+ |---|---|---|---|
158
+ | 1× NVIDIA H100 80GB | FP16 | 8 | 32K |
159
+ | 1× NVIDIA A100 40GB | FP16 | 4 | 32K |
160
+ | Apple Silicon (MPS) | FP16 | 1 | 32K |
161
+ | CPU | FP32 | 1 | 32K |
162
+
163
+ The chunked memory architecture ensures memory scales linearly with context, not quadratically.
164
+
165
+ ## License
166
+
167
+ **Fabric AI Open License v1.0** — a permissive, attribution-required license. See [LICENSE](LICENSE) for full terms.
168
+
169
+ Key requirements:
170
+ - You may use, modify, and distribute the model freely
171
+ - You must **retain attribution** to Fabric AI when redistributing
172
+ - Modified files must carry notices of your changes
173
+ - No warranty or liability provisions
174
+
175
+ ## Citation
176
+
177
+ ```bibtex
178
+ @misc{fabric1.5,
179
+ title = {{Fabric 1.5}: A Causal Language Model with Chunked Fabric Memory},
180
+ author = {Fabric AI},
181
+ year = 2026,
182
+ }
183
+ ```
banner_fabric.png ADDED

Git LFS Details

  • SHA256: 8c7f54394e42cbe74c900cdf446bb3cdbff0bd0c2fe77f21a0360c5ef1eb1746
  • Pointer size: 132 Bytes
  • Size of remote file: 2.42 MB
chat_template.jinja ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {% set default_system_prompt = "You are Fabric, a large language model developed by Fabric AI." %}{% set ns = namespace(has_system=false) %}{% for message in messages %}{% if message['role'] == 'system' %}{% set ns.has_system = true %}{% endif %}{% endfor %}{% if not ns.has_system %}<|system|>
2
+ {{ default_system_prompt }}<|end|>
3
+ {% endif %}{% for message in messages %}{% if message['role'] == 'system' %}<|system|>
4
+ {{ message['content'] }}<|end|>
5
+ {% elif message['role'] == 'user' %}<|user|>
6
+ {{ message['content'] }}<|end|>
7
+ {% elif message['role'] == 'assistant' %}<|assistant|>
8
+ {{ message['content'] }}<|end|>
9
+ {% endif %}{% endfor %}{% if add_generation_prompt %}<|assistant|>
10
+ {% endif %}
config.json ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "activation_checkpointing": true,
3
+ "architecture": "fabric",
4
+ "architectures": [
5
+ "FabricForCausalLM"
6
+ ],
7
+ "attention_backend": "auto",
8
+ "attention_chunk_size": 1024,
9
+ "auto_map": {
10
+ "AutoConfig": "configuration_fabric.FabricConfig",
11
+ "AutoModelForCausalLM": "modeling_fabric.FabricForCausalLM"
12
+ },
13
+ "bos_token_id": 2,
14
+ "checkpoint_dtype": "float16",
15
+ "checkpoint_note": "Model-only Fabric complete checkpoint; optimizer state is excluded.",
16
+ "checkpoint_sha256": "a8d12a687fe5eaa05b601ab2803ca2c14b9cc2c14d754110ca4569b061af2bf1",
17
+ "checkpoint_size_gib": 1.383114,
18
+ "chunked_cross_entropy": true,
19
+ "continued_pretraining_tokens": 5000134656,
20
+ "cumulative_pretraining_tokens": 23000514560,
21
+ "eos_token_id": 7,
22
+ "export_kind": "model_only_inference_fp16",
23
+ "head_dim": 64,
24
+ "hidden_size": 1536,
25
+ "intermediate_size": 4096,
26
+ "license": "fabric-ai-open-1.0",
27
+ "local_attention_window": 2048,
28
+ "loss_chunk_size": 1024,
29
+ "max_position_embeddings": 32768,
30
+ "memory_chunk_size": 512,
31
+ "model_name": "Fabric1.5-0.7B-Instruct",
32
+ "model_type": "fabric",
33
+ "num_attention_heads": 24,
34
+ "num_hidden_layers": 24,
35
+ "num_key_value_heads": 6,
36
+ "num_kv_heads": 6,
37
+ "num_layers": 24,
38
+ "num_parameters": 742528520,
39
+ "num_query_heads": 24,
40
+ "original_pretraining_tokens": 18000379904,
41
+ "pad_token_id": 0,
42
+ "posttraining_supervised_tokens": 318879711,
43
+ "rms_norm_eps": 1e-06,
44
+ "rope_theta": 1000000.0,
45
+ "sequence_length": 32768,
46
+ "summaries_per_chunk": 4,
47
+ "tie_word_embeddings": true,
48
+ "torch_dtype": "float16",
49
+ "transformers_version": "custom",
50
+ "use_cache": false,
51
+ "vocab_size": 65536
52
+ }
configuration_fabric.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from transformers import PretrainedConfig
4
+
5
+
6
+ class FabricConfig(PretrainedConfig):
7
+ model_type = "fabric"
8
+
9
+ def __init__(
10
+ self,
11
+ model_name: str = "Fabric 1.5",
12
+ architecture: str = "fabric",
13
+ vocab_size: int = 65536,
14
+ hidden_size: int = 1536,
15
+ intermediate_size: int = 4096,
16
+ num_layers: int = 24,
17
+ num_query_heads: int = 24,
18
+ num_kv_heads: int = 6,
19
+ head_dim: int = 64,
20
+ sequence_length: int = 32768,
21
+ local_attention_window: int = 2048,
22
+ memory_chunk_size: int = 512,
23
+ summaries_per_chunk: int = 4,
24
+ rope_theta: float = 1000000.0,
25
+ rms_norm_eps: float = 1e-6,
26
+ tie_word_embeddings: bool = True,
27
+ attention_backend: str = "auto",
28
+ attention_chunk_size: int = 1024,
29
+ activation_checkpointing: bool = False,
30
+ chunked_cross_entropy: bool = True,
31
+ loss_chunk_size: int = 1024,
32
+ **kwargs,
33
+ ) -> None:
34
+ kwargs.setdefault("bos_token_id", 2)
35
+ kwargs.setdefault("eos_token_id", 3)
36
+ kwargs.setdefault("pad_token_id", 0)
37
+ kwargs.setdefault("use_cache", False)
38
+ kwargs.setdefault("tie_word_embeddings", tie_word_embeddings)
39
+ super().__init__(**kwargs)
40
+ self.model_name = model_name
41
+ self.architecture = architecture
42
+ self.vocab_size = vocab_size
43
+ self.hidden_size = hidden_size
44
+ self.intermediate_size = intermediate_size
45
+ self.num_layers = num_layers
46
+ self.num_hidden_layers = num_layers
47
+ self.num_query_heads = num_query_heads
48
+ self.num_attention_heads = num_query_heads
49
+ self.num_kv_heads = num_kv_heads
50
+ self.num_key_value_heads = num_kv_heads
51
+ self.head_dim = head_dim
52
+ self.sequence_length = sequence_length
53
+ self.max_position_embeddings = sequence_length
54
+ self.local_attention_window = local_attention_window
55
+ self.memory_chunk_size = memory_chunk_size
56
+ self.summaries_per_chunk = summaries_per_chunk
57
+ self.rope_theta = rope_theta
58
+ self.rms_norm_eps = rms_norm_eps
59
+ self.tie_word_embeddings = tie_word_embeddings
60
+ self.attention_backend = attention_backend
61
+ self.attention_chunk_size = attention_chunk_size
62
+ self.activation_checkpointing = activation_checkpointing
63
+ self.chunked_cross_entropy = chunked_cross_entropy
64
+ self.loss_chunk_size = loss_chunk_size
65
+
66
+ def to_fabric_model_config_dict(self) -> dict:
67
+ return {
68
+ "model_name": self.model_name,
69
+ "architecture": self.architecture,
70
+ "vocab_size": self.vocab_size,
71
+ "hidden_size": self.hidden_size,
72
+ "intermediate_size": self.intermediate_size,
73
+ "num_layers": self.num_layers,
74
+ "num_query_heads": self.num_query_heads,
75
+ "num_kv_heads": self.num_kv_heads,
76
+ "head_dim": self.head_dim,
77
+ "sequence_length": self.sequence_length,
78
+ "local_attention_window": self.local_attention_window,
79
+ "memory_chunk_size": self.memory_chunk_size,
80
+ "summaries_per_chunk": self.summaries_per_chunk,
81
+ "rope_theta": self.rope_theta,
82
+ "rms_norm_eps": self.rms_norm_eps,
83
+ "tie_word_embeddings": self.tie_word_embeddings,
84
+ "attention_backend": self.attention_backend,
85
+ "attention_chunk_size": self.attention_chunk_size,
86
+ "activation_checkpointing": self.activation_checkpointing,
87
+ "chunked_cross_entropy": self.chunked_cross_entropy,
88
+ "loss_chunk_size": self.loss_chunk_size,
89
+ }
fabric_config.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "activation_checkpointing": true,
3
+ "architecture": "fabric",
4
+ "attention_backend": "auto",
5
+ "attention_chunk_size": 1024,
6
+ "checkpoint_dtype": "float16",
7
+ "checkpoint_note": "Model-only Fabric complete checkpoint; optimizer state is excluded.",
8
+ "checkpoint_sha256": "a8d12a687fe5eaa05b601ab2803ca2c14b9cc2c14d754110ca4569b061af2bf1",
9
+ "checkpoint_size_gib": 1.383114,
10
+ "chunked_cross_entropy": true,
11
+ "continued_pretraining_tokens": 5000134656,
12
+ "cumulative_pretraining_tokens": 23000514560,
13
+ "export_kind": "model_only_inference_fp16",
14
+ "head_dim": 64,
15
+ "hidden_size": 1536,
16
+ "intermediate_size": 4096,
17
+ "license": "fabric-ai-open-1.0",
18
+ "local_attention_window": 2048,
19
+ "loss_chunk_size": 1024,
20
+ "memory_chunk_size": 512,
21
+ "model_name": "Fabric1.5-0.7B-Instruct",
22
+ "num_kv_heads": 6,
23
+ "num_layers": 24,
24
+ "num_parameters": 742528520,
25
+ "num_query_heads": 24,
26
+ "original_pretraining_tokens": 18000379904,
27
+ "posttraining_supervised_tokens": 318879711,
28
+ "rms_norm_eps": 1e-06,
29
+ "rope_theta": 1000000.0,
30
+ "sequence_length": 32768,
31
+ "summaries_per_chunk": 4,
32
+ "tie_word_embeddings": true,
33
+ "torch_dtype": "float16",
34
+ "vocab_size": 65536
35
+ }
fabric_runtime.py ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import base64
4
+ import json
5
+ import math
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ import numpy as np
11
+ import torch
12
+ from safetensors import safe_open
13
+ from torch import nn
14
+ from torch.nn import functional as F
15
+
16
+
17
+ @dataclass
18
+ class ModelConfig:
19
+ model_name: str = "Fabric 1.5"
20
+ architecture: str = "fabric"
21
+ vocab_size: int = 65536
22
+ hidden_size: int = 1536
23
+ intermediate_size: int = 4096
24
+ num_layers: int = 24
25
+ num_query_heads: int = 24
26
+ num_kv_heads: int = 6
27
+ head_dim: int = 64
28
+ sequence_length: int = 32768
29
+ local_attention_window: int = 2048
30
+ memory_chunk_size: int = 512
31
+ summaries_per_chunk: int = 4
32
+ rope_theta: float = 1000000.0
33
+ rms_norm_eps: float = 1e-6
34
+ tie_word_embeddings: bool = True
35
+ attention_backend: str = "auto"
36
+ attention_chunk_size: int = 1024
37
+ activation_checkpointing: bool = False
38
+ chunked_cross_entropy: bool = True
39
+ loss_chunk_size: int = 1024
40
+
41
+
42
+ def _decode_structure(value: Any, tensors: dict[str, torch.Tensor]) -> Any:
43
+ if not isinstance(value, dict) or "__kind__" not in value:
44
+ return value
45
+ kind = value["__kind__"]
46
+ if kind == "tensor":
47
+ return tensors[value["key"]]
48
+ if kind == "dict":
49
+ return {
50
+ _decode_structure(key, tensors): _decode_structure(item, tensors)
51
+ for key, item in value["items"]
52
+ }
53
+ if kind == "tuple":
54
+ return tuple(_decode_structure(item, tensors) for item in value["items"])
55
+ if kind == "list":
56
+ return [_decode_structure(item, tensors) for item in value["items"]]
57
+ if kind == "ndarray":
58
+ return np.asarray(value["items"], dtype=np.dtype(value["dtype"])).reshape(value["shape"])
59
+ if kind == "path":
60
+ return Path(value["value"])
61
+ if kind == "bytes":
62
+ return base64.b64decode(value["value"])
63
+ raise ValueError(f"unknown checkpoint structure kind: {kind}")
64
+
65
+
66
+ def load_checkpoint(path: str | Path, map_location: str | torch.device = "cpu") -> dict[str, Any]:
67
+ with safe_open(path, framework="pt", device=str(map_location)) as handle:
68
+ metadata = handle.metadata()
69
+ if metadata.get("format") != "fabric_complete_checkpoint":
70
+ raise ValueError("file is not a Fabric complete checkpoint")
71
+ tensors = {key: handle.get_tensor(key) for key in handle.keys()}
72
+ structure = json.loads(metadata["structure"])
73
+ state = _decode_structure(structure, tensors)
74
+ if not isinstance(state, dict):
75
+ raise ValueError("checkpoint root must be a dictionary")
76
+ return state
77
+
78
+
79
+ class RMSNorm(nn.Module):
80
+ def __init__(self, hidden_size: int, eps: float = 1e-6) -> None:
81
+ super().__init__()
82
+ self.weight = nn.Parameter(torch.ones(hidden_size))
83
+ self.eps = eps
84
+
85
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
86
+ dtype = x.dtype
87
+ variance = x.float().pow(2).mean(dim=-1, keepdim=True)
88
+ return (x.float() * torch.rsqrt(variance + self.eps)).to(dtype) * self.weight
89
+
90
+
91
+ class SwiGLU(nn.Module):
92
+ def __init__(self, hidden_size: int, intermediate_size: int) -> None:
93
+ super().__init__()
94
+ self.gate_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
95
+ self.up_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
96
+ self.down_proj = nn.Linear(intermediate_size, hidden_size, bias=False)
97
+
98
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
99
+ return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
100
+
101
+
102
+ def rotate_half(x: torch.Tensor) -> torch.Tensor:
103
+ x1, x2 = x.chunk(2, dim=-1)
104
+ return torch.cat((-x2, x1), dim=-1)
105
+
106
+
107
+ class RotaryEmbedding(nn.Module):
108
+ def __init__(self, head_dim: int, theta: float = 10000.0) -> None:
109
+ super().__init__()
110
+ inv_freq = 1.0 / (theta ** (torch.arange(0, head_dim, 2).float() / head_dim))
111
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
112
+
113
+ def forward(self, q: torch.Tensor, k: torch.Tensor, position_ids: torch.Tensor):
114
+ angles = position_ids.float().unsqueeze(-1) * self.inv_freq.float()
115
+ emb = torch.cat((angles, angles), dim=-1)
116
+ cos = emb.cos().to(q.dtype).unsqueeze(1)
117
+ sin = emb.sin().to(q.dtype).unsqueeze(1)
118
+ return q * cos + rotate_half(q) * sin, k * cos + rotate_half(k) * sin
119
+
120
+
121
+ def build_local_causal_mask(query_length: int, key_length: int, window: int, device, query_offset: int = 0):
122
+ query_positions = torch.arange(query_offset, query_offset + query_length, device=device)
123
+ key_positions = torch.arange(key_length, device=device)
124
+ return (key_positions[None, :] <= query_positions[:, None]) & (
125
+ key_positions[None, :] > query_positions[:, None] - window
126
+ )
127
+
128
+
129
+ def repeat_kv(x: torch.Tensor, groups: int) -> torch.Tensor:
130
+ if groups == 1:
131
+ return x
132
+ batch, kv_heads, length, dim = x.shape
133
+ return x[:, :, None, :, :].expand(batch, kv_heads, groups, length, dim).reshape(
134
+ batch, kv_heads * groups, length, dim
135
+ )
136
+
137
+
138
+ def reference_attention(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, allowed_mask: torch.Tensor):
139
+ scores = torch.matmul(q.float(), k.float().transpose(-1, -2)) / math.sqrt(q.shape[-1])
140
+ scores = scores.masked_fill(~allowed_mask, torch.finfo(scores.dtype).min)
141
+ probabilities = torch.softmax(scores, dim=-1)
142
+ probabilities = torch.where(allowed_mask.any(dim=-1, keepdim=True), probabilities, 0.0)
143
+ return torch.matmul(probabilities.to(v.dtype), v)
144
+
145
+
146
+ class GQAAttention(nn.Module):
147
+ def __init__(self, config: ModelConfig, window: int | None = None) -> None:
148
+ super().__init__()
149
+ self.num_query_heads = config.num_query_heads
150
+ self.num_kv_heads = config.num_kv_heads
151
+ self.head_dim = config.head_dim
152
+ self.groups = config.num_query_heads // config.num_kv_heads
153
+ self.window = window or config.sequence_length
154
+ self.backend = "sdpa" if config.attention_backend == "flash_attn" else config.attention_backend
155
+ self.attention_chunk_size = config.attention_chunk_size
156
+ self.q_proj = nn.Linear(config.hidden_size, config.num_query_heads * config.head_dim, bias=False)
157
+ self.k_proj = nn.Linear(config.hidden_size, config.num_kv_heads * config.head_dim, bias=False)
158
+ self.v_proj = nn.Linear(config.hidden_size, config.num_kv_heads * config.head_dim, bias=False)
159
+ self.o_proj = nn.Linear(config.num_query_heads * config.head_dim, config.hidden_size, bias=False)
160
+ self.rope = RotaryEmbedding(config.head_dim, config.rope_theta)
161
+
162
+ def forward(self, x: torch.Tensor, position_ids: torch.Tensor | None = None) -> torch.Tensor:
163
+ batch, length, _ = x.shape
164
+ if position_ids is None:
165
+ position_ids = torch.arange(length, device=x.device).expand(batch, -1)
166
+ q = self.q_proj(x).view(batch, length, self.num_query_heads, self.head_dim).transpose(1, 2)
167
+ k = self.k_proj(x).view(batch, length, self.num_kv_heads, self.head_dim).transpose(1, 2)
168
+ v = self.v_proj(x).view(batch, length, self.num_kv_heads, self.head_dim).transpose(1, 2)
169
+ q, k = self.rope(q, k, position_ids)
170
+ k = repeat_kv(k, self.groups)
171
+ v = repeat_kv(v, self.groups)
172
+ use_sdpa = self.backend in {"auto", "sdpa"} and hasattr(F, "scaled_dot_product_attention")
173
+ if use_sdpa:
174
+ outputs = []
175
+ for start in range(0, length, self.attention_chunk_size):
176
+ end = min(start + self.attention_chunk_size, length)
177
+ key_start = max(0, start - self.window + 1)
178
+ key_end = end
179
+ allowed = build_local_causal_mask(
180
+ end - start,
181
+ key_end - key_start,
182
+ self.window,
183
+ x.device,
184
+ query_offset=start - key_start,
185
+ )[None, None]
186
+ outputs.append(
187
+ F.scaled_dot_product_attention(
188
+ q[:, :, start:end],
189
+ k[:, :, key_start:key_end],
190
+ v[:, :, key_start:key_end],
191
+ attn_mask=allowed,
192
+ dropout_p=0.0,
193
+ )
194
+ )
195
+ output = torch.cat(outputs, dim=2)
196
+ else:
197
+ allowed = build_local_causal_mask(length, length, self.window, x.device)[None, None]
198
+ output = reference_attention(q, k, v, allowed)
199
+ output = output.transpose(1, 2).contiguous().view(batch, length, -1)
200
+ return self.o_proj(output)
201
+
202
+
203
+ def build_completed_chunk_mask(sequence_length: int, num_chunks: int, summaries_per_chunk: int, chunk_size: int, device):
204
+ query_chunk = torch.arange(sequence_length, device=device) // chunk_size
205
+ summary_chunk = torch.arange(num_chunks, device=device).repeat_interleave(summaries_per_chunk)
206
+ return summary_chunk[None, :] < query_chunk[:, None]
207
+
208
+
209
+ class ChunkSummarizer(nn.Module):
210
+ def __init__(self, config: ModelConfig) -> None:
211
+ super().__init__()
212
+ self.chunk_size = config.memory_chunk_size
213
+ self.num_summaries = config.summaries_per_chunk
214
+ self.hidden_size = config.hidden_size
215
+ self.queries = nn.Parameter(torch.empty(self.num_summaries, self.hidden_size))
216
+ nn.init.normal_(self.queries, std=0.02)
217
+
218
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
219
+ batch, length, hidden = x.shape
220
+ num_chunks = (length + self.chunk_size - 1) // self.chunk_size
221
+ padded_length = num_chunks * self.chunk_size
222
+ if padded_length != length:
223
+ x = torch.cat((x, x.new_zeros(batch, padded_length - length, hidden)), dim=1)
224
+ chunks = x.view(batch, num_chunks, self.chunk_size, hidden)
225
+ scores = torch.einsum("mh,bnch->bnmc", self.queries.float(), chunks.float()) / math.sqrt(hidden)
226
+ if padded_length != length:
227
+ valid = torch.arange(padded_length, device=x.device).view(num_chunks, self.chunk_size) < length
228
+ scores = scores.masked_fill(~valid[None, :, None, :], torch.finfo(scores.dtype).min)
229
+ weights = torch.softmax(scores, dim=-1).to(chunks.dtype)
230
+ return torch.einsum("bnmc,bnch->bnmh", weights, chunks)
231
+
232
+
233
+ class MemoryAttention(nn.Module):
234
+ def __init__(self, config: ModelConfig) -> None:
235
+ super().__init__()
236
+ self.num_query_heads = config.num_query_heads
237
+ self.num_kv_heads = config.num_kv_heads
238
+ self.head_dim = config.head_dim
239
+ self.groups = config.num_query_heads // config.num_kv_heads
240
+ self.chunk_size = config.memory_chunk_size
241
+ self.num_summaries = config.summaries_per_chunk
242
+ self.q_proj = nn.Linear(config.hidden_size, config.num_query_heads * config.head_dim, bias=False)
243
+ self.k_proj = nn.Linear(config.hidden_size, config.num_kv_heads * config.head_dim, bias=False)
244
+ self.v_proj = nn.Linear(config.hidden_size, config.num_kv_heads * config.head_dim, bias=False)
245
+ self.o_proj = nn.Linear(config.num_query_heads * config.head_dim, config.hidden_size, bias=False)
246
+
247
+ def forward(self, x: torch.Tensor, summaries: torch.Tensor) -> torch.Tensor:
248
+ batch, length, _ = x.shape
249
+ num_chunks = summaries.shape[1]
250
+ flat = summaries.reshape(batch, num_chunks * self.num_summaries, -1)
251
+ q = self.q_proj(x).view(batch, length, self.num_query_heads, self.head_dim).transpose(1, 2)
252
+ k = self.k_proj(flat).view(batch, -1, self.num_kv_heads, self.head_dim).transpose(1, 2)
253
+ v = self.v_proj(flat).view(batch, -1, self.num_kv_heads, self.head_dim).transpose(1, 2)
254
+ k, v = repeat_kv(k, self.groups), repeat_kv(v, self.groups)
255
+ scores = torch.matmul(q.float(), k.float().transpose(-1, -2)) / math.sqrt(self.head_dim)
256
+ allowed = build_completed_chunk_mask(length, num_chunks, self.num_summaries, self.chunk_size, x.device)[None, None]
257
+ scores = scores.masked_fill(~allowed, torch.finfo(scores.dtype).min)
258
+ probabilities = torch.softmax(scores, dim=-1)
259
+ probabilities = torch.where(allowed.any(dim=-1, keepdim=True), probabilities, 0.0)
260
+ output = torch.matmul(probabilities.to(v.dtype), v)
261
+ output = output.transpose(1, 2).contiguous().view(batch, length, -1)
262
+ return self.o_proj(output)
263
+
264
+
265
+ class LocalBlock(nn.Module):
266
+ def __init__(self, config: ModelConfig, window: int | None = None) -> None:
267
+ super().__init__()
268
+ self.attention_norm = RMSNorm(config.hidden_size, config.rms_norm_eps)
269
+ self.attention = GQAAttention(config, window or config.local_attention_window)
270
+ self.mlp_norm = RMSNorm(config.hidden_size, config.rms_norm_eps)
271
+ self.mlp = SwiGLU(config.hidden_size, config.intermediate_size)
272
+
273
+ def forward(self, x: torch.Tensor, position_ids: torch.Tensor | None = None) -> torch.Tensor:
274
+ x = x + self.attention(self.attention_norm(x), position_ids)
275
+ return x + self.mlp(self.mlp_norm(x))
276
+
277
+
278
+ class FabricMemoryBlock(nn.Module):
279
+ def __init__(self, config: ModelConfig) -> None:
280
+ super().__init__()
281
+ self.attention_norm = RMSNorm(config.hidden_size, config.rms_norm_eps)
282
+ self.local_attention = GQAAttention(config, config.local_attention_window)
283
+ self.summarizer = ChunkSummarizer(config)
284
+ self.memory_attention = MemoryAttention(config)
285
+ self.gate = nn.Linear(config.hidden_size, 1, bias=True)
286
+ self.mlp_norm = RMSNorm(config.hidden_size, config.rms_norm_eps)
287
+ self.mlp = SwiGLU(config.hidden_size, config.intermediate_size)
288
+
289
+ def forward(self, x: torch.Tensor, position_ids: torch.Tensor | None = None) -> torch.Tensor:
290
+ normalized = self.attention_norm(x)
291
+ local = self.local_attention(normalized, position_ids)
292
+ summaries = self.summarizer(normalized)
293
+ memory = self.memory_attention(normalized, summaries)
294
+ gate = torch.sigmoid(self.gate(normalized))
295
+ x = x + gate * local + (1.0 - gate) * memory
296
+ return x + self.mlp(self.mlp_norm(x))
297
+
298
+
299
+ @dataclass
300
+ class CausalLMOutput:
301
+ logits: torch.Tensor | None
302
+ loss: torch.Tensor | None = None
303
+
304
+
305
+ class FabricCoreForCausalLM(nn.Module):
306
+ def __init__(self, config: ModelConfig) -> None:
307
+ super().__init__()
308
+ self.config = config
309
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size)
310
+ if config.architecture == "fabric":
311
+ layers = [FabricMemoryBlock(config) if i % 3 == 2 else LocalBlock(config) for i in range(config.num_layers)]
312
+ else:
313
+ window = config.sequence_length if config.architecture == "full" else config.local_attention_window
314
+ layers = [LocalBlock(config, window) for _ in range(config.num_layers)]
315
+ self.layers = nn.ModuleList(layers)
316
+ self.norm = RMSNorm(config.hidden_size, config.rms_norm_eps)
317
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
318
+ if config.tie_word_embeddings:
319
+ self.lm_head.weight = self.embed_tokens.weight
320
+
321
+ def forward(self, input_ids: torch.Tensor, labels: torch.Tensor | None = None) -> CausalLMOutput:
322
+ if input_ids.ndim != 2:
323
+ raise ValueError("input_ids must have shape [batch, sequence]")
324
+ if input_ids.shape[1] > self.config.sequence_length:
325
+ raise ValueError("input sequence exceeds configured sequence_length")
326
+ position_ids = torch.arange(input_ids.shape[1], device=input_ids.device).expand(input_ids.shape[0], -1)
327
+ hidden = self.embed_tokens(input_ids)
328
+ for layer in self.layers:
329
+ hidden = layer(hidden, position_ids)
330
+ normalized = self.norm(hidden)
331
+ logits = self.lm_head(normalized).float()
332
+ loss = None
333
+ if labels is not None:
334
+ loss = F.cross_entropy(
335
+ logits[:, :-1].reshape(-1, logits.shape[-1]),
336
+ labels[:, 1:].reshape(-1),
337
+ ignore_index=-100,
338
+ )
339
+ return CausalLMOutput(logits=logits, loss=loss)
generation_config.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token_id": 2,
3
+ "do_sample": false,
4
+ "eos_token_id": 7,
5
+ "max_new_tokens": 128,
6
+ "pad_token_id": 0,
7
+ "temperature": 1.0,
8
+ "top_p": 1.0,
9
+ "use_cache": false
10
+ }
inference.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import sys, time, torch
3
+ from transformers import AutoModelForCausalLM, AutoTokenizer
4
+ P = "/Users/tudor/Documents/Fabric AI/Fabric_1.5_NVDA/HF_Final"
5
+ def get_device():
6
+ if torch.backends.mps.is_available(): return "mps"
7
+ if torch.cuda.is_available(): return "cuda"
8
+ return "cpu"
9
+ def load_model():
10
+ dev = get_device(); dt = torch.float16 if dev != "cpu" else torch.float32
11
+ print(f"Loading Fabric 1.5 on {dev}...")
12
+ m = AutoModelForCausalLM.from_pretrained(P, trust_remote_code=True, torch_dtype=dt)
13
+ m.to(dev); m.eval()
14
+ tok = AutoTokenizer.from_pretrained(P, trust_remote_code=True)
15
+ print(f"Loaded! {sum(p.numel() for p in m.parameters()):,} params")
16
+ return m, tok, dev
17
+ def generate(m, tok, prompt, dev, max_new=512):
18
+ text = tok.apply_chat_template([{"role":"user","content":prompt}], tokenize=False, add_generation_prompt=True)
19
+ inp = tok(text, return_tensors="pt").to(dev)
20
+ with torch.no_grad():
21
+ out = m.generate(**inp, max_new_tokens=max_new, do_sample=True, temperature=0.65, top_p=0.9, top_k=50, repetition_penalty=1.05, use_cache=True)
22
+ return tok.decode(out[0,inp["input_ids"].shape[1]:], skip_special_tokens=True).strip()
23
+ m, tok, dev = load_model()
24
+ if len(sys.argv) > 1:
25
+ q = " ".join(sys.argv[1:]); t0 = time.time(); r = generate(m, tok, q, dev)
26
+ print(f"\nYou: {q}\nFabric: {r}\n[{time.time()-t0:.1f}s]")
27
+ else:
28
+ print("\nInteractive. Type 'quit' to exit.\n")
29
+ while True:
30
+ try: q = input("You: ").strip()
31
+ except: print(); break
32
+ if not q: continue
33
+ if q.lower() in ("quit","exit","/bye"): break
34
+ t0 = time.time(); r = generate(m, tok, q, dev)
35
+ print(f"Fabric: {r}\n[{time.time()-t0:.1f}s]\n")
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a8d12a687fe5eaa05b601ab2803ca2c14b9cc2c14d754110ca4569b061af2bf1
3
+ size 1485107392
modeling_fabric.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ import torch
8
+ from torch import nn
9
+ from transformers.generation import GenerationMixin
10
+ from transformers.modeling_outputs import CausalLMOutputWithPast
11
+ from transformers.modeling_utils import PreTrainedModel
12
+
13
+ from .configuration_fabric import FabricConfig
14
+ from .fabric_runtime import FabricCoreForCausalLM, ModelConfig, load_checkpoint
15
+
16
+
17
+ def _resolve_repo_dir(pretrained_model_name_or_path: str | os.PathLike[str], **download_kwargs: Any) -> Path:
18
+ path = Path(str(pretrained_model_name_or_path))
19
+ if path.exists():
20
+ return path
21
+ from huggingface_hub import snapshot_download
22
+
23
+ allowed = [
24
+ "model.safetensors",
25
+ "fabric_config.json",
26
+ "config.json",
27
+ "tokenizer.json",
28
+ "tokenizer_config.json",
29
+ "special_tokens_map.json",
30
+ "generation_config.json",
31
+ "configuration_fabric.py",
32
+ "modeling_fabric.py",
33
+ "fabric_runtime.py",
34
+ "system_prompt.txt",
35
+ "chat_template.md",
36
+ ]
37
+ return Path(snapshot_download(str(pretrained_model_name_or_path), allow_patterns=allowed, **download_kwargs))
38
+
39
+
40
+ def _select_device(device_map: Any = None) -> torch.device:
41
+ if isinstance(device_map, str) and device_map not in {"auto", "sequential"}:
42
+ return torch.device(device_map)
43
+ if torch.cuda.is_available():
44
+ return torch.device("cuda")
45
+ if getattr(torch.backends, "mps", None) and torch.backends.mps.is_available():
46
+ return torch.device("mps")
47
+ return torch.device("cpu")
48
+
49
+
50
+ def _normalize_dtype(torch_dtype: Any) -> torch.dtype | None:
51
+ if torch_dtype in {None, "auto"}:
52
+ return None
53
+ if isinstance(torch_dtype, torch.dtype):
54
+ return torch_dtype
55
+ if isinstance(torch_dtype, str):
56
+ return getattr(torch, torch_dtype.replace("torch.", ""))
57
+ return None
58
+
59
+
60
+ class FabricForCausalLM(PreTrainedModel, GenerationMixin):
61
+ config_class = FabricConfig
62
+ base_model_prefix = "fabric"
63
+ main_input_name = "input_ids"
64
+ supports_gradient_checkpointing = False
65
+
66
+ def __init__(self, config: FabricConfig) -> None:
67
+ super().__init__(config)
68
+ values = config.to_fabric_model_config_dict()
69
+ values["activation_checkpointing"] = False
70
+ self.fabric = FabricCoreForCausalLM(ModelConfig(**values))
71
+
72
+ @classmethod
73
+ def from_pretrained(cls, pretrained_model_name_or_path, *model_args, **kwargs):
74
+ token = kwargs.pop("token", None)
75
+ use_auth_token = kwargs.pop("use_auth_token", None)
76
+ if token is None:
77
+ token = use_auth_token
78
+ revision = kwargs.pop("revision", None)
79
+ cache_dir = kwargs.pop("cache_dir", None)
80
+ local_files_only = kwargs.pop("local_files_only", False)
81
+ torch_dtype = _normalize_dtype(kwargs.pop("torch_dtype", kwargs.pop("dtype", None)))
82
+ device_map = kwargs.pop("device_map", None)
83
+ attention_backend = kwargs.pop("attention_backend", None)
84
+ config = kwargs.pop("config", None)
85
+
86
+ repo_dir = _resolve_repo_dir(
87
+ pretrained_model_name_or_path,
88
+ token=token,
89
+ revision=revision,
90
+ cache_dir=cache_dir,
91
+ local_files_only=local_files_only,
92
+ )
93
+ if config is None:
94
+ config = FabricConfig.from_pretrained(repo_dir, local_files_only=True)
95
+ backend = attention_backend if attention_backend is not None else getattr(config, "attention_backend", "auto")
96
+ config.attention_backend = backend
97
+
98
+ model = cls(config)
99
+ state = load_checkpoint(repo_dir / "model.safetensors", "cpu")
100
+ values = state.get("model_config") or state.get("config", {}).get("model")
101
+ if values:
102
+ values = dict(values)
103
+ values["attention_backend"] = backend
104
+ values["activation_checkpointing"] = False
105
+ model.fabric = FabricCoreForCausalLM(ModelConfig(**values))
106
+
107
+ missing, _unexpected = model.fabric.load_state_dict(state["model"], strict=False)
108
+ if missing:
109
+ raise RuntimeError(f"Missing Fabric checkpoint tensors: {missing}")
110
+ if torch_dtype is not None:
111
+ model.fabric.to(dtype=torch_dtype)
112
+ model.to(_select_device(device_map))
113
+ model.eval()
114
+ return model
115
+
116
+ def forward(
117
+ self,
118
+ input_ids: torch.LongTensor,
119
+ attention_mask: torch.Tensor | None = None,
120
+ labels: torch.LongTensor | None = None,
121
+ past_key_values: Any | None = None,
122
+ use_cache: bool | None = None,
123
+ **kwargs,
124
+ ) -> CausalLMOutputWithPast:
125
+ output = self.fabric(input_ids=input_ids, labels=labels)
126
+ return CausalLMOutputWithPast(loss=output.loss, logits=output.logits, past_key_values=None)
127
+
128
+ def prepare_inputs_for_generation(self, input_ids, past_key_values=None, attention_mask=None, **kwargs):
129
+ return {"input_ids": input_ids, "attention_mask": attention_mask}
130
+
131
+ def get_input_embeddings(self) -> nn.Module:
132
+ return self.fabric.embed_tokens
133
+
134
+ def set_input_embeddings(self, value: nn.Module) -> None:
135
+ self.fabric.embed_tokens = value
136
+
137
+ def get_output_embeddings(self) -> nn.Module:
138
+ return self.fabric.lm_head
139
+
140
+ def set_output_embeddings(self, new_embeddings: nn.Module) -> None:
141
+ self.fabric.lm_head = new_embeddings
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ torch
2
+ transformers>=4.50
3
+ safetensors
4
+ tokenizers
5
+ huggingface_hub
6
+ numpy
special_tokens_map.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<|system|>",
4
+ "<|user|>",
5
+ "<|assistant|>"
6
+ ],
7
+ "bos_token": "<bos>",
8
+ "eos_token": "<|end|>",
9
+ "pad_token": "<pad>",
10
+ "unk_token": "<unk>"
11
+ }
system_prompt.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ You are Fabric, a large language model developed by Fabric AI.
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<|system|>",
4
+ "<|user|>",
5
+ "<|assistant|>"
6
+ ],
7
+ "bos_token": "<bos>",
8
+ "chat_template": "{% set default_system_prompt = \"You are Fabric, a large language model developed by Fabric AI.\" %}{% set ns = namespace(has_system=false) %}{% for message in messages %}{% if message['role'] == 'system' %}{% set ns.has_system = true %}{% endif %}{% endfor %}{% if not ns.has_system %}<|system|>\n{{ default_system_prompt }}<|end|>\n{% endif %}{% for message in messages %}{% if message['role'] == 'system' %}<|system|>\n{{ message['content'] }}<|end|>\n{% elif message['role'] == 'user' %}<|user|>\n{{ message['content'] }}<|end|>\n{% elif message['role'] == 'assistant' %}<|assistant|>\n{{ message['content'] }}<|end|>\n{% endif %}{% endfor %}{% if add_generation_prompt %}<|assistant|>\n{% endif %}",
9
+ "chat_template_file": "chat_template.jinja",
10
+ "default_system_prompt": "You are Fabric, a large language model developed by Fabric AI.",
11
+ "eos_token": "<|end|>",
12
+ "model_max_length": 32768,
13
+ "pad_token": "<pad>",
14
+ "tokenizer_class": "PreTrainedTokenizerFast",
15
+ "unk_token": "<unk>"
16
+ }