コンテンツにスキップ

PP-OCRv6 OCRアルゴリズム実行ガイド(RV1126B)

文書情報

項目内容
文書名PP-OCRv6 OCRアルゴリズム実行ガイド(RV1126B)
バージョンv1.0
対象ボードRV1126B開発ボード
対象アルゴリズムPP-OCRv6 OCR
対象機能日本語画像OCR
開発環境Ubuntu 22.04 Docker、RKNN Toolkit2 Docker、RV1126Bボード
推奨モデルPP-OCRv6_small_detPP-OCRv6_small_rec
ボードIP192.168.10.85
ボード配置先/userdata/ppocrv6_ocr_demo/

修正履歴

バージョン日付内容
v1.02026-06-27初版作成。Docker内でPP-OCRv6日本語OCRを実行し、ONNX/RKNN変換およびRV1126Bボード実行へ進める手順を整理。

サンプル関連資料のダウンロード

本チュートリアルで使用するサンプルコード、モデル、テスト画像などの関連資料は、次のリンクからダウンロードできます。

04_ocr.zip

1. 概要

本ガイドでは、RV1126B開発ボード上でPP-OCRv6 OCRを実行するための手順について説明します。開発PCまたはDocker環境でPaddleOCRモデルを準備し、ONNXへ変換した後、RKNN Toolkit2でRV1126B向けRKNNモデルへ変換します。ボード側では、RKNN RuntimeとC++実行プログラムにより、文字検出、文字領域切り出し、文字認識、CTC decode、結果保存を行います。

全体の流れは次のとおりです。

PP-OCRv6 smallモデルで日本語OCRを確認
Paddle inference modelを固定
Paddle model → ONNX
ONNX → RKNN(target_platform=rv1126b)
RV1126Bボードへモデル、辞書、C++実行ファイルを配置
RKNN C APIでdet / recを実行
OCR結果画像とテキストを保存

RV1126B上でPaddleOCR Pythonパッケージ全体を実行するのではなく、ボード側ではRKNN Runtimeのみを使用する構成を標準とします。

2. 使用モデル

用途モデル名ボード側RKNNファイル説明
文字検出PP-OCRv6_small_detppocrv6_small_det_rv1126b_i8.rknn画像中の文字領域を検出します。
文字認識PP-OCRv6_small_recppocrv6_small_rec_rv1126b_fp_no_softmax.rknn文字行画像を日本語テキストとして認識します。

recモデルでは、最終Softmaxを除去したRKNNモデルを使用します。CTC decodeでは各時刻の最大クラスを使用するため、Softmax後の確率ではなくSoftmax前のlogitsを使用しても、argmaxの結果は変わりません。

3. 作業ディレクトリ

作業ディレクトリの例を次に示します。

Terminal window
/opt/linuxshare/work/rv1126b/jp/AI/demo/ai-algorithm/04_ocr/ppocrv6_jp_demo

ディレクトリ構成例は次のとおりです。

ppocrv6_jp_demo/
├── samples/
├── output/
├── models/
│ ├── paddle/
│ ├── onnx/
│ ├── rknn/
│ └── rec/
├── scripts/
├── logs/
└── rv1126b-src/

4. Conda環境とPaddleOCRの準備

PP-OCRv6用のConda環境を作成します。

Terminal window
conda create -n ppocrv6 python=3.10 -y
conda activate ppocrv6

PaddlePaddleとPaddleOCRをインストールします。

Terminal window
python -m pip install --upgrade pip setuptools wheel
python -m pip install paddlepaddle==3.3.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/
python -m pip install paddleocr==3.7.0

インストール結果を確認します。

Terminal window
python - <<'PY'
import paddle
import paddleocr
import sys
print("Python:", sys.version)
print("Paddle:", paddle.__version__)
print("PaddleOCR:", paddleocr.__version__)
print("CUDA:", paddle.is_compiled_with_cuda())
PY

図1 PP-OCRv6日本語OCR環境構築確認画像

5. 日本語OCRテスト画像

今回使用した日本語テスト画像を図1に示します。

図2 PP-OCRv6日本語OCRのテスト画像

画像は次のように配置します。

Terminal window
mkdir -p samples
cp /path/to/jp_001.jpg ./samples/jp_001.jpg

6. PaddleOCRでの日本語OCR確認

scripts/test_ppocrv6_jp.pyを作成します。

import os
os.environ["FLAGS_use_mkldnn"] = "0"
os.environ["FLAGS_use_onednn"] = "0"
os.environ["PADDLE_PDX_ENABLE_MKLDNN_BYDEFAULT"] = "0"
os.environ["PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK"] = "True"
from paddleocr import PaddleOCR
ocr = PaddleOCR(
text_detection_model_name="PP-OCRv6_small_det",
text_recognition_model_name="PP-OCRv6_small_rec",
use_doc_orientation_classify=False,
use_doc_unwarping=False,
use_textline_orientation=False,
text_det_limit_side_len=736,
text_det_limit_type="max",
text_recognition_batch_size=1,
device="cpu",
)
results = ocr.predict("./samples/jp_001.jpg")
for res in results:
res.print()
res.save_to_img("./output")
res.save_to_json("./output")

実行します。

Terminal window
python scripts/test_ppocrv6_jp.py

図3に、PaddleOCRで生成された可視化結果を示します。

図3 PaddleOCR Python版のOCR可視化結果

7. Paddleモデルの固定

自動ダウンロードされたモデルをプロジェクト内に固定します。

Terminal window
mkdir -p models/paddle
cp -r ~/.paddlex/official_models/PP-OCRv6_small_det models/paddle/PP-OCRv6_small_det
cp -r ~/.paddlex/official_models/PP-OCRv6_small_rec models/paddle/PP-OCRv6_small_rec

recモデルの文字辞書は、独立したtxtファイルではなくinference.yml内のPostProcess.character_dictに含まれます。ボード側C++で扱いやすくするため、1行1文字のtxtとして抽出します。

Terminal window
python - <<'PY'
import yaml
from pathlib import Path
yml_path = Path("./models/paddle/PP-OCRv6_small_rec/inference.yml")
out_path = Path("./models/rec/ppocrv6_rec_dict.txt")
out_path.parent.mkdir(parents=True, exist_ok=True)
cfg = yaml.safe_load(yml_path.read_text(encoding="utf-8"))
chars = cfg["PostProcess"]["character_dict"]
out_path.write_text("\n".join(map(str, chars)) + "\n", encoding="utf-8")
print("dict:", out_path)
print("chars:", len(chars))
PY

今回の辞書行数は次のとおりです。

18708

recモデルの出力クラス数は18710です。差分の2クラスは、CTC blankとspace用の特殊クラスとして扱います。

8. Paddle modelからONNXへの変換

PaddleXのpaddle2onnxを使用してONNXへ変換します。

Terminal window
paddlex \
--paddle2onnx \
--paddle_model_dir ./models/paddle/PP-OCRv6_small_rec \
--onnx_model_dir ./models/onnx/PP-OCRv6_small_rec \
--opset_version 11

実行例を図4に示します。

図4 PP-OCRv6 recモデルのPaddle2ONNX変換結果

ONNXファイルは次の場所に生成されます。

models/onnx/PP-OCRv6_small_rec/inference.onnx

同様に、文字検出モデルもONNXへ変換します。

Terminal window
paddlex \
--paddle2onnx \
--paddle_model_dir ./models/paddle/PP-OCRv6_small_det \
--onnx_model_dir ./models/onnx/PP-OCRv6_small_det \
--opset_version 11

9. RKNN変換環境

RKNN変換はRKNN Toolkit2 Docker内で行います。

Terminal window
docker run -t -i --privileged \
-v /dev/bus/usb:/dev/bus/usb \
-v /data/project/sales/csun/rv1126b/jp/AI/demo:/test \
rknn-toolkit2:2.3.2-cp38 /bin/bash

コンテナ内で作業ディレクトリへ移動します。

Terminal window
cd /test/ai-algorithm/04_ocr/ppocrv6_jp_demo

RKNN Toolkit2を確認します。

Terminal window
python - <<'PY'
from rknn.api import RKNN
print("RKNN Toolkit2 import OK")
PY

10. detモデルのRKNN変換

detモデルはINT8量子化モデルを標準とします。入力は固定サイズ1 x 736 x 736 x 3です。

量子化用データセットリストを作成します。

Terminal window
DATASET_ROOT=./datasets/japanese_ocr_synthetic_dataset_v1_0
sed "s#^#japanese_ocr_synthetic_dataset_v1_0/# \
"${DATASET_ROOT}/labels/image_list.txt" \
> ./datasets/ppocrv6_det_calib.txt

ppocrv6_det_calib.txt./datasets/内に置くため、リスト内のパスは./datasets/から見た相対パスにします。./datasets/を二重に含めると、RKNN Toolkitが./datasets/datasets/...として解釈し、画像読み込みに失敗します。

det変換スクリプトでは、動的入力を避けるため、load_onnx()に入力名と固定入力サイズを指定します。

ret = rknn.load_onnx(
model="./models/onnx/PP-OCRv6_small_det/inference.onnx",
inputs=["x"],
input_size_list=[[1, 3, 736, 736]],
)

変換を実行します。

Terminal window
python scripts/convert_ppocrv6_det_to_rknn.py 2>&1 \
| tee logs/convert_ppocrv6_det_to_rknn.log

実行例を図5に示します。

図5 PP-OCRv6 detモデルのINT8 RKNN変換結果

必要に応じて、精度比較用のFPモデルも変換できます。

Terminal window
python scripts/convert_ppocrv6_det_to_rknn_fp.py 2>&1 \
| tee logs/convert_ppocrv6_det_to_rknn_fp.log

図6 PP-OCRv6 detモデルのFP RKNN変換結果

11. recモデルのRKNN変換とSoftmax除去

最初にrecモデルを通常変換した場合、ボード上で最終Softmax実行時に失敗しました。変換ログ例を図6に示します。

図7 PP-OCRv6 recモデルの通常RKNN変換結果

ボード側の失敗箇所は次のとおりです。

op name: exSoftmax13:Softmax.2
rknn_run failed

ONNX内のSoftmaxノードを確認します。

Terminal window
python - <<'PY'
import onnx
model = onnx.load("./models/onnx/PP-OCRv6_small_rec/inference.onnx")
for i, node in enumerate(model.graph.node):
if node.op_type == "Softmax" or "Softmax" in node.name:
print("index:", i)
print("op_type:", node.op_type)
print("name:", node.name)
print("input:", list(node.input))
print("output:", list(node.output))
print("-" * 80)
PY

確認結果は次のとおりです。

index: 480
op_type: Softmax
name: Softmax.2
input: ['p2o.pd_op.add.79.0']
output: ['fetch_name_0']

CTC decodeではSoftmax後の確率ではなく、Softmax前logitsのargmaxを使用しても結果は同じです。そのため、最終Softmaxを出力から外し、p2o.pd_op.add.79.0をRKNN出力にします。

scripts/convert_ppocrv6_rec_to_rknn_no_softmax.pyを作成します。

from pathlib import Path
from rknn.api import RKNN
ONNX_MODEL = "./models/onnx/PP-OCRv6_small_rec/inference.onnx"
RKNN_MODEL = "./models/rknn/ppocrv6_small_rec_rv1126b_fp_no_softmax.rknn"
REC_INPUT_SIZE = [1, 3, 48, 320]
REC_OUTPUT_NAME = "p2o.pd_op.add.79.0"
def main():
Path("./models/rknn").mkdir(parents=True, exist_ok=True)
rknn = RKNN(verbose=True)
rknn.config(
target_platform="rv1126b",
mean_values=[[127.5, 127.5, 127.5]],
std_values=[[127.5, 127.5, 127.5]],
optimization_level=3,
)
ret = rknn.load_onnx(
model=ONNX_MODEL,
inputs=["x"],
input_size_list=[REC_INPUT_SIZE],
outputs=[REC_OUTPUT_NAME],
)
if ret != 0:
raise RuntimeError("load_onnx failed")
ret = rknn.build(do_quantization=False)
if ret != 0:
raise RuntimeError("build failed")
ret = rknn.export_rknn(RKNN_MODEL)
if ret != 0:
raise RuntimeError("export_rknn failed")
rknn.release()
print("done:", RKNN_MODEL)
if __name__ == "__main__":
main()

変換を実行します。

Terminal window
python scripts/convert_ppocrv6_rec_to_rknn_no_softmax.py 2>&1 \
| tee logs/convert_ppocrv6_rec_to_rknn_no_softmax.log

実行例を図8に示します。

図8 最終Softmaxを除去したrecモデルのRKNN変換結果

生成されるモデルは次のとおりです。

models/rknn/ppocrv6_small_rec_rv1126b_fp_no_softmax.rknn

12. RV1126Bボードのマウント

RV1126B開発ボードのIPは192.168.10.85です。ホストPC側でボードのルートファイルシステムをNFSマウントします。

Terminal window
sudo umount -l /mnt 2>/dev/null
sudo mount -t nfs \
-o vers=3,proto=tcp,mountproto=tcp,nolock,retrans=5,timeo=5 \
192.168.10.85:/ /mnt

マウント後、/mnt/userdata/経由でボードへファイルを配置できます。

13. ボード側RKNN Runtimeの扱い

本環境では、ボード側にRKNN Runtimeが既に配置されています。

/usr/lib/librknnrt.so
/usr/lib/librknn_api.so

そのため、デモディレクトリへlibrknnrt.soを個別にコピーしません。古いライブラリを./libへ配置してLD_LIBRARY_PATHで優先ロードすると、既存の正常な実行環境を壊す可能性があります。

ボード側で確認します。

Terminal window
find / -name 'librknn*.so*' 2>/dev/null

実行時は、ボードシステム側の/usr/lib/librknnrt.soを使用します。

14. ボード側配置構成

ボード側の配置先は次のとおりです。

/userdata/ppocrv6_ocr_demo/
├── bin/
│ ├── test-rknn-model-smoke
│ └── test-ppocrv6-ocr
├── model/
│ ├── ppocrv6_small_det_rv1126b_i8.rknn
│ └── ppocrv6_small_rec_rv1126b_fp_no_softmax.rknn
├── dict/
│ └── ppocrv6_rec_dict.txt
└── test/
├── jp_001.jpg
├── ocr_result.txt
├── ocr_result.jpg
└── crops/

モデルと辞書をコピーします。

Terminal window
sudo mkdir -p /mnt/userdata/ppocrv6_ocr_demo/{model,dict,test,bin}
sudo cp models/rknn/ppocrv6_small_det_rv1126b_i8.rknn \
/mnt/userdata/ppocrv6_ocr_demo/model/
sudo cp models/rknn/ppocrv6_small_rec_rv1126b_fp_no_softmax.rknn \
/mnt/userdata/ppocrv6_ocr_demo/model/
sudo cp models/rec/ppocrv6_rec_dict.txt \
/mnt/userdata/ppocrv6_ocr_demo/dict/
sudo cp samples/jp_001.jpg \
/mnt/userdata/ppocrv6_ocr_demo/test/

15. C++実行プログラムの構成

ボード側C++コードは、1つのbuild.shで2つの実行ファイルを生成する構成にします。

rv1126b-src/
├── build.sh
├── CMakeLists.txt
└── src/
├── rknn_model_smoke_test.cc
└── ppocrv6_ocr_demo.cc

生成される実行ファイルは次の2つです。

実行ファイル用途
test-rknn-model-smoke.rknnモデルがボード上でrknn_initrknn_runできるか確認します。
test-ppocrv6-ocr画像読み込み、det推論、crop、rec推論、CTC decode、結果保存を行います。

build.shCURRENT_FOLDER=binを使用し、生成物を$SYSROOT/userdata/ppocrv6_ocr_demo/bin/へコピーします。

Terminal window
./build.sh

生成後の確認例です。

Terminal window
ls -lh Release
ls -lh /mnt/userdata/ppocrv6_ocr_demo/bin/

16. detモデルのsmoke test

ボード上でdetモデルをテストします。

Terminal window
cd /userdata/ppocrv6_ocr_demo
./bin/test-rknn-model-smoke \
./model/ppocrv6_small_det_rv1126b_i8.rknn

図9に実行結果を示します。

図9 detモデルのRV1126B smoke test結果

確認された入出力は次のとおりです。

input: 1 x 736 x 736 x 3, INT8, NHWC
output: 1 x 1 x 736 x 736, INT8, NCHW
rknn_run OK
model smoke test OK

17. rec no-softmaxモデルのsmoke test

ボード上でrec no-softmaxモデルをテストします。

Terminal window
cd /userdata/ppocrv6_ocr_demo
./bin/test-rknn-model-smoke \
./model/ppocrv6_small_rec_rv1126b_fp_no_softmax.rknn

図10に実行結果を示します。

図10 rec no-softmaxモデルのRV1126B smoke test結果

確認された入出力は次のとおりです。

input: 1 x 48 x 320 x 3, FLOAT16, NHWC
output: 1 x 40 x 18710, FLOAT16
rknn_run OK
model smoke test OK

18. ボード側OCR実行

ボード上で端末側OCRプログラムを実行します。

Terminal window
cd /userdata/ppocrv6_ocr_demo
./bin/test-ppocrv6-ocr \
./model/ppocrv6_small_det_rv1126b_i8.rknn \
./model/ppocrv6_small_rec_rv1126b_fp_no_softmax.rknn \
./dict/ppocrv6_rec_dict.txt \
./test/jp_001.jpg \
./test

実行ログを図11、図12に示します。

図11 RV1126B上のPP-OCRv6 OCR実行ログ前半

図12 RV1126B上のPP-OCRv6 OCR実行ログ後半

出力ファイルは次のとおりです。

/userdata/ppocrv6_ocr_demo/test/ocr_result.txt
/userdata/ppocrv6_ocr_demo/test/ocr_result.jpg
/userdata/ppocrv6_ocr_demo/test/crops/

19. ボード側OCR結果

今回のボード側実行では、53個のテキスト領域が検出されました。代表的な認識結果を次に示します。

番号認識結果
0もちもち
1とろっと、後味のよい
2天然の
7焼きたて
10うま味のある
12飽きのこない
23スパイシー
37ふんわり
51後味すっきり
52とろける

図13に、ボード側で保存したOCR可視化結果を示します。

図13 RV1126B上で保存したOCR可視化結果

ocr_result.txtの一部を次に示します。

0 667 58 187 53 0.945086 もちもち
1 855 64 460 99 0.891344 とろっと、後味のよい
2 400 81 135 49 0.932682 天然の
7 922 148 314 82 0.935921 焼きたて
10 100 200 483 103 0.950072 うま味のある
37 409 505 389 105 0.917636 ふんわり
51 496 732 285 64 0.951753 後味すっきり
52 828 768 97 34 0.925347 とろける

20. 現在の精度評価

v1.1時点で、端末側のPP-OCRv6実行チェーンは正常に動作しています。

det RKNN推論:成功
rec no-softmax RKNN推論:成功
CTC decode:成功
結果テキスト保存:成功
結果画像保存:成功

一方で、次の改善点があります。

項目現象対応方針
文字認識口どけのよいロどけのよいになる場合があります。crop品質、認識モデル、辞書後処理を確認します。
検出枠近接する複数語が1つの枠に結合される場合があります。PaddleOCR準拠のDB postprocessへ置き換えます。
後処理v1.1のC++検出後処理は簡易版です。box_score_fastunclip、rotated box処理を追加します。

21. 製品レベル精度に向けたデータセットと追加学習方針

v1.4では、単なる評価方針だけではなく、実際に学習データを作成し、PaddleOCR系の検出モデル・認識モデルを追加学習できる構成まで整理します。

製品レベル精度を目指す場合、公開データセットだけで完結させるのではなく、次の3種類のデータを組み合わせます。

公開データセット
日本語・多言語OCRとしての基礎性能を確認
合成データ
不足文字、フォント、縦書き、低照度、反射、ぼかし条件を補強
RV1126B実機撮影データ
実レンズ、露光、焦点距離、圧縮ノイズ、設置角度、照明条件に最適化

特にRV1126B製品では、最終的な精度はPC上の静止画像ではなく、実際のカメラ、照明、設置距離、画像圧縮条件に強く依存します。そのため、公開データセットは基礎評価と事前学習の補助として使用し、最終精度は必ず実機撮影データで評価します。

21.1 公共データセットとダウンロードリンク

以下のデータセットは、製品開発時の基礎評価、追加学習、または汎化性能確認に利用できます。実際に利用する前に、各データセットのライセンス、研究利用・商用利用条件、再配布可否を必ず確認してください。

用途データセットダウンロードまたは参照先推奨用途
多言語自然シーンOCRICDAR 2019 MLTICDAR 2019 RRC MLT Downloads多言語、複雑背景、傾き、低解像度文字を含む検出・認識評価。ダウンロードにはRRCへの登録が必要です。
日本語シーン文字JPSC1400JPSC1400 Dataset Page / JPSC1400-20201218.zip実環境で撮影された日本語文字画像による認識評価。文字単位評価や弱点文字分析に向いています。
日本語文書OCRNDL古典籍OCR学習用データセットndl-lab/ndl-minhon-ocrdataset日本語文書、縦書き、古典籍、劣化文書に対する参考データ。製品用途とは対象が異なるため、直接混合せず評価用または補助用とします。
日本語文字分類Kuzushiji / KMNIST 系列Kuzushiji Datasetひらがな・漢字の文字単位認識や文字混同分析の参考。PP-OCRの行認識学習には変換が必要です。
日本語文字画像ETL Character DatabaseETL Character Database手書き・印刷日本語文字の基礎評価、文字単位の混同分析、合成データ生成時の参考。

公開データセットを使う場合でも、製品用OCRでは次のように扱います。

公開データセットだけで最終モデルを決めない
公開データセットは事前評価・弱点把握・補助学習に使う
製品判定はRV1126B実機撮影データで行う
量子化校正データも実機撮影画像を中心に作成する

21.2 RV1126B実機撮影データの収集方針

製品精度を上げるうえで最も重要なのは、実際に製品が見る画像を収集することです。最低限、次の条件を含めます。

条件推奨内容
撮影距離近距離、中距離、最大運用距離
角度正面、上下傾き、左右傾き、斜め撮影
照明明るい環境、暗所、逆光、反射、局所照明
文字サイズ大文字、通常文字、小文字、細字
背景白背景、色付き背景、食品包装、金属、透明フィルム、印刷ムラ
ブレピンぼけ、動体ブレ、手持ちブレ
圧縮カメラ出力JPEG、ストリームからの切り出し画像
設置差個体差、レンズ差、焦点距離差、筐体越し撮影

推奨枚数は次のとおりです。

目的推奨枚数
初期検証200〜500枚
det追加学習500枚以上
rec追加学習crop画像5,000枚以上
製品評価1,000枚以上
量子化校正実機撮影画像200〜500枚

実機撮影画像は、次のようなディレクトリに保存します。

datasets/ppocr_product/raw/rv1126b/
├── train/
│ ├── normal/
│ ├── low_light/
│ ├── reflection/
│ ├── blur/
│ └── small_text/
├── eval/
│ ├── normal/
│ ├── low_light/
│ ├── reflection/
│ ├── blur/
│ └── small_text/
└── README.md

22. アノテーション方針と推奨ツール

22.1 推奨アノテーションツール

PaddleOCR系モデルの追加学習では、まずPPOCRLabelを推奨します。PPOCRLabelはOCR向けの半自動アノテーションツールで、検出ラベルLabel.txt、認識ラベルrec_gt.txt、認識用crop画像crop_img/を出力できます。

ツール用途備考
PPOCRLabelOCR検出・認識ラベル作成最優先。PaddleOCR / PaddleX形式に近く、検出と認識を同時に整理できます。
labelme不規則形状やポリゴン修正複雑な領域を扱う場合の補助。PaddleOCR形式への変換が必要です。
CVATチームアノテーション複数人でのレビュー、権限管理、品質管理に向いています。
自社Webツール製品専用ワークフロー量産時の再学習データ収集に向いています。

PPOCRLabelのインストール例を示します。

Terminal window
conda activate ppocrv6
python -m pip install PPOCRLabel
python -m pip install trash-cli

起動例は次のとおりです。

Terminal window
PPOCRLabel --kie True

起動後、画像フォルダを開き、検出枠と認識文字列を確認・修正します。作業終了時には、検出用Label.txtと認識用rec_gt.txtを必ず出力します。

22.2 PPOCRLabel出力ファイル

PPOCRLabel作業フォルダの例を示します。

datasets/ppocr_product/label_projects/rv1126b_jp_001/
├── images/
│ ├── jp_000001.jpg
│ ├── jp_000002.jpg
│ └── ...
├── Label.txt
├── fileState.txt
├── Cache.cach
├── rec_gt.txt
└── crop_img/
├── jp_000001_crop_0.jpg
├── jp_000001_crop_1.jpg
└── ...

検出ラベルLabel.txtは、1行に画像パスとJSON形式の検出結果を保持します。

images/jp_000001.jpg [{"transcription":"後味すっきり","points":[[496,732],[781,732],[781,796],[496,796]],"difficult":false}]

認識ラベルrec_gt.txtは、1行にcrop画像パスと認識文字列を保持します。

crop_img/jp_000001_crop_0.jpg 後味すっきり
crop_img/jp_000001_crop_1.jpg とろける

注意点は次のとおりです。

画像パスとラベルの区切りは必ずタブにする
日本語ラベルはUTF-8で保存する
空白文字、長音、句読点、全角半角の表記ゆれを統一する
読めない文字は無理に推測せず、difficultまたは除外対象にする

23. 学習用ディレクトリ構成

PaddleOCR学習用には、PPOCRLabelの作業フォルダをそのまま使うのではなく、検出用と認識用に分けた学習ディレクトリを作成します。

train_data/japanese_ocr/
├── det/
│ ├── images/
│ │ ├── train/
│ │ └── val/
│ ├── train_label.txt
│ └── val_label.txt
├── rec/
│ ├── images/
│ │ ├── train/
│ │ └── val/
│ ├── rec_gt_train.txt
│ └── rec_gt_val.txt
└── dict/
└── ppocr_japanese_product_dict.txt

検出学習用ラベル例は次のとおりです。

images/train/jp_000001.jpg [{"transcription":"後味すっきり","points":[[496,732],[781,732],[781,796],[496,796]],"difficult":false}]

認識学習用ラベル例は次のとおりです。

images/train/jp_000001_crop_0.jpg 後味すっきり

認識辞書ppocr_japanese_product_dict.txtは、学習ラベル内に出現する文字をすべて含めます。既存のPP-OCRv6_small_reccharacter_dictをベースにする場合は、文字順を維持し、不足文字だけを慎重に追加します。文字順を変更すると、既存重みとの対応が崩れる可能性があります。

24. PPOCRLabelデータから学習データを作成するスクリプト

次のスクリプトは、PPOCRLabel作業フォルダから検出学習用ラベル、認識学習用ラベル、認識辞書を作成します。パッケージ内のtraining-scripts/prepare_ppocr_dataset.pyとして同梱しています。

Terminal window
python training-scripts/prepare_ppocr_dataset.py \
--ppocrlabel_dir datasets/ppocr_product/label_projects/rv1126b_jp_001 \
--out_dir train_data/japanese_ocr \
--val_ratio 0.1 \
--seed 42

生成後、次を確認します。

Terminal window
tree train_data/japanese_ocr -L 3
head -n 3 train_data/japanese_ocr/det/train_label.txt
head -n 3 train_data/japanese_ocr/rec/rec_gt_train.txt
wc -l train_data/japanese_ocr/dict/ppocr_japanese_product_dict.txt

複数のアノテーションプロジェクトを統合する場合は、--ppocrlabel_dirに複数パスを指定できます。

Terminal window
python training-scripts/prepare_ppocr_dataset.py \
--ppocrlabel_dir \
datasets/ppocr_product/label_projects/rv1126b_jp_001 \
datasets/ppocr_product/label_projects/rv1126b_jp_002 \
--out_dir train_data/japanese_ocr \
--val_ratio 0.1

25. 検出モデルの追加学習

検出モデルは、文字領域の位置がずれる、複数単語が結合される、小さい文字が漏れる場合に追加学習します。

PaddleOCRリポジトリを準備します。

Terminal window
mkdir -p third_party
cd third_party
git clone https://github.com/PaddlePaddle/PaddleOCR.git
cd PaddleOCR
python -m pip install -r requirements.txt

使用可能な検出設定ファイルを確認します。

Terminal window
find configs -iname "*det*.yml" | sort | grep -E "OCRv5|OCRv4|OCRv3|DB"

PP-OCRv6の学習用設定ファイルが現在の環境で公開されている場合は、それを使用します。存在しない場合は、PP-OCRv5またはPP-OCRv4のDB検出設定をベースにしてfine-tuneします。実際の設定ファイル名はPaddleOCRのバージョンで異なるため、必ずfind結果で確認します。

学習コマンド例を示します。パッケージ内のtraining-scripts/train_det.shも同じ方針で作成しています。

Terminal window
cd third_party/PaddleOCR
DET_CONFIG=configs/det/PP-OCRv5/PP-OCRv5_server_det.yml \
DATA_ROOT=../../train_data/japanese_ocr \
SAVE_DIR=../../output/train/det_product \
bash ../../training-scripts/train_det.sh

train_det.shでは、主に次の項目を上書きします。

Global.save_model_dir
Train.dataset.data_dir
Train.dataset.label_file_list
Eval.dataset.data_dir
Eval.dataset.label_file_list
Optimizer.lr.learning_rate

単一GPUまたは小規模データでfine-tuneする場合、学習率は小さめに設定します。

初期候補:1e-4
不安定な場合:5e-5
非常に小さいデータの場合:1e-5〜2e-5

26. 認識モデルの追加学習

認識モデルは、、長音、ひらがな・カタカナ、細字、小文字、装飾フォントなどで誤認識が出る場合に追加学習します。

使用可能な認識設定ファイルを確認します。

Terminal window
cd third_party/PaddleOCR
find configs -iname "*rec*.yml" | sort | grep -E "OCRv5|OCRv4|OCRv3|SVTR"

認識モデルの追加学習コマンド例を示します。

Terminal window
cd third_party/PaddleOCR
REC_CONFIG=configs/rec/PP-OCRv5/PP-OCRv5_server_rec.yml \
DATA_ROOT=../../train_data/japanese_ocr \
SAVE_DIR=../../output/train/rec_product \
DICT_PATH=../../train_data/japanese_ocr/dict/ppocr_japanese_product_dict.txt \
bash ../../training-scripts/train_rec.sh

認識学習で重要な項目は次のとおりです。

項目内容
character_dict_path学習用辞書。ラベル中の全文字を含めます。
use_space_char空白を認識対象に含める場合は有効にします。
rec_image_shape本プロジェクトでは最終的に3,48,320へ合わせます。
max_text_length長い文字列を扱う場合は十分な長さにします。
学習率追加学習では小さめにします。

注意点として、既存のPP-OCRv6認識モデルの出力クラス数は本プロジェクトで18710です。辞書を大きく変更した場合、最終分類層の次元が変わるため、既存重みをそのまま流用できない場合があります。製品追加学習では、まず既存辞書範囲内の文字で精度改善し、必要な場合だけ辞書拡張を検討します。

27. 学習後モデルの評価

学習後は、PC上とRV1126B上の両方で評価します。

PC側評価項目は次のとおりです。

det precision / recall / hmean
rec accuracy
end-to-end OCR exact match
文字単位正解率
低照度、反射、ぼけ、小文字条件別の正解率

PaddleOCR評価コマンド例を示します。

Terminal window
cd third_party/PaddleOCR
python tools/eval.py \
-c configs/rec/PP-OCRv5/PP-OCRv5_server_rec.yml \
-o Global.checkpoints=../../output/train/rec_product/best_accuracy

製品評価では、集計表を次のように分けます。

評価セット内容
public_eval公開データセットから作成した評価セット
rv1126b_eval_normal通常照明の実機撮影
rv1126b_eval_low_light暗所・低照度
rv1126b_eval_reflection反射・光沢面
rv1126b_eval_blurピンぼけ・動体ブレ
rv1126b_eval_small_text小文字・遠距離

28. 学習済みモデルのエクスポートとRKNN変換

追加学習後、Paddle inference modelへエクスポートします。

検出モデルのエクスポート例です。

Terminal window
cd third_party/PaddleOCR
python tools/export_model.py \
-c configs/det/PP-OCRv5/PP-OCRv5_server_det.yml \
-o Global.checkpoints=../../output/train/det_product/best_accuracy \
Global.save_inference_dir=../../models/paddle/product_det

認識モデルのエクスポート例です。

Terminal window
python tools/export_model.py \
-c configs/rec/PP-OCRv5/PP-OCRv5_server_rec.yml \
-o Global.checkpoints=../../output/train/rec_product/best_accuracy \
Global.save_inference_dir=../../models/paddle/product_rec

その後、本ガイド前半と同じ流れでONNXへ変換します。

Terminal window
paddlex \
--paddle2onnx \
--paddle_model_dir ./models/paddle/product_rec \
--onnx_model_dir ./models/onnx/product_rec \
--opset_version 11

RV1126B向けRKNNへ変換するときは、次を守ります。

det:実機撮影画像を中心にしたdatasetリストでINT8量子化
rec:まずFP no-softmaxで変換し、動作と精度を確認
rec量子化:精度劣化を評価してから採用判断

29. 量子化校正データの作成

detのINT8量子化では、量子化校正データが精度に大きく影響します。公開データセットだけでなく、RV1126B実機撮影画像を必ず含めます。

推奨構成は次のとおりです。

datasets/ppocr_product/calib/
├── normal/
├── low_light/
├── reflection/
├── blur/
└── small_text/

RKNN用datasetファイルを作成します。

Terminal window
find datasets/ppocr_product/calib -type f \
\( -iname "*.jpg" -o -iname "*.png" \) \
| sort \
| sed "s#^datasets/##" \
> datasets/ppocrv6_product_det_calib.txt

datasets/ppocrv6_product_det_calib.txt./datasets/配下に置く場合、リスト内の相対パスは./datasets/を基準にします。以前確認したとおり、datasets/datasets/...にならないように注意します。

30. 製品精度改善の運用フロー

製品投入後も、誤認識画像を継続的に回収し、再学習に回します。

RV1126BでOCR実行
低信頼・誤認識・未検出画像を保存
PPOCRLabelで再確認・修正
train_dataへ追加
det / recをfine-tune
ONNX / RKNN変換
実機評価
製品モデルとして採用

保存すべき失敗例は次のとおりです。

検出漏れ
複数語の結合
文字領域の切れ
口 / ロ、日 / 目、ー / 一 などの混同
小文字の誤認識
反射や低照度による誤認識

31. 本ドキュメント完了条件

本ドキュメントでは、次の状態を完了条件とします。

公共データセットの入手先を確認できる
PPOCRLabelで検出・認識ラベルを作成できる
PPOCRLabel出力からPaddleOCR学習用ディレクトリを生成できる
det / recの追加学習コマンドを実行できる
学習済みモデルをPaddle inference modelへエクスポートできる
ONNX / RKNN変換の既存手順へ接続できる
RV1126B実機撮影データを評価・量子化校正に利用できる

32. 製品開発に向け改善項目

製品開発では、次の改善を行います。

優先度改善項目
1PaddleOCR準拠のDB postprocess実装
2cropの透視変換と回転文字対応
3認識スコア計算と低信頼結果のフィルタリング
4PPOCRLabel出力からの自動品質チェック
5実機撮影データの評価レポート自動生成
6学習済みモデルのONNX / RKNN変換をCI化
7INT8量子化前後の精度差分レポート作成

33. 参考資料