Text Generation
TensorRT
Safetensors
PyTorch
English
llama
code
developer-agent
blackwell
rtx-5070
slm
conversational
Instructions to use Vivid86/MiniTransformer-91M with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- TensorRT
How to use Vivid86/MiniTransformer-91M with TensorRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
File size: 7,407 Bytes
9e30969 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | """
Text generation with top-k + nucleus (top-p) sampling.
SAMPLING STRATEGIES:
βββββββββββββββββββββ
GREEDY (temperature=0):
Always picks the highest-probability token. Fast but repetitive β the model
gets stuck in loops because the same high-probability token is chosen forever.
TEMPERATURE SCALING:
Divides logits by `temperature` before softmax:
- temperature < 1.0 β sharper distribution β more confident, focused
- temperature > 1.0 β flatter distribution β more random, creative
- temperature = 1.0 β unmodified model distribution
TOP-K FILTERING:
Zeros out all but the K highest-probability tokens. Prevents sampling from
the long tail of very unlikely tokens. Typical values: 40β100.
TOP-P (NUCLEUS) SAMPLING:
Sort tokens by probability (descending). Keep only the smallest set whose
cumulative probability sum reaches `top_p`. The cutoff adapts to the shape
of the distribution β if the model is confident (one token has 80% prob),
nucleus is tight. If the model is uncertain, more tokens are included.
COMBINING TOP-K AND TOP-P:
Apply top-k first, then top-p on the survivors. This clips both the
absolute count and the probability mass of the sampling pool.
KV-CACHE AT INFERENCE:
During training, the full sequence is processed in one forward pass.
During autoregressive generation, each step appends one token and re-runs
the model over the entire grown sequence β O(TΒ²) total compute.
The KV-cache stores K, V tensors from all previous steps. Each new step
only processes the single new token, then appends to the cache.
Total compute drops to O(T) β a massive speedup for long generations.
This implementation uses the cache from MiniTransformer.
"""
import torch
import torch.nn.functional as F
from tokenizer.bpe_tokenizer import BPETokenizer
def sample_logits(
logits: torch.Tensor,
temperature: float = 1.0,
top_k: int = 50,
top_p: float = 0.9,
) -> int:
"""
Sample a single token ID from a logits tensor.
Args:
logits: Raw logits, shape [1, vocab_size].
temperature: Scaling factor. 0 β greedy argmax.
top_k: Keep only top-k tokens (None or 0 to disable).
top_p: Nucleus probability threshold (None or 1.0 to disable).
Returns:
A single integer token ID.
"""
# Greedy shortcut
if temperature <= 0:
return int(logits.argmax(dim=-1).item())
logits = logits / temperature
# ββ Top-k filtering βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if top_k and top_k > 0:
k = min(top_k, logits.size(-1))
v, _ = torch.topk(logits, k)
# v[:, -1:] is the k-th highest value per row β shape [B, 1] for broadcast
logits = logits.masked_fill(logits < v[:, -1:], float("-inf"))
# ββ Top-p (nucleus) filtering βββββββββββββββββββββββββββββββββββββββββββββ
if top_p and top_p < 1.0:
sorted_logits, sorted_indices = torch.sort(logits, descending=True)
cumulative_probs = torch.cumsum(F.softmax(sorted_logits, dim=-1), dim=-1)
# Remove tokens once the cumulative probability exceeds top_p.
# Shift right by 1 so we always keep at least the top-1 token.
remove_mask = (cumulative_probs - F.softmax(sorted_logits, dim=-1)) > top_p
sorted_logits = sorted_logits.masked_fill(remove_mask, float("-inf"))
# Scatter back to original token order
logits = torch.zeros_like(logits).scatter_(1, sorted_indices, sorted_logits)
probs = F.softmax(logits, dim=-1)
return int(torch.multinomial(probs, num_samples=1).item())
def generate(
model,
prompt: str,
tokenizer: "BPETokenizer | None" = None,
max_new_tokens: int = 50,
temperature: float = 0.8,
top_k: int = 50,
top_p: float = 0.9,
device: str = "cuda" if torch.cuda.is_available() else "cpu",
use_kv_cache: bool = True,
repetition_penalty: float = 1.15,
penalty_window: int = 64,
) -> str:
"""
Autoregressively generate text from a prompt using the trained model.
Args:
model: A trained MiniTransformer.
prompt: Input text string to condition generation on.
tokenizer: BPETokenizer instance. Created if not provided.
Pass one in to avoid reloading from disk each call.
max_new_tokens: Maximum number of tokens to generate.
temperature: Sampling temperature (0 = greedy).
top_k: Top-k filtering. Disable with None or 0.
top_p: Nucleus sampling. Disable with None or 1.0.
device: Device for inference ("cuda" or "cpu").
use_kv_cache: Use KV-cache for faster autoregressive inference.
repetition_penalty: Multiplier to penalize repeated tokens (> 1.0 discourages loops).
penalty_window: How many recent tokens to consider for the repetition penalty.
Returns:
The decoded generated string (prompt + continuation), cleaned.
"""
if tokenizer is None:
tokenizer = BPETokenizer("dataProcessed/tokenizer.json")
context_len = model.config.context_len
model.eval()
model.to(device)
# Encode prompt to token IDs
tokens = torch.tensor(
tokenizer.encode(prompt), dtype=torch.long, device=device
).unsqueeze(0) # [1, prompt_len]
past_kvs: list | None = None
temperature = max(temperature, 1e-5)
with torch.no_grad():
for _ in range(max_new_tokens):
if use_kv_cache and past_kvs is not None:
# KV-cache mode: only feed the single newest token
context = tokens[:, -1:]
else:
# Full-context mode (first step or no cache): truncate to window
context = tokens[:, -context_len:]
logits, past_kvs_new = model(context, past_kvs if use_kv_cache else None)
if use_kv_cache:
past_kvs = past_kvs_new
next_logits = logits[:, -1, :].clone() # [1, vocab_size]
# Apply repetition penalty to recent tokens within the window
if repetition_penalty > 1.0 and tokens.shape[1] > 0:
recent_tokens = tokens[0, -penalty_window:].tolist()
for token_id in set(recent_tokens):
if next_logits[0, token_id] > 0:
next_logits[0, token_id] /= repetition_penalty
else:
next_logits[0, token_id] *= repetition_penalty
next_id = sample_logits(next_logits, temperature, top_k, top_p)
# Stop generation when the model produces the EOS token
if next_id == tokenizer.eos_id:
break
next_tensor = torch.tensor([[next_id]], dtype=torch.long, device=device)
tokens = torch.cat([tokens, next_tensor], dim=1)
decoded = tokenizer.decode(tokens[0].tolist())
return tokenizer.clean(decoded)
|