Downloads · 30 days
0
sakasegawa/modernbert-ja-70m-aizuchi
modernbert-ja-70m-aizuchi is a text classification model from sakasegawa. Use it when you need a label for a piece of text. It is set up for onnx. The card lists the license as mit.
A small Japanese classifier that decides which kind of backchannel (相槌, aizuchi) a listener should give first to what the user is saying, from the assistant's previous utterance and the user's (possibly unfinished) sp…
Downloads · 30 days
0
Access
Public
Updated Oct 12, 2026
Repo size
351 MB
Likes
3
Public
Click a slice to open those files.
.onnx351 MB · 98%
From the Hugging Face model README
A small Japanese classifier that decides which kind of backchannel (相槌, aizuchi) a listener should give first to what the user is saying, from the assistant's previous utterance and the user's (possibly unfinished) speech-recognition transcript. It also predicts whether the user has finished the sentence.
It is meant for voice assistants and spoken-dialogue systems that want to react within a few hundred milliseconds, before the main answer is ready: a quick 「うん」 to a reply, 「ちょっと見てみますね」 to a search request, 「え、そうなんですか」 to surprising news, or a small 「うん」 while the user is still in the middle of a sentence.
The classes are cut by the sound the listener makes first, not by what the user did. Two user acts that call for the same sound share a class.
| class | What the user did | A typical first response |
|---|---|---|
none | Greeting, thanks, goodbye, a meaningless fragment, talking to oneself | Nothing; go straight to the answer |
flow | A short reaction to the listener's question, proposal or remark | うん / はい |
ack | An instruction that needs no lookup | あ、はい / 了解です |
work | A request that needs a search, a fetch or an investigation | ちょっと見てみますね |
think | An open question asking for an explanation or a judgement | うーん / そうですね |
check | A check of a fact or a state, with a short answer | えっと / あー、はい |
understand | A neutral report or a piece of information | なるほど / そっか |
agree | An opinion or an evaluation | 確かに / ですよね |
empathy | A trouble, tiredness or complaint | あー / そっかぁ |
cheer | Good news or an achievement | おー / いいですね |
surprise | Unexpected information, good or bad | え、そうなんですか |
correct | A correction of the listener's mistake | あ、失礼しました |
hold | The user has not finished; more is coming | A small うん, and wait longer before taking the turn |
Input. The assistant's previous utterance (prev, optional) and the user's transcript (text), encoded as a sentence pair <s> prev </s><s> text </s>, or as text alone when there is no previous utterance. At most 64 tokens; when the input is longer, truncate prev, not text.
Before encoding, normalize both strings the way the training data was normalized: NFKC, then remove whitespace and the characters 、。,.??!!…・「」『』()(). Speech recognizers add punctuation inconsistently, and the synthetic data carried punctuation unevenly between classes (check had many 「?」), so the model is trained without it.
Output.
| name | shape | meaning |
|---|---|---|
cls_logits | [batch, 13] | Logits over the classes in the order of labels.json. Apply softmax. |
complete_logit | [batch] | Logit that the user has finished the sentence rather than left it hanging. Apply sigmoid. |
The probabilities are not calibrated. Pick thresholds from the distribution you see in your own application; ASIST plays nothing when the top probability is low, because a wrong backchannel is worse than silence.
import json, re, unicodedata
import numpy as np
import onnxruntime as ort
from huggingface_hub import hf_hub_download
from tokenizers import Tokenizer
repo = "sakasegawa/modernbert-ja-70m-aizuchi"
session = ort.InferenceSession(hf_hub_download(repo, "aizuchi.int8.onnx"))
tokenizer = Tokenizer.from_file(hf_hub_download(repo, "tokenizer.json"))
tokenizer.enable_truncation(64, strategy="only_first")
classes = json.load(open(hf_hub_download(repo, "labels.json")))["classes"]
PUNCT = re.compile(r"[\s、。,.??!!…・「」『』()()]")
def normalize(s: str) -> str:
return PUNCT.sub("", unicodedata.normalize("NFKC", s))
def classify(text: str, prev: str | None = None):
text = normalize(text)
encoding = tokenizer.encode(normalize(prev), text) if prev else tokenizer.encode(text)
feed = {
"input_ids": np.array([encoding.ids], dtype=np.int64),
"attention_mask": np.array([encoding.attention_mask], dtype=np.int64),
}
cls_logits, complete_logit = session.run(None, feed)
p = np.exp(cls_logits[0] - cls_logits[0].max())
p /= p.sum()
return classes[int(p.argmax())], float(p.max()), float(1 / (1 + np.exp(-complete_logit[0])))
print(classify("今日の予定を確認して"))
print(classify("それじゃなくてもう一つのほう", prev="会議を10時に入れました。"))
print(classify("あのさ、さっきの話なんだけど"))
In a live system, classify each partial transcript as it arrives and keep only the newest request; one sentence takes under 2 ms on a CPU.
Batches work as well. The fp32 model gives the same probabilities in a padded batch as one sentence at a time. The int8 model quantizes activations per run, so its probabilities move by up to about 0.02 depending on what else is in the batch; the predicted class did not change on the 400 sentences we compared.
The training data is synthetic. For each of 20 situations a voice assistant meets (calendar, mail, weather, coding, small talk, health, travel and so on), Claude (claude-fable-5-1 and claude-opus-5-5) wrote about 40 utterances per class in the style of speech-recognition output: few punctuation marks, dropped particles, fillers, restarts, half polite and half casual. About a fifth of each class were written as boundary cases that look like a neighbouring class. No real conversation logs were used. After removing duplicates that differ only in punctuation, 9,045 rows remain.
| class | rows | class | rows |
|---|---|---|---|
| none | 436 | agree | 764 |
| flow | 394 | empathy | 729 |
| ack | 672 | cheer | 738 |
| work | 780 | surprise | 748 |
| think | 711 | correct | 769 |
| check | 765 | hold | 754 |
| understand | 785 |
none and flow are smaller because their short set phrases repeat across situations and were removed as duplicates.
The data is published as sakasegawa/aizuchi-synthetic-ja under its own terms of use.
The training data was written with Claude Code under a Claude Max plan, so Anthropic's Consumer Terms apply (Claude Code legal and compliance). They forbid using the services to develop products or services that compete with Anthropic's, including training AI models, and the Usage Policy forbids training models on outputs without authorization in the sense of model scraping and distillation.
Anthropic's help article Can I use my Outputs to train an AI model? (updated 2026-03-16) explains where that line is. It allows training models that do not compete with Anthropic's own models and names specialized classifiers, among them content categorization, as examples. It forbids general-purpose chatbots, models for open-ended text generation, using outputs as training targets, and supporting a third party who tries to do those things.
This model is a 70M-parameter encoder that sorts an utterance into 13 classes and returns two probabilities. It generates no text and cannot answer a question, so it falls under the specialized classifiers the help article allows. This is the author's reading of Anthropic's terms as of 2026-10-12, not legal advice.
The encoder's <s> vector feeds two linear heads, one for the class and one for completeness, trained together. Two augmentations:
prev is dropped with probability 0.3, so that the model also works without the previous utterance.work.The released model was trained on all 20 situations for 4 epochs. The training code is at nyosegawa/modernbert-ja-70m-aizuchi.
All numbers are on synthetic data; there is no evaluation on real conversations yet.
| run | validation set | macro-F1, full sentences | cut at 75% | cut at 50% | completeness AUC |
|---|---|---|---|---|---|
| held-out situations | 3 situations never seen in training (hobby, travel, shopping), 1,382 rows | 0.910 | 0.80 | 0.72 | 0.93 (full and cut sentences together) |
| released model | random 5%, 452 rows | 0.863 | 0.74 | 0.63 | 0.99 (full sentences) |
The released model scores lower because its random validation set includes harder situations such as small talk and coding. Most remaining errors are between cheer and surprise, empathy and surprise, and check and understand, where people also disagree, and some synthetic rows carry debatable labels themselves.
MIT, the same as the base model.