/* Copyright 2020 EEMBC and The MLPerf Authors. All Rights Reserved. Copyright (c) 2022 HPMicro 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. This file reflects a modified version of th_lib from EEMBC. The reporting logic in th_results is copied from the original in EEMBC. ==============================================================================*/ /// \file /// \brief C++ implementations of submitter_implemented.h #include "./api/submitter_implemented.h" #include #include #include #include #include #include "api/internally_implemented.h" #include "tensorflow/lite/micro/kernels/micro_ops.h" #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/schema/schema_generated.h" #include "tensorflow/lite/micro/all_ops_resolver.h" #include "util/tf_micro_model_runner.h" #include "util/quantization_helpers.h" #include "tensorflow/lite/micro/system_setup.h" #include "./ic/ic_inputs.h" #include "./ic/ic_model_quant_data.h" #include extern "C" { #include "board.h" } volatile unsigned char gstr[0x100] __attribute__((aligned(4))) = {0}; volatile unsigned char gstr1[0x100] __attribute__((aligned(4))) = {0}; #define timestamp_in_usec ((unsigned long)(((unsigned long long )hpm_csr_get_core_cycle() * (unsigned long long) 1000000) / (unsigned long long) BOARD_CPU_FREQ)) tflite::MicroModelRunner *runner; constexpr int kTensorArenaSize = 100 * 1024; uint8_t tensor_arena_local[kTensorArenaSize]; void th_load_tensor() { uint8_t input_quantized[kIcInputSize]; int8_t input_asint[kIcInputSize]; size_t bytes; bytes = ee_get_buffer(reinterpret_cast(input_quantized), kIcInputSize * sizeof(uint8_t)); if (bytes / sizeof(uint8_t) != kIcInputSize) { th_printf("Input db has %d elemented, expected %d\n", bytes / sizeof(uint8_t), kIcInputSize); return; } uint16_t i = 0; for(i=0; iSetInput(input_asint); } // Add to this method to return real inference results. void th_results() { const int nresults = 10; /** * The results need to be printed back in exactly this format; if easier * to just modify this loop than copy to results[] above, do that. */ th_printf("m-results-["); for (size_t i = 0; i < kCategoryCount; i++) { float converted = DequantizeInt8ToFloat(runner->GetOutput()[i], runner->output_scale(), runner->output_zero_point()); // Some platforms don't implement floating point formatting. th_printf("%0.3f", (double) converted); if (i < (nresults - 1)) { th_printf(","); } } th_printf("]\r\n"); } // Implement this method with the logic to perform one inference cycle. void th_infer() { runner->Invoke(); } /// \brief optional API. void th_final_initialize(void) { static tflite::MicroMutableOpResolver<7> resolver; resolver.AddAdd(); resolver.AddFullyConnected(); resolver.AddConv2D(); resolver.AddDepthwiseConv2D(); resolver.AddReshape(); resolver.AddSoftmax(); resolver.AddAveragePool2D(); //static tflite::AllOpsResolver resolver; static tflite::MicroModelRunner model_runner( pretrainedResnet_quant_tflite, resolver, tensor_arena_local, kTensorArenaSize); runner = &model_runner; } void th_pre() {} void th_post() {} void th_command_ready(char volatile *p_command) { p_command = p_command; ee_serial_command_parser_callback((char *)p_command); } // th_libc implementations. int th_strncmp(const char *str1, const char *str2, size_t n) { return strncmp(str1, str2, n); } char *th_strncpy(char *dest, const char *src, size_t n) { return strncpy(dest, src, n); } size_t th_strnlen(const char *sstr, size_t maxlen) { return strlen(sstr); } char *th_strcat(char *dest, const char *src) { return strcat(dest, src); } char *th_strtok(char *str1, const char *sep) { return strtok(str1, sep); } int th_atoi(const char *str) { return atoi(str); } void *th_memset(void *b, int c, size_t len) { return memset(b, c, len); } void *th_memcpy(void *dst, const void *src, size_t n) { return memcpy(dst, src, n); } int th_vprintf(const char *format, va_list ap) { vsprintf((char *)gstr1, format, ap); printf((char *)gstr1); return 0; } void th_printf(const char *p_fmt, ...) { va_list args; va_start(args, p_fmt); (void)th_vprintf(p_fmt, args); va_end(args); } char th_getchar() { return (char) getchar(); } void th_serialport_initialize(void) { board_init(); tflite::InitializeTarget(); } void th_timestamp(void) { # if EE_CFG_ENERGY_MODE==1 # else unsigned long microSeconds = 0ul; /* USER CODE 2 BEGIN */ //microSeconds = us_ticker_read(); microSeconds = timestamp_in_usec; /* USER CODE 2 END */ /* This message must NOT be changed. */ th_printf(EE_MSG_TIMESTAMP, microSeconds); # endif } void th_timestamp_initialize(void) { /* USER CODE 1 BEGIN */ // Setting up BOTH perf and energy here /* USER CODE 1 END */ /* This message must NOT be changed. */ th_printf(EE_MSG_TIMESTAMP_MODE); /* Always call the timestamp on initialize so that the open-drain output is set to "1" (so that we catch a falling edge) */ th_timestamp(); }