Add an InitializeTarget function that can be sepcialized for a given target.

This will allow the unit tests to be run on additional targets that need
some addiitonal initialization (for example cornstone_300 from ).

This particular change is broken out from the Cornstone PR  to
be able to have smaller more reviewable PRs.

In the past, we have added state to the DebugLog() and
GetCurrentTimeTicks() functions as a way to avoid having an
InitializeTarget function. With this change, we are deciding to go with
an explicit intitialization step instead.

This change has added calls to tflite::InitializeTarget to the tests,
benchmarks, and examples and converted the Arduino and SparkfunEdge to
make use of this explicit initialization.

The changes for the Arduino and SparkfunEdge have not been tested on
actual hardware.

Progress towards 
This commit is contained in:
Advait Jain 2021-02-10 15:00:45 -08:00
parent ed58135ee6
commit 81d33f1b6d
22 changed files with 265 additions and 137 deletions

View File

@ -216,6 +216,17 @@ cc_library(
],
)
cc_library(
name = "system_setup",
srcs = [
"system_setup.cc",
],
hdrs = [
"system_setup.h",
],
copts = micro_copts(),
)
cc_test(
name = "micro_error_reporter_test",
srcs = [

View File

@ -1,4 +1,4 @@
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -12,27 +12,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/micro/debug_log.h"
#include "Arduino.h"
// The Arduino DUE uses a different object for the default serial port shown in
// the monitor than most other models, so make sure we pick the right one. See
// https://github.com/arduino/Arduino/issues/3088#issuecomment-406655244
#if defined(__SAM3X8E__)
#define DEBUG_SERIAL_OBJECT (SerialUSB)
#else
#define DEBUG_SERIAL_OBJECT (Serial)
#endif
// On Arduino platforms, we set up a serial port and write to it for debug
// logging.
extern "C" void DebugLog(const char* s) {
static bool is_initialized = false;
if (!is_initialized) {
DEBUG_SERIAL_OBJECT.begin(9600);
is_initialized = true;
}
DEBUG_SERIAL_OBJECT.print(s);
}
// This file is empty to ensure that a specialized implementation of
// debug_log.h is used (instead of the default implementation from
// tensorflow/lite/micro/debug_log.cc).
//
// The actual target-specific implementation of debug_log.h is in
// system_setup.cc since that allows us to consolidate all the target-specific
// specializations into one source file.

View File

@ -0,0 +1,36 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/micro/system_setup.h"
#include "Arduino.h"
#include "tensorflow/lite/micro/debug_log.h"
// The Arduino DUE uses a different object for the default serial port shown in
// the monitor than most other models, so make sure we pick the right one. See
// https://github.com/arduino/Arduino/issues/3088#issuecomment-406655244
#if defined(__SAM3X8E__)
#define DEBUG_SERIAL_OBJECT (SerialUSB)
#else
#define DEBUG_SERIAL_OBJECT (Serial)
#endif
extern "C" void DebugLog(const char* s) { DEBUG_SERIAL_OBJECT.print(s); }
namespace tflite {
void InitializeTarget() { DEBUG_SERIAL_OBJECT.begin(9600); }
} // namespace tflite

View File

@ -46,6 +46,7 @@ cc_binary(
"//tensorflow/lite/micro:micro_error_reporter",
"//tensorflow/lite/micro:micro_framework",
"//tensorflow/lite/micro:op_resolvers",
"//tensorflow/lite/micro:system_setup",
"//tensorflow/lite/micro/kernels:fully_connected",
],
)
@ -63,6 +64,7 @@ cc_binary(
"//tensorflow/lite/micro:micro_framework",
"//tensorflow/lite/micro:micro_utils",
"//tensorflow/lite/micro:op_resolvers",
"//tensorflow/lite/micro:system_setup",
"//tensorflow/lite/micro/examples/person_detection:model_settings",
"//tensorflow/lite/micro/examples/person_detection:person_detect_model_data",
"//tensorflow/lite/micro/examples/person_detection:simple_images_test_data",

View File

@ -24,6 +24,7 @@ limitations under the License.
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/micro_profiler.h"
#include "tensorflow/lite/micro/system_setup.h"
/*
* Keyword Spotting Benchmark for performance optimizations. The model used in
@ -77,6 +78,7 @@ void KeywordRunNIerations(int iterations, const char* tag,
} // namespace tflite
int main(int argc, char** argv) {
tflite::InitializeTarget();
tflite::MicroProfiler profiler;
uint32_t event_handle = profiler.BeginEvent("InitializeKeywordRunner");

View File

@ -23,6 +23,7 @@ limitations under the License.
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_utils.h"
#include "tensorflow/lite/micro/system_setup.h"
#include "tensorflow/lite/schema/schema_generated.h"
/*
@ -74,6 +75,8 @@ void PersonDetectionNIerations(const int8_t* input, int iterations,
} // namespace tflite
int main(int argc, char** argv) {
tflite::InitializeTarget();
tflite::MicroProfiler profiler;
uint32_t event_handle = profiler.BeginEvent("InitializeBenchmarkRunner");

View File

@ -82,6 +82,7 @@ cc_binary(
"//tensorflow/lite/micro:micro_error_reporter",
"//tensorflow/lite/micro:micro_framework",
"//tensorflow/lite/micro:op_resolvers",
"//tensorflow/lite/micro:system_setup",
"//tensorflow/lite/schema:schema_fbs",
],
)

View File

@ -21,6 +21,7 @@ limitations under the License.
#include "tensorflow/lite/micro/examples/hello_world/output_handler.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/system_setup.h"
#include "tensorflow/lite/schema/schema_generated.h"
// Globals, used for compatibility with Arduino-style sketches.
@ -38,6 +39,8 @@ uint8_t tensor_arena[kTensorArenaSize];
// The name of this function is important for Arduino compatibility.
void setup() {
tflite::InitializeTarget();
// Set up logging. Google style is to avoid globals or statics because of
// lifetime uncertainty, but since this has a trivial destructor it's okay.
// NOLINTNEXTLINE(runtime-global-variables)

View File

@ -23,6 +23,7 @@ limitations under the License.
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/system_setup.h"
#include "tensorflow/lite/schema/schema_generated.h"
#define NUM_OUT_CH 3
@ -34,6 +35,7 @@ static const char* labels[] = {"Plane", "Car", "Bird", "Cat", "Deer",
"Dog", "Frog", "Horse", "Ship", "Truck"};
int main(int argc, char** argv) {
tflite::InitializeTarget();
init_lcd();
wait_ms(100);

View File

@ -154,6 +154,7 @@ cc_binary(
"//tensorflow/lite/micro:micro_error_reporter",
"//tensorflow/lite/micro:micro_framework",
"//tensorflow/lite/micro:op_resolvers",
"//tensorflow/lite/micro:system_setup",
"//tensorflow/lite/schema:schema_fbs",
],
)

View File

@ -23,6 +23,7 @@ limitations under the License.
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/system_setup.h"
#include "tensorflow/lite/schema/schema_generated.h"
// Globals, used for compatibility with Arduino-style sketches.
@ -42,6 +43,8 @@ uint8_t tensor_arena[kTensorArenaSize];
// The name of this function is important for Arduino compatibility.
void setup() {
tflite::InitializeTarget();
// Set up logging. Google style is to avoid globals or statics because of
// lifetime uncertainty, but since this has a trivial destructor it's okay.
static tflite::MicroErrorReporter micro_error_reporter; // NOLINT

View File

@ -362,6 +362,7 @@ cc_binary(
"//tensorflow/lite/micro:micro_error_reporter",
"//tensorflow/lite/micro:micro_framework",
"//tensorflow/lite/micro:op_resolvers",
"//tensorflow/lite/micro:system_setup",
"//tensorflow/lite/micro/examples/micro_speech/micro_features:micro_model_settings",
"//tensorflow/lite/micro/examples/micro_speech/micro_features:model",
"//tensorflow/lite/schema:schema_fbs",
@ -383,6 +384,7 @@ cc_binary(
"//tensorflow/lite/micro:micro_error_reporter",
"//tensorflow/lite/micro:micro_framework",
"//tensorflow/lite/micro:op_resolvers",
"//tensorflow/lite/micro:system_setup",
"//tensorflow/lite/micro/examples/micro_speech/micro_features:micro_model_settings",
"//tensorflow/lite/micro/examples/micro_speech/micro_features:model",
"//tensorflow/lite/schema:schema_fbs",

View File

@ -24,6 +24,7 @@ limitations under the License.
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/system_setup.h"
#include "tensorflow/lite/schema/schema_generated.h"
// Globals, used for compatibility with Arduino-style sketches.
@ -47,6 +48,8 @@ int8_t* model_input_buffer = nullptr;
// The name of this function is important for Arduino compatibility.
void setup() {
tflite::InitializeTarget();
// Set up logging. Google style is to avoid globals or statics because of
// lifetime uncertainty, but since this has a trivial destructor it's okay.
// NOLINTNEXTLINE(runtime-global-variables)

View File

@ -138,6 +138,7 @@ cc_binary(
"//tensorflow/lite/micro:micro_error_reporter",
"//tensorflow/lite/micro:micro_framework",
"//tensorflow/lite/micro:op_resolvers",
"//tensorflow/lite/micro:system_setup",
"//tensorflow/lite/schema:schema_fbs",
],
)

View File

@ -22,6 +22,7 @@ limitations under the License.
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/system_setup.h"
#include "tensorflow/lite/schema/schema_generated.h"
// Globals, used for compatibility with Arduino-style sketches.
@ -45,6 +46,8 @@ static uint8_t tensor_arena[kTensorArenaSize];
// The name of this function is important for Arduino compatibility.
void setup() {
tflite::InitializeTarget();
// Set up logging. Google style is to avoid globals or statics because of
// lifetime uncertainty, but since this has a trivial destructor it's okay.
// NOLINTNEXTLINE(runtime-global-variables)

View File

@ -1,4 +1,4 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -12,24 +12,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Implementation for the DebugLog() function that prints to the UART on the
// SparkFun Edge microcontroller. The same should work for other targets using
// the Ambiq Apollo 3.
#include "tensorflow/lite/micro/debug_log.h"
#include "am_bsp.h" // NOLINT
#include "am_util.h" // NOLINT
extern "C" void DebugLog(const char* s) {
#ifndef TF_LITE_STRIP_ERROR_STRINGS
static bool is_initialized = false;
if (!is_initialized) {
am_bsp_uart_printf_enable();
is_initialized = true;
}
am_util_stdio_printf("%s", s);
#endif
}
// This file is empty to ensure that a specialized implementation of
// debug_log.h is used (instead of the default implementation from
// tensorflow/lite/micro/debug_log.cc).
//
// The actual target-specific implementation of debug_log.h is in
// system_setup.cc since that allows us to consolidate all the target-specific
// specializations into one source file.

View File

@ -1,4 +1,4 @@
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -12,91 +12,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Reference implementation of timer functions. Platforms are not required to
// implement these timer methods, but they are required to enable profiling.
// On platforms that have a POSIX stack or C library, it can be written using
// methods from <sys/time.h> or clock() from <time.h>.
// To add an equivalent function for your own platform, create your own
// implementation file, and place it in a subfolder with named after the OS
// you're targeting. For example, see the Cortex M bare metal version in
// tensorflow/lite/micro/bluepill/micro_timer.cc or the mbed one on
// tensorflow/lite/micro/mbed/micro_timer.cc.
#include "tensorflow/lite/micro/micro_time.h"
#include "tensorflow/lite/micro/debug_log.h"
// These are headers from Ambiq's Apollo3 SDK.
#include "am_bsp.h" // NOLINT
#include "am_mcu_apollo.h" // NOLINT
#include "am_util.h" // NOLINT
namespace tflite {
namespace {
// Select CTIMER 1 as benchmarking timer on Sparkfun Edge. This timer must not
// be used elsewhere.
constexpr int kTimerNum = 1;
// Clock set to operate at 12MHz.
constexpr int kClocksPerSecond = 12e6;
// Enables 96MHz burst mode on Sparkfun Edge. Enable in timer since most
// benchmarks and profilers want maximum performance for debugging.
void BurstModeEnable() {
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);
// Set the default cache configuration
am_hal_cachectrl_config(&am_hal_cachectrl_defaults);
am_hal_cachectrl_enable();
am_hal_burst_avail_e eBurstModeAvailable;
am_hal_burst_mode_e eBurstMode;
// Check that the Burst Feature is available.
int status = am_hal_burst_mode_initialize(&eBurstModeAvailable);
if (status != AM_HAL_STATUS_SUCCESS ||
eBurstModeAvailable != AM_HAL_BURST_AVAIL) {
DebugLog("Failed to initialize burst mode.");
return;
}
status = am_hal_burst_mode_enable(&eBurstMode);
if (status != AM_HAL_STATUS_SUCCESS || eBurstMode != AM_HAL_BURST_MODE) {
DebugLog("Failed to Enable Burst Mode operation\n");
}
}
} // namespace
int32_t ticks_per_second() { return kClocksPerSecond; }
// Calling this method enables a timer that runs for eternity. The user is
// responsible for avoiding trampling on this timer's config, otherwise timing
// measurements may no longer be valid.
int32_t GetCurrentTimeTicks() {
// TODO(b/150808076): Split out initialization, intialize in interpreter.
static bool is_initialized = false;
if (!is_initialized) {
BurstModeEnable();
am_hal_ctimer_config_t timer_config;
// Operate as a 32-bit timer.
timer_config.ui32Link = 1;
// Set timer A to continuous mode at 12MHz.
timer_config.ui32TimerAConfig =
AM_HAL_CTIMER_FN_CONTINUOUS | AM_HAL_CTIMER_HFRC_12MHZ;
am_hal_ctimer_stop(kTimerNum, AM_HAL_CTIMER_BOTH);
am_hal_ctimer_clear(kTimerNum, AM_HAL_CTIMER_BOTH);
am_hal_ctimer_config(kTimerNum, &timer_config);
am_hal_ctimer_start(kTimerNum, AM_HAL_CTIMER_TIMERA);
is_initialized = true;
}
return CTIMERn(kTimerNum)->TMR0;
}
} // namespace tflite
// This file is empty to ensure that a specialized implementation of
// micro_time.h is used (instead of the default implementation from
// tensorflow/lite/micro/micro_time.cc).
//
// The actual target-specific implementation of micro_time.h is in
// system_setup.cc since that allows us to consolidate all the target-specific
// specializations into one source file.

View File

@ -0,0 +1,99 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/micro/system_setup.h"
#include "tensorflow/lite/micro/debug_log.h"
#include "tensorflow/lite/micro/micro_time.h"
// These are headers from Ambiq's Apollo3 SDK.
#include "am_bsp.h" // NOLINT
#include "am_mcu_apollo.h" // NOLINT
#include "am_util.h" // NOLINT
namespace {
// Select CTIMER 1 as benchmarking timer on Sparkfun Edge. This timer must not
// be used elsewhere.
constexpr int kTimerNum = 1;
// Clock set to operate at 12MHz.
constexpr int kClocksPerSecond = 12e6;
// Enables 96MHz burst mode on Sparkfun Edge. Enable in timer since most
// benchmarks and profilers want maximum performance for debugging.
void BurstModeEnable() {
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);
// Set the default cache configuration
am_hal_cachectrl_config(&am_hal_cachectrl_defaults);
am_hal_cachectrl_enable();
am_hal_burst_avail_e eBurstModeAvailable;
am_hal_burst_mode_e eBurstMode;
// Check that the Burst Feature is available.
int status = am_hal_burst_mode_initialize(&eBurstModeAvailable);
if (status != AM_HAL_STATUS_SUCCESS ||
eBurstModeAvailable != AM_HAL_BURST_AVAIL) {
DebugLog("Failed to initialize burst mode.\n");
return;
}
status = am_hal_burst_mode_enable(&eBurstMode);
if (status != AM_HAL_STATUS_SUCCESS || eBurstMode != AM_HAL_BURST_MODE) {
DebugLog("Failed to Enable Burst Mode operation\n");
}
}
} // namespace
// Implementation for the DebugLog() function that prints to the UART on the
// SparkFun Edge microcontroller. The same should work for other targets using
// the Ambiq Apollo 3.
extern "C" void DebugLog(const char* s) {
#ifndef TF_LITE_STRIP_ERROR_STRINGS
am_util_stdio_printf("%s", s);
#endif
}
namespace tflite {
// Calling this method enables a timer that runs for eternity. The user is
// responsible for avoiding trampling on this timer's config, otherwise timing
// measurements may no longer be valid.
void InitializeTarget() {
am_bsp_uart_printf_enable();
BurstModeEnable();
am_hal_ctimer_config_t timer_config;
// Operate as a 32-bit timer.
timer_config.ui32Link = 1;
// Set timer A to continuous mode at 12MHz.
timer_config.ui32TimerAConfig =
AM_HAL_CTIMER_FN_CONTINUOUS | AM_HAL_CTIMER_HFRC_12MHZ;
am_hal_ctimer_stop(kTimerNum, AM_HAL_CTIMER_BOTH);
am_hal_ctimer_clear(kTimerNum, AM_HAL_CTIMER_BOTH);
am_hal_ctimer_config(kTimerNum, &timer_config);
am_hal_ctimer_start(kTimerNum, AM_HAL_CTIMER_TIMERA);
}
int32_t ticks_per_second() { return kClocksPerSecond; }
int32_t GetCurrentTimeTicks() { return CTIMERn(kTimerNum)->TMR0; }
} // namespace tflite

View File

@ -0,0 +1,25 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/micro/system_setup.h"
namespace tflite {
// To add an equivalent function for your own platform, create your own
// implementation file, and place it in a subfolder named after the target. See
// tensorflow/lite/micro/debug_log.cc for a similar example.
void InitializeTarget() {}
} // namespace tflite

View File

@ -0,0 +1,27 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_LITE_MICRO_SYSTEM_SETUP_H_
#define TENSORFLOW_LITE_MICRO_SYSTEM_SETUP_H_
namespace tflite {
// This should called during initialization of TFLM binaries and tests. It can
// be specialized if there is a need for custom target-specific intialization.
// For more information, see tensorflow/lite/micro/system_setup.cc.
void InitializeTarget();
} // namespace tflite
#endif // TENSORFLOW_LITE_MICRO_SYSTEM_SETUP_H_

View File

@ -30,6 +30,7 @@ cc_library(
"//tensorflow/lite/micro:micro_error_reporter",
"//tensorflow/lite/micro:micro_framework",
"//tensorflow/lite/micro:micro_utils",
"//tensorflow/lite/micro:system_setup",
"//tensorflow/lite/micro:test_helpers",
],
)

View File

@ -56,6 +56,7 @@ limitations under the License.
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/system_setup.h"
namespace micro_test {
extern int tests_passed;
@ -64,6 +65,19 @@ extern bool is_test_complete;
extern bool did_test_fail;
} // namespace micro_test
namespace tflite {
// This additional helper function is used (instead of directly calling
// tflite::InitializeTarget from the TF_LITE_MICRO_TESTS_BEGIN macro) to avoid
// adding a dependency from every bazel test target to micro:system_setp (which
// is the target that implements InitializeTarget().
//
// The underlying issue here is that the use of the macros results in
// dependencies that can be containted within the micro/testing:micro_test
// target bleeding on to all the tests.
inline void InitializeTest() { InitializeTarget(); }
} // namespace tflite
#define TF_LITE_MICRO_TESTS_BEGIN \
namespace micro_test { \
int tests_passed; \
@ -74,7 +88,8 @@ extern bool did_test_fail;
\
int main(int argc, char** argv) { \
micro_test::tests_passed = 0; \
micro_test::tests_failed = 0;
micro_test::tests_failed = 0; \
tflite::InitializeTest();
#define TF_LITE_MICRO_TESTS_END \
MicroPrintf("%d/%d tests passed", micro_test::tests_passed, \