//! Advanced Normalization Techniques Demo //! //! This example demonstrates the comprehensive normalization framework //! implemented in RTX-Transformers, showcasing all available normalization //! techniques and their use cases. use rtx_tensor::{Device, Shape, Tensor}; use rtx_transformers::{ Result, layers::{ AdaLayerNorm, DeepNorm, DeepNormConfig, // Layer trait Layer, // Individual normalization types LayerNorm, // Position wrappers NormPosition, NormWrapper, NormalizationConfig, // Unified framework NormalizationType, PostNorm, PowerNorm, PreNorm, RMSNorm, ScaleNorm, UnifiedNorm, normalization_factory, power_norm_presets, }, }; use tracing::{Level, info, warn}; #[tokio::main] async fn main() -> Result<()> { // Initialize logging tracing_subscriber::fmt().with_max_level(Level::INFO).init(); info!("šŸš€ RTX Advanced Normalization Techniques Demo"); // Setup device let device = Device::cuda(0)?; let d_model = 512; let batch_size = 2; let seq_len = 8; // Create sample input tensor let input = Tensor::randn(Shape::new(vec![batch_size, seq_len, d_model])?, &device)?; info!("šŸ“Š Input tensor shape: {:?}", input.shape().dims()); // Demo 1: Individual Normalization Techniques demo_individual_norms(&input, &device).await?; // Demo 2: Unified Normalization Framework demo_unified_framework(&input, &device).await?; // Demo 3: PreNorm vs PostNorm Configurations demo_norm_positions(&input, &device).await?; // Demo 4: DeepNorm for Very Deep Networks demo_deep_norm(&input, &device).await?; // Demo 5: Adaptive Normalization with Conditioning demo_adaptive_norm(&input, &device).await?; // Demo 6: Performance Comparison demo_performance_comparison(&input, &device).await?; info!("āœ… Demo completed successfully!"); Ok(()) } /// Demonstrate individual normalization techniques async fn demo_individual_norms(input: &Tensor, device: &Device) -> Result<()> { info!("\nšŸ”¬ Demo 1: Individual Normalization Techniques"); let d_model = input.shape().dims()[2]; // 1. Standard LayerNorm info!(" Testing LayerNorm..."); let layer_norm = LayerNorm::new(d_model, 1e-5, true, device)?; let ln_output = layer_norm.forward(input)?; info!(" LayerNorm output shape: {:?}", ln_output.shape().dims()); // 2. RMSNorm (used in modern LLMs) info!(" Testing RMSNorm..."); let rms_norm = RMSNorm::new(d_model, 1e-6, device)?; let rms_output = rms_norm.forward(input)?; info!(" RMSNorm output shape: {:?}", rms_output.shape().dims()); // 3. ScaleNorm (efficient alternative) info!(" Testing ScaleNorm..."); let scale_norm = ScaleNorm::new(d_model, 1e-8, device)?; let scale_output = scale_norm.forward(input)?; info!( " ScaleNorm output shape: {:?}", scale_output.shape().dims() ); // 4. PowerNorm variants info!(" Testing PowerNorm variants..."); // L1 norm (Manhattan) let l1_norm = power_norm_presets::manhattan_norm(d_model, device)?; let l1_output = l1_norm.forward(input)?; info!(" L1 norm output shape: {:?}", l1_output.shape().dims()); // L2 norm (Euclidean, equivalent to RMSNorm) let l2_norm = power_norm_presets::euclidean_norm(d_model, device)?; let l2_output = l2_norm.forward(input)?; info!(" L2 norm output shape: {:?}", l2_output.shape().dims()); // Max norm (Lāˆž) let max_norm = power_norm_presets::max_norm(d_model, device)?; let max_output = max_norm.forward(input)?; info!(" Max norm output shape: {:?}", max_output.shape().dims()); Ok(()) } /// Demonstrate unified normalization framework async fn demo_unified_framework(input: &Tensor, device: &Device) -> Result<()> { info!("\nšŸŽÆ Demo 2: Unified Normalization Framework"); let d_model = input.shape().dims()[2]; // Create different normalization configurations let configs = vec![ ( "Standard LayerNorm", normalization_factory::layer_norm(d_model), ), ("Modern RMSNorm", normalization_factory::rms_norm(d_model)), ( "Efficient ScaleNorm", normalization_factory::scale_norm(d_model), ), ("L2 Normalization", normalization_factory::l2_norm(d_model)), ( "Custom Power Norm", normalization_factory::power_norm(d_model, 1.5), ), ]; for (name, config) in configs { info!(" Testing {}...", name); let config = config.with_device(0); match UnifiedNorm::from_config(&config) { Ok(norm) => { let output = norm.forward(input)?; info!( " {} - Type: {}, Shape: {:?}, Complexity: {:.2}x", name, norm.norm_type(), output.shape().dims(), config.norm_type.relative_complexity() ); info!(" Use case: {}", config.norm_type.recommended_use_cases()); } Err(e) => warn!(" Failed to create {}: {}", name, e), } } Ok(()) } /// Demonstrate PreNorm vs PostNorm configurations async fn demo_norm_positions(input: &Tensor, device: &Device) -> Result<()> { info!("\nšŸ“ Demo 3: PreNorm vs PostNorm Configurations"); let d_model = input.shape().dims()[2]; // Create a simple mock sublayer for demonstration #[derive(Debug)] struct MockSublayer { device: Device, } impl Layer for MockSublayer { fn forward(&self, input: &Tensor) -> Result { // Simple identity + small perturbation let perturbation = Tensor::randn(input.shape().clone(), &self.device)? * 0.1; Ok((input + &perturbation)?) } fn layer_type(&self) -> &'static str { "MockSublayer" } fn device(&self) -> &Device { &self.device } fn parameters(&self) -> Vec<&Tensor> { vec![] } fn parameters_mut(&mut self) -> Vec<&mut Tensor> { vec![] } } let sublayer = MockSublayer { device: device.clone(), }; // Test PreNorm configuration info!(" Testing PreNorm (Norm -> Sublayer -> Residual)..."); let norm_pre = RMSNorm::new(d_model, 1e-6, device)?; let prenorm_block = PreNorm::new(norm_pre, sublayer); let prenorm_output = prenorm_block.forward(input)?; info!( " PreNorm output shape: {:?}", prenorm_output.shape().dims() ); // Test PostNorm configuration info!(" Testing PostNorm (Sublayer -> Residual -> Norm)..."); let norm_post = RMSNorm::new(d_model, 1e-6, device)?; let sublayer2 = MockSublayer { device: device.clone(), }; let postnorm_block = PostNorm::new(norm_post, sublayer2); let postnorm_output = postnorm_block.forward(input)?; info!( " PostNorm output shape: {:?}", postnorm_output.shape().dims() ); // Test generic wrapper info!(" Testing NormWrapper with different positions..."); for position in [NormPosition::Pre, NormPosition::Post] { let norm = RMSNorm::new(d_model, 1e-6, device)?; let sublayer = MockSublayer { device: device.clone(), }; let wrapper = NormWrapper::new(position, norm, sublayer); let output = wrapper.forward(input)?; info!( " {:?} wrapper output shape: {:?}", position, output.shape().dims() ); } Ok(()) } /// Demonstrate DeepNorm for very deep networks async fn demo_deep_norm(input: &Tensor, device: &Device) -> Result<()> { info!("\nšŸ—ļø Demo 4: DeepNorm for Very Deep Networks"); let d_model = input.shape().dims()[2]; // Test different network depths let depths = vec![10, 100, 1000]; for num_layers in depths { info!(" Testing DeepNorm for {} layers...", num_layers); let config = DeepNormConfig::new(num_layers, d_model); let deep_norm = DeepNorm::new(config, device)?; info!(" Alpha (residual scaling): {:.4}", deep_norm.alpha()); info!(" Beta (init scaling): {:.4}", deep_norm.beta()); let output = deep_norm.forward(input)?; info!( " DeepNorm-{} output shape: {:?}", num_layers, output.shape().dims() ); // Demonstrate residual connection scaling let sublayer_output = input * 0.1; // Mock sublayer output let residual_output = deep_norm.forward_residual(input, &sublayer_output)?; info!( " Residual output shape: {:?}", residual_output.shape().dims() ); } Ok(()) } /// Demonstrate adaptive normalization with conditioning async fn demo_adaptive_norm(input: &Tensor, device: &Device) -> Result<()> { info!("\nšŸŽ›ļø Demo 5: Adaptive Normalization with Conditioning"); let d_model = input.shape().dims()[2]; let condition_dim = 128; let batch_size = input.shape().dims()[0]; let seq_len = input.shape().dims()[1]; // Create conditioning input let condition = Tensor::randn( Shape::new(vec![batch_size, seq_len, condition_dim])?, device, )?; info!(" Testing AdaLayerNorm with conditioning..."); let ada_norm = AdaLayerNorm::new(d_model, condition_dim, 1e-5, device)?; // Test with conditioning let conditioned_output = ada_norm.forward_conditioned(input, &condition)?; info!( " Conditioned output shape: {:?}", conditioned_output.shape().dims() ); // Test without conditioning (fallback) let unconditioned_output = ada_norm.forward(input)?; info!( " Unconditioned output shape: {:?}", unconditioned_output.shape().dims() ); // Test through unified framework let config = normalization_factory::ada_layer_norm(d_model, condition_dim).with_device(0); match UnifiedNorm::from_config(&config) { Ok(unified_norm) => { let unified_output = unified_norm.forward_conditioned(input, Some(&condition))?; info!( " Unified AdaLayerNorm output shape: {:?}", unified_output.shape().dims() ); } Err(e) => warn!(" Failed to create unified AdaLayerNorm: {}", e), } Ok(()) } /// Demonstrate performance comparison between different norms async fn demo_performance_comparison(input: &Tensor, device: &Device) -> Result<()> { info!("\n⚔ Demo 6: Performance and Complexity Comparison"); let d_model = input.shape().dims()[2]; let norm_types = vec![ NormalizationType::LayerNorm { elementwise_affine: true, }, NormalizationType::RMSNorm, NormalizationType::ScaleNorm, NormalizationType::L1Norm, NormalizationType::L2Norm, NormalizationType::MaxNorm, NormalizationType::PowerNorm { power: 1.5 }, ]; info!(" Normalization Performance Summary:"); info!( " {:20} | {:12} | {:8} | {}", "Type", "Complexity", "Cond.", "Use Case" ); info!(" {:-<20} | {:-<12} | {:-<8} | {}", "", "", "", ""); for norm_type in norm_types { let complexity = norm_type.relative_complexity(); let conditioning = if norm_type.requires_conditioning() { "Yes" } else { "No" }; let use_case = norm_type.recommended_use_cases(); info!( " {:20} | {:8.2}x | {:8} | {}", format!("{:?}", norm_type) .split('{') .next() .unwrap_or("Unknown"), complexity, conditioning, use_case.split(',').next().unwrap_or(use_case) ); } // Test actual forward passes for timing (simplified) info!("\n Testing forward pass execution..."); let configs = vec![ ("LayerNorm", normalization_factory::layer_norm(d_model)), ("RMSNorm", normalization_factory::rms_norm(d_model)), ("ScaleNorm", normalization_factory::scale_norm(d_model)), ]; for (name, config) in configs { let config = config.with_device(0); if let Ok(norm) = UnifiedNorm::from_config(&config) { // Simple timing test (not precise but illustrative) let start = std::time::Instant::now(); for _ in 0..10 { let _ = norm.forward(input)?; } let duration = start.elapsed(); info!(" {} - 10 iterations: {:?}", name, duration); } } Ok(()) } /// Helper function to show tensor statistics (for debugging/analysis) #[allow(dead_code)] fn show_tensor_stats(tensor: &Tensor, name: &str) -> Result<()> { let data = tensor.to_vec()?; let mean = data.iter().sum::() / data.len() as f32; let variance = data.iter().map(|x| (x - mean).powi(2)).sum::() / data.len() as f32; let std_dev = variance.sqrt(); let min_val = data.iter().fold(f32::INFINITY, |a, &b| a.min(b)); let max_val = data.iter().fold(f32::NEG_INFINITY, |a, &b| a.max(b)); info!( " {} stats: mean={:.6}, std={:.6}, min={:.6}, max={:.6}", name, mean, std_dev, min_val, max_val ); Ok(()) }