Cortex-0 / tests /test_generate.py
Frankenstein-Labs's picture
feat(model): Phase 2 — transformer texte from scratch
37d8122 verified
Raw History Blame Contribute Delete
2.57 kB
"""Phase 2/3 — tests de la génération (échantillonnage écrit à la main)."""
from __future__ import annotations
import torch
from src.generate import _apply_top_k, _apply_top_p, generate, generate_text
from src.model.text_model import CortexTextLM, TextConfig
from src.tokenizer import load_tokenizer
TINY = TextConfig(vocab_size=32, n_layer=2, n_head=2, n_embd=32, ctx_len=16, dropout=0.0)
def _tiny():
torch.manual_seed(0)
return CortexTextLM(TINY).eval()
def test_top_k_keeps_exactly_k_finite():
logits = torch.randn(1, 10)
filtered = _apply_top_k(logits, 3)
assert torch.isfinite(filtered).sum().item() == 3
def test_top_p_keeps_a_prefix_by_probability():
logits = torch.zeros(1, 5)
logits[0, 0] = 10.0 # proba ~ 1
filtered = _apply_top_p(logits, 0.5)
assert torch.isfinite(filtered[0, 0])
assert not torch.isfinite(filtered[0, 1:]).any()
def test_greedy_is_deterministic():
model = _tiny()
x = torch.randint(0, 32, (1, 4))
a = generate(model, x, max_new_tokens=5, greedy=True)
b = generate(model, x, max_new_tokens=5, greedy=True)
assert torch.equal(a, b)
def test_generate_extends_sequence():
model = _tiny()
x = torch.randint(0, 32, (1, 4))
out = generate(model, x, max_new_tokens=6, temperature=1.0)
assert out.shape == (1, 10)
assert torch.equal(out[:, :4], x)
def test_generate_respects_ctx_len():
model = _tiny()
x = torch.randint(0, 32, (1, 16))
out = generate(model, x, max_new_tokens=3, greedy=True)
assert out.shape[1] == 19 # la condition est tronquée mais la sortie grandit
def test_generate_stops_on_eos(monkeypatch):
model = _tiny()
x = torch.randint(0, 32, (1, 3))
eos = 7
# Force le modèle à toujours prédire eos.
def fake_forward(input_ids, targets=None):
logits = torch.full((input_ids.size(0), input_ids.size(1), 32), -100.0)
logits[:, :, eos] = 100.0
return logits, None
monkeypatch.setattr(model, "forward", fake_forward)
out = generate(model, x, max_new_tokens=50, greedy=True, eos_id=eos)
assert out.shape[1] == 4 # un seul nouveau token, puis arrêt
def test_generate_text_with_real_tokenizer():
"""Bout-en-bout avec le vrai tokenizer 32k : ne doit pas planter."""
tok = load_tokenizer()
model = CortexTextLM(
TextConfig(vocab_size=tok.vocab_size, n_layer=1, n_head=2, n_embd=32, ctx_len=32)
).eval()
text = generate_text(model, tok, "Bonjour", max_new_tokens=5, greedy=True)
assert isinstance(text, str) and len(text) > 0