バックエンドエンジニアがAI-OCRを通じて機械学習を体験した話

株式会社iCAREの[西口](https://twitter.com/NishiguchiNaoya)です。
これは[iCARE Dev Advent Calendar 2023](https://qiita.com/advent-calendar/2023/icare)の記事です。

普段はRuby on Rails、Vue.js、GraphQLを使用してWebアプリケーションの開発を行っており、ChatGPTを利用することがよくあります。

生成AIには業務や学習、それ以外の用途でも大変お世話になっているのですが、AIや機械学習の知識が一切ないまま活用してきたことに気づいたので、今回は実際にゼロから触れてみた機械学習の体験を入門編としてまとめてみました🎄

# 題材
実務では業務アプリケーションの開発を行っているので帳票を扱うことがしばしばあります。「帳票 AI」でGoogle検索すると「AI-OCR」という技術がヒットするため、OCRを体験してみました。

OCRにはいくつか工程があり、なかでも「文字検出」が機械学習に初めて触れた自分でもわかりやすい結果が得られたので、確定申告の帳票のサンプルを使ってご紹介します。

# まずは結果から💁‍♂️
元の帳票が↓だとして…
![test_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2574689/6cdba81c-f442-2416-6b00-6a6130aa1836.png)



未トレーニングの文字検出モデルを動かすと↓のような感じ。
![test_4_bad.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2574689/c6549204-90da-89f3-1fbb-255e02777fff.png)



↓トレーニング後のモデルで実行。文字検出の精度が少し上がっていることがわかります。
![test_4_trained.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2574689/26c9c3b3-6cdd-3dd1-6a66-a8328757f0c7.png)

※今回はトレーニング用のデータセットが充分に準備できなかったため期待する精度ではないですが、下記のようなデータを用意してトレーニングを行うことでさらなる精度の向上が見込めると思います。
- 「blur(ぼかし)」や「noise(ノイズ)」等で加工した帳票画像
- 帳票に記載され得る文章や文字のリスト(`所得の種類`、`収入金額`、`円`、`金`、`0`、`,` など)


# そもそもOCRってなんですか…？

*Optical Character Recognition*

ひとことで言うと「画像データからテキストを抽出する技術」。

画像内の文字をテキストデータとして扱いたいとき、
コンピューターは素の状態では人間のように手書きや画像内の文字を認識できないので、トレーニングされたOCRエンジンを使う必要があります。

これにより、紙の帳票→PDF(画像)データ→テキストデータのような変換が可能になります。


# OCRの処理フロー
```plantuml
@startuml
!theme cerulean-outline
skinparam rectangle {
    roundCorner 25
}
rectangle "文字検出" as Detection
rectangle "文字認識" as Recognition
rectangle "クラス分類" as Classification

Detection -right-> Recognition
Recognition -right-> Classification
@enduml
```

- 与えられた帳票(画像)から文字認識を行う。
- 画像を見て、「文字がどこか？」「何の文字か？」を判定する。
- 「クラス分類」に関してはOCRの処理フローの中に含めていますが、後述の全体の処理フローの中の「マッピング」に該当すると思います。

省略して `det` とか `rec` とか `clas` のような感じで表現することもあるようです。
(detection, recognition, classification の略)


# ざっくり全体の処理
上記のOCR処理からさらに俯瞰してみると下記のようなフローになっています。

```plantuml
@startuml
!theme cerulean-outline
skinparam rectangle {
    roundCorner 25
}
rectangle "前処理" as Preprocessing
rectangle "OCR" as OCR
rectangle "マッピング" as Mapping
rectangle "後処理" as Postprocessing

Preprocessing -right-> OCR
OCR -right-> Mapping
Mapping -right-> Postprocessing
@enduml
```


### 前処理

まずはPDFファイルをOCRで処理しやすい形に加工します。画像の補正やサブテーブルとセルの特定が含まれます。

### OCR

帳票(画像)から、文字を検出して読み取ります。

### マッピング

OCRの結果をもとに、テキストとその意味を結びつける作業です。どのテキストがどの項目に対応するかを割り当てます。これにより、単なるテキスト情報から意味のあるデータへと変換されます。


### 後処理

最後に、得られたデータを保存し、必要に応じてさらなる処理を行います。


# 使用ライブラリ
## PaddleOCR
https://github.com/PaddlePaddle/PaddleOCR

- オープンソースのOCRエンジンは複数提供されていますが、より日本語に近い言語を扱う中国発のライブラリを使用しています。


### 実行コマンド
モデルのトレーニングは `python3 tools/train.py` のようなコマンドで実行します。

```bash
# モデルのトレーニング
python3 tools/train.py \
        -c configs/rec/PP-OCRv3/multi_language/japan_PP-OCRv3_rec_my_product.yml \
        -o Global.pretrained_model=./pretrain_models/japan_PP-OCRv3_rec_train/best_accuracy.pdparams
```

- 必要があれば設定ファイルを編集し、`-c`でパスを指定します。
- `-o`でトレーニング済みモデルを指定します。
    - 機械学習において、０からモデルを学習することはなく、事前学習(pre-trained)されたモデルを使用しファインチューニング(微調整)しながらトレーニングを行うのが慣例のようです。



他にも下記のようなコマンドを使用しました。
```bash
# モデルの評価(どれくらい精度が向上したか確認する)
python3 tools/eval.py \
        -c configs/rec/PP-OCRv3/multi_language/japan_PP-OCRv3_rec_my_product.yml \
        -o Global.checkpoints=output/v3_japan_mobile/best_accuracy


# モデルのエクスポート(精度が良さそうなところでエクスポートして、他のAPIに組み込める状態にする)
python3 tools/export_model.py \
        -c configs/rec/PP-OCRv3/multi_language/japan_PP-OCRv3_rec_my_product.yml \
        -o Global.pretrained_model=./output/v3_japan_mobile/best_accuracy \
           Global.save_inference_dir=./inference/my_product_japan_PP-OCRv3_rec_inference
```

## その他使用ライブラリ
- [text_renderer](https://github.com/Sanster/text_renderer)
    - 画像ラベル(トレーニングに使用するデータセット)を生成するのに使用
- [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection)
    - 帳票内のセルを検出するのに使用
- [PaddleClas](https://github.com/PaddlePaddle/PaddleClas)
    - サブテーブルの分類に使用

# +α
①使用したDockerイメージ
```docker
paddle:2.4.2-gpu-cuda11.7-cudnn8.4-trt8.4
```
[https://www.paddlepaddle.org.cn/documentation/docs/en/2.4/install/docker/linux-docker_en.html](https://www.paddlepaddle.org.cn/documentation/docs/en/2.4/install/docker/linux-docker_en.html)


②PaddleOCRは現時点で`2.6.0`がStableなバージョンのようでした。
```bash
git checkout tags/v2.6.0 -b release/v2.6.0
```
[https://github.com/PaddlePaddle/PaddleOCR/releases/tag/v2.6.0](https://github.com/PaddlePaddle/PaddleOCR/releases/tag/v2.6.0)

# わかったこと
- AI(モデル)に様々なデータを入力すると学習し、出力する回答の精度が上がる。
- 効率良く精度を上げるには、与えるデータの種類とトレーニングの量が重要。
- AIは、与えたデータをカテゴライズしたり、与えたデータから未来を予測したり、与えたデータから新たな価値を生成したりして事業や製品の成長に貢献してくれる。

（これくらいの情報は少し調べればわかることなのですが、手を動かして実感できたのが良かったです）

# おすすめ書籍
https://one-publishing.co.jp/books/9784651203799/

非常にわかりやすく書かれていました。

# 〆

駆け足になりましたが、ふわっとOCRをご紹介しました。

業務のスコープ外の技術に触れることで視野を広げられたのと、機械学習の流れがイメージできるようになりました。何よりトレーニング後に精度が上がったときは「お〜」となりました。今後も学習をきっかけに感動できたらなと思います。