そらまる くずし字認識モデル (convnext_v4)
ブラウザ完結のくずし字(一文字)認識を目的とした ConvNeXt-tiny ベースの ONNX モデル。 みんなで翻刻 のマスコット「そらまる」がアシスタント役を務めるデモサイトで使用されています。
- 🎮 デモ / フロント実装: https://github.com/yuta1984/soramaru_kuzushiji_ai
- 🔗 モデル本体:
convnext_v4.onnx(約 117 MB)
モデル概要
| 項目 | 値 |
|---|---|
| アーキテクチャ | ConvNeXt-tiny (timm/convnext_tiny.fb_in22k_ft_in1k を fine-tune) |
| 入力 | 384 × 384 RGB |
| 出力 | 3,673 クラスへの logits |
| 形式 | ONNX (opset 17) |
| ランタイム | ONNX Runtime Web / Python onnxruntime |
学習データ
- Kaggle Kuzushiji Recognition コンペティションデータセット
- 東京大学史料編纂所くずし字データセット
ページ画像から各 bounding box を切り出し、一文字単位の分類タスクとして再構成しています。
| 区分 | 件数 |
|---|---|
| 学習サンプル | 887,133 |
| 検証サンプル | 68,481 |
| 出力クラス数 | 3,673 |
学習設定
- 事前学習: ImageNet-22k → ImageNet-1k (timm 提供のチェックポイント)
- Fine-tune: 2 段階(低解像度で大まかに学習 → 384px で仕上げ)
- 損失: Cross-Entropy
- サンプラー:
WeightedRandomSamplerで各クラスの 1 epoch あたりの期待出現回数を平準化 - クラス除外: 出現件数が 3 件未満のクラスは学習対象から除外(cutoff=3)
性能評価
検証セット val_kr(Kaggle Kuzushiji Recognition の hold-out 68,481 件、3,673 クラス出力空間で argmax):
| 指標 | top-1 | top-5 | top-20 |
|---|---|---|---|
| micro 平均 | 96.5% | 99.5% | 99.6% |
| macro 平均(val に出現する 1,268 クラス) | 96.9% | 99.4% | 99.5% |
val_kr + val_extra を併せた 3,673 全クラスでの評価(極稀少クラスを含む厳しめの条件):
| 指標 | top-1 | top-5 | top-20 |
|---|---|---|---|
| micro | 95.3% | 99.0% | 99.4% |
| macro(出現 3,673 クラス) | 71.9% | 91.3% | 95.7% |
訓練サンプル数別の per-class recall(macro 平均)
| 訓練サンプル数 | クラス数 | 検証件数 | top-1 | top-5 | top-20 |
|---|---|---|---|---|---|
| 3 〜 10 | 1,690 | 1,690 | 52.5% | 85.2% | 93.5% |
| 10 〜 30 | 431 | 431 | 66.6% | 90.0% | 93.7% |
| 30 〜 100 | 622 | 2,168 | 92.5% | 97.9% | 98.4% |
| 100 〜 500 | 632 | 7,890 | 96.1% | 98.4% | 98.6% |
| 500 〜 2,000 | 213 | 11,096 | 95.7% | 98.9% | 99.1% |
| 2,000 以上 | 85 | 47,611 | 95.2% | 99.3% | 99.5% |
頻度の高い文字では top-1 が 95% 以上に達します。出現 10 件未満の極稀少クラスでは top-1 を外しがちですが、top-20 候補に含まれる確率は 93% あり、候補列挙ベースの翻刻支援用途では有効です。
前処理
中央正方形クロップ → 384×384 リサイズ → ImageNet 標準で正規化
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
入力テンソル: float32 [1, 3, 384, 384] (NCHW)
出力
shape [1, 3673] の logits。softmax + argmax で top-1 クラスを取得し、convnext_v4.meta.json の classes 配列で対応する Unicode コード(例: U+3042)に変換します。
使い方
ブラウザ (ONNX Runtime Web)
import * as ort from "onnxruntime-web";
const url = "https://huggingface.co/yuta1984/soramaru_kuzushiji_ai/resolve/main/convnext_v4.onnx";
const session = await ort.InferenceSession.create(url, { executionProviders: ["wasm"] });
// preprocess: 中央正方形クロップ → 384×384 → Float32Array [1,3,384,384]
const tensor = new ort.Tensor("float32", buf, [1, 3, 384, 384]);
const out = await session.run({ [session.inputNames[0]]: tensor });
const logits = out[session.outputNames[0]].data;
完全な実装例は app.js を参照。
Python (onnxruntime)
import numpy as np, onnxruntime as ort
from PIL import Image
sess = ort.InferenceSession("convnext_v4.onnx", providers=["CPUExecutionProvider"])
img = Image.open("kuzushiji.png").convert("RGB")
w, h = img.size
s = min(w, h)
img = img.crop(((w-s)//2, (h-s)//2, (w+s)//2, (h+s)//2)).resize((384, 384), Image.BICUBIC)
x = (np.array(img, dtype=np.float32) / 255.0 - [0.485, 0.456, 0.406]) / [0.229, 0.224, 0.225]
x = x.transpose(2, 0, 1)[None].astype(np.float32)
logits = sess.run(None, {sess.get_inputs()[0].name: x})[0][0]
top5 = logits.argsort()[::-1][:5]
# → meta.json["classes"][k] で Unicode コードに変換
制限
- 1 文字単位の分類のみ。ページ全体の検出・OCR ではありません(事前に文字単位で切り出す必要があります)
- 学習データに含まれない字体・崩し方には弱く、信頼度が下がります
- top-1 確率が低い場合は誤認識の可能性が高いため、上位複数候補の参照を推奨
ライセンス
学習元データの再配布条件に倣い、本モデルは CC BY-SA 4.0 で公開しています。派生物を公開する際は本モデルおよび以下のデータセットを引用してください:
- Kaggle Kuzushiji Recognition (2019)
- 東京大学史料編纂所くずし字データセット
クレジット
- マスコット「そらまる」: みんなで翻刻