ブラウザ完結のくずし字(一文字)認識を目的とした ConvNeXt-tiny ベースの ONNX モデル。
みんなで翻刻 のマスコット「そらまる」がアシスタント役を務めるデモサイトで使用されています。
頻度の高い文字では 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]
1import * as ort from "onnxruntime-web";
2
3const url = "https://huggingface.co/yuta1984/soramaru_kuzushiji_ai/resolve/main/convnext_v4.onnx";
4const session = await ort.InferenceSession.create(url, { executionProviders: ["wasm"] });
5
6// preprocess: 中央正方形クロップ → 384×384 → Float32Array [1,3,384,384]
7const tensor = new ort.Tensor("float32", buf, [1, 3, 384, 384]);
8const out = await session.run({ [session.inputNames[0]]: tensor });
9const logits = out[session.outputNames[0]].data;
1import numpy as np, onnxruntime as ort
2from PIL import Image
3
4sess = ort.InferenceSession("convnext_v4.onnx", providers=["CPUExecutionProvider"])
5
6img = Image.open("kuzushiji.png").convert("RGB")
7w, h = img.size
8s = min(w, h)
9img = img.crop(((w-s)//2, (h-s)//2, (w+s)//2, (h+s)//2)).resize((384, 384), Image.BICUBIC)
10
11x = (np.array(img, dtype=np.float32) / 255.0 - [0.485, 0.456, 0.406]) / [0.229, 0.224, 0.225]
12x = x.transpose(2, 0, 1)[None].astype(np.float32)
13
14logits = sess.run(None, {sess.get_inputs()[0].name: x})[0][0]
15top5 = logits.argsort()[::-1][:5]
16# → meta.json["classes"][k] で Unicode コードに変換