SONUB home EN English 한국어 日本語 中文 हिन्दी বাংলা اردو Español Português Français Deutsch Русский العربية Bahasa Indonesia Tiếng Việt ไทย Türkçe

How to enable notifications

Notifications are unavailable in this browser or on this address. Try a supported browser on the secure SONUB site.

If notifications are blocked, allow them in your browser settings.

  1. Open the site controls beside the address bar, or your browser’s site settings. Set Notifications for this site to Allow.
  2. In your device settings, allow notifications for your browser and check Do Not Disturb or Focus.
  3. Return to SONUB, reload the page, and use the bell to enable notifications.

On iPhone or iPad, add SONUB to your Home Screen, open it there, then allow notifications.

XSML · From your first line to a conversation

Now, let's build your very own AI.

Type your own language model in this browser: prepare text, train a tiny GPT, then run your Runner and XChat. No pretrained weights or external AI API.

7

Text generation

Turn next-token scores into generated text.

Generation repeatedly feeds the latest to GPT and appends one predicted token. 0 picks the highest score. Positive temperatures rescale scores before random : higher values spread probability more broadly. top_k keeps only the strongest candidates; 0 keeps all.

A seed repeats the random choices. It does not make answers correct. Generation stops at a newline or the requested token limit. Only the newly generated text is returned. Keep the Q:/A: format used during training.

Type and try

Write generate.py. Compare the three commands while keeping the same checkpoint. Change only temperature first, then top_k and seed. The checkpoint supplies its own tokenizer and model dimensions.

cd ~/xsml
nano generate.py
python3 generate.py --temperature 0 --top-k 1
python3 generate.py --temperature 0.8 --top-k 8 --seed 7
python3 generate.py --temperature 1.2 --top-k 0 --seed 8
generate.py — Complete source to type

load rebuilds the architecture and restores numbers. generate crops context, scores candidates and samples repeatedly. A fixed seed makes comparisons reproducible.

import argparse
import json
import math
import random
from pathlib import Path
from model import GPT
from tokenizer import BPE


def load():
    saved = json.loads(Path('checkpoints/model.json').read_text())
    cfg = saved['settings']
    tokenizer = BPE(**saved['tokenizer'])
    model = GPT(len(tokenizer.vocab), cfg['width'], cfg['context'], cfg['seed'])
    model.load(saved['weights'])
    return model, tokenizer, cfg


def generate(model, tokenizer, prompt, tokens=24, temperature=0.8, top_k=8, seed=7):
    if not prompt or tokens < 1 or temperature < 0 or not math.isfinite(temperature) or top_k < 0:
        raise ValueError('invalid sampling parameters')
    ids, result, rng = tokenizer.encode(prompt), [], random.Random(seed)
    for _ in range(tokens):
        logits = model.forward(ids[-model.context:])[-1]
        ranked = sorted(range(len(logits)), key=lambda i: logits[i].data, reverse=True)
        if temperature == 0:
            token = ranked[0]
        else:
            candidates = ranked[:top_k] if top_k else ranked
            peak = logits[candidates[0]].data
            weights = [math.exp((logits[i].data - peak) / temperature) for i in candidates]
            token = rng.choices(candidates, weights=weights)[0]
        ids.append(token)
        if tokenizer.vocab[token] == '\n':
            break
        result.append(token)
    return tokenizer.decode(result)


if __name__ == '__main__':
    model, tokenizer, cfg = load()
    parser = argparse.ArgumentParser()
    parser.add_argument('--prompt', default='Q: hi\nA:')
    parser.add_argument('--tokens', type=int, default=cfg['tokens'])
    parser.add_argument('--temperature', type=float, default=0.8)
    parser.add_argument('--top-k', type=int, default=8)
    parser.add_argument('--seed', type=int, default=cfg['seed'])
    args = parser.parse_args()
    assert 1 <= args.tokens <= cfg['max_tokens']
    print(generate(model, tokenizer, args.prompt, args.tokens,
                   args.temperature, args.top_k, args.seed))

Check your understanding

The same checkpoint, , seed and parameters should reproduce the same text. Explain why loading weights differs from training them and why an empty answer can occur when newline is selected first.

If you get stuck

Strange or empty output is expected from a tiny, briefly trained model. Check data format, unknown characters and training loss. More sampling randomness is not a fix for insufficient training.