Downloads · 30 days
51
46% of all-time downloads
oddadmix/Nawah-RuleCheck-1M
Nawah-RuleCheck-1M is a text classification model from oddadmix. Use it when you need a label for a piece of text. It is set up for transformers. The card lists the license as apache-2.0.
A 1,073,504-parameter Arabic rule checker; weights file 4,298,088 bytes (4.30 MB). Give it a text and a rule written in ordinary Arabic and it answers مطابق (the text satisfies the rule) or مخالف (it does not).
Downloads · 30 days
51
46% of all-time downloads
All-time downloads
112
Public
Parameters
1.1M
4.3 MB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors4.3 MB · 51%
From the Hugging Face model README
A 1,073,504-parameter Arabic rule checker; weights file 4,298,088 bytes (4.30 MB). Give it a text and a rule written in ordinary Arabic and it answers مطابق (the text satisfies the rule) or مخالف (it does not).
بالعربية: نموذج عربي صغير (1,073,504 معامل) يأخذ نصًا وقاعدة مكتوبة بلغة طبيعية ويقرّر إن كان النص مطابقًا للقاعدة أم مخالفًا لها.
4 transformer layers, hidden size 32. It is a sequence classifier
(LlamaForSequenceClassification), not a generator — the answer is two-valued, so a classification
head fits better at this size and is directly scorable.
Where the parameters are. 49,504 of the 1,073,504 parameters are the transformer body; 1,024,000 (95.4%) are the 32,000 × 32 embedding table. Small Arabic models are mostly vocabulary — worth knowing before reading the results as reasoning capacity.
This model is one rung of a four-point ladder trained on identical data and scored by one harness
in one session (eval_all.py). Nothing below
is carried over from an earlier run or another card.
| model | params | weights | seen wording | unseen wording | minimal pairs | hand-written wording | CPU ms |
|---|---|---|---|---|---|---|---|
Nawah-RuleCheck-500K | 518,256 | 2.08 MB | 0.9866 | 0.9778 | 0.9926 | 0.5558 | 0.33 |
| this model | 1,073,504 | 4.30 MB | 0.9952 | 0.9864 | 0.9991 | 0.7708 | 0.55 |
Nawah-RuleCheck-5M | 5,080,704 | 20.33 MB | 0.9979 | 0.9949 | 0.9926 | 0.8642 | 1.06 |
Nawah-RuleCheck-v2 | 51,787,264 | 207.16 MB | 0.9980 | 0.9980 | 0.9991 | 0.8883 | 16.58 |
| majority baseline | — | — | 0.6401 | 0.6401 | 0.5000 | 0.5925 | — |
CPU ms = single example, batch 1, float32, 2 threads, median of 200 runs, same input for every model. On an RTX 5090 this model is 1.53 ms.
task_id split, zero text overlap
with training), rules phrased the way training phrased them. Text generalisation.rules_common.py. Any cue that merely correlates with the label
inside the corpus dies here.| rule | acc |
|---|---|
ends_question | 1.000 |
has_number | 1.000 |
no_email | 1.000 |
no_url | 1.000 |
no_latin | 0.998 |
has_date | 0.998 |
has_price | 0.998 |
no_phone | 0.996 |
has_phone | 0.994 |
has_city | 0.991 |
max_words_30 | 0.978 |
no_excess_punct | 0.930 |
min_words_15 | 0.929 |
max_words_25 | 0.900 |
min_words_20 | 0.886 |
max_words_50 | 0.884 |
min_words_25 | 0.875 |
max_words_40 | 0.826 |
min_words_30 | 0.821 |
| rule | acc |
|---|---|
no_url | 1.000 |
has_price | 1.000 |
no_excess_punct | 0.992 |
has_date | 0.950 |
no_email | 0.875 |
has_number | 0.858 |
no_latin | 0.667 |
ends_question | 0.592 |
no_phone | 0.533 |
has_phone | 0.242 |
Read the hand-written wording column, not the headline. Inside the paraphrase distribution the whole ladder is bunched between 0.9778 and 0.9980 — a 2.0-point spread across a 100x size range. On rule wordings written from scratch the same four models spread from 0.5558 to 0.8883, a 33.2-point gap, and the 500K rung falls below the 0.5925 majority-class baseline. Almost all of what size buys on this task is robustness to wording you did not train on. If your rules are a fixed catalogue you can phrase in the training register, the small rungs are close to free. If users will phrase rules in wording you do not control, size matters and no rung on this ladder is finished.
Trained on 19 rules decidable from the string itself. Rules needing world knowledge, judgement or multi-step inference are out of distribution. Texts are 1–3 line Arabic business documents (classified ads, support tickets, job posts, complaints, rental listings) across nine regions; longer or very different text is untested. Word-count rules are the weakest family — counting is the one operation here that cannot be pattern-matched.
import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer
M = "oddadmix/Nawah-RuleCheck-1M"
tok = AutoTokenizer.from_pretrained(M)
model = AutoModelForSequenceClassification.from_pretrained(M).eval()
def check(text, rule):
x = tok(f"النص: {text}\nالقاعدة: {rule}", return_tensors="pt", add_special_tokens=False)
with torch.no_grad():
p = model(**x).logits.softmax(-1)[0]
return model.config.id2label[int(p.argmax())], float(p.max())
check("للبيع سيارة نظيفة، للتواصل على الرقم 0551234567",
"يُمنع ظهور أي رقم هاتف (8-15 خانة) في النص")
Input format is النص: {text}\nالقاعدة: {rule} with add_special_tokens=False. Text first, rule
second: the head pools the last non-pad token, so under causal attention only the trailing rule
tokens can attend to the whole text.
Base oddadmix/Emhotob-1M-v2 — Llama,
4 layers, hidden 32, vocab 32,000, tied embeddings, 2048 context.
159,240 (text, rule) pairs, LR 1e-3, 10 epochs, cosine schedule,
500 warmup steps, effective batch 64, bf16, max_length 224. Best checkpoint
selected on unseen-wording macro-F1.
"Smaller models need a higher learning rate" is true here — but only below 5M. Each rung was swept independently on the same data and the same eval:
| rung | params | chosen LR | epochs | tuned? |
|---|---|---|---|---|
Nawah-RuleCheck-500K | 518,256 | 6e-3 | 15 | ✅ |
Nawah-RuleCheck-1M | 1,073,504 | 1e-3 | 10 | ✅ |
Nawah-RuleCheck-5M | 5,080,704 | 1e-4 | 10 | ✅ |
Nawah-RuleCheck-v2 | 51,787,264 | 1e-4 | 10 | ✅ |
The optimum climbs 60× between the 5M and the 500K (1e-4 → 6e-3), and getting it wrong is expensive: on the 500K base the big model's recipe scores 0.9179 unseen against 0.9780 tuned — six points that look like a capacity limit and are not.
Above 5M the effect simply stops. The 5M and the 51.8M want the same 1e-4, and pushing the 5M up toward the 500K's learning rate destroys it (3e-3 → 0.88, 6e-3 → 0.77 unseen). So neither recipe transfers in either direction: the tiny rungs need their own LR, and that LR must not be carried back up the ladder.
Same data, same eval splits, same everything — only LR and epoch budget move:
| LR | epochs | seen | unseen |
|---|---|---|---|
| 3e-4 | 3 | 0.9897 | 0.9518 |
| 1e-4 | 10 | 0.9929 | 0.9564 |
| 3e-4 | 10 | 0.9964 | 0.9849 |
| 1e-3 | 10 | 0.9952 | 0.9866 |
| 3e-3 | 10 | 0.9914 | 0.9707 |
| 6e-3 | 10 | 0.9902 | 0.9778 |
| 3e-4 | 15 | 0.9946 | 0.9697 |
| 1e-3 | 15 | 0.9944 | 0.9843 |
| 1e-3 | 20 | 0.9955 | 0.9814 |
1e-3 is a genuine interior optimum: unseen-wording accuracy falls off on both sides (1e-4 -> 0.9564, 3e-3 -> 0.9707). The 51.8M model's published recipe (3e-4, 3 epochs) scores 0.9518 on this base - 3.5 points of the apparent capacity gap at 1M is undertraining, not size. Longer budgets at 1e-3 do not help: 15 and 20 epochs both regress on unseen wording while seen accuracy keeps climbing, which is memorisation of training phrasings.
Labels are computed, not model-judged. Each rule is a deterministic predicate over the raw
string (rules_common.py, shipped here), so ground truth is exact by construction. That also makes
paraphrasing free supervision: rewording a rule cannot change its verdict.
oddadmix/Nawah-RuleCheck-500K — 518,256 paramsoddadmix/Nawah-RuleCheck-1M — 1,073,504 paramsoddadmix/Nawah-RuleCheck-5M — 5,080,704 paramsoddadmix/Nawah-RuleCheck-v2 — 51,787,264 paramspython eval_all.py oddadmix/Nawah-RuleCheck-500K oddadmix/Nawah-RuleCheck-1M \
oddadmix/Nawah-RuleCheck-5M oddadmix/Nawah-RuleCheck-v2
eval_all.py is in this repo, along with the frozen case sets it scores against
(cf_cases.json, ood_cases.json) so the minimal pairs and the hand-written wordings are
byte-identical for every rung and every re-run. Also here: prepare_rules_cls.py,
train_rules_cls.py, gen_rule_paraphrases.py, counterfactual_eval.py, rules_common.py
(which defines the labels), and the 631 rule paraphrases in rule_paraphrases.json.