โ๏ธ 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 ๋ฐ์ดํฐ ์ฌ์ฉ
'1๏ธโฃ AIโขDS > ๐ LLM' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| 14. ๋ฉํฐ๋ชจ๋ฌLLM (0) | 2025.11.12 |
|---|---|
| 13. LLM ์ด์ํ๊ธฐ (0) | 2025.10.27 |
| 11. ์์ ์ ๋ฐ์ดํฐ์ ๋ง์ถ ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ง๋ค๊ธฐ : RAG ๊ฐ์ ํ๊ธฐ (0) | 2025.10.19 |
| [์ฑ ์คํฐ๋] 10-(2). ์ค์ต : ์๋ฏธ๊ฒ์ ๊ตฌํํ๊ธฐ (0) | 2025.09.19 |
| [์ฑ ์คํฐ๋] 10-(1). ์๋ฒ ๋ฉ ๋ชจ๋ธ๋ก ๋ฐ์ดํฐ ์๋ฏธ ์์ถํ๊ธฐ (0) | 2025.09.18 |
๋๊ธ