LayerX で機械学習エンジニアとして働いている松村 @yu-ya4 です。現在はAI-OCRチームにて、バクラクシリーズのOCR機能の開発を主に行なっています。この記事は LayerX Tech Advent Calendar 2022 の18日目の記事です。
OCR機能とは、アップロードされた請求書や領収書などの帳票の画像データを読み取り、人間が手入力せずとも必要な項目を自動で抽出してデータ化する機能のことです。以下は請求書OCR機能のデモ動画です。
このブログは、このようなOCR機能を誰でも簡単に実現してしまおうとしている Document AI というサービスを触って検証した際のメモ書きとなります。API を扱う Client ライブラリもいくつかの言語で公開されており、今回は Python を使いました。もしかしたら私の仕事がなくなるかもしれません。
Document AI とは
Document AI は2020年にリリースされた Google Cloud のサービスのひとつです。非構造化データである契約書や請求書などのドキュメントデータを対象に、テキストなどの情報を抽出したりそれらを構造化することで、データを理解、分析、利用しやすくすることを目的とします。
Document AI の種類(Processor と呼ぶ)は大きく以下の3つに分かれています。
- General
- 大方のドキュメントに対応した汎用的な機械学習モデルを利用
- Specialized
- 請求書や免許証、契約書など特定のドキュメントごとに特化して作成された機械学習モデルを利用
- Custom
- ユーザーが自前で用意したドキュメントを使って訓練した機械学習モデルを利用
Web 上でも好きな Processor を利用して任意のドキュメント(なければサンプルもあります)をアップロードすることで簡単に試せるので是非試してみてください。
事前準備
Cloud API を活用する際のいつものやつです。こちらに従って進めてください。
- Cloud Document AI API の有効化
- 今回利用するプロジェクトを選択した上で Document APIを有効化
- 認証設定
- 適切な権限を付与したサービスアカウントを作成して、アカウントキーを発行
- 発行したキーを実行環境にダウンロードし、パスを環境変数にセットする。
export GOOGLE_APPLICATION_CREDENTIALS="KEY_PATH"
- プロセッサインスタンスの作成
- 今回はドキュメントの中でも請求書を取り上げるので、Specialized Processor の中でも請求書に特化した Invoice Parser を選択
- 作成したインスタンスの ID は後ほど利用
Python Client を利用して Document AI API を試す
Client のインストール
今回の検証では Python Client を利用します。手元の M1 Mac において Python3.9 で検証しました。Python Client ライブラリは pip でインストール可能です。
$ python --version Python 3.9.15 $ pip install --upgrade google-cloud-documentai
利用する請求書データ
今回は以下のようなサンプルの請求書を使ってみます。「株式会社LayerZ」から「株式会社LayerX」に対して「2022/12/18」に発行された請求書です。合計請求金額は「66,000」で支払い期限は「2022/12/30」となっています。
API のリクエスト
あとは ドキュメントを参考に請求書ファイルを指定してAPIを叩きます。
from google.api_core.client_options import ClientOptions from google.cloud import documentai def process_document( project_id: str, location: str, processor_id: str, file_path: str, mime_type: str ): # Initialize opts = ClientOptions(api_endpoint=f"{location}-documentai.googleapis.com") client = documentai.DocumentProcessorServiceClient(client_options=opts) # The full resource name of the processor, e.g.: # projects/project_id/locations/location/processor/processor_id name = client.processor_path(project_id, location, processor_id) with open(file_path, "rb") as image: image_content = image.read() # Load Binary Data into Document AI RawDocument Object raw_document = documentai.RawDocument(content=image_content, mime_type=mime_type) # Configure the process request request = documentai.ProcessRequest(name=name, raw_document=raw_document) result = client.process_document(request=request) document = result.document return document # project_id = 'YOUR_PROJECT_ID' # location = 'YOUR_PROCESSOR_LOCATION' # Format is 'us' or 'eu' # processor_id = 'YOUR_PROCESSOR_ID' # Create processor before running sample # file_path = '/path/to/local/pdf' # mime_type = 'application/pdf' # Refer to https://cloud.google.com/document-ai/docs/file-types for supported file types document = process_document( project_id=project_id, location=location, processor_id=processor_id, file_path=file_path, mime_type=mime_type, )
請求書データの解析結果
読み取ったドキュメント内のテキスト情報には text
フィールドでアクセスします。なんとなく意味のある単位で単語が読み取れており、請求書として読み取りたい情報も含まれている気配がします。
>>> print(document.text) 2022/12/18 : lx-001 * LayerX LayerZ LEEF T012-3456 |||||1-1-1 CHRAN ¥ 66,000 - TEL: 09012341234 test@gmail.com 2022/12/30 • # #m 7077AXE 50 h 1,000 50,000 705 1 10,000 10,000 60,000 (10%) 6,000 Alt 66,000 =()0012345 LTÞ▬ť» |
Invoice Parser では、読み取ったテキストから請求書として読み取りたい項目ごとの値(entity)を識別します。その結果は entities
フィールドで取得できます。取得できた entitiy のうち適当なものを表示してみます。
>>> document.entities[3] text_anchor { text_segments { start_index: 111 end_index: 121 } content: "2022/12/30" } type_: "invoice_date" mention_text: "2022/12/30" confidence: 0.870477498 page_anchor { page_refs { bounding_poly { normalized_vertices { x: 0.190362886 y: 0.251892358 } normalized_vertices { x: 0.271267116 y: 0.251892358 } normalized_vertices { x: 0.271267116 y: 0.262825906 } normalized_vertices { x: 0.190362886 y: 0.262825906 } } } } id: "3" normalized_value { date_value { year: 2022 month: 12 day: 30 } text: "2022-12-30" }
こちらは type_: "invoice_date"
とあるように、請求書の発行日に該当する entity のようです。発行日として取得した値を見てみると mention_text: "2022/12/30"
となっています。請求書内の日付に関する情報をうまく取得できてはいるのですが、サンプルの請求書を見返すとこちらは「支払い期限」に当たる日付ですので、発行日をうまく識別できてはいなさそうです。
normalized_value
内で、「2022/12/30」-> 「2022-12-30」のように正規化した日付表現を返しているのは地味に便利ですね。
取得できたすべての entity の情報を表示します。参考までに元の請求書ファイルに取得した entity の位置を(手動で)マッピングしたものも用意しました。
>>> for e in document.entities: ... print(f"{e.type_}: {e.mention_text}") ... net_amount: 60,000 total_amount: 66,000 supplier_email: test@gmail.com invoice_date: 2022/12/30 total_tax_amount: 6,000 invoice_type: supplier_phone: 09012341234 supplier_name: LayerZ line_item: 50 h 1,000 50,000 line_item: 1 10,000 10,000
invoice_date 以外で取得できた entity については正しい情報となっていそうなことが分かります。表のそれぞれの情報を意味する line_item については、品番・品名に該当する「プロダクト開発業務」なども本来含めたかったようには思います。このようにドキュメント内で位置が離れているものをひとつの意味ある塊として認識するのは難しいと普段の業務でも実感しているため、とても気持ちが分かります。
また、本来 Invoice Parser では他にも、due_date(支払い期限)や receiver_name(請求先)など請求書読み取り機能としては重要な項目も entity として取得できるはずですが今回のケースではうまくいっていませんでした。
他に読み取れる項目など API の詳細については Invoice Parser のドキュメントを参照ください。
所感
他にもいくつかのパターンを試してみたのですが、少なくとも現時点では LayerX バクラク請求書の OCR 機能のほうが必要な情報を読み取れているようでした(仕事を失わずに済みそうでよかった)。特に、やはり日本語への対応は難しそうで、日付の表現を「2022年12月30日」と変えてみたり、請求書の発行者名を漢字の社名にしたりすると entity としては全然読み取れなくなってしまいました。
ただ、大前提として現在の Document AI の日本語対応は不十分な状態です。自然言語処理については OCR で読み取った日本語のテキスト情報を Translation AI にかけて翻訳することで対応しているとのことでした(【Google Cloud Day: Digital ’22】機械学習 セッションより)。また、海外で使われている請求書フォーマットと日本のフォーマットは同じ項目でも記載されている位置が異なっていたりするため、日本語をうまく扱えたとしても該当項目を識別することは困難な可能性が高いです。
一方で、日本語への対応は計画しているとのことなので、どこまでうまく読み取ることができるようになるのかは楽しみです。ただ、実務で大量の生の請求書データを扱っている身としては、あれだけ多種多様なフォーマットや表現を有する請求書を汎用的に読み取ることができる機械学習モデルを作成するのはなかなかに難しいのではないかと感じています。もうしばらく私の仕事はなくならなさそうです。
終わりに
今回は LayerX のバクラクシリーズにおける OCR 機能のように、ドキュメントを解析して必要な項目を読み取ることができる Google Cloud の Document AI、その中でも請求書に特化した Invoice Parser API の検証をしてみた結果を簡単に紹介しました。
LayerX ではOCR機能をいくつかの処理に分割し、一部はドメイン知識に基づくルール/ロジックを明示的に記述することで、そして一部は機械学習を用いることで実現しています。機械学習を用いる部分についても、外部のAPIを利用する部分、学習済みの公開モデルを利用する部分、そして独自の機械学習モデルを作成する部分、といったように分かれています。このように処理ごとに現在の状況に応じた適切な手段を採用することで、小さなチームでも最大限の価値をお客様に提供するべく効率的に開発を進めています。
独自の機械学習モデルの開発については、今年の3月に一人目の機械学習エンジニアが入社してから始まったものでありまだまだ発展途上にありますが、開発の取り組みについての発信も最近は増えてきており、ぜひチェックしてみてください。
LayerX における機械学習活用はまだまだ始まったばかりですが、機械学習エンジニアとして成果を出し成長していくための環境としては他にないくらいいいものだと自負しております。この辺りの話は私の LayerX への入社ブログに記していますので、こちらも是非ご覧ください。
Document AI に負けないためにも一緒にハタラク仲間を募集しています!まずはカジュアルにお話しできればと思いますので、お気軽に twitter のDMや以下のリンクから声をかけてください。