incremental_rs/
monitoring.rs1use crate::error::IncrementalError;
2use crate::IncrementalSupervisedEstimator;
3use ndarray::{Array1, Array2};
4
5#[derive(Debug, Clone, Copy)]
7pub struct BatchStats {
8 pub step: usize,
9 pub loss: f64,
10 pub learning_rate: Option<f64>,
11}
12
13pub struct MonitoredEstimator<'a, E: IncrementalSupervisedEstimator, F>
15where
16 F: FnMut(BatchStats),
17{
18 pub estimator: &'a mut E,
19 pub callback: F,
20 pub step_counter: usize,
21}
22
23impl<'a, E: IncrementalSupervisedEstimator, F> MonitoredEstimator<'a, E, F>
24where
25 F: FnMut(BatchStats),
26{
27 pub fn new(estimator: &'a mut E, callback: F) -> Self {
28 Self {
29 estimator,
30 callback,
31 step_counter: 0,
32 }
33 }
34
35 fn calculate_mse(y_true: &Array1<f64>, y_pred: &Array1<f64>) -> f64 {
37 if y_true.is_empty() {
38 return 0.0;
39 }
40 y_true
41 .iter()
42 .zip(y_pred.iter())
43 .map(|(t, p)| (t - p).powi(2))
44 .sum::<f64>()
45 / (y_true.len() as f64)
46 }
47}
48
49impl<'a, E: IncrementalSupervisedEstimator, F> IncrementalSupervisedEstimator
50 for MonitoredEstimator<'a, E, F>
51where
52 F: FnMut(BatchStats),
53{
54 fn partial_fit(
55 &mut self,
56 batch_x: &Array2<f64>,
57 batch_y: &Array1<f64>,
58 ) -> Result<(), IncrementalError> {
59 let predictions = self.estimator.predict(batch_x).unwrap_or_default();
61 let loss = Self::calculate_mse(batch_y, &predictions);
62
63 self.estimator.partial_fit(batch_x, batch_y)?;
65
66 (self.callback)(BatchStats {
68 step: self.step_counter,
69 loss,
70 learning_rate: None,
71 });
72
73 self.step_counter += 1;
74 Ok(())
75 }
76
77 fn predict(&self, x: &Array2<f64>) -> Result<Array1<f64>, IncrementalError> {
78 self.estimator.predict(x)
79 }
80}