|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _EDGE_IMPULSE_RUN_CLASSIFIER_H_ |
|
|
#define _EDGE_IMPULSE_RUN_CLASSIFIER_H_ |
|
|
|
|
|
#include "model-parameters/model_metadata.h" |
|
|
|
|
|
#include "ei_run_dsp.h" |
|
|
#include "ei_classifier_types.h" |
|
|
#include "ei_signal_with_axes.h" |
|
|
#include "ei_performance_calibration.h" |
|
|
|
|
|
#include "edge-impulse-sdk/porting/ei_classifier_porting.h" |
|
|
|
|
|
#if EI_CLASSIFIER_HAS_ANOMALY == 1 |
|
|
#include "inferencing_engines/anomaly.h" |
|
|
#endif |
|
|
|
|
|
#if defined(EI_CLASSIFIER_HAS_SAMPLER) && EI_CLASSIFIER_HAS_SAMPLER == 1 |
|
|
#include "ei_sampler.h" |
|
|
#endif |
|
|
|
|
|
#if (EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_TFLITE) && (EI_CLASSIFIER_COMPILED != 1) |
|
|
#include "edge-impulse-sdk/classifier/inferencing_engines/tflite_micro.h" |
|
|
#elif EI_CLASSIFIER_COMPILED == 1 |
|
|
#include "edge-impulse-sdk/classifier/inferencing_engines/tflite_eon.h" |
|
|
#elif EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_TFLITE_FULL |
|
|
#include "edge-impulse-sdk/classifier/inferencing_engines/tflite_full.h" |
|
|
#elif EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_TFLITE_TIDL |
|
|
#include "edge-impulse-sdk/classifier/inferencing_engines/tflite_tidl.h" |
|
|
#elif (EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_TENSORRT) |
|
|
#include "edge-impulse-sdk/classifier/inferencing_engines/tensorrt.h" |
|
|
#elif EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_TENSAIFLOW |
|
|
#include "edge-impulse-sdk/classifier/inferencing_engines/tensaiflow.h" |
|
|
#elif EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_DRPAI |
|
|
#include "edge-impulse-sdk/classifier/inferencing_engines/drpai.h" |
|
|
#elif EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_AKIDA |
|
|
#include "edge-impulse-sdk/classifier/inferencing_engines/akida.h" |
|
|
#elif EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_ONNX_TIDL |
|
|
#include "edge-impulse-sdk/classifier/inferencing_engines/onnx_tidl.h" |
|
|
#elif EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_MEMRYX |
|
|
#include "edge-impulse-sdk/classifier/inferencing_engines/memryx.h" |
|
|
#elif EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_NONE |
|
|
|
|
|
#else |
|
|
#error "Unknown inferencing engine" |
|
|
#endif |
|
|
|
|
|
#include "model-parameters/model_variables.h" |
|
|
|
|
|
#if ECM3532 |
|
|
void* __dso_handle = (void*) &__dso_handle; |
|
|
#endif |
|
|
|
|
|
#ifdef __cplusplus |
|
|
namespace { |
|
|
#endif |
|
|
|
|
|
|
|
|
extern "C" EI_IMPULSE_ERROR run_inference(const ei_impulse_t *impulse, ei::matrix_t *fmatrix, ei_impulse_result_t *result, bool debug); |
|
|
extern "C" EI_IMPULSE_ERROR run_classifier_image_quantized(const ei_impulse_t *impulse, signal_t *signal, ei_impulse_result_t *result, bool debug); |
|
|
static EI_IMPULSE_ERROR can_run_classifier_image_quantized(const ei_impulse_t *impulse, ei_learning_block_t block_ptr); |
|
|
|
|
|
|
|
|
|
|
|
static uint64_t classifier_continuous_features_written = 0; |
|
|
static RecognizeEvents *avg_scores = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if EI_CLASSIFIER_LOAD_IMAGE_SCALING |
|
|
static const float torch_mean[] = { 0.485, 0.456, 0.406 }; |
|
|
static const float torch_std[] = { 0.229, 0.224, 0.225 }; |
|
|
|
|
|
static EI_IMPULSE_ERROR scale_fmatrix(ei_learning_block_t *block, ei::matrix_t *fmatrix) { |
|
|
if (block->image_scaling == EI_CLASSIFIER_IMAGE_SCALING_TORCH) { |
|
|
|
|
|
for (size_t ix = 0; ix < fmatrix->rows * fmatrix->cols; ix += 3) { |
|
|
fmatrix->buffer[ix + 0] = (fmatrix->buffer[ix + 0] - torch_mean[0]) / torch_std[0]; |
|
|
fmatrix->buffer[ix + 1] = (fmatrix->buffer[ix + 1] - torch_mean[1]) / torch_std[1]; |
|
|
fmatrix->buffer[ix + 2] = (fmatrix->buffer[ix + 2] - torch_mean[2]) / torch_std[2]; |
|
|
} |
|
|
} |
|
|
else if (block->image_scaling == EI_CLASSIFIER_IMAGE_SCALING_0_255) { |
|
|
int scale_res = numpy::scale(fmatrix, 255.0f); |
|
|
if (scale_res != EIDSP_OK) { |
|
|
ei_printf("ERR: Failed to scale matrix (%d)\n", scale_res); |
|
|
return EI_IMPULSE_DSP_ERROR; |
|
|
} |
|
|
} |
|
|
|
|
|
return EI_IMPULSE_OK; |
|
|
} |
|
|
|
|
|
static EI_IMPULSE_ERROR unscale_fmatrix(ei_learning_block_t *block, ei::matrix_t *fmatrix) { |
|
|
if (block->image_scaling == EI_CLASSIFIER_IMAGE_SCALING_TORCH) { |
|
|
|
|
|
for (size_t ix = 0; ix < fmatrix->rows * fmatrix->cols; ix += 3) { |
|
|
fmatrix->buffer[ix + 0] = (fmatrix->buffer[ix + 0] * torch_std[0]) + torch_mean[0]; |
|
|
fmatrix->buffer[ix + 1] = (fmatrix->buffer[ix + 1] * torch_std[1]) + torch_mean[1]; |
|
|
fmatrix->buffer[ix + 2] = (fmatrix->buffer[ix + 2] * torch_std[2]) + torch_mean[2]; |
|
|
} |
|
|
} |
|
|
else if (block->image_scaling == EI_CLASSIFIER_IMAGE_SCALING_0_255) { |
|
|
int scale_res = numpy::scale(fmatrix, 1 / 255.0f); |
|
|
if (scale_res != EIDSP_OK) { |
|
|
ei_printf("ERR: Failed to scale matrix (%d)\n", scale_res); |
|
|
return EI_IMPULSE_DSP_ERROR; |
|
|
} |
|
|
} |
|
|
return EI_IMPULSE_OK; |
|
|
} |
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" EI_IMPULSE_ERROR run_inference( |
|
|
const ei_impulse_t *impulse, |
|
|
ei::matrix_t *fmatrix, |
|
|
ei_impulse_result_t *result, |
|
|
bool debug = false) |
|
|
{ |
|
|
for (size_t ix = 0; ix < impulse->learning_blocks_size; ix++) { |
|
|
ei_learning_block_t block = impulse->learning_blocks[ix]; |
|
|
|
|
|
#if EI_CLASSIFIER_LOAD_IMAGE_SCALING |
|
|
EI_IMPULSE_ERROR scale_res = scale_fmatrix(&block, fmatrix); |
|
|
if (scale_res != EI_IMPULSE_OK) { |
|
|
return scale_res; |
|
|
} |
|
|
#endif |
|
|
|
|
|
EI_IMPULSE_ERROR res = block.infer_fn(impulse, fmatrix, result, block.config, debug); |
|
|
if (res != EI_IMPULSE_OK) { |
|
|
return res; |
|
|
} |
|
|
|
|
|
#if EI_CLASSIFIER_LOAD_IMAGE_SCALING |
|
|
|
|
|
scale_res = unscale_fmatrix(&block, fmatrix); |
|
|
if (scale_res != EI_IMPULSE_OK) { |
|
|
return scale_res; |
|
|
} |
|
|
#endif |
|
|
} |
|
|
|
|
|
if (ei_run_impulse_check_canceled() == EI_IMPULSE_CANCELED) { |
|
|
return EI_IMPULSE_CANCELED; |
|
|
} |
|
|
|
|
|
return EI_IMPULSE_OK; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" EI_IMPULSE_ERROR process_impulse(const ei_impulse_t *impulse, |
|
|
signal_t *signal, |
|
|
ei_impulse_result_t *result, |
|
|
bool debug = false) |
|
|
{ |
|
|
|
|
|
#if (EI_CLASSIFIER_QUANTIZATION_ENABLED == 1 && (EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_TFLITE || EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_TENSAIFLOW || EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_ONNX_TIDL)) || EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_DRPAI |
|
|
|
|
|
ei_learning_block_t block = impulse->learning_blocks[0]; |
|
|
if (can_run_classifier_image_quantized(impulse, block) == EI_IMPULSE_OK) { |
|
|
return run_classifier_image_quantized(impulse, signal, result, debug); |
|
|
} |
|
|
#endif |
|
|
|
|
|
memset(result, 0, sizeof(ei_impulse_result_t)); |
|
|
|
|
|
ei::matrix_t features_matrix(1, impulse->nn_input_frame_size); |
|
|
|
|
|
uint64_t dsp_start_us = ei_read_timer_us(); |
|
|
|
|
|
size_t out_features_index = 0; |
|
|
|
|
|
for (size_t ix = 0; ix < impulse->dsp_blocks_size; ix++) { |
|
|
ei_model_dsp_t block = impulse->dsp_blocks[ix]; |
|
|
|
|
|
if (out_features_index + block.n_output_features > impulse->nn_input_frame_size) { |
|
|
ei_printf("ERR: Would write outside feature buffer\n"); |
|
|
return EI_IMPULSE_DSP_ERROR; |
|
|
} |
|
|
|
|
|
ei::matrix_t fm(1, block.n_output_features, features_matrix.buffer + out_features_index); |
|
|
|
|
|
#if EIDSP_SIGNAL_C_FN_POINTER |
|
|
if (block.axes_size != impulse->raw_samples_per_frame) { |
|
|
ei_printf("ERR: EIDSP_SIGNAL_C_FN_POINTER can only be used when all axes are selected for DSP blocks\n"); |
|
|
return EI_IMPULSE_DSP_ERROR; |
|
|
} |
|
|
int ret = block.extract_fn(signal, &fm, block.config, impulse->frequency); |
|
|
#else |
|
|
SignalWithAxes swa(signal, block.axes, block.axes_size, impulse); |
|
|
int ret = block.extract_fn(swa.get_signal(), &fm, block.config, impulse->frequency); |
|
|
#endif |
|
|
|
|
|
if (ret != EIDSP_OK) { |
|
|
ei_printf("ERR: Failed to run DSP process (%d)\n", ret); |
|
|
return EI_IMPULSE_DSP_ERROR; |
|
|
} |
|
|
|
|
|
if (ei_run_impulse_check_canceled() == EI_IMPULSE_CANCELED) { |
|
|
return EI_IMPULSE_CANCELED; |
|
|
} |
|
|
|
|
|
out_features_index += block.n_output_features; |
|
|
} |
|
|
|
|
|
result->timing.dsp_us = ei_read_timer_us() - dsp_start_us; |
|
|
result->timing.dsp = (int)(result->timing.dsp_us / 1000); |
|
|
|
|
|
if (debug) { |
|
|
ei_printf("Features (%d ms.): ", result->timing.dsp); |
|
|
for (size_t ix = 0; ix < features_matrix.cols; ix++) { |
|
|
ei_printf_float(features_matrix.buffer[ix]); |
|
|
ei_printf(" "); |
|
|
} |
|
|
ei_printf("\n"); |
|
|
} |
|
|
|
|
|
if (debug) { |
|
|
ei_printf("Running impulse...\n"); |
|
|
} |
|
|
|
|
|
return run_inference(impulse, &features_matrix, result, debug); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" EI_IMPULSE_ERROR process_impulse_continuous(const ei_impulse_t *impulse, |
|
|
signal_t *signal, |
|
|
ei_impulse_result_t *result, |
|
|
bool debug, |
|
|
bool enable_maf) |
|
|
{ |
|
|
|
|
|
static ei::matrix_t static_features_matrix(1, impulse->nn_input_frame_size); |
|
|
if (!static_features_matrix.buffer) { |
|
|
return EI_IMPULSE_ALLOC_FAILED; |
|
|
} |
|
|
|
|
|
memset(result, 0, sizeof(ei_impulse_result_t)); |
|
|
|
|
|
EI_IMPULSE_ERROR ei_impulse_error = EI_IMPULSE_OK; |
|
|
|
|
|
uint64_t dsp_start_us = ei_read_timer_us(); |
|
|
|
|
|
size_t out_features_index = 0; |
|
|
bool is_mfcc = false; |
|
|
bool is_mfe = false; |
|
|
bool is_spectrogram = false; |
|
|
|
|
|
for (size_t ix = 0; ix < impulse->dsp_blocks_size; ix++) { |
|
|
ei_model_dsp_t block = impulse->dsp_blocks[ix]; |
|
|
|
|
|
if (out_features_index + block.n_output_features > impulse->nn_input_frame_size) { |
|
|
ei_printf("ERR: Would write outside feature buffer\n"); |
|
|
return EI_IMPULSE_DSP_ERROR; |
|
|
} |
|
|
|
|
|
ei::matrix_t fm(1, block.n_output_features, |
|
|
static_features_matrix.buffer + out_features_index); |
|
|
|
|
|
int (*extract_fn_slice)(ei::signal_t *signal, ei::matrix_t *output_matrix, void *config, const float frequency, matrix_size_t *out_matrix_size); |
|
|
|
|
|
|
|
|
if (block.extract_fn == extract_mfcc_features) { |
|
|
extract_fn_slice = &extract_mfcc_per_slice_features; |
|
|
is_mfcc = true; |
|
|
} |
|
|
else if (block.extract_fn == extract_spectrogram_features) { |
|
|
extract_fn_slice = &extract_spectrogram_per_slice_features; |
|
|
is_spectrogram = true; |
|
|
} |
|
|
else if (block.extract_fn == extract_mfe_features) { |
|
|
extract_fn_slice = &extract_mfe_per_slice_features; |
|
|
is_mfe = true; |
|
|
} |
|
|
else { |
|
|
ei_printf("ERR: Unknown extract function, only MFCC, MFE and spectrogram supported\n"); |
|
|
return EI_IMPULSE_DSP_ERROR; |
|
|
} |
|
|
|
|
|
matrix_size_t features_written; |
|
|
|
|
|
#if EIDSP_SIGNAL_C_FN_POINTER |
|
|
if (block.axes_size != impulse->raw_samples_per_frame) { |
|
|
ei_printf("ERR: EIDSP_SIGNAL_C_FN_POINTER can only be used when all axes are selected for DSP blocks\n"); |
|
|
return EI_IMPULSE_DSP_ERROR; |
|
|
} |
|
|
int ret = extract_fn_slice(signal, &fm, block.config, impulse->frequency, &features_written); |
|
|
#else |
|
|
SignalWithAxes swa(signal, block.axes, block.axes_size, impulse); |
|
|
int ret = extract_fn_slice(swa.get_signal(), &fm, block.config, impulse->frequency, &features_written); |
|
|
#endif |
|
|
|
|
|
if (ret != EIDSP_OK) { |
|
|
ei_printf("ERR: Failed to run DSP process (%d)\n", ret); |
|
|
return EI_IMPULSE_DSP_ERROR; |
|
|
} |
|
|
|
|
|
if (ei_run_impulse_check_canceled() == EI_IMPULSE_CANCELED) { |
|
|
return EI_IMPULSE_CANCELED; |
|
|
} |
|
|
|
|
|
classifier_continuous_features_written += (features_written.rows * features_written.cols); |
|
|
|
|
|
out_features_index += block.n_output_features; |
|
|
} |
|
|
|
|
|
result->timing.dsp_us = ei_read_timer_us() - dsp_start_us; |
|
|
result->timing.dsp = (int)(result->timing.dsp_us / 1000); |
|
|
|
|
|
if (debug) { |
|
|
ei_printf("\r\nFeatures (%d ms.): ", result->timing.dsp); |
|
|
for (size_t ix = 0; ix < static_features_matrix.cols; ix++) { |
|
|
ei_printf_float(static_features_matrix.buffer[ix]); |
|
|
ei_printf(" "); |
|
|
} |
|
|
ei_printf("\n"); |
|
|
} |
|
|
|
|
|
if (classifier_continuous_features_written >= impulse->nn_input_frame_size) { |
|
|
dsp_start_us = ei_read_timer_us(); |
|
|
ei::matrix_t classify_matrix(1, impulse->nn_input_frame_size); |
|
|
|
|
|
|
|
|
for (size_t m_ix = 0; m_ix < impulse->nn_input_frame_size; m_ix++) { |
|
|
classify_matrix.buffer[m_ix] = static_features_matrix.buffer[m_ix]; |
|
|
} |
|
|
|
|
|
if (is_mfcc) { |
|
|
calc_cepstral_mean_and_var_normalization_mfcc(&classify_matrix, impulse->dsp_blocks[0].config); |
|
|
} |
|
|
else if (is_spectrogram) { |
|
|
calc_cepstral_mean_and_var_normalization_spectrogram(&classify_matrix, impulse->dsp_blocks[0].config); |
|
|
} |
|
|
else if (is_mfe) { |
|
|
calc_cepstral_mean_and_var_normalization_mfe(&classify_matrix, impulse->dsp_blocks[0].config); |
|
|
} |
|
|
result->timing.dsp_us += ei_read_timer_us() - dsp_start_us; |
|
|
result->timing.dsp = (int)(result->timing.dsp_us / 1000); |
|
|
|
|
|
if (debug) { |
|
|
ei_printf("Running impulse...\n"); |
|
|
} |
|
|
|
|
|
ei_impulse_error = run_inference(impulse, &classify_matrix, result, debug); |
|
|
|
|
|
#if EI_CLASSIFIER_CALIBRATION_ENABLED |
|
|
if (impulse->sensor == EI_CLASSIFIER_SENSOR_MICROPHONE) { |
|
|
if((void *)avg_scores != NULL && enable_maf == true) { |
|
|
if (enable_maf && !impulse->calibration.is_configured) { |
|
|
|
|
|
static bool has_printed_msg = false; |
|
|
|
|
|
if (!has_printed_msg) { |
|
|
ei_printf("WARN: run_classifier_continuous, enable_maf is true, but performance calibration is not configured.\n"); |
|
|
ei_printf(" Previously we'd run a moving-average filter over your outputs in this case, but this is now disabled.\n"); |
|
|
ei_printf(" Go to 'Performance calibration' in your Edge Impulse project to configure post-processing parameters.\n"); |
|
|
ei_printf(" (You can enable this from 'Dashboard' if it's not visible in your project)\n"); |
|
|
ei_printf("\n"); |
|
|
|
|
|
has_printed_msg = true; |
|
|
} |
|
|
} |
|
|
else { |
|
|
|
|
|
static bool has_printed_msg = false; |
|
|
|
|
|
if (!has_printed_msg) { |
|
|
ei_printf("\nPerformance calibration is configured for your project. If no event is detected, all values are 0.\r\n\n"); |
|
|
has_printed_msg = true; |
|
|
} |
|
|
|
|
|
int label_detected = avg_scores->trigger(result->classification); |
|
|
|
|
|
if (avg_scores->should_boost()) { |
|
|
for (int i = 0; i < impulse->label_count; i++) { |
|
|
if (i == label_detected) { |
|
|
result->classification[i].value = 1.0f; |
|
|
} |
|
|
else { |
|
|
result->classification[i].value = 0.0f; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
#endif |
|
|
} |
|
|
else { |
|
|
if (!impulse->object_detection) { |
|
|
for (int i = 0; i < impulse->label_count; i++) { |
|
|
|
|
|
result->classification[i].label = impulse->categories[(uint32_t)i]; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return ei_impulse_error; |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((unused)) static EI_IMPULSE_ERROR can_run_classifier_image_quantized(const ei_impulse_t *impulse, ei_learning_block_t block_ptr) { |
|
|
|
|
|
if (impulse->inferencing_engine != EI_CLASSIFIER_TFLITE |
|
|
&& impulse->inferencing_engine != EI_CLASSIFIER_TENSAIFLOW |
|
|
&& impulse->inferencing_engine != EI_CLASSIFIER_DRPAI |
|
|
&& impulse->inferencing_engine != EI_CLASSIFIER_ONNX_TIDL) |
|
|
{ |
|
|
return EI_IMPULSE_UNSUPPORTED_INFERENCING_ENGINE; |
|
|
} |
|
|
|
|
|
if (impulse->has_anomaly == 1){ |
|
|
return EI_IMPULSE_ONLY_SUPPORTED_FOR_IMAGES; |
|
|
} |
|
|
|
|
|
|
|
|
if (block_ptr.infer_fn != run_nn_inference) { |
|
|
return EI_IMPULSE_ONLY_SUPPORTED_FOR_IMAGES; |
|
|
} |
|
|
|
|
|
|
|
|
ei_learning_block_config_tflite_graph_t *block_config = (ei_learning_block_config_tflite_graph_t*)block_ptr.config; |
|
|
if (block_config->quantized != 1) { |
|
|
return EI_IMPULSE_ONLY_SUPPORTED_FOR_IMAGES; |
|
|
} |
|
|
|
|
|
|
|
|
if (impulse->dsp_blocks_size != 1 || impulse->dsp_blocks[0].extract_fn != extract_image_features) { |
|
|
return EI_IMPULSE_ONLY_SUPPORTED_FOR_IMAGES; |
|
|
} |
|
|
|
|
|
return EI_IMPULSE_OK; |
|
|
} |
|
|
|
|
|
#if EI_CLASSIFIER_QUANTIZATION_ENABLED == 1 && (EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_TFLITE || EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_TENSAIFLOW || EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_DRPAI || EI_CLASSIFIER_INFERENCING_ENGINE == EI_CLASSIFIER_ONNX_TIDL) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" EI_IMPULSE_ERROR run_classifier_image_quantized( |
|
|
const ei_impulse_t *impulse, |
|
|
signal_t *signal, |
|
|
ei_impulse_result_t *result, |
|
|
bool debug = false) |
|
|
{ |
|
|
memset(result, 0, sizeof(ei_impulse_result_t)); |
|
|
|
|
|
return run_nn_inference_image_quantized(impulse, signal, result, impulse->learning_blocks[0].config, debug); |
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" void run_classifier_init() |
|
|
{ |
|
|
|
|
|
classifier_continuous_features_written = 0; |
|
|
ei_dsp_clear_continuous_audio_state(); |
|
|
|
|
|
#if EI_CLASSIFIER_CALIBRATION_ENABLED |
|
|
|
|
|
const ei_impulse_t impulse = ei_default_impulse; |
|
|
const ei_model_performance_calibration_t *calibration = &impulse.calibration; |
|
|
|
|
|
if(calibration != NULL) { |
|
|
avg_scores = new RecognizeEvents(calibration, |
|
|
impulse.label_count, impulse.slice_size, impulse.interval_ms); |
|
|
} |
|
|
#endif |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((unused)) void run_classifier_init(const ei_impulse_t *impulse) |
|
|
{ |
|
|
classifier_continuous_features_written = 0; |
|
|
ei_dsp_clear_continuous_audio_state(); |
|
|
|
|
|
#if EI_CLASSIFIER_CALIBRATION_ENABLED |
|
|
const ei_model_performance_calibration_t *calibration = &impulse->calibration; |
|
|
|
|
|
if(calibration != NULL) { |
|
|
avg_scores = new RecognizeEvents(calibration, |
|
|
impulse->label_count, impulse->slice_size, impulse->interval_ms); |
|
|
} |
|
|
#endif |
|
|
} |
|
|
|
|
|
extern "C" void run_classifier_deinit(void) |
|
|
{ |
|
|
if((void *)avg_scores != NULL) { |
|
|
delete avg_scores; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" EI_IMPULSE_ERROR run_classifier_continuous( |
|
|
signal_t *signal, |
|
|
ei_impulse_result_t *result, |
|
|
bool debug = false, |
|
|
bool enable_maf = true) |
|
|
{ |
|
|
const ei_impulse_t impulse = ei_default_impulse; |
|
|
return process_impulse_continuous(&impulse, signal, result, debug, enable_maf); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((unused)) EI_IMPULSE_ERROR run_classifier_continuous( |
|
|
const ei_impulse_t *impulse, |
|
|
signal_t *signal, |
|
|
ei_impulse_result_t *result, |
|
|
bool debug = false, |
|
|
bool enable_maf = true) |
|
|
{ |
|
|
return process_impulse_continuous(impulse, signal, result, debug, enable_maf); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" EI_IMPULSE_ERROR run_classifier( |
|
|
signal_t *signal, |
|
|
ei_impulse_result_t *result, |
|
|
bool debug = false) |
|
|
{ |
|
|
const ei_impulse_t impulse = ei_default_impulse; |
|
|
return process_impulse(&impulse, signal, result, debug); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((unused)) EI_IMPULSE_ERROR run_classifier( |
|
|
const ei_impulse_t *impulse, |
|
|
signal_t *signal, |
|
|
ei_impulse_result_t *result, |
|
|
bool debug = false) |
|
|
{ |
|
|
return process_impulse(impulse, signal, result, debug); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if EIDSP_SIGNAL_C_FN_POINTER == 0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((unused)) EI_IMPULSE_ERROR run_impulse( |
|
|
#if defined(EI_CLASSIFIER_HAS_SAMPLER) && EI_CLASSIFIER_HAS_SAMPLER == 1 |
|
|
EdgeSampler *sampler, |
|
|
#endif |
|
|
ei_impulse_result_t *result, |
|
|
#ifdef __MBED__ |
|
|
mbed::Callback<void(float*, size_t)> data_fn, |
|
|
#else |
|
|
std::function<void(float*, size_t)> data_fn, |
|
|
#endif |
|
|
bool debug = false) { |
|
|
|
|
|
const ei_impulse_t impulse = ei_default_impulse; |
|
|
|
|
|
float *x = (float*)calloc(impulse.dsp_input_frame_size, sizeof(float)); |
|
|
if (!x) { |
|
|
return EI_IMPULSE_OUT_OF_MEMORY; |
|
|
} |
|
|
|
|
|
uint64_t next_tick = 0; |
|
|
|
|
|
uint64_t sampling_us_start = ei_read_timer_us(); |
|
|
|
|
|
|
|
|
for (int i = 0; i < (int)impulse.dsp_input_frame_size; i += impulse.raw_samples_per_frame) { |
|
|
uint64_t curr_us = ei_read_timer_us() - sampling_us_start; |
|
|
|
|
|
next_tick = curr_us + (impulse.interval_ms * 1000); |
|
|
|
|
|
data_fn(x + i, impulse.raw_samples_per_frame); |
|
|
#if defined(EI_CLASSIFIER_HAS_SAMPLER) && EI_CLASSIFIER_HAS_SAMPLER == 1 |
|
|
if (sampler != NULL) { |
|
|
sampler->write_sensor_data(x + i, impulse.raw_samples_per_frame); |
|
|
} |
|
|
#endif |
|
|
|
|
|
if (ei_run_impulse_check_canceled() == EI_IMPULSE_CANCELED) { |
|
|
free(x); |
|
|
return EI_IMPULSE_CANCELED; |
|
|
} |
|
|
|
|
|
while (next_tick > ei_read_timer_us() - sampling_us_start); |
|
|
} |
|
|
|
|
|
result->timing.sampling = (ei_read_timer_us() - sampling_us_start) / 1000; |
|
|
|
|
|
signal_t signal; |
|
|
int err = numpy::signal_from_buffer(x, impulse.dsp_input_frame_size, &signal); |
|
|
if (err != 0) { |
|
|
free(x); |
|
|
ei_printf("ERR: signal_from_buffer failed (%d)\n", err); |
|
|
return EI_IMPULSE_DSP_ERROR; |
|
|
} |
|
|
|
|
|
EI_IMPULSE_ERROR r = run_classifier(&signal, result, debug); |
|
|
free(x); |
|
|
return r; |
|
|
} |
|
|
|
|
|
#if defined(EI_CLASSIFIER_HAS_SAMPLER) && EI_CLASSIFIER_HAS_SAMPLER == 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((unused)) EI_IMPULSE_ERROR run_impulse( |
|
|
ei_impulse_result_t *result, |
|
|
#ifdef __MBED__ |
|
|
mbed::Callback<void(float*, size_t)> data_fn, |
|
|
#else |
|
|
std::function<void(float*, size_t)> data_fn, |
|
|
#endif |
|
|
bool debug = false) { |
|
|
return run_impulse(NULL, result, data_fn, debug); |
|
|
} |
|
|
#endif |
|
|
|
|
|
#endif |
|
|
|
|
|
#ifdef __cplusplus |
|
|
} |
|
|
#endif |
|
|
|
|
|
#endif |
|
|
|