Gantry decision model (English)
A fine-tuned decision model that turns a spoken or typed home command ("turn off the kitchen lights") into a device action. Instead of generating text, it answers a multiple-choice question (which action, which room, which door) with a calibrated probability for each option, in a single forward pass. So it can't produce a malformed command, and the hub can ask you to repeat when it isn't sure.
421M parameters (ModernBERT-large encoder, 395M, plus the Laya decision head). In Gantry it answers English requests; Korean requests go to the bilingual model, nohaah/laya-home-fine-tune-kr.
Part of Gantry, a fully offline voice assistant for the home that runs on a Raspberry Pi (source: github.com/noahhps/gantry).
Files
| File | What it is |
|---|---|
laya-home.int8.onnx |
int8 ONNX export: what Gantry runs (598 MB) |
model.safetensors |
PyTorch weights, fp16 (843 MB) |
rl_agent_config.json, encoder/config.json, tokenizer/ |
Model configuration and tokenizer |
questions.json |
The question format it was trained on |
train_report.json |
Training settings and held-out results before and after fine-tuning |
SHA256SUMS |
Checksums for every file |
Training
- Base model: convaiinnovations/laya, encoder answerdotai/ModernBERT-large (the "typed-decisions" checkpoint).
- Data: 4,000 synthetic English commands, generated by
training/generate_data.py: 5,751 training questions after splitting each command into its action, room and door questions. The data covers varied home layouts, follow-ups, and requests that aren't device commands. Published as nohaah/laya-home-fine-tune-en-training-set. - Settings: 1 epoch, effective batch 16 (8 Γ 2 gradient accumulation), learning rate 2.5e-5 (encoder) and 1e-4 (head), label smoothing 0.1, seed 42, Laya's
rlcdloss, on an Apple M1 Pro (MPS). - Calibration: temperature fitted on 400 held-out training items, so the probabilities can be used as confidence.
How to use
The model answers one multiple-choice question at a time and returns a calibrated probability for every option. It is loaded with the laya library from convaiinnovations/laya.
from huggingface_hub import snapshot_download
from laya.onnx_agent import ONNXAgent
snapshot_download("nohaah/laya-home-fine-tune-en", local_dir="gantry-laya-en")
agent = ONNXAgent("gantry-laya-en", onnx_path="gantry-laya-en/laya-home.int8.onnx")
answer = agent.predict(
'Latest request: "turn off the kitchen lights"',
{"action": {"type": "choice", "instructions": "Which action?",
"criteria": ["turn_on_lights", "turn_off_lights", "set_temperature", "raise_temperature",
"lower_temperature", "open_garage", "close_garage", "lock_door", "unlock_door", "none"]}},
)["answers"]["action"]
print(answer["choice"], answer["probabilities"])
The PyTorch weights (model.safetensors) load with laya.load("gantry-laya-en").
Input format
The input describes the request, and for follow-ups the earlier commands, exactly as Gantry's hub writes it:
Earlier requests, oldest first:
- "turn on the kitchen lights" -> turn_on_lights {"room":"kitchen"}
Latest request: "turn them off"
It was trained on three short questions with bare option ids:
| Question | Options |
|---|---|
Which action? |
turn_on_lights, turn_off_lights, set_temperature, raise_temperature, lower_temperature, open_garage, close_garage, lock_door, unlock_door, none |
Which room? |
all plus the home's rooms (English ids such as kitchen, living room) |
Which door? |
the home's doors (English ids such as front, back) |
In Gantry, services/laya_server.py serves this folder to the hub: python services/laya_server.py --checkpoint gantry-laya-en --onnx gantry-laya-en/laya-home.int8.onnx.
Evaluation
| Measure (held-out phrasings never seen in training) | Result |
|---|---|
| All questions (action, room, door), fp16, before β after fine-tuning | 87.8% β 97.9% correct (189 questions) |
| Calibration error (ECE), before β after | 0.184 β 0.081 |
| Action question, int8 ONNX as deployed | 95.2% correct (126 requests) |
| Speed, int8, Raspberry Pi 4, 4 threads | ~1.1 s per question |
| Speed, int8, Apple M1 Pro, 4 threads | ~68 ms per question |
Longer input
Single held-out requests with 0β3 unrelated earlier commands added in front, int8 ONNX, Apple M1 Pro, 4 threads:
| Language | Earlier commands in input | Tokens | Correct action | Time per question |
|---|---|---|---|---|
| English | 0 | 14 | 96.9% | 68 ms |
| English | 1 | 43 | 86.5% | 93 ms |
| English | 2 | 60 | 88.5% | 108 ms |
| English | 3 | 82 | 83.3% | 129 ms |
Limitations
- Synthetic data. Training and test requests are generated from templates (
training/generate_data.py), not recorded from people. Accuracy on real speech, through a speech-to-text model, will be lower. - A narrow job. It chooses among a smart home's actions, rooms and doors. It isn't a general language model and won't answer questions.
- Unrelated context hurts. Accuracy drops when unrelated earlier commands are included (see the table above), so Gantry only sends history for follow-ups.
- Not a safety mechanism on its own. Gantry requires 80% confidence for unlocking doors and opening the garage and asks again below that, and the panel asks for confirmation. Keep a check like that around any action with consequences.
License
Apache-2.0, the same license as the base model convaiinnovations/laya and its encoder answerdotai/ModernBERT-large. See LICENSE and NOTICE.
Model tree for nohaah/laya-home-fine-tune-en
Base model
convaiinnovations/laya