Skip to content

Commit f3ecb3d

Browse files
authored
Merge pull request #299 from whybe-choi/docs/vector_search_with_hub_as_backend
[i18n-ko] Translated `vector_search_with_hub_as_backend.ipynb` to Korean
2 parents 9318e2e + 90516ca commit f3ecb3d

File tree

3 files changed

+337
-1
lines changed

3 files changed

+337
-1
lines changed

notebooks/ko/_toctree.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,10 @@
3333
- local: faiss_with_hf_datasets_and_clip
3434
title: 유사성 검색을 위한 멀티모달 데이터 임베딩
3535
- local: ko_fine_tuning_vlm_dpo_smolvlm_instruct
36-
title: 개인용 GPU에서 TRL로 SmolVLM DPO 파인튜닝하기
36+
title: 개인용 GPU에서 TRL로 SmolVLM DPO 파인튜닝하기
37+
- title: 검색 레시피
38+
isExpanded: false
39+
sections:
40+
- local: vector_search_with_hub_as_backend
41+
title: 허깅페이스 허브를 백엔드로 사용한 벡터 검색
42+

notebooks/ko/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- [유사성 검색을 위한 멀티모달 데이터 임베딩](faiss_with_hf_datasets_and_clip)
1616
- [개인용 GPU에서 TRL로 SmolVLM DPO 파인튜닝하기](ko_fine_tuning_vlm_dpo_smolvlm_instruct)
1717
- [커스텀 데이터셋으로 객체 탐지 모델 파인튜닝하기, Spaces에 배포하기, 그리고 Gradio API 연동하기](fine_tuning_detr_custom_dataset)
18+
- [허깅페이스 허브를 백엔드로 사용한 벡터 검색](vector_search_with_hub_as_backend)
1819

1920
더 다양한 노트북을 확인하고 싶다면 Cookbook's [GitHub 리포지토리](https://github.com/huggingface/cookbook)에 방문해보세요.
2021

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {
6+
"id": "ksUdu7H7qBig"
7+
},
8+
"source": [
9+
"# 허깅페이스 허브를 백엔드로 사용한 벡터 검색\n",
10+
"\n",
11+
"_작성자: [Martin Elstner](https://github.com/MartinEls) , 번역: [최용빈](https://github.com/whybe-choi)_\n",
12+
"\n",
13+
"허깅페이스의 데이터셋은 파켓(parquet) 파일에 의존합니다. 우리는 빠른 인메모리 데이터베이스 시스템인 [DuckDB를 사용하여 이 파일들과 상호작용](https://huggingface.co/docs/hub/en/datasets-duckdb)할 수 있습니다. DuckDB의 기능 중 하나는 [벡터 유사도 검색](https://duckdb.org/docs/extensions/vss.html)으로, 인덱스 유무에 관계없이 사용할 수 있습니다."
14+
]
15+
},
16+
{
17+
"cell_type": "markdown",
18+
"metadata": {
19+
"id": "Nwziazq7qBig"
20+
},
21+
"source": [
22+
"## 의존성 설치"
23+
]
24+
},
25+
{
26+
"cell_type": "code",
27+
"execution_count": null,
28+
"metadata": {
29+
"id": "_10SP4H4qBih"
30+
},
31+
"outputs": [],
32+
"source": [
33+
"!pip install datasets duckdb sentence-transformers model2vec -q"
34+
]
35+
},
36+
{
37+
"cell_type": "markdown",
38+
"metadata": {
39+
"id": "E8DN3ihKqBih"
40+
},
41+
"source": [
42+
"## 데이터셋에 대한 임베딩 생성\n",
43+
"\n",
44+
"먼저, 검색할 데이터셋에 대한 임베딩을 생성해야 합니다. 우리는 `sentence-transformers` 라이브러리를 사용하여 데이터셋에 대한 임베딩을 생성할 것입니다."
45+
]
46+
},
47+
{
48+
"cell_type": "code",
49+
"execution_count": null,
50+
"metadata": {
51+
"id": "ecQmlrkyqBih"
52+
},
53+
"outputs": [],
54+
"source": [
55+
"from sentence_transformers import SentenceTransformer\n",
56+
"from sentence_transformers.models import StaticEmbedding\n",
57+
"\n",
58+
"static_embedding = StaticEmbedding.from_model2vec(\"minishlab/potion-base-8M\")\n",
59+
"model = SentenceTransformer(modules=[static_embedding])"
60+
]
61+
},
62+
{
63+
"cell_type": "markdown",
64+
"metadata": {
65+
"id": "pOxpuYpxqBih"
66+
},
67+
"source": [
68+
"이제 허브에서 [ai-blueprint/fineweb-bbc-news](https://huggingface.co/datasets/ai-blueprint/fineweb-bbc-news) 데이터셋을 로드해 보겠습니다."
69+
]
70+
},
71+
{
72+
"cell_type": "code",
73+
"execution_count": null,
74+
"metadata": {
75+
"id": "Zbo4T4edqBih"
76+
},
77+
"outputs": [],
78+
"source": [
79+
"from datasets import load_dataset\n",
80+
"\n",
81+
"ds = load_dataset(\"ai-blueprint/fineweb-bbc-news\")"
82+
]
83+
},
84+
{
85+
"cell_type": "markdown",
86+
"metadata": {
87+
"id": "rXZDtCytqBii"
88+
},
89+
"source": [
90+
"이제 데이터셋에 대한 임베딩을 생성할 수 있습니다. 일반적으로 정밀도(precision)를 잃지 않기 위해 데이터를 더 작은 배치로 나누고 싶을 수 있지만, 이 예제에서는 데이터셋의 전체 텍스트에 대한 임베딩만 생성하겠습니다."
91+
]
92+
},
93+
{
94+
"cell_type": "code",
95+
"execution_count": null,
96+
"metadata": {
97+
"id": "Y7QClFshqBii"
98+
},
99+
"outputs": [],
100+
"source": [
101+
"def create_embeddings(batch):\n",
102+
" embeddings = model.encode(batch[\"text\"], convert_to_numpy=True)\n",
103+
" batch[\"embeddings\"] = embeddings.tolist()\n",
104+
" return batch\n",
105+
"\n",
106+
"ds = ds.map(create_embeddings, batched=True)"
107+
]
108+
},
109+
{
110+
"cell_type": "markdown",
111+
"metadata": {
112+
"id": "BeM-bRRhqBii"
113+
},
114+
"source": [
115+
"이제 임베딩이 포함된 데이터셋을 허브에 다시 업로드할 수 있습니다."
116+
]
117+
},
118+
{
119+
"cell_type": "code",
120+
"execution_count": null,
121+
"metadata": {
122+
"id": "rCRDC_pUqBii"
123+
},
124+
"outputs": [],
125+
"source": [
126+
"ds.push_to_hub(\"ai-blueprint/fineweb-bbc-news-embeddings\")"
127+
]
128+
},
129+
{
130+
"cell_type": "markdown",
131+
"metadata": {
132+
"id": "pFE5laHqqBii"
133+
},
134+
"source": [
135+
"## 허깅페이스 허브에서 벡터 검색\n",
136+
"이제 `duckdb`를 사용하여 데이터셋에서 벡터 검색을 수행할 수 있습니다. 이때 인덱스를 사용하거나 사용하지 않을 수 있습니다. 인덱스를 **활용하지 않고** 검색하는 것은 더 느리지만 더 정확하고, 인덱스를 **활용하여** 검색하는 것은 더 빠르지만 덜 정확합니다.\n",
137+
"\n",
138+
"### 인덱스를 활용하지 않고 검색하기\n",
139+
"인덱스를 활용하지 않고 검색하려면 `duckdb` 라이브러리를 사용하여 데이터셋에 연결하고 벡터 검색을 수행할 수 있습니다. 이는 느린 작업지만 일반적으로 약 10만 행까지의 작은 데이터셋에서는 충분히 빠르게 동작합니다. 즉, 우리가 사용하는 데이터셋에 대해서 쿼리를 날리는 것은 다소 느릴 것입니다."
140+
]
141+
},
142+
{
143+
"cell_type": "code",
144+
"execution_count": null,
145+
"metadata": {
146+
"id": "BTeqWPCNqBii"
147+
},
148+
"outputs": [],
149+
"source": [
150+
"import duckdb\n",
151+
"from typing import List\n",
152+
"\n",
153+
"def similarity_search_without_duckdb_index(\n",
154+
" query: str,\n",
155+
" k: int = 5,\n",
156+
" dataset_name: str = \"ai-blueprint/fineweb-bbc-news-embeddings\",\n",
157+
" embedding_column: str = \"embeddings\",\n",
158+
"):\n",
159+
" # 인덱스를 위해 사용한 모델과 동일한 모델을 사용\n",
160+
" query_vector = model.encode(query)\n",
161+
" embedding_dim = model.get_sentence_embedding_dimension()\n",
162+
"\n",
163+
" sql = f\"\"\"\n",
164+
" SELECT\n",
165+
" *,\n",
166+
" array_cosine_distance(\n",
167+
" {embedding_column}::float[{embedding_dim}],\n",
168+
" {query_vector.tolist()}::float[{embedding_dim}]\n",
169+
" ) as distance\n",
170+
" FROM 'hf://datasets/{dataset_name}/**/*.parquet'\n",
171+
" ORDER BY distance\n",
172+
" LIMIT {k}\n",
173+
" \"\"\"\n",
174+
" return duckdb.sql(sql).to_df()\n",
175+
"\n",
176+
"similarity_search_without_duckdb_index(\"What is the future of AI?\")"
177+
]
178+
},
179+
{
180+
"cell_type": "markdown",
181+
"metadata": {
182+
"id": "Y4W1wkkRqBij"
183+
},
184+
"source": [
185+
"### 인덱스를 활용하여 검색하기\n",
186+
"\n",
187+
"이 접근법은 데이터셋의 로컬 복사본을 생성하고 이를 사용하여 인덱스를 생성합니다. 약간의 경미한 오버헤드가 있지만 한번 생성한 후에는 검색 속도가 상당히 향상될 것입니다."
188+
]
189+
},
190+
{
191+
"cell_type": "code",
192+
"execution_count": null,
193+
"metadata": {
194+
"id": "5ewJ7Ns8qBij"
195+
},
196+
"outputs": [],
197+
"source": [
198+
"import duckdb\n",
199+
"\n",
200+
"def _setup_vss():\n",
201+
" duckdb.sql(\n",
202+
" query=\"\"\"\n",
203+
" INSTALL vss;\n",
204+
" LOAD vss;\n",
205+
" \"\"\"\n",
206+
" )\n",
207+
"def _drop_table(table_name):\n",
208+
" duckdb.sql(\n",
209+
" query=f\"\"\"\n",
210+
" DROP TABLE IF EXISTS {table_name};\n",
211+
" \"\"\"\n",
212+
" )\n",
213+
"\n",
214+
"def _create_table(dataset_name, table_name, embedding_column):\n",
215+
" duckdb.sql(\n",
216+
" query=f\"\"\"\n",
217+
" CREATE TABLE {table_name} AS\n",
218+
" SELECT *, {embedding_column}::float[{model.get_sentence_embedding_dimension()}] as {embedding_column}_float\n",
219+
" FROM 'hf://datasets/{dataset_name}/**/*.parquet';\n",
220+
" \"\"\"\n",
221+
" )\n",
222+
"\n",
223+
"def _create_index(table_name, embedding_column):\n",
224+
" duckdb.sql(\n",
225+
" query=f\"\"\"\n",
226+
" CREATE INDEX my_hnsw_index ON {table_name} USING HNSW ({embedding_column}_float) WITH (metric = 'cosine');\n",
227+
" \"\"\"\n",
228+
" )\n",
229+
"\n",
230+
"def create_index(dataset_name, table_name, embedding_column):\n",
231+
" _setup_vss()\n",
232+
" _drop_table(table_name)\n",
233+
" _create_table(dataset_name, table_name, embedding_column)\n",
234+
" _create_index(table_name, embedding_column)\n",
235+
"\n",
236+
"create_index(\n",
237+
" dataset_name=\"ai-blueprint/fineweb-bbc-news-embeddings\",\n",
238+
" table_name=\"fineweb_bbc_news_embeddings\",\n",
239+
" embedding_column=\"embeddings\"\n",
240+
")"
241+
]
242+
},
243+
{
244+
"cell_type": "markdown",
245+
"metadata": {
246+
"id": "rPv0DiO8qBij"
247+
},
248+
"source": [
249+
"이제 인덱스를 사용하여 벡터 검색을 수행할 수 있으며, 결과는 즉시 반환됩니다."
250+
]
251+
},
252+
{
253+
"cell_type": "code",
254+
"execution_count": null,
255+
"metadata": {
256+
"id": "ZT0732nmqBij"
257+
},
258+
"outputs": [],
259+
"source": [
260+
"def similarity_search_with_duckdb_index(\n",
261+
" query: str,\n",
262+
" k: int = 5,\n",
263+
" table_name: str = \"fineweb_bbc_news_embeddings\",\n",
264+
" embedding_column: str = \"embeddings\"\n",
265+
"):\n",
266+
" embedding = model.encode(query).tolist()\n",
267+
" return duckdb.sql(\n",
268+
" query=f\"\"\"\n",
269+
" SELECT *, array_cosine_distance({embedding_column}_float, {embedding}::FLOAT[{model.get_sentence_embedding_dimension()}]) as distance\n",
270+
" FROM {table_name}\n",
271+
" ORDER BY distance\n",
272+
" LIMIT {k};\n",
273+
" \"\"\"\n",
274+
" ).to_df()\n",
275+
"\n",
276+
"similarity_search_with_duckdb_index(\"What is the future of AI?\")"
277+
]
278+
},
279+
{
280+
"cell_type": "markdown",
281+
"metadata": {
282+
"id": "XVT4VYknqBij"
283+
},
284+
"source": [
285+
"이 쿼리는 응답시간을 30초에서 1초 미만으로 줄이며, 무거운 벡터 검색 엔진을 배포할 필요가 없고 저장소는 허브에서 처리됩니다."
286+
]
287+
},
288+
{
289+
"cell_type": "markdown",
290+
"metadata": {
291+
"id": "AQf6IxFGqBij"
292+
},
293+
"source": [
294+
"## 결론\n",
295+
"\n",
296+
"우리는 `duckbd`를 사용하여 허브에서 벡터 검색을 수행하는 방법을 보았습니다. 10만 행 미만의 작은 데이터셋의 경우, 허브를 벡터 검색 벡엔드로 사용하여 인덱스 없이 벡터 검색을 수행할 수 있지만, 더 큰 데이터셋의 경우 `vss` 확장 프로그램으로 인덱스를 생성하면서 로컬 검색을 수행하고 허브를 스토리지 백엔드로 사용해야 합니다.\n",
297+
"\n",
298+
"## 더 알아보기\n",
299+
"\n",
300+
"- [허깅페이스에서의 벡터 검색](https://huggingface.co/docs/hub/en/datasets-duckdb)\n",
301+
"- [DuckDB를 사용한 벡터 검색 인덱싱](https://duckdb.org/docs/extensions/vss.html)"
302+
]
303+
}
304+
],
305+
"metadata": {
306+
"colab": {
307+
"provenance": []
308+
},
309+
"kernelspec": {
310+
"display_name": ".venv",
311+
"language": "python",
312+
"name": "python3"
313+
},
314+
"language_info": {
315+
"codemirror_mode": {
316+
"name": "ipython",
317+
"version": 3
318+
},
319+
"file_extension": ".py",
320+
"mimetype": "text/x-python",
321+
"name": "python",
322+
"nbconvert_exporter": "python",
323+
"pygments_lexer": "ipython3",
324+
"version": "3.11.11"
325+
}
326+
},
327+
"nbformat": 4,
328+
"nbformat_minor": 0
329+
}

0 commit comments

Comments
 (0)