Upload ThingsLID multi-task model (epoch 3, avg acc 88.0%)
Browse files- README.md +133 -0
- label_maps.json +395 -0
- model.pt +3 -0
- model.py +86 -0
- task_configs.json +6 -0
README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language: multilingual
|
| 3 |
+
license: apache-2.0
|
| 4 |
+
tags:
|
| 5 |
+
- language-identification
|
| 6 |
+
- text-classification
|
| 7 |
+
- programming-language-detection
|
| 8 |
+
- spam-detection
|
| 9 |
+
- toxicity-detection
|
| 10 |
+
- byte-level
|
| 11 |
+
- multi-task
|
| 12 |
+
- lightweight
|
| 13 |
+
pipeline_tag: text-classification
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
# ThingsLID — Multi-Task Byte-Level Text Classifier
|
| 17 |
+
|
| 18 |
+
**4M parameters** · **5 tasks** · **No tokenizer needed** · **Runs on CPU**
|
| 19 |
+
|
| 20 |
+
ThingsLID 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.
|
| 21 |
+
|
| 22 |
+
## Tasks & Performance
|
| 23 |
+
|
| 24 |
+
| Task | Labels | Val Accuracy | Description |
|
| 25 |
+
|------|--------|-------------|-------------|
|
| 26 |
+
| `lang_id` | 351 | 94.3% | Language identification |
|
| 27 |
+
| `prog_lang` | 30 | 94.4% | Programming language detection |
|
| 28 |
+
| `spam` | 2 | 96.1% | Spam vs ham classification |
|
| 29 |
+
| `toxic` | 2 | 67.3% | Toxicity detection (multilingual) |
|
| 30 |
+
|
| 31 |
+
**Average validation accuracy: 88.0%**
|
| 32 |
+
|
| 33 |
+
## Architecture
|
| 34 |
+
|
| 35 |
+
ThingsLID uses a byte-level hybrid architecture inspired by [CommonLingua](https://huggingface.co/PleIAs/CommonLingua):
|
| 36 |
+
|
| 37 |
+
- **Input**: Raw UTF-8 bytes (no tokenizer), padded to 512 bytes
|
| 38 |
+
- **Trigram hash embedding**: Polynomial rolling hash of byte 3-grams → 8192-bucket embedding table
|
| 39 |
+
- **Byte unigram embedding**: Standard embedding for individual bytes
|
| 40 |
+
- **4× Conv1D blocks**: Causal convolutions + BatchNorm + GELU + residual
|
| 41 |
+
- **2× Bidirectional attention**: Multi-head self-attention with RoPE
|
| 42 |
+
- **Global average pooling** → per-task classification heads
|
| 43 |
+
|
| 44 |
+
Total: ~4M shared parameters + small per-task linear heads.
|
| 45 |
+
|
| 46 |
+
## Usage
|
| 47 |
+
|
| 48 |
+
```python
|
| 49 |
+
import torch
|
| 50 |
+
from huggingface_hub import hf_hub_download
|
| 51 |
+
|
| 52 |
+
# Download and load
|
| 53 |
+
ckpt_path = hf_hub_download("ThingAI/ThingsLID", "model.pt")
|
| 54 |
+
ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=False)
|
| 55 |
+
|
| 56 |
+
# Reconstruct model (see model.py in repo)
|
| 57 |
+
from model import MultiTaskLID
|
| 58 |
+
model = MultiTaskLID(ckpt["task_configs"]).eval()
|
| 59 |
+
model.load_state_dict(ckpt["model"])
|
| 60 |
+
|
| 61 |
+
# Predict
|
| 62 |
+
def predict(text, task="lang_id", top_k=3):
|
| 63 |
+
raw = text.encode("utf-8")[:512]
|
| 64 |
+
byte_ids = list(raw) + [0] * (512 - len(raw))
|
| 65 |
+
inp = torch.tensor([byte_ids], dtype=torch.long)
|
| 66 |
+
with torch.no_grad():
|
| 67 |
+
logits = model(inp, task)["logits"][0]
|
| 68 |
+
probs = torch.softmax(logits, dim=-1)
|
| 69 |
+
idx2label = {i: l for l, i in ckpt["label_maps"][task].items()}
|
| 70 |
+
topk = probs.topk(top_k)
|
| 71 |
+
return [(idx2label[topk.indices[i].item()], topk.values[i].item()) for i in range(top_k)]
|
| 72 |
+
|
| 73 |
+
# Examples
|
| 74 |
+
print(predict("La pizza napoletana è patrimonio UNESCO", task="lang_id"))
|
| 75 |
+
# [('ita', 0.98), ('cos', 0.003), ...]
|
| 76 |
+
|
| 77 |
+
print(predict("def foo(x): return x + 1", task="prog_lang"))
|
| 78 |
+
# [('Python', 0.95), ...]
|
| 79 |
+
|
| 80 |
+
print(predict("You won a FREE iPhone!!!", task="spam"))
|
| 81 |
+
# [('spam', 0.99), ...]
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
## Quick predict script
|
| 85 |
+
|
| 86 |
+
```bash
|
| 87 |
+
python predict.py --text "Ciao, come stai?"
|
| 88 |
+
# lang_id: ita (98.2%)
|
| 89 |
+
|
| 90 |
+
python predict.py --task prog_lang --text "fn main() { println!("hello"); }"
|
| 91 |
+
# prog_lang: Rust (97.1%)
|
| 92 |
+
|
| 93 |
+
python predict.py --task spam --text "URGENT: Click here to win!"
|
| 94 |
+
# spam: spam (99.5%)
|
| 95 |
+
```
|
| 96 |
+
|
| 97 |
+
## Training Data
|
| 98 |
+
|
| 99 |
+
| Task | Dataset | Samples |
|
| 100 |
+
|------|---------|---------|
|
| 101 |
+
| Language ID | [PleIAs/CommonLingua-Train](https://huggingface.co/datasets/PleIAs/CommonLingua-Train) | 200K (capped) |
|
| 102 |
+
| Programming Language | [cakiki/rosetta-code](https://huggingface.co/datasets/cakiki/rosetta-code) | ~26K |
|
| 103 |
+
| Spam Detection | [ucirvine/sms_spam](https://huggingface.co/datasets/ucirvine/sms_spam) | 5.5K |
|
| 104 |
+
| Toxicity | [textdetox/multilingual_toxicity_dataset](https://huggingface.co/datasets/textdetox/multilingual_toxicity_dataset) | ~45K |
|
| 105 |
+
|
| 106 |
+
## Key Design Decisions
|
| 107 |
+
|
| 108 |
+
- **Byte-level input**: No tokenizer means it works on any language, script, or encoding without preprocessing
|
| 109 |
+
- **Trigram hashing**: +1.2 F1 over unigram-only baseline, acts as regularization via hash collisions
|
| 110 |
+
- **Multi-task learning**: Shared backbone learns universal text representations; per-task heads are tiny (~130K params each)
|
| 111 |
+
- **No attention masking**: Bidirectional attention for classification (not causal)
|
| 112 |
+
- **OneCycleLR**: Fast convergence in few epochs
|
| 113 |
+
|
| 114 |
+
## Limitations
|
| 115 |
+
|
| 116 |
+
- Designed for paragraph-level classification (50+ bytes). Short texts (<20 bytes) may be unreliable
|
| 117 |
+
- Toxicity detection accuracy is lower than specialized models (trained on limited multilingual data)
|
| 118 |
+
- Programming language detection trained on Rosetta Code samples which have a specific style
|
| 119 |
+
|
| 120 |
+
## Citation
|
| 121 |
+
|
| 122 |
+
```bibtex
|
| 123 |
+
@misc{thingslid2026,
|
| 124 |
+
author = {ThingAI},
|
| 125 |
+
title = {ThingsLID: Multi-Task Byte-Level Text Classifier},
|
| 126 |
+
year = {2026},
|
| 127 |
+
url = {https://huggingface.co/ThingAI/ThingsLID}
|
| 128 |
+
}
|
| 129 |
+
```
|
| 130 |
+
|
| 131 |
+
## License
|
| 132 |
+
|
| 133 |
+
Apache 2.0
|
label_maps.json
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"lang_id": {
|
| 3 |
+
"abk": 0,
|
| 4 |
+
"ace": 1,
|
| 5 |
+
"ach": 2,
|
| 6 |
+
"ady": 3,
|
| 7 |
+
"afr": 4,
|
| 8 |
+
"aka": 5,
|
| 9 |
+
"akk": 6,
|
| 10 |
+
"alt": 7,
|
| 11 |
+
"amh": 8,
|
| 12 |
+
"ami": 9,
|
| 13 |
+
"ang": 10,
|
| 14 |
+
"anp": 11,
|
| 15 |
+
"arb": 12,
|
| 16 |
+
"arc": 13,
|
| 17 |
+
"arg": 14,
|
| 18 |
+
"arq": 15,
|
| 19 |
+
"ary": 16,
|
| 20 |
+
"arz": 17,
|
| 21 |
+
"asm": 18,
|
| 22 |
+
"ast": 19,
|
| 23 |
+
"atj": 20,
|
| 24 |
+
"ava": 21,
|
| 25 |
+
"avk": 22,
|
| 26 |
+
"awa": 23,
|
| 27 |
+
"aym": 24,
|
| 28 |
+
"azb": 25,
|
| 29 |
+
"azj": 26,
|
| 30 |
+
"bak": 27,
|
| 31 |
+
"bam": 28,
|
| 32 |
+
"ban": 29,
|
| 33 |
+
"bar": 30,
|
| 34 |
+
"bbc": 31,
|
| 35 |
+
"bel": 32,
|
| 36 |
+
"bem": 33,
|
| 37 |
+
"ben": 34,
|
| 38 |
+
"bho": 35,
|
| 39 |
+
"bik": 36,
|
| 40 |
+
"bis": 37,
|
| 41 |
+
"bjn": 38,
|
| 42 |
+
"blk": 39,
|
| 43 |
+
"bod": 40,
|
| 44 |
+
"bos": 41,
|
| 45 |
+
"bpy": 42,
|
| 46 |
+
"bre": 43,
|
| 47 |
+
"bug": 44,
|
| 48 |
+
"bul": 45,
|
| 49 |
+
"bxr": 46,
|
| 50 |
+
"bzj": 47,
|
| 51 |
+
"cat": 48,
|
| 52 |
+
"cbk": 49,
|
| 53 |
+
"cdo": 50,
|
| 54 |
+
"ceb": 51,
|
| 55 |
+
"ces": 52,
|
| 56 |
+
"che": 53,
|
| 57 |
+
"chr": 54,
|
| 58 |
+
"chu": 55,
|
| 59 |
+
"chv": 56,
|
| 60 |
+
"chy": 57,
|
| 61 |
+
"ckb": 58,
|
| 62 |
+
"cor": 59,
|
| 63 |
+
"cos": 60,
|
| 64 |
+
"crh": 61,
|
| 65 |
+
"csb": 62,
|
| 66 |
+
"cym": 63,
|
| 67 |
+
"dag": 64,
|
| 68 |
+
"dan": 65,
|
| 69 |
+
"dcr": 66,
|
| 70 |
+
"deu": 67,
|
| 71 |
+
"dga": 68,
|
| 72 |
+
"din": 69,
|
| 73 |
+
"dip": 70,
|
| 74 |
+
"diq": 71,
|
| 75 |
+
"div": 72,
|
| 76 |
+
"dsb": 73,
|
| 77 |
+
"dty": 74,
|
| 78 |
+
"dzo": 75,
|
| 79 |
+
"egx": 76,
|
| 80 |
+
"egy": 77,
|
| 81 |
+
"ell": 78,
|
| 82 |
+
"elx": 79,
|
| 83 |
+
"eml": 80,
|
| 84 |
+
"eng": 81,
|
| 85 |
+
"epo": 82,
|
| 86 |
+
"est": 83,
|
| 87 |
+
"ett": 84,
|
| 88 |
+
"eus": 85,
|
| 89 |
+
"ewe": 86,
|
| 90 |
+
"ext": 87,
|
| 91 |
+
"fao": 88,
|
| 92 |
+
"fas": 89,
|
| 93 |
+
"fat": 90,
|
| 94 |
+
"fij": 91,
|
| 95 |
+
"fil": 92,
|
| 96 |
+
"fin": 93,
|
| 97 |
+
"fon": 94,
|
| 98 |
+
"fra": 95,
|
| 99 |
+
"fro": 96,
|
| 100 |
+
"frp": 97,
|
| 101 |
+
"frr": 98,
|
| 102 |
+
"fry": 99,
|
| 103 |
+
"ful": 100,
|
| 104 |
+
"fur": 101,
|
| 105 |
+
"gag": 102,
|
| 106 |
+
"gan": 103,
|
| 107 |
+
"gaz": 104,
|
| 108 |
+
"gcr": 105,
|
| 109 |
+
"gez": 106,
|
| 110 |
+
"gla": 107,
|
| 111 |
+
"gle": 108,
|
| 112 |
+
"glg": 109,
|
| 113 |
+
"glk": 110,
|
| 114 |
+
"glv": 111,
|
| 115 |
+
"gom": 112,
|
| 116 |
+
"gor": 113,
|
| 117 |
+
"got": 114,
|
| 118 |
+
"gpe": 115,
|
| 119 |
+
"grc": 116,
|
| 120 |
+
"gsw": 117,
|
| 121 |
+
"guc": 118,
|
| 122 |
+
"gug": 119,
|
| 123 |
+
"guj": 120,
|
| 124 |
+
"gur": 121,
|
| 125 |
+
"guw": 122,
|
| 126 |
+
"hak": 123,
|
| 127 |
+
"hat": 124,
|
| 128 |
+
"hau": 125,
|
| 129 |
+
"haw": 126,
|
| 130 |
+
"hbo": 127,
|
| 131 |
+
"hbs": 128,
|
| 132 |
+
"heb": 129,
|
| 133 |
+
"hif": 130,
|
| 134 |
+
"hin": 131,
|
| 135 |
+
"hit": 132,
|
| 136 |
+
"hrv": 133,
|
| 137 |
+
"hsb": 134,
|
| 138 |
+
"hun": 135,
|
| 139 |
+
"hye": 136,
|
| 140 |
+
"hyw": 137,
|
| 141 |
+
"ibo": 138,
|
| 142 |
+
"ido": 139,
|
| 143 |
+
"iku": 140,
|
| 144 |
+
"ile": 141,
|
| 145 |
+
"ilo": 142,
|
| 146 |
+
"ina": 143,
|
| 147 |
+
"ind": 144,
|
| 148 |
+
"inh": 145,
|
| 149 |
+
"ipk": 146,
|
| 150 |
+
"isl": 147,
|
| 151 |
+
"ita": 148,
|
| 152 |
+
"jam": 149,
|
| 153 |
+
"jav": 150,
|
| 154 |
+
"jbo": 151,
|
| 155 |
+
"jpn": 152,
|
| 156 |
+
"kaa": 153,
|
| 157 |
+
"kab": 154,
|
| 158 |
+
"kal": 155,
|
| 159 |
+
"kan": 156,
|
| 160 |
+
"kas": 157,
|
| 161 |
+
"kat": 158,
|
| 162 |
+
"kaz": 159,
|
| 163 |
+
"kbd": 160,
|
| 164 |
+
"kbp": 161,
|
| 165 |
+
"kcg": 162,
|
| 166 |
+
"khk": 163,
|
| 167 |
+
"khm": 164,
|
| 168 |
+
"kik": 165,
|
| 169 |
+
"kin": 166,
|
| 170 |
+
"kir": 167,
|
| 171 |
+
"kmr": 168,
|
| 172 |
+
"koi": 169,
|
| 173 |
+
"kok": 170,
|
| 174 |
+
"kom": 171,
|
| 175 |
+
"kon": 172,
|
| 176 |
+
"kor": 173,
|
| 177 |
+
"kpe": 174,
|
| 178 |
+
"krc": 175,
|
| 179 |
+
"ksh": 176,
|
| 180 |
+
"lad": 177,
|
| 181 |
+
"lao": 178,
|
| 182 |
+
"lat": 179,
|
| 183 |
+
"latex": 180,
|
| 184 |
+
"lav": 181,
|
| 185 |
+
"lbe": 182,
|
| 186 |
+
"lez": 183,
|
| 187 |
+
"lfn": 184,
|
| 188 |
+
"lij": 185,
|
| 189 |
+
"lim": 186,
|
| 190 |
+
"lin": 187,
|
| 191 |
+
"lit": 188,
|
| 192 |
+
"lld": 189,
|
| 193 |
+
"lmo": 190,
|
| 194 |
+
"lrc": 191,
|
| 195 |
+
"ltg": 192,
|
| 196 |
+
"ltz": 193,
|
| 197 |
+
"lug": 194,
|
| 198 |
+
"luo": 195,
|
| 199 |
+
"lzh": 196,
|
| 200 |
+
"mad": 197,
|
| 201 |
+
"mai": 198,
|
| 202 |
+
"mal": 199,
|
| 203 |
+
"mar": 200,
|
| 204 |
+
"mdf": 201,
|
| 205 |
+
"mhr": 202,
|
| 206 |
+
"min": 203,
|
| 207 |
+
"mkc": 204,
|
| 208 |
+
"mkd": 205,
|
| 209 |
+
"mlg": 206,
|
| 210 |
+
"mlt": 207,
|
| 211 |
+
"mni": 208,
|
| 212 |
+
"mnw": 209,
|
| 213 |
+
"mri": 210,
|
| 214 |
+
"mrj": 211,
|
| 215 |
+
"msa": 212,
|
| 216 |
+
"mwl": 213,
|
| 217 |
+
"mya": 214,
|
| 218 |
+
"myv": 215,
|
| 219 |
+
"mzn": 216,
|
| 220 |
+
"nah": 217,
|
| 221 |
+
"nan": 218,
|
| 222 |
+
"nap": 219,
|
| 223 |
+
"nav": 220,
|
| 224 |
+
"nds": 221,
|
| 225 |
+
"nep": 222,
|
| 226 |
+
"new": 223,
|
| 227 |
+
"nia": 224,
|
| 228 |
+
"nld": 225,
|
| 229 |
+
"nno": 226,
|
| 230 |
+
"nor": 227,
|
| 231 |
+
"nov": 228,
|
| 232 |
+
"nqo": 229,
|
| 233 |
+
"nrf": 230,
|
| 234 |
+
"nso": 231,
|
| 235 |
+
"nya": 232,
|
| 236 |
+
"nyn": 233,
|
| 237 |
+
"oci": 234,
|
| 238 |
+
"olo": 235,
|
| 239 |
+
"orm": 236,
|
| 240 |
+
"ory": 237,
|
| 241 |
+
"oss": 238,
|
| 242 |
+
"pag": 239,
|
| 243 |
+
"pam": 240,
|
| 244 |
+
"pan": 241,
|
| 245 |
+
"pap": 242,
|
| 246 |
+
"pcd": 243,
|
| 247 |
+
"pcm": 244,
|
| 248 |
+
"pdc": 245,
|
| 249 |
+
"peo": 246,
|
| 250 |
+
"pfl": 247,
|
| 251 |
+
"pih": 248,
|
| 252 |
+
"pli": 249,
|
| 253 |
+
"pms": 250,
|
| 254 |
+
"pnb": 251,
|
| 255 |
+
"pnt": 252,
|
| 256 |
+
"pol": 253,
|
| 257 |
+
"por": 254,
|
| 258 |
+
"pus": 255,
|
| 259 |
+
"pwn": 256,
|
| 260 |
+
"quy": 257,
|
| 261 |
+
"rcf": 258,
|
| 262 |
+
"rmy": 259,
|
| 263 |
+
"roh": 260,
|
| 264 |
+
"ron": 261,
|
| 265 |
+
"rue": 262,
|
| 266 |
+
"run": 263,
|
| 267 |
+
"rup": 264,
|
| 268 |
+
"rus": 265,
|
| 269 |
+
"sah": 266,
|
| 270 |
+
"san": 267,
|
| 271 |
+
"sas": 268,
|
| 272 |
+
"sat": 269,
|
| 273 |
+
"scn": 270,
|
| 274 |
+
"sgs": 271,
|
| 275 |
+
"shi": 272,
|
| 276 |
+
"shn": 273,
|
| 277 |
+
"sin": 274,
|
| 278 |
+
"skr": 275,
|
| 279 |
+
"slk": 276,
|
| 280 |
+
"slv": 277,
|
| 281 |
+
"sme": 278,
|
| 282 |
+
"smn": 279,
|
| 283 |
+
"smo": 280,
|
| 284 |
+
"sna": 281,
|
| 285 |
+
"snd": 282,
|
| 286 |
+
"som": 283,
|
| 287 |
+
"sot": 284,
|
| 288 |
+
"spa": 285,
|
| 289 |
+
"sqi": 286,
|
| 290 |
+
"srd": 287,
|
| 291 |
+
"srn": 288,
|
| 292 |
+
"srp": 289,
|
| 293 |
+
"ssw": 290,
|
| 294 |
+
"stq": 291,
|
| 295 |
+
"sun": 292,
|
| 296 |
+
"sux": 293,
|
| 297 |
+
"swe": 294,
|
| 298 |
+
"swh": 295,
|
| 299 |
+
"szl": 296,
|
| 300 |
+
"szy": 297,
|
| 301 |
+
"tah": 298,
|
| 302 |
+
"tam": 299,
|
| 303 |
+
"tat": 300,
|
| 304 |
+
"tay": 301,
|
| 305 |
+
"tcy": 302,
|
| 306 |
+
"tel": 303,
|
| 307 |
+
"tet": 304,
|
| 308 |
+
"tgk": 305,
|
| 309 |
+
"tgl": 306,
|
| 310 |
+
"tha": 307,
|
| 311 |
+
"tir": 308,
|
| 312 |
+
"tly": 309,
|
| 313 |
+
"ton": 310,
|
| 314 |
+
"tpi": 311,
|
| 315 |
+
"trv": 312,
|
| 316 |
+
"tsn": 313,
|
| 317 |
+
"tso": 314,
|
| 318 |
+
"tuk": 315,
|
| 319 |
+
"tum": 316,
|
| 320 |
+
"tur": 317,
|
| 321 |
+
"txb": 318,
|
| 322 |
+
"tyv": 319,
|
| 323 |
+
"udm": 320,
|
| 324 |
+
"uig": 321,
|
| 325 |
+
"ukr": 322,
|
| 326 |
+
"urd": 323,
|
| 327 |
+
"uzb": 324,
|
| 328 |
+
"uzn": 325,
|
| 329 |
+
"vec": 326,
|
| 330 |
+
"ven": 327,
|
| 331 |
+
"vep": 328,
|
| 332 |
+
"vie": 329,
|
| 333 |
+
"vls": 330,
|
| 334 |
+
"vol": 331,
|
| 335 |
+
"vro": 332,
|
| 336 |
+
"war": 333,
|
| 337 |
+
"wln": 334,
|
| 338 |
+
"wol": 335,
|
| 339 |
+
"wuu": 336,
|
| 340 |
+
"xal": 337,
|
| 341 |
+
"xcl": 338,
|
| 342 |
+
"xho": 339,
|
| 343 |
+
"xmf": 340,
|
| 344 |
+
"xog": 341,
|
| 345 |
+
"xto": 342,
|
| 346 |
+
"ydd": 343,
|
| 347 |
+
"yor": 344,
|
| 348 |
+
"yue": 345,
|
| 349 |
+
"zea": 346,
|
| 350 |
+
"zgh": 347,
|
| 351 |
+
"zha": 348,
|
| 352 |
+
"zho": 349,
|
| 353 |
+
"zul": 350
|
| 354 |
+
},
|
| 355 |
+
"prog_lang": {
|
| 356 |
+
"11l": 0,
|
| 357 |
+
"Ada": 1,
|
| 358 |
+
"C": 2,
|
| 359 |
+
"C#": 3,
|
| 360 |
+
"C++": 4,
|
| 361 |
+
"D": 5,
|
| 362 |
+
"Factor": 6,
|
| 363 |
+
"FreeBASIC": 7,
|
| 364 |
+
"Go": 8,
|
| 365 |
+
"Haskell": 9,
|
| 366 |
+
"J": 10,
|
| 367 |
+
"Java": 11,
|
| 368 |
+
"Julia": 12,
|
| 369 |
+
"Kotlin": 13,
|
| 370 |
+
"Lua": 14,
|
| 371 |
+
"Nim": 15,
|
| 372 |
+
"Perl": 16,
|
| 373 |
+
"Phix": 17,
|
| 374 |
+
"PicoLisp": 18,
|
| 375 |
+
"Python": 19,
|
| 376 |
+
"REXX": 20,
|
| 377 |
+
"Racket": 21,
|
| 378 |
+
"Raku": 22,
|
| 379 |
+
"Ruby": 23,
|
| 380 |
+
"Rust": 24,
|
| 381 |
+
"Scala": 25,
|
| 382 |
+
"Sidef": 26,
|
| 383 |
+
"Tcl": 27,
|
| 384 |
+
"Wren": 28,
|
| 385 |
+
"zkl": 29
|
| 386 |
+
},
|
| 387 |
+
"spam": {
|
| 388 |
+
"ham": 0,
|
| 389 |
+
"spam": 1
|
| 390 |
+
},
|
| 391 |
+
"toxic": {
|
| 392 |
+
"non-toxic": 0,
|
| 393 |
+
"toxic": 1
|
| 394 |
+
}
|
| 395 |
+
}
|
model.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2f5b2455a714c855abb4cda333f3e12223bafefb6297610ce0a63a23daa6340b
|
| 3 |
+
size 14823241
|
model.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""ThingsLID model definition — standalone, no dependencies beyond PyTorch."""
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
import torch.nn as nn
|
| 5 |
+
import torch.nn.functional as F
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class TrigramHashEmbedding(nn.Module):
|
| 9 |
+
def __init__(self, n_buckets=8192, d_embed=64, prime=31):
|
| 10 |
+
super().__init__()
|
| 11 |
+
self.n_buckets, self.prime = n_buckets, prime
|
| 12 |
+
self.embed = nn.Embedding(n_buckets, d_embed)
|
| 13 |
+
def forward(self, x):
|
| 14 |
+
xp = F.pad(x.long(), (2, 0), value=0)
|
| 15 |
+
h = (xp[:, :-2] * self.prime * self.prime + xp[:, 1:-1] * self.prime + xp[:, 2:]) % self.n_buckets
|
| 16 |
+
return self.embed(h)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class RoPE(nn.Module):
|
| 20 |
+
def __init__(self, head_dim, max_len=1024, theta=10000.0):
|
| 21 |
+
super().__init__()
|
| 22 |
+
inv_freq = 1.0 / (theta ** (torch.arange(0, head_dim, 2).float() / head_dim))
|
| 23 |
+
self.register_buffer("inv_freq", inv_freq, persistent=False)
|
| 24 |
+
self._build(max_len)
|
| 25 |
+
def _build(self, seq_len):
|
| 26 |
+
t = torch.arange(seq_len, device=self.inv_freq.device).float()
|
| 27 |
+
freqs = torch.outer(t, self.inv_freq); emb = torch.cat([freqs, freqs], dim=-1)
|
| 28 |
+
self.register_buffer("cos", emb.cos()[None, None], persistent=False)
|
| 29 |
+
self.register_buffer("sin", emb.sin()[None, None], persistent=False); self._max = seq_len
|
| 30 |
+
@staticmethod
|
| 31 |
+
def _rotate(x):
|
| 32 |
+
x1, x2 = x.chunk(2, dim=-1); return torch.cat([-x2, x1], dim=-1)
|
| 33 |
+
def forward(self, q, k):
|
| 34 |
+
T = q.size(2)
|
| 35 |
+
if T > self._max: self._build(T)
|
| 36 |
+
c, s = self.cos[:,:,:T], self.sin[:,:,:T]
|
| 37 |
+
return q*c + self._rotate(q)*s, k*c + self._rotate(k)*s
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
class Attention(nn.Module):
|
| 41 |
+
def __init__(self, d_model, n_heads):
|
| 42 |
+
super().__init__()
|
| 43 |
+
self.n_heads, self.head_dim = n_heads, d_model // n_heads
|
| 44 |
+
self.qkv = nn.Linear(d_model, 3 * d_model); self.out = nn.Linear(d_model, d_model)
|
| 45 |
+
self.rope = RoPE(self.head_dim); self.norm = nn.LayerNorm(d_model)
|
| 46 |
+
def forward(self, x):
|
| 47 |
+
res = x; x = self.norm(x); B, T, C = x.shape
|
| 48 |
+
qkv = self.qkv(x).view(B, T, 3, self.n_heads, self.head_dim)
|
| 49 |
+
q, k, v = qkv.permute(2, 0, 3, 1, 4); q, k = self.rope(q, k)
|
| 50 |
+
out = F.scaled_dot_product_attention(q, k, v, is_causal=False)
|
| 51 |
+
return res + self.out(out.transpose(1, 2).contiguous().view(B, T, C))
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
class ConvBlock(nn.Module):
|
| 55 |
+
def __init__(self, d_in, d_out, kernel=3):
|
| 56 |
+
super().__init__()
|
| 57 |
+
self.conv = nn.Conv1d(d_in, d_out, kernel, padding=kernel // 2)
|
| 58 |
+
self.bn = nn.BatchNorm1d(d_out)
|
| 59 |
+
self.residual = nn.Conv1d(d_in, d_out, 1) if d_in != d_out else nn.Identity()
|
| 60 |
+
def forward(self, x): return F.gelu(self.bn(self.conv(x))) + self.residual(x)
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
class MultiTaskLID(nn.Module):
|
| 64 |
+
"""
|
| 65 |
+
ThingsLID: Multi-task byte-level text classifier.
|
| 66 |
+
~4M shared parameters + per-task classification heads.
|
| 67 |
+
"""
|
| 68 |
+
def __init__(self, task_configs, max_len=512, d_byte=64, d_tri=64,
|
| 69 |
+
n_buckets=8192, d_model=384, n_conv=4, n_attn=2, n_heads=6, dropout=0.0):
|
| 70 |
+
super().__init__()
|
| 71 |
+
self.max_len = max_len; self.d_model = d_model
|
| 72 |
+
self.byte_embed = nn.Embedding(256, d_byte)
|
| 73 |
+
self.tri_embed = TrigramHashEmbedding(n_buckets, d_tri)
|
| 74 |
+
self.proj = nn.Linear(d_byte + d_tri, d_model)
|
| 75 |
+
self.convs = nn.ModuleList([ConvBlock(d_model, d_model, 3) for _ in range(n_conv)])
|
| 76 |
+
self.attns = nn.ModuleList([Attention(d_model, n_heads) for _ in range(n_attn)])
|
| 77 |
+
self.drop = nn.Dropout(dropout); self.norm = nn.LayerNorm(d_model)
|
| 78 |
+
self.heads = nn.ModuleDict({t: nn.Linear(d_model, n) for t, n in task_configs.items()})
|
| 79 |
+
|
| 80 |
+
def forward(self, x, task):
|
| 81 |
+
h = self.proj(torch.cat([self.byte_embed(x), self.tri_embed(x)], dim=-1))
|
| 82 |
+
h = h.transpose(1, 2)
|
| 83 |
+
for conv in self.convs: h = conv(h)
|
| 84 |
+
h = h.transpose(1, 2)
|
| 85 |
+
for attn in self.attns: h = attn(h)
|
| 86 |
+
return {"logits": self.heads[task](self.drop(self.norm(h).mean(dim=1)))}
|
task_configs.json
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"lang_id": 351,
|
| 3 |
+
"prog_lang": 30,
|
| 4 |
+
"spam": 2,
|
| 5 |
+
"toxic": 2
|
| 6 |
+
}
|