はじめに
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ファイルを対象としています。
今回、精度確認の為にオブジェクト内の埋め込み文章や、手書きの文章も加えています。
利用方法
実行方法
まず始めに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',
}
}
)
今回は文字列抽出を中心とした検証実施のため、StartDocumentTextDetection
APIを利用しましたが、他に表やフォームデータからのデータ抽出や請求書/領収書分析をおこなえるStartDocumentAnalysis
APIも用意されています。
入力データはS3に設置したファイルを指定する形です。
実行すると以下の様にJOB ID
返されます。
{
"JobId": "string"
}
実行ステータスの確認
StartDocumentTextDetection
APIは前述の通り非同期実行となるため、実行後に実行状況を確認する必要があります。
実行ステータスの確認はGetDocumentTextDetection
APIを利用します。
入力としては、StartDocumentTextDetection
APIの応答で返されたJOB ID
を指定します。
TextractResult = TxtractClient.get_document_text_detection(
JobId= TxtractStart['JobId']
)
実行すると以下の様にJOBStatus
が返されます。
{
'JobStatus': 'IN_PROGRESS',
'DetectDocumentTextModelVersion': '1.0',
略
}
実行結果の取得
JOBStatus
がSUCCEEDED
になると解析結果が取得できます。
解析結果の取得も実行ステータスの確認と同様にGetDocumentTextDetection
APIで取得することができます。
実行時の指定パラメータも同様でAPI実行の返却値に解析結果が含まれて応答されます。
具体的にはGetDocumentTextDetection
APIからの返り値にBlocks
オブジェクトが
含まれた形で返却され、Blocks
オブジェクト内に解析結果が含まれます。
{
'JobStatus': 'SUCCEEDED',
'DetectDocumentTextModelVersion': '1.0',
'Blocks':[
{
略
},
略
]
略
}
尚、注意点としては、GetDocumentTextDetection
で返却できる結果の上限は1000となっています。
そのため、ページ数が多いドキュメントをソースとして場合、この上限に達してしまい、1回のAPIコールでは全ての結果が返却されません。
結果の返却がすべて返せない場合、GetDocumentTextDetection
APIからNextToken
が発行されます。
{
'JobStatus': 'IN_PROGRESS',
'DetectDocumentTextModelVersion': '1.0',
'NextToken': 'XXXXXXX',
'Blocks':[
{
略
},
略
]
略
}
GetDocumentTextDetection
APIからNextToken
が返された場合は、以下の様にGetDocumentTextDetection
APIの入力にNextToken
を含めることにより、取得できなった値から取得することができます。
TextractResult = TxtractClient.get_document_text_detection(
JobId= TxtractStart['JobId']
NextToken='XXXXX'
)
実行時間について
今回3ページ程度のドキュメントの解析でしたが、30秒程度で完了いたしました。
解析結果について
解析結果の内容
解析結果については、前述の通りGetDocumentTextDetection
APIからの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 を触ってみましたが、利用方法も簡単で面白いサービスでした。
今後の日本語対応及び東京/大阪リージョンでのリリースに期待します。