티스토리 뷰

Engineering

Gmarket의 유사이미지 추천 기능 파헤치기

지마켓 김윤제 2022. 11. 23. 14:45

Gmarket의 유사이미지 추천 기능 파헤치기

안녕하세요 VIP & Vertical 팀 김윤제입니다.

VIP 파트에서 상품 상세 페이지 및 리뷰 업무를 맡고 있습니다.

이번 블로깅에서는 Gmarket에서 사용하고 있는 유사이미지 추천 기능에 대해 소개하려 합니다.


유사이미지 추천 기능이란?

Gmaket App에는 2022년 5월 유사이미지 추천 기능이 추가되었습니다.

유사이미지 추천 기능이란 방금 본 상품과 같은 상품 이미지가 아닌 '시각적으로 유사한' 이미지의 상품을 보여주는 것입니다.

이 기능이 생기면서 사용자는 유사한 상품을 보다 쉽게 찾을 수 있게 되었습니다.

유사이미지 추천 기능의 개발이 완료되기까지는 수많은 시간과 노력, 인내가 필요했다고 합니다.

아래에서 자세히 살펴보도록 하겠습니다.


유사이미지 검색

유사 이미지 검색이란 Query Image를 이용하여, 시각적으로 유사한 이미지를 검색해 내는 것입니다.

 

이미지가 유사하다는 것은 무엇일까?

아래의 예시 상품들은 다른 이미지이지만 '시각적으로 유사한 이미지' 입니다.

  • 유사이미지 예시


사물인식에 대한 연구들과 한계

사물인식에 대한 연구는 Deep Learning 이전과 이후로 지속적으로 이루어져왔습니다.

  • Deep Learning 이전 (HOG, SIFT, SURF visual recognition 등)

  • Deep Learning 이후 (Image Classification, Localization, Object Detection, Object Segmentation 등)


장애물

위의 사물 인식 알고리즘들을 활용하여 유사 이미지 추천 기능을 개발하는데 있어서 가장 큰 문제점은
데이터 생성에 엄청난 시간과 비용이 필요하다는 것입니다.

  • Deep Learning Localization에 필요한 데이터 예시

 

Gmarket의 1억 개가 넘는 상품에 대해 위와 같은 방법으로 데이터들을 수집 및 학습하고 분류하는 데는

엄청난 시간과 비용이 들 것입니다.

또한 수많은 데이터를 저장할 디스크 공간도 문제입니다.


해결책

가장 중요한 사항은 시간 & 비용을 줄여야 한다는 것입니다.

  • Triplet Loss 기반 딥러닝 모델을 통한 학습은 현실적으로 불가능하다. (시간과 비용의 문제)
  • 데이터 저장 공간 문제

Inspired

수많은 고민을 하던 도중 추천 이미지 기능을 개발하신 분은 아래의 동영상을 보다가 영감을 받았다고 합니다.

해당 동영상은 VGGNet을 통해 이미지의 Feature를 뽑아내는 내용입니다.

VGGNet은 옥스포드 대학의 연구팀 VGG에 의해 개발된 모델로써, 
2014년 이미지넷 이미지 인식 대회에서 준우승을 한 모델이다.
여기서 말하는 VGGNet은 16개 또는 19개의 층으로 구성된 모델을 의미한다(VGG16, VGG19로 불림)

 

VGGNet 정도면… 유사 Image 검색에 필요한 feature(특징)를 뽑기에 충분하며,

이미지에서 추출한 Feature를 기반으로 Text Search의 원리를 응용한다면 Image Search도 할 수 있다!!

 


VGG19의 conv5 layer에서 feature 추출

conv5 layer는 512개의 feature map으로 구성되는데, 각 map의 intensity average 값을 feature로 취합니다.

이것은 어떤 feature map(filter를 통과한 결과)들이 input 이미지에 강하게 반응하는지를 표현합니다.

 

 

layer_no(feature map layer no.) : intensity(average)

그러면 512개의 layer_no:intensity의 정보를 얻을 수 있으며, 이를 image의 feature로 정의합니다.


Text Search는 문서 안에 사용된 단어와 그 빈도수를 이용하여 유사 문서 검색을 하고 있습니다.

 


Image Feature의 의미 변형

Image → Document

Layer_no → Term

Intensity → Term Frequency

Text Search의 원리를 이용하여 위와 같이 Feature를 취급한다면 유사 이미지도 검색해 낼 수 있습니다.

즉 1개의 이미지는 512개의 term과 그 빈도수(frequency)로 표현할 수 있습니다.


Trouble Shooting

해결책은 나왔지만 실제 개발에 있어 아래와 같이 여전히 많은 어려움들이 있었습니다.

  • 처리해야 할 데이터가 너무 많다. 1억 2000만 개의 이미지
    • 100만 개 이미지 다운로드
      • 시간은? 디스크는?
    • image feature를 뽑는데 너무 많은 시간이 필요하다
    • 데이터를 저장하는데 디스크와 메모리가 너무 많이 필요하다
  • 검색을 하기 위해 많은 양의 memory가 필요하다
    • 1억 2천만 개 상품 전체를 메모리에 띄워 search 해 보고 싶지만, 메모리가 부족
    • 적은 수의 상품만을 대상으로 시작함.
      • 20만 개? 100만 개?
  • 검색 속도가 느리다
    • 1개 검색 시 2초, 1억 2천만 개 전체 검색 시 약 7.61(년) 걸림

 

image feature size 줄이기

1개 image feature → (3+1+2+1) * 512 = 3,584(byte) 필요

3+1+2+1 = (layer_no average 3byte) + (colon 1byte) + (intensity average 2 byte) + (comma 1byte)

120,000,000개 image feature를 저장하는데 필요한 메모리 공간

3,584(byte) * 120,000,000 = 약 430GB

허용된 메모리는.. 단 62GB

데이터의 규모가 너무 크다. 과연 모든 Feature가 필요할까?

512개 feature가 모두 필요하지는 않고, 그중 가장 큰 특징을 내는 feature 25개만 저장한다.

  • (3+1+2+1) * 25 = 175(byte) , 175 * 120,000,000 = 21GB

4byte int로 저장할 경우

  • (2 byte int) + (2 byte int) = 4 byte , 4 * 25 = 100(byte) , 100 * 120,000,000 = 12GB

3 byte를 binary 형식으로 저장하여 사이즈를 더 줄인다.

  • layer_no:intensity 를 3 byte에 저장
    • layer_no : 14 bt
    • intensity : 10 bit (1024 숫자까지 표현)
  • 3(byte) * 25 = 75(byte) , 75(byte)로 1개의 image feature 를 저장한다.
  • 75 * 120,000,000 = 9GB

Search Data 만들기

(Inverted Index는 엘라스틱 서치의 베이스인 아파치 루씬의 검색을 위한 기본 아이디어입니다. )

현재 G마켓 live 상품번호는 제일 처음에 등록된 상품번호는 1, 그 후 등록된 상품번호는 2, 3, 4, 5, … 형식으로

연속된 숫자로 표현되고 있습니다. (현재 최신 상품번호는 약 20억이 넘는 숫자로 표현되어 있습니다.)

위와 같이 각 key 마다, G마켓의 실제 상품번호를 그대로 문자열로 저장하는 경우

숫자 2,000,000,000 = 10 byte 문자열

  • 512개의 각 key 에 약 10,000,000 ~ 80,000,000 개의 상품 번호가 저장된다.
  • 각 키에 약 50,000,000 개의 상품번호를 저장할 경우 필요한 메모리.
  • 10 byte * 50,000,000 = 500,000,000 (byte) = 500M

512 개 key에 모두 저장하면 500M * 512 = 256GB

허용된 메모리는.. 단 62GB.. 줄여야 한다.

 

bit field로 저장한다면?

2,000,000,000개의 상품번호를 중복하여 저장하려면 2,000,000,000/8 byte(250M byte)가 필요하다.

250M * 512 개 Key = 128GB

메모리 사용은 반으로 줄었지만.. 허용된 메모리는.. 단 62GB.. 줄여야 한다.

상품 번호 index의 사용

실제 상품 번호의 숫자가 크기 때문에, 그 보다 약 1/20 작은 index번호를 만들어 메모리 사용량을 줄이고,
연산 속도를 높입니다.

Live 상품 번호는 높지만 이렇게 인덱스를 매기게 되면 실제 상품의 개수는 약 1억 2천 개로 정리가 되며
공간이 절약됩니다.

120,000,000개의 상품번호를 중복하여 저장하려면 120,000,000/8 byte(15M byte)가 필요합니다.

120,000,000 / 8 * 512 = 7.68GB

 

드디어 용량 문제가 해결이 되었습니다.

 

 


검색 방법

query image에서 image feature(25개)를 뽑는다.

layer_no(feature map layer no) : intensity(average) 
  • 25:34,37:28,128:25,12:23,150:22,479:16,58:16,438:16,146:15,157:15,93:14,511:14,118:14, 502:14,71:13,178:13,12:12,26:12,52:11,70:11,309:9,18:8,79:8,177:8,330:8,340:8,428:8

​ 큰 특징을 나타내는 feature 순으로, 그 feature를 가지는 상품번호를 모두 찾는다.

  • 첫 번째 feature를 가진 상품번호(bit field) & 두 번째 feature를 가진 상품번호(bit field)
  • 위의 방법으로 세 번째, 네 번째 feature도 가지고 있는 상품 번호를 찾는다.
    그러면 상품번호의 개수는 점점 줄어들게 된다.
  • 상품 번호의 개수가 약 300개 정도 될 때까지 위의 과정을 반복한다.
  • 위의 과정은 redis의 bitwise AND operation 함수를 이용하여 수행한다

Redis bitwise AND operation search의 단점과 해결책

단점

  • Redis는 Single Thread로 작동하기에, 병렬로 동시에 10개의 요청이 들어오면 2.5초(0.25초 * 10)의 시간이 소요됩니다.
  • 또한 검색을 redis에 의존하게 되면, AND 연산 중에 다른 처리 요청이 들어올 경우 AND 연산이 끝날 때까지 처리가 되지 않습니다.

해결책

search를 redis에 의존하지 않고 별도로 만든다.

python 개발

  • 12개 core를 사용하여 100개의 유사 이미지 검색을 수행시키면, 약 45초 걸림.
  • 1개 검색에 약 0.45초
    • redis bitwise operation 보다 느린 결과
    • redis bitwise operation은 C로 구현되어 빠르다
    • 단점은 redis 자체가 single thread라 병렬 처리를 할 수 없다.
  • multi process로 처리할 수 있게 되었다.
    • process를 100개를 띄우면 속도가 10배(0.045초) 빨라진다.

하지만 너무 느리다.

속도 향상을 위하여 C로 porting

  • 10개 core를 사용하여 100개의 유사 이미지 검색을 수행시키면, 약 4.3초 걸림.
  • 1개 검색 시 약 0.04(초) 걸림.
    • python process 100개를 띄운 효과가 있다.
    • python 에 비하여 약 10배 이상의 속도 향상이 있다.

C 검색 루틴 튜닝

메모리 절약

  • 7.68G의 검색용 데이터를 512개의 file로 저장하여, 각 process 마다 7.68G의 검색 데이터를 중복하여
    직접 메모리에 올리지 않도록 한다.
  • 필요시에만 파일에서 데이터를 읽어 오도록 한다.
    • 10개 process로 수행하여도, 실제로 사용하는 메모리는 1G 이하가 되게 한다.
  • file 입출력 속도 줄이기
    • 일반 file이 아니라, memory mapped file 사용
    • shared memory를 사용
      • memory mapped file을 복수 개의 process에서 공유하여 사용하도록 한다.

튜닝 결과

  • 10개의 core를 사용 시
    • 100,000개 1590(초), 1,000,000개 15,900(초) (약 4.4시간)
    • 1 개 검색 시 약 0.0159(초) 소요
    • 100개 core 사용 시 0.00159(초)

1,000,000개 검색 약 4.4시간

이러한 노력 끝에 검색 성능까지 개선되었습니다.

 


시스템 개략도

사용자가 상품을 클릭하게 되면 API 서버에 해당 상품의 이미지와 비슷한 이미지의 데이터를 요청합니다.

API 서버는 시각 이미지 검색 서버에 해당 데이터 요청 후 응답을 가공하여 클라이언트에게 전달합니다.


Daily 이미지 추출 System

새로 추가되거나 수정된 이미지는 매일 배치 작업을 통해 저장소에 업데이트되고 있습니다.

 


마치며

이렇게 구성된 유사 이미지 추천 서비스는 현재 Gmarket App에 전체 카테고리를 대상으로 운영되고 있습니다.

내년에는 옥션 App에도 서비스하기 위해 개발 중에 있습니다.

 

지금까지 Gmarket의 유사이미지 추천 기능에 대해서 알아보았습니다.

도움 주신 유사이미지 추천 기능 개발자 염경춘님께 감사의 말씀드립니다.

긴 글 읽어주셔서 감사합니다.

댓글
댓글쓰기 폼