Microsoft의 Phi-3를 CPU에서 Rust와 Candle로 실행하기
Source: Dev.to
소개
Python은 풍부한 생태계(예: PyTorch와 Hugging Face Transformers)를 갖춘 현재 머신러닝 모델 학습에 가장 좋은 도구입니다. 하지만 프로덕션 환경이나 엣지 디바이스에서 추론을 할 때는 Python의 오버헤드—큰 Docker 이미지, 느린 콜드 스타트, 높은 메모리 사용량—가 큰 제약이 될 수 있습니다.
Rust와 Candle은 훨씬 적은 오버헤드로 대규모 언어 모델(LLM)을 실행할 수 있는 방법을 제공합니다. Candle은 Hugging Face에서 만든 최소주의 ML 프레임워크로, 양자화된 GGUF 모델을 지원합니다. 이를 통해 GPU 없이도 표준 CPU에서 Microsoft Phi‑3와 같은 최신 모델을 배포할 수 있습니다.
이 가이드에서는 다음을 배울 수 있습니다:
- 무거운 PyTorch 의존성을 제거하기.
- 양자화된 Phi‑3 모델을 Rust에서 직접 로드하기.
- 빠른 CPU 추론을 위한 독립형 경량 CLI 도구 만들기.
1단계: 프로젝트 설정
cargo new rust-phi3-cpu
cd rust-phi3-cpu
Cargo.toml에 Candle 스택과 기타 의존성을 추가합니다:
[package]
name = "rust-phi3"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0"
tokenizers = "0.19.1"
clap = { version = "4.4", features = ["derive"] }
candle-core = { git = "https://github.com/huggingface/candle.git", branch = "main" }
candle-transformers = { git = "https://github.com/huggingface/candle.git", branch = "main" }
candle-nn = { git = "https://github.com/huggingface/candle.git", branch = "main" }
candle-transformers는 GGUF(양자화) 모델에 대한 내장 지원을 포함하고 있으며, 이는 효율적인 CPU 추론의 핵심입니다.
2단계: 구현
src/main.rs 파일을 다음 코드로 작성합니다:
use anyhow::{Error as E, Result};
use clap::Parser;
use candle_transformers::models::quantized_phi3 as model; // Phi‑3 specific module
use candle_core::{Tensor, Device};
use candle_core::quantized::gguf_file;
use tokenizers::Tokenizer;
use std::io::Write;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Prompt for inference
#[arg(short, long, default_value = "Physics is fun. Explain quantum physics to a 5-year-old in simple words:")]
prompt: String,
/// Path to the GGUF model file
#[arg(long, default_value = "Phi-3-mini-4k-instruct-q4.gguf")]
model_path: String,
}
fn main() -> Result<()> {
let args = Args::parse();
println!("Loading model from: {}", args.model_path);
// 1. Setup device (CPU)
let device = Device::Cpu;
// 2. Load the GGUF model
let mut file = std::fs::File::open(&args.model_path)
.map_err(|_| E::msg(format!("Could not find model file at {}. Did you download it?", args.model_path)))?;
let content = gguf_file::Content::read(&mut file)?;
// Flash Attention disabled for CPU
let mut model = model::ModelWeights::from_gguf(false, content, &mut file, &device)?;
// 3. Load tokenizer
println!("Loading tokenizer...");
let tokenizer = Tokenizer::from_file("tokenizer.json").map_err(E::msg)?;
// 4. Encode prompt
let tokens = tokenizer.encode(args.prompt, true).map_err(E::msg)?;
let prompt_tokens = tokens.get_ids();
let mut all_tokens = prompt_tokens.to_vec();
// 5. Inference loop
println!("Generating response...\n");
let mut to_generate = 100; // max tokens
let mut logits_processor = candle_transformers::generation::LogitsProcessor::new(299_792_458, None, None);
print!("Response: ");
std::io::stdout().flush()?;
let mut next_token = *prompt_tokens.last().unwrap();
for _ in 0..to_generate {
let input = Tensor::new(&[next_token], &device)?.unsqueeze(0)?;
let logits = model.forward(&input, all_tokens.len())?;
let logits = logits.squeeze(0)?;
next_token = logits_processor.sample(&logits)?;
all_tokens.push(next_token);
if let Some(t) = tokenizer.decode(&[next_token], true).ok() {
print!("{}", t);
std::io::stdout().flush()?;
}
}
println!("\n\nDone!");
Ok(())
}
3단계: 모델 가중치 확보
Hugging Face에서 양자화된 Phi‑3 Mini 모델(GGUF 포맷)을 다운로드합니다:
- 모델 파일:
Phi-3-mini-4k-instruct-q4.gguf(≈ 2.3 GB,q4_k_m.gguf변형) - 토크나이저:
tokenizer.json(공식 레포지토리에서 제공)
두 파일을 프로젝트 루트에 배치합니다.
4단계: 데모 실행
최적 성능을 위해 릴리스 모드로 컴파일합니다:
cargo run --release -- \
--model-path "Phi-3-mini-4k-instruct-q4.gguf" \
--prompt "whatever you want:"
Python 기반 추론에서 흔히 겪는 긴 시작 지연 없이 토큰이 거의 즉시 콘솔에 스트리밍되는 것을 확인할 수 있습니다.

일반적인 노트북(예: Intel i5‑8100Y)에서도 추론이 완전히 CPU만으로 원활히 실행됩니다. 배포 아티팩트(바이너리 + 런타임)는 유사한 Python/Docker 설정에 비해 크게 작아집니다.
결론
Python은 모델 학습 및 실험에 여전히 최고의 생태계입니다. 하지만 시작 시간과 메모리 사용량이 중요한 엣지, IoT, 서버리스 환경 등 프로덕션 배포에서는 Rust와 Candle이 매력적인 대안을 제공합니다. Phi‑3와 같은 양자화된 GGUF 모델을 활용하면 표준 CPU에서도 빠르고 저오버헤드인 추론을 구현할 수 있습니다.