Rustで大規模モデル推論エンジンを構築:candleによる軽量デプロイ実践
なぜRustでLLM推論?
PythonはAI訓練の王者だが、推論デプロイには致命的弱点:GIL、高メモリオーバーヘッド、ゼロコピー不可。
| 次元 | Python (PyTorch) | Rust (candle) |
|---|---|---|
| ランタイムオーバーヘッド | インタプリタ+フレームワークで余分なメモリ | ランタイムなし。メモリはほぼモデル重みのみ |
| コールドスタート | 通常10-30秒 | 約2-5秒(検証環境での実測例、参考値) |
| メモリ安全性 | 手動管理 | コンパイル時保証 |
candleフレームワーク
HuggingFaceのRust MLフレームワーク:
- 純粋Rust実装、Python依存なし
- CUDA/Metal GPUアクセラレーション
- ゼロコピーテンソル操作
- GGML/GGUF量子化対応
推論エンジンコア
pub struct InferenceEngine {
model: Arc<RwLock<Model>>,
tokenizer: Tokenizer,
device: Device,
}
impl InferenceEngine {
pub async fn generate(&self, prompt: &str, max_tokens: usize) -> anyhow::Result<String> {
let tokens = self.tokenizer.encode(prompt, true)?;
let mut input_tokens = tokens.get_ids().to_vec();
let mut generated_tokens = Vec::new();
let model = self.model.read().await;
for _ in 0..max_tokens {
let input = Tensor::new(&input_tokens, &self.device)?.unsqueeze(0)?;
let logits = model.forward(&input, input_tokens.len() - 1)?;
let next_token = self.sample_token(&logits, &generated_tokens)?;
generated_tokens.push(next_token);
input_tokens.push(next_token);
}
let output = self.tokenizer.decode(&generated_tokens, true)?;
Ok(output)
}
}
正直な性能位置づけ
結論から:本記事のエンジンは教育・軽量ユースケース向けであり、candleのスループット上限を示すものではなく、vLLMに勝つこともありません。
上記コードはグローバルRwLockでforwardを直列化し、バッチ処理なしでトークンごとに実行します——物理的に数千tok/sには到達できません。ネットに流布する「candle 8,200 tok/s が vLLM 2,500 を圧倒」のような数字に信頼できる出典はなく、本記事の旧版でも引用していましたが削除しました。
業界の共通認識と独立系ベンチマークの結論は逆です:
- 高同時実行スループット:PagedAttention+連続バッチ処理を備えるvLLMが明確に上位。candle系のシングルリクエスト実装のスループットは一般にvLLMの約70%程度(モデル・ハードウェア・量子化形式で変動、参考値)。
- candleの真の強みはデプロイ形態:シングルバイナリ、Python非依存、高速なコールドスタート、低いランタイムメモリオーバーヘッド。
定性比較(デプロイ観点)
| 次元 | vLLM | 本記事のcandleエンジン |
|---|---|---|
| 高同時実行スループット | 強い(PagedAttention+連続バッチ) | 弱い(バッチなし、リクエスト直列) |
| 単一リクエストのレイテンシ | 低い | 低い |
| デプロイ依存 | Python+CUDAエコシステム | シングルバイナリ、Python不要 |
| コールドスタート | 通常10-30秒 | 約2-5秒(検証環境での実測例、参考値) |
| ランタイムメモリ | Pythonランタイム+フレームワーク | ほぼモデル重み+KVキャッシュのみ |
| 適用シーン | 本番の高同時実行サービス | 教育、エッジ/組み込み、軽量サービス |
メモリ使用量の正直な数字
Qwen2.5-7B-Instruct Q4_0の例:
- 重み:Q4_0量子化後 約4GB(1パラメータあたり約0.55バイト、7B × 0.55 ≈ 3.9GB)
- KVキャッシュ:コンテキスト長と同時実行数に応じて増加、通常さらに1-2GB
- 合計:約5-6GB
「7B Q4_0モデルのメモリが1.1GBだけ」という主張は基本算術に反します——重みだけで約4GBです。旧版の当該数字は誤りであり、修正済みです。
まとめ
- 軽量デプロイ:単一バイナリ約15MB(ビルド例)、Python非依存、コールドスタート約2-5秒(検証環境の実測例)
- メモリ安全性:データ競合なし、ヌルポインタなし、バッファオーバーフローなし
- 低ランタイムオーバーヘッド:メモリはほぼモデル重み+KVキャッシュのみ
- GILなし:真のマルチスレッド同時実行
正直に言えば、スループットは本構成の売りではありません。高同時実行の本番サービスにはvLLMなどPagedAttention+連続バッチ処理を備えたエンジンを選びましょう。candle構成は教育、エッジデプロイ、デプロイ形態が重要な軽量サービスに適しています。
Rustはスループットで誰かを圧倒するためではなく、推論デプロイにもう一つの形態を与えるもの——訓練はPython、高同時実行はvLLM、軽量/エッジはRust+candle。
#Rust#LLM推理#轻量部署#candle#推理引擎#内存安全