CoolFace
Modelpublic

blue-machines/Canine-S-sentence-intent-v1

sourceHugging Faceupdated 20d agoView on Hugging Face
0likes28downloads
Model Card

CANINE-S Sentence Intent v1

blue-machines/Canine-S-sentence-intent-v1 is a sentence-level intent classifier.

  • —Base model: google/canine-s (~133M)
  • —Task: 7-class utterance intent
  • —Runtime: TorchScript INT8 for fast CPU — ONNX Runtime is not supported for CANINE
  • —Input format: a single bare sentence / utterance (no dialogue tags like [assistant] / [user])
  • —Output: intent class label + confidence (softmax max probability)

Intent labels

idlabel
0provide_info
1affirm
2deny
3correction
4question
5clarify_request
6unclear

Files

FileRole
model.ptDeploy (fast CPU) — TorchScript dynamic INT8
model_int8.ptSame INT8 TorchScript (explicit name)
model_fp32.ptTorchScript FP32 reference
model.safetensorsOriginal PyTorch weights
cpu_bench.jsonLocal CPU latency numbers
label_map.jsonLabel id ↔ name map
tokenizer_config.jsonCANINE char tokenizer config
config.jsonTransformer config
Why not ONNX / ORT INT8? CANINE’s local-attention + molecule path still yields illegal MatMul shapes in ONNX Runtime. For very fast CPU use TorchScript INT8.

CPU latency (batch=1, pad to 192, 8 threads)

Runtimep50 latencyApprox QPS
TorchScript INT8 (model.pt)24.7 ms40.5
TorchScript FP32 (model_fp32.pt)40.3 ms24.8

INT8 is ~1.63× faster on CPU and ~2.3× smaller on disk (221 MB vs 508 MB).

Recommended confidence threshold

Optimal threshold (selected for performance + coverage): `0.55`

Serving rule:

text
probs = softmax(intent_logits)
pred  = argmax(probs)
conf  = max(probs)
if conf < 0.55:
    pred = unclear   # safe abstain

Selection rule: among thresholds with coverage ≥ 0.97, maximize selective accuracy (tie-break: lower false-intent rate). This keeps most examples committed while cutting false specific intents.

Test-set metrics (sentence-direct test)

VariantAccuracyMacro-F1False-intentCoverageSelective acc
FP32 raw (no gate)0.93790.93650.05471.00000.9379
Deploy raw (no gate)0.93790.93650.05471.00000.9379
Deploy @ thr=0.550.93290.93330.04100.97150.9528

Input / output contract

Input: pass one individual sentence (or a batch of independent sentences). Do not wrap with dialogue markers.

Valid examples:

  • —Haan, ye sahi hai. Proceed karo.
  • —What is the minimum balance required?
  • —Nahi, maine ye payment nahi kiya.
  • —Sorry I meant March not April.

Tensors

NameTypeShapeNotes
input_idsint64[batch, seq]pad/truncate to 192
attention_maskint64[batch, seq]1 = real, 0 = pad
logits / intent_logitsfloat[batch, 7]apply softmax for confidence

Inference snippet

python
import json
from pathlib import Path

import numpy as np
from transformers import AutoTokenizer, CanineTokenizer

MODEL_DIR = Path(".")  # or huggingface_hub.snapshot_download(...)
MAX_LEN = 192
CONF_THRESHOLD = 0.55  # optimal gate (coverage>=0.97, max selective acc)
UNCLEAR_ID = 6

# tokenizer — Character-level CANINE tokenizer (no WordPiece vocab).
tokenizer = CanineTokenizer.from_pretrained(MODEL_DIR)

with open(MODEL_DIR / "label_map.json", encoding="utf-8") as f:
    maps = json.load(f)
id2intent = {int(k): v for k, v in maps["head4_intent"]["id2label"].items()}

import torch

# Fast CPU path: INT8 TorchScript (model.pt == model_int8.pt)
session = torch.jit.load(str(MODEL_DIR / "model.pt"), map_location="cpu")
session.eval()
torch.set_num_threads(8)  # tune; too many threads can hurt

def predict_intent(sentence: str) -> dict:
    """Pass a single bare sentence; returns label + confidence."""
    enc = tokenizer(
        sentence,
        return_tensors="pt",
        truncation=True,
        max_length=MAX_LEN,
        padding="max_length",
    )
    with torch.inference_mode():
        logits = session(
            enc["input_ids"].to(torch.int64),
            enc["attention_mask"].to(torch.int64),
        )[0].cpu().numpy()

    x = logits.astype(np.float64)
    x = x - x.max()
    probs = np.exp(x)
    probs = probs / probs.sum()
    pred_id = int(probs.argmax())
    conf = float(probs.max())
    abstained = conf < CONF_THRESHOLD
    if abstained:
        pred_id = UNCLEAR_ID
    return {
        "text": sentence,
        "intent": id2intent[pred_id],
        "confidence": conf,
        "abstained": abstained,
        "threshold": CONF_THRESHOLD,
        "probs": {id2intent[i]: float(probs[i]) for i in range(7)},
    }

for s in [
    "Haan, ye sahi hai. Proceed karo.",
    "What is the minimum balance required?",
    "Nahi, maine ye payment nahi kiya.",
]:
    print(predict_intent(s))

Notes

  • —Intent-only model (no LID / LSD heads).
  • —Trained on sentence-direct data (Gemini synth + Muthoot user turns + noisy unclear), without [assistant]/[user] packing.