182 lines
4.5 KiB
Rust
182 lines
4.5 KiB
Rust
//! Burn backend configuration and detection
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
use tracing::info;
|
|
|
|
/// Available Burn backends
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum BurnBackend {
|
|
/// `NdArray` backend (CPU, always available)
|
|
NdArray,
|
|
/// WebGPU backend (cross-platform GPU)
|
|
Wgpu,
|
|
/// CUDA backend (NVIDIA GPUs)
|
|
Cuda,
|
|
/// `PyTorch` backend (via tch-rs)
|
|
Tch,
|
|
}
|
|
|
|
impl Default for BurnBackend {
|
|
fn default() -> Self {
|
|
detect_best_backend()
|
|
}
|
|
}
|
|
|
|
impl BurnBackend {
|
|
/// Get the name of the backend
|
|
pub fn name(&self) -> &'static str {
|
|
match self {
|
|
BurnBackend::NdArray => "ndarray",
|
|
BurnBackend::Wgpu => "wgpu",
|
|
BurnBackend::Cuda => "cuda",
|
|
BurnBackend::Tch => "tch",
|
|
}
|
|
}
|
|
|
|
/// Check if this backend supports GPU acceleration
|
|
pub fn is_gpu(&self) -> bool {
|
|
matches!(
|
|
self,
|
|
BurnBackend::Wgpu | BurnBackend::Cuda | BurnBackend::Tch
|
|
)
|
|
}
|
|
|
|
/// Check if this backend is available
|
|
pub fn is_available(&self) -> bool {
|
|
match self {
|
|
BurnBackend::NdArray => cfg!(feature = "ndarray"),
|
|
BurnBackend::Wgpu => cfg!(feature = "wgpu"),
|
|
BurnBackend::Cuda => cfg!(feature = "cuda") && is_cuda_runtime_available(),
|
|
BurnBackend::Tch => cfg!(feature = "tch"),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Detect the best available backend based on features and hardware
|
|
pub fn detect_best_backend() -> BurnBackend {
|
|
// Prefer CUDA if available
|
|
#[cfg(feature = "cuda")]
|
|
{
|
|
if is_cuda_runtime_available() {
|
|
info!("Burn: Using CUDA backend");
|
|
return BurnBackend::Cuda;
|
|
}
|
|
}
|
|
|
|
// Then WGPU for cross-platform GPU
|
|
#[cfg(feature = "wgpu")]
|
|
{
|
|
info!("Burn: Using WebGPU backend");
|
|
return BurnBackend::Wgpu;
|
|
}
|
|
|
|
// Then tch if available
|
|
#[cfg(feature = "tch")]
|
|
{
|
|
info!("Burn: Using PyTorch (tch) backend");
|
|
return BurnBackend::Tch;
|
|
}
|
|
|
|
// Fall back to ndarray
|
|
info!("Burn: Using NdArray (CPU) backend");
|
|
BurnBackend::NdArray
|
|
}
|
|
|
|
/// Check if CUDA runtime is available
|
|
fn is_cuda_runtime_available() -> bool {
|
|
#[cfg(feature = "cuda")]
|
|
{
|
|
// Check for CUDA environment
|
|
std::env::var("CUDA_VISIBLE_DEVICES").is_ok()
|
|
|| std::path::Path::new("/usr/local/cuda").exists()
|
|
}
|
|
#[cfg(not(feature = "cuda"))]
|
|
{
|
|
false
|
|
}
|
|
}
|
|
|
|
/// Backend configuration options
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct BackendConfig {
|
|
/// Selected backend
|
|
pub backend: BurnBackend,
|
|
/// Device index (for multi-GPU)
|
|
pub device_index: usize,
|
|
/// Enable memory optimizations
|
|
pub memory_efficient: bool,
|
|
/// Seed for reproducibility
|
|
pub seed: Option<u64>,
|
|
}
|
|
|
|
impl Default for BackendConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
backend: detect_best_backend(),
|
|
device_index: 0,
|
|
memory_efficient: true,
|
|
seed: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BackendConfig {
|
|
/// Create config with specific backend
|
|
pub fn with_backend(mut self, backend: BurnBackend) -> Self {
|
|
self.backend = backend;
|
|
self
|
|
}
|
|
|
|
/// Set device index
|
|
pub fn with_device(mut self, index: usize) -> Self {
|
|
self.device_index = index;
|
|
self
|
|
}
|
|
|
|
/// Set seed for reproducibility
|
|
pub fn with_seed(mut self, seed: u64) -> Self {
|
|
self.seed = Some(seed);
|
|
self
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_backend_name() {
|
|
assert_eq!(BurnBackend::NdArray.name(), "ndarray");
|
|
assert_eq!(BurnBackend::Wgpu.name(), "wgpu");
|
|
assert_eq!(BurnBackend::Cuda.name(), "cuda");
|
|
assert_eq!(BurnBackend::Tch.name(), "tch");
|
|
}
|
|
|
|
#[test]
|
|
fn test_backend_is_gpu() {
|
|
assert!(!BurnBackend::NdArray.is_gpu());
|
|
assert!(BurnBackend::Wgpu.is_gpu());
|
|
assert!(BurnBackend::Cuda.is_gpu());
|
|
assert!(BurnBackend::Tch.is_gpu());
|
|
}
|
|
|
|
#[test]
|
|
fn test_detect_backend() {
|
|
let backend = detect_best_backend();
|
|
// Should always succeed
|
|
assert!(backend.name().len() > 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_backend_config() {
|
|
let config = BackendConfig::default()
|
|
.with_backend(BurnBackend::NdArray)
|
|
.with_device(1)
|
|
.with_seed(42);
|
|
|
|
assert_eq!(config.backend, BurnBackend::NdArray);
|
|
assert_eq!(config.device_index, 1);
|
|
assert_eq!(config.seed, Some(42));
|
|
}
|
|
}
|