Tutorial — Text Generation¶
Notebook: generation.ipynb
(download)
What you'll build¶
A minimal causal-LM generation loop using the SNEPPX Transformer and the
sampling/beam-search utilities in SneppX_ALG.interface_bindings.generation.
Setup¶
$env:PYTHONPATH = "bindings/python"
import numpy as np
from SneppX_ALG import Transformer, Tokenizer, Tensor
from SneppX_ALG.interface_bindings.generation import (
generate, GenerationConfig, TextStreamer, TokenStreamer,
)
HAS_C = __import__("SneppX_ALG")._HAS_C_BACKEND
1. A tiny model¶
We keep vocab/size small so the NumPy path is fast enough to preview behavior.
model = Transformer(
vocab_size=200, dim=64, num_heads=4, num_layers=2,
ffn_dim=128, max_seq_len=64, dropout=0.0,
)
model.eval()
2. Greedy search (do_sample=False)¶
cfg = GenerationConfig(max_new_tokens=24, do_sample=False)
ids = [1, 2, 3] # BOS, token, token
out = generate(model, ids, generation_config=cfg)
print(out["output_ids"]) # (1, 3 + 24)
3. Sampling with top-k + top-p¶
cfg = GenerationConfig(
max_new_tokens=48,
do_sample=True,
temperature=0.8,
top_k=40,
top_p=0.9,
repetition_penalty=1.15,
)
out = generate(model, ids, generation_config=cfg)
print("final length:", out["output_ids"].shape)
generate picks the strategy automatically:
| Condition | Strategy |
|---|---|
num_beams > 1 |
beam search |
do_sample and temperature > 1e-6 |
sampling (top-k/top-p) |
| otherwise | greedy |
4. Beam search¶
cfg = GenerationConfig(
max_new_tokens=32,
num_beams=3,
length_penalty=0.7,
early_stopping=True,
)
out = generate(model, ids, generation_config=cfg)
5. Stream tokens live¶
tok = Tokenizer(vocab_size=200)
stream = TextStreamer(tokenizer=tok, skip_prompt=True)
out = generate(model, ids, generation_config=GenerationConfig(max_new_tokens=40), streamer=stream)
# tokens print as they are produced
For raw IDs instead of text, swap TextStreamer for TokenStreamer and read
stream.get_tokens().
6. Batch generation (variable-length prompts)¶
from SneppX_ALG.interface_bindings.generation import batch_generate
prompts = [[1,2,3], [1,4,5,6,7], [1,8,9]]
cfg = GenerationConfig(max_new_tokens=16, temperature=0.7)
out = batch_generate(model, prompts, generation_config=cfg)
print(out["output_ids"].shape) # (3, max_len + 16)
Key takeaways¶
generateexpects a model whoseforward(input_ids=..., past_key_values=..., use_cache=True)returns{"logits", "past_key_values"};Transformerreturns logits directly, so wrap it for true KV-cache decoding in production (seedocs/API.md).- CPU-safe NumPy sampling loop works without the C backend — just slower.
repetition_penalty,top_k,top_p, andstop_stringsare all configurable viaGenerationConfig(or**kwargsoverride).
Next steps¶
- Pair with a real
Tokenizer(HFtokenizersJSON) — see Data Pipeline. - Serve the model with
sneppx-serve— see Quantization + Serving.