8#ifdef USE_MICRO_WAKE_WORD_INTERNAL_RAM
9#include <esp_memory_utils.h>
19 " Probability cutoff: %.2f\n"
20 " Sliding window size: %d",
21 this->
wake_word_.c_str(), this->probability_cutoff_ / 255.0f, this->sliding_window_size_);
27 " Probability cutoff: %.2f\n"
28 " Sliding window size: %d",
34 ESP_LOGE(TAG,
"Streaming model has no data to load");
43 ESP_LOGE(TAG,
"Could not allocate the streaming model's variable tensor arena.");
46 this->
ma_ = tflite::MicroAllocator::Create(this->
var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE);
47 this->
mrv_ = tflite::MicroResourceVariables::Create(this->
ma_, 20);
50 const tflite::Model *model = tflite::GetModel(this->
model_start_);
51 if (model->version() != TFLITE_SCHEMA_VERSION) {
52 ESP_LOGE(TAG,
"Streaming model's schema is not supported");
59 if (probed_size > 0) {
60 ESP_LOGD(TAG,
"Probed tensor arena size: %zu bytes", probed_size);
63 ESP_LOGW(TAG,
"Arena size probe failed, using manifest size: %zu bytes", this->
tensor_arena_size_);
69#ifdef USE_MICRO_WAKE_WORD_INTERNAL_RAM
73 ESP_LOGW(TAG,
"Could not allocate %zu bytes of internal RAM for tensor arena; using default memory",
80 ESP_LOGE(TAG,
"Could not allocate the streaming model's tensor arena.");
85#ifdef USE_MICRO_WAKE_WORD_INTERNAL_RAM
90 ESP_LOGW(TAG,
"Could not allocate %zu bytes of internal RAM for model; using original model data",
93 std::memcpy(this->
model_copy_.get(), this->model_start_, this->model_size_);
100#ifdef USE_MICRO_WAKE_WORD_INTERNAL_RAM
107 if (this->
interpreter_->AllocateTensors() != kTfLiteOk) {
108 ESP_LOGE(TAG,
"Failed to allocate tensors for the streaming model");
115 if ((input->dims->size != 3) || (input->dims->data[0] != 1) ||
116 (input->dims->data[2] != PREPROCESSOR_FEATURE_SIZE)) {
117 ESP_LOGE(TAG,
"Streaming model tensor input dimensions has improper dimensions.");
121 if (input->type != kTfLiteInt8) {
122 ESP_LOGE(TAG,
"Streaming model tensor input is not int8.");
128 if ((output->dims->size != 2) || (output->dims->data[0] != 1) || (output->dims->data[1] != 1)) {
129 ESP_LOGE(TAG,
"Streaming model tensor output dimension is not 1x1.");
133 if (output->type != kTfLiteUInt8) {
134 ESP_LOGE(TAG,
"Streaming model tensor output is not uint8.");
154 for (
size_t attempt_size : attempt_sizes) {
155 uint8_t *probe_arena = arena_allocator.
allocate(attempt_size);
156 if (probe_arena ==
nullptr) {
161 auto probe_interpreter = make_unique<tflite::MicroInterpreter>(
164 if (probe_interpreter->AllocateTensors() != kTfLiteOk) {
165 probe_interpreter.reset();
166 arena_allocator.
deallocate(probe_arena, attempt_size);
167 this->
ma_ = tflite::MicroAllocator::Create(this->
var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE);
168 this->
mrv_ = tflite::MicroResourceVariables::Create(this->
ma_, 20);
174 size_t lower = (probe_interpreter->arena_used_bytes() + 16 + 15) & ~15;
175 probe_interpreter.reset();
176 this->
ma_ = tflite::MicroAllocator::Create(this->
var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE);
177 this->
mrv_ = tflite::MicroResourceVariables::Create(this->
ma_, 20);
179 size_t upper = attempt_size;
181 while (lower < upper) {
182 auto test_interpreter = make_unique<tflite::MicroInterpreter>(
185 bool ok = test_interpreter->AllocateTensors() == kTfLiteOk;
187 test_interpreter.reset();
188 this->
ma_ = tflite::MicroAllocator::Create(this->
var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE);
189 this->
mrv_ = tflite::MicroResourceVariables::Create(this->
ma_, 20);
198 lower = ((lower + upper) / 2 + 15) & ~15;
201 arena_allocator.
deallocate(probe_arena, attempt_size);
210#ifdef USE_MICRO_WAKE_WORD_INTERNAL_RAM
253 uint8_t stride = this->
interpreter_->input(0)->dims->data[1];
257 (int8_t *) (tflite::GetTensorData<int8_t>(input)) + PREPROCESSOR_FEATURE_SIZE * this->
current_stride_step_,
258 features, PREPROCESSOR_FEATURE_SIZE);
261 if (this->current_stride_step_ >= stride) {
262 TfLiteStatus invoke_status = this->
interpreter_->Invoke();
263 if (invoke_status != kTfLiteOk) {
264 ESP_LOGW(TAG,
"Streaming interpreter invoke failed");
293 uint8_t default_probability_cutoff,
size_t sliding_window_average_size,
294 const std::string &wake_word,
size_t tensor_arena_size,
bool default_enabled,
295 bool internal_only) {
298#ifdef USE_MICRO_WAKE_WORD_INTERNAL_RAM
323 uint8_t default_probability_cutoff,
size_t sliding_window_average_size,
324 const std::string &wake_word, std::vector<std::string> trained_languages,
325 size_t tensor_arena_size) {
332#ifdef USE_MICRO_WAKE_WORD_INTERNAL_RAM
336 ESP_LOGE(TAG,
"Model '%s' has no valid data and will not be loaded",
id.c_str());
382 return detection_event;
395 return detection_event;
399 size_t sliding_window_size,
size_t tensor_arena_size) {
401#ifdef USE_MICRO_WAKE_WORD_INTERNAL_RAM
420 return detection_event;
432 return detection_event;
436 if (op_resolver.AddCallOnce() != kTfLiteOk)
438 if (op_resolver.AddVarHandle() != kTfLiteOk)
440 if (op_resolver.AddReshape() != kTfLiteOk)
442 if (op_resolver.AddReadVariable() != kTfLiteOk)
444 if (op_resolver.AddStridedSlice() != kTfLiteOk)
446 if (op_resolver.AddConcatenation() != kTfLiteOk)
448 if (op_resolver.AddAssignVariable() != kTfLiteOk)
450 if (op_resolver.AddConv2D() != kTfLiteOk)
452 if (op_resolver.AddMul() != kTfLiteOk)
454 if (op_resolver.AddAdd() != kTfLiteOk)
456 if (op_resolver.AddMean() != kTfLiteOk)
458 if (op_resolver.AddFullyConnected() != kTfLiteOk)
460 if (op_resolver.AddLogistic() != kTfLiteOk)
462 if (op_resolver.AddQuantize() != kTfLiteOk)
464 if (op_resolver.AddDepthwiseConv2D() != kTfLiteOk)
466 if (op_resolver.AddAveragePool2D() != kTfLiteOk)
468 if (op_resolver.AddMaxPool2D() != kTfLiteOk)
470 if (op_resolver.AddPad() != kTfLiteOk)
472 if (op_resolver.AddPack() != kTfLiteOk)
474 if (op_resolver.AddSplitV() != kTfLiteOk)
An STL allocator that uses SPI or internal RAM.
void deallocate(T *p, size_t n)
RAMUniquePtr< T[]> make_unique_array_for_overwrite(size_t n)
n elements left uninitialized, as std::make_unique_for_overwrite does; empty on exhaustion,...
tflite::MicroAllocator * ma_
RAMUniquePtr< uint8_t[]> model_copy_
bool load_model_()
Allocates tensor and variable arenas and sets up the model interpreter.
uint8_t current_stride_step_
size_t sliding_window_size_
bool tensor_arena_size_probed_
std::unique_ptr< tflite::MicroInterpreter > interpreter_
uint8_t default_probability_cutoff_
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.
size_t tensor_arena_size_
std::vector< uint8_t > recent_streaming_probabilities_
size_t probe_arena_size_()
Probes the actual required tensor arena size by trial allocation.
bool unprocessed_probability_status_
tflite::MicroResourceVariables * mrv_
bool perform_streaming_inference(const int8_t features[PREPROCESSOR_FEATURE_SIZE])
uint8_t probability_cutoff_
void unload_model()
Destroys the TFLite interpreter and frees the tensor and variable arenas' memory.
const uint8_t * model_start_
DetectionEvent determine_detected() override
Checks for voice activity by comparing the max probability in the sliding window with the probability...
void log_model_config() override
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.
DetectionEvent determine_detected() override
Checks for the wake word by comparing the mean probability in the sliding window with the probability...
void log_model_config() override
std::shared_ptr< ModelData > model_data_
ESPPreferenceObject pref_
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_
ESPPreferences * global_preferences
uint32_t fnv1_hash(const char *str)
Calculate a FNV-1 hash of str.
ESPHOME_LOG_TAG(TAG, "micro_wake_word")
ESPPreferenceObject make_preference(size_t, uint32_t, bool)
uint8_t average_probability