Text Generation
Transformers
Safetensors
English
fabric
efficient
0.7b
causal-lm
chunked-memory
conversational
custom_code
Instructions to use FabricAI/Fabric1.5-0.7B-Instruct with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use FabricAI/Fabric1.5-0.7B-Instruct with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="FabricAI/Fabric1.5-0.7B-Instruct", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("FabricAI/Fabric1.5-0.7B-Instruct", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use FabricAI/Fabric1.5-0.7B-Instruct with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "FabricAI/Fabric1.5-0.7B-Instruct" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FabricAI/Fabric1.5-0.7B-Instruct", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/FabricAI/Fabric1.5-0.7B-Instruct
- SGLang
How to use FabricAI/Fabric1.5-0.7B-Instruct with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "FabricAI/Fabric1.5-0.7B-Instruct" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FabricAI/Fabric1.5-0.7B-Instruct", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "FabricAI/Fabric1.5-0.7B-Instruct" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "FabricAI/Fabric1.5-0.7B-Instruct", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use FabricAI/Fabric1.5-0.7B-Instruct with Docker Model Runner:
docker model run hf.co/FabricAI/Fabric1.5-0.7B-Instruct
Upload 17 files
Browse files- .gitattributes +1 -0
- LICENSE +43 -0
- README.md +183 -0
- banner_fabric.png +3 -0
- chat_template.jinja +10 -0
- config.json +52 -0
- configuration_fabric.py +89 -0
- fabric_config.json +35 -0
- fabric_runtime.py +339 -0
- generation_config.json +10 -0
- inference.py +35 -0
- model.safetensors +3 -0
- modeling_fabric.py +141 -0
- requirements.txt +6 -0
- special_tokens_map.json +11 -0
- system_prompt.txt +1 -0
- tokenizer.json +0 -0
- tokenizer_config.json +16 -0
.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 |
+

|
| 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
|
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 |
+
}
|