File size: 4,797 Bytes
5434506 e3d43ae 9bab82f e3d43ae 5434506 e3d43ae 9bab82f e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 9bab82f e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 9bab82f e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 78fb42d e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 e3d43ae 5434506 | 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 | ---
language: multilingual
license: apache-2.0
tags:
- language-identification
- text-classification
- programming-language-detection
- spam-detection
- toxicity-detection
- byte-level
- multi-task
- lightweight
pipeline_tag: text-classification
---
# Glyph — Multi-Task Byte-Level Text Classifier
**4M parameters** · **5 tasks** · **No tokenizer needed** · **Runs on CPU**
Glyph is an ultra-compact multi-task text classification model that operates directly on raw UTF-8 bytes. A single shared backbone serves 5 classification heads simultaneously.
## Tasks & Performance
| Task | Labels | Val Accuracy | Description |
|------|--------|-------------|-------------|
| `lang_id` | 351 | 94.3% | Language identification |
| `prog_lang` | 30 | 94.4% | Programming language detection |
| `spam` | 2 | 96.1% | Spam vs ham classification |
| `toxic` | 2 | 67.3% | Toxicity detection (multilingual) |
**Average validation accuracy: 88.0%**
## Architecture
Glyph uses a byte-level hybrid architecture inspired by [CommonLingua](https://huggingface.co/PleIAs/CommonLingua):
- **Input**: Raw UTF-8 bytes (no tokenizer), padded to 512 bytes
- **Trigram hash embedding**: Polynomial rolling hash of byte 3-grams → 8192-bucket embedding table
- **Byte unigram embedding**: Standard embedding for individual bytes
- **4× Conv1D blocks**: Causal convolutions + BatchNorm + GELU + residual
- **2× Bidirectional attention**: Multi-head self-attention with RoPE
- **Global average pooling** → per-task classification heads
Total: ~4M shared parameters + small per-task linear heads.
## Usage
```python
import torch, importlib, sys
from huggingface_hub import hf_hub_download
# Download model + weights
model_py_path = hf_hub_download("ThingAI/Glyph", "model.py")
ckpt_path = hf_hub_download("ThingAI/Glyph", "model.pt")
# Load model definition
import importlib.util
spec = importlib.util.spec_from_file_location("model", model_py_path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
# Load weights
ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=False)
model = mod.MultiTaskLID(ckpt["task_configs"]).eval()
model.load_state_dict(ckpt["model"])
# Predict
def predict(text, task="lang_id", top_k=3):
raw = text.encode("utf-8")[:512]
byte_ids = list(raw) + [0] * (512 - len(raw))
inp = torch.tensor([byte_ids], dtype=torch.long)
with torch.no_grad():
logits = model(inp, task)["logits"][0]
probs = torch.softmax(logits, dim=-1)
idx2label = {v: k for k, v in ckpt["label_maps"][task].items()}
k = min(top_k, len(probs))
topk = probs.topk(k)
return [(idx2label[topk.indices[i].item()], topk.values[i].item()) for i in range(k)]
# Examples
print(predict("La pizza napoletana è patrimonio UNESCO", task="lang_id"))
print(predict("def foo(x): return x + 1", task="prog_lang"))
print(predict("You won a FREE iPhone!!!", task="spam"))
```
## Quick predict script
```bash
python predict.py --text "Ciao, come stai?"
# lang_id: ita (98.2%)
python predict.py --task prog_lang --text "fn main() { println!("hello"); }"
# prog_lang: Rust (97.1%)
python predict.py --task spam --text "URGENT: Click here to win!"
# spam: spam (99.5%)
```
## Training Data
| Task | Dataset | Samples |
|------|---------|---------|
| Language ID | [PleIAs/CommonLingua-Train](https://huggingface.co/datasets/PleIAs/CommonLingua-Train) | 200K (capped) |
| Programming Language | [cakiki/rosetta-code](https://huggingface.co/datasets/cakiki/rosetta-code) | ~26K |
| Spam Detection | [ucirvine/sms_spam](https://huggingface.co/datasets/ucirvine/sms_spam) | 5.5K |
| Toxicity | [textdetox/multilingual_toxicity_dataset](https://huggingface.co/datasets/textdetox/multilingual_toxicity_dataset) | ~45K |
## Key Design Decisions
- **Byte-level input**: No tokenizer means it works on any language, script, or encoding without preprocessing
- **Trigram hashing**: +1.2 F1 over unigram-only baseline, acts as regularization via hash collisions
- **Multi-task learning**: Shared backbone learns universal text representations; per-task heads are tiny (~130K params each)
- **No attention masking**: Bidirectional attention for classification (not causal)
- **OneCycleLR**: Fast convergence in few epochs
## Limitations
- Designed for paragraph-level classification (50+ bytes). Short texts (<20 bytes) may be unreliable
- Toxicity detection accuracy is lower than specialized models (trained on limited multilingual data)
- Programming language detection trained on Rosetta Code samples which have a specific style
## Citation
```bibtex
@misc{glyph2026,
author = {ThingAI},
title = {Glyph: Multi-Task Byte-Level Text Classifier},
year = {2026},
url = {https://huggingface.co/ThingAI/Glyph}
}
```
## License
Apache 2.0
|