1#![allow(dead_code)]
10
11use anyhow::Result;
12use std::collections::{HashMap, VecDeque};
13
14use super::types::{
15 ConvergenceStatus, LayerActivationStats, ModelPerformanceMetrics, TrainingDynamics,
16};
17
18#[derive(Debug)]
20pub struct AutoDebugger {
21 config: AutoDebugConfig,
23 performance_history: VecDeque<ModelPerformanceMetrics>,
25 layer_history: HashMap<String, VecDeque<LayerActivationStats>>,
27 dynamics_history: VecDeque<TrainingDynamics>,
29 issue_patterns: IssuePatternDatabase,
31 session_state: DebuggingSession,
33}
34
35#[derive(Debug, Clone)]
37pub struct AutoDebugConfig {
38 pub max_history_size: usize,
40 pub min_samples_for_analysis: usize,
42 pub recommendation_confidence_threshold: f64,
44 pub enable_advanced_patterns: bool,
46 pub enable_hyperparameter_suggestions: bool,
48 pub enable_architectural_recommendations: bool,
50}
51
52#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
54pub struct DebuggingSession {
55 pub session_start: chrono::DateTime<chrono::Utc>,
57 pub identified_issues: Vec<IdentifiedIssue>,
59 pub recommendations: Vec<DebuggingRecommendation>,
61 pub session_stats: SessionStatistics,
63}
64
65#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
67pub struct IdentifiedIssue {
68 pub category: IssueCategory,
70 pub description: String,
72 pub severity: IssueSeverity,
74 pub confidence: f64,
76 pub evidence: Vec<String>,
78 pub potential_causes: Vec<String>,
80 pub identified_at: chrono::DateTime<chrono::Utc>,
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
86pub enum IssueCategory {
87 LearningRate,
89 GradientFlow,
91 Overfitting,
93 Underfitting,
95 DataQuality,
97 Architecture,
99 Memory,
101 Convergence,
103 NumericalStability,
105}
106
107#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)]
109pub enum IssueSeverity {
110 Minor,
112 Moderate,
114 Major,
116 Critical,
118}
119
120#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
122pub struct DebuggingRecommendation {
123 pub category: RecommendationCategory,
125 pub title: String,
127 pub description: String,
129 pub actions: Vec<String>,
131 pub expected_impact: String,
133 pub confidence: f64,
135 pub priority: AutoDebugRecommendationPriority,
137 pub hyperparameter_suggestions: Vec<HyperparameterSuggestion>,
139}
140
141#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
143pub enum RecommendationCategory {
144 HyperparameterTuning,
146 ArchitecturalModification,
148 DataPreprocessing,
150 TrainingStrategy,
152 DebuggingAndMonitoring,
154 ResourceOptimization,
156}
157
158#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)]
160pub enum AutoDebugRecommendationPriority {
161 Low,
163 Medium,
165 High,
167 Urgent,
169}
170
171#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
173pub struct HyperparameterSuggestion {
174 pub parameter_name: String,
176 pub current_value: Option<f64>,
178 pub suggested_value: f64,
180 pub reasoning: String,
182 pub expected_effect: String,
184}
185
186#[derive(Debug, Clone)]
188pub struct IssuePatternDatabase {
189 pub learning_rate_patterns: Vec<IssuePattern>,
191 pub gradient_patterns: Vec<IssuePattern>,
193 pub convergence_patterns: Vec<IssuePattern>,
195 pub layer_patterns: Vec<IssuePattern>,
197}
198
199#[derive(Debug, Clone)]
201pub struct IssuePattern {
202 pub name: String,
204 pub description: String,
206 pub conditions: Vec<PatternCondition>,
208 pub issue_category: IssueCategory,
210 pub confidence_weight: f64,
212 pub solutions: Vec<String>,
214}
215
216#[derive(Debug, Clone)]
218pub struct PatternCondition {
219 pub metric: String,
221 pub operator: ComparisonOperator,
223 pub threshold: f64,
225 pub consecutive_count: usize,
227}
228
229#[derive(Debug, Clone)]
231pub enum ComparisonOperator {
232 GreaterThan,
234 LessThan,
236 EqualTo,
238 Increasing,
240 Decreasing,
242 Oscillating,
244}
245
246#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
248pub struct SessionStatistics {
249 pub total_issues: usize,
251 pub issues_by_category: HashMap<IssueCategory, usize>,
253 pub total_recommendations: usize,
255 pub avg_recommendation_confidence: f64,
257 pub analysis_duration: chrono::Duration,
259}
260
261impl Default for AutoDebugConfig {
262 fn default() -> Self {
263 Self {
264 max_history_size: 1000,
265 min_samples_for_analysis: 10,
266 recommendation_confidence_threshold: 0.7,
267 enable_advanced_patterns: true,
268 enable_hyperparameter_suggestions: true,
269 enable_architectural_recommendations: true,
270 }
271 }
272}
273
274impl AutoDebugger {
275 pub fn new() -> Self {
277 Self {
278 config: AutoDebugConfig::default(),
279 performance_history: VecDeque::new(),
280 layer_history: HashMap::new(),
281 dynamics_history: VecDeque::new(),
282 issue_patterns: IssuePatternDatabase::new(),
283 session_state: DebuggingSession::new(),
284 }
285 }
286
287 pub fn with_config(config: AutoDebugConfig) -> Self {
289 Self {
290 config,
291 performance_history: VecDeque::new(),
292 layer_history: HashMap::new(),
293 dynamics_history: VecDeque::new(),
294 issue_patterns: IssuePatternDatabase::new(),
295 session_state: DebuggingSession::new(),
296 }
297 }
298
299 pub fn record_performance_metrics(&mut self, metrics: ModelPerformanceMetrics) {
301 self.performance_history.push_back(metrics);
302
303 while self.performance_history.len() > self.config.max_history_size {
304 self.performance_history.pop_front();
305 }
306 }
307
308 pub fn record_layer_stats(&mut self, stats: LayerActivationStats) {
310 let layer_name = stats.layer_name.clone();
311
312 let layer_history = self.layer_history.entry(layer_name).or_default();
313 layer_history.push_back(stats);
314
315 while layer_history.len() > self.config.max_history_size {
316 layer_history.pop_front();
317 }
318 }
319
320 pub fn record_training_dynamics(&mut self, dynamics: TrainingDynamics) {
322 self.dynamics_history.push_back(dynamics);
323
324 while self.dynamics_history.len() > self.config.max_history_size {
325 self.dynamics_history.pop_front();
326 }
327 }
328
329 pub fn perform_analysis(&mut self) -> Result<DebuggingReport> {
331 let analysis_start = chrono::Utc::now();
332
333 if self.performance_history.len() < self.config.min_samples_for_analysis {
334 return Err(anyhow::anyhow!("Insufficient data for analysis"));
335 }
336
337 self.session_state = DebuggingSession::new();
339
340 self.analyze_learning_rate_issues()?;
342 self.analyze_convergence_issues()?;
343 self.analyze_gradient_flow_issues()?;
344 self.analyze_layer_health_issues()?;
345 self.analyze_memory_issues()?;
346 self.analyze_overfitting_underfitting()?;
347
348 self.generate_recommendations()?;
350
351 self.session_state.session_stats.analysis_duration = chrono::Utc::now() - analysis_start;
353 self.update_session_statistics();
354
355 Ok(DebuggingReport {
356 session_info: self.session_state.clone(),
357 identified_issues: self.session_state.identified_issues.clone(),
358 recommendations: self.session_state.recommendations.clone(),
359 summary: self.generate_analysis_summary(),
360 })
361 }
362
363 fn analyze_learning_rate_issues(&mut self) -> Result<()> {
365 let recent_metrics: Vec<_> = self.performance_history.iter().rev().take(20).collect();
366 if recent_metrics.len() < 10 {
367 return Ok(());
368 }
369
370 let mut issues_to_add = Vec::new();
371
372 let recent_losses: Vec<f64> = recent_metrics.iter().map(|m| m.loss).collect();
374 if let Some(max_loss) = recent_losses
375 .iter()
376 .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
377 {
378 if let Some(min_loss) = recent_losses
379 .iter()
380 .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
381 {
382 if max_loss / min_loss > 10.0 {
383 issues_to_add.push(IdentifiedIssue {
384 category: IssueCategory::LearningRate,
385 description: "Learning rate too high - loss explosion detected".to_string(),
386 severity: IssueSeverity::Critical,
387 confidence: 0.9,
388 evidence: vec![
389 format!("Loss ratio: {:.2}", max_loss / min_loss),
390 "Rapid loss increase observed".to_string(),
391 ],
392 potential_causes: vec![
393 "Learning rate set too high".to_string(),
394 "Gradient clipping disabled".to_string(),
395 "Numerical instability".to_string(),
396 ],
397 identified_at: chrono::Utc::now(),
398 });
399 }
400 }
401 }
402
403 let loss_variance = self.calculate_variance(&recent_losses);
405 let recent_metrics_len = recent_metrics.len();
406 if loss_variance < 1e-6 && recent_metrics_len >= 15 {
407 issues_to_add.push(IdentifiedIssue {
408 category: IssueCategory::LearningRate,
409 description: "Learning rate too low - training stagnation".to_string(),
410 severity: IssueSeverity::Major,
411 confidence: 0.8,
412 evidence: vec![
413 format!("Loss variance: {:.2e}", loss_variance),
414 "No learning progress in recent steps".to_string(),
415 ],
416 potential_causes: vec![
417 "Learning rate set too low".to_string(),
418 "Learning rate decay too aggressive".to_string(),
419 "Model has converged".to_string(),
420 ],
421 identified_at: chrono::Utc::now(),
422 });
423 }
424
425 for issue in issues_to_add {
427 self.add_issue(issue);
428 }
429
430 Ok(())
431 }
432
433 fn analyze_convergence_issues(&mut self) -> Result<()> {
435 if let Some(latest_dynamics) = self.dynamics_history.back() {
436 match latest_dynamics.convergence_status {
437 ConvergenceStatus::Diverging => {
438 self.add_issue(IdentifiedIssue {
439 category: IssueCategory::Convergence,
440 description: "Training is diverging".to_string(),
441 severity: IssueSeverity::Critical,
442 confidence: 0.95,
443 evidence: vec!["Convergence status: Diverging".to_string()],
444 potential_causes: vec![
445 "Learning rate too high".to_string(),
446 "Gradient explosion".to_string(),
447 "Numerical instability".to_string(),
448 ],
449 identified_at: chrono::Utc::now(),
450 });
451 },
452 ConvergenceStatus::Plateau => {
453 if let Some(plateau_info) = &latest_dynamics.plateau_detection {
454 if plateau_info.duration_steps > 100 {
455 self.add_issue(IdentifiedIssue {
456 category: IssueCategory::Convergence,
457 description: "Training has plateaued".to_string(),
458 severity: IssueSeverity::Moderate,
459 confidence: 0.8,
460 evidence: vec![
461 format!(
462 "Plateau duration: {} steps",
463 plateau_info.duration_steps
464 ),
465 format!("Plateau value: {:.4}", plateau_info.plateau_value),
466 ],
467 potential_causes: vec![
468 "Learning rate too low".to_string(),
469 "Model capacity insufficient".to_string(),
470 "Local minimum reached".to_string(),
471 ],
472 identified_at: chrono::Utc::now(),
473 });
474 }
475 }
476 },
477 ConvergenceStatus::Oscillating => {
478 self.add_issue(IdentifiedIssue {
479 category: IssueCategory::NumericalStability,
480 description: "Training is oscillating".to_string(),
481 severity: IssueSeverity::Moderate,
482 confidence: 0.7,
483 evidence: vec!["Convergence status: Oscillating".to_string()],
484 potential_causes: vec![
485 "Learning rate too high".to_string(),
486 "Batch size too small".to_string(),
487 "Momentum settings suboptimal".to_string(),
488 ],
489 identified_at: chrono::Utc::now(),
490 });
491 },
492 _ => {},
493 }
494 }
495
496 Ok(())
497 }
498
499 fn analyze_gradient_flow_issues(&mut self) -> Result<()> {
501 let mut issues_to_add = Vec::new();
502
503 for (layer_name, layer_history) in &self.layer_history {
505 if let Some(latest_stats) = layer_history.back() {
506 if latest_stats.dead_neurons_ratio > 0.5 {
508 issues_to_add.push(IdentifiedIssue {
509 category: IssueCategory::GradientFlow,
510 description: format!("High dead neuron ratio in layer {}", layer_name),
511 severity: IssueSeverity::Major,
512 confidence: 0.85,
513 evidence: vec![
514 format!(
515 "Dead neurons: {:.1}%",
516 latest_stats.dead_neurons_ratio * 100.0
517 ),
518 format!("Layer: {}", layer_name),
519 ],
520 potential_causes: vec![
521 "Dying ReLU problem".to_string(),
522 "Poor weight initialization".to_string(),
523 "Learning rate too high".to_string(),
524 ],
525 identified_at: chrono::Utc::now(),
526 });
527 }
528
529 if latest_stats.saturated_neurons_ratio > 0.3 {
531 issues_to_add.push(IdentifiedIssue {
532 category: IssueCategory::GradientFlow,
533 description: format!("High activation saturation in layer {}", layer_name),
534 severity: IssueSeverity::Moderate,
535 confidence: 0.8,
536 evidence: vec![
537 format!(
538 "Saturated neurons: {:.1}%",
539 latest_stats.saturated_neurons_ratio * 100.0
540 ),
541 format!("Layer: {}", layer_name),
542 ],
543 potential_causes: vec![
544 "Vanishing gradient problem".to_string(),
545 "Poor activation function choice".to_string(),
546 "Input normalization issues".to_string(),
547 ],
548 identified_at: chrono::Utc::now(),
549 });
550 }
551 }
552 }
553
554 for issue in issues_to_add {
556 self.add_issue(issue);
557 }
558
559 Ok(())
560 }
561
562 fn analyze_layer_health_issues(&mut self) -> Result<()> {
564 let mut issues_to_add = Vec::new();
565
566 for (layer_name, layer_history) in &self.layer_history {
567 if layer_history.len() >= 5 {
568 let recent_stats: Vec<_> = layer_history.iter().rev().take(5).collect();
569
570 let variances: Vec<f64> = recent_stats.iter().map(|s| s.std_activation).collect();
572 let avg_variance = variances.iter().sum::<f64>() / variances.len() as f64;
573
574 if avg_variance < 0.01 {
575 issues_to_add.push(IdentifiedIssue {
576 category: IssueCategory::Architecture,
577 description: format!("Low activation variance in layer {}", layer_name),
578 severity: IssueSeverity::Minor,
579 confidence: 0.6,
580 evidence: vec![
581 format!("Average variance: {:.4}", avg_variance),
582 format!("Layer: {}", layer_name),
583 ],
584 potential_causes: vec![
585 "Poor weight initialization".to_string(),
586 "Input normalization too aggressive".to_string(),
587 "Activation function saturation".to_string(),
588 ],
589 identified_at: chrono::Utc::now(),
590 });
591 }
592 }
593 }
594
595 for issue in issues_to_add {
597 self.add_issue(issue);
598 }
599
600 Ok(())
601 }
602
603 fn analyze_memory_issues(&mut self) -> Result<()> {
605 if self.performance_history.len() >= 10 {
606 let recent_memory: Vec<f64> = self
607 .performance_history
608 .iter()
609 .rev()
610 .take(10)
611 .map(|m| m.memory_usage_mb)
612 .collect();
613
614 let memory_trend = self.calculate_trend(&recent_memory);
616 if memory_trend > 10.0 {
617 self.add_issue(IdentifiedIssue {
619 category: IssueCategory::Memory,
620 description: "Memory leak detected".to_string(),
621 severity: IssueSeverity::Critical,
622 confidence: 0.9,
623 evidence: vec![
624 format!("Memory growth rate: {:.2} MB/step", memory_trend),
625 "Increasing memory usage trend".to_string(),
626 ],
627 potential_causes: vec![
628 "Gradient accumulation without clearing".to_string(),
629 "Cached tensors not being released".to_string(),
630 "Memory fragmentation".to_string(),
631 ],
632 identified_at: chrono::Utc::now(),
633 });
634 }
635
636 if let Some(max_memory) = recent_memory
638 .iter()
639 .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
640 {
641 if *max_memory > 16384.0 {
642 self.add_issue(IdentifiedIssue {
644 category: IssueCategory::Memory,
645 description: "Excessive memory usage detected".to_string(),
646 severity: IssueSeverity::Major,
647 confidence: 0.8,
648 evidence: vec![
649 format!("Peak memory: {:.0} MB", max_memory),
650 "High memory consumption".to_string(),
651 ],
652 potential_causes: vec![
653 "Batch size too large".to_string(),
654 "Model too large for available memory".to_string(),
655 "Inefficient memory allocation".to_string(),
656 ],
657 identified_at: chrono::Utc::now(),
658 });
659 }
660 }
661 }
662
663 Ok(())
664 }
665
666 fn analyze_overfitting_underfitting(&mut self) -> Result<()> {
668 let mut issues_to_add = Vec::new();
669
670 if let Some(latest_dynamics) = self.dynamics_history.back() {
671 for indicator in &latest_dynamics.overfitting_indicators {
673 if let super::types::OverfittingIndicator::TrainValidationGap { gap } = indicator {
674 if *gap > 0.1 {
675 issues_to_add.push(IdentifiedIssue {
676 category: IssueCategory::Overfitting,
677 description: "Large training-validation gap detected".to_string(),
678 severity: IssueSeverity::Major,
679 confidence: 0.85,
680 evidence: vec![
681 format!("Train-validation gap: {:.3}", gap),
682 "Overfitting indicator present".to_string(),
683 ],
684 potential_causes: vec![
685 "Model complexity too high".to_string(),
686 "Insufficient regularization".to_string(),
687 "Training set too small".to_string(),
688 ],
689 identified_at: chrono::Utc::now(),
690 });
691 }
692 }
693 }
694
695 for indicator in &latest_dynamics.underfitting_indicators {
697 match indicator {
698 super::types::UnderfittingIndicator::HighTrainingLoss { loss, threshold } => {
699 issues_to_add.push(IdentifiedIssue {
700 category: IssueCategory::Underfitting,
701 description: "High training loss indicates underfitting".to_string(),
702 severity: IssueSeverity::Moderate,
703 confidence: 0.7,
704 evidence: vec![
705 format!("Training loss: {:.3}", loss),
706 format!("Threshold: {:.3}", threshold),
707 ],
708 potential_causes: vec![
709 "Model capacity too low".to_string(),
710 "Learning rate too low".to_string(),
711 "Insufficient training time".to_string(),
712 ],
713 identified_at: chrono::Utc::now(),
714 });
715 },
716 super::types::UnderfittingIndicator::SlowConvergence {
717 steps_taken,
718 expected,
719 } => {
720 issues_to_add.push(IdentifiedIssue {
721 category: IssueCategory::Underfitting,
722 description: "Slow convergence detected".to_string(),
723 severity: IssueSeverity::Minor,
724 confidence: 0.6,
725 evidence: vec![
726 format!("Steps taken: {}", steps_taken),
727 format!("Expected: {}", expected),
728 ],
729 potential_causes: vec![
730 "Learning rate too conservative".to_string(),
731 "Optimizer choice suboptimal".to_string(),
732 "Poor initialization".to_string(),
733 ],
734 identified_at: chrono::Utc::now(),
735 });
736 },
737 _ => {},
738 }
739 }
740 }
741
742 for issue in issues_to_add {
744 self.add_issue(issue);
745 }
746
747 Ok(())
748 }
749
750 fn generate_recommendations(&mut self) -> Result<()> {
752 for issue in &self.session_state.identified_issues {
753 let recommendations = self.generate_recommendations_for_issue(issue);
754 self.session_state.recommendations.extend(recommendations);
755 }
756
757 self.session_state.recommendations.sort_by(|a, b| {
759 b.priority
760 .partial_cmp(&a.priority)
761 .unwrap_or(std::cmp::Ordering::Equal)
762 .then(b.confidence.partial_cmp(&a.confidence).unwrap_or(std::cmp::Ordering::Equal))
763 });
764
765 Ok(())
766 }
767
768 fn generate_recommendations_for_issue(
770 &self,
771 issue: &IdentifiedIssue,
772 ) -> Vec<DebuggingRecommendation> {
773 match issue.category {
774 IssueCategory::LearningRate => {
775 if issue.description.contains("too high") {
776 vec![DebuggingRecommendation {
777 category: RecommendationCategory::HyperparameterTuning,
778 title: "Reduce Learning Rate".to_string(),
779 description: "Lower the learning rate to stabilize training".to_string(),
780 actions: vec![
781 "Reduce learning rate by factor of 2-10".to_string(),
782 "Enable gradient clipping".to_string(),
783 "Consider learning rate scheduling".to_string(),
784 ],
785 expected_impact: "Stabilized training with reduced loss oscillations"
786 .to_string(),
787 confidence: 0.9,
788 priority: AutoDebugRecommendationPriority::High,
789 hyperparameter_suggestions: vec![HyperparameterSuggestion {
790 parameter_name: "learning_rate".to_string(),
791 current_value: None,
792 suggested_value: 0.0001,
793 reasoning: "Reduce to prevent loss explosion".to_string(),
794 expected_effect: "More stable training".to_string(),
795 }],
796 }]
797 } else if issue.description.contains("too low") {
798 vec![DebuggingRecommendation {
799 category: RecommendationCategory::HyperparameterTuning,
800 title: "Increase Learning Rate".to_string(),
801 description: "Increase learning rate to improve convergence speed"
802 .to_string(),
803 actions: vec![
804 "Increase learning rate by factor of 2-5".to_string(),
805 "Use learning rate warmup".to_string(),
806 "Consider adaptive learning rate methods".to_string(),
807 ],
808 expected_impact: "Faster convergence and better final performance"
809 .to_string(),
810 confidence: 0.8,
811 priority: AutoDebugRecommendationPriority::Medium,
812 hyperparameter_suggestions: vec![HyperparameterSuggestion {
813 parameter_name: "learning_rate".to_string(),
814 current_value: None,
815 suggested_value: 0.001,
816 reasoning: "Increase to improve learning speed".to_string(),
817 expected_effect: "Faster convergence".to_string(),
818 }],
819 }]
820 } else {
821 Vec::new()
822 }
823 },
824 IssueCategory::Memory => {
825 vec![DebuggingRecommendation {
826 category: RecommendationCategory::ResourceOptimization,
827 title: "Optimize Memory Usage".to_string(),
828 description: "Implement memory optimization strategies".to_string(),
829 actions: vec![
830 "Reduce batch size".to_string(),
831 "Enable gradient checkpointing".to_string(),
832 "Clear cached tensors regularly".to_string(),
833 "Use mixed precision training".to_string(),
834 ],
835 expected_impact: "Reduced memory consumption and stable training".to_string(),
836 confidence: 0.85,
837 priority: AutoDebugRecommendationPriority::High,
838 hyperparameter_suggestions: vec![HyperparameterSuggestion {
839 parameter_name: "batch_size".to_string(),
840 current_value: None,
841 suggested_value: 16.0,
842 reasoning: "Reduce to lower memory usage".to_string(),
843 expected_effect: "Lower memory consumption".to_string(),
844 }],
845 }]
846 },
847 IssueCategory::Overfitting => {
848 vec![DebuggingRecommendation {
849 category: RecommendationCategory::TrainingStrategy,
850 title: "Address Overfitting".to_string(),
851 description: "Implement regularization strategies to reduce overfitting"
852 .to_string(),
853 actions: vec![
854 "Add dropout layers".to_string(),
855 "Increase weight decay".to_string(),
856 "Use data augmentation".to_string(),
857 "Reduce model complexity".to_string(),
858 "Implement early stopping".to_string(),
859 ],
860 expected_impact: "Better generalization and validation performance".to_string(),
861 confidence: 0.8,
862 priority: AutoDebugRecommendationPriority::Medium,
863 hyperparameter_suggestions: vec![HyperparameterSuggestion {
864 parameter_name: "dropout_rate".to_string(),
865 current_value: None,
866 suggested_value: 0.1,
867 reasoning: "Add regularization to reduce overfitting".to_string(),
868 expected_effect: "Better generalization".to_string(),
869 }],
870 }]
871 },
872 IssueCategory::GradientFlow => {
873 vec![DebuggingRecommendation {
874 category: RecommendationCategory::ArchitecturalModification,
875 title: "Improve Gradient Flow".to_string(),
876 description: "Address gradient flow issues in the network".to_string(),
877 actions: vec![
878 "Use different activation functions (e.g., Leaky ReLU, Swish)".to_string(),
879 "Add batch normalization".to_string(),
880 "Implement residual connections".to_string(),
881 "Adjust weight initialization".to_string(),
882 ],
883 expected_impact: "Better gradient flow and training stability".to_string(),
884 confidence: 0.75,
885 priority: AutoDebugRecommendationPriority::Medium,
886 hyperparameter_suggestions: Vec::new(),
887 }]
888 },
889 _ => Vec::new(),
890 }
891 }
892
893 fn add_issue(&mut self, issue: IdentifiedIssue) {
895 self.session_state.identified_issues.push(issue);
896 }
897
898 fn calculate_variance(&self, values: &[f64]) -> f64 {
900 if values.len() < 2 {
901 return 0.0;
902 }
903
904 let mean = values.iter().sum::<f64>() / values.len() as f64;
905 let variance =
906 values.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (values.len() - 1) as f64;
907
908 variance
909 }
910
911 fn calculate_trend(&self, values: &[f64]) -> f64 {
913 if values.len() < 2 {
914 return 0.0;
915 }
916
917 let n = values.len() as f64;
918 let x_mean = (n - 1.0) / 2.0;
919 let y_mean = values.iter().sum::<f64>() / n;
920
921 let numerator: f64 = values
922 .iter()
923 .enumerate()
924 .map(|(i, &y)| (i as f64 - x_mean) * (y - y_mean))
925 .sum();
926
927 let denominator: f64 = (0..values.len()).map(|i| (i as f64 - x_mean).powi(2)).sum();
928
929 if denominator == 0.0 {
930 0.0
931 } else {
932 numerator / denominator
933 }
934 }
935
936 fn update_session_statistics(&mut self) {
938 let mut issues_by_category = HashMap::new();
939 for issue in &self.session_state.identified_issues {
940 *issues_by_category.entry(issue.category.clone()).or_insert(0) += 1;
941 }
942
943 let avg_confidence = if self.session_state.recommendations.is_empty() {
944 0.0
945 } else {
946 self.session_state.recommendations.iter().map(|r| r.confidence).sum::<f64>()
947 / self.session_state.recommendations.len() as f64
948 };
949
950 self.session_state.session_stats = SessionStatistics {
951 total_issues: self.session_state.identified_issues.len(),
952 issues_by_category,
953 total_recommendations: self.session_state.recommendations.len(),
954 avg_recommendation_confidence: avg_confidence,
955 analysis_duration: self.session_state.session_stats.analysis_duration,
956 };
957 }
958
959 fn generate_analysis_summary(&self) -> String {
961 let critical_issues = self
962 .session_state
963 .identified_issues
964 .iter()
965 .filter(|i| i.severity == IssueSeverity::Critical)
966 .count();
967
968 let major_issues = self
969 .session_state
970 .identified_issues
971 .iter()
972 .filter(|i| i.severity == IssueSeverity::Major)
973 .count();
974
975 let high_priority_recommendations = self
976 .session_state
977 .recommendations
978 .iter()
979 .filter(|r| r.priority == AutoDebugRecommendationPriority::High)
980 .count();
981
982 format!(
983 "Auto-debugging analysis completed. Found {} critical issues, {} major issues. \
984 Generated {} recommendations with {} high-priority actions. \
985 Average recommendation confidence: {:.2}",
986 critical_issues,
987 major_issues,
988 self.session_state.recommendations.len(),
989 high_priority_recommendations,
990 self.session_state.session_stats.avg_recommendation_confidence
991 )
992 }
993}
994
995#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
997pub struct DebuggingReport {
998 pub session_info: DebuggingSession,
1000 pub identified_issues: Vec<IdentifiedIssue>,
1002 pub recommendations: Vec<DebuggingRecommendation>,
1004 pub summary: String,
1006}
1007
1008impl IssuePatternDatabase {
1009 pub fn new() -> Self {
1011 Self {
1012 learning_rate_patterns: Self::create_learning_rate_patterns(),
1013 gradient_patterns: Self::create_gradient_patterns(),
1014 convergence_patterns: Self::create_convergence_patterns(),
1015 layer_patterns: Self::create_layer_patterns(),
1016 }
1017 }
1018
1019 fn create_learning_rate_patterns() -> Vec<IssuePattern> {
1021 vec![IssuePattern {
1022 name: "Loss Explosion".to_string(),
1023 description: "Rapid increase in loss indicating learning rate too high".to_string(),
1024 conditions: vec![PatternCondition {
1025 metric: "loss".to_string(),
1026 operator: ComparisonOperator::Increasing,
1027 threshold: 2.0,
1028 consecutive_count: 3,
1029 }],
1030 issue_category: IssueCategory::LearningRate,
1031 confidence_weight: 0.9,
1032 solutions: vec![
1033 "Reduce learning rate by factor of 10".to_string(),
1034 "Enable gradient clipping".to_string(),
1035 ],
1036 }]
1037 }
1038
1039 fn create_gradient_patterns() -> Vec<IssuePattern> {
1041 vec![]
1042 }
1043
1044 fn create_convergence_patterns() -> Vec<IssuePattern> {
1046 vec![]
1047 }
1048
1049 fn create_layer_patterns() -> Vec<IssuePattern> {
1051 vec![]
1052 }
1053}
1054
1055impl DebuggingSession {
1056 fn new() -> Self {
1058 Self {
1059 session_start: chrono::Utc::now(),
1060 identified_issues: Vec::new(),
1061 recommendations: Vec::new(),
1062 session_stats: SessionStatistics {
1063 total_issues: 0,
1064 issues_by_category: HashMap::new(),
1065 total_recommendations: 0,
1066 avg_recommendation_confidence: 0.0,
1067 analysis_duration: chrono::Duration::zero(),
1068 },
1069 }
1070 }
1071}
1072
1073impl Default for AutoDebugger {
1074 fn default() -> Self {
1075 Self::new()
1076 }
1077}
1078
1079#[cfg(test)]
1080mod tests {
1081 use super::*;
1082
1083 #[test]
1084 fn test_auto_debugger_creation() {
1085 let debugger = AutoDebugger::new();
1086 assert_eq!(debugger.performance_history.len(), 0);
1087 assert_eq!(debugger.layer_history.len(), 0);
1088 }
1089
1090 #[test]
1091 fn test_issue_identification() {
1092 let mut debugger = AutoDebugger::new();
1093
1094 let issue = IdentifiedIssue {
1095 category: IssueCategory::LearningRate,
1096 description: "Test issue".to_string(),
1097 severity: IssueSeverity::Major,
1098 confidence: 0.8,
1099 evidence: vec!["Test evidence".to_string()],
1100 potential_causes: vec!["Test cause".to_string()],
1101 identified_at: chrono::Utc::now(),
1102 };
1103
1104 debugger.add_issue(issue);
1105 assert_eq!(debugger.session_state.identified_issues.len(), 1);
1106 }
1107
1108 #[test]
1109 fn test_variance_calculation() {
1110 let debugger = AutoDebugger::new();
1111 let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
1112 let variance = debugger.calculate_variance(&values);
1113 assert!(variance > 0.0);
1114 }
1115
1116 #[test]
1117 fn test_trend_calculation() {
1118 let debugger = AutoDebugger::new();
1119 let increasing_values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
1120 let trend = debugger.calculate_trend(&increasing_values);
1121 assert!(trend > 0.0);
1122 }
1123}