本記事では、画像とプロンプト(命令文)を入力データとして、その回答を文章で生成するサンプルコードを掲載しました。この場合、視覚言語モデル(Vision Language Model, VLM)を用います。
使用したモデルは、Hugging Faceの「llava-calm2-siglip」です。詳細については、https://huggingface.co/cyberagent/llava-calm2-siglip を参照ください。他のVLMモデルでも、Hugging Faceを活用して同様の手順で利用可能です。
使用したPCスペックは以下の通りです。
実行中のビデオメモリの使用量は常に上限の12GBでした。一方、GPUを利用せずにCPUでの実行時には処理が途中で落ちました。以上の結果より、VLMモデルを用いる場合は、ビデオカードは必須と思われます。
1. ライブラリとモデルの準備
まず、必要なライブラリであるPIL
(Python Imaging Library)とtransformers
ライブラリをインポートします。PIL
は画像処理に、transformers
は視覚と言語モデルのロードに使用します。
from PIL import Image
import requests
from transformers import AutoProcessor, LlavaForConditionalGeneration
import torch
PIL.Image
: 画像のロードと変換に使用。
requests
: インターネットから画像を取得するためのライブラリ。
AutoProcessor
と LlavaForConditionalGeneration
: 画像とテキストを扱うLlavaモデル用のユーティリティ。
2. モデルのダウンロード
初回はインターネットから、モデルをダウンロード(DL)する必要があります。DLは下記コードで可能です。
上記にてDLしたモデルは、ユーザーディレクトリのキャッシュフォルダ内に複数のファイルで構成されます(下図)。
このモデルを他のPCなどで使用する場合など、任意の場所へ移動やコピーして使用することも可能です。下記はその移動先の例です。
model_name = "./vlm_models/local_llava_calm2_siglip"
3. モデルのロード
model = LlavaForConditionalGeneration.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
).to(0)
processor = AutoProcessor.from_pretrained(model_name)
processor
torch_dtype=torch.bfloat16
: 省メモリで高精度な計算を行うための設定。
to(0)
: モデルをGPU上に移動して高速化します。
4. 画像のロード
URLから直接画像をロードする場合や、ローカルに保存された画像を使用する場合があります。今回は、Wikipediaから昆虫の画像を取得しています。
url = "https://upload.wikimedia.org/wikipedia/commons/9/9d/Shoryobatta_06z1482sv.jpg"
image = Image.open(requests.get(url, stream=True).raw).convert("RGB")
image
下図は、上記のリンク先の画像で、ショウリョウバッタです(Cory, CC 表示-継承 3.0, https://commons.wikimedia.org/w/index.php?curid=1047627による)。
ローカルPCにある画像ファイルを読み込む際のコードの例は次の通りです。
5. プロンプトの設定と推論実行
プロンプトを定義し、画像をモデルに入力して推論を行います。ここでは昆虫の名前を尋ねる形式の命令文を作成しています。
prompt = """USER: <image>
この昆虫の名称は、何かわかりますか?
ASSISTANT: """
inputs = processor(text=prompt, images=image, return_tensors="pt").to(0, torch.bfloat16)
processor
: テキストと画像をモデルに適した形式に変換します。
return_tensors="pt"
: 入力をPyTorchテンソルに変換。
to(0)
: GPU上で計算を行う設定。
5. 出力の取得
モデルから生成された出力をテキストとして取得し、不要な部分を取り除いて最終的な回答を得ます。
generate_ids = model.generate(**inputs,
max_length=500,
do_sample=True,
temperature=0.2,
)
output = processor.tokenizer.decode(generate_ids[0][:-1], clean_up_tokenization_spaces=False)
answer = output.split("ASSISTANT: ", 1)[-1]
answer
temperature=0.2
: モデルの出力に多様性を持たせるためのパラメータ。
split("ASSISTANT: ", 1)[-1]
: 最終的な回答部分のみを抽出。
上記の一連のコードを実行して得られた結果は次の通りです。回答の精度はモデルによります。
'画像に写っている昆虫は、緑色の体と長い脚が特徴的な「バッタ」のようです。'
▼最後に、上記の一連のpythonコードを下記に記します。
from PIL import Image
import requests
from transformers import AutoProcessor, LlavaForConditionalGeneration
import torch
model_name = "./vlm_models/local_llava_calm2_siglip"
model = LlavaForConditionalGeneration.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
).to(0)
processor = AutoProcessor.from_pretrained(model_name)
processor
url = "https://upload.wikimedia.org/wikipedia/commons/9/9d/Shoryobatta_06z1482sv.jpg"
image = Image.open(requests.get(url, stream=True).raw).convert("RGB")
image
prompt = """USER: <image>
この昆虫の名称は、何かわかりますか?
ASSISTANT: """
inputs = processor(text=prompt, images=image, return_tensors="pt").to(0, torch.bfloat16)
generate_ids = model.generate(**inputs,
max_length=500,
do_sample=True,
temperature=0.2,
)
output = processor.tokenizer.decode(generate_ids[0][:-1], clean_up_tokenization_spaces=False)
answer = output.split("ASSISTANT: ", 1)[-1]
answer
以上
<広告>
リンク
リンク
リンク