Pix2Struct と OpenVINO™ を使用した文書による視覚的な質問回答

この Jupyter ノートブックはオンラインで起動でき、ブラウザーのウィンドウで対話型環境を開きます。ローカルにインストールすることもできます。次のオプションのいずれかを選択します。

Google Colab GitHub

DocVQA (Document Visual Question Answering) は、スキャンされた文書、スクリーンショット、テキスト文書の画像など、画像形式で表現された文書の内容に関連する質問に回答するアルゴリズムの開発に重点を置いた、コンピューター・ビジョンと自然言語処理の研究分野です。画像やビデオに関連する質問への回答に重点を置く他の視覚的な質問回答とは異なり、DocVQA は、ドキュメントのテキストとレイアウトに基づいて質問を理解し、回答することに重点を置いています。質問は、文書テキストのあらゆる側面について行うことができます。DocVQA では、ドキュメントの視覚的なコンテンツを理解し、その中のテキストを理解する能力が必要です。

DocVQA には、OCR (光学文字認識) テクノロジーと比較していくつかの利点があります。

  • まず、DocVQA はドキュメントからテキストを認識して抽出できるだけでなく、テキストが出現するコンテキストも理解できます。つまり、単にデジタル版を提供するだけでなく、文書の内容に関する質問に答えることができるということです。
  • 第二に、DocVQA は、従来の OCR システムでは困難な、表や図などの複雑なレイアウトや構造を持つ文書を処理できます。
  • 最後に、DocVQA は、ドキュメントのルーティングや承認プロセスなど、多くのドキュメント・ベースのワークフローを自動化し、従業員がより有意義な作業に集中できるようにします。DocVQA の潜在的な用途には、情報検索、ドキュメント分析、ドキュメント要約などのタスクの自動化が含まれます。

Pix2Struct は、画像から情報を簡単に抽出できる、視覚的に位置付けられた言語を理解するためのマルチモーダル・モデルです。このモデルは、ウェブページのマスクされたスクリーンショットを簡略化された HTML に解析する新しい学習手法を使用してトレーニングされ、OCR、視覚的な質問回答、画像キャプション作成などのさまざまな下流のアクティビティーに非常に適した事前トレーニング・データ・ソースを提供します。

このチュートリアルでは、ドキュメントの視覚的な質問応答タスクを解決するため、OpenVINO を使用して Pix2Struct モデルを実行する方法について説明します。Hugging Face Transformers ライブラリーの事前トレーニング済みモデルを使用します。ユーザー・エクスペリエンスを簡素化するために、Hugging Face の Optimum ライブラリーを使用してモデルを OpenVINO™ IR 形式に変換します。

目次

Pix2Struct について

Pix2Struct は、画像キャプション作成や視覚的な質問への回答など、さまざまなタスク用に画像とテキストのペアでトレーニングされた画像エンコーダー、テキスト・デコーダー・モデルです。このモデルは、純粋にピクセルレベルの入力のシンプルさと、多様で豊富なウェブデータからの自己教師あり事前トレーニングによって提供される一般性とスケーラビリティーを兼ね備えています。モデルは、部分的にマスクされたウェブページのスクリーンショットから HTML ベースの解析を予測する必要があるスクリーンショット解析目標を推奨することによってこれを実現します。ウェブ上のテキスト要素と視覚要素の多様性と複雑さを考慮して、Pix2Struct はウェブページの基礎となる構造の豊富な表現を学習し、それをさまざまな下流の視覚言語理解タスクに効果的に転送できます。

Pix2Struct は、入力表現を変更してさまざまなアスペクト比の画像の処理に対してモデルをより堅牢にする、画像エンコーダー・テキスト・デコーダー・モデルである Vision Transformer (ViT) に基づいています。標準 ViT は、入力画像を所定の解像度にスケーリングした後、固定サイズのパッチを抽出します。これにより、画像の適切なアスペクト比が歪んでしまい、ドキュメント、モバイル UI、図によって大きく変化する可能性があります。Pix2Struct は、指定されたシーケンスの長さに収まるパッチの最大数を抽出するために、入力画像を拡大または縮小することを提案します。このアプローチは、Pix2Struct が実験する領域で一般的な極端なアスペクト比に対してより堅牢です。さらに、このモデルは、シーケンスの長さと解像度のオンザフライの変更を処理できます。可変解像度を明確に処理するために、入力パッチには 2 次元の絶対位置埋め込みが使用されます。

必要条件

最初に、OpenVINO 統合によって高速化された Hugging Face Optimum ライブラリーをインストールする必要があります。Hugging Face Optimum API は、Hugging Face Transformers ライブラリーのモデルを OpenVINO™ IR 形式に変換および量子化できる高レベル API です。詳細については、Hugging Face Optimum のドキュメントを参照してください。

%pip install -q torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
%pip install -q "git+https://github.com/huggingface/optimum-intel.git" "openvino>=2023.1.0" "transformers>=4.33.0" onnx gradio --extra-index-url https://download.pytorch.org/whl/cpu

モデルのダウンロードと変換

Optimum Intel を使用すると、Hugging Face Hub から最適化されたモデルをロードし、Hugging Face API を使用して OpenVINO ランタイムで推論を実行するパイプラインを作成できます。Optimum 推論モデルは、Hugging Face Transformers モデルと API の互換性があります。つまり、AutoModelForXxx クラスを対応する OVModelForXxx クラスに置き換えるだけで済みます。

モデルクラスの初期化は、from_pretrained メソッドの呼び出しから始まります。Transformers モデルをダウンロードして変換する場合は、パラメーター export=True を追加する必要があります。save_pretrained メソッドを使用して、変換されたモデルを次回に使用するため保存できます。save_pretrained メソッドを使用してモデルを保存した後、export パラメーターなしで変換されたモデルをロードして、次回のモデル変換を回避できます。メモリー消費を削減するため、half() メソッドを使用してモデルを float16 に圧縮できます。

このチュートリアルでは、モデルのエクスポートと読み込みを分離して、両方のモードでモデルを操作する方法を説明します。このチュートリアルでは、pix2struct-docvqa-base モデルを例として使用しますが、pix2struct ファミリーの他のモデルにも同じ実行手順が適用されます。

import gc
from pathlib import Path
from optimum.intel.openvino import OVModelForPix2Struct

model_id = "google/pix2struct-docvqa-base"
model_dir = Path(model_id.split('/')[-1])

if not model_dir.exists():
    ov_model = OVModelForPix2Struct.from_pretrained(model_id, export=True, compile=False)
    ov_model.half()
    ov_model.save_pretrained(model_dir)
    del ov_model
    gc.collect();
INFO:nncf:NNCF initialized successfully. Supported frameworks detected: torch, tensorflow, onnx, openvino
No CUDA runtime is found, using CUDA_HOME='/usr/local/cuda'
2023-10-20 13:49:09.525682: I tensorflow/core/util/port.cc:110] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable TF_ENABLE_ONEDNN_OPTS=0.
2023-10-20 13:49:09.565139: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.
To enable the following instructions: AVX2 AVX512F AVX512_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.
2023-10-20 13:49:10.397504: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT
/home/ea/work/ov_venv/lib/python3.8/site-packages/transformers/deepspeed.py:23: FutureWarning: transformers.deepspeed module is deprecated and will be removed in a future version. Please import deepspeed modules directly from transformers.integrations
  warnings.warn(

推論デバイスの選択

OpenVINO を使用して推論を実行するためにドロップダウン・リストからデバイスを選択します。

import ipywidgets as widgets
import openvino as ov

core = ov.Core()

device = widgets.Dropdown(
    options=[d for d in core.available_devices if "GPU" not in d] + ["AUTO"],
    value='AUTO',
    description='Device:',
    disabled=False,
)


device
Dropdown(description='Device:', index=1, options=('CPU', 'AUTO'), value='AUTO')

モデルの推論をテスト

以下の図は、モデルがどのように機能するかを示しています。
pix2struct_diagram.png

モデル推論を実行するには、まずデータを前処理する必要があります。Pix2StructProcessor は、元の PyTorch モデルの入力データの準備と出力のデコードを担当し、Optimum Intel モデルでの実行に簡単に再利用できます。次に、OVModelForPix2Struct.generate メソッドが回答の生成を開始します。最後に、生成された回答トークン・インデックスは、Pix2StructProcessor.decode でテキスト形式でデコードする必要があります。

from transformers import Pix2StructProcessor

processor = Pix2StructProcessor.from_pretrained(model_id)
ov_model = OVModelForPix2Struct.from_pretrained(model_dir, device=device.value)
Compiling the encoder to AUTO ...
Compiling the decoder to AUTO ...
Compiling the decoder to AUTO ...

実際のモデルを見てみましょう。モデルのテストには、OpenVINOドキュメントのスクリーンショットを使用します。

import requests
from PIL import Image
from io import BytesIO


def load_image(image_file):
    response = requests.get(image_file)
    image = Image.open(BytesIO(response.content)).convert("RGB")
    return image

test_image_url = "https://github.com/openvinotoolkit/openvino_notebooks/assets/29454499/aa46ef0c-c14d-4bab-8bb7-3b22fe73f6bc"

image = load_image(test_image_url)
text = "What performance hints do?"

inputs = processor(images=image, text=text, return_tensors="pt")
display(image)
../_images/260-pix2struct-docvqa-with-output_11_0.png
answer_tokens = ov_model.generate(**inputs)
answer = processor.decode(answer_tokens[0], skip_special_tokens=True)
print(f"Question: {text}")
print(f"Answer: {answer}")
/home/ea/work/ov_venv/lib/python3.8/site-packages/optimum/intel/openvino/modeling_seq2seq.py:395: FutureWarning: shared_memory is deprecated and will be removed in 2024.0. Value of shared_memory is going to override share_inputs value. Please use only share_inputs explicitly.
  last_hidden_state = torch.from_numpy(self.request(inputs, shared_memory=True)["last_hidden_state"]).to(
/home/ea/work/ov_venv/lib/python3.8/site-packages/transformers/generation/utils.py:1260: UserWarning: Using the model-agnostic default max_length (=20) to control the generation length. We recommend setting max_new_tokens to control the maximum length of the generation.
  warnings.warn(
/home/ea/work/ov_venv/lib/python3.8/site-packages/optimum/intel/openvino/modeling_seq2seq.py:476: FutureWarning: shared_memory is deprecated and will be removed in 2024.0. Value of shared_memory is going to override share_inputs value. Please use only share_inputs explicitly.
  self.request.start_async(inputs, shared_memory=True)
Question: What performance hints do?
Answer: automatically adjust runtime parameters to prioritize for low latency or high throughput

インタラクティブなデモ

import gradio as gr

example_images_urls = [
    "https://github.com/openvinotoolkit/openvino_notebooks/assets/29454499/94ef687c-aebb-452b-93fe-c7f29ce19503",
    "https://github.com/openvinotoolkit/openvino_notebooks/assets/29454499/70b2271c-9295-493b-8a5c-2f2027dcb653",
    "https://github.com/openvinotoolkit/openvino_notebooks/assets/29454499/1e2be134-0d45-4878-8e6c-08cfc9c8ea3d"
]

file_names = ["eiffel_tower.png", "exsibition.jpeg", "population_table.jpeg"]

for img_url, image_file in zip(example_images_urls, file_names):
    load_image(img_url).save(image_file)

questions = ["What is Eiffel tower tall?", "When is the coffee break?", "What the population of Stoddard?"]

examples = [list(pair) for pair in zip(file_names, questions)]

def generate(img, question):
    inputs = processor(images=img, text=question, return_tensors="pt")
    predictions = ov_model.generate(**inputs, max_new_tokens=256)
    return processor.decode(predictions[0], skip_special_tokens=True)

demo = gr.Interface(
    fn=generate,
    inputs=["image", "text"],
    outputs="text",
    title="Pix2Struct for DocVQA",
    examples=examples,
    cache_examples=False,
    allow_flagging="never",
)

try:
    demo.queue().launch(debug=False)
except Exception:
    demo.queue().launch(share=True, debug=False)
# if you are launching remotely, specify server_name and server_port
# demo.launch(server_name='your server name', server_port='server port in int')
# Read more in the docs: https://gradio.app/docs/