Text Generation
Transformers
Safetensors
English
nano-proofread
grammar-correction
proofreading
homophones
tiny
byte-level
from-scratch
Instructions to use vukrosic/nano-proofread with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use vukrosic/nano-proofread with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="vukrosic/nano-proofread")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("vukrosic/nano-proofread", dtype="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use vukrosic/nano-proofread with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "vukrosic/nano-proofread" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "vukrosic/nano-proofread", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/vukrosic/nano-proofread
- SGLang
How to use vukrosic/nano-proofread 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 "vukrosic/nano-proofread" \ --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": "vukrosic/nano-proofread", "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 "vukrosic/nano-proofread" \ --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": "vukrosic/nano-proofread", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use vukrosic/nano-proofread with Docker Model Runner:
docker model run hf.co/vukrosic/nano-proofread
| """Standalone nano-proofread benchmark: the published weights vs the best context-free | |
| script, overall and on the context-dependent slice the script cannot do. | |
| The naive script (`naive_fix` in data_proofread.py) is the strongest *context-free* | |
| fixer a developer would write: remove adjacent doubled words, and normalise every | |
| homophone to the most common member of its family. It fixes doubled words and | |
| `could of`->`could have` perfectly, but it cannot know whether `their`/`there`/ | |
| `they're` is right — that needs the surrounding words. The hard slice = examples where | |
| the correct homophone is NOT the script's default, i.e. exactly where context decides. | |
| python eval_nano_proofread.py | |
| """ | |
| from __future__ import annotations | |
| import torch | |
| from data_proofread import OOD_CASES, naive_fix, proofread_pairs | |
| from modeling_nano_proofread import load | |
| _HOLDOUT_SEED = 987_654_321 | |
| def _greedy_batch(model, prompts, max_new=48, device="cpu"): | |
| """Greedy-decode `max_new` tokens per prompt, then cut at the newline EOS. | |
| Prompts are bucketed by EXACT byte length so each batch is a dense, padding-free | |
| (B, L) tensor — bucketing (not padding) keeps the result bit-identical to decoding | |
| one prompt at a time.""" | |
| enc = [list(p.encode("utf-8")) for p in prompts] | |
| order = sorted(range(len(prompts)), key=lambda i: len(enc[i])) | |
| max_seq = model.cfg["max_seq_len"] | |
| out = [None] * len(prompts) | |
| i = 0 | |
| while i < len(order): | |
| L = len(enc[order[i]]) | |
| j = i | |
| while j < len(order) and len(enc[order[j]]) == L: | |
| j += 1 | |
| rows = order[i:j] | |
| toks = torch.tensor([enc[k] for k in rows], dtype=torch.long, device=device) | |
| for _ in range(max_new): | |
| nxt = model(toks[:, -max_seq:])[:, -1, :].argmax(-1, keepdim=True) | |
| toks = torch.cat([toks, nxt], dim=1) | |
| tail = toks[:, L:L + max_new] | |
| for r, k in enumerate(rows): | |
| s = bytes(int(b) & 0xFF for b in tail[r].tolist()).decode("utf-8", "replace") | |
| out[k] = s.split("\n", 1)[0] | |
| i = j | |
| return out | |
| def main(): | |
| m = load() | |
| n_params = sum(p.numel() for p in m.parameters()) | |
| pairs = proofread_pairs(_HOLDOUT_SEED, 4000) | |
| preds = _greedy_batch(m, [p for p, _ in pairs]) | |
| mo = nv = 0 | |
| hn = hm = hnv = 0 | |
| for (prompt, target), pred in zip(pairs, preds): | |
| inp = prompt[:-4] | |
| mo += pred == target | |
| nv += naive_fix(inp) == target | |
| if naive_fix(target) != target: # correct answer isn't the script default | |
| hn += 1 | |
| hm += pred == target | |
| hnv += naive_fix(inp) == target | |
| N = len(pairs) | |
| print(f"params : {n_params:,}") | |
| print(f"held-out: N={N} (seed {_HOLDOUT_SEED})\n") | |
| print(f" {'overall':<28}model {mo/N:>6.1%} naive-script {nv/N:>6.1%}") | |
| print(f" context slice (N={hn}): model {hm/hn:>6.1%} naive-script {hnv/hn:>6.1%}") | |
| print(" (context slice = correct homophone is NOT the script's default —") | |
| print(" exactly where the surrounding words decide the answer)") | |
| # ---- the honest test: hand-written natural phrases NOT drawn from the frames ---- | |
| ood_preds = _greedy_batch(m, [f"{i} => " for i, _ in OOD_CASES]) | |
| om = onv = 0 | |
| print(f"\nOUT-OF-DISTRIBUTION (hand-written, N={len(OOD_CASES)}):") | |
| for (inp, gold), pred in zip(OOD_CASES, ood_preds): | |
| om += pred == gold | |
| onv += naive_fix(inp) == gold | |
| flag = "ok " if pred == gold else "XX " | |
| print(f" {flag}{inp:<28}-> {pred:<28} (gold: {gold})") | |
| O = len(OOD_CASES) | |
| print(f"\n OOD exact-match: model {om/O:>6.1%} naive-script {onv/O:>6.1%}") | |
| if __name__ == "__main__": | |
| main() | |