burn_train/evaluator/
base.rs1use crate::{
2 AsyncProcessorEvaluation, EvaluationItem, FullEventProcessorEvaluation, InferenceStep,
3 Interrupter, LearnerSummaryConfig,
4 evaluator::components::EvaluatorComponentTypes,
5 metric::processor::{EvaluatorEvent, EventProcessorEvaluation},
6 renderer::{EvaluationName, MetricsRenderer},
7};
8use burn_core::{data::dataloader::DataLoader, module::Module};
9use std::sync::Arc;
10
11pub(crate) type TestInput<EC> = <<EC as EvaluatorComponentTypes>::Model as InferenceStep>::Input;
12pub(crate) type TestOutput<EC> = <<EC as EvaluatorComponentTypes>::Model as InferenceStep>::Output;
13
14pub(crate) type TestLoader<EC> = Arc<dyn DataLoader<TestInput<EC>>>;
15
16pub struct EvaluationResult {
18 pub renderer: Box<dyn MetricsRenderer>,
20 pub interrupted: Option<crate::Interruption>,
23 pub error: Option<Arc<crate::TrainingError>>,
27}
28
29pub struct Evaluator<EC: EvaluatorComponentTypes> {
31 pub(crate) model: EC::Model,
32 pub(crate) interrupter: Interrupter,
33 pub(crate) event_processor:
34 AsyncProcessorEvaluation<FullEventProcessorEvaluation<TestOutput<EC>>>,
35 pub summary: Option<LearnerSummaryConfig>,
37}
38
39impl<EC: EvaluatorComponentTypes> Evaluator<EC> {
40 pub fn eval<S: core::fmt::Display>(
44 self,
45 name: S,
46 dataloader: TestLoader<EC>,
47 ) -> EvaluationResult {
48 self.eval_all([(name, dataloader)])
49 }
50
51 pub fn eval_all<S: core::fmt::Display>(
56 mut self,
57 splits: impl IntoIterator<Item = (S, TestLoader<EC>)>,
58 ) -> EvaluationResult {
59 let splits: Vec<_> = splits.into_iter().collect();
60 let total_tests = splits.len();
61
62 self.interrupter.fail_on_error(
63 self.event_processor
64 .process_test(EvaluatorEvent::Start { total_tests }),
65 );
66
67 for (name, dataloader) in splits {
68 let dataloader = dataloader.to_device(self.model.devices().first().unwrap());
69 let name = EvaluationName::new(name);
70 let total_items = dataloader.num_items();
71 let mut iterator = dataloader.iter();
72 let mut iteration = 0;
73
74 self.interrupter.fail_on_error(
75 self.event_processor
76 .process_test(EvaluatorEvent::StartTest(name.clone(), total_items)),
77 );
78
79 while let Some(item) = iterator.next() {
80 let item = match item {
81 Ok(item) => item,
82 Err(err) => {
83 self.interrupter.fail(err);
84 break;
85 }
86 };
87 let progress = iterator.progress();
88 iteration += 1;
89
90 let item = self.model.step(item);
91 let item = EvaluationItem::new(item, progress, Some(iteration));
92
93 self.interrupter.fail_on_error(
94 self.event_processor
95 .process_test(EvaluatorEvent::ProcessedItem(name.clone(), item)),
96 );
97
98 if self.interrupter.should_stop() {
99 log::info!("Testing interrupted.");
100 break;
101 }
102 }
103
104 self.interrupter
105 .fail_on_error(self.event_processor.process_test(EvaluatorEvent::EndTest));
106
107 if self.interrupter.should_stop() {
109 break;
110 }
111 }
112
113 let summary = self.summary.and_then(|summary| {
114 summary
115 .init()
116 .map(|summary| summary.with_model(self.model.to_string()))
117 .ok()
118 });
119
120 self.interrupter.fail_on_error(
121 self.event_processor
122 .process_test(EvaluatorEvent::End(summary)),
123 );
124
125 self.interrupter.fail_on_error(self.event_processor.flush());
127
128 EvaluationResult {
129 renderer: self.event_processor.renderer(),
130 interrupted: self.interrupter.interruption(),
131 error: self.interrupter.error(),
132 }
133 }
134}