shion-v4.2-small
日本語 IME 向けのかな漢字変換モデル(ONNX)。encoder-only の CTC 非自己回帰 (NAT) モデルで、読み(ひらがな列)と左文脈を入力に、1 回の forward で漢字かな交じり文を出力します。AR モデルと違い逐次生成がないため、CPU でリアルタイム IME に組み込める速度(int8 / beam16 / 辞書融合込みで実測 p50 ≈ 13ms)が特徴です。
English TL;DR: A 30M-parameter encoder-only CTC (non-autoregressive) kana-to-kanji conversion model for Japanese IMEs. Single forward pass, int8 ONNX, ~13ms p50 on desktop CPU including beam search. Feed [CLS] context [SEP] reading, CTC-collapse the argmax (blank id = 4), decode with the bundled vocab.
llama.cpp / karukan 互換性
この artifact は ONNX 形式の CTC-NAT モデルです。llama.cpp / GGUF 向けの GPT-2/CausalLM ではないため、karukan-im の model = "...gguf" にそのまま指定して使うことはできません。karukan で使うには、karukan 側にこの CTC-NAT ONNX 推論・CTC prefix beam search・vocab decoder を実装するか、本モデルを使う IME/daemon 側を ONNX Runtime で接続してください。
Files
| file | 内容 |
|---|---|
shion-v4.2-small-step140k.int8.onnx |
int8 動的量子化(27MB、配備用) |
shion-v4.2-small-step140k.fp32.onnx + .data |
fp32(107MB、検証・再量子化用) |
shion-v4.2-small-step140k.fp32.tokenizer.json.vocab.hex.tsv |
vocab(id → token の hex 表現) |
Model
- アーキテクチャ: Transformer encoder ×6 層、hidden 384 / heads 6 / FFN 1536、max_positions 128
- 出力: 文字単位 CTC、vocab 4801(特殊 token 含む)
- 文脈条件付け: 左文脈(確定済みテキスト)を入力に連結。学習時の文脈は最大 ~64 字
- 学習: in-house の大規模日本語 Web/書籍系コーパス(読み付与は自動)
I/O 仕様
input: input_ids int64 (batch, seq) seq ≤ 128
input: attention_mask int64 (batch, seq) 1 = 有効
output: logits float (batch, seq, 4801)
入力レイアウト: [CLS] <context(左 trim)> [SEP] <reading>
- reading(読み)を最優先で確保し、残り枠に context を右端から詰める
- 特殊 token id:
[PAD]=0 [UNK]=1 [SEP]=2 [CLS]=3 [BLANK]=4 [MASK]=5
デコード手順(最小)
- logits を position ごとに argmax
- CTC collapse: 連続する同一 id を 1 つに圧縮 → blank(=4)を除去
- 残った id 列から特殊 token(id 0–5)を落とし、vocab で文字列化
精度を上げる場合は CTC prefix beam search(width 8–20)+ 辞書・n-gram 融合を推奨(下記 Eval の数値は beam + 辞書融合込み)。
vocab の読み方
TSV の各行は id \t hex 形式。hex は token 文字列の UTF-8 バイト列の 16 進表現です(PUA・不可視文字を安全に扱うため)。<0xXX> という形の token は byte-fallback(OOV 文字を UTF-8 バイト単位で表現)で、デコード時はバイトとして連結してから UTF-8 復号してください。
Python 最小例
import numpy as np
import onnxruntime as ort
vocab = {}
with open("shion-v4.2-small-step140k.fp32.tokenizer.json.vocab.hex.tsv", encoding="utf-8") as f:
for line in f:
i, hx = line.rstrip("\n").split("\t")
vocab[int(i)] = bytes.fromhex(hx).decode("utf-8")
tok2id = {t: i for i, t in vocab.items()}
def encode(text): # 1 文字 1 token、OOV は byte fallback
ids = []
for ch in text:
if ch in tok2id:
ids.append(tok2id[ch])
else:
ids.extend(tok2id[f"<0x{b:02X}>"] for b in ch.encode("utf-8"))
return ids
reading, context = "きょうはいいてんきですね", "おはよう。"
ids = [3, *encode(context), 2, *encode(reading)] # [CLS] ctx [SEP] reading
x = np.array([ids], dtype=np.int64)
mask = np.ones_like(x)
sess = ort.InferenceSession("shion-v4.2-small-step140k.int8.onnx")
logits = sess.run(None, {"input_ids": x, "attention_mask": mask})[0][0]
out, prev = [], -1
for i in logits.argmax(-1): # greedy CTC collapse
if i != prev and i > 5:
out.append(vocab[int(i)])
prev = i
print("".join(out)) # → 今日はいい天気ですね
Eval(AJIMEE-Bench JWTD, n=200, 文脈付き)
| 構成 | EM@1 | EM@5 | p50 |
|---|---|---|---|
| int8 + beam16 + 辞書融合(配備構成) | 0.645 | 0.795 | 13.3ms |
| int8 + beam100 + 辞書融合 | 0.650 | — | ~340ms |
| int8 + beam100(モデル単体) | 0.630 | — | ~200ms |
p50 はデスクトップ CPU・Rust エンジン実測(モデル forward + beam + 辞書融合込み)。参考: AR 系の zenz-v3.2-small(GGUF 配備版)は同ベンチ EM@1 0.78。本モデルは精度では下回りますが、単発 forward の NAT として桁違いに低いレイテンシで動作します。
Known issues
- まれに OOV 記号類に対して
〓(geta)や代替記号を出力することがあります(学習データ由来。NFKC 等の後段正規化を推奨) - 英字・記号混じり入力(例: 読みから ASCII への変換)は弱い領域です
- max_positions 128 を超える長文は読み優先で文脈が切り捨てられます
License
Apache-2.0