๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
1๏ธโƒฃ AI•DS/๐ŸŒ LLM

12. ๋ฒกํ„ฐ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ํ™•์žฅํ•˜๊ธฐ : RAG ๊ตฌํ˜„ํ•˜๊ธฐ

by isdawell 2025. 10. 22.
728x90
โ˜€๏ธ  Summary 

โ  ๋ฒกํ„ฐ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
โ  Indexing & Search : KNN, ANN(HNSW, IVF)
โ  ํŒŒ์ธ์ฝ˜

 

 

 

 

1.   ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ž€ 


 

1.1  ๋”ฅ๋Ÿฌ๋‹๊ณผ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค 

 

โ  ๋ฒกํ„ฐ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

 โ†ช๏ธŽ  ๋ฒกํ„ฐ ์ž„๋ฒ ๋”ฉ์„ ํ‚ค๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋งํ•œ๋‹ค. ๋ฒกํ„ฐ ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ์— ํŠนํ™”๋œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ด๋‹ค. 

 โ†ช๏ธŽ  ํ…์ŠคํŠธ, ์ด๋ฏธ์ง€ ๋“ฑ์˜ ๋น„์ •ํ˜• ๋ฐ์ดํ„ฐ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ƒํ’ˆ/์‚ฌ์šฉ์ž ๊ฐ™์€ ๊ฐœ๋…๋„ ๋ชจ๋‘ ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ์„ ํ†ตํ•ด ๋ฒกํ„ฐ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 โ†ช๏ธŽ  ์ ์ ˆํ•œ ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ž„๋ฒ ๋”ฉ ๋ฒกํ„ฐ๋กœ ๋ณ€ํ™˜ํ–ˆ๋‹ค๋ฉด, ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๊ณ , ์ž„๋ฒ ๋”ฉ ๋ฒกํ„ฐ์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ์„ ํ†ตํ•ด ์œ ์‚ฌํ•˜๊ฑฐ๋‚˜ ๊ด€๋ จ์ด ๊นŠ์€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

โ  ๋”ฅ๋Ÿฌ๋‹๊ณผ ๋ฒกํ„ฐDB

 

 

โ†ช๏ธŽ  ๋จธ์‹ ๋Ÿฌ๋‹๊ณผ ๋‹ฌ๋ฆฌ ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์€ Representation learning (ํ‘œํ˜„ํ•™์Šต) ์„ ํ†ตํ•ด, ๋ฐ์ดํ„ฐ๋งŒ ์ถฉ๋ถ„ํ•˜๋‹ค๋ฉด ๋ชจ๋ธ์ด ์•Œ์•„์„œ ๋ฐ์ดํ„ฐ์˜ ํŠน์ง•์ถ”์ถœ๊นŒ์ง€๋„ ์ž๋™์œผ๋กœ ํ•™์Šตํ•œ๋‹ค. 

 โ†ช๏ธŽ  ํ‘œํ˜„ํ•™์Šต์ด ์ œ๋Œ€๋กœ ์ˆ˜ํ–‰๋œ ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ๋กœ ์ž„๋ฒ ๋”ฉ์„ ๊ณต๊ฐ„์ƒ์— ๋ฐฐ์น˜ํ•˜๋ฉด, ๋น„์Šทํ•œ ํŠน์ง•์„ ๊ฐ€์ง„ ๋ฐ์ดํ„ฐ๋Š” ๊ฐ€๊น๊ฒŒ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋Š” ๋ฉ€๊ฒŒ ์œ„์น˜ํ•˜๊ฒŒ ๋œ๋‹ค. ์ด๋Ÿฌํ•œ ์ž„๋ฒ ๋”ฉ ๋ฒกํ„ฐ์˜ ํŠน์ง•์„ ์ด์šฉํ•˜๋ฉด ๋ฒกํ„ฐ ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•ด ์„œ๋กœ ๋น„์Šทํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค. ๋ฒกํ„ฐDB๋Š” ์ด๋Ÿฌํ•œ ์ž„๋ฒ ๋”ฉ๋ฒกํ„ฐ์˜ ํŠน์ง•์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์œผ๋กœ ๊ฐœ๋ฐœ๋˜์—ˆ๋‹ค. 

 

 

โ  ๋ฒกํ„ฐDBํ™œ์šฉ 3๋‹จ๊ณ„

 

 

 โ†ช๏ธŽ  1) ์ €์žฅ : ์ €์žฅํ•  ๋ฐ์ดํ„ฐ๋ฅผ ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ์„ ๊ฑฐ์ณ ๋ฒกํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , ๋ฒกํ„ฐDB์— ์ €์žฅํ•œ๋‹ค. 

 โ†ช๏ธŽ  2) ๊ฒ€์ƒ‰ : ๊ฒ€์ƒ‰ํ•  ๋ฐ์ดํ„ฐ(ex.๊ฒ€์ƒ‰์ฟผ๋ฆฌ)๋ฅผ ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ์„ ๊ฑฐ์ณ ๋ฒกํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , ๋ฒกํ„ฐDB์—์„œ ๊ฒ€์ƒ‰ํ•œ๋‹ค. 

 โ†ช๏ธŽ  3) ๊ฒฐ๊ณผ๋ฐ˜ํ™˜ : ๋ฒกํ„ฐDB์—์„œ๋Š” ๊ฒ€์ƒ‰์ฟผ๋ฆฌ์˜ ์ž„๋ฒ ๋”ฉ๊ณผ ๊ฑฐ๋ฆฌ๊ฐ€ ๊ฐ€๊นŒ์šด ๋ฒกํ„ฐ๋ฅผ ์ฐพ์•„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 

 

 โ†ช๏ธŽ  ๋ฒกํ„ฐ ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ๋ฅผ ์ธก์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์œ ํด๋ฆฌ๋””์•ˆ๊ฑฐ๋ฆฌ, ์ฝ”์‚ฌ์ธ์œ ์‚ฌ๋„, ์ ๊ณฑ(๋‚ด์ )์„ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค. 

 โ†ช๏ธŽ  ๋”ฅ๋Ÿฌ๋‹ ๊ธฐ์ˆ ์ด ํญ๋„“๊ฒŒ ํ™œ์šฉ๋˜๋ฉฐ ๋ฐ์ดํ„ฐ์˜ ํŠน์ง•์„ ์ถ”์ถœํ•œ ์ž„๋ฒ ๋”ฉ์„ ํ™œ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„์กŒ๊ณ , ์ž„๋ฒ ๋”ฉ์„ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์š”๊ตฌ๋˜๋ฉฐ ์—ฌ๋Ÿฌ ๋ฒกํ„ฐDB๊ฐ€ ๋“ฑ์žฅํ–ˆ๋‹ค. ํ•€ํ„ฐ๋ ˆ์ŠคํŠธ๊ฐ™์€ ์ด๋ฏธ์ง€ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์ด๋‚˜ ์ถ”์ฒœ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•  ๋•Œ ๋งŽ์ด ํ™œ์šฉํ•œ๋‹ค. ์ž„๋ฒ ๋”ฉ ๋ฒกํ„ฐ์˜ ์œ ์‚ฌ๋„๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๋ฌธ์„œ ๊ฒ€์ƒ‰์„ ํ™œ์šฉํ•˜๋Š” RAG๊ฐ€ LLM์˜ ํ™˜๊ฐํ˜„์ƒ์„ ์ค„์ด๊ณ  ํ•™์Šต ์—†์ด๋„ ์ตœ์‹  ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ํ•ต์‹ฌ ๊ธฐ๋ฒ•์œผ๋กœ ํ™œ์šฉ๋˜์–ด ์ง€๊ธˆ์€ ๋Œ€๋ถ€๋ถ„์˜ DB์— ๋ฒกํ„ฐ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜๊ณ  ์žˆ๋‹ค. 

 

 

 

1.2  ๋ฒกํ„ฐ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ง€ํ˜• ํŒŒ์•…ํ•˜๊ธฐ 

 

โ  ๋ฒกํ„ฐ์ž„๋ฒ ๋”ฉ๊ณผ ๊ด€๋ จํ•œ ์†Œํ”„ํŠธ์›จ์–ด ์ข…๋ฅ˜

 โ†ช๏ธŽ  1) ๋ฒกํ„ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ : Faiss, Annoy, NMSLIB, ScaNN 

       โ†ช๏ธŽ  ์†Œ๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋ฒกํ„ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด์„œ ์ถฉ๋ถ„ํžˆ ๋ฒกํ„ฐ ์ €์žฅ ๋ฐ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 โ†ช๏ธŽ  2) ๋ฒกํ„ฐ ์ „์šฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค : Pinecone, Weaviate, Milvus, Chroma, Qdrant, Vespa 

       โ†ช๏ธŽ  ์ €์žฅ, ๊ฒ€์ƒ‰, ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ €์žฅ ๋ฐ ํ•„ํ„ฐ๋ง, ๋ฐฑ์—… ๋ฐ ๊ด€๋ฆฌ, ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ AI๋„๊ตฌ ๋“ฑ๊ณผ์˜ ํ†ตํ•ฉ, ๋ณด์•ˆ ๋ฐ ์—‘์„ธ์Šค ๊ด€๋ฆฌ 

 โ†ช๏ธŽ  3) ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฒกํ„ฐ ์ €์žฅ๊ณผ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ : Elasticsearch, PostgreSQL, MongoDB, Neo4j 

 

 

โ  ๋ฒกํ„ฐ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ตฌ๋ถ„

 

 

 โ†ช๏ธŽ  ๊ณ ๊ธ‰ ๋ฒกํ„ฐ ๊ฒ€์ƒ‰์ด๋‚˜ ์›Œํฌ๋กœ๋“œ(๋ฐ์ดํ„ฐ์ˆ˜, ์ฐจ์›์ˆ˜ ๋“ฑ)๊ฐ€ ํฐ ๊ฒฝ์šฐ, ์™ผ์ชฝ์˜ ๋ฒกํ„ฐ ์ „์šฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ข‹๊ณ , ๋ฒกํ„ฐ ์ด์™ธ์˜ ๋ฐ์ดํ„ฐ ํ˜•ํƒœ ์ฒ˜๋ฆฌ๊นŒ์ง€๋„ ์›ํ•œ๋‹ค๋ฉด ์˜ค๋ฅธ์ชฝ ์ „์šฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. 

 

 

 

 

2.   ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘๋™ ์›๋ฆฌ 


 

2.1  KNN๊ฒ€์ƒ‰๊ณผ ํ•œ๊ณ„ 

 

โ  KNN๊ฒ€์ƒ‰

 โ†ช๏ธŽ  ๊ฒ€์ƒ‰ํ•˜๋ ค๋Š” ๋ฒกํ„ฐ์™€ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด K๊ฐœ์˜ ์ด์›ƒ ๋ฒกํ„ฐ๋ฅผ ์ฐพ๋Š” ๊ฒ€์ƒ‰ ๋ฐฉ์‹

 โ†ช๏ธŽ  ์ง๊ด€์ ์ด๊ณ  ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ์‚ฌํ•˜๋ฏ€๋กœ ์ •ํ™•ํ•˜์ง€๋งŒ, ๊ทธ๋งŒํผ ์—ฐ์‚ฐ๋Ÿ‰์ด ๋ฐ์ดํ„ฐ ์ˆ˜์— ๋น„๋ก€ํ•˜์—ฌ ์†๋„๊ฐ€ ๋А๋ ค์ ธ ํ™•์žฅ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ๋‹ค. 

 

 

โ  ๋ฒกํ„ฐ๊ฒ€์ƒ‰

 โ†ช๏ธŽ  1) Indexing (์ƒ‰์ธ) : ์ธ๋ฑ์Šค์— ๋ฒกํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณผ์ • (๊ฒ€์ƒ‰์„ ์œ„ํ•ด ์ผ์ข…์˜ ์ง€๋„๋‚˜ ๋ชฉ์ฐจ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ) โžฑ ์ธ๋ฑ์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰๊ณผ ์ƒ‰์ธ ์‹œ๊ฐ„์ด ์ค‘์š”

 โ†ช๏ธŽ  2) Search : ๊ฒ€์ƒ‰ ์‹œ๊ฐ„๊ณผ ์žฌํ˜„์œจ(Recall)์ด ์ค‘์š”

 โ†ช๏ธŽ  Recall : ์‹ค์ œ๋กœ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด K๊ฐœ์˜ ์ •๋‹ต ๋ฐ์ดํ„ฐ ์ค‘ ๋ช‡ ๊ฐœ๊ฐ€ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜๋˜์—ˆ๋Š”์ง€ ๋น„์œจ์„ ๋‚˜ํƒ€๋‚ธ ๊ฐ’, KNN์€ ๋ชจ๋“  ๋ฒกํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ฏ€๋กœ ํ•ญ์ƒ 100% 

 

 

 

 

โ  ์‹ค์Šต๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

 

import time
import faiss
from faiss.contrib.datasets import DatasetSIFT1M

ds = DatasetSIFT1M()

xq = ds.get_queries()
xb = ds.get_database()
gt = ds.get_groundtruth()

 

 โ†ช๏ธŽ  SIFT1M : 100๋งŒ๊ฐœ์˜ 128์ฐจ์› ์ž„๋ฒ ๋”ฉ ๋ฐ์ดํ„ฐ

 โ†ช๏ธŽ  faiss ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ œ๊ณตํ•˜๋Š” DatasetSIFT1M ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด, ๋‚ด๋ ค๋ฐ›์€ SIFT1M๋ฐ์ดํ„ฐ์…‹์„ ๋ถˆ๋Ÿฌ์˜จ๋‹ค. 

 โ†ช๏ธŽ  xq : ๊ฒ€์ƒ‰์— ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ, xb : ์ €์žฅ๋œ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ, gt : ์‹ค์ œ ์ •๋‹ต ๋ฐ์ดํ„ฐ 

 

 

 

โ  ๋ฐ์ดํ„ฐ๊ฐ€ ๋Š˜์–ด๋‚  ๋•Œ ์ƒ‰์ธ/๊ฒ€์ƒ‰์‹œ๊ฐ„, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋ณ€ํ™”

 

k=1
d = xq.shape[1] 
nq = 1000 # ๊ฒ€์ƒ‰ํ•  ๋ฐ์ดํ„ฐ ์ˆ˜ : 1000๊ฐœ 
xq = xq[:nq] 

for i in range(1, 10, 2): # ์ €์žฅํ•˜๋Š” ๋ฐ์ดํ„ฐ์ˆ˜๋ฅผ ์ ์ฐจ ๋Š˜๋ฆฌ๊ธฐ 
    start_memory = get_memory_usage_mb() 
    start_indexing = time.time() 
    index = faiss.IndexFlatL2(d) # ์ธ๋ฑ์Šค ๋งŒ๋“ค๊ธฐ 
    index.add(xb[:(i+1)*100000]) # add๋ฉ”์„œ๋“œ๋กœ ์ž„๋ฒ ๋”ฉ ๋ฒกํ„ฐ๋ฅผ ์ƒ‰์ธ 
    end_indexing = time.time()
    end_memory = get_memory_usage_mb() # ๋ฉ”๋ชจ๋ฆฌ์‚ฌ์šฉ๋Ÿ‰ ์ธก์ • (์ง์ ‘ ํ•จ์ˆ˜ ์ •์˜)

    t0 = time.time() 
    D, I = index.search(xq, k) # search ๋ฉ”์„œ๋“œ๋กœ ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰ 
    t1 = time.time()
    print(f"๋ฐ์ดํ„ฐ {(i+1)*100000}๊ฐœ:")
    print(f"์ƒ‰์ธ: {(end_indexing - start_indexing) * 1000 :.3f} ms ({end_memory - start_memory:.3f} MB) ๊ฒ€์ƒ‰: {(t1 - t0) * 1000 / nq :.3f} ms")

 

 

 โ†ช๏ธŽ  ๋ฐ์ดํ„ฐ๊ฐ€ ๋Š˜์–ด๋‚˜๋ฉด์„œ ์ƒ‰์ธ ์‹œ๊ฐ„์ด ๋Š˜์–ด๋‚˜๊ณ , ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰๋„ ์ง€์†์ ์œผ๋กœ ์„ ํ˜•์ ์œผ๋กœ ์ฆ๊ฐ€ํ•œ๋‹ค. 

 โ†ช๏ธŽ  KNN๊ฒ€์ƒ‰์˜ ๊ฒฝ์šฐ์—๋Š”, ์ธ๋ฑ์Šค์— ๋” ๋น ๋ฅธ ๊ฒ€์ƒ‰์„ ์œ„ํ•œ ๋ณ„๋„ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š์•„ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ž‘๊ณ , ์ƒ‰์ธ์‹œ๊ฐ„๋„ ๊ฑฐ์˜ ๋ฌด์‹œํ•  ์ •๋„์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ๋‹ค. ๊ฒ€์ƒ‰์‹œ๊ฐ„์ด ๋ฌธ์ œ์ธ ๊ฒƒ

 โ†ช๏ธŽ  ์ž„๋ฒ ๋”ฉ ๋ฒกํ„ฐ์˜ ์ฐจ์›์ด ์ปค์ง€๋ฉด ๊ฒ€์ƒ‰์— ๋” ์˜ค๋žœ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ๋‹ค. ์ฆ‰, ๋ฒกํ„ฐ์˜ ์ฐจ์›์ด ์ปค์ง€๋ฉด ๊ฒ€์ƒ‰ ์†๋„๊ฐ€ ๋А๋ ค์ง„๋‹ค. ์‹ค์‚ฌ๋ก€์—์„œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ํฌ๊ณ  ๊ณ ์ฐจ์›์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ํšจ์œจ์ ์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋‹ค์–‘ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋“ฑ์žฅํ–ˆ๋‹ค. 

 

 

 

 

2.2  ANN ๊ฒ€์ƒ‰์ด๋ž€ 

 

โ  ANN

 โ†ช๏ธŽ  ๊ทผ์‚ฌ์ตœ๊ทผ์ ‘์ด์›ƒ ๊ฒ€์ƒ‰์€ ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ์—์„œ ์ฃผ์–ด์ง„ ์ฟผ๋ฆฌ ํ•ญ๋ชฉ๊ณผ ๊ฐ€์žฅ ์œ ์‚ฌํ•œ ํ•ญ๋ชฉ์„ ํšจ์œจ์ ์œผ๋กœ ์ฐพ๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ์ˆ  

 โ†ช๏ธŽ  ์•ฝ๊ฐ„์˜ ์ •ํ™•๋„๋ฅผ ํฌ์ƒํ•˜๋Š” ๋Œ€์‹  ํ›จ์”ฌ ๋” ๋น ๋ฅธ ๊ฒ€์ƒ‰์†๋„๋ฅผ ์ œ๊ณต 

 โ†ช๏ธŽ  ๊ฒ€์ƒ‰ ์‹œ ํƒ์ƒ‰ ํ•  ๋ฒ”์œ„๋ฅผ ์ขํžˆ๋Š”๋ฐ ์ง‘์ค‘ 

 โ†ช๏ธŽ  ๋Œ€ํ‘œ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ : IVF, HNSW 

 

 

โ  IVF

 

 โ†ช๏ธŽ  ๊ฒ€์ƒ‰ ๊ณต๊ฐ„์„ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด, ๋ฐ์ดํ„ฐ์…‹ ๋ฒกํ„ฐ๋“ค์„ ํด๋Ÿฌ์Šคํ„ฐ๋กœ ๊ทธ๋ฃนํ™”ํ•˜๋Š” ANN ์•Œ๊ณ ๋ฆฌ์ฆ˜ 

 โ†ช๏ธŽ  ์ธ๋ฑ์‹ฑ ์‹œ์ ์— IVF๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€ ์ค‘์‹ฌ์ (์œ ์‚ฌํ•œ ๋ฒกํ„ฐ๋“ค์˜ ํด๋Ÿฌ์Šคํ„ฐ)์„ ํ˜•์„ฑ 

 โ†ช๏ธŽ  ์ฟผ๋ฆฌ ์‹œ์ ์—๋Š” ๋จผ์ € ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์ค‘์‹ฌ์ ์„ ์ฐพ๊ณ , ํ•ด๋‹น ์ค‘์‹ฌ์  ๋‚ด์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ๋ฅผ ์ฐพ๋Š”๋‹ค 

 โ†ช๏ธŽ  ๊ฒ€์ƒ‰๋˜์ง€ ์•Š์€ ํด๋Ÿฌ์Šคํ„ฐ์— ํ• ๋‹น๋œ ์ผ๋ถ€ ์ด์›ƒ์„ ๋†“์น  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋‹จ์ 

 

 

 

โ  HNSW

 

 โ†ช๏ธŽ  ํšจ์œจ์ ์ธ ANN๊ฒ€์ƒ‰์„ ์œ„ํ•œ ๊ทธ๋ž˜ํ”„ ๊ธฐ๋ฐ˜ ์ธ๋ฑ์‹ฑ ๊ตฌ์กฐ 

 โ†ช๏ธŽ ์ƒ์œ„ ๊ณ„์ธต์€ ์—ฐ๊ฒฐ์ด ์ ๊ณ , ํ•˜์œ„ ๊ณ„์ธต์€ ์—ฐ๊ฒฐ์ด ๋ฐ€์ง‘๋œ ๋‹ค์ธต ๊ทธ๋ž˜ํ”„๋ฅผ ๊ตฌ์ถ•ํ•œ๋‹ค. 

 โ†ช๏ธŽ ์ตœ์ƒ์œ„ ๊ณ„์ธต์€ ์—ฐ๊ฒฐ์ด ์ ์–ด์„œ ๋ฐ์ดํ„ฐ ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ๊ฐ€ ๋จผ๋ฐ, ํ•œ ๋ฒˆ์— ๋จผ ๊ฑฐ๋ฆฌ๋ฅผ ์ด๋™ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ทธ๋ž˜ํ”„๋ฅผ ๋น ๋ฅด๊ฒŒ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ ํ•˜์œ„ ๊ณ„์ธต์—๋Š” ๋” ๋งŽ์€ ์—ฐ๊ฒฐ์ด ์žˆ์–ด ๊ผผ๊ผผํ•œ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค. 

 

 

โ  ANN ๊ฒ€์ƒ‰์˜ ์žฌํ˜„์œจ

 โ†ช๏ธŽ  ์žฌํ˜„์œจ = (์˜ˆ์ธก ์ค‘ ์ •๋‹ต์— ํ•ด๋‹นํ•˜๋Š” ์ˆ˜)/(์‹ค์ œ์ •๋‹ต์ˆ˜)

 โ†ช๏ธŽ  K : ๊ฒ€์ƒ‰ํ•  ๊ทผ์ ‘ ๋ฐ์ดํ„ฐ์˜ ์ˆ˜ 

 โ†ช๏ธŽ  ANN ๊ฒ€์ƒ‰์˜ ์žฌํ˜„์œจ = (KNN์œผ๋กœ ์ฐพ์€ ์‹ค์ œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด K๊ฐœ ์ค‘ ANN์ด ์ฐพ์€ ๊ฐœ์ˆ˜)/K

 

 

 

2.3  ํƒ์ƒ‰๊ฐ€๋Šฅํ•œ ์ž‘์€์„ธ๊ณ„ (NSW) 

 

โ  ๊ทธ๋ž˜ํ”„ ๊ตฌ์กฐ 

 โ†ช๏ธŽ  ๋…ธ๋“œ(node) : ๋ฒกํ„ฐ ์ž„๋ฒ ๋”ฉ

 โ†ช๏ธŽ  edge : ์„œ๋กœ ์—ฐ๊ฒฐ๋œ ๋…ธ๋“œ๋ผ๋ฆฌ๋งŒ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋…ธ๋“œ์™€ ๋…ธ๋“œ ์‚ฌ์ด์— ์–ผ๋งˆ๋‚˜ ๋งŽ์€ edge๋ฅผ ์—ฐ๊ฒฐํ• ์ง€๊ฐ€ ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ๊ณผ ์†๋„์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค. 

 

โ  ํƒ์ƒ‰๊ฐ€๋Šฅํ•œ ์ž‘์€ ์„ธ๊ณ„  

 

 โ†ช๏ธŽ  ์™„์ „ํžˆ ๋žœ๋คํ•œ ๊ทธ๋ž˜ํ”„์™€ ์™„์ „ํžˆ ๊ทœ์น™์ ์ธ ๊ทธ๋ž˜ํ”„ ์‚ฌ์ด์— ์ ๋‹นํžˆ ๋žœ๋คํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋œ ๊ทธ๋ž˜ํ”„ ์ƒํƒœ 

 

 

 โ†ช๏ธŽ  small world ๋Š”, ๊ทœ์น™์ ์ธ ์—ฐ๊ฒฐ์—์„œ ์ผ๋ถ€ ์—ฐ๊ฒฐ๋งŒ ๋žœ๋คํ•˜๊ฒŒ ๋ฐ”๊พผ ํ˜•ํƒœ๋กœ, ์ •ํ™•ํ•œ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๋ฉด์„œ๋„ ๋žœ๋คํ•œ ์„ฑ์งˆ์„ ํ†ตํ•ด ๋น ๋ฅธ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ํŠน์ง•์ด ์žˆ๋‹ค. 

 โ†ช๏ธŽ  ๋žœ๋ค ์—ฐ๊ฒฐ์„ ๋งŒ๋“ค์–ด์ฃผ๊ธฐ ์œ„ํ•ด, ๋ฒกํ„ฐ์˜ ์ˆœ์„œ๋ฅผ ๋žœ๋ค์œผ๋กœ ์„ž์–ด ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค. 

 โ†ช๏ธŽ  ๊ทธ๋Ÿฌ๋‚˜, ๋žœ๋ค์œผ๋กœ ์ €์žฅํ•˜๊ฒŒ ๋˜๋ฉด ์ฐพ์œผ๋ ค๋Š” ๊ฒ€์ƒ‰ ๋ฒกํ„ฐ์™€ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์ ์ด ์•„๋‹Œ ์ ์—์„œ ํƒ์ƒ‰์„ ๋ฉˆ์ถ”๋Š” local minimum ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๊ณ„์ธต๊ตฌ์กฐ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. 

 

 

 

2.4 ๊ณ„์ธต๊ตฌ์กฐ

 

โ  Linked list 

 

 

 โ†ช๏ธŽ  ๋งŽ์ด ํ™œ์šฉ๋˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ๋•Œ ์„œ๋กœ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ์ฃผ์†Œ ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๋ฉด๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์•ž์—์„œ๋ถ€ํ„ฐ ์ˆœ์ฐจ ํƒ์ƒ‰์„ ํ•ด์•ผ ํ•ด์„œ ์†๋„๊ฐ€ ๋А๋ฆฌ๋‹ค. ๊ฐ€๋ น, 91์„ ์ฐพ๋Š”๋‹ค ํ•˜๋ฉด 8๋‹จ๊ณ„๋ฅผ ๊ฑฐ์ณ์•ผ ํ•œ๋‹ค. 

 

 

โ  Skip list 

 

 

 

 โ†ช๏ธŽ  ๊ฐ€๋ น, level์„ ์„ค์ •ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๋“ฌ์„ฑ๋“ฌ์„ฑ ๋ฐฐ์น˜ํ•˜๋Š” ๊ฒ€์ƒ‰ ๋ฐฉ์‹์„ ํ™œ์šฉํ•œ๋‹ค๊ณ  ํ•˜๋ฉด, 3๋‹จ๊ณ„๋งŒ์— 91์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ NSW์— ์ ‘๋ชฉํ•ด์„œ ์—ฌ๋Ÿฌ ๊ณ„์ธต์— ๊ทธ๋ž˜ํ”„๋ฅผ ๋ฐฐ์น˜ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฒกํ„ฐ๋ฅผ ์ €์žฅํ•œ๋‹ค. 

 

 

 

โ  HNSW

 

 

 

 

 โ†ช๏ธŽ  ๋ ˆ๋ฒจ0์—์„œ๋Š” ๋ชจ๋“  ๋ฒกํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ , ๋ ˆ๋ฒจ1,๋ ˆ๋ฒจ2๋กœ ๊ฐˆ์ˆ˜๋ก ์ ์€ ๋ฐ์ดํ„ฐ๋งŒ ์ €์žฅํ•œ๋‹ค. 

 โ†ช๏ธŽ  ์Šคํ‚ต๋ฆฌ์ŠคํŠธ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋†’์€ ์ธต์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋Š” ๊ทธ๋ณด๋‹ค ๋‚ฎ์€ ์ธต์— ํ•ญ์ƒ ์กด์žฌํ•œ๋‹ค. 

 โ†ช๏ธŽ  ๋†’์€์ธต์— ์–ด๋–ค ๋ฒกํ„ฐ๋ฅผ ์ €์žฅํ• ์ง€๋ง์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์€ ๋ณต์žกํ•˜์ง€๋งŒ, ๋ณธ์งˆ์ ์œผ๋กœ ํ™•๋ฅ ์„ ์ด์šฉํ•ด ๋†’์€ ์ธต์œผ๋กœ ๊ฐˆ์ˆ˜๋ก ๋ฐ์ดํ„ฐ๊ฐ€ ์ ์–ด์ง€๋Š” ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ ๋งŒ ์ดํ•ดํ•ด๋„ ์ข‹๋‹ค. ์•„๋ฌดํŠผ ๋‚ฎ์€ ์ธต์—๋Š” ๋ชจ๋“  ๋ฒกํ„ฐ๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์ง€์—ญ ์ตœ์†Ÿ๊ฐ’์— ๋น ์งˆ ์œ„ํ—˜์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค. 

 

 

 

 

3.   ์‹ค์Šต : HNSW ์ธ๋ฑ์Šค์˜ ํ•ต์‹ฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์ดํ•ดํ•˜๊ธฐ


 

โ  3๊ฐ€์ง€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰, ์ƒ‰์ธ์‹œ๊ฐ„, ์žฌํ˜„์œจ, ๊ฒ€์ƒ‰์‹œ๊ฐ„์ด ๋‹ฌ๋ผ์ง„๋‹ค. 

 

 

3.1  ํŒŒ๋ผ๋ฏธํ„ฐ m 

 

โ  m

 โ†ช๏ธŽ  ํ•˜๋‚˜์˜ ๋ฒกํ„ฐ์— ์—ฐ๊ฒฐํ•˜๋Š” ์ตœ์†Œ ์—ฐ๊ฒฐ์ˆ˜ (์ถ”๊ฐ€ํ•˜๋Š” ์ž„๋ฒ ๋”ฉ ๋ฒกํ„ฐ์— ์—ฐ๊ฒฐํ•˜๋Š” edge์˜ ์ˆ˜) 

 โ†ช๏ธŽ  m์ด ํด์ˆ˜๋ก ์—ฐ๊ฒฐ๋˜๋Š” edge ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚˜ ๊ทธ๋ž˜ํ”„๊ฐ€ ๋” ์ด˜์ด˜ํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜๋ฏ€๋กœ ์žฌํ˜„์œจ์€ ์ข‹์•„์ง€๋‚˜, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์€ ์ปค์ง€๊ณ  ์ƒ‰์ธ ์‹œ๊ฐ„์ด ์ฆ๊ฐ€ํ•œ๋‹ค. ํƒ์ƒ‰์—์„œ๋„ ๋” ๋งŽ์€ edge๋ฅผ ๊ณ ๋ คํ•˜๋ฏ€๋กœ ๊ฒ€์ƒ‰์‹œ๊ฐ„๋„ ์ฆ๊ฐ€ํ•œ๋‹ค. 

 

 

โ  ์‹ค์Šต

 

import numpy as np

k=1
d = xq.shape[1]
nq = 1000
xq = xq[:nq]

for m in [8, 16, 32, 64]:
    index = faiss.IndexHNSWFlat(d, m) # HNSW ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค์— m ํŒŒ๋ผ๋ฏธํ„ฐ ์ง€์ • 
    time.sleep(3)
    start_memory = get_memory_usage_mb()
    start_index = time.time()
    index.add(xb)
    end_memory = get_memory_usage_mb()
    end_index = time.time()
    print(f"M: {m} - ์ƒ‰์ธ ์‹œ๊ฐ„: {end_index - start_index} s, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰: {end_memory - start_memory} MB")

    t0 = time.time()
    D, I = index.search(xq, k)
    t1 = time.time()

    recall_at_1 = np.equal(I, gt[:nq, :1]).sum() / float(nq)
    print(f"{(t1 - t0) * 1000.0 / nq:.3f} ms per query, R@1 {recall_at_1:.3f}")

 

 โ†ช๏ธŽ  ef_construction = 40, ef_search = 16์ธ ๊ธฐ๋ณธ๊ฐ’์—์„œ, m๋งŒ ์กฐ์ •ํ–ˆ์„ ๋•Œ, m์ด ์ปค์ง€๋ฉด ์žฌํ˜„์œจ์ด ํฌ๊ฒŒ ์ฆ๊ฐ€ํ•˜๊ณ  ๋ฉ”๋ชจ๋ฆฌ์‚ฌ์šฉ๋Ÿ‰์ด ์ฆ๊ฐ€ํ•˜๊ณ  ๊ฒ€์ƒ‰๊ณผ ์ƒ‰์ธ ์‹œ๊ฐ„์ด ๊ธธ์–ด์ง„๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, KNN๊ณผ ๋น„๊ตํ–ˆ์„ ๋•Œ๋ฅผ ๋ณด๋ฉด, m=64์ผ ๋•Œ ๊ฒ€์ƒ‰์‹œ๊ฐ„์ด 0.237ms ๋ฐ–์— ๊ฑธ๋ฆฌ์ง€ ์•Š์œผ๋ฉด์„œ 93.2%์˜ ์žฌํ˜„์œจ์„ ๋ณด์ด๋Š”๋ฐ, KNN์€ ๊ฒ€์ƒ‰์— 7.6ms๋‚˜ ๊ฑธ๋ ธ์œผ๋‹ˆ 30๋ฐฐ ์ด์ƒ ๋นจ๋ผ์ง„ ๊ฒƒ์ด๋‹ค. 

 

 

 

3.2  ํŒŒ๋ผ๋ฏธํ„ฐ ef_construction 

 

โ  ef_construction

 โ†ช๏ธŽ  ์ƒ‰์ธ ๊ณผ์ •์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด M๊ฐœ๋ฅผ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•ด ์ €์žฅํ•˜๋Š” ํ›„๋ณด์˜ ์ˆ˜ 

 โ†ช๏ธŽ ์ธ๋ฑ์Šค์— ์ƒˆ๋กœ์šด ๋ฒกํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒฝ์šฐ, ๊ฒ€์ƒ‰ํ•  ๋•Œ ์œ ์‚ฌํ•˜๊ฒŒ ์ถ”๊ฐ€ํ•œ ๋ฒกํ„ฐ์™€ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋ฒกํ„ฐ๋ฅผ ํƒ์ƒ‰ํ•œ๋‹ค. 

 โ†ช๏ธŽ ef_construction ์ด ํฌ๋ฉด ๋” ๋งŽ์€ ํ›„๋ณด๋ฅผ ํƒ์ƒ‰ํ•˜๋ฏ€๋กœ, ์‹ค์ œ๋กœ ์ถ”๊ฐ€ํ•œ ๋ฒกํ„ฐ์™€ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋ฒกํ„ฐ๋ฅผ ์„ ํƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง„๋‹ค. ์ฆ‰ ์ƒ์„ฑํ•˜๋Š” ๊ทธ๋ž˜ํ”„์˜ ํ’ˆ์งˆ์ด ์ข‹์•„์ง„๋‹ค. ๋”ฐ๋ผ์„œ ์žฌํ˜„์œจ์ด ์˜ฌ๋ผ๊ฐ„๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋” ๋งŽ์€ ํ›„๋ณด๋ฅผ ํƒ์ƒ‰ํ•˜๋ฏ€๋กœ ์ƒ‰์ธ ์‹œ๊ฐ„์ด ์ฆ๊ฐ€ํ•œ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰๊ณผ ๊ฒ€์ƒ‰์‹œ๊ฐ„์€ ํฌ๊ฒŒ ์˜ํ–ฅ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. 

 

 

โ  ์‹ค์Šต

 

k=1
d = xq.shape[1]
nq = 1000
xq = xq[:nq]

for ef_construction in [40, 80, 160, 320]:
    index = faiss.IndexHNSWFlat(d, 32)
    index.hnsw.efConstruction = ef_construction # efConstruction ์†์„ฑ ์ง€์ • 
    time.sleep(3)
    start_memory = get_memory_usage_mb()
    start_index = time.time()
    index.add(xb)
    end_memory = get_memory_usage_mb()
    end_index = time.time()
    print(f"efConstruction: {ef_construction} - ์ƒ‰์ธ ์‹œ๊ฐ„: {end_index - start_index} s, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰: {end_memory - start_memory} MB")

    t0 = time.time()
    D, I = index.search(xq, k)
    t1 = time.time()

    recall_at_1 = np.equal(I, gt[:nq, :1]).sum() / float(nq)
    print(f"{(t1 - t0) * 1000.0 / nq:.3f} ms per query, R@1 {recall_at_1:.3f}")

 

 โ†ช๏ธŽ  ef_construction์ด ์ฆ๊ฐ€ํ•˜๋ฉด ์žฌํ˜„์œจ์ด ์ฆ๊ฐ€ํ•˜๊ณ (๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๋ž˜ํ”„์— ๋žœ๋ค์„ฑ์ด ๋“ค์–ด๊ฐ€๋ฏ€๋กœ ์–ธ์ œ๋‚˜ ์ฆ๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค) ์ƒ‰์ธ์‹œ๊ฐ„๋„ ์ฆ๊ฐ€ํ•œ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰๊ณผ ๊ฒ€์ƒ‰์‹œ๊ฐ„์€ ํฌ๊ฒŒ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. 

 

 

 

 

3.3  ํŒŒ๋ผ๋ฏธํ„ฐ ef_search 

 

โ  ef_search

 โ†ช๏ธŽ  ๊ฒ€์ƒ‰ ๊ณผ์ •์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด K๊ฐœ๋ฅผ ์„ ํƒํ•  ๋•Œ ์ €์žฅํ•˜๋Š” ํ›„๋ณด์˜ ์ˆ˜ 

 โ†ช๏ธŽ  ํ›„๋ณด๊ตฐ์ด ์ปค์ง€๋ฉด ๋” ๋งŽ์€ ๋ฒกํ„ฐ๋ฅผ ํƒ์ƒ‰ํ•ด ์žฌํ˜„์œจ์ด ๋†’์•„์ง€์ง€๋งŒ ๊ฒ€์ƒ‰ ์‹œ๊ฐ„์€ ์ฆ๊ฐ€ํ•œ๋‹ค. 

 

โ  ์‹ค์Šต

for ef_search in [16, 32, 64, 128]:
    index.hnsw.efSearch = ef_search # ef_search ์ง€์ •
    t0 = time.time()
    D, I = index.search(xq, k) 
    t1 = time.time()

    recall_at_1 = np.equal(I, gt[:nq, :1]).sum() / float(nq)
    print(f"{(t1 - t0) * 1000.0 / nq:.3f} ms per query, R@1 {recall_at_1:.3f}")

 

 โ†ช๏ธŽ  ์ƒ‰์ธ๊ณผ๋Š” ๊ด€๋ จ์ด ์—†์–ด ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด๋‚˜ ์ƒ‰์ธ์‹œ๊ฐ„์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค. ef_search๋ฅผ 32 ์ด์ƒ ์„ค์ •ํ–ˆ์„ ๋•Œ ์žฌํ˜„์œจ์ด 0.97์ด์ƒ์ด๊ณ , ๊ฒ€์ƒ‰ ์‹œ๊ฐ„์€ 1ms ๋ฏธ๋งŒ์œผ๋กœ, KNN๊ณผ ๋น„๊ตํ–ˆ์„ ๋•Œ ์•ฝ 10๋ฐฐ ์ด์ƒ ๋น ๋ฅด๋‹ค. 

 

 

 

 

 

4.   ์‹ค์Šต : ํŒŒ์ธ์ฝ˜์œผ๋กœ ๋ฒกํ„ฐ ๊ฒ€์ƒ‰ ๊ตฌํ˜„ํ•˜๊ธฐ 


 

4.1  ํŒŒ์ธ์ฝ˜ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์šฉ๋ฒ•

 

โ  ํŒŒ์ธ์ฝ˜

 โ†ช๏ธŽ  ๋Œ€ํ‘œ์ ์ธ ๋ฒกํ„ฐ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค 

 

 

 

(1) ๊ณ„์ • ์—ฐ๊ฒฐ ๋ฐ ์ธ๋ฑ์Šค ์ƒ์„ฑ 

from pinecone import Pinecone, ServerlessSpec

# ๊ณ„์ • ์—ฐ๊ฒฐ 
pinecone_api_key = "์ž์‹ ์˜ API ํ‚ค๋ฅผ ์ž…๋ ฅ"
pc = Pinecone(api_key=pinecone_api_key)

# ์ธ๋ฑ์Šค ์ƒ์„ฑ
pc.create_index("llm-book", spec=ServerlessSpec("aws", "us-east-1"), dimension=768)
index = pc.Index('llm-book')

 

โ†ช๏ธŽ  ์ธ๋ฑ์Šค ์ด๋ฆ„์€ 'llm-book'์œผ๋กœ, ์ž„๋ฒ ๋”ฉ ๋ฒกํ„ฐ์˜ ์ฐจ์›์ˆ˜๋Š” 768๋กœ ์„ค์ • 

โ†ช๏ธŽ  Indexํด๋ž˜์Šค์— ์ƒ์„ฑํ•œ ์ธ๋ฑ์Šค ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์‚ฌ์šฉํ•  ์ธ๋ฑ์Šค๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค. 

 

 

(2) ์ž„๋ฒ ๋”ฉ ์ƒ์„ฑ

from datasets import load_dataset
from sentence_transformers import SentenceTransformer

# ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
sentence_model = SentenceTransformer('snunlp/KR-SBERT-V40K-klueNLI-augSTS')

# ๋ฐ์ดํ„ฐ์…‹ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
klue_dp_train = load_dataset('klue', 'dp', split='train[:100]')

# ์ž„๋ฒ ๋”ฉ๋ณ€ํ™˜
embeddings = sentence_model.encode(klue_dp_train['sentence'])

 

โ†ช๏ธŽ  ํ•œ๊ตญ์–ด์ž„๋ฒ ๋”ฉ๋ชจ๋ธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ 

โ†ช๏ธŽ  ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ KLUE DP ๋ฐ์ดํ„ฐ์…‹ 

โ†ช๏ธŽ  encode ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์‹ค์Šต ๋ฐ์ดํ„ฐ์…‹ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ์ž„๋ฒ ๋”ฉ์œผ๋กœ ๋ณ€ํ™˜ 

 

 

 

(3) ํŒŒ์ธ์ฝ˜ ์ž…๋ ฅ์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ํ˜•ํƒœ ๋ณ€๊ฒฝ 

# ํŒŒ์ด์ฌ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝ
embeddings = embeddings.tolist()

# {"id": ๋ฌธ์„œ ID(str), "values": ๋ฒกํ„ฐ ์ž„๋ฒ ๋”ฉ(List[float]), "metadata": ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ(dict) ) ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ ์ค€๋น„
insert_data = []
for idx, (embedding, text) in enumerate(zip(embeddings, klue_dp_train['sentence'])):
  insert_data.append({"id": str(idx), "values": embedding, "metadata": {'text': text}})

 

โ†ช๏ธŽ  ํŒŒ์ธ์ฝ˜ ์ธ๋ฑ์Šค์— ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฐ์ดํ„ฐ ํ˜•ํƒœ ๋ณ€๊ฒฝ

โ†ช๏ธŽ  id, values, metadata๋กœ ๊ตฌ์„ฑ๋œ ์‚ฌ์ „ ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ 

 

 

(4) ์ž„๋ฒ ๋”ฉ ๋ฐ์ดํ„ฐ๋ฅผ ์ธ๋ฑ์Šค์— ์ €์žฅ 

upsert_response = index.upsert(vectors = insert_data, namespace='llm-book-sub')

 

โ†ช๏ธŽ  upsert ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํŒŒ์ธ์ฝ˜ ์ธ๋ฑ์Šค์— ์ €์žฅ 

โ†ช๏ธŽ  namespace๋ฅผ ์ง€์ •ํ•˜๋Š”๋ฐ, ํŒŒ์ธ์ฝ˜์—์„œ๋Š” ํ•˜๋‚˜์˜ ์ธ๋ฑ์Šค ์•ˆ์—์„œ๋„ ์—ฌ๋Ÿฌ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

 

 

(5) ์ธ๋ฑ์Šค ๊ฒ€์ƒ‰ํ•˜๊ธฐ 

query_response = index.query(
    namespace='llm-book-sub', # ๊ฒ€์ƒ‰ํ•  ๋„ค์ž„์ŠคํŽ˜์ด์Šค
    top_k=10, # ๋ช‡ ๊ฐœ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ• ์ง€
    include_values=True, # ๋ฒกํ„ฐ ์ž„๋ฒ ๋”ฉ ๋ฐ˜ํ™˜ ์—ฌ๋ถ€
    include_metadata=True, # ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜ ์—ฌ๋ถ€
    vector=embeddings[0] # ๊ฒ€์ƒ‰ํ•  ๋ฒกํ„ฐ ์ž„๋ฒ ๋”ฉ
)
query_response

 

โ†ช๏ธŽ  query ๋ฉ”์„œ๋“œ : ๋„ค์ž„์ŠคํŽ˜์ด์Šค, ๋ช‡ ๊ฐœ์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ƒ‰ํ• ์ง€(top_k), ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์— ํฌํ•จ์‹œํ‚ฌ ๋ฐ์ดํ„ฐ ์ข…๋ฅ˜ (include_values ๋˜๋Š” include_metadata), ๊ฒ€์ƒ‰ํ•  ๋ฒกํ„ฐ vector) ์ธ์ž๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. 

 

 

 

(6) ํŒŒ์ธ์ฝ˜์—์„œ ๋ฌธ์„œ ์ˆ˜์ • ๋ฐ ์‚ญ์ œ 

new_text = '๋ณ€๊ฒฝํ•  ์ƒˆ๋กœ์šด ํ…์ŠคํŠธ'
new_embedding = sentence_model.encode(new_text).tolist()

# ์—…๋ฐ์ดํŠธ
update_response = index.update(
    id= '๊ธฐ์กด_๋ฌธ์„œ_id',
    values=new_embedding,
    set_metadata={'text': new_text},
    namespace='llm-book-sub'
)

# ์‚ญ์ œ
delete_response = index.delete(ids=['๊ธฐ์กด_๋ฌธ์„œ_id'], namespace='llm-book-sub')

 

โ†ช๏ธŽ  update ๋ฉ”์„œ๋“œ : ๋ฐ์ดํ„ฐ ์ˆ˜์ • : ๋ฌธ์„œ์˜ id์™€, ๋ณ€๊ฒฝํ•  ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด ๋œ๋‹ค. 

โ†ช๏ธŽ  delete ๋ฉ”์„œ๋“œ : ์‚ญ์ œํ•˜๋ ค๋Š” ๋ฌธ์„œ์˜ id์™€ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ „๋‹ฌ 

 

 

 

 

4.2  ๋ผ๋งˆ์ธ๋ฑ์Šค์—์„œ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ณ€๊ฒฝํ•˜๊ธฐ

 

โ  ๋ผ๋งˆ ์ธ๋ฑ์Šค์— ํŒŒ์ธ์ฝ˜ ์ธ๋ฑ์Šค ์—ฐ๊ฒฐ

 

# ํŒŒ์ธ์ฝ˜ ๊ธฐ๋ณธ ์„ค์ •
from pinecone import Pinecone, ServerlessSpec

pc = Pinecone(api_key=pinecone_api_key)
pc.create_index(
    "quickstart", dimension=1536, metric="euclidean", spec=ServerlessSpec("aws", "us-east-1")
)
pinecone_index = pc.Index("quickstart")


# ๋ผ๋งˆ์ธ๋ฑ์Šค์— ํŒŒ์ธ์ฝ˜ ์ธ๋ฑ์Šค ์—ฐ๊ฒฐ
from llama_index.core import VectorStoreIndex
from llama_index.vector_stores.pinecone import PineconeVectorStore
from llama_index.core import StorageContext

vector_store = PineconeVectorStore(pinecone_index=pinecone_index)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
    documents, storage_context=storage_context
)

 

 โ†ช๏ธŽ  (๋ณต์Šต) ๋ผ๋งˆ์ธ๋ฑ์Šค : ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค, ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ, ๋ฒกํ„ฐ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋“ฑ LLM ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” LLM์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋„๊ตฌ 

 โ†ช๏ธŽ  ๋ผ๋งˆ์ธ๋ฑ์Šค์—์„œ๋Š” ๋‹ค์–‘ํ•œ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์‰ฝ๊ฒŒ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ง€์›ํ•œ๋‹ค. ์œ„ ์ฝ”๋“œ๋Š” ํŒŒ์ธ์ฝ˜์„ ๋ผ๋งˆ์ธ๋ฑ์Šค์™€ ์—ฐ๊ฒฐ์‹œ์ผœ RAG์˜ ๋ฒกํ„ฐdb๋กœ ํ™œ์šฉํ•˜๋Š” ์ฝ”๋“œ๋‹ค. 

 

 

 

 

 

 

 

5.   ์‹ค์Šต : ํŒŒ์ธ์ฝ˜์„ ํ™œ์šฉํ•ด ๋ฉ€ํ‹ฐ๋ชจ๋‹ฌ๊ฒ€์ƒ‰ ๊ตฌํ˜„ํ•˜๊ธฐ 


โ  ์š”์•ฝ

 โ†ช๏ธŽ  ์ด๋ฏธ์ง€์™€ ํ…์ŠคํŠธ๋ฅผ ๋™์ผํ•œ ๋ฒกํ„ฐ ๊ณต๊ฐ„์— ์ž„๋ฒ ๋”ฉ์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” CLIP ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ, ์ž…๋ ฅํ•œ ์ด๋ฏธ์ง€์™€ ๋น„์Šทํ•œ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋Šฅ์—์„œ ํŒŒ์ธ์ฝ˜์„ ๋ฒกํ„ฐdb๋กœ ํ™œ์šฉ 

 โ†ช๏ธŽ  ํ”„๋กฌํ”„ํŠธ์™€ ์ด๋ฏธ์ง€์Œ์œผ๋กœ ๊ตฌ์„ฑ๋œ DeffusionDB ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ 

 

 

 

 

 

728x90

๋Œ“๊ธ€