Files
foxhunt/testing/integration/gpu/ml_gpu_inference_test.rs
jgrusewski 9c3d741a08 refactor: restructure repo — crates/, bin/, testing/ layout
Move 17 library crates into crates/, CLI binary into bin/fxt,
consolidate 10 test crates into testing/, split config crate
from deployment config files.

Root directory reduced from 38+ to ~17 directories.
All Cargo.toml paths and build.rs proto refs updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:56:00 +01:00

383 lines
14 KiB
Rust
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! ML Model GPU Inference Tests
//!
//! Tests GPU acceleration for ML models including DQN, MAMBA, TFT, and other models
use super::utils::*;
use candle_core::{Device, DType, Tensor};
use log::{info, warn};
use std::time::Instant;
// Import ML model types from the main codebase
use ml::dqn::network::DQNConfig;
use ml::inference::{InferenceConfig, MLInferenceEngine};
use ml::mamba::MambaConfig;
use ml::tft::TFTConfig;
use ml::training::DeviceCapabilities;
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_dqn_gpu_inference() {
init_gpu_test_env();
info!("🧠 Testing DQN GPU inference");
let device = get_test_device();
// Create DQN configuration for testing
let config = DQNConfig {
state_dim: 8,
action_dim: 4,
hidden_dim: 64,
use_gpu: device.is_cuda(),
learning_rate: 0.001,
..Default::default()
};
info!("DQN config - GPU enabled: {}", config.use_gpu);
// Test DQN network creation and inference
match ml::dqn::network::DQNNetwork::new(config, device.clone()) {
Ok(network) => {
info!("✅ DQN network created successfully on device: {:?}", device);
// Create test state tensor
let batch_size = 32;
let state = match Tensor::randn(0.0, 1.0, (batch_size, 8), &device) {
Ok(tensor) => tensor,
Err(e) => {
warn!("❌ Failed to create state tensor: {}", e);
return;
}
};
// Test inference
let start_time = Instant::now();
match network.forward(&state) {
Ok(output) => {
let inference_time = start_time.elapsed();
info!("✅ DQN inference completed in {:?}", inference_time);
info!("Output shape: {:?}", output.shape());
// Validate output shape
assert_eq!(output.shape().dims(), &[batch_size, 4]);
// Log GPU utilization if available
if device.is_cuda() {
info!("🚀 GPU inference successful");
} else {
info!("💻 CPU inference successful");
}
}
Err(e) => {
warn!("❌ DQN inference failed: {}", e);
}
}
}
Err(e) => {
warn!("❌ Failed to create DQN network: {}", e);
}
}
}
#[tokio::test]
async fn test_mamba_gpu_inference() {
init_gpu_test_env();
info!("🐍 Testing MAMBA GPU inference");
let device = get_test_device();
// Create MAMBA configuration
let config = MambaConfig {
d_model: 128,
n_layer: 4,
vocab_size: 1000,
use_cuda: device.is_cuda(),
..Default::default()
};
info!("MAMBA config - GPU enabled: {}", config.use_cuda);
// Test MAMBA model creation and inference
match ml::mamba::Mamba::new(config, device.clone()) {
Ok(model) => {
info!("✅ MAMBA model created successfully on device: {:?}", device);
// Create test sequence tensor
let seq_len = 64;
let batch_size = 16;
let input_ids = match Tensor::randint(0, 1000, (batch_size, seq_len), &device) {
Ok(tensor) => tensor,
Err(e) => {
warn!("❌ Failed to create input tensor: {}", e);
return;
}
};
// Test inference
let start_time = Instant::now();
match model.forward(&input_ids) {
Ok(output) => {
let inference_time = start_time.elapsed();
info!("✅ MAMBA inference completed in {:?}", inference_time);
info!("Output shape: {:?}", output.shape());
// Validate output shape
assert_eq!(output.shape().dims(), &[batch_size, seq_len, 1000]);
if device.is_cuda() {
info!("🚀 GPU MAMBA inference successful");
}
}
Err(e) => {
warn!("❌ MAMBA inference failed: {}", e);
}
}
}
Err(e) => {
warn!("❌ Failed to create MAMBA model: {}", e);
}
}
}
#[tokio::test]
async fn test_tft_gpu_inference() {
init_gpu_test_env();
info!("📈 Testing TFT (Temporal Fusion Transformer) GPU inference");
let device = get_test_device();
// Create TFT configuration
let config = TFTConfig {
input_size: 16,
output_size: 1,
hidden_size: 64,
num_heads: 4,
num_layers: 3,
dropout: 0.1,
use_gpu: device.is_cuda(),
..Default::default()
};
info!("TFT config - GPU enabled: {}", config.use_gpu);
// Test TFT model creation and inference
match ml::tft::TemporalFusionTransformer::new(config, device.clone()) {
Ok(model) => {
info!("✅ TFT model created successfully on device: {:?}", device);
// Create test temporal data
let batch_size = 8;
let seq_len = 32;
let features = match Tensor::randn(0.0, 1.0, (batch_size, seq_len, 16), &device) {
Ok(tensor) => tensor,
Err(e) => {
warn!("❌ Failed to create features tensor: {}", e);
return;
}
};
// Test inference
let start_time = Instant::now();
match model.forward(&features) {
Ok(output) => {
let inference_time = start_time.elapsed();
info!("✅ TFT inference completed in {:?}", inference_time);
info!("Output shape: {:?}", output.shape());
// Validate output shape
assert_eq!(output.shape().dims(), &[batch_size, 1]);
if device.is_cuda() {
info!("🚀 GPU TFT inference successful");
}
}
Err(e) => {
warn!("❌ TFT inference failed: {}", e);
}
}
}
Err(e) => {
warn!("❌ Failed to create TFT model: {}", e);
}
}
}
#[tokio::test]
async fn test_ml_inference_engine_gpu() {
init_gpu_test_env();
info!("🏭 Testing ML Inference Engine GPU integration");
let device = get_test_device();
// Create inference configuration
let config = InferenceConfig {
device_preference: if device.is_cuda() {
"cuda".to_string()
} else {
"cpu".to_string()
},
batch_size: 16,
max_sequence_length: 128,
enable_optimization: true,
..Default::default()
};
info!("Inference engine config - Device preference: {}", config.device_preference);
// Test inference engine creation
match MLInferenceEngine::new(config).await {
Ok(engine) => {
info!("✅ ML Inference Engine created successfully");
// Test GPU model loading
let model_id = "test_model";
match engine.load_model(model_id).await {
Ok(_) => {
info!("✅ Model loaded successfully");
// Test batch inference
let features = vec![vec![1.0, 2.0, 3.0, 4.0]; 16]; // 16 samples
let start_time = Instant::now();
match engine.predict_batch(model_id, features).await {
Ok(predictions) => {
let inference_time = start_time.elapsed();
info!("✅ Batch inference completed in {:?}", inference_time);
info!("Predictions count: {}", predictions.len());
assert_eq!(predictions.len(), 16);
if device.is_cuda() {
info!("🚀 GPU batch inference successful");
}
}
Err(e) => {
warn!("❌ Batch inference failed: {}", e);
}
}
}
Err(e) => {
warn!("❌ Model loading failed: {}", e);
}
}
}
Err(e) => {
warn!("❌ Failed to create ML Inference Engine: {}", e);
}
}
}
#[test]
fn test_device_capabilities_gpu() {
init_gpu_test_env();
info!("⚙️ Testing device capabilities assessment");
let device_caps = if cuda_available() {
DeviceCapabilities::new_with_gpu()
} else {
DeviceCapabilities::cpu_default()
};
info!("Device capabilities:");
info!(" GPU available: {}", device_caps.has_gpu());
info!(" Memory capacity: {}", device_caps.memory_capacity());
info!(" Compute capability: {}", device_caps.compute_capability());
// Test capability-based optimizations
if device_caps.has_gpu() {
info!("✅ GPU capabilities detected - enabling GPU optimizations");
assert!(device_caps.compute_capability() > 0.5);
} else {
info!("💻 CPU-only capabilities - using CPU optimizations");
assert!(device_caps.compute_capability() > 0.0);
}
info!("✅ Device capabilities test completed");
}
#[tokio::test]
async fn test_gpu_fallback_behavior() {
init_gpu_test_env();
info!("🔄 Testing GPU fallback behavior");
// Test graceful fallback when GPU operations fail
let device = get_test_device();
// Create a configuration that prefers GPU but can fallback to CPU
let config = InferenceConfig {
device_preference: "auto".to_string(),
enable_fallback: true,
..Default::default()
};
match MLInferenceEngine::new(config).await {
Ok(engine) => {
info!("✅ Inference engine with fallback created successfully");
// Test that engine can handle both GPU and CPU operations
let test_features = vec![vec![1.0, 2.0, 3.0, 4.0]];
// This should work regardless of GPU availability
let result = engine.predict_batch("fallback_test", test_features).await;
match result {
Ok(_predictions) => {
info!("✅ Fallback inference test successful");
}
Err(e) => {
// Even if this specific test fails, the fallback mechanism was tested
info!(" Inference failed but fallback was tested: {}", e);
}
}
}
Err(e) => {
warn!("❌ Failed to create inference engine with fallback: {}", e);
}
}
info!("✅ GPU fallback behavior test completed");
}
#[test]
fn test_tensor_device_consistency() {
init_gpu_test_env();
info!("🎯 Testing tensor device consistency across operations");
let device = get_test_device();
// Create multiple tensors on the same device
let tensor_a = Tensor::ones((10, 10), DType::F32, &device)
.expect("Should create tensor A");
let tensor_b = Tensor::zeros((10, 10), DType::F32, &device)
.expect("Should create tensor B");
// Test that operations maintain device consistency
let result = tensor_a.add(&tensor_b);
match result {
Ok(sum_tensor) => {
assert_eq!(sum_tensor.device(), &device);
info!("✅ Tensor device consistency maintained through operations");
// Test more complex operations
let matmul_result = sum_tensor.matmul(&tensor_a);
match matmul_result {
Ok(matmul_tensor) => {
assert_eq!(matmul_tensor.device(), &device);
info!("✅ Device consistency maintained through matrix operations");
}
Err(e) => {
warn!("⚠️ Matrix multiplication failed: {}", e);
}
}
}
Err(e) => {
warn!("❌ Tensor addition failed: {}", e);
}
}
info!("✅ Tensor device consistency test completed");
}
}