AWS Textract を試してみた

Pocket

はじめに

AWS の textract を利用して PDF ファイルから文字列抽出を試してみました。

AWS Textract とは

AWSの公式の説明では以下の通りです。

Amazon Textract は、スキャンしたドキュメントからテキスト、手書き文字、およびデータを自動的に抽出する機械学習 (ML) サービスです。これは、単純な光学文字認識 (OCR) のレベルにとどまらず、フォームやラベルからデータを識別、理解、および抽出します。

https://aws.amazon.com/jp/textract/

対応するファイル形式は画像 (PNG、TIFF または JPEG)及び PDF ファイルとなります。
対応する言語は現状では、英語、スペイン語、イタリア語、ポルトガル語、フランス語、ドイツ語となっており、残念ながら日本語に対応していません。
対応リージョンに関してもまだ日本のリージョンでは対応していない状況となっています。そのため、今回はオレゴンリージョンを利用してためしてみました。

今回の検証内容

今回は英語で掛かれたPDFファイルを利用いたしました。
Textractの実行は Python(boto3)を利用した検証としています。

余談ですが検証用のサンプル文章は ChatGPT で適当な文章を作ってもらいました。
文字数としては2500文字程度で3ページのPDFファイルを対象としています。

image1

今回、精度確認の為にオブジェクト内の埋め込み文章や、手書きの文章も加えています。

image2

image3

利用方法

実行方法

まず始めにtextractに対して入力指定をして実行させます。
PDFファイルからのテキスト抽出については、非同期実行となり、StartDocumentTextDetection API を利用したコードとなります。
具体的には以下の様なコードとなります。

import boto3

my_session = boto3.Session(profile_name='profile_name')
TxtractClient = my_session.client('textract', region_name="us-west-2")

TxtractStart = TxtractClient.start_document_text_detection(
    DocumentLocation={
        'S3Object': {
            'Bucket': 'Bucket Name',
            'Name': 'XXXX.pdf',
        }
    }
)

今回は文字列抽出を中心とした検証実施のため、StartDocumentTextDetectionAPIを利用しましたが、他に表やフォームデータからのデータ抽出や請求書/領収書分析をおこなえるStartDocumentAnalysisAPIも用意されています。

入力データはS3に設置したファイルを指定する形です。

実行すると以下の様にJOB ID返されます。

{
   "JobId": "string"
}

実行ステータスの確認

StartDocumentTextDetectionAPIは前述の通り非同期実行となるため、実行後に実行状況を確認する必要があります。

実行ステータスの確認はGetDocumentTextDetectionAPIを利用します。
入力としては、StartDocumentTextDetectionAPIの応答で返されたJOB IDを指定します。

TextractResult = TxtractClient.get_document_text_detection(
    JobId= TxtractStart['JobId']
)

実行すると以下の様にJOBStatusが返されます。

{
    'JobStatus': 'IN_PROGRESS', 
    'DetectDocumentTextModelVersion': '1.0',
     略
}

実行結果の取得

JOBStatusSUCCEEDEDになると解析結果が取得できます。
解析結果の取得も実行ステータスの確認と同様にGetDocumentTextDetectionAPIで取得することができます。

実行時の指定パラメータも同様でAPI実行の返却値に解析結果が含まれて応答されます。
具体的にはGetDocumentTextDetectionAPIからの返り値にBlocksオブジェクトが
含まれた形で返却され、Blocksオブジェクト内に解析結果が含まれます。

{
    'JobStatus': 'SUCCEEDED', 
    'DetectDocumentTextModelVersion': '1.0',
    'Blocks':[
        {
            略
        },
       略
    ]
     略
}

尚、注意点としては、GetDocumentTextDetectionで返却できる結果の上限は1000となっています。
そのため、ページ数が多いドキュメントをソースとして場合、この上限に達してしまい、1回のAPIコールでは全ての結果が返却されません。
結果の返却がすべて返せない場合、GetDocumentTextDetectionAPIからNextTokenが発行されます。

{
    'JobStatus': 'IN_PROGRESS', 
    'DetectDocumentTextModelVersion': '1.0',
    'NextToken': 'XXXXXXX',
    'Blocks':[
        {
            略
        },
       略
    ]
     略
}

GetDocumentTextDetectionAPIからNextTokenが返された場合は、以下の様にGetDocumentTextDetectionAPIの入力にNextTokenを含めることにより、取得できなった値から取得することができます。

TextractResult = TxtractClient.get_document_text_detection(
    JobId= TxtractStart['JobId']
    NextToken='XXXXX'
)

実行時間について

今回3ページ程度のドキュメントの解析でしたが、30秒程度で完了いたしました。

解析結果について

解析結果の内容

解析結果については、前述の通りGetDocumentTextDetectionAPIからのBlocksオブジェクトに含まれた形で返されます。

Blocksオブジェクトではドキュメントの単位の抽出結果と、単語単位の抽出結果が出力されます。
具体例は以下の通りです。

    {
        "BlockType": "LINE",
        "Confidence": 99.97674560546875,
        "Text": "Cloud computing is a technology that allows users to access",
        "Geometry": {
            "BoundingBox": {
                "Width": 0.6183375716209412,
                "Height": 0.015160156413912773,
                "Left": 0.14295847713947296,
                "Top": 0.12277334928512573
            },
            "Polygon": [
                {
                    "X": 0.1429687887430191,
                    "Y": 0.12277334928512573
                },
                {
                    "X": 0.7612960934638977,
                    "Y": 0.12363825738430023
                },
                {
                    "X": 0.7612884640693665,
                    "Y": 0.13793350756168365
                },
                {
                    "X": 0.14295847713947296,
                    "Y": 0.13706855475902557
                }
            ]
        },
        "Id": "254870c7-997f-4a98-8bd9-258f22903bd9",
        "Relationships": [
            {
                "Type": "CHILD",
                "Ids": [
                    "36a23618-ff80-43cc-a52e-3ceb307b3ca0",
                    "2c768f5c-edde-4abf-a76a-9dda15d58e74",
                    "6e02d71a-e743-4349-a60f-5d16395b1913",
                    "f14300a7-57ee-4cab-9c01-1ddb25ffed61",
                    "c3163e3a-3221-4bfa-bed1-932db47292cc",
                    "cd553dda-8860-4717-b9dc-bc9e7dfb4eef",
                    "bd30df0b-681d-475e-a2df-a11194d2115b",
                    "2bbab066-2950-4072-b89b-b87375288ae3",
                    "f612fcd0-6a23-461b-8bdf-cacbe224ecc8",
                    "8d4d867d-319c-4b5f-99d8-b96765c3a69f"
                ]
            }
        ],
        "Page": 1
    },

単位の抽出結果は"BlockType": "LINE"となり、Textに行単位の抽出文字列が返されます。
また、信頼度やドキュメント内の位置情報に関しても返されます。

Relationshipsでは、単語単位の抽出結果との関連性が返されます。

尚、文章としての抽出ではなく単位の抽出結果となるため、複数行に渡る文章の場合は、行単位で分割される結果となります。

次に単語単位の抽出結果は以下の通りです。
(ここでは行単位の抽出結果と関連性のある36a23618-ff80-43cc-a52e-3ceb307b3ca0の結果を記載します。)

    {
        "BlockType": "WORD",
        "Confidence": 99.96621704101562,
        "Text": "Cloud",
        "TextType": "PRINTED",
        "Geometry": {
            "BoundingBox": {
                "Width": 0.05831551179289818,
                "Height": 0.012241126969456673,
                "Left": 0.1429593712091446,
                "Top": 0.12367869913578033
            },
            "Polygon": [
                {
                    "X": 0.14296813309192657,
                    "Y": 0.12367869913578033
                },
                {
                    "X": 0.20127487182617188,
                    "Y": 0.12376026064157486
                },
                {
                    "X": 0.2012663185596466,
                    "Y": 0.13591982424259186
                },
                {
                    "X": 0.1429593712091446,
                    "Y": 0.13583827018737793
                }
            ]
        },
        "Id": "36a23618-ff80-43cc-a52e-3ceb307b3ca0",
        "Page": 1
    },

単語単位の抽出結果は"BlockType": "WORD"となり、Textに抽出単語が返されます。
本例ではTextの結果が Cloud となっていますが、先程提示した単位の抽出結果に含まれている単語となっています。

"BlockType": "LINE"と同様に信頼度やドキュメント内の位置情報に関しても返されますが、Relationshipsは返されませんので、単語の抽出結果から該当行の特定は出来ない仕様です。

解析精度ついて

解析精度については平文で書かれた文章については、誤りが1件もありませんでした。
一点だけ注意が必要と感じたのは、仕方ない部分ではありますが1単語が複数の行に跨って記載されている場合は行毎に分割されて解析されていました。

(入力)
popular in recent years, due to its flexibility, scalability, and cost-
effectiveness.

(解析結果)
cost-effectiveness が「cost-」と「effectiveness」と分割して解析

オブジェクト内の解析に関しても誤りがなく解析された結果となりました。

最後に手書き文章ですが、文章としては認識されましたが、「HAND TEST」が「AND TEST」と解析されていました。
こちらは私の手書き文字が汚かったところが原因で綺麗な手書き文字であれば正確な精度が出たものと思われます。

まとめ

初めて Textract を触ってみましたが、利用方法も簡単で面白いサービスでした。
今後の日本語対応及び東京/大阪リージョンでのリリースに期待します。

Pocket

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です