Psycho-passは限界かもしれない
当時好きだったアニメ サイコパス。仕事の忙しさに追われてプロビデンス編を見逃していたのだけれども、ふと思い出してNetflixで見ることができた。
普通にAIが進歩しすぎてPSYCHO-PASSの世界観が少し色あせて見えるかもなぁという話。
以降、psychopassに関するネタバレを含みます。
まずシビュラシステムとサイコパス自体を思い出す。
シビュラシステムは免罪体質者というイレギュラーな存在(きわめて高度な俯瞰視点の持ち主)の脳を逐一システムに取り込むことで、アップデートを行うシステム。
このシステムが全能である。という前提から常に脆弱性を探して問題提起を行うのがphychopassだと自分は考えている。
・無印では純粋な免罪体質者
・2では移植によって正しく判別されなかった者
・3では組織的犯罪に対してサイマネティックスキャンができない問題(だったっけ?)
そして今回のプロビデンス。
2~3の間に起こっているプロビデンスでは脆弱性とかではなく、法律を廃止したいシビュラシステムに対して、シビュラ統治の状況でも法律は必要だ。と唱える常森の戦い。
法律の廃止自体はピースブレイカーも求めていたのか、ジェネラル(医療用AIシステム)が求めていたのかは分からないし多分後者なんだけれども。
一旦、ここまでざっくり思い出して整理したけれども。色あせているというか限界を感じるというか。。。
「脳の集合体によるAIの統治」自体が2026年の技術水準で見ると違うように感じる。SFの宿命なのだろうけれども、時代が進歩しすぎて 物語としての新鮮さが無くなってきたように感じる。
AIに対する解像度が上がったことがまず挙げられる。AIはすさまじいエンジンではあるけれども、その出力に対するファジーな判断はやはり、というか当然人間系が行う。それは当然のことであって、この常識から抜け出せていないサイコパスの世界観もまた同じところで足踏みしているといえる。
AIのエンジン部分に対する描き方が違う(サイコパスでは脳、現代ではGPU)だけで残念ながら人間系の判断が無ければ自動化は不可能。という現代と同じ問題を描くに帰結してしまう。
もっと矮小化して書いてしまうと、シビュラシステムが間違いを犯すから常森がそれを正している。というように見えてしまう。
続いて脳の集合体というファンタジー要素が少し色あせてみる。現代のAIは人間の脳など用いずとも十分すぎるほどGPUで動いている。ChatGPTが凄すぎたよね。
処理能力の面で見た時に人間の脳がこれに追いつけるとは到底思えない。また脳を使ってもあらゆる判断において作中ではずいぶん弱い。(免罪体質すらまともに処理できない)
っていうか、シビュラシステムくらいなら普通に半導体で動きそうな気がするのが昨今なんだよなぁ。難しいのは意思決定の設計であって、何の上に動くかはさして問題じゃない気がしてきている。
いやそもそも無印は2012年らしいので、当時に組み立てた構想としてはずいぶん素晴らしいと思うのだけれども、2026年時点で少し古いのは否めない気がする。
4期があるか、無いかは分からないのだけれども、今後どのようにこの世界を調理していくのか。シビュラを使ってどのような未来を創作してくれるのか。楽しみではあるけれども、戦闘シーンや人間関係の話に逃げてほしくはないと願うばかり。
常森がずっと保守的な動きなので、懲役を終えた常森がシビュラを使ってどのような世界を設計するか見てみたいところやね。
Wikipedia が25周年らしい
たぶん自分が最もインターネットの中で尊敬するサイトである。
wikipediaがソースだというと少し邪険に扱われることもありましたね。昔は。
確かに専門分野においては記載が難しすぎて、初見で読むには無理があることもしばしばですが、wikipediaに書かれていることがおそらく正しいだろう。と考えて、その中でわからない単語を検索にかけることでかみ砕きながら読み進めればそれなりに知識が得れる。
また、その分野に詳しくなった後、改めて見るとそんなことまで書いてあったのか。と思うことも。
とにかくgoogle検索をしてwikipediaが出てくると、一旦正しい知識がここにある。と思えたのが素晴らしい。
今では生成AIのダミー記事と戦っているそうですが、今後も頑張ってほしい。
中学、高校でお世話になって、大人になった後、wikipediaに寄付できた時、初めて感謝ができたような気がして。お金を払ったのに嬉しかったのを覚えている。
なんなら嬉しくてノリでIPS細胞の研究にも寄付した気がする。
wikipediaと言えば変更履歴を見るのも少し好きで、本当にいろいろな人によってこの記事がメンテナンスされているんだな。と裏にいる人を感じることができるのが良い。
PaddleOCR ver3.3.2をファインチューニングまで試してみた時のメモ
追記1:一応、できたから書きましたけど、この数日間paddleocrで遊んでいるので、徐々に更新しています。もしかしたら数日後に見てもらったほうが良いかもです。(2025/12/11)
追記2:手書きのOCRができるかもしれないとウキウキで始めたのですが、ちょっと限界が見えてきたので中座。(2026/1/21)
AIにバチバチに作ってもらったけど、それでもわからないこと多すぎて。。。
すぐにやり方忘れそうなので、メモ
一応使ったコードを貼ってますが、相対パスがあまりにも多いので、そこは各々ご自身の環境で見直してください。
nvidiaのGPU(グラボ)を積んでいる。という前提の内容になっています。
■概要
ざっくり2つのモデルが動いているみたい
①DET(検出:Detection):PP-OCRv5_server_det
画像から文字のある領域を検出するところまでが仕事
②REC(認識:Recognition):PP-OCRv5_server_rec
検出された小さな文字画像から文字列を認識する処理
これらの工程を一気に行うのがPIPELINEというらしい。
後ほどDETとRECをトレーニング(ファインチューニング)する
※ちなみにこれ以外に3モデルぐらいオプションを入れると動く。いわゆる前処理をやるらしい。
■なにはともあれ環境
windows11 pro x64
Python 3.10.11()
pip 23.0.1
package系について
鬼のような数のパッケージが必要だけれども、versionのかみ合わせ、みたいなのがとにかく複雑らしい。
絶対に仮想で環境を組んだほうが良いし、paddle~系をバージョンアップするときは仮想環境のバックアップを取ったほうが良い。。。(py -3.10 -m venv env)
とりあえずマスト一覧
pip install paddlepaddle-gpu==3.2.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu???/ # paddlepaddle-gpuの後ろのURLは後で説明 pip install paddleocr==3.3.2 pip install PyMuPDF==1.20.2 pip install PPOCRLabel==3.1.4 pip show paddlex #これのバージョンと同じバージョンのpaddlex[ocr] pip install paddlex[ocr]==??????? pip install fontTools
・paddlepaddle
python -m pip install paddlepaddle-gpu==3.2.0 -i https://???
「?」の部分は下記のサイトから自分の環境にあったものを調べる必要がある。
ちなみにNVIDIAの人はCUDAのバージョンをを聞かれるので調べるコマンド
がこれ→(nvidia-smi)
※CUDA:GPUのライブラリ名らしい
C:\Users\Administrator>nvidia-smi Wed Dec 10 17:20:54 2025 +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 591.44 Driver Version: 591.44 CUDA Version: 13.1 |
自分の環境はCUDA13.1だったけれども、paddlepaddleはCUDA12.9対応のもので十分動いている…と思う。
・gitクローンでPaddleOCR
ファインチューニングをする場合はgitのクローンをいただく必要があるので、まずgitのインストールから始まる。
大量に設定を聞かれるけど、いわれるがままデフォルトのチェックのままNextを連打し続けた。
任意のディレクトリでgitクローン
ちなみにクローンしてきたらインストールしてほしいパッケージリストのテキスト(requirements.txt )があり、実行するだけでパッケージが揃うらしい。
PaddleOCR (OCR本体の開発環境一式)
git clone https://github.com/PaddlePaddle/PaddleOCR.git cd PaddleOCR pip install -r requirements.txt
・ccache
PPOCRLabelが動くときに無いと忠告される。無くてもいいらしいが、導入が簡単なので、とりあえず入れておく。
下記URLから環境にあったccacheをダウンロード
https://github.com/ccache/ccache/releases/
自分は「ccache-4.12.2-windows-aarch64.zip」でした。
解凍して任意の場所に置き、pathを通せば完了。
※いまだに恩恵わからず。。。
・動いている環境のpipリスト
一応参考までに、自分の環境のパッケージバージョン
いろいろ前処理や後処理で試行錯誤したので、おそらく不要なパッケージもある。
Package Version ------------------------ ----------- aistudio-sdk 0.3.8 albucore 0.0.24 albumentations 2.0.8 annotated-types 0.7.0 anyio 4.12.0 astor 0.8.1 attrdict 2.0.1 babel 2.17.0 bce-python-sdk 0.9.55 beautifulsoup4 4.14.3 blinker 1.9.0 cachetools 6.2.2 certifi 2025.11.12 chardet 5.2.0 charset-normalizer 3.4.4 click 8.3.1 colorama 0.4.6 colorlog 6.10.1 contourpy 1.3.2 cssselect 1.3.0 cssutils 2.11.1 cycler 0.12.1 Cython 3.2.2 decorator 5.2.1 einops 0.8.1 et_xmlfile 2.0.0 exceptiongroup 1.3.1 filelock 3.20.0 fire 0.7.1 Flask 3.1.2 flask-babel 4.0.0 fonttools 4.61.0 fsspec 2025.12.0 ftfy 6.3.1 future 1.0.0 GPUtil 1.4.0 h11 0.16.0 hf-xet 1.2.0 httpcore 1.0.9 httpx 0.28.1 huggingface_hub 1.2.1 idna 3.11 ImageIO 2.37.2 imagesize 1.4.1 imgaug 0.4.0 itsdangerous 2.2.0 Jinja2 3.1.6 joblib 1.5.2 kenlm 0.2.0 kiwisolver 1.4.9 lazy_loader 0.4 lmdb 1.7.5 lxml 6.0.2 MarkupSafe 3.0.3 matplotlib 3.10.7 modelscope 1.32.0 more-itertools 10.8.0 networkx 3.4.2 numpy 2.0.2 nvidia-cublas-cu11 11.11.3.6 nvidia-cublas-cu12 12.9.0.13 nvidia-cuda-nvrtc-cu11 11.8.89 nvidia-cuda-runtime-cu11 11.8.89 nvidia-cuda-runtime-cu12 12.9.37 nvidia-cudnn-cu11 8.9.4.19 nvidia-cudnn-cu12 9.9.0.52 nvidia-cufft-cu11 10.9.0.58 nvidia-cufft-cu12 11.4.0.6 nvidia-curand-cu11 10.3.0.86 nvidia-curand-cu12 10.3.10.19 nvidia-cusolver-cu11 11.4.1.48 nvidia-cusolver-cu12 11.7.4.40 nvidia-cusparse-cu11 11.7.5.86 nvidia-cusparse-cu12 12.5.9.5 nvidia-nvjitlink-cu12 12.9.86 opencv-contrib-python 4.10.0.84 opencv-python 4.6.0.66 opencv-python-headless 4.12.0.88 openpyxl 3.1.5 opt-einsum 3.3.0 packaging 25.0 paddleocr 3.3.2 paddlepaddle 3.2.0 paddlepaddle-gpu 3.2.0 paddlex 3.3.10 pandas 2.2.3 pdf2docx 0.5.8 pdf2image 1.17.0 pillow 12.0.0 pip 23.0.1 PPOCRLabel 3.1.4 premailer 3.10.0 prettytable 3.17.0 protobuf 3.20.2 psutil 7.1.3 py-cpuinfo 9.0.0 pyclipper 1.4.0 pycryptodome 3.23.0 pydantic 2.12.5 pydantic_core 2.41.5 PyMuPDF 1.20.2 pyparsing 3.2.5 PyPDF2 3.0.1 pypdfium2 5.1.0 PyQt5 5.15.11 PyQt5-Qt5 5.15.2 PyQt5_sip 12.17.2 python-bidi 0.6.7 python-dateutil 2.9.0.post0 python-docx 1.2.0 pytz 2025.2 PyYAML 6.0.2 RapidFuzz 3.14.3 rarfile 4.2 regex 2025.11.3 reportlab 4.4.5 requests 2.32.5 ruamel.yaml 0.18.16 ruamel.yaml.clib 0.2.15 safetensors 0.6.2 scikit-image 0.25.2 scikit-learn 1.7.2 scipy 1.15.3 sentencepiece 0.2.1 setuptools 65.5.0 shapely 2.1.2 shellingham 1.5.4 simsimd 6.5.3 six 1.17.0 soupsieve 2.8 stringzilla 4.4.0 termcolor 3.2.0 threadpoolctl 3.6.0 tifffile 2025.5.10 tiktoken 0.12.0 tokenizers 0.22.1 tqdm 4.67.1 typer-slim 0.20.0 typing_extensions 4.15.0 typing-inspection 0.4.2 tzdata 2025.2 ujson 5.11.0 urllib3 2.6.0 visualdl 2.5.3 wcwidth 0.2.14 Werkzeug 3.1.4 xlrd 1.2.0
paddle ocrのPIPELINE単品では
入力は画像(OpenCVのカラー画像)
戻りはテキスト(テキスト+座標+スコアの配列)
自分は手書きPDFでやりたかったので、
入力は手書きPDF
出力は検索可能なPDF
一旦、標準のモデルを使ったOCRを実施するコード
import fitz # PyMuPDF import numpy as np import cv2 from io import BytesIO from PIL import Image from paddleocr import PaddleOCR # ================================ # 設定 # ================================ INPUT_PDF = "input.pdf" OUTPUT_PDF = "output_searchable.pdf" FONT_PATH = r"C:\Windows\Fonts\HGRSMP.TTF" FONT_NAME = "HG丸ゴシックM-PRO標準" DPI_OCR = 300 #OCRするときの解像度 OUTPUT_MODE_VISIBLE = True # True: 赤テキスト(確認) / False: 透明テキスト MODEL_SEL = "User" #モデルを選択 # MODEL_SEL = "Proto" # ================================ # OCRエンジン初期化 # ================================ def init_pipeline_ocr(): if MODEL_SEL == "User": #ユーザーがトレーニングしたモデル return PaddleOCR( text_detection_model_dir=r'./build_ppocr_dataset/PaddleOCR/User/inference/PPOCRv5_jp_det', text_recognition_model_dir=r'./build_ppocr_dataset/PaddleOCR/User/inference/PPOCRv5_jp_rec', use_doc_orientation_classify=True, # 文書向き分類 use_doc_unwarping=False, # 歪み補正 UVDoc(座標ズレが発生するのでOFF) use_textline_orientation=True # CLS 180°反転行を補正 ) elif MODEL_SEL == "Proto": #標準のパイプライン return PaddleOCR( lang="japan", ocr_version="PP-OCRv5", use_doc_orientation_classify=True, # 文書向き分類 use_doc_unwarping=False, # 歪み補正 UVDoc(座標ズレが発生するのでOFF) use_textline_orientation=True # CLS 180°反転行を補正 ) # ================================ # paddleocr RECデータから要素取り出し # ================================ def get_rec_data(pred_page): texts = pred_page.get('rec_texts') assert isinstance(texts, list) and len(texts) > 0, "rec_texts が空です" dt_polys = pred_page.get('dt_polys') assert isinstance(dt_polys, list), "dt_polys が存在しません(None or 非list)" assert len(dt_polys) == len(texts), f"dt_polys count={len(dt_polys)} != rec_texts count={len(texts)}" return texts, pred_page.get('rec_scores'), dt_polys # ================================ # OCR実施 # ================================ def run_ocr_pipeline(ocr, img): outputs = ocr.predict(img) pred_page = outputs[0] if isinstance(outputs, list) else outputs texts, scores, dt_polys = get_rec_data(pred_page) return texts, scores, dt_polys # ================================ # PDFオーバーレイ(未回転・CropBox安全) # ================================ def process_pdf_overlay(input_pdf, output_pdf): ocr = init_pipeline_ocr() det = rec = None doc = fitz.open(input_pdf) for page_index in range(doc.page_count): page = doc.load_page(page_index) #--- pdfから画像を取得 --- # PaddleOCRは OpenCV画像(numpy配列)しか対応していない。 img_pix = page.get_pixmap(dpi=DPI_OCR, rotate=0) #PyMuPDF専用の Pixmap形式(生画像バッファ) img_png = img_pix.tobytes("png") #Pixmap → png img_np_uint8 = np.frombuffer(img_png, dtype=np.uint8) #png → numpy数値配列 img_cv2 = cv2.imdecode(img_np_uint8, cv2.IMREAD_COLOR) #numpy数値配列 → OpenCVのBGR画像 assert img_cv2.shape[1] == img_pix.width and img_cv2.shape[0] == img_pix.height #--- 前処理(画像に対する処理) --- #--- OCR実施 --- texts, scores, polys = run_ocr_pipeline(ocr, img_cv2) kind = "dt_polys" # print(f"[page {page_index}] items={len(texts)} kind={kind}") #デバッグ向け、ocr結果の表示 #--- 後処理(帰ってきたテキストに対する処理) --- #--- OCR結果の座標を処理 --- for j, poly in enumerate(polys): #OCR結果から座標を取得 arr = np.asarray(poly, dtype=float) xs, ys = arr[:,0], arr[:,1] x0, y0, x1, y1 = float(xs.min()), float(ys.min()), float(xs.max()), float(ys.max()) mm_x0 = x0 * 25.4 / DPI_OCR mm_y0 = y0 * 25.4 / DPI_OCR print(f" #{j:03d} text='{texts[j]}' score={scores[j]:.4f} " f"bbox_img=({x0:.2f},{y0:.2f},{x1:.2f},{y1:.2f}) x0≈{mm_x0:.2f}mm y0≈{mm_y0:.2f}mm") bound = page.bound() scale_x = bound.width / img_pix.width scale_y = bound.height / img_pix.height offset_x, offset_y = bound.x0, bound.y0 if not page.is_wrapped: page.wrap_contents() #--- pdfへフォントの埋め込み --- try: page.insert_font(fontname=FONT_NAME, fontfile=FONT_PATH) except Exception: print("フォント登録失敗") #--- pdfへテキストを乗せる --- for j, poly in enumerate(polys): arr = np.asarray(poly, dtype=float) xs, ys = arr[:,0], arr[:,1] x0, y0, x1, y1 = float(xs.min()), float(ys.min()), float(xs.max()), float(ys.max()) rect_pdf = fitz.Rect( offset_x + x0 * scale_x, offset_y + y0 * scale_y, offset_x + x1 * scale_x, offset_y + y1 * scale_y ) rc = page.insert_textbox( rect_pdf, texts[j], fontsize=(y1 - y0) * scale_y * 0.9, color=(1, 0, 0) if OUTPUT_MODE_VISIBLE else (0, 0, 0), render_mode=0 if OUTPUT_MODE_VISIBLE else 3, fontname=FONT_NAME, overlay=True ) # はみ出して描けなかったら小さめサイズでリトライ if rc < 0: # 描画に失敗したときは負数が戻る # 幅と高さの両方に基づく安全なフォントサイズを再計算 try: fobj = fitz.Font(fontfile=FONT_PATH) # フォントを明示取得 width_pt = rect_pdf.width height_pt = rect_pdf.height # 幅に収まるサイズ(text_length は fontsize=1での幅 → 目標は幅/その値) w_fit = width_pt / max(fobj.text_length(texts[j], fontsize=1), 1e-6) # 高さに収まるサイズ(行間を考慮せず1行想定) h_fit = height_pt * 0.8 # 余白を少し new_fs = max(min(w_fit, h_fit), 4) # 下限4ptなど rc = page.insert_textbox( rect_pdf, texts[j], fontsize=new_fs, color=(1, 0, 0) if DEBUG_MODE else (0, 0, 0), render_mode=0 if DEBUG_MODE else 3, fontname=FONT_NAME, overlay=True ) except Exception as e: print(f"フォント幅計算に失敗: {e}") #--- 埋め込みフォントから使っていないフォントを削除 --- doc.subset_fonts() #--- 圧縮して保存 --- doc.ez_save(output_pdf) doc.close() print("OCR終了") # ================================ # 実行 # ================================ if __name__ == "__main__": process_pdf_overlay(INPUT_PDF, OUTPUT_PDF)
これで問題なくOCRが実施できるが、精度はあまり褒められたものではない。
というか十分すごいのだが、実用レベルではない。
■ ファインチューニング(再学習)の概要
DETモデルとRECモデルをファインチューニングする。
手元に手書きPDFとデータセットを自分で用意するという熱い情熱と時間が必要である。。。
モデルの強化教育にはデータセットが必要である。
モデルは二つDET(検出)とREC(認識)が居る。この二人とも教育するが、要は手書きの画像に対して、座標とテキストの内容がわかるデータが必要なのだ。
これを簡単に準備するのがPPOCRLabelである。
①データセットを用意する
まず、PPOCRLabel向けに手書きPDFのままでは読み込めないので、png画像に分割する。
import os
from pdf2image import convert_from_path
def pdf_to_images(input_pdf_path, dpi=300):
"""
PDF を PNG 画像に変換し、pages フォルダに保存する関数。
Parameters
----------
input_pdf_path : str
入力 PDF のパス
dpi : int
出力画像の DPI
"""
# PDF ファイルの存在確認
if not os.path.isfile(input_pdf_path):
print("PDFファイルが見つかりません:", input_pdf_path)
return
# 出力フォルダ
output_dir = os.path.join(os.path.dirname(input_pdf_path), "pages")
os.makedirs(output_dir, exist_ok=True)
# PDF → 画像リスト
pages = convert_from_path(input_pdf_path, dpi=dpi)
# 各ページ保存
for i, page in enumerate(pages, 1):
filename = f"page_{i:04d}.png"
save_path = os.path.join(output_dir, filename)
page.save(save_path, "PNG")
print("保存:", save_path)
print("完了しました。出力フォルダ:", output_dir)
# 使用例
if __name__ == "__main__":
pdf_to_images("input.pdf", dpi=300)
②分割できたらPPOCRLabelを起動する
PPOCRLabel --lang ja
初回起動は裏でモデルをダウンロードしているらしいので、5分くらいかかります。
ちなみに5分以上待ってもGUIが表示されない場合は何かパッケージが足りていないかもしれません。
見た目ではわからない上に、ログにも残りません。。。
もし仮想環境なら
python .\env\Lib\site-packages\PPOCRLabel\PPOCRLabel.py
を実行して、エラーを解決し続ければパッケージが足りると思います。
さて、起動したらopen dirから先ほど作ったpng画像のフォルダを開く。
画像が大量に読み込まれたら「Auto Recognition」をクリック。
緑枠で大量に識字された適当な文字を、手打ちで正しい文字に打ちかえる・・・地獄か
1ページの確認が終わったら右下にある[check]をクリック
★★注意★★
PPOCRLabelではDETとRECの教育データは作れますが、CLSの教育データは作れません。なので、さかさま文字や90度回転している文字などの識字が極端に悪いですが、修正してはならないと思います。(おそらく)
緑の枠ごと消したほうが良いと考えます。
実際の運用ではCLSが文字の角度を修正したあとにDETが動くはずなので。
すべて終わったらfileから
[Export~]と書かれたものはすべて押す。押すに限る。
下記が生成されていたらOK
・crop_imgフォルダー (フォルダーの中に細かい文字画像群)
・Label.txt
・rec_gt.txt
③trainとval分ける
どうやら強化教育には頑張って作ったデータセットを二つに分ける必要があるらしい。
トレーニング用(train:traning)と評価用(Eval:evaluation)らしい
これらはランダムに分けるだけで良いらしい。わけわからん・・・
ランダムに分割するためのコード
import os
import argparse
import random
from typing import List, Tuple
def str2bool(s: str) -> bool:
return s.lower() in {"1", "true", "t", "yes", "y"}
def split_lines(lines: List[str], ratio: float) -> Tuple[List[str], List[str]]:
n = len(lines)
# 切り捨てで分割数を決定
k = max(0, min(n, int(n * ratio)))
return lines[:k], lines[k:]
def main():
ap = argparse.ArgumentParser(description="検出ラベルの train/eval 分割スクリプト")
ap.add_argument("--input", required=True, help="入力ラベルファイル(例: det_gt.txt)")
ap.add_argument("--ratio", type=float, default=0.9, help="train の比率 (0.0〜1.0、既定0.9)")
ap.add_argument("--seed", type=int, default=0, help="乱数シード (既定0: 未固定)")
ap.add_argument("--shuffle", type=str2bool, default=True, help="シャッフルするか (true/false、既定true)")
args = ap.parse_args()
in_path = args.input
if not os.path.exists(in_path):
raise FileNotFoundError(f"入力ファイルが見つかりません: {in_path}")
# 入力の読み込み
with open(in_path, "r", encoding="utf-8") as f:
# 空白行は除外(安全のため)
lines = [ln for ln in f.readlines() if ln.strip()]
if args.shuffle:
if args.seed:
random.seed(args.seed)
random.shuffle(lines)
# 出力ファイル名の決定
base, ext = os.path.splitext(in_path)
out_train = f"{base}_train{ext}"
out_val = f"{base}_val{ext}"
# 分割
train_lines, val_lines = split_lines(lines, args.ratio)
# 保存
with open(out_train, "w", encoding="utf-8") as f:
for ln in train_lines:
f.write(ln.rstrip("\n") + "\n")
with open(out_val, "w", encoding="utf-8") as f:
for ln in val_lines:
f.write(ln.rstrip("\n") + "\n")
print(f"入力: {in_path}")
print(f"分割比率: train={args.ratio:.2f} / val={1-args.ratio:.2f}")
print(f"行数: total={len(lines)} / train={len(train_lines)} / val={len(val_lines)}")
print(f"出力: {out_train}\n {out_val}")
if __name__ == "__main__":
main()
これで
・Label_train.txt
・Label_val.txt
・rec_gt_train.txt
・rec_gt_val.txt
が出来上がれば良い
④いよいよ教育。。。の前に設定ファイルの変更(.yml)
トレーニングのコードを走らせる前にデータセットを読むようにしないといけない。
まず、設定ファイルの元ネタを任意の場所にコピーする
DET側の設定ファイル
".\PaddleOCR\configs\det\PP-OCRv5\PP-OCRv5_server_det.yml"
REC側の設定ファイル
".\PaddleOCR\configs\rec\PP-OCRv5\PP-OCRv5_server_rec.yml"
DET側の変更箇所(当然パスは任意です)
#トレーニングデータの出力先
Global:
save_model_dir: ./User/models_output/PPOCRv5_jp_det
#ベースになるモデルのデータ
pretrained_model: ./User/official_pretrained_model/PP-OCRv5_server_det_pretrained.pdparams
※これはダウンロードしてくる必要がある。
直リン注意
#辞書(使用する文字リスト)
character_dict_path: ./PaddleOCR/ppocr/utils/dict/japan_dict.txt
character_dict_path: ./PaddleOCR/ppocr/utils/dict/ppocrv5_dict.txt
※japan_dictの中身、日本語入ってなくて草です。
Train:
dataset:
name: SimpleDataSet
data_dir: ./User/
label_file_list:
- ./User/pages/Label_train.txt
# 評価用のデータセット参照
Eval:
dataset:
name: SimpleDataSet
data_dir: ./User/
label_file_list:
- ./User/pages/Label_val.txt
REC側の変更箇所(当然パスは任意です)
#トレーニングデータの出力先
save_model_dir: ./User/models_output/PPOCRv5_jp_rec
#ベースになるモデルのデータ
pretrained_model: ./User/official_pretrained_model/PP-OCRv5_server_rec_pretrained.pdparams
※これはダウンロードしてくる必要がある。
直リン注意
Train:
dataset:
name: MultiScaleDataSet
ds_width: false
data_dir: ./User/pages
ext_op_transform_idx: 1
label_file_list:
- ./User/pages/rec_gt_train.txt
# 評価用のデータセット参照
Eval:
dataset:
name: SimpleDataSet
data_dir: ./User/pages
label_file_list:
- ./USer/pages/rec_gt_val.txt
⑤トレーニング開始
準備は整ったので、ymlファイルを渡しながらtrain.pyを叩けばトレーニングが始まります。
DET向けbat
@echo off echo --- 仮想環境をアクティベート --- call ..\env\Scripts\activate REM フォルダ移動 cd PaddleOCR REM --- WindowsコンソールのShift-JIS対応 --- chcp 65001 >NUL set PYTHONUTF8=1 echo --- Pythonスクリプトを実行 --- python "./tools/train.py" ^ -c "./User/configs/PPOCRv5_jp_det.yml" pause
REC向けbat
@echo off echo --- 仮想環境をアクティベート --- call ..\env\Scripts\activate REM フォルダ移動 cd PaddleOCR REM --- WindowsコンソールのShift-JIS対応 --- chcp 65001 >NUL set PYTHONUTF8=1 echo --- Pythonスクリプトを実行 --- python "./tools/train.py" ^ -c "./User/configs/PPOCRv5_jp_rec.yml" pause
これで出力先のフォルダに複数の「.pdparams」が生成される。
.pdparamsファイルは重みファイルらしくモデルの元ネタになるらしい。
本当は「best~.pdparams」というファイルが出てくるらしいが、自分のデータセットが少ないからか、生成されたことがない。
とりあえず、この重みファイルからモデルを生成する。
latest.pdparams→モデル作成のbat
※bestが生成されたらbest~.pdparamsが良い
DET向けbat
@echo off echo --- 仮想環境をアクティベート --- call ..\env\Scripts\activate REM フォルダ移動 cd PaddleOCR REM --- WindowsコンソールのShift-JIS対応 --- chcp 65001 >NUL set PYTHONUTF8=1 echo --- Pythonスクリプトを実行 --- python ./tools/export_model.py ^ -c ./User/configs/PPOCRv5_jp_det.yml ^ -o Global.pretrained_model=./User/models_output/PPOCRv5_jp_det/latest.pdparams ^ Global.save_inference_dir=./User/inference/PPOCRv5_jp_det pause
REC向けbat
@echo off echo --- 仮想環境をアクティベート --- call ..\env\Scripts\activate REM フォルダ移動 cd PaddleOCR REM --- WindowsコンソールのShift-JIS対応 --- chcp 65001 >NUL set PYTHONUTF8=1 echo --- Pythonスクリプトを実行 --- python ./tools/export_model.py ^ -c ./User/configs/PPOCRv5_jp_rec.yml ^ -o Global.pretrained_model=./User/models_output/PPOCRv5_jp_rec/latest.pdparams ^ Global.save_inference_dir=./User/inference/PPOCRv5_jp_rec pause
inferenceフォルダにモデルが出力されたはずです。
・inference.json
・inference.pdiparams
・inference.yml
■チューニング後のOCR実行
このチューニングしたモデルを使う!という段階まで来ました。
一番最初にOCRをしたpythonのinit_pipeline_ocr()を差し替えます。
text_detection_model_dir=r'./PaddleOCR/User/inference/PPOCRv5_jp_det',
text_recognition_model_dir=r'./PaddleOCR/User/inference/PPOCRv5_jp_rec',
use_doc_orientation_classify=True, # 文書向き分類
use_doc_unwarping=False, # 歪み補正 UVDoc(座標ズレが発生するのでOFF)
use_textline_orientation=True # CLS 180°反転行を補正