Naluri-279M-encoder (XLM-R base, M6-pairs)

Formerly naluri-xlmr-base. The old name redirects here.

Model Backbone Parameters System One Bench Latency (GPU, p50)
Naluri-279M-encoder (this model) XLM-RoBERTa base 278.6M 50.4 (main, M6-pairs); 58.0 (m9 branch) ~5 ms
Naluri-308M-encoder mmBERT-base 307.5M 61.0 ~9 ms
Naluri-561M-encoder XLM-RoBERTa large 560.9M 64.9 ~14 ms

Instinctive, multilingual decisions in one pass.

Naluri (Indonesian for instinct; Neural Answering via Label Understanding and Rapid Inference) is a small System One decision model: 278.6M parameters, built on XLM-RoBERTa base. You give it a text or JSON state and a typed question with its options written out. It returns calibrated probabilities over those options in a single forward pass, taking about 5 ms per question on a laptop GPU and about 50–60 ms on a CPU. It never generates text.

It supports the same three question types as TypeSafe Jev and Laya:

Type Options Returns
noul yes / no (optional descriptions) p(true)
choice 2+ named options (optional descriptions) one probability per option
score ordered levels one probability per level; expected level = score

Code, training pipeline and full report: github.com/jerichosiahaya/naluri.

Versions:

Revision Model Notes
main M6-pairs recommended
m9 (branch) M9 System One Bench 58.0 vs 50.4 for main: trained on named-field states and yes/no reading questions. Not yet checked for state-reading (empty-state agreement), which is why main is unchanged
m7 (branch) M7 experimental: higher typed-decisions score (48.6%), but partly from shifted default answers
m5, m4 (tags) M5, M4 earlier releases

Load with the bundled naluri.py (see Usage). The standard transformers pipeline and the hosted inference widget can't run Naluri: its decision head is custom code.

Usage

pip install torch transformers safetensors huggingface_hub
from huggingface_hub import hf_hub_download
import importlib.util

# naluri.py (input format + model + loader) ships with this repo
spec = importlib.util.spec_from_file_location("naluri", hf_hub_download("jerichosiahaya/Naluri-279M-encoder", "naluri.py"))
naluri = importlib.util.module_from_spec(spec); spec.loader.exec_module(naluri)

tok, model = naluri.from_pretrained("jerichosiahaya/Naluri-279M-encoder", device="cpu")   # or device="cuda"

state = {"order": {"id": "A-1029", "status": "delayed", "days_late": 6},
         "customer": {"tier": "VIP"}, "note": "Asked twice already, threatening to cancel."}
questions = {
    "action": {"type": "choice", "instructions": "What should support do next?",
               "criteria": {"apologize": "send an apology only", "discount": "offer a discount voucher",
                            "escalate": "escalate to a supervisor now", "wait": "wait for the courier update"}},
    "churn_risk": {"type": "noul", "instructions": "Is this customer likely to leave?"},
    "mood": {"type": "score", "instructions": "How upset is the customer?", "criteria": ["calm", "annoyed", "angry"]},
}
print(naluri.predict(tok, model, state, questions, device="cpu"))
# {'action': {'apologize': ..., 'escalate': ...}, 'churn_risk': {'false': ..., 'true': ...}, 'mood': {0: ..., 1: ..., 2: ...}}

# a specific version, e.g. the experimental M7 branch:
from huggingface_hub import snapshot_download
tok, model = naluri.load(snapshot_download("jerichosiahaya/Naluri-279M-encoder", revision="m7"), device="cpu")
  • Option descriptions matter. Naluri reads them, so clear, distinct descriptions give better answers.
  • Limits: keep each question under about 20 options, and the question plus options under about 192 tokens. Inputs are capped at 512 tokens in total.
  • Uncertainty is meaningful: probabilities near 0.5 (or several options close together) are the cases to send to a human or an LLM.

Results

These numbers are for this checkpoint (M6-pairs, single seed). All models answered identical questions: Laya-multilingual was run zero-shot, and Jev was called live through its API. Unseen languages and unseen tasks are marked. More details are in the report.

Eval Naluri (this model) Laya-multilingual (zero-shot) Jev 1.13.0 (live)
SIB-200 topic, 12 languages (trained on other topic datasets) 73.2% 70.8% –
XCOPA cause/effect, 11 languages (unseen task) 57.2% 54.7% –
Belebele reading, 12 languages 36.2% 33.1% –
Sentiment, new domain + languages 61.1% 52.7% –
Intent (MASSIVE), 5 unseen languages 75.8% 37.6% –
XNLI, 5 unseen languages 58.1% 46.1% –
Review stars, 1–5 exact (MAE) 55.7% (0.58) 29.0% (1.45) –
AG News topic 74.1% 92.0% 88.0%
typed-decisions, zero-shot (2,000 business decisions) 46.9% 35.2% 73.8%
Calibration error on AG News (lower is better) 0.038 0.052 0.080
Latency per question ~5 ms (RTX 5050 laptop), ~55 ms (CPU) ~10–19 ms (same GPU) ~307 ms per case (API)
  • Fine-tuning closes the gap on specific tasks. With the same recipe, an earlier Naluri checkpoint fine-tuned for 17 minutes on typed-decisions' train split reached 72.5% vs Jev's 73.8%, a statistical tie (p = 0.29). That fine-tuned checkpoint is not this one.
  • Zero-shot on structured business decisions (typed-decisions) is the main weakness. Jev is far ahead there.
  • Why this checkpoint: minimal-pair training made the model genuinely use the state. On typed-decisions choice questions, its answer matches its empty-state answer 52% of the time, down from 93% for M5. A later run (M7) scored 48.6% but partly by shifting its default answer, so it was not released. Details are in the report.

Training

  • Input format (the same layout as Laya): <s> {type} question: {instructions} </s> <mask> option 1 <mask> option 2 … </s> {state} </s>. Each option is scored from the encoder vector at its own <mask> by a small MLP head, and a softmax over a question's options gives the answer distribution.
  • Objective: cross-entropy against one-hot labels or a teacher's soft probabilities, followed by one calibration temperature per question type.
  • Recipe:
    • M4: continue from M2 for 2 epochs, with task-balanced sampling (p ∝ √size), 3× weight on synthetic decisions, and public topic data
    • M5: continue from M4 for 2 epochs (learning rate 1e-5 for the encoder, 1e-4 for the head), adding 10k operational decisions with 2× synthetic weight
    • M6-pairs (this checkpoint): continue from M5 for 2 epochs, adding 5.2k contrastive minimal-pair decisions (weighted 3×): one question set, 3–4 near-identical states whose correct answers differ, so the model must read the state
    • the epoch is selected on the mean of per-task dev accuracies (SIB-200 and XCOPA validation splits + both synthetic dev sets)
    • about 50 minutes per stage on an 8 GB RTX 5050 laptop GPU
  • Augmentation: options shuffled, labels renamed, instructions paraphrased, varying option counts, and noul, choice and score mixed.
  • Weights: stored in fp16 (the encoder) and loaded in fp32. The largest probability difference against the fp32 training checkpoint was 0.0005.

Training data

About 107k typed questions. The licenses below are as listed on each dataset's card; check them yourself before any use.

Dataset Use License (per dataset card)
XNLI entailment (noul / choice) CC BY-NC 4.0
MASSIVE (mteb/amazon_massive_intent) intent (choice / noul) CC BY 4.0 (original) / Apache 2.0 (mirror)
Amazon Reviews Multi (mirror) review stars (score) + polarity Amazon's own terms (non-commercial)
TextDetox multilingual toxicity toxicity OpenRAIL++
papluca/language-identification language ID derived from Amazon Reviews, XNLI and STSb
dair-ai/emotion emotion other
RACE reading comprehension non-commercial research
UCI SMS Spam spam unknown on the Hub
MasakhaNEWS, Yahoo Answers Topics, DBpedia-14 topic classification see each dataset card
Synthetic decisions (5k) business decisions in 17 languages and 45 domains written by DeepSeek V4 Flash, labeled with probabilities by DeepSeek V4 Pro
Synthetic ops decisions (10k) run and event logs in 30 operational domains (next action, outcome, risk, review) written by DeepSeek V4 Flash, labeled with probabilities by DeepSeek V4 Pro
Synthetic minimal pairs (5.2k) groups of near-identical states whose answers differ written by DeepSeek V4 Flash, labeled with probabilities by DeepSeek V4 Pro

The SIB-200 and XCOPA validation splits were used only to pick the epoch. No test split of any eval set was trained on.

License

These weights are released under CC BY-NC 4.0 (non-commercial), because several training datasets restrict commercial use. The code on GitHub is Apache 2.0. For commercial use, retrain on data you are licensed to use; the pipeline is in the GitHub repo.

Limitations

  • Zero-shot on structured business decisions is weak: 46.9% on typed-decisions vs Jev's 73.8%. Choice questions like "which action should be taken?" are the weakest part (37%), and on some of them the model still leans on how the options are worded. Fine-tune for such tasks.
  • Yes/no questions about structured JSON react only weakly to the data. For example, "should this transfer be held for fraud review?" got 0.09 for a Rp 45M transfer from a 2-day-old account on a new device vs 0.07 for a normal one: right direction, far too small a gap. Yes/no on text works well (an Indonesian cancellation threat 0.91 vs a thank-you message 0.02).
  • English topic classification (AG News) trails Laya and Jev.
  • Low-resource languages such as Yoruba are weaker.
  • Inputs: a 512-token limit, and up to about 20 options per question.
  • Seeds: this is a single run. For M4, two seeds agreed within about 1 point.

Acknowledgements

Built on XLM-RoBERTa. The input format and fine-tuning recipe follow Laya. Inspired by Contrastive Language Models and TypeSafe's Jev.

Downloads last month
113
Safetensors
Model size
0.3B params
Tensor type
F16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for jerichosiahaya/Naluri-279M-encoder

Quantized
(46)
this model

Space using jerichosiahaya/Naluri-279M-encoder 1

Collection including jerichosiahaya/Naluri-279M-encoder