A Rust ML-ökoszisztéma évek óta azzal küzd, hogy nincs egy olyan letisztult, éretten használható tenzorkönyvtára, amire ráépülhetne egy egészséges közösség. A tch-rs (LibTorch binding), a burn és a linfa mind próbálkoztak, de vagy C++ függőséghez kötöttek, vagy más filozófiát követnek. Ebbe a résbe lépett be most a Hugging Face a Candle nevű crate-tel, amelynek 0.1-es verziója pár napja jelent meg és futótűzként terjed a Rust és az ML közösségben egyaránt.
Mi az a Candle és miért fontos hír ez?
A Candle egy minimalista ML keretrendszer Rustban, aminek a fő ígérete a könnyű, szerver-oldali inferencia. A Hugging Face blogbejegyzése és a GitHub repo (huggingface/candle) szerint a motiváció nagyon konkrét: a Python + PyTorch stack production környezetben nehézkes — GIL, nagy Docker image-ek, lassú cold start szerverless környezetben, és a Python runtime általános overhead-je.
A Candle ezzel szemben egyetlen, kis méretű bináris, amit be lehet égetni egy konténerbe vagy akár WASM-be fordítani. Ez azoknak a csapatoknak szól elsősorban, akik már meglévő, betanított modelleket (BERT, Whisper, Llama-szerű architektúrák) szeretnének futtatni gyorsan és megbízhatóan, betanítás helyett fókuszban az inferenciával.
A Candle a 0.1.x verzióban még kifejezetten korai állapotban van — az API bármikor változhat, és a dokumentáció is hiányos. Ne cseréld le vele holnap a production PyTorch szolgáltatásod, de érdemes már most kísérletezni vele.
A Hugging Face motivációi a Rust választása mögött
A Hugging Face csapata több blogposztban és GitHub discussion-ben is kifejtette, miért esett a választás Rustra egy Python-központú cég esetében:
- Memóriabiztonság ownership modellel: a borrow checker garantálja, hogy a tenzor buffer-ek élettartama helyesen legyen kezelve, adatverseny (data race) nélkül — ez különösen fontos, ha később GPU/multi-thread inferenciáról van szó.
- Egyetlen bináris, minimális futásidejű overhead: nincs szükség Python interpreterre, nincs GIL, a végeredmény egy natív, statikusan linkelhető executable.
- WASM-kompatibilitás: a Rust toolchain kiváló WebAssembly targetet biztosít, ami böngészőben futó inferenciát is lehetővé tesz.
- Cargo és a crates.io ökoszisztéma: a függőségkezelés és a build folyamat sokkal reprodukálhatóbb, mint a Python
pip/condavilág.
A csapat egyébként nem titkolja, hogy a tch-rs-szel (a LibTorch Rust binding-jával) is dolgoztak korábban, de az FFI réteg és a C++ függőség miatt a deployment sosem volt annyira egyszerű, mint amit egy natív Rust megoldástól elvárnának.
Fő funkciók az első, 0.1-es kiadásban
A Candle jelenleg a következő képességekkel rendelkezik:
- Tenzor műveletek CPU-n, alapvető lineáris algebrával (matmul, broadcast, reduce operátorok).
- Kezdeti CUDA support, ami GPU-n is futtatja a legfontosabb műveleteket — bár ez még kísérleti státuszú.
- Modell betöltés safetensors formátumból, ami a Hugging Face Hub natív, biztonságos súlyformátuma (nem
pickle, tehát nincs kódfuttatási kockázat betöltéskor). - Néhány előre elkészített modell implementáció, például BERT-szerű enkóderek, amivel gyorsan lehet embeddinget generálni.
candle-coreéscandle-nnkülön crate-ekre bontva, hogy a réteg-építőelemek (Linear, LayerNorm, stb.) elkülönüljenek az alap tenzor logikától.
Íme egy egyszerű példa, ami két véletlen tenzort hoz létre és összeszorozza — ez már most lefordul és futtatható a Candle 0.1-gyel:
use candle_core::{Device, Tensor};
fn main() -> anyhow::Result<()> {
let device = Device::Cpu;
let a = Tensor::randn(0f32, 1f32, (3, 4), &device)?;
let b = Tensor::randn(0f32, 1f32, (4, 5), &device)?;
let c = a.matmul(&b)?;
println!("eredmény shape: {:?}", c.shape());
println!("{c}");
Ok(())
}
A Device::Cpu helyett Device::new_cuda(0)?-t is megadhatnál, ha van elérhető GPU-d és a cuda feature-rel fordítottad a crate-et — ez már most is elérhető, csak instabil.
Ha kipróbálod a Candle-t, érdemes a friss, 1.71-es Rust toolchaint használni. A let-else szintaxis nagyon jól jön a modell betöltő kódban, ahol gyakran kell early-return-ölni hibás/hiányzó tenzor esetén.
use candle_core::Tensor;
fn describe(t: Option<&Tensor>) -> anyhow::Result<()> {
let Some(tensor) = t else {
anyhow::bail!("hiányzó tenzor a modellben");
};
println!("dtype: {:?}, shape: {:?}", tensor.dtype(), tensor.shape());
Ok(())
}
A Candle viszonya a PyTorchhoz és más ML keretrendszerekhez
Fontos leszögezni: a Candle nem akarja lecserélni a PyTorchot a kutatásban vagy a betanításban. A PyTorch dinamikus gráfja, a hatalmas ökoszisztémája (optimizerek, adatbetöltők, vizualizációs eszközök) és a Python interaktivitása egyelőre verhetetlen kutatói workflow-hoz.
A Candle célja szűkebb, de nagyon éles: a betanított modell futtatása egyszerű, gyors, alacsony overhead-ű környezetben. Ebben a szegmensben a versenytársak inkább az onnxruntime C API bindingjei, vagy a tch-rs LibTorch wrapper. A Candle előnye, hogy nincs C++ toolchain függősége — tisztán Rust (a CUDA kernel-eket leszámítva), ami drasztikusan egyszerűsíti a build és deployment folyamatot.
Érdemes még megemlíteni a burn crate-et is, amely hasonló célokat követ, de más architektúra mögé áll (backend-agnosztikus tenzor absztrakció, ami akár WGPU-t is használhat). A Candle inkább a Hugging Face Hub modellek gyors, minimalista futtatására fókuszál, kevesebb absztrakciós réteggel.
Ha production rendszerbe tervezed beépíteni, számolj azzal, hogy a 0.1-es verzió API-ja instabil. A Cargo.lock rögzítése és a pontos verzió pinelése (candle-core = "=0.1.0") most különösen fontos, hogy egy patch release ne törje el a buildedet.
Első lépések: hello world modell futtatása Candle-lel
A leggyorsabb módja a kipróbálásnak, hogy klónozod a repót, és lefuttatod az egyik példát. Egy tipikus Cargo.toml a projekt gyökerében így nézhet ki:
[package]
name = "candle-hello-world"
version = "0.1.0"
edition = "2021"
[dependencies]
candle-core = "0.1"
anyhow = "1"
Ezután a src/main.rs-be bekerülhet egy egyszerű lineáris réteg is, ha a candle-nn crate-et is hozzáadod:
use candle_core::{Device, Tensor};
use candle_nn::{Linear, Module};
fn main() -> anyhow::Result<()> {
let device = Device::Cpu;
let weight = Tensor::randn(0f32, 1f32, (5, 3), &device)?;
let bias = Tensor::randn(0f32, 1f32, (5,), &device)?;
let layer = Linear::new(weight, Some(bias));
let input = Tensor::randn(0f32, 1f32, (1, 3), &device)?;
let output = layer.forward(&input)?;
println!("kimenet: {output}");
Ok(())
}
Ha a safetensors formátumú súlyokat szeretnéd betölteni egy Hugging Face Hub repóból, a candle-core::safetensors modul segít a beolvasásban — ez teszi lehetővé, hogy egy már meglévő, PyTorchban betanított BERT modellt közvetlenül Rust-ban futtass, konverzió nélkül.
Összefoglalás
A Candle 0.1 még gyerekcipőben jár, de a hír azért fontos, mert egy komoly, jól finanszírozott szereplő — a Hugging Face — most tette le a Rust melletti voksát az ML inferencia területén. Ha eddig azt gondoltad, hogy a Rust és a gépi tanulás nem fér össze jól, most van itt az idő, hogy átgondold: a memóriabiztonság, a kis binárisok és a natív teljesítmény kombinációja pontosan azt az űrt tölti ki, amit a Python-alapú stack nem tud. Érdemes követni a projekt fejlődését — az elkövetkező hónapokban valószínűleg gyors iterációkat fogunk látni.