🙌

FAISSを使った画像類似検索の実装:女性のプロマイド画像を例に詳細解説

2025/02/27に公開

📌 目的:
本記事では、FAISS(Facebook AI Similarity Search) を用いて、画像の類似検索 を実装する方法を、女性のプロマイド画像を例に詳細に解説します。


📌 1. FAISSとは?

FAISS(Facebook AI Similarity Search) は、Facebook AI Research(FAIR)が開発した、大規模な特徴量ベクトルの類似検索を高速に行うライブラリ です。

🔹 FAISSのメリット

超高速検索:数百万件のデータからでも、ミリ秒単位で類似検索が可能
大規模データ対応:数GB~TB規模の特徴量ベクトルを効率的に検索可能
柔軟なインデックス:L2距離・コサイン類似度・HNSW(近似最近傍検索)など多彩な検索手法をサポート
GPUサポート:GPUを活用してさらに高速化可能


📌 2. FAISSのユースケース

FAISSは以下のような場面で活用されています。

ユースケース 説明
画像類似検索 似た画像を検索(例: ファッションEC、アイドルフォト類似検索)
顔認識 ユーザーの顔特徴から同じ人物を検索(例: 顔認証システム)
動画推薦 動画の特徴ベクトルをもとに、関連動画を推薦(例: YouTube、TikTok)
音楽推薦 曲の特徴を分析し、類似した楽曲を検索(例: Spotify)
テキスト検索 単語の埋め込みベクトルを用いた類似文章検索(例: 検索エンジン)

💡 今回は、女性のプロマイド画像を使った類似検索を実装します!


📌 3. FAISSを使った画像類似検索の流れ

FAISSを使って、以下の流れで類似画像を検索します。

  1. 画像の特徴量を抽出(ResNetを使用)
  2. FAISSのインデックスに特徴量を登録
  3. クエリ画像を入力し、類似画像を検索
  4. 検索結果を表示し、分析

📌 4. 画像の特徴量を抽出

まずは、ResNet50 を使って画像の特徴量(ベクトル)を取得します。

🔹 ライブラリのインストール

pip install faiss-cpu tensorflow numpy opencv-python

🔹 画像の特徴量抽出(ResNet50)

import numpy as np
import tensorflow as tf
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.resnet50 import preprocess_input
import os
from glob import glob

# ResNet50のロード(最後の全結合層を削除)
model = ResNet50(weights='imagenet', include_top=False, pooling='avg')

def extract_features(img_path):
    """画像から特徴量を抽出する"""
    img = image.load_img(img_path, target_size=(224, 224))
    img_array = image.img_to_array(img)
    img_array = np.expand_dims(img_array, axis=0)
    img_array = preprocess_input(img_array)
    
    features = model.predict(img_array)
    return features.flatten()  # 2048次元の特徴ベクトルを返す

# データセットの画像パスを取得
image_paths = glob("dataset/*.jpg")  # datasetフォルダに画像を配置
feature_vectors = np.array([extract_features(img) for img in image_paths])

# 特徴量と画像パスを保存
np.save("image_features.npy", feature_vectors)
np.save("image_paths.npy", np.array(image_paths))

🔍 結果:
feature_vectors に、全画像の特徴ベクトル(2048次元)が保存されます。


📌 5. FAISSのインデックス作成

次に、FAISSを使って高速検索のための**インデックス(検索用データ構造)**を作成します。

import faiss

# 特徴量をロード
feature_vectors = np.load("image_features.npy")
image_paths = np.load("image_paths.npy")

# FAISSのインデックス作成(L2距離を使用)
index = faiss.IndexFlatL2(feature_vectors.shape[1])  # 2048次元のL2距離ベースの検索
index.add(feature_vectors)  # 画像特徴量をインデックスに追加

# インデックスを保存
faiss.write_index(index, "faiss_index.bin")

🔍 結果:
FAISSのインデックスが作成され、faiss_index.bin に保存されます。


📌 6. クエリ画像の類似検索

ユーザーがアップロードした画像と似た画像を検索します。

# FAISSのインデックスをロード
index = faiss.read_index("faiss_index.bin")

def search_similar_images(query_img, top_k=5):
    """クエリ画像と類似する画像を検索"""
    query_vector = extract_features(query_img).reshape(1, -1)
    distances, indices = index.search(query_vector, top_k)
    return [image_paths[i] for i in indices[0]]  # 類似画像のパスを返す

# 検索テスト(例: "test.jpg" の類似画像を取得)
query_image = "test.jpg"
similar_images = search_similar_images(query_image)

print("🔍 類似画像のパス:", similar_images)

🔍 結果:
入力画像 "test.jpg" に最も似た5枚の画像のパスが返されます。


📌 7. 検索結果の可視化

検索結果を画像で表示します。

import cv2
import matplotlib.pyplot as plt

def show_images(query_img, similar_images):
    """クエリ画像と類似画像を可視化"""
    fig, axes = plt.subplots(1, len(similar_images) + 1, figsize=(15, 5))
    
    # クエリ画像
    img = cv2.imread(query_img)[..., ::-1]  # BGR → RGB変換
    axes[0].imshow(img)
    axes[0].set_title("Query Image")
    axes[0].axis("off")

    # 類似画像
    for i, img_path in enumerate(similar_images):
        img = cv2.imread(img_path)[..., ::-1]
        axes[i + 1].imshow(img)
        axes[i + 1].set_title(f"Rank {i+1}")
        axes[i + 1].axis("off")

    plt.show()

# 類似画像を可視化
show_images(query_image, similar_images)

検索結果が視覚的に確認できるようになります!


📌 8. まとめ

🎯 FAISSの活用ポイント

  • ResNet50で画像特徴を抽出し、FAISSで高速類似検索を実装
  • L2距離を用いたベクトル検索で、精度の高い結果を取得
  • 大規模データにも対応し、数百万枚の画像もミリ秒単位で検索可能
  • 画像検索の他、顔認識・動画推薦・音楽検索にも応用可能

🚀 次のステップ

  • コサイン類似度を用いる(L2距離と比較)
  • HNSWを使った近似最近傍検索(より高速化)
  • 顔認識モデル(FaceNet)と組み合わせる

これで、プロマイド画像の類似検索システムを構築できます! 🎉

Discussion