Florence-2という画像認識AIを試す

# 記事を書いた人

こんにちは！
株式会社マーズフラッグのバックエンドを担当するリュウです。
普段タスクをこなしながら、AI関連の研究をしています。

## はじめに

最近なにかの作業で画像認識AIを使う機会があったけど、物件選択と物件認識のため、複数のツールを使う必要がありました、でもちょっと複雑と思いました、一つのモデルで処理できたらいいなと思いました。
そこで最近Florence-2という新しいモデルを見つけたので、複数のツールを使う必要がなくなるかもしれないため、Florence-2を使って画像認識AIを試してみたいと思います。

## Florence-2とは

Florence-2は、Microsoftが開発したマルチモーダル視覚言語モデル(Vision Language Model)です、画像に対して、物体検出、セグメンテーション、画像キャプション、グラウンディングなどの幅広いタスクに対応しています。

## 環境

- Windows 11
- WSL2
- Ubuntu 22.04
- Python 3.10
- Florence-2

## セットアップ

Florence-2をインストールするために、以下のコマンドを実行します。
poetryを使ってました。

```bash
poetry init
```

パケージの追加、試す時必要なパケージでした。

```bash
poetry add torch torchvision transformers Pillow timm einops
```

## 画像認識AIを試す

コードを準備する

```python
import torch
from transformers import AutoProcessor, AutoModelForCausalLM 
from PIL import Image


# モデルとプロセッサの準備
model = AutoModelForCausalLM.from_pretrained(
    "microsoft/Florence-2-large", 
    torch_dtype=torch.float16, 
    trust_remote_code=True
).to("cuda:0")
processor = AutoProcessor.from_pretrained(
    "microsoft/Florence-2-large", 
    trust_remote_code=True
)

# 推論実行の関数
def run_inference(task_prompt, image_path, text_input=None):
    if text_input is None:
        prompt = task_prompt
    else:
        prompt = task_prompt + text_input
    image = Image.open(image_path)
    inputs = processor(text=prompt, images=image, return_tensors="pt").to("cuda:0", torch.float16)
    generated_ids = model.generate(
      input_ids=inputs["input_ids"],
      pixel_values=inputs["pixel_values"],
      max_new_tokens=1024,
      num_beams=3
    )
    generated_text = processor.batch_decode(generated_ids, skip_special_tokens=False)[0]
    result = processor.post_process_generation(generated_text, task=task_prompt, image_size=(image.width, image.height))
    return result
```

画像認識AIの推論を試す

```python
task_prompt = "Recognize the objects in the image:"
image_path = "image.jpg"
result = run_inference(task_prompt, image_path)
print(result)
```

## 準備した画像

![pexels-arina-naomi-jilly-30037706-18595609.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916505/9c172580-8dbe-0726-a1b9-4bceb9e825a9.jpeg)

Image from (https://www.pexels.com/search/cat%20and%20dog/)


## 機能と実行

### CAPTION

```python
prompt = "<CAPTION>"
result = run_inference(prompt, image_url)
print(result)
```

```
{'<CAPTION>': 'A dog sitting next to a car with a cat on the hood.'}
```

翻訳

```
犬が車の横に座っており、フードに猫が座っています。
```

おおよそ正しいキャプションが生成されました。

### DETAILED_CAPTION

```python
prompt = "<DETAILED_CAPTION>"
result = run_inference(prompt, image_url)
print(result)
```

```
{'<DETAILED_CAPTION>': 'The image shows a white dog sitting next to a grey Audi A3 car on a grassy field, with two cats perched on the roof. In the background, there are trees, buildings, and a clear blue sky.'}
```

翻訳

```
画像は、草の生えたフィールドにある灰色のAudi A3車の横に座っている白い犬を示しており、屋根に2匹の猫が座っています。背景には、木々、建物、晴れた青空があります。
```

より詳細なキャプションが生成されましたが、猫の数が間違っていますね、見たところ縄が影響しています。

### MORE_DETAILED_CAPTION

```python
prompt = "<MORE_DETAILED_CAPTION>"
result = run_inference(prompt, image_url)
print(result)
```

```
{'<MORE_DETAILED_CAPTION>': 'The image shows a silver Audi car parked on a grassy field with a building in the background. On the front of the car, there is a white dog with a yellow collar sitting next to it. The dog is looking directly at the camera with its tongue hanging out. Next to the dog, there are two cats, one black and white and the other brown and white. The car has a license plate that reads "TX-720-G".'}
```

翻訳

```
画像は、背景に建物がある草の生えたフィールドに駐車された銀色のAudi車を示しています。車の前には、白い首輪をつけた白い犬が座っています。犬は舌を出してカメラを見つめています。犬の横には、黒と白の猫と茶色と白の猫がいます。車には「TX-720-G」と書かれたナンバープレートが付いています。
```

もうちょっと詳細なキャプションが生成されましたが、猫の数は間違っています。

### CAPTION_TO_PHRASE_GROUNDING

```python
prompt = "<CAPTION_TO_PHRASE_GROUNDING>"
result = run_inference(prompt, image_url, 'A dog sitting next to a car with a cat on the hood.')
print(result)
```

```
{'<CAPTION_TO_PHRASE_GROUNDING>': {'bboxes': [[592.5, 1842.0, 1228.5, 3018.0], [1.5, 950.0, 2995.5, 2730.0], [1669.5, 1258.0, 2278.5, 1586.0], [829.5, 1434.0, 2995.5, 1950.0]], 'labels': ['A dog', 'a car', 'a cat', 'the hood']}}
```

画像に対するキャプションの位置を示すバウンディングボックス

```python
from PIL import ImageDraw

def draw_bounding_boxes(image, bboxes, labels):
    image = image.copy()
    draw = ImageDraw.Draw(image)
    font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 50)  # フォントとサイズの指定
    for bbox, label in zip(bboxes, labels):
        draw.rectangle(bbox, outline="red", width=3)
        draw.text((bbox[0], bbox[1] - 50), label, fill="red", font=font)
    return image

# バウンディングボックス画像の生成
bbox_image = draw_bounding_boxes(
    Image.open(image_url),
    result['<CAPTION_TO_PHRASE_GROUNDING>']['bboxes'], 
    result['<CAPTION_TO_PHRASE_GROUNDING>']['labels'])

# 確認
bbox_image.save(f"./images_output/{image_url.split('/')[-1]}")
```

![pexels-arina-naomi-jilly-30037706-18595609.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916505/af2b1eec-eca6-224a-9ab5-53908a0ccf2b.jpeg)

バウンディングボックスが生成されました。
これはいいですね、犬、車、猫、フードの位置が正確に示されています、シンプルな物件を選択するため、CAPTIONの結果を参考に入れました。
前ボックスとラベルを生成する時、違うツールを使ってましたが、Florence-2を使うと、一つのモデルで全部のタスクを実行できます、違うモデルを使う必要がなくなりました！

## まとめ

Florence-2を使って画像認識AIを試してみました。Florence-2は複数のツールを使う必要がなく、一つのモデルでボックスとラベルを生成できます、すごく便利と思います！
これからはFlorence-2を使って画像認識AIを試してみたいと思います。

後で色々調べていましたが、Florence-2はVQA機能もあるはずですが、今リリースされたモデルにはVQA機能がないようです、VQA機能は別のモデルで実行する必要があるようです、今度もしVQA機能があればをまた試してみたいと思います。


## 参考文献

- [Florence-2](https://huggingface.co/microsoft/Florence-2-large)
- [Florence-2の使い方](https://huggingface.co/microsoft/Florence-2-large/blob/main/sample_inference.ipynb)