Skip to main content

trustformers_debug/gradient_debugger/
debugger.rs

1//! Main Gradient Debugger Implementation
2//!
3//! This module provides the main GradientDebugger that orchestrates all gradient
4//! debugging capabilities including monitoring, anomaly detection, performance tracking,
5//! conflict analysis, visualization, and enhanced analysis.
6// reason: debug/profiling scaffolding — structs are constructed and their fields/methods
7// are retained for the data model, serialization completeness, and future consumers that
8// do not yet read every member. Consolidated from many item-level #[allow(dead_code)].
9#![allow(dead_code)]
10
11use super::anomaly_detection::*;
12use super::conflict_analysis::*;
13use super::enhanced_analysis::*;
14use super::monitoring::*;
15use super::performance_tracking::*;
16use super::types::*;
17use super::visualization::*;
18use crate::DebugConfig;
19use anyhow::Result;
20use serde::{Deserialize, Serialize};
21use std::collections::HashMap;
22
23/// Flow analysis for gradient flow patterns
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct FlowAnalysis {
26    pub layer_analyses: HashMap<String, LayerFlowAnalysis>,
27}
28
29/// Analysis of gradient flow for a specific layer
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct LayerFlowAnalysis {
32    pub layer_name: String,
33    pub is_vanishing: bool,
34    pub is_exploding: bool,
35    pub gradient_norm: f64,
36    pub flow_consistency: f64,
37}
38
39/// Main gradient debugger
40#[derive(Debug)]
41pub struct GradientDebugger {
42    config: DebugConfig,
43    gradient_config: GradientDebugConfig,
44    gradient_histories: HashMap<String, GradientHistory>,
45    current_step: usize,
46    alerts: Vec<GradientAlert>,
47    layer_no_gradient_count: HashMap<String, usize>,
48
49    // Advanced features
50    adaptive_thresholds: HashMap<String, AdaptiveThresholds>,
51    real_time_monitors: HashMap<String, RealTimeGradientMonitor>,
52    anomaly_detector: GradientAnomalyDetector,
53    performance_tracker: GradientPerformanceTracker,
54    conflict_analyzer: GradientConflictAnalyzer,
55    flow_visualizer: GradientFlowVisualizer,
56    enhanced_analyzer: EnhancedGradientAnalyzer,
57}
58
59impl GradientDebugger {
60    /// Create a new gradient debugger
61    pub fn new(config: DebugConfig) -> Self {
62        let gradient_config = GradientDebugConfig::default();
63
64        Self {
65            config,
66            gradient_config: gradient_config.clone(),
67            gradient_histories: HashMap::new(),
68            current_step: 0,
69            alerts: Vec::new(),
70            layer_no_gradient_count: HashMap::new(),
71            adaptive_thresholds: HashMap::new(),
72            real_time_monitors: HashMap::new(),
73            anomaly_detector: GradientAnomalyDetector::default(),
74            performance_tracker: GradientPerformanceTracker::default(),
75            conflict_analyzer: GradientConflictAnalyzer::default(),
76            flow_visualizer: GradientFlowVisualizer::default(),
77            enhanced_analyzer: EnhancedGradientAnalyzer::default(),
78        }
79    }
80
81    /// Create with custom gradient configuration
82    pub fn with_gradient_config(config: DebugConfig, gradient_config: GradientDebugConfig) -> Self {
83        Self {
84            config,
85            gradient_config: gradient_config.clone(),
86            gradient_histories: HashMap::new(),
87            current_step: 0,
88            alerts: Vec::new(),
89            layer_no_gradient_count: HashMap::new(),
90            adaptive_thresholds: HashMap::new(),
91            real_time_monitors: HashMap::new(),
92            anomaly_detector: GradientAnomalyDetector::default(),
93            performance_tracker: GradientPerformanceTracker::default(),
94            conflict_analyzer: GradientConflictAnalyzer::default(),
95            flow_visualizer: GradientFlowVisualizer::default(),
96            enhanced_analyzer: EnhancedGradientAnalyzer::default(),
97        }
98    }
99
100    /// Record gradient flow for a layer
101    pub fn record_gradient_flow(
102        &mut self,
103        layer_name: &str,
104        gradient_norm: f64,
105        gradient_mean: f64,
106        gradient_std: f64,
107    ) -> Result<()> {
108        let flow = GradientFlow {
109            layer_name: layer_name.to_string(),
110            step: self.current_step,
111            gradient_norm,
112            gradient_mean,
113            gradient_std,
114            gradient_max: gradient_mean + gradient_std,
115            gradient_min: gradient_mean - gradient_std,
116            dead_neurons_ratio: self.estimate_dead_neurons_ratio(gradient_norm),
117            active_neurons_ratio: 1.0 - self.estimate_dead_neurons_ratio(gradient_norm),
118            timestamp: chrono::Utc::now(),
119        };
120
121        // Update gradient history
122        {
123            let history = self
124                .gradient_histories
125                .entry(layer_name.to_string())
126                .or_insert_with(|| GradientHistory::new(layer_name.to_string(), 1000));
127            history.add_gradient_flow(&flow);
128        }
129
130        // Update adaptive thresholds
131        let thresholds =
132            self.adaptive_thresholds.entry(layer_name.to_string()).or_insert_with(|| {
133                AdaptiveThresholds::new(
134                    layer_name.to_string(),
135                    self.gradient_config.vanishing_threshold,
136                    self.gradient_config.exploding_threshold,
137                )
138            });
139        thresholds.update_thresholds(gradient_norm);
140
141        // Update real-time monitor
142        let monitor = self
143            .real_time_monitors
144            .entry(layer_name.to_string())
145            .or_insert_with(|| RealTimeGradientMonitor::new(layer_name.to_string()));
146        monitor.update(gradient_norm);
147
148        // Check for alerts
149        self.check_gradient_alerts(layer_name, &flow)?;
150
151        // Record performance metrics
152        let timer = self.performance_tracker.start_timing(layer_name);
153        let (_, computation_time) = timer.finish();
154        self.performance_tracker
155            .record_layer_performance(layer_name, computation_time, 0); // Memory usage simplified
156
157        // Detect anomalies
158        let anomalies =
159            self.anomaly_detector
160                .detect_anomalies(layer_name, gradient_norm, self.current_step);
161        for anomaly in anomalies {
162            self.alerts.push(GradientAlert::GradientOscillation {
163                layer_name: anomaly.layer_name,
164                variance: anomaly.severity,
165            });
166        }
167
168        // Establish baseline if needed
169        if let Some(history) = self.gradient_histories.get(layer_name) {
170            if history.gradient_norms.len() == 50 {
171                let gradient_values: Vec<f64> = history.gradient_norms.iter().cloned().collect();
172                self.anomaly_detector.establish_baseline(layer_name, &gradient_values);
173            }
174        }
175
176        Ok(())
177    }
178
179    /// Get current gradient debugging status
180    pub fn get_status(&self) -> GradientDebugStatus {
181        let layer_statuses: HashMap<String, LayerGradientStatus> = self
182            .gradient_histories
183            .iter()
184            .map(|(layer_name, history)| {
185                let status = self.compute_layer_status(layer_name, history);
186                (layer_name.clone(), status)
187            })
188            .collect();
189
190        let overall_health = self.compute_overall_health(&layer_statuses);
191        let recent_alerts: Vec<GradientAlert> =
192            self.alerts.iter().rev().take(10).cloned().collect();
193
194        GradientDebugStatus {
195            current_step: self.current_step,
196            overall_health,
197            layer_statuses,
198            recent_alerts,
199            total_alerts: self.alerts.len(),
200            active_layers: self.gradient_histories.len(),
201        }
202    }
203
204    /// Generate flow analysis for report generation
205    fn generate_flow_analysis(&self) -> FlowAnalysis {
206        let mut layer_analyses = HashMap::new();
207
208        for (layer_name, history) in &self.gradient_histories {
209            let latest_gradient = history.gradient_norms.back().cloned().unwrap_or(0.0);
210
211            // Determine if gradients are vanishing or exploding
212            let is_vanishing = latest_gradient < 1e-8
213                || (history.gradient_norms.len() > 5
214                    && history.gradient_norms.iter().rev().take(5).all(|&g| g < 1e-6));
215
216            let is_exploding = latest_gradient > 100.0
217                || (history.gradient_norms.len() > 3
218                    && history.gradient_norms.iter().rev().take(3).any(|&g| g > 50.0));
219
220            // Calculate flow consistency (variance in gradient norms)
221            let flow_consistency = if history.gradient_norms.len() > 1 {
222                let mean = history.gradient_norms.iter().sum::<f64>()
223                    / history.gradient_norms.len() as f64;
224                let variance =
225                    history.gradient_norms.iter().map(|&x| (x - mean).powi(2)).sum::<f64>()
226                        / history.gradient_norms.len() as f64;
227                1.0 / (1.0 + variance) // Higher consistency = lower variance
228            } else {
229                1.0
230            };
231
232            layer_analyses.insert(
233                layer_name.clone(),
234                LayerFlowAnalysis {
235                    layer_name: layer_name.clone(),
236                    is_vanishing,
237                    is_exploding,
238                    gradient_norm: latest_gradient,
239                    flow_consistency,
240                },
241            );
242        }
243
244        FlowAnalysis { layer_analyses }
245    }
246
247    /// Generate comprehensive debugging report
248    pub fn generate_comprehensive_report(&self) -> Result<ComprehensiveGradientReport> {
249        let status = self.get_status();
250        let conflict_analysis = self.conflict_analyzer.analyze_conflicts(&self.gradient_histories);
251        let visualization = self
252            .flow_visualizer
253            .generate_visualization(&self.gradient_histories, self.current_step);
254        let enhanced_analysis =
255            self.enhanced_analyzer.generate_enhanced_analysis(&self.gradient_histories);
256        let performance_snapshot = self.performance_tracker.take_performance_snapshot();
257        let anomaly_summary = self.anomaly_detector.get_anomaly_summary(None);
258
259        let flow_analysis = self.generate_flow_analysis();
260
261        Ok(ComprehensiveGradientReport {
262            timestamp: chrono::Utc::now(),
263            status,
264            conflict_analysis,
265            visualization,
266            enhanced_analysis,
267            flow_analysis,
268            performance_snapshot,
269            anomaly_summary,
270            recommendations: self.generate_comprehensive_recommendations()?,
271        })
272    }
273
274    /// Analyze gradient conflicts between layers
275    pub fn analyze_gradient_conflicts(&self) -> GradientConflictAnalysis {
276        self.conflict_analyzer.analyze_conflicts(&self.gradient_histories)
277    }
278
279    /// Generate gradient flow visualization
280    pub fn generate_gradient_flow_visualization(&self) -> GradientFlowVisualization {
281        self.flow_visualizer
282            .generate_visualization(&self.gradient_histories, self.current_step)
283    }
284
285    /// Generate enhanced layer analysis
286    pub fn generate_enhanced_layer_analysis(&self) -> EnhancedLayerGradientAnalysis {
287        self.enhanced_analyzer.generate_enhanced_analysis(&self.gradient_histories)
288    }
289
290    /// Get performance insights
291    pub fn get_performance_insights(&self) -> PerformanceInsights {
292        let trends = self.performance_tracker.get_performance_trends();
293        let recommendations = self.performance_tracker.generate_optimization_recommendations();
294        let bottlenecks = self.performance_tracker.bottleneck_layers.clone();
295
296        PerformanceInsights {
297            trends,
298            recommendations,
299            bottlenecks,
300            current_throughput: self.performance_tracker.throughput_gradients_per_second,
301            memory_usage: self.performance_tracker.memory_usage_bytes,
302        }
303    }
304
305    /// Advance to next step
306    pub fn next_step(&mut self) {
307        self.current_step += 1;
308
309        // Clear old alerts (keep last 100)
310        if self.alerts.len() > 100 {
311            self.alerts.drain(0..self.alerts.len() - 100);
312        }
313
314        // Update no-gradient counters
315        for (layer_name, history) in &self.gradient_histories {
316            if let Some(latest_norm) = history.gradient_norms.back() {
317                if *latest_norm < 1e-8 {
318                    *self.layer_no_gradient_count.entry(layer_name.clone()).or_insert(0) += 1;
319                } else {
320                    self.layer_no_gradient_count.insert(layer_name.clone(), 0);
321                }
322            }
323        }
324
325        // Check for no-gradient alerts
326        for (layer_name, &count) in &self.layer_no_gradient_count {
327            if count >= self.gradient_config.no_gradient_steps_threshold {
328                self.alerts.push(GradientAlert::NoGradientFlow {
329                    layer_name: layer_name.clone(),
330                    steps_without_gradient: count,
331                });
332            }
333        }
334    }
335
336    /// Reset debugger state
337    pub fn reset(&mut self) {
338        self.gradient_histories.clear();
339        self.current_step = 0;
340        self.alerts.clear();
341        self.layer_no_gradient_count.clear();
342        self.adaptive_thresholds.clear();
343        self.real_time_monitors.clear();
344        self.anomaly_detector = GradientAnomalyDetector::default();
345        self.performance_tracker = GradientPerformanceTracker::default();
346    }
347
348    /// Get alerts for a specific layer
349    pub fn get_layer_alerts(&self, layer_name: &str) -> Vec<&GradientAlert> {
350        self.alerts
351            .iter()
352            .filter(|alert| match alert {
353                GradientAlert::VanishingGradients {
354                    layer_name: name, ..
355                } => name == layer_name,
356                GradientAlert::ExplodingGradients {
357                    layer_name: name, ..
358                } => name == layer_name,
359                GradientAlert::DeadNeurons {
360                    layer_name: name, ..
361                } => name == layer_name,
362                GradientAlert::GradientOscillation {
363                    layer_name: name, ..
364                } => name == layer_name,
365                GradientAlert::NoGradientFlow {
366                    layer_name: name, ..
367                } => name == layer_name,
368            })
369            .collect()
370    }
371
372    /// Get gradient history for a layer
373    pub fn get_layer_history(&self, layer_name: &str) -> Option<&GradientHistory> {
374        self.gradient_histories.get(layer_name)
375    }
376
377    /// Get all monitored layers
378    pub fn get_monitored_layers(&self) -> Vec<&String> {
379        self.gradient_histories.keys().collect()
380    }
381
382    // Private helper methods
383
384    fn estimate_dead_neurons_ratio(&self, gradient_norm: f64) -> f64 {
385        // Simplified estimation - in practice would analyze individual neuron gradients
386        if gradient_norm < 1e-6 {
387            0.9 // Assume 90% dead if very low gradient
388        } else if gradient_norm < 1e-4 {
389            0.3 // Assume 30% dead if low gradient
390        } else {
391            0.05 // Assume 5% dead for normal gradients
392        }
393    }
394
395    fn check_gradient_alerts(&mut self, layer_name: &str, flow: &GradientFlow) -> Result<()> {
396        // Check adaptive thresholds first
397        if let Some(thresholds) = self.adaptive_thresholds.get(layer_name) {
398            let threshold_alerts = thresholds.check_thresholds(flow.gradient_norm);
399            self.alerts.extend(threshold_alerts);
400        } else {
401            // Fallback to static thresholds
402            if flow.gradient_norm < self.gradient_config.vanishing_threshold {
403                self.alerts.push(GradientAlert::VanishingGradients {
404                    layer_name: layer_name.to_string(),
405                    norm: flow.gradient_norm,
406                    threshold: self.gradient_config.vanishing_threshold,
407                });
408            }
409
410            if flow.gradient_norm > self.gradient_config.exploding_threshold {
411                self.alerts.push(GradientAlert::ExplodingGradients {
412                    layer_name: layer_name.to_string(),
413                    norm: flow.gradient_norm,
414                    threshold: self.gradient_config.exploding_threshold,
415                });
416            }
417        }
418
419        // Check dead neurons
420        if flow.dead_neurons_ratio > self.gradient_config.dead_neuron_threshold {
421            self.alerts.push(GradientAlert::DeadNeurons {
422                layer_name: layer_name.to_string(),
423                ratio: flow.dead_neurons_ratio,
424                threshold: self.gradient_config.dead_neuron_threshold,
425            });
426        }
427
428        // Check oscillation
429        if let Some(monitor) = self.real_time_monitors.get(layer_name) {
430            if monitor.is_oscillating() {
431                self.alerts.push(GradientAlert::GradientOscillation {
432                    layer_name: layer_name.to_string(),
433                    variance: monitor.get_stability_score(),
434                });
435            }
436        }
437
438        Ok(())
439    }
440
441    fn compute_layer_status(
442        &self,
443        layer_name: &str,
444        history: &GradientHistory,
445    ) -> LayerGradientStatus {
446        let latest_norm = history.gradient_norms.back().cloned().unwrap_or(0.0);
447        let health = self.classify_layer_health(layer_name, history);
448        let alerts = self.get_layer_alerts(layer_name).len();
449        let trend = history.get_trend_slope().unwrap_or(0.0);
450
451        LayerGradientStatus {
452            layer_name: layer_name.to_string(),
453            health,
454            latest_gradient_norm: latest_norm,
455            gradient_trend: trend,
456            alert_count: alerts,
457            steps_recorded: history.gradient_norms.len(),
458        }
459    }
460
461    fn classify_layer_health(&self, layer_name: &str, history: &GradientHistory) -> LayerHealth {
462        let latest_norm = history.gradient_norms.back().cloned().unwrap_or(0.0);
463        let alert_count = self.get_layer_alerts(layer_name).len();
464
465        if !(1e-7..=100.0).contains(&latest_norm) || alert_count > 3 {
466            LayerHealth::Critical
467        } else if !(1e-5..=10.0).contains(&latest_norm) || alert_count > 0 {
468            LayerHealth::Warning
469        } else {
470            LayerHealth::Healthy
471        }
472    }
473
474    fn compute_overall_health(
475        &self,
476        layer_statuses: &HashMap<String, LayerGradientStatus>,
477    ) -> LayerHealth {
478        if layer_statuses.is_empty() {
479            return LayerHealth::Healthy;
480        }
481
482        let critical_count =
483            layer_statuses.values().filter(|s| s.health == LayerHealth::Critical).count();
484        let warning_count =
485            layer_statuses.values().filter(|s| s.health == LayerHealth::Warning).count();
486        let total = layer_statuses.len();
487
488        if critical_count > 0 || warning_count as f64 / total as f64 > 0.5 {
489            LayerHealth::Critical
490        } else if warning_count > 0 {
491            LayerHealth::Warning
492        } else {
493            LayerHealth::Healthy
494        }
495    }
496
497    fn generate_comprehensive_recommendations(&self) -> Result<Vec<GradientRecommendation>> {
498        let mut recommendations = Vec::new();
499
500        // Performance recommendations
501        let perf_recs = self.performance_tracker.generate_optimization_recommendations();
502        for rec in perf_recs {
503            recommendations.push(GradientRecommendation {
504                recommendation_type: RecommendationType::Performance,
505                title: rec.layer_name,
506                description: format!("{:?}: {}", rec.issue_type, rec.recommendations.join(", ")),
507                priority: match rec.severity {
508                    OptimizationSeverity::Critical => GradientRecommendationPriority::High,
509                    OptimizationSeverity::High => GradientRecommendationPriority::High,
510                    OptimizationSeverity::Medium => GradientRecommendationPriority::Medium,
511                    OptimizationSeverity::Low => GradientRecommendationPriority::Low,
512                },
513                expected_impact: rec.expected_improvement,
514            });
515        }
516
517        // Conflict recommendations
518        let conflict_analysis = self.conflict_analyzer.analyze_conflicts(&self.gradient_histories);
519        for strategy in conflict_analysis.mitigation_strategies {
520            recommendations.push(GradientRecommendation {
521                recommendation_type: RecommendationType::Conflict,
522                title: strategy.strategy_name,
523                description: strategy.description,
524                priority: match strategy.implementation_complexity {
525                    MitigationComplexity::Simple => GradientRecommendationPriority::High,
526                    MitigationComplexity::Moderate => GradientRecommendationPriority::Medium,
527                    MitigationComplexity::Complex => GradientRecommendationPriority::Medium,
528                    MitigationComplexity::RequiresArchitectureChange => {
529                        GradientRecommendationPriority::Low
530                    },
531                },
532                expected_impact: strategy.effectiveness,
533            });
534        }
535
536        // Anomaly recommendations
537        let anomaly_summary = self.anomaly_detector.get_anomaly_summary(None);
538        for rec_text in anomaly_summary.recommendations {
539            recommendations.push(GradientRecommendation {
540                recommendation_type: RecommendationType::Anomaly,
541                title: "Anomaly Mitigation".to_string(),
542                description: rec_text,
543                priority: if anomaly_summary.average_severity > 0.7 {
544                    GradientRecommendationPriority::High
545                } else {
546                    GradientRecommendationPriority::Medium
547                },
548                expected_impact: 1.0 - anomaly_summary.average_severity,
549            });
550        }
551
552        // Sort by priority and expected impact
553        recommendations.sort_by(|a, b| {
554            let priority_cmp = b.priority.cmp(&a.priority);
555            if priority_cmp == std::cmp::Ordering::Equal {
556                b.expected_impact
557                    .partial_cmp(&a.expected_impact)
558                    .unwrap_or(std::cmp::Ordering::Equal)
559            } else {
560                priority_cmp
561            }
562        });
563
564        Ok(recommendations)
565    }
566
567    /// Generate recommendations based on current analysis
568    pub fn generate_recommendations(&self) -> Result<Vec<GradientRecommendation>> {
569        self.generate_comprehensive_recommendations()
570    }
571
572    /// Start the gradient debugger
573    pub async fn start(&mut self) -> Result<()> {
574        // Initialize monitoring systems
575        self.performance_tracker.start_monitoring();
576
577        // Reset state for a new debugging session
578        self.current_step = 0;
579        self.alerts.clear();
580
581        // Initialize adaptive thresholds for existing histories
582        for (layer_name, history) in &self.gradient_histories {
583            if !history.gradient_norms.is_empty() {
584                let thresholds = AdaptiveThresholds::from_history(history);
585                self.adaptive_thresholds.insert(layer_name.clone(), thresholds);
586            }
587        }
588
589        Ok(())
590    }
591
592    /// Generate comprehensive gradient report
593    pub async fn generate_report(&self) -> Result<ComprehensiveGradientReport> {
594        let status = GradientDebugStatus {
595            current_step: self.current_step,
596            overall_health: self.evaluate_overall_health(),
597            layer_statuses: self.get_layer_statuses(),
598            recent_alerts: self.alerts.iter().rev().take(10).cloned().collect(),
599            total_alerts: self.alerts.len(),
600            active_layers: self.gradient_histories.len(),
601        };
602
603        let conflict_analysis = self.conflict_analyzer.analyze_conflicts(&self.gradient_histories);
604        let visualization = self.flow_visualizer.create_visualization(&self.gradient_histories);
605        let enhanced_analysis = self.enhanced_analyzer.analyze_gradients(&self.gradient_histories);
606        let performance_snapshot = self.performance_tracker.take_performance_snapshot();
607        let anomaly_summary = self.anomaly_detector.get_anomaly_summary(None);
608        let recommendations = self.generate_recommendations().unwrap_or_default();
609
610        let flow_analysis = self.generate_flow_analysis();
611
612        Ok(ComprehensiveGradientReport {
613            timestamp: chrono::Utc::now(),
614            status,
615            conflict_analysis,
616            visualization,
617            enhanced_analysis,
618            flow_analysis,
619            performance_snapshot,
620            anomaly_summary,
621            recommendations,
622        })
623    }
624
625    /// Quick analysis for immediate insights
626    pub async fn quick_analysis(&self) -> Result<GradientQuickAnalysis> {
627        let mut problematic_layers = Vec::new();
628        let mut total_gradients = 0f64;
629        let mut active_layers = 0;
630
631        for (layer_name, history) in &self.gradient_histories {
632            if let Some(latest_norm) = history.gradient_norms.back() {
633                active_layers += 1;
634                total_gradients += latest_norm;
635
636                // Check for basic problems
637                if *latest_norm < 1e-8 {
638                    problematic_layers.push(format!("{}: Vanishing gradients", layer_name));
639                } else if *latest_norm > 100.0 {
640                    problematic_layers.push(format!("{}: Exploding gradients", layer_name));
641                }
642            }
643        }
644
645        let average_gradient =
646            if active_layers > 0 { total_gradients / active_layers as f64 } else { 0.0 };
647
648        let health_score = self.calculate_quick_health_score();
649
650        Ok(GradientQuickAnalysis {
651            overall_health: if health_score > 0.8 {
652                LayerHealth::Healthy
653            } else if health_score > 0.5 {
654                LayerHealth::Warning
655            } else {
656                LayerHealth::Critical
657            },
658            active_layers,
659            problematic_layers,
660            average_gradient_norm: average_gradient,
661            recent_alerts_count: self.alerts.len(),
662            timestamp: chrono::Utc::now(),
663        })
664    }
665
666    /// Evaluate overall gradient health
667    fn evaluate_overall_health(&self) -> LayerHealth {
668        if self.gradient_histories.is_empty() {
669            return LayerHealth::Unknown;
670        }
671
672        let mut healthy_count = 0;
673        let mut warning_count = 0;
674        let mut critical_count = 0;
675
676        for history in self.gradient_histories.values() {
677            if let Some(latest_norm) = history.gradient_norms.back() {
678                if *latest_norm < 1e-8 || *latest_norm > 100.0 {
679                    critical_count += 1;
680                } else if *latest_norm < 1e-6 || *latest_norm > 10.0 {
681                    warning_count += 1;
682                } else {
683                    healthy_count += 1;
684                }
685            }
686        }
687
688        let total = healthy_count + warning_count + critical_count;
689        let critical_ratio = critical_count as f64 / total as f64;
690        let warning_ratio = (warning_count + critical_count) as f64 / total as f64;
691
692        if critical_ratio > 0.3 {
693            LayerHealth::Critical
694        } else if warning_ratio > 0.5 {
695            LayerHealth::Warning
696        } else {
697            LayerHealth::Healthy
698        }
699    }
700
701    /// Get status for each layer
702    fn get_layer_statuses(&self) -> HashMap<String, LayerGradientStatus> {
703        let mut statuses = HashMap::new();
704
705        for (layer_name, history) in &self.gradient_histories {
706            let status = if let Some(latest_norm) = history.gradient_norms.back() {
707                LayerGradientStatus {
708                    layer_name: layer_name.clone(),
709                    latest_gradient_norm: *latest_norm,
710                    gradient_trend: self.calculate_trend_value(history),
711                    health: if *latest_norm < 1e-8 {
712                        LayerHealth::Critical
713                    } else if *latest_norm > 100.0 {
714                        LayerHealth::Critical
715                    } else if *latest_norm < 1e-6 || *latest_norm > 10.0 {
716                        LayerHealth::Warning
717                    } else {
718                        LayerHealth::Healthy
719                    },
720                    alert_count: self.get_layer_alerts(layer_name).len(),
721                    steps_recorded: history.gradient_norms.len(),
722                }
723            } else {
724                LayerGradientStatus {
725                    layer_name: layer_name.clone(),
726                    latest_gradient_norm: 0.0,
727                    gradient_trend: 0.0,
728                    health: LayerHealth::Unknown,
729                    alert_count: 0,
730                    steps_recorded: 0,
731                }
732            };
733
734            statuses.insert(layer_name.clone(), status);
735        }
736
737        statuses
738    }
739
740    /// Calculate gradient trend for a layer
741    fn calculate_trend(&self, history: &GradientHistory) -> GradientTrend {
742        if history.gradient_norms.len() < 3 {
743            return GradientTrend::Unknown;
744        }
745
746        let recent: Vec<f64> = history.gradient_norms.iter().rev().take(3).cloned().collect();
747
748        if recent[0] > recent[1] && recent[1] > recent[2] {
749            GradientTrend::Increasing
750        } else if recent[0] < recent[1] && recent[1] < recent[2] {
751            GradientTrend::Decreasing
752        } else {
753            GradientTrend::Stable
754        }
755    }
756
757    /// Calculate gradient trend as numeric value for a layer
758    fn calculate_trend_value(&self, history: &GradientHistory) -> f64 {
759        if history.gradient_norms.len() < 2 {
760            return 0.0;
761        }
762
763        let recent: Vec<f64> = history.gradient_norms.iter().rev().take(10).cloned().collect();
764        if recent.len() < 2 {
765            return 0.0;
766        }
767
768        // Calculate linear trend slope
769        let n = recent.len() as f64;
770        let sum_x = (0..recent.len()).sum::<usize>() as f64;
771        let sum_y = recent.iter().sum::<f64>();
772        let sum_xy = recent.iter().enumerate().map(|(i, &y)| i as f64 * y).sum::<f64>();
773        let sum_x2 = (0..recent.len()).map(|i| (i * i) as f64).sum::<f64>();
774
775        (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x)
776    }
777
778    /// Calculate quick health score
779    fn calculate_quick_health_score(&self) -> f64 {
780        if self.gradient_histories.is_empty() {
781            return 0.0;
782        }
783
784        let mut score = 0.0;
785        let mut count = 0;
786
787        for history in self.gradient_histories.values() {
788            if let Some(latest_norm) = history.gradient_norms.back() {
789                // Score based on gradient magnitude (ideal range: 1e-4 to 1.0)
790                let norm_score = if *latest_norm >= 1e-4 && *latest_norm <= 1.0 {
791                    1.0
792                } else if *latest_norm >= 1e-6 && *latest_norm <= 10.0 {
793                    0.7
794                } else if *latest_norm >= 1e-8 && *latest_norm <= 100.0 {
795                    0.3
796                } else {
797                    0.0
798                };
799
800                score += norm_score;
801                count += 1;
802            }
803        }
804
805        if count == 0 {
806            0.0
807        } else {
808            score / count as f64
809        }
810    }
811}
812
813/// Current gradient debugging status
814#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
815pub struct GradientDebugStatus {
816    pub current_step: usize,
817    pub overall_health: LayerHealth,
818    pub layer_statuses: HashMap<String, LayerGradientStatus>,
819    pub recent_alerts: Vec<GradientAlert>,
820    pub total_alerts: usize,
821    pub active_layers: usize,
822}
823
824/// Comprehensive gradient debugging report
825#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
826pub struct ComprehensiveGradientReport {
827    pub timestamp: chrono::DateTime<chrono::Utc>,
828    pub status: GradientDebugStatus,
829    pub conflict_analysis: GradientConflictAnalysis,
830    pub visualization: GradientFlowVisualization,
831    pub enhanced_analysis: EnhancedLayerGradientAnalysis,
832    pub flow_analysis: FlowAnalysis,
833    pub performance_snapshot: PerformanceSnapshot,
834    pub anomaly_summary: AnomalySummary,
835    pub recommendations: Vec<GradientRecommendation>,
836}
837
838impl ComprehensiveGradientReport {
839    /// Check if there are vanishing gradient issues
840    pub fn has_vanishing_gradients(&self) -> bool {
841        // Check if any layers have very small gradients
842        for layer_status in self.status.layer_statuses.values() {
843            if layer_status.latest_gradient_norm < 1e-8 {
844                return true;
845            }
846        }
847
848        // Check anomaly summary for vanishing gradient patterns
849        for anomaly in &self.anomaly_summary.anomalies {
850            if matches!(
851                anomaly.anomaly_type,
852                crate::anomaly_detector::AnomalyType::GradientVanishing
853            ) {
854                return true;
855            }
856        }
857
858        false
859    }
860
861    /// Check if there are exploding gradient issues
862    pub fn has_exploding_gradients(&self) -> bool {
863        // Check if any layers have very large gradients
864        for layer_status in self.status.layer_statuses.values() {
865            if layer_status.latest_gradient_norm > 100.0 {
866                return true;
867            }
868        }
869
870        // Check anomaly summary for exploding gradient patterns
871        for anomaly in &self.anomaly_summary.anomalies {
872            if matches!(
873                anomaly.anomaly_type,
874                crate::anomaly_detector::AnomalyType::GradientExplosion
875                    | crate::anomaly_detector::AnomalyType::NumericalInstability
876            ) {
877                return true;
878            }
879        }
880
881        false
882    }
883}
884
885/// Performance insights summary
886#[derive(Debug, Clone)]
887pub struct PerformanceInsights {
888    pub trends: PerformanceTrends,
889    pub recommendations: Vec<OptimizationRecommendation>,
890    pub bottlenecks: Vec<String>,
891    pub current_throughput: f64,
892    pub memory_usage: usize,
893}
894
895/// Gradient debugging recommendation
896#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
897pub struct GradientRecommendation {
898    pub recommendation_type: RecommendationType,
899    pub title: String,
900    pub description: String,
901    pub priority: GradientRecommendationPriority,
902    pub expected_impact: f64,
903}
904
905#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
906pub enum RecommendationType {
907    Performance,
908    Conflict,
909    Anomaly,
910    Architecture,
911    Optimization,
912}
913
914#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
915pub enum GradientRecommendationPriority {
916    Low,
917    Medium,
918    High,
919}
920
921/// Quick analysis results for immediate insights
922#[derive(Debug, Clone)]
923pub struct GradientQuickAnalysis {
924    pub overall_health: LayerHealth,
925    pub active_layers: usize,
926    pub problematic_layers: Vec<String>,
927    pub average_gradient_norm: f64,
928    pub recent_alerts_count: usize,
929    pub timestamp: chrono::DateTime<chrono::Utc>,
930}
931
932/// Status for individual layer gradients
933#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
934pub struct LayerGradientStatus {
935    pub layer_name: String,
936    pub health: LayerHealth,
937    pub latest_gradient_norm: f64,
938    pub gradient_trend: f64,
939    pub alert_count: usize,
940    pub steps_recorded: usize,
941}
942
943/// Gradient trend indicators
944#[derive(Debug, Clone, PartialEq, Eq)]
945pub enum GradientTrend {
946    Unknown,
947    Increasing,
948    Decreasing,
949    Stable,
950}