[python] 이미지 임베딩 후 검색엔진에 저장까지_elastic/opensearch

 

[python] 원하는 이미지 데이터셋을 만들고싶은데, 귀찮을 때

이미지 데이터셋을 만들려면 직접 웹에서 다운받고 이름 매핑하고 폴도 구조 관리하고 여간 귀찮은 일이 아닐 수 없다..그래서 파이썬 라이브러리에서 이미지 검색쪽을 찾아보니 괜찮은 것이

x2bee.tistory.com

이 글에 이어지는 내용이다. 

 

원하는 카테고리별로 이미지를 빙에서 가져와서 로컬로 저장하는 로직까지 설명되어있는 글이다.

 

이제는 검색엔진에 상품 데이터를 저장하는 로직을 추가하려고한다.

 

여기서 핵심은 이미지를 벡터 임베딩을 해서 저장하는 것이다. 향후 이 벡터값으로 이미지 검색을 했을 때 유사성이 높은 이미지가 검색되도록 하기 위한 것이다.

 

짧게 설명하자면

 

검색하고자 하는 이미지 검색 -> 임베딩--------------유사도 계산--------------검색엔진에 저장되어 있는 이미지 벡터

 

이렇게 해서 가장 유사성이 높은 순으로 검색엔진에서 데이터를 추출하면 검색했던 이미지와 비슷한 이미지들이 쏟아져나올 것이다.

 


임베딩 모델 선택

 

daanelson/imagebind – Run with an API on Replicate

Run time and cost This model runs on Nvidia T4 GPU hardware. Predictions typically complete within 1 seconds. Readme Note: This model is licensed under a non-commercial license, and so should only be used for research and experimentation purposes. Model de

replicate.com

 

임베딩 모델은 아무거나 선택해도된다. 인기있는 모델을 쓰면 된다. 성능이 좋을 수록 의미적 관계와 유사성을 포착하여 모델이 이미지를 더 잘 이해하고 일반화할 수 있게 해준다.

 

위 페이지에 들어가면 예시 코드가 있는데 그것을 복사해서 사용하면 바로 실행될 것이다.

 

# 예시코드
import replicate

input = {
    "input": "https://replicate.delivery/pbxt/IqLXryIoF3aK3loaAUERG2lxnZX8x0yTZ9Nas9JtMxqcgotD/astronaut.png"
}

output = replicate.run(
    "daanelson/imagebind:0383f62e173dc821ec52663ed22a076d9c970549c209666ac3db181618b7a304",
    input=input
)
print(output)
#=> [-0.04028015583753586,0.032599665224552155,0.029634267091...

 

 

근데 기본예시 코드는 url을 변화하는 코드라,

 

내가 필요한건 로컬에 있는 이미지를 임베딩하는게 필요해서

 

이미지를 불러와서 base64 값으로 변환하고 그것을 임베딩할 수 있도록 수정했다.

 

어차피 s3 에서 추출된 이미지 url을 가지고 임베딩하는 방식으로 해야될 거 같긴한데, 테스트만 잠깐 해볼 거라..

 

url로 한다면 더 쉬워진다.

 

# base64

def vectorize_image(image_path):
  with open(image_path, "rb") as f:
    image_data = f.read()
    encoded_image = base64.b64encode(image_data).decode('utf-8')
    image_data_uri = f"data:application/octet-stream;base64,{encoded_image}"

    response = replicate.run(
      "daanelson/imagebind:0383f62e173dc821ec52663ed22a076d9c970549c209666ac3db181618b7a304",
      input={"input": image_data_uri, "modality": "vision"}
    )

  if response and isinstance(response, list):
    return response
  else:
    raise Exception(f"Failed to vectorize image: {response}")​

 

이렇게 이미지 임베딩하는 함수를 가지고 활용해주면 

 

이미지를 웹에서 크롤링하면서 동시에 임베딩을 진행해줄 수 있다. 

 

마지막으로 검색엔진에 해당 벡터값을 포함해서 상품 정보 데이터를 모두 때려넣어주면 끝이다.

 


검색엔진

검색엔진에는 대표적으로 두 가지가 있다.

 

Elasticsearch 와 Opensearch 가 있다. 현재 두 가지 검색엔진에 데이터 넣어보는 건 다 해봐서 정리하는 차원에서 작성해보려고 한다.

 

import 해주고.

from elasticsearch import Elasticsearch, helpers # 엘라스틱서치
from opensearchpy import OpenSearch, helpers # 오픈서치

 

클라이언트 설정해주고.

# Elasticsearch 클라이언트 설정
os_client = Elasticsearch(
   "http://0.0.0.0:3000",
   http_auth=("id", "pw")
)

# OpenSearch 클라이언트 설정
os_client = OpenSearch(
  hosts=[{
    'host': '0.0.0.0',
    'port': 3000
  }],
  http_auth=('id', 'pw'),
)

 

원하는 양식을 doc에 이쁘게 정리해서 .. 여기에 vector값도 넣어줘야한다.

 

opensearch 에서는 벡터 유사도 검사를 위해서 knn 플러그인을 설치해줘야한다.

 

또한 mapping은 다음과 같이 설정하자. 위에다가 settings 설정 빼먹지 말자.

# opensearch mapping /// elastic은 이미 되어있는 곳에 해봐서 안알아봄. 필요하면 검색 ㄱ
PUT test-index
{
  "settings": {
    "index": {
      "knn": true,
      "knn.algo_param.ef_search": 100
    }
  },
  "mappings": {
    "properties": {
      "my_vector1": {
        "type": "knn_vector",
        "dimension": 3,
        "method": {
          "name": "hnsw",
          "space_type": "l2",
          "engine": "lucene",
          "parameters": {
            "ef_construction": 128,
            "m": 24
          }
        }
      }
    }
  }
}

 

각 파라미터 설명

더보기

setting 속성

  • index.knn : k-NN 벡터 검색을 활성화한다.
  • index.knn.algo_param.ef_search : 검색 시 사용할 ef(search) 파라미터를 지정한다. 이 파라미터는 검색 시 고려할 이웃을 수를 결정한다. 값이 클수록 더 많은 이웃을 고려하게 되어 정확도가 높아질 수 있지만, 검색 속도는 느려질 수 있다.

mappings 속성

  • properties : 인덱스의 속성들을 정의하는 부분이다.

my_vector1 속성

  • type : 이 필드의 타입을 정의한다. k-NN 벡터검색을 위해 knn_vector로 설정
  • dimension : 벡터의 차원 수를 정의한다.
  • method : 벡터 검색에 사용할 알고리즘 및 설정을 정의하는 부분

method 속성

  • name : 벡터 검색에 사용할 알고리즘의 이름
  • space_type : 벡터 간의 거리 측정 방식을 정의한다. I2(유클리드 거리)를 사용한다. 다른 예로는 cosinesimil(코사인 유사도) 등이 있다
  • engine : 벡터 검색 엔진을 정의 여기서는 lucene 을 사용
  • parameters 알고리즘의 추가 파라미터를 정의

parameters 속성

  • ef_construction : HNSW 그래프 구축 시 고려할 최대 이웃 수를 지정한다. 값이 클수록 정확도가 높아질 수 있지만, 인덱스 생성 시간이 길어질 수 있다.
  • m: 그래프에서 각 노드가 가질 최대 이웃 수를 지정한다. 값이 클수록 그래프가 더 연결되며 검색 정확도가 노파질 수 있지만, 메모리 사용량도 증가할 수 있다.

 

최종적으로 데이터 저장. helpers.bulk 하면된다.

# doc을 helpers.bulk 으로 그냥 넣어주면 끝.
......
vector = vectorize_image_v2(dest_path)

# 오픈서치에 저장할 데이터 구성
doc = {
    "_index": "",
    "_id": goods_id,
    "_source": {
        "id": goods_id,
        "goodsNo": goods_id,
        "goodsNm": f"{idx}",
        "imageVector": vector
     }
}
new_data.append(doc)


# 엘라스틱서치에 데이터 추가
if new_data:
    try:
        helpers.bulk(os_client, new_data)
        print(f"Added {len(new_data)} documents to Elasticsearch for keyword '{keyword}'")
    except Exception as e:
        print(f"Failed to add documents to Elasticsearch: {e}")

 

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유