こんにちは、サイオステクノロジーの佐藤 陽です。
今回は Azure の AI Services の 1 つである Azure AI Document Intelligence について入門していきたいと思います。
- PDF や画像データを扱いやすいデータにしたい!
- RAG の開発で PDF の情報を独自データとして活用したい!
- Document Intelligence から返ってくるパラメータの構造が分からない。
といった方は最後までご覧ください。
特に、3つ目のDocument Intelligence から返ってくるパラメータについて知りたい方はコチラへどうぞ!
AI Document Intelligence概要
Azure AI Document Intelligence は Azure AI Services に含まれるサービスのひとつであり、pdf ファイルや画像データからの文字起こしが可能となります。
Document Intelligence には様々な事前学習済みのモデルが提供されており、一般的な文章の文字起こしや、領収書や請求書などの読み取りなど様々なデータに対応することが可能です。
GUI ベースで操作も可能で、数クリックするだけで簡単に画像からテキストデータを取得し、活用しやすい形へと変換することができます。
また発展的な利用として、AI Document Intelligence と Azure AI Search を統合することで、RAG(Retrieval-Augmented Generation)をより強力なものにすることが可能ともいわれています。
リソース作成について
Document Intelligence のリソースなのですが
続々と Update が行われており、それらは以下のリージョンで先んじて行われているようです。
- East US
- West US2
- West Europe
最新の機能に触れるためにも、これらのリージョンでのリソース作成をお勧めします。
そもそもこれらのリージョンでないと、SDK が扱えなかったりするので注意です。
価格については、今回は Free プランで Document Intelligence のリソースを作成しました。
Free プランの制限として、pdf が最初の 2 ページしか読み取れなかったりしますが、検証には十分です。
また、おそらくですが Free プランは Azure のサブスクリプションあたり 1 つしか作成できません。
そのため新規に作成するためには既存のFreeプランのリソースを削除する必要があります。
ただ注意することとして、単にリソース削除するだけでは完全に削除されません。
「削除されたリソースの管理」というタブから完全に削除することで、新たに Free プランのリソースが作成できるようになります。
利用方法
Document Intelligence を利用する方法としては、以下 2 つがあります。
- Document Intelligence Studio
- REST API & SDK
Document Intelligence Studio
GUI ベースでさくっと機能をお試しできます。
今回はこちらをベースに作業していきたいと思います。
REST API & SDK
実際にシステムに組み込むとなったら API や SDK を活用することになります。
SDK としては C#や python 用のものが提供されています。
今回は利用しませんが、サンプルコードなども豊富なので是非見てみてください。
Model
DocumentIntelligenceのモデルは大きく分けて3種類あります
- Document analysis
- Prebuilt models
- Custom model
Document analysisとPrebuilt modelsは、Microsoft によって事前にトレーニングされた強力なモデル群です。
一方Custom modelに関しては、独自のトレーニングを行って作成するモデルになります。
本記事ではDocument analysisとPrebuild modelsにスポットを当てて紹介していきます。
Document analysis
Document Analysisの モデル群を使用すると、フォームやドキュメントからテキストを抽出し、文章を文字起こしすることが可能です。
一般的な文章や、論文の解析などに使われることが多いように思います。
このDocument analysisにおいては
- Read
- Layout
- General documents
の 3 種類のモデルが用意されています。
ただし、 General documents に関しては公式ドキュメントにおいて
Document Intelligence バージョン 2024-02-29-preview、2023-10-31-preview 以降、一般的なドキュメント モデル (事前構築済みドキュメント) は非推奨となりました。
とあるため、今回は説明から除外したいと思います。
後ほど詳しく解説しますが、ReadモデルとLayoutモデルの違いとしては
- Read:文章のテキストを抽出
- Layout:文章のテキストに加えて、ドキュメントの構造や表情報なども取得可能
といった感じです。
もちろん使用料金に関してはLayoutモデルの方が高い形となっています。
Layout
(順序的にはReadモデルの方が先ですが、記事の解説の都合でLayoutモデルから解説します。)
Layout モデルは、文章からテキストだけではなく、構造や表情報なども取得することが可能です。
また文章の Markdown への変換機能も備えており、このあたりも非常に強力です。
今回、文字起こしの対象とするデータとして、以下のような pdf データを用意しました。
表やグラフ、チェックボックスを含むよう作成しています。
(なお文章の内容に関しては ChatGPT に適当に作ってもらったものなので、参考にしないでください。)
では以下のステップで分析の方進めていきます。
- Document Intelligence Studio から Layout のモデルを選択
- Browse for files から pdf をアップロード
- Run analysis のボタンをクリック
解析が完了すると、pdf 上にマーキングがされ、結果が右側のエリアに表示されます。
細かいパラメータは後ほど見ていきますが、ひとまず文章が正しく書き起こされていることが確認できます。
また、テーブル情報もチェックボックス情報も正しく読み取れていることが確認できます。
ただ、さすがに絵文字はうまく認識してくれませんでした😅
Resultパラメータ解説
次に Result タブの内容を見てみます。
ここには、解析された結果が json 形式で表示されます。
ちなみにREST API や SDK を利用した場合も、この json 形式と同じフォーマットとして分析結果が得られます。
なお、これらのjsonの中には以下のような情報が含まれています。
- SDK や API 、モデルなどの情報
- 要素の位置
- 要素の大きさ
- 文章の内容
- 構造(要素の親子関係)
- 信頼度
中身を見ると非常に細かい情報まで返してくれているのですが、いかんせん分かりづらいです。
そのため、今回はこのResultのパラメータについて細かく見ていきたいと思います!
Result に説明コメントを付けて、以下のようなjson形式で表しました。
(可読性向上のため、内容を抜粋して書いています。)
{
"apiVersion": "2024-02-29-preview", //使用されたAPIバージョン
"modelId": "prebuilt-layout", //使用されたモデルID
"stringIndexType": "textElements", //文字列のオフセットと長さを計算する方法
"content": "", //全体の文章,
"pages": [//抽出されたコンテンツ要素とレイアウト要素
{
"pageNumber": 1,
"angle": 0, //角度(時計回りの方向のコンテンツの一般的な向き)
"width": 8.5, //イメージ/PDF の幅
"height": 11, //画像/PDF の高さ
"unit": "inch", //幅、高さ、境界ポリゴンのプロパティで使用される単位
"words": [
//ページから抽出された単語
{
"content": "SIOS", //テキスト. ※日本語の場合は1文字ずつ
"polygon": [
//ページの左上を基準にして座標を指定した、単語の境界ポリゴン
0.9898, //左上x座標
1.1093, //左上y座標
1.4297, //右上x座標
1.1097, //右上y座標
1.4266, //右下x座標
1.2766, //右下y座標
0.9868, //左下x座標
1.2779 //左下y座標
],
"confidence": 0.989, //単語を正しく抽出する信頼度
"span": {
//読み取り順序の連結されたコンテンツ内の単語の場所
"offset": 0, //スパンで表されるコンテンツの 0 から始まるインデックス
"length": 4 //スパンで表されるコンテンツ内の文字数
}
}
],
"selectionMarks": [ //チェック ボックス、ラジオ ボタン、および選択範囲を示すその他の要素を表す選択マーク オブジェクト。
{
"state": "unselected", //選択されているかどうか(selected,unselected)
"polygon": [
//選択マークの境界ポリゴン。
//略
],
"confidence": 0.988, //選択マークを正しく抽出する信頼度
"span": {
//読み取り順序の連結されたコンテンツ内の選択マークの位置
"offset": 1241,
"length": 12
}
}
],
"lines": [
//単語や選択マークなどのコンテンツ要素の隣接するシーケンスで構成されるコンテンツ行オブジェクト。
{
"content": "SIOS HOGEHOGE TECHONLOGY", //コンテンツ
"polygon": [
//略
],
"spans": [
//linesのoffsetとspan
{
"offset": 0,
"length": 24
}
]
}
],
"spans": [
//page自体のoffsetとspan
{
"offset": 0,
"length": 639
}
]
}
],
"tables": [
{
"rowCount": 5, //行数
"columnCount": 3, //列数
"cells": [
//テーブルに含まれるセル情報
{
"kind": "columnHeader", //セルの種類(content,rowHeader,columnHeader,stubHead,description)
"rowIndex": 0, //行のインデックス
"columnIndex": 0, //列のインデックス
"content": "技術分野", //セルの内容
"boundingRegions": [
//テーブルセルをカバーする境界領域
{
"pageNumber": 1, //境界領域を含む 1 から始まるページ番号
"polygon": [
//ページ上の多角形の境界、または指定されていない場合はページ全体。左上を基準にして指定された座標.
//略
]
}
],
"spans": [
{
"offset": 491,
"length": 4
}
],
"elements": [
//テーブル セルの子要素
"/paragraphs/8"
]
}
]
}
],
"paragraphs": [//一般的に、一般的な配置と間隔を持つ連続した行で構成される段落オブジェクト。
{
"spans": [
{
"offset": 63,
"length": 17
}
],
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [
//略
]
}
],
"role": "sectionHeading", //段落のセマンティックロール(FOOTNOTE, FORMULA_BLOCK,PAGE_FOOTER,PAGE_HEADER,PAGE_NUMBER,SECTION_HEADING,TITLE)
"content": "# 調査概要 2024 年9月4日"
}
],
"contentFormat": "markdown",
"sections": [
//ドキュメント内のセクションを表すオブジェクト。
{
"spans": [
//読み取り順序の連結されたコンテンツ内の単語の場所
{
"offset": 0,
"length": 60
}
],
"elements": [
//セクションの子要素。
"/sections/1"
]
}
],
"figures": [
{
"id": "2.1", //不明
"boundingRegions": [
{
"pageNumber": 2,
"polygon": [
//略
]
}
],
"spans": [
{
"offset": 639,
"length": 289
}
],
"elements": [
//図の子要素(キャプションや脚注を除く)
"/paragraphs/23"
]
}
]
}
これで各パラメータの内容に関して雰囲気はつかめるかと思うのですが、もう少し詳しく解説していきたいと思います。
構造について
Resultのjsonを構成する主な要素として、以下の配列オブジェクトがあります。
- pages(ページ)
- tables(表)
- paragraphs(段落)
- sections(セクション)
- figures(図)
各要素について何となく名前から想像がつくのですが、それぞれの関係性がやや分かりづらく感じました。
そこでjsonの中から構造(親子関係)を抜き出し、階層関係をまとめてみます。
(それぞれの要素が elements というパラメータを持っており、このパラメータにて構造(親子関係)が表現されています。)
※階層が深すぎると分かりづらいので、paragraphsを最下層として書いています。
※重複している部分などはだいぶ省略して書いています。
sections/0
/sections/1
/paragraphs/0:"SIOS HOGEHOGE TECHONLOGY 111-1111 東京都ホゲ村 ホゲ番地 (+81) 000-0000"
/sections/2
/paragraphs/1:"調査概要 2024 年9月4日"
/sections/3
/paragraphs/2:"調査目的"
/paragraphs/3:""本市場調査の目的は、最新の IT 技術動向を詳細に把握し、各技術の市場シェア、成長予測、およ び競争状況を包括的に明らかにすることであり、特にクラウドコンピューティング、AI(人工知能)、loT (モノのインターネット)、およびブロックチェーン技術の各分野に焦点を当てるものである。"
/sections/4
/paragraphs/4:"調査方法"
/paragraphs/5:"1. プライマリーデータはアンケート調査およびインタビューによって収集し、直接的かつ現場の 視点から得られる情報を重視する一方で、セカンダリーデータは公開データベースおよび業 界レポートから取得し、信頼性の高い既存の情報源を利用して補完的なデータ収集を行う。"
/paragraphs/6:"2. データ分析に関しては、定量分析として統計解析ソフトウェアを駆使して大量の数値データを 精緻に解析し、定性分析として内容分析およびテーマ別分析を行い、収集されたデータの質 的側面を多角的に検討する。"
/sections/5
paragraphs/7:"市場概況"
tables/0
cells/0
paragraphs/11":"クラウドコンピューティング"
paragraphs/8 "技術分野"
figures/0
paragraph/23~41 :"Market Size and Growth Rate of Major Technology Fields"
sections/6
paragraphs/42:"技術別市場シェア"
sections/7
paragraphs/43:"クラウドコンピューティング ♡"
sections/8
paragraphs/45:"AIN"
paragraphs/46:"AI 技術に関しては、IBM が市場シェアの 25%を占め、Google が 20%、Microsoft が 18%、その他が 37%を占めている。"
sections/9
paragraphs/47:"ブロックチェーン"
また、このまま分かりずらいので図との対応表を作成しました。
このような形で pdf が各要素に分解され、それぞれの要素において位置情報やコンテンツの内容を含む構造となっています。
なおparagraphs/8という表現は、jsonにおけるparagraphs[]配列の8番目の要素を表しています。
この時に気を付けたい点としては、json の階層と pdfの要素の階層は一致していない!ということです。
例えば json の階層としては pragraphs と sections は同じ階層にありますが、
pdf要素 としては sections が paragraphs を含むようになっています。
このあたり別に考える必要があるため気を付けましょう!
Enum値について
"role": "sectionHeading", //段落のセマンティックロール(FOOTNOTE, FORMULA_BLOCK,PAGE_FOOTER,PAGE_HEADER,PAGE_NUMBER,SECTION_HEADING,TITLE)
といったようなEnum値の内容に関しては、公式ドキュメントに説明があるのでこちらを参照ください。
wordの扱いについて
pagesの配列の中にwordという要素が存在しています。
このwordに関して、日本語においては文字が1文字ずつ分割されてしまいます。
"words": [
{
"content": "概",
"polygon": [
],
"confidence": 0.995,
"span": {
"offset": 63,
"length": 1
}
},
{
"content": "要",
"polygon": [
これは公式ドキュメントにも書いてある通りです。
単語間にスペース区切りを使用しない言語の場合、セマンティックな単語単位を表していない場合でも、各文字は個別の単語として返されます。
そのため、日本語の文章を分析するとpagesの配列が膨大になりがちです。
この点、今後の改善に期待です。
その他のパラメータ
分析対象とする pdf の内容によっては、記事の中で触れていない要素が出てくる場合もあります。
そういった場合は公式ドキュメントにて各要素のクラスが定義しているため確認してみてください。
Markdownへの変換
Layoutモデルの強力な機能のひとつとして、Markdownへの変換があります。
Analyze optionsのボタンをクリックし、その中でOutput form styleをMarkdownにします。
この状態で分析を行うと、Markdownというタブでの結果が表示されます。
また、Resultの中に入っている最上位のcontentの中身がMarkdownの形式として出力されます。
精度は完ぺきではないですが、このくらいのレベルでpdfをMarkdownに変換してくれるのは助かります。
文章の構造を認識できるLayoutモデルならではの機能ですね。
Markdownへ変換するメリット
Layoutモデルの機能として、Markdownへ変換が可能なことが分かりました。
これによって得られるメリットとして、生成AIとの親和性の高さが言えるかと思います。
プロンプトエンジニアリングの一つに「明確な構文を追加する」というものがあります。
また、さらに
使用する構文がわからない場合は、Markdown または XML の使用を検討してください。 モデルは、XML と Markdown の大量の Web コンテンツでトレーニングされており、より良い結果が得られる可能性があります。
といった記載もみられます。
つまり、生成AIはMarkdownの構文を理解しやすいということが言えます。
そのため、Document Intelligenceで抽出したMarkdownのテキストを生成AIに投げることによって、より質の高い回答が得られることが期待できます。
Document IntelligenceとRAGを組み合わせたケースなどで効果を発揮しそうですね。
手書き文書
先程はpdfということで、文字崩れがないデータの読み取りを行いました。
一方で「手書きの文章の画像データを読み込む」というユースケースも大いにあり得るかと思います。
分析を行う画像として、以下のものを用意しました。
それでは分析してみます。
さすがにだいぶ崩した文章は難しいですが、それなりに汚い字でも正しく読み取ってくれました。
またこの時、Resultのjsonの中身を見てみると、先程までは含まれていなかった
- styles
という配列オブジェクトが見られました。
中身としては以下のような感じです。
"styles": [ //観察されたテキストスタイルを表すオブジェクト
{
"confidence": 1, //信頼度
"spans": [
{
"offset": 0,
"length": 30
}
],
"isHandwritten": true //コンテンツが手書きかどうかを示す
}
基本的には先ほども出てきたパラメータですが、isHandWrittenのパラメータが新規なパラメータとして存在しています。
その名の通りですが、手書きである事の判定パラメータであり、判定が正しく行われています。
Read
次に Read のモデルを見ていきます。
Read は Layout と比較して、文章のテキスト読み取りだけの機能を持ちます。
そのため文章の構造情報やテーブル情報などは読み取ることができません。
早速 Read モデルを利用し、先程と同じ pdf を分析してみます。
結果のタブを見ると「Text」しかなく、Layout で見られたような「Tables」や「Selection marks」などが無いことが分かります。
次に Result タブから json 形式の値も見てみたいと思います。
先ほど挙げた主な構成要素に関してみてみると、Layoutと比較して
- pages
- paragraphs
しか含まれていないことが分かります。
Layoutモデル に含まれていた
- tables
- sections
- figures
に関しては存在していません。
これが構造に関する情報の読み取りをしていないということの表れでもあります。
テキストだけ分かればいいというのであれば Read モデルで十分という判断ができそうです。
ちなみに Layout と Read では使用するにあたり、価格が異なります。
Prebuild models
事前構築済みモデルを使用することで、独自モデルのトレーニングや構築をしなくても様々なドキュメントを処理することができます。
Document analysisは一般文書がターゲットでしたが、こちらの事前構築済みモデルは請求書、領収書、名刺といった特定のドキュメントの解析に対する強みを持ちます。
様々なモデルがありすぎるので、全部は試せませんが
今回は名刺の分析を行ってみたいと思います。
Business cards
名刺のモデルを選択し、先程と同じステップを踏んで分析していきます。
今回は用意されているサンプル画像を利用します。
早速分析してみると、正しく各情報が抽出できていることが確認できます。
また、Resultの値を見ると
- documents
という配列オブジェクトがあるのが分かります。
中身を少し見てみると、docTypeとしてbusinessCardが指定されており
その下のfieldsの中で、住所や氏名情報が含まれていることが分かります。
"documents": [
{
"docType": "businessCard",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [
0,
0,
1024,
0,
1024,
768,
0,
768
]
}
],
"fields": {
"Addresses": {
"type": "array",
"valueArray": [
{
"type": "address",
"content": "〒108-0075 東京都港区港南 2-16-3"
まとめ
今回は、Azure AI Servicesの一つであるAzure AI Document Intelligenceに入門してみました。
Document Intelligence Studioという、GUIでも扱いやすいサービスも提供されており、簡単に画像の分析ができることが分かりました。
ただ返されるパラメータがやや複雑ということもあり、その点は本記事を通して理解してもらえればと思います。
また、今回は入門編ということで基本的な機能だけを触っています。
まだまだ触れていない機能が盛りだくさんなので、引き続き勉強して記事にしていこうと思います
ではまた!
参考
Azure AI Document Intelligence のドキュメント
【最新】Azure AI Document Intelligence による文書構造の解析(Markdown、図、セクション)