FastEmbed-rs๐Ÿฆ€: Rust๋กœ ๊ตฌํ˜„๋œ ๋ฒกํ„ฐ ์ž„๋ฒ ๋”ฉ(embedding)๊ณผ ์žฌ์ •๋ ฌ(Reranking) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

FastEmbed-rs :crab: ์†Œ๊ฐœ

FastEmbed-rs๋Š” Rust ์–ธ์–ด๋กœ ์ž‘์„ฑ๋œ ์ž„๋ฒ ๋”ฉ(Embedding) ๋ฐ ์žฌ์ •๋ ฌ(Reranking) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ์›๋ž˜ Qdrant์˜ fastembed ํ”„๋กœ์ ํŠธ๋ฅผ Rust ์ƒํƒœ๊ณ„์— ๋งž๊ฒŒ ๋‹ค์‹œ ๊ตฌํ˜„ํ•œ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค. ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ํ…์ŠคํŠธ, ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒกํ„ฐ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๊ฒ€์ƒ‰, ๋ถ„๋ฅ˜, ์ถ”์ฒœ ์‹œ์Šคํ…œ ๋“ฑ์— ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ์ตœ๊ทผ ๋Œ€๊ทœ๋ชจ ์–ธ์–ด ๋ชจ๋ธ(LLM)๊ณผ ๋ฉ€ํ‹ฐ๋ชจ๋‹ฌ AI์˜ ๋ฐœ์ „์œผ๋กœ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ž„๋ฒ ๋”ฉ ๊ธฐ์ˆ ์ด ํ•ต์‹ฌ ์š”์†Œ๋กœ ์ž๋ฆฌ์žก์œผ๋ฉด์„œ, Rust ๊ธฐ๋ฐ˜์˜ ๊ณ ์„ฑ๋Šฅยท์ €๋น„์šฉ ์†”๋ฃจ์…˜์— ๋Œ€ํ•œ ์ˆ˜์š”๊ฐ€ ์ปค์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Rust์˜ ์žฅ์ ์ธ ๋น ๋ฅธ ์‹คํ–‰ ์†๋„์™€ ์•ˆ์ „ํ•œ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๋•๋ถ„์—, FastEmbed-rs๋Š” Python ๊ธฐ๋ฐ˜์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ณด๋‹ค ์„ฑ๋Šฅ์ด ์šฐ์ˆ˜ํ•˜๋ฉด์„œ๋„ ์˜์กด์„ฑ ๋ถ€๋‹ด์ด ์ ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ Tokio์™€ ๊ฐ™์€ ๋น„๋™๊ธฐ ๋Ÿฐํƒ€์ž„์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, Rust ์ƒํƒœ๊ณ„ ๋‚ด ๋‹ค์–‘ํ•œ ํ”„๋กœ์ ํŠธ์— ์‰ฝ๊ฒŒ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํ”„๋กœ์ ํŠธ๋Š” ONNX ๋Ÿฐํƒ€์ž„์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ชจ๋ธ ์ถ”๋ก ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , Hugging Face์˜ tokenizers๋ฅผ ํ™œ์šฉํ•ด ๋น ๋ฅธ ํ† ํฐํ™” ๊ณผ์ •์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ…์ŠคํŠธ, ์ด๋ฏธ์ง€, ๋‹ค๊ตญ์–ด ๋ฐ์ดํ„ฐ๊นŒ์ง€ ๋‹ค์–‘ํ•œ AI ์‘์šฉ์— ์ ํ•ฉํ•œ ์ž„๋ฒ ๋”ฉ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Rust ๊ฐœ๋ฐœ์ž์—๊ฒŒ๋Š” โ€œ๋น ๋ฅด๊ณ  ์•ˆ์ „ํ•œ AI ์ž„๋ฒ ๋”ฉ ๋„๊ตฌโ€๋ผ๋Š” ์ ์—์„œ ๋งค์šฐ ๋งค๋ ฅ์ ์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

FastEmbed๋Š” Rust๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Python, Go, JavaScript ๋“ฑ ๋‹ค์–‘ํ•œ ์–ธ์–ด ์ƒํƒœ๊ณ„์— ๊ตฌํ˜„์ฒด๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. Python ๋ฒ„์ „์€ ๊ฐ€์žฅ ๋จผ์ € ๋“ฑ์žฅํ–ˆ๊ณ  Hugging Face ๋ชจ๋ธ๊ณผ์˜ ํ˜ธํ™˜์„ฑ์ด ๋›ฐ์–ด๋‚˜์ง€๋งŒ, ์†๋„์™€ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ ๋ฉด์—์„œ๋Š” Rust ๋ฒ„์ „์ด ๊ฐ•์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. Go ๋ฐ JavaScript ๋ฒ„์ „์€ ์›น ์„œ๋น„์Šค ๋ฐ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ํ™˜๊ฒฝ์— ํŠนํ™”๋˜์–ด ์žˆ๋Š” ๋ฐ˜๋ฉด, Rust ๋ฒ„์ „์€ ์‹œ์Šคํ…œ ๋ ˆ๋ฒจ์—์„œ ๊ณ ์„ฑ๋Šฅ ์—ฐ์‚ฐ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์™€ ์‹ค์‹œ๊ฐ„ ๊ฒ€์ƒ‰ ์‹œ์Šคํ…œ ๊ตฌ์ถ•์—๋Š” Rust ๋ฒ„์ „์ด ํŠนํžˆ ์œ ๋ฆฌํ•˜๋ฉฐ, Python๊ณผ ๋‹ฌ๋ฆฌ ๋Ÿฐํƒ€์ž„ ๋น„์šฉ์ด ์ ๋‹ค๋Š” ์ ์—์„œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์•ˆ์ •์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

FastEmbed-rs์˜ ์ฃผ์š” ํŠน์ง• ๋ฐ ์ง€์› ๋ชจ๋ธ

์ฃผ์š” ๊ธฐ๋Šฅ

  • ๋™๊ธฐ์‹ ์‹คํ–‰(Synchronous Execution) ์ง€์› โ†’ Tokio ๋ถˆํ•„์š”
  • ONNX ๊ธฐ๋ฐ˜ ์ถ”๋ก  โ†’ ๊ณ ์„ฑ๋Šฅ, ๊ฒฝ๋Ÿ‰ํ™”๋œ ์‹คํ–‰
  • Hugging Face tokenizers ๊ธฐ๋ฐ˜ ๋น ๋ฅธ ์ธ์ฝ”๋”ฉ
  • ํ…์ŠคํŠธ, ์ด๋ฏธ์ง€, ํฌ์†Œ ๋ฒกํ„ฐ, ์žฌ์ •๋ ฌ ๋ชจ๋ธ ์ง€์›

๋ชจ๋ธ ์ง€์›

FastEmbed-rs๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๋ชจ๋ธ์„ ์„ ํƒ์ ์œผ๋กœ ํ™œ์šฉํ•˜์—ฌ ๊ฒ€์ƒ‰ ์‹œ์Šคํ…œ, ์ถ”์ฒœ ์—”์ง„, ๋ฌธ์„œ ๋ถ„๋ฅ˜, ์ด๋ฏธ์ง€ ๊ฒ€์ƒ‰ ๋“ฑ๊ณผ ๊ฐ™์€ AI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์— ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ํ…์ŠคํŠธ ์ž„๋ฒ ๋”ฉ(Text Embedding)

  2. ํฌ์†Œ ๋ฒกํ„ฐ ์ž„๋ฒ ๋”ฉ(Sparse Text Embedding)

  1. ์ด๋ฏธ์ง€ ์ž„๋ฒ ๋”ฉ(Image Embedding)

  2. ์žฌ์ •๋ ฌ(Reranking)

FastEmbed-rs์˜ ์„ค์น˜ ๋ฐฉ๋ฒ•

Cargo.toml์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค:

[dependencies]
fastembed = "5"

FastEmbed-rs ์‚ฌ์šฉ ์˜ˆ์‹œ

ํ…์ŠคํŠธ ์ž…๋ ฅ์œผ๋กœ๋ถ€ํ„ฐ ์ž„๋ฒ ๋”ฉ ์ƒ์„ฑํ•˜๊ธฐ

๋‹ค์Œ์€ FastEmbed-rs๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…์ŠคํŠธ ์ž„๋ฒ ๋”ฉ์„ ์ƒ์„ฑํ•˜๋Š” ์˜ˆ์‹œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค:

use fastembed::{TextEmbedding, InitOptions, EmbeddingModel};

let mut model = TextEmbedding::try_new(Default::default())?;
let documents = vec![
    "passage: Hello, World!",
    "query: Hello, World!",
    "passage: This is an example passage.",
];
let embeddings = model.embed(documents, None)?;
println!("Embeddings length: {}", embeddings.len());

์ด๋ฏธ์ง€ ์ž…๋ ฅ์œผ๋กœ๋ถ€ํ„ฐ ์ž„๋ฒ ๋”ฉ ์ƒ์„ฑํ•˜๊ธฐ

๋‹ค์Œ์€ FastEmbed-rs๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€ ์ž„๋ฒ ๋”ฉ์„ ์ƒ์„ฑํ•˜๋Š” ์˜ˆ์‹œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค:

use fastembed::{ImageEmbedding, ImageInitOptions, ImageEmbeddingModel};

let mut model = ImageEmbedding::try_new(Default::default())?;
let images = vec!["assets/image_0.png", "assets/image_1.png"];
let embeddings = model.embed(images, None)?;
println!("Embeddings length: {}", embeddings.len());

์žฌ์ •๋ ฌ(Reranking)

๋‹ค์Œ์€ FastEmbed-rs๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์žฌ์ •๋ ฌ(Reranking)์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์˜ˆ์‹œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค:

use fastembed::{TextRerank, RerankInitOptions, RerankerModel};

let mut model = TextRerank::try_new(Default::default())?;
let docs = vec!["panda is animal", "giant panda is a mammal"];
let results = model.rerank("what is panda?", docs, true, None)?;
println!("Rerank result: {:?}", results);

๋ผ์ด์„ ์Šค

FastEmbed-rs ํ”„๋กœ์ ํŠธ๋Š” Apache 2.0 ๋ผ์ด์„ ์Šค๋กœ ๊ณต๊ฐœ ๋ฐ ๋ฐฐํฌ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒ์—…์  ์‚ฌ์šฉ์— ์ œ์•ฝ์ด ์—†์œผ๋ฉฐ, ์ž์œ ๋กญ๊ฒŒ ์ˆ˜์ • ๋ฐ ๋ฐฐํฌ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

:github: FastEmbed-rs ํ”„๋กœ์ ํŠธ GitHub ์ €์žฅ์†Œ

:books: FastEmbed-rs ํ”„๋กœ์ ํŠธ API ๋ฌธ์„œ




์ด ๊ธ€์€ GPT ๋ชจ๋ธ๋กœ ์ •๋ฆฌํ•œ ๊ธ€์„ ๋ฐ”ํƒ•์œผ๋กœ ํ•œ ๊ฒƒ์œผ๋กœ, ์›๋ฌธ์˜ ๋‚ด์šฉ ๋˜๋Š” ์˜๋„์™€ ๋‹ค๋ฅด๊ฒŒ ์ •๋ฆฌ๋œ ๋‚ด์šฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€์‹ฌ์žˆ๋Š” ๋‚ด์šฉ์ด์‹œ๋ผ๋ฉด ์›๋ฌธ๋„ ํ•จ๊ป˜ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”! ์ฝ์œผ์‹œ๋ฉด์„œ ์–ด์ƒ‰ํ•˜๊ฑฐ๋‚˜ ์ž˜๋ชป๋œ ๋‚ด์šฉ์„ ๋ฐœ๊ฒฌํ•˜์‹œ๋ฉด ๋ง๊ธ€๋กœ ์•Œ๋ ค์ฃผ์‹œ๊ธฐ๋ฅผ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค. :hugs:

:pytorch:ํŒŒ์ดํ† ์น˜ ํ•œ๊ตญ ์‚ฌ์šฉ์ž ๋ชจ์ž„:south_korea:์ด ์ •๋ฆฌํ•œ ์ด ๊ธ€์ด ์œ ์šฉํ•˜์…จ๋‚˜์š”? ํšŒ์›์œผ๋กœ ๊ฐ€์ž…ํ•˜์‹œ๋ฉด ์ฃผ์š” ๊ธ€๋“ค์„ ์ด๋ฉ”์ผ:love_letter:๋กœ ๋ณด๋‚ด๋“œ๋ฆฝ๋‹ˆ๋‹ค! (๊ธฐ๋ณธ์€ Weekly์ง€๋งŒ Daily๋กœ ๋ณ€๊ฒฝ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.)

:wrapped_gift: ์•„๋ž˜:down_right_arrow:์ชฝ์— ์ข‹์•„์š”:+1:๋ฅผ ๋ˆŒ๋Ÿฌ์ฃผ์‹œ๋ฉด ์ƒˆ๋กœ์šด ์†Œ์‹๋“ค์„ ์ •๋ฆฌํ•˜๊ณ  ๊ณต์œ ํ•˜๋Š”๋ฐ ํž˜์ด ๋ฉ๋‹ˆ๋‹ค~ :star_struck:

1๊ฐœ์˜ ์ข‹์•„์š”