# 画像特徴抽出

画像特徴抽出とは、与えられた画像から意味的に有意な特徴を抽出するタスクです。画像の類似度判定や画像検索など、多くのユースケースがあります。さらに、ほとんどのコンピュータビジョンモデルは画像特徴抽出に利用でき、タスク固有のヘッド（画像分類、物体検出など）を除去することで特徴を取得できます。これらの特徴は、エッジ検出やコーナー検出など、より上位レベルの処理において非常に有用です。また、モデルの深さによっては、現実世界に関する情報（例：猫の外見）を含むこともあります。そのため、これらの出力は、特定のデータセット上で新しい分類器を訓練するために使用できます。

このガイドでは、次のことを行います。

- `image-feature-extraction` パイプラインを基盤として、シンプルな画像類似度システムを構築する方法を学びましょう。
- 生のモデル推論で同じタスクを達成します。

## `image-feature-extraction` パイプラインによる画像類似度

猫が魚網の上で座っている画像が2枚あり、そのうち1枚は生成されたものです。

```python
from PIL import Image
import requests

img_urls = ["https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png", "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.jpeg"]
image_real = Image.open(requests.get(img_urls[0], stream=True).raw).convert("RGB")
image_gen = Image.open(requests.get(img_urls[1], stream=True).raw).convert("RGB")
```

パイプラインの動作を確認しましょう。まず、パイプラインを初期化します。モデルを渡さない場合、パイプラインは自動的に[google/vit-base-patch16-224](https://huggingface.co/google/vit-base-patch16-224)で初期化されます。類似度を計算したい場合は、`pool`をTrueに設定してください。

```python
import torch
from transformers import pipeline
from accelerate import Accelerator
# automatically detects the underlying device type (CUDA, CPU, XPU, MPS, etc.)
device = Accelerator().device
pipe = pipeline(task="image-feature-extraction", model="google/vit-base-patch16-384", device=device, pool=True)
```

`pipe`で推論を行うには、両方の画像を渡します。

```python
outputs = pipe([image_real, image_gen])
```

出力には、それら2つの画像のプーリング済み埋め込みが含まれます。

```python
# get the length of a single output
print(len(outputs[0][0]))
# show outputs
print(outputs)

# 768
# [[[-0.03909236937761307, 0.43381670117378235, -0.06913255900144577,
```

類似度スコアを取得するには、それらを類似度関数に渡す必要があります。

```python
from torch.nn.functional import cosine_similarity

similarity_score = cosine_similarity(torch.Tensor(outputs[0]),
                                     torch.Tensor(outputs[1]), dim=1)

print(similarity_score)

# tensor([0.6043])
```

プーリング前の最後の隠れ状態を取得するには、`pool` パラメータに値を渡さないでください。デフォルトでは `False` に設定されているためです。これらの隠れ状態は、モデルの機能に基づいて新しい分類器やモデルを訓練する際に役立ちます。

```python
pipe = pipeline(task="image-feature-extraction", model="google/vit-base-patch16-224", device=device)
outputs = pipe(image_real)
```

出力はプーリングされていないため、得られるのは最後の隠れ状態です。最初の次元はバッチサイズ、最後の2次元は埋め込みの形状を表します。

```python
import numpy as np
print(np.array(outputs).shape)
# (1, 197, 768)
```

## `AutoModel` を使用して特徴量と類似度を取得する

transformersの`AutoModel`クラスを使用して、特徴量を取得することもできます。`AutoModel`は、タスク固有のヘッドを持たない任意のtransformersモデルを読み込むため、これを使用して特徴量を取得できます。

```python
from transformers import AutoImageProcessor, AutoModel

processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
model = AutoModel.from_pretrained("google/vit-base-patch16-224").to(device)
```

推論用のシンプルな関数を書いてみましょう。まず入力を`processor`に渡し、その出力を`model`に渡します。

```python
def infer(image):
  inputs = processor(image, return_tensors="pt").to(device)
  outputs = model(**inputs)
  return outputs.pooler_output
```

この関数に画像を直接渡すことで、埋め込みを取得できます。

```python
embed_real = infer(image_real)
embed_gen = infer(image_gen)
```

埋め込みに対して、再び類似度を取得できます。

```python
from torch.nn.functional import cosine_similarity

similarity_score = cosine_similarity(embed_real, embed_gen, dim=1)
print(similarity_score)

# tensor([0.6061], device='cuda:0', grad_fn=<SumBackward1>)
```

