SingleStoreDB 벡터 함수로 이미지 유사도 구하기

Jongsoo Noh·2023년 3월 23일
0

SingleStore

목록 보기
20/20
post-thumbnail

머리말

이번 글은 SingleStoreDB 의 Vector 함수를 이용한 이미지 유사도, 정확하게는 벡터간 내적을 이용한 유사도를 구하는 예제입니다.

아래 SingleStore Blog 를 참조했습니다.
https://www.singlestore.com/blog/image-matching-in-sql-with-singlestoredb/

제일 간단하게 이미지 유사도를 얻는 방법은 미리 생성된 7161개의 Image Vector 를 people 테이블에 저장한 후 그 안에서 이미지 유사도를 체크하는 것입니다.

Quick Start

celebrity_data.sql 을 다음 Google Drive 에서 다운로드 한 후 SingleStoreDB 장비에 업로드합니다.

https://drive.google.com/file/d/18Nk20PG6XxMIe2-tWKXcixyMipuMHt4R/view?usp=sharing

해당 파일은 다음과 같은 형식으로 7161개의 Insert 문장으로 구성되어 있습니다. 128개의 항목으로 구성된 Vector 를 BLOB 형식으로 변환하여 파일명과 함께 저장하게 됩니다.

insert into people values(
"Max_von_Sydow/Max_von_Sydow_0001.jpg", 
json_array_pack("[-0.11498698592185974, -0.07706524431705475, . . .  -0.00044909791904501617, -0.11840023845434189]"));

테이블을 만들고 데이터를 insert 합니다

create table people (filename varchar(255), vector blob, shard(filename));
source celebrity_data.sql;

유사도 검사는 dot_product 를 사용합니다. 벡터의 내적을 구하는 함수입니다.

벡터간의 내적을 통해서 벡터를 구성하는 요소들간의 관계가 얼마나 밀접한지 알 수 있으며 1에 가까울 수록 유사도가 높고 0에 가까울 수록 유사도가 없다고 할 수 있습니다.

singlestore> select filename, dot_product(vector, v) as score
    -> from people,
    ->      (select vector as v
    ->       from people
    ->       where filename = "Winona_Ryder/Winona_Ryder_0011.jpg")
    -> order by score desc
    -> limit 5;
+------------------------------------+--------------------+
| filename                           | score              |
+------------------------------------+--------------------+
| Winona_Ryder/Winona_Ryder_0011.jpg | 0.9999999403953552 |
| Winona_Ryder/Winona_Ryder_0010.jpg | 0.8344369530677795 |
| Winona_Ryder/Winona_Ryder_0009.jpg | 0.8271929621696472 |
| Winona_Ryder/Winona_Ryder_0020.jpg | 0.7829042673110962 |
| Winona_Ryder/Winona_Ryder_0008.jpg |  0.777327835559845 |
+------------------------------------+--------------------+
5 rows in set (0.00 sec)

"Winona_Ryder_0011.jpg" 이라는 파일명에 해당하는 벡터를 구해 dot_product 함수로 테이블의 모든 vector 의 내적을 구해 가장 유사도가 큰 순서로 5개를 나열하니 모두 위노나 라이더의 파일들을 보여주고 있습니다.

같은 장소에서 같은 시간에 찍힌 사진들이 유사하게 나오고 있네요. 실제 저장된 파일은 아래와 같습니다.

다른 이미지로 벡터 생성후 유사도 체크

구글에서 찾은 아래 이미지로 벡터를 만들겠습니다. 위노나 라이더의 사진으로 위 리스트와는 조금 다른 모습으로 골랐습니다.

벡터 만드는 방법은 원래 Blog ( https://www.singlestore.com/blog/image-matching-in-sql-with-singlestoredb/ )에 설명되어 있으므로 해당 글에서 언급한 대로 python 3.9, tensorflow, facenet 등을 설치하고 따라하면 가능합니다.

생성된 벡터를 변수 v 에 저장합니다.

set @v = json_array_pack('[-0.03780638799071312, 0.07395680993795395, -0.015616362914443016, -0.03179147094488144, -0.08830723911523819, 0.09027735888957977, 0.12396328896284103, 0.013575875200331211, -0.08650781959295273, -0.07209326326847076, 0.09793207794427872, 0.05709252879023552, -0.04023003578186035, 0.14975067973136902, 0.10445944219827652, 0.10415973514318466, 0.019815005362033844, -0.0627552941441536, -0.19538944959640503, 0.10224207490682602, -0.08927532285451889, 0.03779282048344612, -0.13858665525913239, -0.041312675923109055, 0.03474624082446098, -0.08430100232362747, 0.09628234058618546, -0.1009807363152504, 0.019152343273162842, 0.12146738916635513, 0.13661067187786102, 0.06908190995454788, 0.10235368460416794, 0.029023468494415283, -0.026075270026922226, -0.06621786206960678, 0.06574148684740067, -0.01001928374171257, -0.05440671741962433, 0.16115085780620575, 0.1088806688785553, 0.003563736565411091, -0.16167475283145905, -0.0790223777294159, 0.029756927862763405, -0.1589423269033432, -0.004182749893516302, 0.05354636535048485, 0.2056141048669815, 0.09790534526109695, -0.04670286551117897, -0.036865800619125366, 0.11992967873811722, -0.040894076228141785, 0.02599705383181572, -0.011481598019599915, 0.007726398762315512, 0.06719265133142471, 0.06331252306699753, -0.07907164841890335, -0.0011076019145548344, 0.034705180674791336, -0.015078789554536343, 0.1283341944217682, 0.05731748417019844, 0.028007954359054565, 0.0401611290872097, 0.02418236993253231, 0.0531611330807209, -0.02330959402024746, -0.03532962501049042, 0.00527904974296689, 0.20329520106315613, 0.05922047793865204, -0.03517293184995651, -0.18295474350452423, 0.06496357172727585, -0.03927427902817726, -0.030000027269124985, 0.13033461570739746, -0.21222658455371857, -0.014778239652514458, -0.036381348967552185, 0.051467131823301315, 0.11100602149963379, 0.16885623335838318, 0.04631807282567024, -0.03362177684903145, -0.015608654357492924, 0.14769379794597626, -0.040230024605989456, 0.07539396733045578, 0.022581620141863823, -0.05388599634170532, 0.054645538330078125, 0.06474482268095016, 0.1563086211681366, 0.0645790845155716, 0.0005070041515864432, 0.04836813360452652, -0.11997682601213455, 0.058164454996585846, -0.06869622319936752, 0.1675301492214203, 0.11051632463932037, -0.000605833949521184, 0.019346462562680244, 0.1255461424589157, 0.013662147335708141, 0.03440195322036743, -0.010617092251777649, 0.004071109928190708, 0.12172971665859222, -0.034963805228471756, -0.08145664632320404, 0.006116472650319338, 0.0770099088549614, 0.017310427501797676, 0.049548737704753876, -0.12094640731811523, 0.07858401536941528, -0.003873147303238511, -0.036694224923849106, -0.16348500549793243, -0.1578969657421112, 0.07876384258270264, -0.19576381146907806, 0.05358898639678955]');

해당 벡터를 이용해 유사도를 검사합니다.

singlestore> select filename, dot_product(vector, @v) as score
    -> from people
    -> order by score desc
    -> limit 5;
+--------------------------------------+--------------------+
| filename                             | score              |
+--------------------------------------+--------------------+
| Winona_Ryder/Winona_Ryder_0007.jpg   | 0.5486093163490295 |
| Eve_Ensler/Eve_Ensler_0001.jpg       | 0.5300491452217102 |
| Erin_Runnion/Erin_Runnion_0004.jpg   | 0.5061808228492737 |
| Winona_Ryder/Winona_Ryder_0005.jpg   |  0.500889778137207 |
| Bonnie_Fuller/Bonnie_Fuller_0001.jpg |  0.491347998380661 |
+--------------------------------------+--------------------+
5 rows in set (0.00 sec)

다행히 위노나 라이더가 제일 먼저 나왔습니다.
다른 그림들은 왜 유사하다고 나왔는지 순서대로 살펴 보겠습니다.

어떻게 비슷해 보이시나요?

마무리

단순하게 Dot Product 함수 만으로 100% 유사도를 확정할 수는 없겠지만 SingleStoreDB 만의 다양한 Vector Function 중의 하나인 Dot Product 를 이용한 재미있는 사례라서 소개해 드렸습니다.

Feature Vector 를 저장해 검색에 사용하거나, Model Training 대상 데이터 소스로 SingleStoreDB 의 빠른 Ingest/Query 를 활용하거나, SIMD 기능을 native 하게 구현한 Vector Function 을 사용하는 등 AI, ML 처리에서도 SingleStoreDB 의 강점을 충분히 이용하실 수 있습니다.

profile
Database Guy

0개의 댓글