Views
No views yet
agentic / non_agentic) in milliseconds instead of a VLM call.| file | backbone | params | route acc | route F1 | score MAE |
|---|---|---|---|---|---|
finetune-convnext.onnx | ConvNeXt-Tiny | 28M | 0.951 | 0.914 | 0.028 |
finetune-mobilenetv3.onnx | MobileNetV3-Large | 5M | 0.952 | 0.916 | 0.029 |
probe-dinov2s.onnx | DINOv2-S (frozen) + MLP | 22M + 0.2M | 0.934 | 0.886 | 0.039 |
finetune-convnext.onnx - best soft-score fidelity (lowest score MAE) and best indirect routing; the default in the kurenai SDK.finetune-mobilenetv3.onnx - leads the binary route at 5.6× fewer parameters; the pick for routing-only or latency-sensitive use.probe-dinov2s.onnx - cheapest to retrain (only the MLP head); ~3 F1 points behind the fine-tunes.clean_single_column, multi_column_text, table_heavy, form_or_key_value, figure_chart_heavy, complex_mixed, scanned_or_degraded, title_blank_otheragentic when it belongs to table_heavy, form_or_key_value, figure_chart_heavy, complex_mixed, or scanned_or_degraded; everything else is non_agentic.1import numpy as np
2import onnxruntime as ort
3from PIL import Image
4from huggingface_hub import hf_hub_download
5
6CLASSES = ["clean_single_column", "multi_column_text", "table_heavy",
7 "form_or_key_value", "figure_chart_heavy", "complex_mixed",
8 "scanned_or_degraded", "title_blank_other"]
9
10def preprocess(img: Image.Image, size: int = 224) -> np.ndarray:
11 if img.mode != "RGB": # composite RGBA onto white
12 rgba = img.convert("RGBA")
13 img = Image.new("RGB", rgba.size, (255, 255, 255))
14 img.paste(rgba, mask=rgba.getchannel("A"))
15 w, h = img.size # pad to centered square on white
16 side = max(w, h)
17 canvas = Image.new("RGB", (side, side), (255, 255, 255))
18 canvas.paste(img, ((side - w) // 2, (side - h) // 2))
19 arr = np.asarray(canvas.resize((size, size), Image.Resampling.BILINEAR),
20 dtype=np.float32) / 255.0
21 arr = arr.transpose(2, 0, 1) # CHW
22 mean = np.array([0.485, 0.456, 0.406], np.float32).reshape(3, 1, 1)
23 std = np.array([0.229, 0.224, 0.225], np.float32).reshape(3, 1, 1)
24 return (arr - mean) / std
25
26path = hf_hub_download("4thel00z/kurenai", "finetune-mobilenetv3.onnx")
27session = ort.InferenceSession(path, providers=["CPUExecutionProvider"])
28
29batch = np.stack([preprocess(Image.open("page.png"))]).astype(np.float32)
30score_logits, route_logit = session.run(None, {"pixel_values": batch})
31
32sigmoid = lambda x: 1.0 / (1.0 + np.exp(-x))
33route_prob = float(sigmoid(route_logit)[0])
34scores = dict(zip(CLASSES, sigmoid(score_logits)[0].tolist()))
35
36print("agentic" if route_prob >= 0.5 else "non_agentic", route_prob)
37print(max(scores, key=scores.get), scores)Classifier(), batch inference, CLI, automatic CUDA/CoreML provider selection) in the kurenai repository.| tensor | shape | dtype | notes |
|---|---|---|---|
pixel_values (input) | [batch, 3, 224, 224] | float32 | ImageNet-normalized, see preprocessing above |
score_logits (output) | [batch, 8] | float32 | logits — apply sigmoid per class |
route_logit (output) | [batch, 1] | float32 | logit — sigmoid ≥ 0.5 ⇒ agentic |
kimi-k2.6 vision-language model (eight soft layout scores + a routing decision per page).route_BCE(pos_weighted) + λ · score_BCE - the 8-class score head doubles as an auxiliary signal that regularizes the route head.scanned_or_degraded never occurs as a hard label in the training data; it is routed agentic by rule, so its score is the least calibrated of the eight.