ICT 드림업 - 무물 매니저/개발
[무물 매니저] Faiss데이터베이스 사용해보기
kangchaewon
2025. 4. 23. 23:21
Faiss 벡터 데이터베이스에 image-1,2,3저장
from pathlib import Path
from PIL import Image
import numpy as np
import torch
import faiss
from transformers import CLIPProcessor, CLIPModel
import json
model_name = "openai/clip-vit-base-patch32"
clip_model = CLIPModel.from_pretrained(model_name)
processor = CLIPProcessor.from_pretrained(model_name)
def image_embedding(img_path: Path) -> np.ndarray:
image = Image.open(img_path).convert("RGB")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
emb = clip_model.get_image_features(**inputs) # [1, 512]
emb = emb / emb.norm(dim=-1, keepdim=True) # L2 정규화
return emb.cpu().numpy().astype("float32")
# 이미지 디렉토리 경로
image_dir = Path("../test-images/")
# 설명을 포함한 메타데이터
image_data = {
"pic1.jpg": "Peers, flowers, and water kettles",
"monet_waterlilies.png": "A famous painting by Claude Monet",
"starry_night.jpg": "A painting by Vincent van Gogh"
}
# 임베딩 벡터와 메타데이터 저장할 리스트
vectors, ids, descriptions = [], [], []
# 이미지 파일에 대해 임베딩 생성하고 메타데이터 저장
# 수정 후 이미지 파일 경로 찾기 (jpeg 파일 추가)
image_files = list(image_dir.glob("*.jpg")) + list(image_dir.glob("*.jpeg")) + list(image_dir.glob("*.png"))
for img_file in image_files:
try:
vectors.append(image_embedding(img_file))
ids.append(img_file.name) # 파일명 저장
descriptions.append(image_data.get(img_file.name, "No description available")) # 설명 저장
except Exception as e:
print(f"Error processing {img_file}: {e}")
# 임베딩된 벡터들 합치기
if len(vectors) > 0:
matrix = np.vstack(vectors) # 벡터가 있을 때만 호출
else:
print("No vectors to stack. Please check your image files and embeddings.")
# 벡터의 차원 정보 확인
if 'matrix' in locals():
d = matrix.shape[1]
# Faiss 인덱스 생성 (코사인 유사도용)
index = faiss.IndexFlatIP(d)
index.add(matrix)
# Faiss 인덱스를 파일로 저장
faiss.write_index(index, "image_clip.index")
# 설명과 파일명을 JSON 형식으로 저장
meta_data = {"ids": ids, "descriptions": descriptions}
with open("image_meta.json", "w") as f:
json.dump(meta_data, f)
print(f"Saved {len(ids)} image vectors with descriptions.")
else:
print("No embeddings were generated.")
저장 후, test-1이미지와 가장 비슷한 결과 반환
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Apr 23 23:12:12 2025
@author: kangchaewon
"""
import torch
import faiss
import numpy as np
from PIL import Image
from transformers import CLIPProcessor, CLIPModel
from pathlib import Path
# 모델 로드
model_name = "openai/clip-vit-base-patch32"
clip_model = CLIPModel.from_pretrained(model_name)
processor = CLIPProcessor.from_pretrained(model_name)
# 이미지 임베딩 함수
def image_embedding(img_path: Path) -> np.ndarray:
image = Image.open(img_path).convert("RGB")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
emb = clip_model.get_image_features(**inputs) # [1, 512]
emb = emb / emb.norm(dim=-1, keepdim=True) # L2 정규화
return emb.cpu().numpy().astype("float32")
# 이미지 디렉토리 경로
image_dir = Path("../test-images/")
# Faiss 인덱스 불러오기
index = faiss.read_index("image_clip.index")
# 쿼리 이미지의 임베딩을 구하는 함수
def search_similar_image(query_img_path: Path, index: faiss.Index, top_k=1):
query_embedding = image_embedding(query_img_path) # 쿼리 이미지 임베딩
query_embedding = query_embedding.astype('float32') # 타입 변환
# Faiss 인덱스를 사용하여 가장 유사한 이미지 검색
distances, indices = index.search(query_embedding, top_k) # top_k=1로 설정하여 가장 유사한 하나만 찾음
return distances, indices
# 검색할 이미지
query_img_path = Path("../test-images/test-1.jpg") # 검색할 이미지 경로를 지정
# 검색
distances, indices = search_similar_image(query_img_path, index)
# 결과 출력
print(f"Query image: {query_img_path.name}")
print(f"Most similar image index: {indices[0][0]}") # 가장 유사한 이미지의 인덱스
print(f"Distance (similarity score): {distances[0][0]}") # 유사도 점수

Query image : 검색한 이미지
Most similar image index : 가장 비슷한 결과로 인식된 이미지 인덱스
{"ids": ["image-1.jpg", "image-3.jpg", "image-2.jpg"], "descriptions": ["No description available", "No description available", "No description available"]}
ids가 1인 image-3이 결과값
image-3은 정물화 이미지이고, test-1이미지는 배 이미지.
결과값을 잘 인식하는 것을 볼 수 있음.