Upload nvfp4/examples/nvfp4_inference.rs with huggingface_hub
Browse files
nvfp4/examples/nvfp4_inference.rs
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// NVFP4 Inference Example for Candle
|
| 2 |
+
//
|
| 3 |
+
// This example demonstrates:
|
| 4 |
+
// 1. Loading a model from HuggingFace
|
| 5 |
+
// 2. Quantizing weights to NVFP4
|
| 6 |
+
// 3. Running inference with NVFP4 quantized weights on CUDA
|
| 7 |
+
//
|
| 8 |
+
// Usage:
|
| 9 |
+
// cargo run --release --features cuda --bin nvfp4-inference -- \
|
| 10 |
+
// --model igorls/gemma-4-12B-it-heretic-v1 \
|
| 11 |
+
// --prompt "Hello, world!" \
|
| 12 |
+
// --n-tokens 128
|
| 13 |
+
|
| 14 |
+
use candle::{DType, Device, Tensor, Module};
|
| 15 |
+
use std::io::Write;
|
| 16 |
+
|
| 17 |
+
fn main() -> candle::Result<()> {
|
| 18 |
+
let model_id = std::env::args()
|
| 19 |
+
.find(|arg| arg.starts_with("--model="))
|
| 20 |
+
.map(|s| s[8..].to_string())
|
| 21 |
+
.unwrap_or_else(|| "igorls/gemma-4-12B-it-heretic-v1".to_string());
|
| 22 |
+
|
| 23 |
+
let prompt = std::env::args()
|
| 24 |
+
.find(|arg| arg.starts_with("--prompt="))
|
| 25 |
+
.map(|s| s[9..].to_string())
|
| 26 |
+
.unwrap_or_else(|| "What is the meaning of life?".to_string());
|
| 27 |
+
|
| 28 |
+
let n_tokens: usize = std::env::args()
|
| 29 |
+
.find(|arg| arg.starts_with("--n-tokens="))
|
| 30 |
+
.and_then(|s| s[11..].parse().ok())
|
| 31 |
+
.unwrap_or(128);
|
| 32 |
+
|
| 33 |
+
println!("NVFP4 Inference Example");
|
| 34 |
+
println!("Model: {model_id}");
|
| 35 |
+
println!("Prompt: {prompt}");
|
| 36 |
+
println!("Max tokens: {n_tokens}");
|
| 37 |
+
println!();
|
| 38 |
+
|
| 39 |
+
// Initialize CUDA device
|
| 40 |
+
let device = Device::cuda_if_available(0)?;
|
| 41 |
+
println!("Device: {:?}", device);
|
| 42 |
+
|
| 43 |
+
// Test NVFP4 quantization
|
| 44 |
+
println!("\n=== NVFP4 Quantization Test ===");
|
| 45 |
+
let test_data = Tensor::randn(0f32, 1f32, (256, 512), &device)?;
|
| 46 |
+
println!("Input shape: {:?}", test_data.shape());
|
| 47 |
+
|
| 48 |
+
// Quantize to NVFP4
|
| 49 |
+
use candle::quantized::{GgmlDType, QTensor};
|
| 50 |
+
let qtensor = QTensor::quantize(&test_data, GgmlDType::NVFP4)?;
|
| 51 |
+
println!("Quantized dtype: {:?}", qtensor.dtype());
|
| 52 |
+
println!("Quantized shape: {:?}", qtensor.shape());
|
| 53 |
+
|
| 54 |
+
// Dequantize back
|
| 55 |
+
let dequant = qtensor.dequantize(&device)?;
|
| 56 |
+
println!("Dequantized shape: {:?}", dequant.shape());
|
| 57 |
+
|
| 58 |
+
// Compute error
|
| 59 |
+
let diff = test_data.broadcast_sub(&dequant)?;
|
| 60 |
+
let max_err = diff.max_all()?.to_scalar::<f32>()?;
|
| 61 |
+
let mean_err = diff.mean_all()?.to_scalar::<f32>()?;
|
| 62 |
+
let ref_mean = test_data.abs()?.mean_all()?.to_scalar::<f32>()?;
|
| 63 |
+
println!("Max error: {:.6}", max_err);
|
| 64 |
+
println!("Mean error: {:.6}", mean_err);
|
| 65 |
+
println!("Relative error: {:.6}", mean_err / ref_mean);
|
| 66 |
+
|
| 67 |
+
// Test matmul
|
| 68 |
+
println!("\n=== NVFP4 MatMul Test ===");
|
| 69 |
+
let x = Tensor::randn(0f32, 1f32, (1, 512), &device)?;
|
| 70 |
+
let w = Tensor::randn(0f32, 0.5f32, (256, 512), &device)?;
|
| 71 |
+
let w_q = QTensor::quantize(&w, GgmlDType::NVFP4)?;
|
| 72 |
+
|
| 73 |
+
// Reference matmul
|
| 74 |
+
let ref_out = x.matmul(&w.t()?)?;
|
| 75 |
+
|
| 76 |
+
// NVFP4 matmul via QMatMul
|
| 77 |
+
use candle::quantized::QMatMul;
|
| 78 |
+
let qmatmul = QMatMul::from_arc(std::sync::Arc::new(w_q))?;
|
| 79 |
+
let nvfp4_out = qmatmul.forward(&x)?;
|
| 80 |
+
|
| 81 |
+
let matmul_diff = ref_out.broadcast_sub(&nvfp4_out)?;
|
| 82 |
+
let matmul_max_err = matmul_diff.max_all()?.to_scalar::<f32>()?;
|
| 83 |
+
let matmul_mean_err = matmul_diff.mean_all()?.to_scalar::<f32>()?;
|
| 84 |
+
let matmul_ref_mean = ref_out.abs()?.mean_all()?.to_scalar::<f32>()?;
|
| 85 |
+
println!("MatMul max error: {:.6}", matmul_max_err);
|
| 86 |
+
println!("MatMul mean error: {:.6}", matmul_mean_err);
|
| 87 |
+
println!("MatMul relative error: {:.6}", matmul_mean_err / matmul_ref_mean);
|
| 88 |
+
|
| 89 |
+
println!("\n=== NVFP4 Memory Analysis ===");
|
| 90 |
+
let n = 4096usize;
|
| 91 |
+
let k = 4096usize;
|
| 92 |
+
let fp32_bytes = n * k * 4;
|
| 93 |
+
let nvfp4_bytes = n * (k / 16) * 9; // 9 bytes per 16 elements
|
| 94 |
+
println!("FP32 weight: {:.1} MB", fp32_bytes as f64 / 1024.0 / 1024.0);
|
| 95 |
+
println!("NVFP4 weight: {:.1} MB", nvfp4_bytes as f64 / 1024.0 / 1024.0);
|
| 96 |
+
println!("Compression: {:.2}x", fp32_bytes as f64 / nvfp4_bytes as f64);
|
| 97 |
+
|
| 98 |
+
println!("\n=== Done ===");
|
| 99 |
+
Ok(())
|
| 100 |
+
}
|