Text Generation
Transformers
Safetensors
English
llama
blackhole
p150
tenstorrent
thin
trained-from-scratch
tt-metal
tt-model-cache
ttml
vllm
conversational
text-generation-inference
Instructions to use episod/tt-tnt with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use episod/tt-tnt with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="episod/tt-tnt") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("episod/tt-tnt") model = AutoModelForCausalLM.from_pretrained("episod/tt-tnt", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use episod/tt-tnt with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "episod/tt-tnt" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "episod/tt-tnt", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/episod/tt-tnt
- SGLang
How to use episod/tt-tnt 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 "episod/tt-tnt" \ --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": "episod/tt-tnt", "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 "episod/tt-tnt" \ --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": "episod/tt-tnt", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use episod/tt-tnt with Docker Model Runner:
docker model run hf.co/episod/tt-tnt
Upload README.md with huggingface_hub
Browse files
README.md
CHANGED
|
@@ -44,7 +44,7 @@ every dead end, is documented at
|
|
| 44 |
| Hidden size | 384 |
|
| 45 |
| Layers | 6 |
|
| 46 |
| Attention heads / KV groups | 6 / 3 |
|
| 47 |
-
| Context length | **
|
| 48 |
| Vocabulary | 32,000 (byte-level BPE, trained for this model) |
|
| 49 |
| Weights dtype | bfloat16 |
|
| 50 |
| Training hardware | One Tenstorrent Blackhole chip (`mesh_shape [1, 1]`) |
|
|
@@ -60,56 +60,100 @@ a verbatim copy of tt-train's own `nanollama3.yaml`.
|
|
| 60 |
|
| 61 |
| | |
|
| 62 |
|---|---|
|
| 63 |
-
| Corpus | Nine-source, licence-audited blend β TinyStories, Simple English Wikipedia, and seven curated Project Gutenberg slices (see [`docs/corpus_blend.md`](https://github.com/tsingletaryTT/tt-tnt/blob/main/docs/corpus_blend.md)).
|
| 64 |
-
| Tokens seen | **
|
| 65 |
-
| Steps | 10,
|
| 66 |
-
| Wall clock | ~
|
| 67 |
-
| Final train loss | 3.
|
| 68 |
-
| **Final validation loss** | **4.2203** |
|
| 69 |
| Optimizer | AdamW, constant lr 3e-4, weight decay 0.01, `stochastic_rounding: true` |
|
| 70 |
|
| 71 |
## Limitations β please read these
|
| 72 |
|
| 73 |
-
**
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
match.** Read against the frozen evaluation set
|
| 85 |
-
([`docs/measurements/samples-tt-tnt-
|
| 86 |
greedy decoding, 15 prompts): the model sometimes engages with a prompt's own material β sticks,
|
| 87 |
-
roses, a procession, bees β where a TinyStories-only baseline would default to a generic moral
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
|
|
|
| 96 |
|
| 97 |
**It is a base completion model.** No instruction tuning, no chat template. Give it the opening
|
| 98 |
of a simple story; do not ask it questions.
|
| 99 |
|
| 100 |
-
**Its context is
|
| 101 |
Note that `tokenizer_config.json` carries the conventional `model_max_length` sentinel
|
| 102 |
(~1e18). Do not derive a serving length from it β use `max_position_embeddings`. Serving this
|
| 103 |
-
model with a 4k context will silently degrade output
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
**Unlike the original checkpoint, this run's RMSNorm layers did learn.** The very first tt-tnt
|
| 106 |
checkpoint (see Lineage) trained with `stochastic_rounding` disabled, which silently froze all
|
| 107 |
13 RMSNorm gammas at bfloat16's rounding fixed-point of 1.0 β the gradients were real, but every
|
| 108 |
update rounded back to 1.0 and was discarded. This run set `stochastic_rounding: true`, and it
|
| 109 |
-
worked: read directly from the
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
its normalization layers genuinely live
|
| 113 |
|
| 114 |
## Verification
|
| 115 |
|
|
@@ -144,16 +188,23 @@ Runs on CPU; no Tenstorrent hardware required for inference.
|
|
| 144 |
## Sample output
|
| 145 |
|
| 146 |
Greedy decoding, 60 new tokens, from the frozen evaluation set
|
| 147 |
-
([`docs/measurements/samples-tt-tnt-
|
| 148 |
|
| 149 |
-
>
|
| 150 |
-
>
|
| 151 |
-
>
|
| 152 |
-
> bite. It was so sweet and juicy!**
|
| 153 |
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
|
| 158 |
## Licensing and provenance
|
| 159 |
|
|
@@ -194,11 +245,21 @@ tt-train's own `nanollama3.yaml`, and every checkpoint (including the one this c
|
|
| 194 |
is trained through `ttml` against it. What changed is the corpus and tokenizer this project
|
| 195 |
now owns β a nine-source, licence-audited blend and a BPE tokenizer trained on that blend,
|
| 196 |
rather than a single downloaded corpus and an inherited vocabulary β and that is what earned
|
| 197 |
-
the new name, `tt-tnt`.
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
|
| 203 |
## Origin
|
| 204 |
|
|
|
|
| 44 |
| Hidden size | 384 |
|
| 45 |
| Layers | 6 |
|
| 46 |
| Attention heads / KV groups | 6 / 3 |
|
| 47 |
+
| Context length | **2048** |
|
| 48 |
| Vocabulary | 32,000 (byte-level BPE, trained for this model) |
|
| 49 |
| Weights dtype | bfloat16 |
|
| 50 |
| Training hardware | One Tenstorrent Blackhole chip (`mesh_shape [1, 1]`) |
|
|
|
|
| 60 |
|
| 61 |
| | |
|
| 62 |
|---|---|
|
| 63 |
+
| Corpus | Nine-source, licence-audited blend β TinyStories, Simple English Wikipedia, and seven curated Project Gutenberg slices (see [`docs/corpus_blend.md`](https://github.com/tsingletaryTT/tt-tnt/blob/main/docs/corpus_blend.md)). **This is the first tt-tnt checkpoint trained on a blend that carries document separators (`</s>`)** β earlier revisions contained none at all, so no previous checkpoint had ever seen an end-of-document token and none could stop generating. Measured on the token arrays directly: the pre-fix array holds **zero** id-2 tokens across the whole training split; this one averages one per ~478 tokens (one per ~210 in the short-document sources, one per ~80,000 in the book-length ones). The blend recipe β source registry, fetch/prepare/measure/blend scripts, and the provenance manifest β is published separately as [`episod/tt-tnt-corpus`](https://huggingface.co/datasets/episod/tt-tnt-corpus) |
|
| 64 |
+
| Tokens seen | **352,714,752** β the full training split, **one epoch** |
|
| 65 |
+
| Steps | 10,764 at batch 16, sequence length 2048 (32,768 tokens/step, unchanged from the previous run's 64Γ512) |
|
| 66 |
+
| Wall clock | ~91 minutes on a single Blackhole p300c |
|
| 67 |
+
| Final train loss | 3.25 |
|
| 68 |
+
| **Final validation loss** | **2.9937** β the end-of-run figure from `train/run.py`'s `evaluate()`. The periodic curve's last entry (`artifacts/checkpoints-tt-tnt-v3/val_losses.jsonl`, step 10,764) reads 2.939; the two differ only by which held-out windows each sampled. **Do not read this as an improvement on the previous checkpoint's 4.2203** β see below |
|
| 69 |
| Optimizer | AdamW, constant lr 3e-4, weight decay 0.01, `stochastic_rounding: true` |
|
| 70 |
|
| 71 |
## Limitations β please read these
|
| 72 |
|
| 73 |
+
**The headline validation loss is not comparable to the previous checkpoint's.** 2.9937 against
|
| 74 |
+
4.2203 looks like a large gain, and most of it is not one. The previous checkpoint's validation
|
| 75 |
+
split was the tail 10% of a token stream whose sources are concatenated in sorted-name order,
|
| 76 |
+
so it landed **entirely inside `wikipedia_simple`** β the most out-of-domain source in the
|
| 77 |
+
blend, and by per-source measurement the second-hardest (held-out loss 4.28, against
|
| 78 |
+
TinyStories' 1.83; see
|
| 79 |
+
[`docs/measurements/per-source-loss-tt-tnt-v1.md`](https://github.com/tsingletaryTT/tt-tnt/blob/main/docs/measurements/per-source-loss-tt-tnt-v1.md)).
|
| 80 |
+
That number measured domain transfer, not learning. This run's split is **stratified by
|
| 81 |
+
source** β a proportional tail from each of the nine β so it is a fair sample of the training
|
| 82 |
+
mixture, and a much easier one, because 31% of the mixture is TinyStories. A meaningful share
|
| 83 |
+
of the drop from 4.22 to 2.99 is the yardstick changing, not the model improving. The two
|
| 84 |
+
numbers should not be subtracted.
|
| 85 |
+
|
| 86 |
+
**It has seen its training corpus once, not memorized it.** At batch 16, sequence length 2048,
|
| 87 |
+
10,764 steps is one epoch over the blend's 352.7M-token training split β the same 32,768
|
| 88 |
+
tokens per step as the previous run, at four times the context. The validation curve
|
| 89 |
+
(`artifacts/checkpoints-tt-tnt-v3/val_losses.jsonl`) falls from 5.084 at step 500 to ~3.28 by
|
| 90 |
+
step 4,000, and then keeps drifting down slowly and noisily β the last ~2,300 steps oscillate
|
| 91 |
+
between 2.87 and 3.10 against ~3.12 around step 7,000β8,000. That is a real if modest continued
|
| 92 |
+
decline, unlike the previous run, which was flat for its final stretch. Read plainly: this one
|
| 93 |
+
had not clearly stopped improving when it ended, but the per-step gain over the last third is
|
| 94 |
+
small enough that more steps at these settings would not transform it.
|
| 95 |
+
|
| 96 |
+
**It can now stop, which no previous checkpoint could.** Every earlier tt-tnt checkpoint was
|
| 97 |
+
trained on a corpus containing **zero** `</s>` tokens while its `config.json` nonetheless
|
| 98 |
+
declared `eos_token_id: 2` β so generation could never terminate naturally and always ran to
|
| 99 |
+
whatever token limit the caller set. This is the first checkpoint trained on a corpus that
|
| 100 |
+
marks document boundaries, and it does terminate: on the frozen 15-prompt evaluation set at
|
| 101 |
+
128 max new tokens, **5/15 completions end on `</s>` under greedy decoding** (median 48 tokens)
|
| 102 |
+
and **11/30 under sampling** at temperature 0.8 / top_p 0.95 (median 91). The comparable
|
| 103 |
+
numbers for the previous checkpoint are **0/15 and 0/30** β not "rarely", but never, by
|
| 104 |
+
construction. This matters most for chained generation, where you want a passage to end rather
|
| 105 |
+
than be cut off mid-sentence at the limit.
|
| 106 |
+
|
| 107 |
+
It is a partial fix, not a solved problem: two thirds of completions still run to the limit,
|
| 108 |
+
and the model is much readier to stop on short-document material (TinyStories-like prompts)
|
| 109 |
+
than on the book-length sources, which is what the corpus taught it β separator density in the
|
| 110 |
+
blend ranges from one per ~210 tokens in the short sources to one per ~80,000 in the books.
|
| 111 |
+
|
| 112 |
+
**The corpus is a nine-source, licence-audited blend, and the model's behavior is a mix to
|
| 113 |
match.** Read against the frozen evaluation set
|
| 114 |
+
([`docs/measurements/samples-tt-tnt-v3.md`](https://github.com/tsingletaryTT/tt-tnt/blob/main/docs/measurements/samples-tt-tnt-v3.md),
|
| 115 |
greedy decoding, 15 prompts): the model sometimes engages with a prompt's own material β sticks,
|
| 116 |
+
roses, a procession, bees β where a TinyStories-only baseline would default to a generic moral.
|
| 117 |
+
But **TinyStories still dominates**, and under greedy decoding several prompts still degenerate
|
| 118 |
+
into hard repetition loops ("the rose is a rose, and the rose is a rose, and..."; "the bees were
|
| 119 |
+
busy, and the bees were busy"). The oblique, observational voice this blend targets β closer to
|
| 120 |
+
Fabre's insect notebooks than to a children's story β is **not** present in this checkpoint.
|
| 121 |
+
Under sampling the output is markedly better behaved
|
| 122 |
+
([`docs/measurements/samples-tt-tnt-v3-t0.8.md`](https://github.com/tsingletaryTT/tt-tnt/blob/main/docs/measurements/samples-tt-tnt-v3-t0.8.md)),
|
| 123 |
+
which is the honest way to read the greedy loops: greedy decoding on a 22M-parameter model
|
| 124 |
+
manufactures repetition attractors that sampling largely avoids. Treat the promising examples
|
| 125 |
+
as evidence of what the blend can nudge toward, not as evidence the voice has arrived.
|
| 126 |
|
| 127 |
**It is a base completion model.** No instruction tuning, no chat template. Give it the opening
|
| 128 |
of a simple story; do not ask it questions.
|
| 129 |
|
| 130 |
+
**Its context is 2048 tokens** (256 β 512 β 2048 across the three checkpoints β see Lineage).
|
| 131 |
Note that `tokenizer_config.json` carries the conventional `model_max_length` sentinel
|
| 132 |
(~1e18). Do not derive a serving length from it β use `max_position_embeddings`. Serving this
|
| 133 |
+
model with a 4k context will silently degrade output; serving it at 512 silently discards three
|
| 134 |
+
quarters of the context it was trained to use.
|
| 135 |
+
|
| 136 |
+
**Whether it actually uses all 2048 tokens is a separate question from whether it was trained
|
| 137 |
+
at 2048.** A position-wise loss probe on the *previous* checkpoint found per-token loss flat
|
| 138 |
+
from position ~64 onward β that model extracted nothing from distant context, because the
|
| 139 |
+
corpus had no document boundaries and so distant context genuinely was unpredictable. Fixing
|
| 140 |
+
the separators is what makes a longer window worth having, and is why this run raised it. The
|
| 141 |
+
equivalent probe for this checkpoint
|
| 142 |
+
([`docs/measurements/context-use-tt-tnt-v3.md`](https://github.com/tsingletaryTT/tt-tnt/blob/main/docs/measurements/context-use-tt-tnt-v3.md))
|
| 143 |
+
shows loss still falling well past where the old one went flat β 4.23 at positions [0,32),
|
| 144 |
+
3.28 at [32,64), 2.94 at [64,128), 2.85 at [256,512) β but the improvement past ~256 tokens is
|
| 145 |
+
about 0.02 nats per bucket against a standard error of ~0.08, i.e. **directionally right and
|
| 146 |
+
inside the noise**. The honest claim is that the long window is no longer actively useless, not
|
| 147 |
+
that all 2048 tokens are earning their keep.
|
| 148 |
|
| 149 |
**Unlike the original checkpoint, this run's RMSNorm layers did learn.** The very first tt-tnt
|
| 150 |
checkpoint (see Lineage) trained with `stochastic_rounding` disabled, which silently froze all
|
| 151 |
13 RMSNorm gammas at bfloat16's rounding fixed-point of 1.0 β the gradients were real, but every
|
| 152 |
update rounded back to 1.0 and was discarded. This run set `stochastic_rounding: true`, and it
|
| 153 |
+
worked: read directly from the published weights, all 13 gammas have moved off 1.0 and none is
|
| 154 |
+
degenerate (per-tensor means 0.874β1.720, per-tensor standard deviation 0.034β0.207, values
|
| 155 |
+
spanning roughly 0.691β2.359 across the set; zero tensors have standard deviation 0). The model
|
| 156 |
+
trained with its normalization layers genuinely live.
|
| 157 |
|
| 158 |
## Verification
|
| 159 |
|
|
|
|
| 188 |
## Sample output
|
| 189 |
|
| 190 |
Greedy decoding, 60 new tokens, from the frozen evaluation set
|
| 191 |
+
([`docs/measurements/samples-tt-tnt-v3.md`](https://github.com/tsingletaryTT/tt-tnt/blob/main/docs/measurements/samples-tt-tnt-v3.md)):
|
| 192 |
|
| 193 |
+
> Once upon a time, there was a little **girl named Lily. She loved to play outside in the
|
| 194 |
+
> park. One day, she saw a big, shiny rock on the ground. She picked it up and showed it to
|
| 195 |
+
> her mom. "Look, Mommy! I found a shiny rock!" she said. Her mom smiled and said, "That**
|
|
|
|
| 196 |
|
| 197 |
+
And one that **stops on its own** rather than being cut off at the limit β the new behavior
|
| 198 |
+
described in Limitations:
|
| 199 |
+
|
| 200 |
+
> The ants had learned that being eaten was a way of **helping others. The moral of the story
|
| 201 |
+
> is that it's important to be kind to others and to help others.**
|
| 202 |
+
|
| 203 |
+
Both are near the top of the frozen set of 15, not typical of it β see Limitations above and
|
| 204 |
+
the linked file for the honest range, including the TinyStories collapses to "a little girl
|
| 205 |
+
named Lily" and several hard repetition loops. Sampled output at temperature 0.8 is in
|
| 206 |
+
[`docs/measurements/samples-tt-tnt-v3-t0.8.md`](https://github.com/tsingletaryTT/tt-tnt/blob/main/docs/measurements/samples-tt-tnt-v3-t0.8.md)
|
| 207 |
+
and is the more representative read of the model's range.
|
| 208 |
|
| 209 |
## Licensing and provenance
|
| 210 |
|
|
|
|
| 245 |
is trained through `ttml` against it. What changed is the corpus and tokenizer this project
|
| 246 |
now owns β a nine-source, licence-audited blend and a BPE tokenizer trained on that blend,
|
| 247 |
rather than a single downloaded corpus and an inherited vocabulary β and that is what earned
|
| 248 |
+
the new name, `tt-tnt`.
|
| 249 |
+
|
| 250 |
+
Three checkpoints have now been published under this repo id, and it is worth being plain
|
| 251 |
+
about which is which, because they differ only in weights and one config field:
|
| 252 |
+
|
| 253 |
+
| | corpus | context | document separators |
|
| 254 |
+
|---|---|---|---|
|
| 255 |
+
| the original (TinyStories-only) | TinyStories alone | 256 | none |
|
| 256 |
+
| the first blend-trained checkpoint | nine-source blend | 512 | **none** |
|
| 257 |
+
| **this one** | nine-source blend, separator-carrying revision | **2048** | **yes** |
|
| 258 |
+
|
| 259 |
+
The middle checkpoint was the first trained on the blend; this one is the first trained on a
|
| 260 |
+
revision of that blend which marks where one document ends and the next begins, and the first
|
| 261 |
+
whose declared `eos_token_id: 2` corresponds to a token the training data actually contained.
|
| 262 |
+
That, rather than the context length, is the substantive difference.
|
| 263 |
|
| 264 |
## Origin
|
| 265 |
|