1#![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#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct FlowAnalysis {
26 pub layer_analyses: HashMap<String, LayerFlowAnalysis>,
27}
28
29#[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#[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 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 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 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 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 {
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 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 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 self.check_gradient_alerts(layer_name, &flow)?;
150
151 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); 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 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 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 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 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 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) } 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 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 pub fn analyze_gradient_conflicts(&self) -> GradientConflictAnalysis {
276 self.conflict_analyzer.analyze_conflicts(&self.gradient_histories)
277 }
278
279 pub fn generate_gradient_flow_visualization(&self) -> GradientFlowVisualization {
281 self.flow_visualizer
282 .generate_visualization(&self.gradient_histories, self.current_step)
283 }
284
285 pub fn generate_enhanced_layer_analysis(&self) -> EnhancedLayerGradientAnalysis {
287 self.enhanced_analyzer.generate_enhanced_analysis(&self.gradient_histories)
288 }
289
290 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 pub fn next_step(&mut self) {
307 self.current_step += 1;
308
309 if self.alerts.len() > 100 {
311 self.alerts.drain(0..self.alerts.len() - 100);
312 }
313
314 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 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 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 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 pub fn get_layer_history(&self, layer_name: &str) -> Option<&GradientHistory> {
374 self.gradient_histories.get(layer_name)
375 }
376
377 pub fn get_monitored_layers(&self) -> Vec<&String> {
379 self.gradient_histories.keys().collect()
380 }
381
382 fn estimate_dead_neurons_ratio(&self, gradient_norm: f64) -> f64 {
385 if gradient_norm < 1e-6 {
387 0.9 } else if gradient_norm < 1e-4 {
389 0.3 } else {
391 0.05 }
393 }
394
395 fn check_gradient_alerts(&mut self, layer_name: &str, flow: &GradientFlow) -> Result<()> {
396 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 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 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 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 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 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 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 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 pub fn generate_recommendations(&self) -> Result<Vec<GradientRecommendation>> {
569 self.generate_comprehensive_recommendations()
570 }
571
572 pub async fn start(&mut self) -> Result<()> {
574 self.performance_tracker.start_monitoring();
576
577 self.current_step = 0;
579 self.alerts.clear();
580
581 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 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 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 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 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 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 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 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 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 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 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#[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#[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 pub fn has_vanishing_gradients(&self) -> bool {
841 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 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 pub fn has_exploding_gradients(&self) -> bool {
863 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 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#[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#[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#[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#[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#[derive(Debug, Clone, PartialEq, Eq)]
945pub enum GradientTrend {
946 Unknown,
947 Increasing,
948 Decreasing,
949 Stable,
950}