Microsoft의 Phi-3를 CPU에서 Rust와 Candle로 실행하기

발행: (2025년 12월 3일 오후 07:56 GMT+9)
5 min read
원문: Dev.to

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 기반 추론에서 흔히 겪는 긴 시작 지연 없이 토큰이 거의 즉시 콘솔에 스트리밍되는 것을 확인할 수 있습니다.

Demo output

일반적인 노트북(예: Intel i5‑8100Y)에서도 추론이 완전히 CPU만으로 원활히 실행됩니다. 배포 아티팩트(바이너리 + 런타임)는 유사한 Python/Docker 설정에 비해 크게 작아집니다.

결론

Python은 모델 학습 및 실험에 여전히 최고의 생태계입니다. 하지만 시작 시간과 메모리 사용량이 중요한 엣지, IoT, 서버리스 환경 등 프로덕션 배포에서는 Rust와 Candle이 매력적인 대안을 제공합니다. Phi‑3와 같은 양자화된 GGUF 모델을 활용하면 표준 CPU에서도 빠르고 저오버헤드인 추론을 구현할 수 있습니다.

Back to Blog

관련 글

더 보기 »

Blender Addon 개발에 DevOps가 더 필요함

개요 테스트 코드를 작성하고 자동화하십시오. 마음의 평안을 가지고 릴리즈하기 위해 다양한 버전의 Blender에서 테스트를 실행합니다. 현재 개발자이거나 개발자가 되고자 하는 개인…