pulse-decide-150m / README.md
ashish296's picture
Make repo self-contained: add pulse_model.py + runnable usage example
46bfb9c verified
|
Raw History Blame Contribute Delete
6.27 kB
---
license: other
license_name: pulse-research-preview
tags:
- decision-model
- text-classification
- zero-shot-classification
- on-device
- non-generative
library_name: pytorch
---
# Pulse Decide 150M
**RouterML's on-device decision model.** 149.3M parameters (~570MB fp32). Non-generative:
it *scores* typed decisions rather than generating text, which is why it runs on a laptop
instead of a server.
> Makes typed decisions β€” choice, boolean, multi-label, ordinal β€” over **arbitrary runtime
> schemas**, offline, on-device.
**Status: `v0.1` research preview.** This is an early research model, not a production release.
![Pulse Decide β€” governed routing](pulse_beat.gif)
*One customer message, routed twice. Without governed context Pulse isn't confident enough,
so it escalates rather than guessing. With governed context it decides β€” 99.7% confident,
on-device, in ~32ms.*
## What it does
Given a piece of text (the *state*) and a set of candidate labels supplied **at runtime**,
Pulse scores each candidate and returns a decision plus a confidence. The label set does not
need to be seen during training β€” that is the "arbitrary schema" property.
## Key facts
| | |
|---|---|
| Parameters | **149.3M** (0.149B) |
| Encoder | `answerdotai/ModernBERT-base` |
| Architecture | cross-encoder decision scorer (non-generative) |
| Size on disk | ~570MB (fp32); ~150MB at int8 |
| Runs on | CPU / Apple MPS / CUDA β€” **offline, no data leaves the device** |
| Decision types | choice, boolean, multi-label, ordinal |
## Performance
Pulse is designed to run **behind a confidence gate** β€” answering what it is confident about
and escalating the rest. That selective mode is how it is intended to be deployed, so it is
what we report here. Measured on held-out, schema-disjoint evaluation sets (label sets never
seen in training) at confidence threshold 0.5:
| evaluation set | answering everything | confident subset only |
|---|---:|---|
| MASSIVE (intent, 60 labels) | 47.6% | **71.1%** at 47% coverage |
| macro (3 held-out sets) | ~51% | **59.5%** at 63% coverage |
Accuracy on *accepted* decisions is meaningfully higher than on forced answers β€” at the cost
of escalating the remainder. This is the intended operating mode.
> **A same-split benchmark evaluation against other published decision models is forthcoming.**
> We make no claim of matching or exceeding any other model at this time.
## Intended use
- Research on small, non-generative decision models and governed routing
- On-device / offline decisioning where data cannot leave the machine
- As the local tier of an escalation system (cheap local decision β†’ escalate when unsure)
## Limitations
- **Multi-label is weak** (~8% exact-set on FD multi-label heads). The model often identifies
the right labels but selects the wrong *number* of them. Active work.
- **Confidence calibration drifts between training runs**; treat thresholds as needing
per-deployment calibration rather than as universal constants.
- Not evaluated for fairness, safety, or high-stakes domains. **Do not use for consequential
decisions without your own evaluation.**
- English only.
- Early research preview β€” interfaces and weights may change.
## Training data and licensing ⚠️
Trained on a derived corpus assembled from **40 public text-classification datasets**
(contamination-audited against all evaluation sets; near-duplicate filtered).
**The source datasets carry mixed licenses**, including:
- ~24 permissive (Apache-2.0, CC-BY, MIT-like)
- several **research/non-commercial-only** datasets
- several derived from **Twitter/X content**, whose Terms of Service restrict redistribution
**We publish the model weights, not the training data.** Because the corpus mixes
research-only and ToS-restricted sources, **users are responsible for verifying that their
intended use complies with the underlying dataset licenses.** A cleanly-licensed
(permissive-only) release is planned.
## Usage
The repo is self-contained: `pulse_model.py` is the full model definition (113 lines, only
`torch` + `transformers` required).
```bash
pip install torch transformers
```
```python
import torch
from pulse_model import PulseConfig, PulseUnified, load_tokenizer
blob = torch.load("pulse_decide_150m.pt", map_location="cpu", weights_only=True)
cfg = PulseConfig(**blob["cfg"])
tok = load_tokenizer(cfg)
model = PulseUnified(cfg)
model.load_state_dict(blob["state_dict"])
model.eval()
def decide(state, question, choices, context=None):
"""Score every choice and return (label, confidence). Options are read at RUNTIME,
so label sets never seen in training still work."""
ctx = " | ".join(context) + " || " if context else ""
left = [f"{ctx}{state} [SEP] {question}"] * len(choices)
enc = tok(left, choices, truncation=True, max_length=cfg.max_length,
padding=True, return_tensors="pt")
with torch.no_grad():
scores = model.score_pairs(enc["input_ids"], enc["attention_mask"])
probs = torch.softmax(scores, dim=0)
i = int(probs.argmax())
return choices[i], float(probs[i])
label, confidence = decide(
state="We were invoiced twice this month and the NET-60 terms were not applied.",
question="Which team should handle this?",
choices=["sales", "support", "billing", "success", "compliance"],
context=["NET-60 payment terms", "prior billing dispute on file"],
)
print(label, f"{confidence:.1%}") # -> billing 99.7%
# Governance: act only when confident, otherwise escalate.
if confidence < 0.60:
print("escalate β€” not confident enough to act")
```
Download the two files you need:
```python
from huggingface_hub import hf_hub_download
repo = "RouterML/pulse-decide-150m"
ckpt = hf_hub_download(repo, "pulse_decide_150m.pt")
code = hf_hub_download(repo, "pulse_model.py")
```
## Model family
Pulse Decide is the decision model inside **RouterML**, which adds the governance layer β€”
eligibility, confidence gating, escalation and verification β€” around it.
## Citation
```bibtex
@software{pulse_decide_150m,
title = {Pulse Decide 150M: an on-device non-generative decision model},
author = {RouterML},
year = {2026},
note = {v0.1 research preview}
}
```