Text Generation
Transformers
Safetensors
English
llama
gpt-u
tiny-lm
pretrained-from-scratch
text-generation-inference
Instructions to use DedeProGames/GPT-U-20M with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use DedeProGames/GPT-U-20M with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="DedeProGames/GPT-U-20M")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("DedeProGames/GPT-U-20M") model = AutoModelForCausalLM.from_pretrained("DedeProGames/GPT-U-20M", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use DedeProGames/GPT-U-20M with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "DedeProGames/GPT-U-20M" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "DedeProGames/GPT-U-20M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/DedeProGames/GPT-U-20M
- SGLang
How to use DedeProGames/GPT-U-20M 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 "DedeProGames/GPT-U-20M" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "DedeProGames/GPT-U-20M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'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 "DedeProGames/GPT-U-20M" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "DedeProGames/GPT-U-20M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use DedeProGames/GPT-U-20M with Docker Model Runner:
docker model run hf.co/DedeProGames/GPT-U-20M
Download scripts/train_tokenizer.py from DedeProGames/GPT-U-20M: direct link, hf CLI and curl.
- Browser
- Download file 9.57 kB
-
https://huggingface.co/DedeProGames/GPT-U-20M/resolve/main/scripts/train_tokenizer.py
- Command line
-
hf download hf://DedeProGames/GPT-U-20M/scripts/train_tokenizer.py
-
curl -L -o train_tokenizer.py https://huggingface.co/DedeProGames/GPT-U-20M/resolve/main/scripts/train_tokenizer.py
9.57 kB
| """Train the GPT-U-20M tokenizer: byte-level BPE, 16,384 vocab, on ~2 GB of text sampled in the 45/35/20 mix. | |
| Stages (finished stages are skipped on re-run): | |
| 1. corpus -> data/tok_corpus/<stream>.jsonl (training files) + <stream>.holdout.jsonl (holdout files) | |
| 2. train -> tokenizer/ | |
| 3. validate -> logs/tokenizer_report.json: fertility per domain, round-trip on 1000 samples | |
| """ | |
| import json | |
| import multiprocessing as mp | |
| import random | |
| import time | |
| from concurrent.futures import ProcessPoolExecutor | |
| from tokenizers import Regex, Tokenizer, decoders, models, pre_tokenizers, trainers | |
| from transformers import PreTrainedTokenizerFast | |
| from common import LOG_DIR, ROOT, TOKENIZER_DIR | |
| from sources import STREAM_DOMAIN, STREAM_SHARE, STREAMS, file_splits, open_stream | |
| EOT = "<|endoftext|>" | |
| VOCAB_SIZE = 16384 | |
| CORPUS_BYTES = 2_000_000_000 | |
| HOLDOUT_DOCS = 1000 | |
| CORPUS_DIR = ROOT / "data" / "tok_corpus" | |
| SPLITS_PATH = ROOT / "data" / "file_splits.json" | |
| # cl100k-style split: whitespace runs stay whole pre-tokens (Python indentation), digits handled by Digits below. | |
| SPLIT_PATTERN = r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\s\p{L}\p{N}]+[\r\n]*|\s*[\r\n]+|\s+(?!\S)|\s+""" | |
| def log(msg: str) -> None: | |
| print(f"[{time.strftime('%H:%M:%S')}] {msg}", flush=True) | |
| def collect(name: str, files: list[str], byte_budget: float, max_docs: float, out_name: str): | |
| out_path = CORPUS_DIR / out_name | |
| tmp = out_path.with_suffix(".tmp") | |
| n_docs = n_bytes = 0 | |
| t0 = time.time() | |
| with open(tmp, "w", encoding="utf-8") as f: | |
| for row in open_stream(name, files): | |
| f.write(json.dumps({"text": row["text"]}, ensure_ascii=False) + "\n") | |
| n_docs += 1 | |
| n_bytes += len(row["text"].encode("utf-8")) | |
| if n_bytes >= byte_budget or n_docs >= max_docs: | |
| break | |
| if n_docs % 50_000 == 0: | |
| log(f" {out_name}: {n_docs:,} docs, {n_bytes / 1e6:,.0f} MB ({n_bytes / 1e6 / (time.time() - t0):.1f} MB/s)") | |
| tmp.replace(out_path) | |
| return out_name, n_docs, n_bytes, time.time() - t0 | |
| def build_corpus(splits: dict) -> None: | |
| CORPUS_DIR.mkdir(parents=True, exist_ok=True) | |
| jobs = [] | |
| for name in STREAMS: | |
| part = splits[STREAM_DOMAIN[name]] | |
| jobs.append((name, part["train"], STREAM_SHARE[name] * CORPUS_BYTES, float("inf"), f"{name}.jsonl")) | |
| jobs.append((name, part["holdout"], float("inf"), HOLDOUT_DOCS, f"{name}.holdout.jsonl")) | |
| pending = [j for j in jobs if not (CORPUS_DIR / j[-1]).exists()] | |
| log(f"corpus: {len(pending)} of {len(jobs)} files to collect") | |
| t0 = time.time() | |
| with ProcessPoolExecutor(max_workers=4, mp_context=mp.get_context("spawn")) as ex: | |
| for out_name, n_docs, n_bytes, secs in ex.map(collect, *zip(*pending)) if pending else []: | |
| log(f" done {out_name}: {n_docs:,} docs, {n_bytes / 1e6:,.1f} MB in {secs / 60:.1f} min") | |
| log(f"corpus ready in {(time.time() - t0) / 60:.1f} min") | |
| def read_texts(out_name: str, limit: int | None = None) -> list[str]: | |
| texts = [] | |
| with open(CORPUS_DIR / out_name, encoding="utf-8") as f: | |
| for line in f: | |
| texts.append(json.loads(line)["text"]) | |
| if limit and len(texts) >= limit: | |
| break | |
| return texts | |
| def batches(out_names: list[str], size: int = 1000): | |
| buf = [] | |
| for out_name in out_names: | |
| with open(CORPUS_DIR / out_name, encoding="utf-8") as f: | |
| for line in f: | |
| buf.append(json.loads(line)["text"]) | |
| if len(buf) == size: | |
| yield buf | |
| buf = [] | |
| if buf: | |
| yield buf | |
| def build_tokenizer() -> Tokenizer: | |
| tok = Tokenizer(models.BPE(byte_fallback=True)) | |
| tok.pre_tokenizer = pre_tokenizers.Sequence([ | |
| pre_tokenizers.Split(Regex(SPLIT_PATTERN), behavior="isolated"), | |
| pre_tokenizers.Digits(individual_digits=True), | |
| pre_tokenizers.ByteLevel(add_prefix_space=False, use_regex=False), | |
| ]) | |
| tok.decoder = decoders.ByteLevel() | |
| return tok | |
| def train() -> None: | |
| tok = build_tokenizer() | |
| trainer = trainers.BpeTrainer(vocab_size=VOCAB_SIZE, special_tokens=[EOT], | |
| initial_alphabet=pre_tokenizers.ByteLevel.alphabet(), show_progress=False) | |
| t0 = time.time() | |
| tok.train_from_iterator(batches([f"{name}.jsonl" for name in STREAMS]), trainer=trainer) | |
| log(f"BPE trained in {(time.time() - t0) / 60:.1f} min, vocab {tok.get_vocab_size()}") | |
| TOKENIZER_DIR.mkdir(parents=True, exist_ok=True) | |
| hf_tok = PreTrainedTokenizerFast(tokenizer_object=tok, bos_token=EOT, eos_token=EOT, pad_token=EOT, | |
| model_max_length=1024, clean_up_tokenization_spaces=False) | |
| hf_tok.save_pretrained(TOKENIZER_DIR) | |
| EDGE_CASES = [ | |
| "def f(x):\n\tif x:\n\t\treturn x\n\treturn None\n", | |
| "class A:\n def __init__(self):\n self.x = 1\n\n\n def run(self): # comment\n pass\n", | |
| " four\n eight\n\t\ttabs\n \t mixed \t\n", | |
| "line1\r\nline2\r\n\r\nline3\rline4", | |
| "Olá, ação, coração — “aspas” ‘simples’ … não é?", | |
| "日本語のテキスト、中文文本,한국어 텍스트", | |
| "emoji 👍🏽 👨👩👧👦 🇧🇷 ❤️", | |
| "مرحبا بالعالم שלום עולם", | |
| "combining: e\u0301 a\u0308 n\u0303", | |
| "zero-width:\u200b\u200c\u200d\ufeff end", | |
| "numbers 1234567890 3.14159 -0.0001 1e-10 0xFF 000123", | |
| " leading and trailing spaces ", | |
| "\n\n\n\t\t\t\n", | |
| "", | |
| " ", | |
| "control \x00\x01\x1f\x7f chars", | |
| "math ∑∫√∞≠≤≥ αβγ ℝ²", | |
| "<|endoftext|> literal special token <|endoftext|>", | |
| "a" * 5000, | |
| " " * 300 + "x", | |
| ] | |
| RANGES = [(0x20, 0x7E), (0xA0, 0x24F), (0x370, 0x3FF), (0x400, 0x4FF), (0x590, 0x6FF), (0x900, 0x97F), | |
| (0x3040, 0x30FF), (0x4E00, 0x4FFF), (0xAC00, 0xAD00), (0x2000, 0x206F), (0x2200, 0x22FF), | |
| (0x1F300, 0x1F64F), (0x1F900, 0x1F9FF)] | |
| WHITESPACE = [" ", " ", " ", "\t", "\t\t", "\n", "\r\n", "\n\n", "\u00a0", "\u3000", "\n ", "\n\t"] | |
| def synthetic(n: int, rng: random.Random) -> list[str]: | |
| out = list(EDGE_CASES) | |
| while len(out) < n: | |
| parts = [] | |
| for _ in range(rng.randint(5, 60)): | |
| r = rng.random() | |
| if r < 0.3: | |
| parts.append(rng.choice(WHITESPACE)) | |
| elif r < 0.4: | |
| parts.append(rng.choice(EDGE_CASES)) | |
| else: | |
| lo, hi = rng.choice(RANGES) | |
| parts.append("".join(chr(rng.randint(lo, hi)) for _ in range(rng.randint(1, 8)))) | |
| out.append("".join(parts)) | |
| return out[:n] | |
| def fertility(tok: Tokenizer, texts: list[str]) -> dict: | |
| n_tok = sum(len(e.ids) for e in tok.encode_batch(texts)) | |
| n_words = sum(len(t.split()) for t in texts) | |
| n_bytes = sum(len(t.encode("utf-8")) for t in texts) | |
| return {"docs": len(texts), "tokens": n_tok, "tokens_per_word": round(n_tok / n_words, 4), | |
| "bytes_per_token": round(n_bytes / n_tok, 4)} | |
| def validate() -> dict: | |
| tok = Tokenizer.from_file(str(TOKENIZER_DIR / "tokenizer.json")) | |
| hf_tok = PreTrainedTokenizerFast.from_pretrained(TOKENIZER_DIR) | |
| held = {name: read_texts(f"{name}.holdout.jsonl") for name in STREAMS} | |
| n_py = round(HOLDOUT_DOCS * 0.27) | |
| code_mix = held["code_py"][:n_py] + held["code_other"][:HOLDOUT_DOCS - n_py] | |
| report = { | |
| "vocab_size": tok.get_vocab_size(), | |
| "eot_id": tok.token_to_id(EOT), | |
| "fits_uint16": tok.get_vocab_size() <= 65535, | |
| "fertility": { | |
| "dclm": fertility(tok, held["dclm"]), | |
| "edu": fertility(tok, held["edu"]), | |
| "code": fertility(tok, code_mix), | |
| "code_python_only": fertility(tok, held["code_py"]), | |
| }, | |
| } | |
| rng = random.Random(0) | |
| code_all = held["code_py"] + held["code_other"] | |
| rng.shuffle(code_all) | |
| tabbed = [t for t in code_all if "\t" in t][:150] | |
| plain = [t for t in code_all if "\t" not in t][:300 - len(tabbed)] | |
| samples = held["dclm"][:300] + held["edu"][:300] + tabbed + plain + synthetic(100, rng) | |
| raw_fail = [i for i, s in enumerate(samples) if tok.decode(tok.encode(s).ids, skip_special_tokens=False) != s] | |
| hf_fail = [i for i, s in enumerate(samples) | |
| if hf_tok.decode(hf_tok.encode(s, add_special_tokens=False), skip_special_tokens=False, | |
| clean_up_tokenization_spaces=False) != s] | |
| report["round_trip"] = { | |
| "samples": len(samples), | |
| "with_tabs": sum("\t" in s for s in samples), | |
| "non_ascii": sum(not s.isascii() for s in samples), | |
| "failures_tokenizers": len(raw_fail), | |
| "failures_transformers": len(hf_fail), | |
| "first_failures": [repr(samples[i][:120]) for i in (raw_fail + hf_fail)[:5]], | |
| } | |
| example = "def f(x):\n return x\n\t\tpass # 2024" | |
| report["example_tokens"] = tok.encode(example).tokens | |
| return report | |
| def main() -> None: | |
| splits = file_splits(SPLITS_PATH) | |
| log("holdout files: " + ", ".join(f"{d}={v['holdout'][0]}" for d, v in splits.items())) | |
| build_corpus(splits) | |
| if (TOKENIZER_DIR / "tokenizer.json").exists(): | |
| log("tokenizer already trained, skipping") | |
| else: | |
| train() | |
| report = validate() | |
| LOG_DIR.mkdir(parents=True, exist_ok=True) | |
| (LOG_DIR / "tokenizer_report.json").write_text(json.dumps(report, indent=2, ensure_ascii=False)) | |
| log(json.dumps(report, indent=2, ensure_ascii=False)) | |
| if __name__ == "__main__": | |
| main() | |