到现在已经完成两个实验了,但是都是在编译和测试别人的东西,那如何移植到我们熟悉的IDE,比如古董Keil(其实我也不喜欢,但是Team里都用这个,我也没办法!),所幸X-CUBE-AI能给到很大的帮助.他是STM32CubeMX内的一个组件.但是Cube只能支持M4/M7/M23/M33/M35P/M55等等(最低推荐架构:ARMv7E-M),大尺寸低配MCU不常见,比如STM32F030RB,手动移植即可.
注意:目前支持依然有点问题,模型文件不知道被他转换到哪里去了,不过他能帮忙添加目录结构也是挺好的.
在新建CubeMX工程后选择顶部的Software Pack并添加X-CUBE-AI组件,选择Core以及应用为Not Selected.
从软件中Add Network.
模型还是从这里获取:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/micro/examples/hello_world/train/train_hello_world_model.ipynb,最终要的文件是这个.
从左侧文件浏览中下载他,然后直接在Cube加载并分析.
- 如果选的是CubeAI框架,那么可以节约很多编译时间.
- 如果选的是Tensorflow Micro框架,则可以有和TinyML一样的原生开发体验.
然后可以进行验证测试,我是NUCLEO-H723ZG,PD8/PD9作为USART3的Bootloader下载接口,其他的要自行看原理图,编译工程需要不少时间,耐心等等,由于没有配备验证解雇集,所以能跑就不错了.
然后其他按照自己喜欢配置,最后生成工程,最后编译还缺了个文件:
缺了的东西要补上(主要是ST软件开小差忘了复制了吧,如果要提交到Git,最好是包含官方工程的submodule而不是全部打包.),然后重新添加Keil工程里Application/User/X-CUBE-AI/App缺失的syscall文件.
然后micro_error_reporter没有定义,从前面的学习知道,这个其实就应该映射为串口输出.暂时不想实现他就可以在主函数写个dummy函数.
void DebugLog(const char* s){
__nop();
}
然后C文件还要CPP化,最后把代码移植过去.(完整版请查看:https://gist.github.com/nickfox-taterli/f21dba55a2118a95406547253ff7141a 完成工程:https://github.com/nickfox-taterli/KeilCube_TfMciro)
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define TFLITE_SCHEMA_VERSION (3)
const int kInferencesPerCycle = 1000;
const float kXrange = 2.f * 3.14159265359f;
// Globals, used for compatibility with Arduino-style sketches.
namespace {
tflite::ErrorReporter* error_reporter = nullptr;
const tflite::Model* model = nullptr;
tflite::MicroInterpreter* interpreter = nullptr;
TfLiteTensor* input = nullptr;
TfLiteTensor* output = nullptr;
int inference_count = 0;
constexpr int kTensorArenaSize = 2000;
uint8_t tensor_arena[kTensorArenaSize];
}
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
alignas(8) const unsigned char g_model[] = {
0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x14, 0x00, 0x20, 0x00,
....
0x00, 0x00, 0x00, 0x09};
const int g_model_len = 2488;
/* USER CODE END PV */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void DebugLog(const char* s){
__nop();
}
void HandleOutput(tflite::ErrorReporter* error_reporter, float x_value,
float y_value) {
// 从例子中挪过来
}
void setup() {
// 从例子中挪过来
}
void loop() {
// 从例子中挪过来
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 2 */
setup();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
loop();
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
查看输出.