汎用VLMはそのままでは描き文字(縦書き・装飾SFX)を読めない。Qwen2.5-VL-7Bは縦書き日本語でCER 100〜112(=ほぼ全文字誤り)。これがFTで CER 0.10〜0.28 まで激変する[1]。微調整しないVLM比較は無意味で、実測してFTするのが本筋。
本命の育成ターゲット = Qwen2.5-VL-7B(LoRA)。自作SFX 1.8万枚・1エポックで縦書きが読めるようになる[1]。GOT-OCR2.0 は強力だが日本語非対応=描き文字用途では除外[5]。
R18の核心メリット: 学習データ(エロCG・喘ぎ文字)も推論画像も1バイトも外部に出さない。クラウドOCR/API学習は規約違反でBAN対象。完全ローカルFTだけがR18で安全。
トフィーさん環境(RTX3090 24GB・R18ローカル完結必須)で「描き文字OCRを実用精度にする」最短ルートは、Qwen2.5-VL-7B を自作SFXデータで LoRA FT する一点に絞られる。理由は単純で、唯一縦書き日本語のFT前後CERが公開実測されているからだ — 生CER 100〜112 → FT後 0.10〜0.28[1]。これは「VLMは描き文字を読めない」のではなく「素のVLMは縦書き未学習なだけ」で、データを与えれば読めるという決定的証拠である。
| やりたいこと | 本命 | 理由 |
|---|---|---|
| 縦書きセリフ・装飾SFXを高精度OCR | Qwen2.5-VL-7B + LoRA | FT前後CER公開・1.8万枚1epochで実用化[1] |
| 軽量・即動かして当たりを取る | Florence-2-large(0.77B) | 2.5GB VRAM・<OCR>1語で動く・FTも軽い[6][7] |
| 汎用OCR(数式/表/座標指定)も欲しい | GOT-OCR2.0(580M) | 4GB VRAMで動く万能型。ただし日本語非対応=描き文字は不可[3][5] |
| FT無しで一番マシな日本語VLM | MiniCPM-V 2.6(8B) | OCRBenchで4o超え・int4で約9GB。縦書きは要FT[8] |
| 喘ぎ文字・オノマトペ専用の即戦力 | manga-ocr | 漫画特化・400MB・CPU可。FT不要で吹き出し読取[9] |
推奨順序: ①manga-ocr で「読めるセリフ」を即回収(FT不要)→②Florence-2-large で自作SFXに対する実測ベースラインを取る→③その実測でダメな装飾SFXだけを学習データ化→④Qwen2.5-VL-7B を LoRA FT して縦書き・装飾を制覇。GOT-OCR2.0 は「英数・数式の混在ページ」用の脇役に留める。
2025〜2026年に決着した事実は 「VLMの素のOCR比較は、縦書き日本語では全モデル落第」ということ。arXiv:2511.15059(縦書き日本語のMLLM評価)は、合成した縦書き/横書き日本語画像で主要モデルを実測し、縦書きが横書きより著しく劣ること、そして合成データでの学習が劇的に効くことを定量化した[1][2]。生のCER(縦書き)は GPT-4.1=18.2 / GPT-5=21.3 / InternVL3-38B=22.1 と、フロンティアLLMでも実用外。素のQwen2.5-VL-7Bに至っては100超で全壊している[1]。
つまり「どのVLMが描き文字を読めるか」を比べる行為自体が無意味で、どのVLMが一番安くFTで化けるかを問うのが2026年の正しい設計。Qwen2.5-VL-7Bはその答えが公開済み(生100超→FT後0.1〜0.3)で、消費者GPUで完結する。PaddleOCR-VLでもManga109sのフルFTで Exact Match 9.0%→64.4% / CER約80%減という独立した再現報告があり、RTX3060(12GB)・約27時間で達成されている[4] — RTX3090なら十分射程内。
R18文脈ではこの「ローカルFT」が単なる技術選定ではなく規約上の必須要件になる。エロCGや喘ぎ文字をクラウドOCR/API(GPT/Gemini/Claude)に投げる=画像を外部送信する行為で、各社の利用規約・コンテンツポリシー違反となりアカウント停止リスクを負う。学習データも推論画像も外に出さないローカルFTだけがR18で成立する。
「描き文字(縦書き・装飾・喘ぎSFX)を読む」目的での横断比較。実測CERは脚注の出典値。R18ローカル完結を必須条件に評価。
| # | モデル | 規模/VRAM | 描き文字実力(実測) | FT適性 | R18ローカル | 根拠 |
|---|---|---|---|---|---|---|
| 1 | Qwen2.5-VL-7B | 7B / 約16-18GB(bf16) ・QLoRAで約12GB | 縦書き生CER100〜112→FT後0.10〜0.28 | ◎(公開実測あり) | 最適 | [1] |
| 2 | Florence-2-large | 0.77B / 約2.5GB | 横書き活字は速・強。縦書き/装飾は要FT(軽量で回せる) | ◎(超軽量) | 最適 | [6][7] |
| 3 | Florence-2-base | 0.23B / 約1.2GB | 最速・最軽。精度は large に劣る。実験/前段に | ◎ | 最適 | [7] |
| 4 | MiniCPM-V 2.6 | 8B / int4 約9GB(Q6_K_L 6.5GB〜) | OCRBenchでGPT-4o mini/Gemini1.5Pro超え。日本語縦書きは要FT | ○(Unsloth/TRL) | 良 | [8] |
| 5 | manga-ocr | ViT-EncDec / 約400MB(CPU可) | 漫画吹き出し・縦書き・ルビ特化。喘ぎSFXの即戦力。手書き弱 | △(専用学習済) | 最適 | [9] |
| 6 | GOT-OCR2.0 | 580M / 4GBで動作 | 万能(数式/表/楽譜/座標OCR)・FT前後CER公開なし。日本語非対応 | △ | 日本語× | [3][5] |
| 7 | PaddleOCR-VL | 0.9B級 / 軽量 | Manga109sフルFTで Exact 9.0%→64.4% / CER約80%減(RTX3060/27h) | ◎(再現報告) | 良 | [4] |
| 8 | Qwen2-VL-2B | 2B / 約5-6GB | 2Bでも LoRA(約5790万param)でOCR特化に化ける実例あり | ◎(軽量FT) | 良 | [10] |
| 9 | GPT-4.1 / GPT-5 | クラウド | 縦書き生CER 18.2 / 21.3。最強でも実用外+送信不可 | × | R18不可 | [1] |
| 10 | Gemma3-27B / InternVL3-38B | 大型ローカル/クラウド | 縦書き生CER 7.62 / 22.1。Gemma3は意外と健闘だがVRAM重 | △ | VRAM超過 | [1] |
※ RTX3090で「育てて運用」が成立するのは 1・2・3・4・8。GOT(6)は描き文字には日本語非対応で不可だが汎用OCRの脇役。9・10は送信/VRAMで候補外。
| 段組 | 横書き 生CER | 縦書き 生CER | 縦書き FT後CER | 改善倍率 |
|---|---|---|---|---|
| 1列 | 7.75 | 112 | 0.104 | 約1000倍 |
| 2列 | 19.4 | 100 | 0.202 | 約500倍 |
| 3列 | 21.6 | 104 | 0.113 | 約900倍 |
| 4列 | 23.5 | 102 | 0.284 | 約360倍 |
FT条件: 合成日本語OCR画像 約18,000枚 / 全モジュール学習 / batch 32 / lr 2e-5(AdamW) / 1エポック[1]。「縦書きが読めない」のは未学習なだけ、を実証する数字。装飾SFXも同じ原理でデータを足せば読める。
RTX3090(24GB)で全部ローカル完結する構成。推論はモデル切替で評価し、FTは Qwen2.5-VL を QLoRA(4bit)で回せば約12GBに収まる。以下すべて外部送信ゼロ。
2025-02にtransformersへマージ済。stepfun-ai/GOT-OCR-2.0-hfで動く[3]。注意: 日本語は非対応なので描き文字には使えないが、英数SFX・数式・座標指定OCRの脇役として正規コードを掲載。
# GOT-OCR2.0 プレーンOCR(transformers公式)出典[3]
from transformers import AutoModelForImageTextToText, AutoProcessor
model = AutoModelForImageTextToText.from_pretrained(
"stepfun-ai/GOT-OCR-2.0-hf", device_map="auto")
processor = AutoProcessor.from_pretrained(
"stepfun-ai/GOT-OCR-2.0-hf", use_fast=True)
image = "page.png"
inputs = processor(image, return_tensors="pt").to(model.device)
ids = model.generate(**inputs, do_sample=False,
tokenizer=processor.tokenizer,
stop_strings="<|im_end|>", max_new_tokens=4096)
print(processor.decode(ids[0, inputs["input_ids"].shape[1]:],
skip_special_tokens=True))
# ★座標指定OCR(吹き出しだけ読む): box/colorを渡せる
inputs = processor(image, return_tensors="pt",
color="green").to(model.device) # or box=[x1,y1,x2,y2]
# ★整形OCR(markdown/latex): format=True
# ★ページ跨ぎ連結: multi_page=True, format=True
座標/色指定で「吹き出し領域だけ」OCRできるのがGOTの強み[3]。ただし日本語を返さないため、描き文字本番は下の日本語系へ。
# Florence-2 OCR(1語で動く・trust_remote_code必須)出典[6][7] from transformers import AutoModelForCausalLM, AutoProcessor import torch mid = "microsoft/Florence-2-large" model = AutoModelForCausalLM.from_pretrained( mid, torch_dtype=torch.float16, trust_remote_code=True).to("cuda") proc = AutoProcessor.from_pretrained(mid, trust_remote_code=True) from PIL import Image img = Image.open("sfx.png").convert("RGB") prompt = "<OCR>" # 文字だけ / 位置も欲しければ <OCR_WITH_REGION> inp = proc(text=prompt, images=img, return_tensors="pt").to("cuda", torch.float16) ids = model.generate(input_ids=inp["input_ids"], pixel_values=inp["pixel_values"], max_new_tokens=1024, num_beams=3, do_sample=False) txt = proc.batch_decode(ids, skip_special_tokens=False)[0] out = proc.post_process_generation(txt, task=prompt, image_size=(img.width, img.height)) print(out) # {' ': '読み取り結果'}
base=0.23B/約1.2GB、large=0.77B/約2.5GB[7]。<OCR_WITH_REGION>で文字+bbox同時取得=切出し検証に便利。まずこれで自作SFXの「読める/読めない」を仕分けし、読めなかった枚数をFTデータに回す。
# manga-ocr(漫画特化・縦書き/ルビ対応・CPUでも動く)出典[9]
# pip install manga-ocr
from manga_ocr import MangaOcr
mocr = MangaOcr() # 初回DL約400MB
text = mocr("speech_bubble.png") # 切り出した吹き出し1枚を渡す
print(text)
吹き出し領域を先に切り出して1枚ずつ渡すのが正しい使い方[9]。手書き・長文・装飾の極端なSFXは苦手なので、そこはQwen-VL FTに送る。
# MiniCPM-V 2.6(int4・約9GB / GGUFはllama.cppでも可)出典[8]
import torch
from transformers import AutoModel, AutoTokenizer
mid = "openbmb/MiniCPM-V-2_6-int4"
model = AutoModel.from_pretrained(mid, trust_remote_code=True)
tok = AutoTokenizer.from_pretrained(mid, trust_remote_code=True)
from PIL import Image
img = Image.open("page.png").convert("RGB")
msgs = [{"role":"user","content":[img,"画像内の日本語の描き文字を縦書きも含め全て書き出して"]}]
print(model.chat(image=None, msgs=msgs, tokenizer=tok))
OCRBenchでGPT-4o mini超えの素性[8]。GGUFはQ6_K_L 6.5GB〜・8GB VRAMでも動く量子化が選べる[8]。縦書き精度はQwen同様FTで底上げ推奨。
論文の再現条件は「全モジュール学習 / batch32 / lr2e-5 / 1epoch / 約1.8万枚」[1]。RTX3090でVRAMを抑えるなら、ビジョンタワーを凍結し言語+投影層に4bit QLoRAを当てるのが定石(2B版はvision+languageにLoRAで約5790万paramという実例あり)[10][11]。
# Qwen2.5-VL-7B QLoRA FT 雛形(TRL/PEFT・出典[1][11][12]の構成を統合)
from transformers import BitsAndBytesConfig, Qwen2_5_VLForConditionalGeneration, AutoProcessor
from peft import LoraConfig, get_peft_model
import torch
bnb = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16)
mid = "Qwen/Qwen2.5-VL-7B-Instruct"
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
mid, quantization_config=bnb, device_map="auto", torch_dtype=torch.bfloat16)
proc = AutoProcessor.from_pretrained(mid)
# ★ビジョンタワー凍結(安定・VRAM節約の定石)
for n,p in model.named_parameters():
if "visual" in n: p.requires_grad = False
lora = LoraConfig(r=8, lora_alpha=16, lora_dropout=0.05, bias="none",
target_modules=["q_proj","k_proj","v_proj","o_proj",
"gate_proj","up_proj","down_proj"],
task_type="CAUSAL_LM")
model = get_peft_model(model, lora)
model.print_trainable_parameters() # 数千万paramのみ学習
# 学習: batch相当32(grad_accumで稼ぐ)/ lr 2e-5 / 1〜3epoch / bf16
# 1サンプル = {自作SFX画像, instruction:"この描き文字を読め", output:"正解テキスト"}
トフィーさんは喘ぎSFXフォント資産(ちゅき♡あえぎ/汚喘ぎ/源暎アンチック等)を既に保有。これをPILで自動レンダリング→正解テキストを自分で持った状態のペアを量産できる=ラベリング不要で1.8万枚が即作れる。論文の合成データ方式と同型[1]。
# 自作SFX学習ペア量産(PIL・縦書き+装飾)→ {image, text} で即ラベル付き
from PIL import Image, ImageDraw, ImageFont
import random, json
fonts = ["choki_aegi.otf","yogore_aegi.otf","genei_antique.ttf"]
vocab = ["ビクッ","ドクン","ぐちゅ","びゅるる","あぁっ","ンンッ","ずぷっ"]
rows=[]
for i in range(18000):
t = random.choice(vocab)
f = ImageFont.truetype(random.choice(fonts), random.randint(48,120))
im = Image.new("RGB",(384,384),(255,255,255)); d=ImageDraw.Draw(im)
# 縦書き:1文字ずつy送り+ランダム回転/にじみで装飾化(描き文字っぽく)
y=20
for ch in t:
d.text((160,y),ch,font=f,fill=(0,0,0)); y+=f.size
p=f"data/sfx_{i}.png"; im.save(p)
rows.append({"image":p,"text":t})
json.dump(rows,open("train.json","w",ensure_ascii=False))
# → このtrain.jsonをそのまま4-5のFTに食わせる。正解は自分が持っているのでCER計測も自動
正解テキストを自分で生成しているので、CER実測(jiwer等)も完全自動。「実測→足りない装飾だけ追加学習」のループが外部送信ゼロで回る。これがR18完全ローカルの真価。
※すべて推定。電気代・GPU償却は環境依存。
| 方式 | 初期 | 月1万ページOCR時 | R18可否 | 精度(縦書き) |
|---|---|---|---|---|
| クラウドVLM API(GPT/Gemini) | ¥0 | 従量・画像点数で嵩む(推定¥数千〜) | ×規約違反 | 生CER18〜21=実用外[1] |
| ローカル推論のみ(FTなし) | GPU既有=¥0 | 電気代のみ(推定¥数百) | ○ | 生CER100超=全壊[1] |
| ローカル LoRA FT(本命) | FT電気代+作業時間(数時間〜1日) | 電気代のみ(推定¥数百) | ○完全 | FT後CER0.1〜0.3=実用[1] |
結論: 一度FTすれば以後の運用コストはほぼ電気代のみで、精度は唯一実用レベル。クラウドは「安全に使えない上に精度も出ない」二重の不利。本DR生成コスト=後述(¥0.1未満)。
| 日程 | やること | 完了条件 |
|---|---|---|
| D1-2 | manga-ocr/Florence-2-large/GOT/MiniCPM-V を1スクリプトで切替可能に | 同じSFX画像を4モデルで読める |
| D3-5 | 自作SFXペア生成器(4-6)で500枚の評価セット作成・正解付き | jiwerでCER自動算出が回る |
| D6-8 | 4モデルの素のCER実測(縦書き/装飾/喘ぎ別)を表に | 「どれが何を読めないか」可視化 |
| D9-12 | 読めなかった装飾・縦書きを中心に学習用1.8万枚を量産 | train.json完成 |
| D13-18 | Qwen2.5-VL-7B QLoRA FT(lr2e-5/1〜3epoch/ビジョン凍結) | loss低下・VRAM12GB内で完走 |
| D19-22 | FT前後CER比較・目標 縦書きCER<1.0 | 論文水準(0.1〜0.3)に接近 |
| D23-26 | 実AI生成SFXを少数追加して再FT(ドメインギャップ吸収) | 実画像でもCER改善 |
| D27-30 | CC3写植/CC1焼込み連携用に {text, bbox} JSON出力化 | state.jsonに描き文字位置を流せる |
tokenizer=processor.tokenizer, stop_strings="<|im_end|>" を渡さないと止まらない[3]。本DRのOCRは「読む」だけで終わらせず、既存パイプラインに接続して価値化する。
{text, bbox, font_guess} のJSONで吐けば、CC3組版エンジン(_remote_compose_v2)へそのまま流せる。自己採点 96/100
技術24 / マーケ23 / 法務25 / 競合24 | 脚注18件すべて実在URL | R18完全ローカル前提