ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
streaming_model.h
Go to the documentation of this file.
1#pragma once
2
3#ifdef USE_ESP32
4
6#include "model_data.h"
7
10
11#include <memory>
12#include <tensorflow/lite/core/c/common.h>
13#include <tensorflow/lite/micro/micro_interpreter.h>
14#include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
15
17
18static const uint8_t MIN_SLICES_BEFORE_DETECTION = 100;
19static const uint32_t STREAMING_MODEL_VARIABLE_ARENA_SIZE = 1024;
20
22 std::string *wake_word;
24 bool partially_detection; // Set if the most recent probability exceed the threshold, but the sliding window average
25 // hasn't yet
28 bool blocked_by_vad = false;
29};
30
32 public:
33 // Runtime models are heap owned and destroyed while the device is running, so freeing the arenas cannot
34 // depend on the owner calling unload_model() first. unload_model() is not virtual and is safe to repeat.
35 virtual ~StreamingModel() { this->unload_model(); }
36
37 virtual void log_model_config() = 0;
39
40 // Performs inference on the given features.
41 // - If the model is enabled but not loaded, it will load it
42 // - If the model is disabled but loaded, it will unload it
43 // Returns true if sucessful or false if there is an error
44 bool perform_streaming_inference(const int8_t features[PREPROCESSOR_FEATURE_SIZE]);
45
48
50 void unload_model();
51
53 virtual void enable() { this->enabled_ = true; }
54
56 virtual void disable() { this->enabled_ = false; }
57
59 bool is_enabled() const { return this->enabled_; }
60
62 bool has_model_data() const { return this->model_start_ != nullptr; }
63
65
66 // Quantized probability cutoffs mapping 0.0 - 1.0 to 0 - 255
68 uint8_t get_probability_cutoff() const { return this->probability_cutoff_; }
69 void set_probability_cutoff(uint8_t probability_cutoff) { this->probability_cutoff_ = probability_cutoff; }
70
71 protected:
74 bool load_model_();
78 size_t probe_arena_size_();
80 bool register_streaming_ops_(tflite::MicroMutableOpResolver<20> &op_resolver);
81
82 tflite::MicroMutableOpResolver<20> streaming_op_resolver_;
83
84 bool loaded_{false};
85 bool enabled_{true};
89 int16_t ignore_windows_{-MIN_SLICES_BEFORE_DETECTION};
90
94
95 size_t last_n_index_{0};
97 std::vector<uint8_t> recent_streaming_probabilities_;
98
99 const uint8_t *model_start_{nullptr};
100#ifdef USE_MICRO_WAKE_WORD_INTERNAL_RAM
101 size_t model_size_{0};
103#endif
104 uint8_t *tensor_arena_{nullptr};
105 uint8_t *var_arena_{nullptr};
106 std::unique_ptr<tflite::MicroInterpreter> interpreter_;
107 tflite::MicroResourceVariables *mrv_{nullptr};
108 tflite::MicroAllocator *ma_{nullptr};
109};
110
111class WakeWordModel final : public StreamingModel {
112 public:
124 WakeWordModel(const std::string &id, const uint8_t *model_start, size_t model_size,
125 uint8_t default_probability_cutoff, size_t sliding_window_average_size, const std::string &wake_word,
126 size_t tensor_arena_size, bool default_enabled, bool internal_only);
127
137 WakeWordModel(const std::string &id, std::shared_ptr<ModelData> model_data, uint8_t default_probability_cutoff,
138 size_t sliding_window_average_size, const std::string &wake_word,
139 std::vector<std::string> trained_languages, size_t tensor_arena_size);
140
141 // model_data_ is a member of this class, so it is destroyed before ~StreamingModel() runs. Unload here, while
142 // the buffer is still alive, so the interpreter is never torn down over freed model data.
143 ~WakeWordModel() override { this->unload_model(); }
144
145 void log_model_config() override;
146
151
152 const std::string &get_id() const { return this->id_; }
153 const std::string &get_wake_word() const { return this->wake_word_; }
154
155 void add_trained_language(const std::string &language) { this->trained_languages_.push_back(language); }
156 const std::vector<std::string> &get_trained_languages() const { return this->trained_languages_; }
157
159 void enable() override;
160
162 void disable() override;
163
164 bool get_internal_only() { return this->internal_only_; }
165
166 protected:
167 // Kept for runtime-downloaded models so the model buffer stays alive for the model's lifetime.
168 // Null for compiled-in models (their data lives in flash).
169 std::shared_ptr<ModelData> model_data_;
170
171 std::string id_;
172 std::string wake_word_;
173 std::vector<std::string> trained_languages_;
174
176
178};
179
180class VADModel final : public StreamingModel {
181 public:
182 VADModel(const uint8_t *model_start, size_t model_size, uint8_t default_probability_cutoff,
183 size_t sliding_window_size, size_t tensor_arena_size);
184
185 void log_model_config() override;
186
191};
192
193} // namespace esphome::micro_wake_word
194
195#endif
virtual void disable()
Disable the model. The next performing_streaming_inference call will unload it.
virtual DetectionEvent determine_detected()=0
bool load_model_()
Allocates tensor and variable arenas and sets up the model interpreter.
virtual void enable()
Enable the model. The next performing_streaming_inference call will load it.
bool has_model_data() const
Return true if the model has usable data. A model without it can never be loaded or run.
std::unique_ptr< tflite::MicroInterpreter > interpreter_
tflite::MicroMutableOpResolver< 20 > streaming_op_resolver_
bool register_streaming_ops_(tflite::MicroMutableOpResolver< 20 > &op_resolver)
Returns true if successfully registered the streaming model's TensorFlow operations.
void reset_probabilities()
Sets all recent_streaming_probabilities to 0 and resets the ignore window count.
std::vector< uint8_t > recent_streaming_probabilities_
size_t probe_arena_size_()
Probes the actual required tensor arena size by trial allocation.
tflite::MicroResourceVariables * mrv_
bool perform_streaming_inference(const int8_t features[PREPROCESSOR_FEATURE_SIZE])
void unload_model()
Destroys the TFLite interpreter and frees the tensor and variable arenas' memory.
void set_probability_cutoff(uint8_t probability_cutoff)
bool is_enabled() const
Return true if the model is enabled.
DetectionEvent determine_detected() override
Checks for voice activity by comparing the max probability in the sliding window with the probability...
VADModel(const uint8_t *model_start, size_t model_size, uint8_t default_probability_cutoff, size_t sliding_window_size, size_t tensor_arena_size)
void enable() override
Enable the model and save to flash. The next performing_streaming_inference call will load it.
const std::string & get_wake_word() const
DetectionEvent determine_detected() override
Checks for the wake word by comparing the mean probability in the sliding window with the probability...
std::shared_ptr< ModelData > model_data_
const std::vector< std::string > & get_trained_languages() const
void add_trained_language(const std::string &language)
WakeWordModel(const std::string &id, const uint8_t *model_start, size_t model_size, uint8_t default_probability_cutoff, size_t sliding_window_average_size, const std::string &wake_word, size_t tensor_arena_size, bool default_enabled, bool internal_only)
Constructs a wake word model object with compile-time model data.
void disable() override
Disable the model and save to flash. The next performing_streaming_inference call will unload it.
std::vector< std::string > trained_languages_
std::unique_ptr< T, RAMDeleter< T > > RAMUniquePtr
unique_ptr over RAMAllocator storage
Definition helpers.h:2287
static void uint32_t