Text Generation
Transformers
Safetensors
English
cagliostro
causal-lm
language-model
base-model
pretrained-from-scratch
small-language-model
custom_code
Instructions to use bench-labs/tinctura-v1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use bench-labs/tinctura-v1 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="bench-labs/tinctura-v1", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("bench-labs/tinctura-v1", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use bench-labs/tinctura-v1 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "bench-labs/tinctura-v1" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "bench-labs/tinctura-v1", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/bench-labs/tinctura-v1
- SGLang
How to use bench-labs/tinctura-v1 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 "bench-labs/tinctura-v1" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "bench-labs/tinctura-v1", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'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 "bench-labs/tinctura-v1" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "bench-labs/tinctura-v1", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use bench-labs/tinctura-v1 with Docker Model Runner:
docker model run hf.co/bench-labs/tinctura-v1
Commit ·
f1df53d
1
Parent(s): 787d9e6
Release: HF export, model card, charts and film
Browse files- .gitattributes +4 -0
- README.md +282 -0
- comparison_index.png +3 -0
- comparison_tasks.png +0 -0
- config.json +30 -0
- configuration_cagliostro.py +43 -0
- cooldown_gain.png +0 -0
- generation_config.json +8 -0
- index_curve.png +3 -0
- loss_curve.png +3 -0
- model.safetensors +3 -0
- modeling_cagliostro.py +270 -0
- tinctura-v1.mp4 +3 -0
- tokenizer.json +0 -0
- tokenizer_config.json +7 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,7 @@ 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 |
+
comparison_index.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
index_curve.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
loss_curve.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
tinctura-v1.mp4 filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
pipeline_tag: text-generation
|
| 6 |
+
library_name: transformers
|
| 7 |
+
tags:
|
| 8 |
+
- causal-lm
|
| 9 |
+
- language-model
|
| 10 |
+
- base-model
|
| 11 |
+
- pretrained-from-scratch
|
| 12 |
+
- small-language-model
|
| 13 |
+
datasets:
|
| 14 |
+
- HuggingFaceTB/smollm-corpus
|
| 15 |
+
- mlfoundations/dclm-baseline-1.0
|
| 16 |
+
- HuggingFaceTB/finemath
|
| 17 |
+
- nvidia/OpenMathInstruct-2
|
| 18 |
+
- HuggingFaceTB/smoltalk
|
| 19 |
+
---
|
| 20 |
+
|
| 21 |
+
# tinctura-v1
|
| 22 |
+
|
| 23 |
+
A 96.2M parameter decoder-only language model pretrained from scratch on 75B tokens. It is the [cagliostro-v3](https://huggingface.co/bench-labs/cagliostro-v3) recipe at two thirds of the size: the same architecture, data, schedule and token count, with 18 layers instead of 30.
|
| 24 |
+
|
| 25 |
+
On the [Open SLM Leaderboard](https://huggingface.co/spaces/AxiomicLabs/Open_SLM_Leaderboard) Index it scores **20.77**. Among models under 100M parameters that places it second, 0.30 behind Rose-1.5-Medium at 21.07.
|
| 26 |
+
|
| 27 |
+
The training run is **complete**. 75.00B tokens, 762,939 steps, learning rate decayed to zero.
|
| 28 |
+
|
| 29 |
+
<video controls src="https://huggingface.co/bench-labs/tinctura-v1/resolve/main/tinctura-v1.mp4" width="100%"></video>
|
| 30 |
+
|
| 31 |
+
## Results
|
| 32 |
+
|
| 33 |
+
Zero-shot, measured with lm-evaluation-harness and the leaderboard's own ArithMark-3 script, on the exported float32 weights in this repository.
|
| 34 |
+
|
| 35 |
+
| Benchmark | Metric | Score |
|
| 36 |
+
|---|---|---:|
|
| 37 |
+
| HellaSwag | acc_norm | 38.01 |
|
| 38 |
+
| ARC-Easy | acc_norm | 48.15 |
|
| 39 |
+
| ARC-Challenge | acc_norm | 26.02 |
|
| 40 |
+
| PIQA | acc_norm | 65.67 |
|
| 41 |
+
| ArithMark-3 | acc_norm | 37.70 |
|
| 42 |
+
| **Open SLM Index** | | **20.77** |
|
| 43 |
+
|
| 44 |
+
The Index is the leaderboard's own formula, `(N(HellaSwag,25) + N(CombinedARC,25) + N(PIQA,50) + 0.65*N(ArithMark,25)) / 3.65` where `N(v,c) = 100(v-c)/(100-c)` and CombinedARC is the mean of ARC-Easy and ARC-Challenge. The final weights were downloaded back from this repository and evaluated again, and they reproduced the same scores exactly.
|
| 45 |
+
|
| 46 |
+
The top of the sub-100M field, using the leaderboard's published figures. tinctura-v1 is scored with the same formula but is not yet listed on the board.
|
| 47 |
+
|
| 48 |
+
| Model | Params | Index |
|
| 49 |
+
|---|---:|---:|
|
| 50 |
+
| Rose-1.5-Medium | 98.2M | 21.07 |
|
| 51 |
+
| **tinctura-v1** | **96.2M** | **20.77** |
|
| 52 |
+
| Surjo-100m | 97.7M | 18.86 |
|
| 53 |
+
| cRia-LM-75M | 75.7M | 18.06 |
|
| 54 |
+
| Rose-Medium | 97.8M | 17.73 |
|
| 55 |
+
| Surjo-50M | 53.8M | 16.40 |
|
| 56 |
+
|
| 57 |
+

|
| 58 |
+
|
| 59 |
+

|
| 60 |
+
|
| 61 |
+
Against the leader the result is split. tinctura-v1 is ahead on ARC-Easy and PIQA, level on HellaSwag, and behind on ARC-Challenge and ArithMark-3. ArithMark-3 is most of the gap: 3.0 points there cost about 0.7 Index at its 0.65 weight, more than the whole 0.30 margin. Rose-1.5-Medium was trained on roughly 100B tokens according to its card, against 75B here.
|
| 62 |
+
|
| 63 |
+
## What a third fewer parameters costs
|
| 64 |
+
|
| 65 |
+
Because tinctura-v1 follows cagliostro-v3 step for step, the two runs can be compared at identical points in training. Several of these comparisons were run side by side on the same machine with the same evaluation code, using checkpoints from both repositories.
|
| 66 |
+
|
| 67 |
+

|
| 68 |
+
|
| 69 |
+
Through the stable phase the smaller model trailed by about 1.7 Index over the first 20B tokens and by about 2.9 after that. Single evaluations carry roughly one point of noise, so individual gaps ranged from 0.5 to 3.9. Just before the cooldown, at step 646,000, the paired evaluation read 19.34 against 21.96.
|
| 70 |
+
|
| 71 |
+

|
| 72 |
+
|
| 73 |
+
The cooldown is where the two models part. cagliostro-v3 gained 4.6 Index over the last 15% of training. tinctura-v1 gained 1.4. The shortfall came in two places. From step 646,000 to 706,000 cagliostro-v3 added 1.95 and tinctura-v1 only 0.21. From 706,000 to 736,000 the two moved together, 1.32 and 1.23. Over the final stretch to the end cagliostro-v3 added another 1.32 while tinctura-v1 held flat. On ARC-Challenge and ArithMark-3 the smaller model finished the cooldown slightly lower than it started it.
|
| 74 |
+
|
| 75 |
+

|
| 76 |
+
|
| 77 |
+
After the first few billion tokens the training loss gap to cagliostro-v3 settled between 0.07 and 0.10 and stayed there through the cooldown. The sharp drop at 63.75B is the data mixture changing, not the model improving.
|
| 78 |
+
|
| 79 |
+
## The cooldown was run twice
|
| 80 |
+
|
| 81 |
+
The first attempt at the cooldown hit a bug in the data loader. When training switches to the cooldown mixture, each process restarts its data-loading threads. Threads blocked on a full queue could miss the stop signal and keep producing batches from the old mixture next to the new ones, so each process trained on a blend. A standalone test of the loader leaked old-mixture batches in 9 of 10 trials, 20 to 44% of batches after the switch. The loss told on it: at the switch the loss fell by 0.26 where cagliostro-v3's fell by 0.49.
|
| 82 |
+
|
| 83 |
+
The loader was fixed so that every restart gets its own queue and old threads exit on their own, and the fixed version leaked nothing in the same test. The cooldown was then rerun from the last checkpoint before it, step 644,000. The rerun's loss fell by 0.45 at the switch and tracked cagliostro-v3 as expected. The weights in this repository come from the rerun.
|
| 84 |
+
|
| 85 |
+
The fix did not change the benchmarks in a measurable way. At step 706,000 the first attempt scored 19.68 and the rerun 19.55, which is within evaluation noise. The data-mixing bug was real, but it was not what held the cooldown gain down.
|
| 86 |
+
|
| 87 |
+
## Model details
|
| 88 |
+
|
| 89 |
+
| Field | Value |
|
| 90 |
+
|---|---:|
|
| 91 |
+
| Parameters | 96,200,064 |
|
| 92 |
+
| Non-embedding parameters | 78.2% |
|
| 93 |
+
| Layers | 18 |
|
| 94 |
+
| Hidden size | 640 |
|
| 95 |
+
| Intermediate size | 1,536 |
|
| 96 |
+
| Attention heads | 10 |
|
| 97 |
+
| Key/value heads | 5 |
|
| 98 |
+
| Attention | Grouped query attention with cross-head subspace attenuation |
|
| 99 |
+
| Activation | SwiGLU |
|
| 100 |
+
| Normalization | RMSNorm, eps 1e-6 |
|
| 101 |
+
| Positional encoding | RoPE, theta 100,000 |
|
| 102 |
+
| Context length | 2,048 |
|
| 103 |
+
| Vocabulary | 32,768 BPE |
|
| 104 |
+
| Embeddings | Tied input and output |
|
| 105 |
+
| Logit cap | 15.0 |
|
| 106 |
+
| Weights | float32 safetensors |
|
| 107 |
+
|
| 108 |
+
The architecture is defined in this repository and is the same code as cagliostro-v3. `trust_remote_code=True` is required because `CagliostroForCausalLM` is not part of transformers.
|
| 109 |
+
|
| 110 |
+
## Training data
|
| 111 |
+
|
| 112 |
+
The same mixtures and shards as cagliostro-v3. The first mixture covers the stable phase, and the second takes over when the cooldown begins at 85% of the run.
|
| 113 |
+
|
| 114 |
+
| Source | Stable phase | Cooldown |
|
| 115 |
+
|---|---:|---:|
|
| 116 |
+
| FineWeb-Edu (deduplicated) | 43.7% | 37.0% |
|
| 117 |
+
| DCLM-Baseline | 28.3% | 5.0% |
|
| 118 |
+
| Cosmopedia v2 | 16.0% | 25.0% |
|
| 119 |
+
| FineMath 3+ | 5.0% | 15.0% |
|
| 120 |
+
| OpenMathInstruct-2 | 3.0% | 13.0% |
|
| 121 |
+
| InfiWebMath 3+ | 2.0% | 0.0% |
|
| 122 |
+
| SmolTalk | 2.0% | 5.0% |
|
| 123 |
+
|
| 124 |
+
Mathematics rises from 10% to 28% during the cooldown.
|
| 125 |
+
|
| 126 |
+
## Training setup
|
| 127 |
+
|
| 128 |
+
| Field | Value |
|
| 129 |
+
|---|---:|
|
| 130 |
+
| Optimizer | AdamW, betas 0.9 and 0.95, weight decay 0.01 |
|
| 131 |
+
| Peak learning rate | 3e-3 |
|
| 132 |
+
| Schedule | Warmup-stable-decay |
|
| 133 |
+
| Warmup | 2,000 steps |
|
| 134 |
+
| Stable phase | steps 2,000 to 648,498 at peak learning rate |
|
| 135 |
+
| Cooldown | 114,441 steps, cosine to zero |
|
| 136 |
+
| Tokens per step | 98,304 |
|
| 137 |
+
| Total steps | 762,939 |
|
| 138 |
+
| Precision | bfloat16 with float32 master weights |
|
| 139 |
+
| Hardware | eight RTX 5090, data parallel, 6 sequences of 2,048 tokens per GPU |
|
| 140 |
+
| Throughput | about 1.05M tokens per second |
|
| 141 |
+
| Wall clock | about 21 hours for the published run, plus 2 hours on the discarded first cooldown |
|
| 142 |
+
|
| 143 |
+
## Usage
|
| 144 |
+
|
| 145 |
+
```python
|
| 146 |
+
import torch
|
| 147 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 148 |
+
|
| 149 |
+
model_id = "bench-labs/tinctura-v1"
|
| 150 |
+
tok = AutoTokenizer.from_pretrained(model_id)
|
| 151 |
+
model = AutoModelForCausalLM.from_pretrained(model_id, trust_remote_code=True, dtype=torch.float32)
|
| 152 |
+
|
| 153 |
+
ids = tok("The capital of France is", return_tensors="pt")
|
| 154 |
+
out = model.generate(**ids, max_new_tokens=32, do_sample=False)
|
| 155 |
+
print(tok.decode(out[0], skip_special_tokens=True))
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
This is a base model with no instruction tuning and no chat template. It completes text.
|
| 159 |
+
|
| 160 |
+
## Samples
|
| 161 |
+
|
| 162 |
+
Twelve fixed prompts, one sample each, unedited. Sampling at temperature 0.7, top-p 0.9, repetition penalty 1.1, 48 new tokens, seed 0 before every prompt. These are the same prompts used for cagliostro-v3. The film shows the first sentence of three of them. The misses are left in.
|
| 163 |
+
|
| 164 |
+
<details>
|
| 165 |
+
<summary>All 12 samples</summary>
|
| 166 |
+
|
| 167 |
+
**1.** `The water cycle begins when`
|
| 168 |
+
|
| 169 |
+
```text
|
| 170 |
+
The water cycle begins when the oceans absorb more carbon dioxide than they release. As a result, they are rapidly cooling and ocean currents move more quickly.
|
| 171 |
+
“This is a pretty good analogy for how climate change might happen,” said Professor Charles G. Hines,
|
| 172 |
+
```
|
| 173 |
+
|
| 174 |
+
**2.** `Photosynthesis is the process by which`
|
| 175 |
+
|
| 176 |
+
```text
|
| 177 |
+
Photosynthesis is the process by which plants convert light energy into chemical energy. The reaction produces oxygen and water as a by-product.
|
| 178 |
+
What is photosynthesis?
|
| 179 |
+
Photosynthesis is a type of photosynthetic process that occurs in plants. Photosynthesis takes place in the roots
|
| 180 |
+
```
|
| 181 |
+
|
| 182 |
+
**3.** `To solve 47 + 68, first`
|
| 183 |
+
|
| 184 |
+
```text
|
| 185 |
+
To solve 47 + 68, first add the digits together:
|
| 186 |
+
\[ 4 + 7 + 8 = 11 + 8 = 19 \]
|
| 187 |
+
|
| 188 |
+
2. Now subtract the sum from 5 (the number we want to find) from
|
| 189 |
+
```
|
| 190 |
+
|
| 191 |
+
**4.** `The Roman Empire fell because`
|
| 192 |
+
|
| 193 |
+
```text
|
| 194 |
+
The Roman Empire fell because of the threat of the Black Death. The Romans were not interested in fighting off a disease, but rather had an idealism for the destruction of their enemies and the preservation of civilization. This idea was reflected in the policies of Rome, which
|
| 195 |
+
```
|
| 196 |
+
|
| 197 |
+
**5.** `A prime number is a number that`
|
| 198 |
+
|
| 199 |
+
```text
|
| 200 |
+
A prime number is a number that has exactly two distinct positive divisors: 1 and itself.
|
| 201 |
+
|
| 202 |
+
The sum of the digits of an integer is equal to the sum of its digits multiplied by the number of digits in its base-$d$ representation, where
|
| 203 |
+
```
|
| 204 |
+
|
| 205 |
+
**6.** `The three states of matter are`
|
| 206 |
+
|
| 207 |
+
```text
|
| 208 |
+
The three states of matter are also called the solids, liquids and gases.
|
| 209 |
+
- Atoms are found in a single layer called an atom.
|
| 210 |
+
- The number of atoms is inversely proportional to the energy.
|
| 211 |
+
- A gas has molecules that have very small amounts
|
| 212 |
+
```
|
| 213 |
+
|
| 214 |
+
**7.** `Gravity is the force that`
|
| 215 |
+
|
| 216 |
+
```text
|
| 217 |
+
Gravity is the force that holds everything in place, while gravity is what pulls everything towards the center of the universe.
|
| 218 |
+
|
| 219 |
+
Now, let's talk about energy. Energy is a form of power, and it can be transformed from one form to another through various processes
|
| 220 |
+
```
|
| 221 |
+
|
| 222 |
+
**8.** `In 1969, astronauts`
|
| 223 |
+
|
| 224 |
+
```text
|
| 225 |
+
In 1969, astronauts from the International Space Station (ISS) were to use their space suits for a brief period of time before being sent back to Earth. The astronauts also wore a variety of spacesuits and space suits, which they used to protect them from extreme
|
| 226 |
+
```
|
| 227 |
+
|
| 228 |
+
**9.** `The heart pumps blood through`
|
| 229 |
+
|
| 230 |
+
```text
|
| 231 |
+
The heart pumps blood through the body and then the arteries deliver the oxygen to the tissues.
|
| 232 |
+
- Blood is made up of white and red blood cells, which carry oxygen from the lungs to all parts of the body.
|
| 233 |
+
- The red blood cells are also known
|
| 234 |
+
```
|
| 235 |
+
|
| 236 |
+
**10.** `To find the area of a rectangle you`
|
| 237 |
+
|
| 238 |
+
```text
|
| 239 |
+
To find the area of a rectangle you need to know two things: the length and width.
|
| 240 |
+
|
| 241 |
+
The area of a rectangle is given by the formula A = L * W. In this case, we know that L = 10 and W = 12.
|
| 242 |
+
```
|
| 243 |
+
|
| 244 |
+
**11.** `Volcanoes form when`
|
| 245 |
+
|
| 246 |
+
```text
|
| 247 |
+
Volcanoes form when the surface of a volcano cools and becomes very hot. The resulting heat causes a lot of steam to rise up through the volcano's vents, which are areas where magma is released. When this steam comes out of the vents
|
| 248 |
+
```
|
| 249 |
+
|
| 250 |
+
**12.** `The difference between weather and climate is`
|
| 251 |
+
|
| 252 |
+
```text
|
| 253 |
+
The difference between weather and climate is more important than what the term suggests. The temperature in a given location can be found by measuring how much it gets warmer or colder than the average of that region. If you have a map of your local area, you can look at its
|
| 254 |
+
```
|
| 255 |
+
|
| 256 |
+
</details>
|
| 257 |
+
|
| 258 |
+
## Reproducing the evaluation
|
| 259 |
+
|
| 260 |
+
```
|
| 261 |
+
pip install lm-eval
|
| 262 |
+
python -m lm_eval --model hf \
|
| 263 |
+
--model_args pretrained=bench-labs/tinctura-v1,dtype=float32,trust_remote_code=True \
|
| 264 |
+
--tasks hellaswag,arc_easy,arc_challenge,piqa \
|
| 265 |
+
--num_fewshot 0 --batch_size 8 --device cuda:0
|
| 266 |
+
```
|
| 267 |
+
|
| 268 |
+
ArithMark-3 uses the script linked from the leaderboard, pointed at the same model id. Evaluate in float32. The exported weights agree with the training checkpoint exactly.
|
| 269 |
+
|
| 270 |
+
## Provenance
|
| 271 |
+
|
| 272 |
+
This repository holds the training history. A checkpoint was pushed about every 30 minutes, and any of them can be retrieved by revision. The history starts at step 22,000, because pushes during the first half hour failed on a repository permission error.
|
| 273 |
+
|
| 274 |
+
The commits for steps 662,000, 680,000, 700,000 and 718,000, pushed between 23:08 UTC on 23 September and 00:39 UTC on 24 September 2026, belong to the first cooldown attempt described above and were not used. The published line continues from step 644,000 with the commits from step 656,000 onward.
|
| 275 |
+
|
| 276 |
+
## Limitations
|
| 277 |
+
|
| 278 |
+
English only. 2,048 token context. No instruction tuning, no safety tuning, no RLHF. At 96M parameters it confabulates freely, as the samples show, and should not be relied on for factual questions. The mathematics ability measured by ArithMark is arithmetic and short symbolic work, not general mathematical reasoning.
|
| 279 |
+
|
| 280 |
+
## License
|
| 281 |
+
|
| 282 |
+
Apache-2.0. The training data is drawn from FineWeb-Edu and FineMath (ODC-By), DCLM-Baseline and OpenMathInstruct-2 (CC-BY-4.0), Cosmopedia v2 and SmolTalk (Apache-2.0).
|
comparison_index.png
ADDED
|
Git LFS Details
|
comparison_tasks.png
ADDED
|
config.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"CagliostroForCausalLM"
|
| 4 |
+
],
|
| 5 |
+
"bos_token_id": 0,
|
| 6 |
+
"canon": false,
|
| 7 |
+
"dtype": "float32",
|
| 8 |
+
"eos_token_id": 0,
|
| 9 |
+
"hidden_size": 640,
|
| 10 |
+
"intermediate_size": 1536,
|
| 11 |
+
"layer_repeat": 1,
|
| 12 |
+
"logit_cap": 15.0,
|
| 13 |
+
"max_position_embeddings": 2048,
|
| 14 |
+
"mlp_type": "swiglu",
|
| 15 |
+
"model_type": "cagliostro",
|
| 16 |
+
"num_attention_heads": 10,
|
| 17 |
+
"num_hidden_layers": 18,
|
| 18 |
+
"num_key_value_heads": 5,
|
| 19 |
+
"rms_norm_eps": 1e-06,
|
| 20 |
+
"rope_theta": 100000.0,
|
| 21 |
+
"tie_word_embeddings": true,
|
| 22 |
+
"transformers_version": "5.17.0",
|
| 23 |
+
"value_residual": false,
|
| 24 |
+
"vocab_size": 32768,
|
| 25 |
+
"xsa": true,
|
| 26 |
+
"auto_map": {
|
| 27 |
+
"AutoConfig": "configuration_cagliostro.CagliostroConfig",
|
| 28 |
+
"AutoModelForCausalLM": "modeling_cagliostro.CagliostroForCausalLM"
|
| 29 |
+
}
|
| 30 |
+
}
|
configuration_cagliostro.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers import PretrainedConfig
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class CagliostroConfig(PretrainedConfig):
|
| 5 |
+
model_type = "cagliostro"
|
| 6 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 7 |
+
|
| 8 |
+
def __init__(
|
| 9 |
+
self,
|
| 10 |
+
vocab_size=32768,
|
| 11 |
+
hidden_size=640,
|
| 12 |
+
num_hidden_layers=30,
|
| 13 |
+
num_attention_heads=10,
|
| 14 |
+
num_key_value_heads=5,
|
| 15 |
+
intermediate_size=1600,
|
| 16 |
+
max_position_embeddings=4096,
|
| 17 |
+
rope_theta=100000.0,
|
| 18 |
+
rms_norm_eps=1e-6,
|
| 19 |
+
tie_word_embeddings=True,
|
| 20 |
+
mlp_type="swiglu",
|
| 21 |
+
xsa=False,
|
| 22 |
+
canon=False,
|
| 23 |
+
value_residual=False,
|
| 24 |
+
layer_repeat=1,
|
| 25 |
+
logit_cap=0.0,
|
| 26 |
+
**kwargs,
|
| 27 |
+
):
|
| 28 |
+
self.vocab_size = vocab_size
|
| 29 |
+
self.hidden_size = hidden_size
|
| 30 |
+
self.num_hidden_layers = num_hidden_layers
|
| 31 |
+
self.num_attention_heads = num_attention_heads
|
| 32 |
+
self.num_key_value_heads = num_key_value_heads
|
| 33 |
+
self.intermediate_size = intermediate_size
|
| 34 |
+
self.max_position_embeddings = max_position_embeddings
|
| 35 |
+
self.rope_theta = rope_theta
|
| 36 |
+
self.rms_norm_eps = rms_norm_eps
|
| 37 |
+
self.mlp_type = mlp_type
|
| 38 |
+
self.xsa = xsa
|
| 39 |
+
self.canon = canon
|
| 40 |
+
self.value_residual = value_residual
|
| 41 |
+
self.layer_repeat = layer_repeat
|
| 42 |
+
self.logit_cap = logit_cap
|
| 43 |
+
super().__init__(tie_word_embeddings=tie_word_embeddings, **kwargs)
|
cooldown_gain.png
ADDED
|
generation_config.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_from_model_config": true,
|
| 3 |
+
"bos_token_id": 0,
|
| 4 |
+
"eos_token_id": 0,
|
| 5 |
+
"output_attentions": false,
|
| 6 |
+
"output_hidden_states": false,
|
| 7 |
+
"transformers_version": "5.17.0"
|
| 8 |
+
}
|
index_curve.png
ADDED
|
Git LFS Details
|
loss_curve.png
ADDED
|
Git LFS Details
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e6dfb66d0c7dc41fefb5ab0f7d4846cb0d84b4eab2f4413ff9991d899695e52b
|
| 3 |
+
size 384820248
|
modeling_cagliostro.py
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
import torch.nn as nn
|
| 5 |
+
import torch.nn.functional as F
|
| 6 |
+
from transformers import PreTrainedModel
|
| 7 |
+
from transformers.generation import GenerationMixin
|
| 8 |
+
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 9 |
+
|
| 10 |
+
try:
|
| 11 |
+
from .configuration_cagliostro import CagliostroConfig
|
| 12 |
+
except ImportError:
|
| 13 |
+
from configuration_cagliostro import CagliostroConfig
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class RMSNorm(nn.Module):
|
| 17 |
+
def __init__(self, dim, eps=1e-6):
|
| 18 |
+
super().__init__()
|
| 19 |
+
self.eps = eps
|
| 20 |
+
self.weight = nn.Parameter(torch.ones(dim))
|
| 21 |
+
|
| 22 |
+
def forward(self, x):
|
| 23 |
+
dtype = x.dtype
|
| 24 |
+
x = x.float()
|
| 25 |
+
x = x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
|
| 26 |
+
return x.to(dtype) * self.weight
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def rope_freqs(seq_len, head_dim, theta, device=None):
|
| 30 |
+
inv_freq = 1.0 / (theta ** (torch.arange(0, head_dim, 2, device=device).float() / head_dim))
|
| 31 |
+
t = torch.arange(seq_len, device=device).float()
|
| 32 |
+
freqs = torch.outer(t, inv_freq)
|
| 33 |
+
return torch.cat([freqs, freqs], dim=-1)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def rotate_half(x):
|
| 37 |
+
x1, x2 = x.chunk(2, dim=-1)
|
| 38 |
+
return torch.cat([-x2, x1], dim=-1)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def apply_rope(x, cos, sin):
|
| 42 |
+
return x * cos + rotate_half(x) * sin
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class Attention(nn.Module):
|
| 46 |
+
def __init__(self, dim, n_heads, n_kv_heads, head_dim, norm_eps=1e-6,
|
| 47 |
+
xsa=False, value_residual=False):
|
| 48 |
+
super().__init__()
|
| 49 |
+
if n_heads % n_kv_heads != 0:
|
| 50 |
+
raise ValueError(
|
| 51 |
+
f"num_attention_heads ({n_heads}) must be divisible by "
|
| 52 |
+
f"num_key_value_heads ({n_kv_heads})")
|
| 53 |
+
self.n_heads = n_heads
|
| 54 |
+
self.n_kv_heads = n_kv_heads
|
| 55 |
+
self.head_dim = head_dim
|
| 56 |
+
self.n_rep = n_heads // n_kv_heads
|
| 57 |
+
self.xsa = xsa
|
| 58 |
+
|
| 59 |
+
self.q_proj = nn.Linear(dim, n_heads * head_dim, bias=False)
|
| 60 |
+
self.k_proj = nn.Linear(dim, n_kv_heads * head_dim, bias=False)
|
| 61 |
+
self.v_proj = nn.Linear(dim, n_kv_heads * head_dim, bias=False)
|
| 62 |
+
self.o_proj = nn.Linear(n_heads * head_dim, dim, bias=False)
|
| 63 |
+
|
| 64 |
+
self.q_norm = RMSNorm(head_dim, eps=norm_eps)
|
| 65 |
+
self.k_norm = RMSNorm(head_dim, eps=norm_eps)
|
| 66 |
+
|
| 67 |
+
self.value_residual = value_residual
|
| 68 |
+
if value_residual:
|
| 69 |
+
self.v_mix = nn.Parameter(torch.full((1,), -4.0))
|
| 70 |
+
|
| 71 |
+
def forward(self, x, cos, sin, attn_mask=None, v_first=None):
|
| 72 |
+
B, T, _ = x.shape
|
| 73 |
+
q = self.q_proj(x).view(B, T, self.n_heads, self.head_dim)
|
| 74 |
+
k = self.k_proj(x).view(B, T, self.n_kv_heads, self.head_dim)
|
| 75 |
+
v = self.v_proj(x).view(B, T, self.n_kv_heads, self.head_dim)
|
| 76 |
+
|
| 77 |
+
q = self.q_norm(q)
|
| 78 |
+
k = self.k_norm(k)
|
| 79 |
+
q = apply_rope(q, cos, sin)
|
| 80 |
+
k = apply_rope(k, cos, sin)
|
| 81 |
+
|
| 82 |
+
v_raw = v
|
| 83 |
+
if self.value_residual and v_first is not None:
|
| 84 |
+
lam = torch.sigmoid(self.v_mix)
|
| 85 |
+
v = (1 - lam) * v + lam * v_first
|
| 86 |
+
|
| 87 |
+
q = q.transpose(1, 2)
|
| 88 |
+
k = k.transpose(1, 2).repeat_interleave(self.n_rep, dim=1)
|
| 89 |
+
v = v.transpose(1, 2).repeat_interleave(self.n_rep, dim=1)
|
| 90 |
+
|
| 91 |
+
if attn_mask is None:
|
| 92 |
+
out = F.scaled_dot_product_attention(q, k, v, is_causal=True)
|
| 93 |
+
else:
|
| 94 |
+
out = F.scaled_dot_product_attention(q, k, v, attn_mask=attn_mask)
|
| 95 |
+
|
| 96 |
+
if self.xsa:
|
| 97 |
+
num = (out * v).sum(dim=-1, keepdim=True)
|
| 98 |
+
den = (v * v).sum(dim=-1, keepdim=True).clamp_min(1e-6)
|
| 99 |
+
out = out - (num / den) * v
|
| 100 |
+
|
| 101 |
+
out = out.transpose(1, 2).contiguous().view(B, T, -1)
|
| 102 |
+
return self.o_proj(out), v_raw
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class SwiGLU(nn.Module):
|
| 106 |
+
def __init__(self, dim, hidden):
|
| 107 |
+
super().__init__()
|
| 108 |
+
self.gate_proj = nn.Linear(dim, hidden, bias=False)
|
| 109 |
+
self.up_proj = nn.Linear(dim, hidden, bias=False)
|
| 110 |
+
self.down_proj = nn.Linear(hidden, dim, bias=False)
|
| 111 |
+
|
| 112 |
+
def forward(self, x):
|
| 113 |
+
return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
class ReLU2MLP(nn.Module):
|
| 117 |
+
def __init__(self, dim, hidden):
|
| 118 |
+
super().__init__()
|
| 119 |
+
self.up_proj = nn.Linear(dim, hidden, bias=False)
|
| 120 |
+
self.down_proj = nn.Linear(hidden, dim, bias=False)
|
| 121 |
+
|
| 122 |
+
def forward(self, x):
|
| 123 |
+
return self.down_proj(F.relu(self.up_proj(x)).square())
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
class Canon(nn.Module):
|
| 127 |
+
def __init__(self, dim, kernel=4):
|
| 128 |
+
super().__init__()
|
| 129 |
+
self.kernel = kernel
|
| 130 |
+
self.conv = nn.Conv1d(dim, dim, kernel, groups=dim, bias=False)
|
| 131 |
+
|
| 132 |
+
def forward(self, x):
|
| 133 |
+
y = F.pad(x.transpose(1, 2), (self.kernel - 1, 0))
|
| 134 |
+
return x + self.conv(y).transpose(1, 2)
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
class DecoderLayer(nn.Module):
|
| 138 |
+
def __init__(self, dim, n_heads, n_kv_heads, head_dim, mlp_hidden, norm_eps,
|
| 139 |
+
xsa, mlp_type, canon, value_residual):
|
| 140 |
+
super().__init__()
|
| 141 |
+
self.attn_norm = RMSNorm(dim, eps=norm_eps)
|
| 142 |
+
self.attn = Attention(dim, n_heads, n_kv_heads, head_dim, norm_eps,
|
| 143 |
+
xsa=xsa, value_residual=value_residual)
|
| 144 |
+
self.mlp_norm = RMSNorm(dim, eps=norm_eps)
|
| 145 |
+
self.mlp = ReLU2MLP(dim, mlp_hidden) if mlp_type == "relu2" else SwiGLU(dim, mlp_hidden)
|
| 146 |
+
self.canon = Canon(dim) if canon else None
|
| 147 |
+
|
| 148 |
+
def forward(self, x, cos, sin, attn_mask=None, v_first=None):
|
| 149 |
+
h = self.attn_norm(x)
|
| 150 |
+
if self.canon is not None:
|
| 151 |
+
h = self.canon(h)
|
| 152 |
+
a, v = self.attn(h, cos, sin, attn_mask, v_first)
|
| 153 |
+
x = x + a
|
| 154 |
+
x = x + self.mlp(self.mlp_norm(x))
|
| 155 |
+
return x, v
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class CagliostroPreTrainedModel(PreTrainedModel):
|
| 159 |
+
config_class = CagliostroConfig
|
| 160 |
+
base_model_prefix = "model"
|
| 161 |
+
supports_gradient_checkpointing = False
|
| 162 |
+
_no_split_modules = ["DecoderLayer"]
|
| 163 |
+
_tied_weights_keys = {"lm_head.weight": "embed_tokens.weight"}
|
| 164 |
+
|
| 165 |
+
def _init_weights(self, module):
|
| 166 |
+
if isinstance(module, nn.Linear):
|
| 167 |
+
nn.init.normal_(module.weight, mean=0.0, std=0.02)
|
| 168 |
+
elif isinstance(module, nn.Embedding):
|
| 169 |
+
nn.init.normal_(module.weight, mean=0.0, std=0.02)
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
class CagliostroForCausalLM(CagliostroPreTrainedModel, GenerationMixin):
|
| 173 |
+
def __init__(self, config):
|
| 174 |
+
super().__init__(config)
|
| 175 |
+
dim = config.hidden_size
|
| 176 |
+
self.head_dim = dim // config.num_attention_heads
|
| 177 |
+
self.layer_repeat = max(1, config.layer_repeat)
|
| 178 |
+
self.logit_cap = config.logit_cap
|
| 179 |
+
|
| 180 |
+
mlp_hidden = config.intermediate_size
|
| 181 |
+
if config.mlp_type == "relu2":
|
| 182 |
+
mlp_hidden = int(round(mlp_hidden * 1.5 / 64) * 64)
|
| 183 |
+
|
| 184 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, dim)
|
| 185 |
+
self.layers = nn.ModuleList([
|
| 186 |
+
DecoderLayer(
|
| 187 |
+
dim, config.num_attention_heads, config.num_key_value_heads,
|
| 188 |
+
self.head_dim, mlp_hidden, config.rms_norm_eps,
|
| 189 |
+
config.xsa, config.mlp_type, config.canon,
|
| 190 |
+
config.value_residual and i > 0,
|
| 191 |
+
)
|
| 192 |
+
for i in range(config.num_hidden_layers)
|
| 193 |
+
])
|
| 194 |
+
self.norm_out = RMSNorm(dim, eps=config.rms_norm_eps)
|
| 195 |
+
self.lm_head = nn.Linear(dim, config.vocab_size, bias=False)
|
| 196 |
+
|
| 197 |
+
self.rope_theta = config.rope_theta
|
| 198 |
+
self._rope_cache = None
|
| 199 |
+
|
| 200 |
+
self.post_init()
|
| 201 |
+
|
| 202 |
+
def _rope(self, seq_len, device, dtype):
|
| 203 |
+
key = (seq_len, str(device), str(dtype))
|
| 204 |
+
if self._rope_cache is None or self._rope_cache[0] != key:
|
| 205 |
+
freqs = rope_freqs(seq_len, self.head_dim, self.rope_theta, device=device)
|
| 206 |
+
self._rope_cache = (key,
|
| 207 |
+
freqs.cos()[None, :, None, :].to(dtype),
|
| 208 |
+
freqs.sin()[None, :, None, :].to(dtype))
|
| 209 |
+
return self._rope_cache[1], self._rope_cache[2]
|
| 210 |
+
|
| 211 |
+
def get_input_embeddings(self):
|
| 212 |
+
return self.embed_tokens
|
| 213 |
+
|
| 214 |
+
def set_input_embeddings(self, value):
|
| 215 |
+
self.embed_tokens = value
|
| 216 |
+
|
| 217 |
+
def get_output_embeddings(self):
|
| 218 |
+
return self.lm_head
|
| 219 |
+
|
| 220 |
+
def set_output_embeddings(self, value):
|
| 221 |
+
self.lm_head = value
|
| 222 |
+
|
| 223 |
+
def _causal_mask(self, attention_mask, B, T, dtype, device):
|
| 224 |
+
causal = torch.ones(T, T, dtype=torch.bool, device=device).tril()
|
| 225 |
+
mask = causal[None, None, :, :].expand(B, 1, T, T)
|
| 226 |
+
if attention_mask is not None:
|
| 227 |
+
pad = attention_mask.to(torch.bool)[:, None, None, :]
|
| 228 |
+
mask = mask & pad
|
| 229 |
+
out = torch.zeros(mask.shape, dtype=dtype, device=device)
|
| 230 |
+
return out.masked_fill(~mask, torch.finfo(dtype).min)
|
| 231 |
+
|
| 232 |
+
def forward(self, input_ids=None, attention_mask=None, labels=None,
|
| 233 |
+
inputs_embeds=None, use_cache=None, output_attentions=None,
|
| 234 |
+
output_hidden_states=None, return_dict=None, **kwargs):
|
| 235 |
+
if inputs_embeds is None:
|
| 236 |
+
x = self.embed_tokens(input_ids)
|
| 237 |
+
else:
|
| 238 |
+
x = inputs_embeds
|
| 239 |
+
B, T, _ = x.shape
|
| 240 |
+
|
| 241 |
+
cos, sin = self._rope(T, x.device, x.dtype)
|
| 242 |
+
|
| 243 |
+
attn_mask = None
|
| 244 |
+
if attention_mask is not None and attention_mask.dim() == 2 and not bool(attention_mask.all()):
|
| 245 |
+
attn_mask = self._causal_mask(attention_mask, B, T, x.dtype, x.device)
|
| 246 |
+
|
| 247 |
+
v_first = None
|
| 248 |
+
for layer in self.layers:
|
| 249 |
+
for _ in range(self.layer_repeat):
|
| 250 |
+
x, v = layer(x, cos, sin, attn_mask, v_first)
|
| 251 |
+
if v_first is None:
|
| 252 |
+
v_first = v
|
| 253 |
+
|
| 254 |
+
x = self.norm_out(x)
|
| 255 |
+
logits = self.lm_head(x)
|
| 256 |
+
if self.logit_cap:
|
| 257 |
+
logits = self.logit_cap * torch.tanh(logits / self.logit_cap)
|
| 258 |
+
|
| 259 |
+
loss = None
|
| 260 |
+
if labels is not None:
|
| 261 |
+
shift_logits = logits[:, :-1].float().reshape(-1, logits.size(-1))
|
| 262 |
+
shift_labels = labels[:, 1:].reshape(-1)
|
| 263 |
+
loss = F.cross_entropy(shift_logits, shift_labels, ignore_index=-100)
|
| 264 |
+
|
| 265 |
+
if return_dict is False:
|
| 266 |
+
return (loss, logits) if loss is not None else (logits,)
|
| 267 |
+
return CausalLMOutputWithPast(loss=loss, logits=logits)
|
| 268 |
+
|
| 269 |
+
def prepare_inputs_for_generation(self, input_ids, attention_mask=None, **kwargs):
|
| 270 |
+
return {"input_ids": input_ids, "attention_mask": attention_mask}
|
tinctura-v1.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:59475dbfb89b1ef9235a3bbe38b89de204ddc42d0194782c4fc7f364a239371f
|
| 3 |
+
size 13674126
|
tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"tokenizer_class": "PreTrainedTokenizerFast",
|
| 3 |
+
"bos_token": "<|endoftext|>",
|
| 4 |
+
"eos_token": "<|endoftext|>",
|
| 5 |
+
"unk_token": "<|endoftext|>",
|
| 6 |
+
"model_max_length": 2048
|
| 7 |
+
}
|