Intel iGPU で Florence-2 を動かしてみた (第2回 : text prompt で特定の物体検出編)
0. はじめに
会社で支給されるような普通のWindowsノートPCで、Florence-2を動かしてみたという話です。Florence-2とは、これ。
前回、環境構築とIntel最適化についてご紹介しましたが、その内容を前提に続きを書きますので、まだの方は先にそちらをご覧ください。
1. Florence-2でできること
1.1) 単一モデルで14タスクも!
技術の進歩は凄まじいもので、Florence-2は単一モデルで画像に対する14ものタスクをこなすことができます。
詳細は割愛しますが、中身がすごいのなんのって。
具体的なタスクと必要なpromptについては、このページをご覧ください。
1.2) 今回使うのは
今回は、物体検出をしてみましょう。
それも、text prompt を与え、そのphraseやwordに反応した物体のみを検出してみます。
2. サンプルコードの説明
頭から順を追って説明していきます。
これまでの記事同様、最初に言い訳しておきますが、Pythonを勉強し始めて2週目に書いたものなので、お約束的な書き方になっていない箇所もあろうかと思いますが、その辺りはご容赦を。
また、元ネタとしては、本家OpenVINOのサイトに書かれているドキュメントと、前述したGitHubのページなのですが、今回の環境に合わせてサンプルコードをちょこちょこ書き換えています。
OpenVINOの原典を読みたいという方は、こちらをご参照ください。
2.1) OpenVINO IRの保存場所とモデルの選択
前回の記事で書いた階層に、OpenVINO IR のモデルが既に存在しているという前提です。
from pathlib import Path
# model_name = "Florence-2-base" # Pretrained model with FLD-5B
# model_name = "Florence-2-large" # Pretrained model with FLD-5B
model_name = "Florence-2-base-ft" # Finetuned model on a collection of downstream tasks
# model_name = "Florence-2-large-ft" # Finetuned model on a collection of downstream tasks
model_id = "microsoft/" + model_name # ov_florence2_helper.pyが想定している値なので変えない
model_path = Path("model") # modelの保存場所
model_path = model_path / "Florence-2" # Florence-2の各modelの保存場所
model_path = model_path / model_name # 選択したmodelの保存場所
2.2) modelの読み込み
どうやら、ov_florence2_helper.pyがいろんなことしてくれるようで、こんな簡単な記述で終わります。裏では、Intel最適化のためのコンパイルもしています。
from ov_florence2_helper import OVFlorence2Model
model = OVFlorence2Model(model_path, device="AUTO")
print("Initialized.", flush=True)
from transformers import AutoProcessor
processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True)
print("Florence-2 model loaded.", flush=True)
device="AUTO"の解説は、SAM2の記事を参照してください。
2.3) task prompt の設定
ここで、14タスクのうち、どのタスクにするのかを指定します。
今回は、<CAPTION_TO_PHRASE_GROUNDING>を指定し、この後で text prompt の設定をします。
ちなみに、text prompt を与えない、お任せ物体検出は<OD>です。
# task_prompt = "<CAPTION>" # Caption
# task_prompt = "<DETAILED_CAPTION>" # Detailed Caption
# task_prompt = "<MORE_DETAILED_CAPTION>" # More Detailed Caption
# task_prompt = "<DENSE_REGION_CAPTION>" # Dense Region Caption
# task_prompt = "<REGION_PROPOSAL>" # Region Proposal (output: bbox, empty label)
# task_prompt = "<OD>" # Object Detection
task_prompt = "<CAPTION_TO_PHRASE_GROUNDING>" # Phrase Grounding (input: text)
# task_prompt = "<REFERRING_EXPRESSION_SEGMENTATION>" # Referring Expression Segmentation (input: text, output: polygon)
# task_prompt = "<REGION_TO_SEGMENTATION>" # Region to Segmentation (input: loc_x1, lox_y1, loc_x2, loc_y2)
# task_prompt = "<OPEN_VOCABULARY_DETECTION>" # Open Vocabulary Detection (input: text)
# task_prompt = "<REGION_TO_CATEGORY>" # Region to Texts (input: loc_x1, loc_y1, loc_x2, loc_y2)
# task_prompt = "<REGION_TO_DESCRIPTION>" # Region to Texts (input: loc_x1, loc_y1, loc_x2, loc_y2)
# task_prompt = "<OCR>" # OCR (output: text)
# task_prompt = "<OCR_WITH_REGION>" # OCR with Region (output: text, label)
2.4) 対象画像の設定
ざっくり、以下のことをしています。
画像を読み込む
RGB情報に変換する (RGB以外のチャネルを落とし、RGBの順に並び替え)
from PIL import Image
image = Image.open("images/test45.png")
image = image.convert("RGB")
print("Image file opened.", flush=True)
2.5) text prompt の設定
前述した通り、今回は text prompt を与えて特定の物体を検出したいので、text prompt を設定します。(wordでもphraseでもよし。)
# text_prompt = None # text prompt を与えない場合
text_prompt = "sky" # text prompt を与える場合
# text_prompt = "<loc_x1><loc_y1><loc_x2><loc_y2>" # 座標を与える場合 x1, y1, x2, y2を数値に
コメント文の通り、text prompt のないタスクは、Noneを設定しておきます。
また、座標を与える場合は、矩形の左上と右下の座標を設定します。
2.6) 最終的なpromptの設定
ここで、各タスクに合ったpromptを設定します。
if text_prompt is None:
prompt = task_prompt
else:
prompt = task_prompt + text_prompt
2.7) 推論
これで材料が揃いましたので、これらを投入。
inputs = processor(text=prompt, images=image, return_tensors="pt")
print("Inference started.", flush=True)
generated_ids = model.generate(
input_ids=inputs["input_ids"],
pixel_values=inputs["pixel_values"],
max_new_tokens=1024,
do_sample=False,
num_beams=3
)
generated_text = processor.batch_decode(generated_ids, skip_special_tokens=False)[0]
2.8) 推論結果の表示
推論結果は、すべてテキスト情報です。
その中から、該当タスクのdictを抽出して、表示します。
parsed_answer = processor.post_process_generation(
generated_text,
task=task_prompt,
image_size=(image.width, image.height)
)
results = parsed_answer[task_prompt] # 該当task_promptのdictを抽出
print(results, flush=True)
3. 次回は
実際にFlorence-2で物体検出を行ない、どんな結果になったのかをご紹介します。
お楽しみに。