//! Pipeline Parallelism Demo //! //! This example demonstrates how to use the RTX Transformers Pipeline Parallelism //! implementation for distributed training of large transformer models. use rtx_tensor::{DType, Device, Tensor}; use rtx_transformers::distributed::{ ModelPartitionable, PipelineConfig, PipelineParallelism, PipelineSchedule, }; use rtx_transformers::prelude::*; use std::error::Error; /// Mock transformer model for demonstration #[derive(Debug, Clone)] struct DemoTransformerModel { layers: Vec, vocab_size: usize, hidden_dim: usize, } #[derive(Debug, Clone)] struct DemoLayer { id: usize, hidden_dim: usize, } impl DemoTransformerModel { fn new(num_layers: usize, hidden_dim: usize, vocab_size: usize) -> Self { let layers = (0..num_layers) .map(|i| DemoLayer { id: i, hidden_dim }) .collect(); Self { layers, vocab_size, hidden_dim, } } fn num_layers(&self) -> usize { self.layers.len() } } impl ModelPartitionable for DemoTransformerModel { fn num_layers(&self) -> usize { self.num_layers() } fn layer_range(&self, start: usize, end: usize) -> Result> { let layers = self.layers[start..end].to_vec(); Ok(Box::new(layers)) } } #[tokio::main] async fn main() -> Result<(), Box> { // Initialize RTX Transformers rtx_transformers::init()?; println!("šŸš€ Pipeline Parallelism Demo"); println!("===========================\n"); // 1. Create a large transformer model let model = DemoTransformerModel::new(24, 1024, 50000); // 24-layer model println!( "šŸ“Š Created demo model with {} layers, hidden_dim={}", model.num_layers(), model.hidden_dim ); // 2. Configure pipeline parallelism across 4 devices let devices = vec![Device::cuda(0).unwrap_or(Device::default()); 4]; // In practice, use GPUs let config = PipelineConfig::new() .with_devices(devices) .with_micro_batch_size(8) .with_schedule(PipelineSchedule::PipeDream1F1B) .with_gradient_accumulation_steps(4) .with_activation_checkpointing(true) .with_checkpointing_segments(2) .with_load_balancing(true) .with_fault_tolerance(true) .with_memory_limit_mb(2048); // 2GB per stage println!("āš™ļø Pipeline Configuration:"); println!( " - {} stages across {} devices", config.num_stages(), config.num_stages() ); println!(" - Micro-batch size: {}", config.micro_batch_size()); println!(" - Schedule: {:?}", config.schedule()); println!( " - Gradient accumulation: {} steps", config.gradient_accumulation_steps() ); println!( " - Activation checkpointing: {}", config.activation_checkpointing_enabled() ); // 3. Initialize pipeline parallelism println!("\nšŸ”§ Initializing Pipeline Parallelism..."); let mut pipeline = PipelineParallelism::new(config, model).await?; // 4. Integrate with existing training infrastructure let gradient_accumulator = GradientAccumulator::new(4, true); let mixed_precision_trainer = MixedPrecisionTrainer::new(DType::F16, LossScalingStrategy::default(), true)?; let pipeline = pipeline .with_gradient_accumulator(gradient_accumulator)? .with_mixed_precision(mixed_precision_trainer)?; println!( "āœ… Pipeline initialized with {} stages", pipeline.num_stages() ); println!( " - Gradient accumulation: {}", pipeline.has_gradient_accumulator() ); println!(" - Mixed precision: {}", pipeline.has_mixed_precision()); // 5. Demonstrate training workflow println!("\nšŸŽÆ Starting Training Simulation..."); // Set training mode let mut training_pipeline = pipeline; training_pipeline.set_training_mode(true); // Create sample training data let batch_size = 32; let sequence_length = 512; let input = Tensor::randn(&[batch_size, sequence_length], DType::F32)?; let targets = Tensor::randn(&[batch_size, sequence_length], DType::F32)?; println!( "šŸ“¦ Training data: batch_size={}, sequence_length={}", batch_size, sequence_length ); // Run several training steps for step in 1..=5 { println!("\nšŸ“ˆ Training Step {}/5", step); let start_time = std::time::Instant::now(); let result = training_pipeline.training_step(&input, &targets).await?; let elapsed = start_time.elapsed(); println!(" āœ… Loss: {:.6}", result.loss()); println!( " ⚔ Processed {} micro-batches", result.num_micro_batches() ); println!(" ā±ļø Step time: {:.2}ms", elapsed.as_millis()); println!( " 🧠 Used mixed precision: {}", result.used_mixed_precision() ); println!( " šŸ”„ Used gradient accumulation: {}", result.used_gradient_accumulation() ); } // 6. Show comprehensive metrics println!("\nšŸ“Š Final Pipeline Metrics:"); let metrics = training_pipeline.get_metrics(); println!(" Throughput:"); println!( " - Average: {:.2} samples/sec", metrics.samples_per_second() ); println!(" - Peak throughput: {:.2}", metrics.peak_throughput()); println!(" Efficiency:"); println!( " - Pipeline efficiency: {:.1}%", metrics.pipeline_efficiency() * 100.0 ); println!( " - Bubble time ratio: {:.1}%", metrics.bubble_time_ratio() * 100.0 ); println!(" Memory:"); println!( " - Peak memory usage: {:.1} MB", metrics.peak_memory_usage() as f64 / (1024.0 * 1024.0) ); println!( " - Activation checkpointing: {}", metrics.has_activation_checkpoints() ); println!(" Training:"); println!(" - Total steps: {}", metrics.total_training_steps()); println!( " - Total micro-batches: {}", metrics.total_micro_batches() ); // 7. Demonstrate fault tolerance println!("\nšŸ›”ļø Testing Fault Tolerance..."); training_pipeline.inject_stage_failure(1).await?; let recovery_stats = training_pipeline.get_recovery_stats(); println!( " āœ… Recovered from {} failures in {:.2}ms", recovery_stats.total_failures(), recovery_stats.recovery_time().as_millis() ); // 8. Show load balancing info println!("\nāš–ļø Load Balancing Statistics:"); let load_balancer = training_pipeline.load_balancer(); let balance_stats = load_balancer.get_balance_statistics(); println!(" - Balanced: {}", balance_stats.is_balanced()); println!( " - Max stage time: {:.2}ms", balance_stats.max_stage_time().as_millis() ); println!( " - Min stage time: {:.2}ms", balance_stats.min_stage_time().as_millis() ); // 9. Clean shutdown println!("\nšŸ”„ Shutting down pipeline..."); training_pipeline.shutdown().await?; println!("\nšŸŽ‰ Pipeline Parallelism Demo Completed Successfully!"); println!("\nšŸ“ˆ Summary of Capabilities Demonstrated:"); println!(" āœ… Multi-stage pipeline across devices"); println!(" āœ… PipeDream 1F1B scheduling for efficiency"); println!(" āœ… Micro-batch processing for memory efficiency"); println!(" āœ… Gradient accumulation and synchronization"); println!(" āœ… Activation checkpointing for large models"); println!(" āœ… Mixed precision training integration"); println!(" āœ… Load balancing across stages"); println!(" āœ… Fault tolerance and automatic recovery"); println!(" āœ… Comprehensive metrics and monitoring"); println!(" āœ… Clean resource management"); Ok(()) } /// Additional helper to show configuration options fn show_advanced_configurations() { println!("\nšŸ”§ Advanced Configuration Options:"); // GPipe configuration for maximum throughput let _gpipe_config = PipelineConfig::new() .with_schedule(PipelineSchedule::GPipe) .with_micro_batch_size(16) .with_max_outstanding_batches(8); println!(" šŸ“‹ GPipe: Fill-drain pattern, high throughput"); // Memory-constrained configuration let _memory_config = PipelineConfig::new() .with_activation_checkpointing(true) .with_gradient_compression(true) .with_memory_limit_mb(1024) .with_micro_batch_size(2); println!(" šŸ’¾ Memory-efficient: Checkpointing + compression"); // High-performance configuration let _perf_config = PipelineConfig::new() .with_schedule(PipelineSchedule::Interleaved1F1B) .with_dynamic_batching(true) .with_load_balancing(true) .with_communication_backend(rtx_transformers::distributed::CommunicationBackend::Hybrid); println!(" šŸš€ High-performance: Interleaved scheduling + dynamic batching"); }