Skip to content

Commit 9407f8d

Browse files
Model Conversion and Code Integration
1 parent c1d0fa7 commit 9407f8d

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# 模型转换与代码集成
2+
3+
在 openvela 开发中,由于微控制器 (MCU) 的 RAM 资源受限且文件系统支持可能被裁剪,直接读取 .tflite 文件通常不可行。标准做法是将训练好的 TensorFlow Lite 模型转换为 C 语言数组,作为只读数据 (RODATA) 编译到应用程序固件中,直接从 Flash 执行读取。
4+
5+
本节将指导开发者如何将模型转换为 C 数组,并将其集成到 openvela 的 C++ 应用(如 helloxx)中。
6+
7+
## 一、模型转换 (TFLite 转 C 数组)
8+
9+
为了将模型嵌入固件,我们需要使用工具将 `.tflite` 二进制文件转换为 C 源代码文件。
10+
11+
### 1、准备模型文件
12+
13+
本教程使用 TensorFlow Lite Micro 官方的 Hello World 模型(正弦波预测)。为了配合下文的代码逻辑,我们需要下载 Float32(浮点)版本的模型。
14+
15+
- 下载地址:[hello_world_float.tflite](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/hello_world/models/hello_world_float.tflite) (Google 官方示例)
16+
17+
请将下载的文件重命名为 `converted_model.tflite` 并放置在当前目录下。
18+
19+
### 2、使用 xxd 工具转换
20+
21+
在 Linux/Unix 环境下,使用 `xxd` 命令即可生成包含模型数据的源文件:
22+
23+
```Bash
24+
# 将 converted_model.tflite 转换为 model_data.cc
25+
xxd -i converted_model.tflite > model_data.cc
26+
```
27+
28+
### 3、优化模型数组声明
29+
30+
`xxd` 生成的默认输出类似如下:
31+
32+
```c++
33+
unsigned char converted_model_tflite[] = { 0x18, 0x00, ...};
34+
unsigned int converted_model_tflite_len = 18200;
35+
```
36+
37+
**关键优化步骤**:
38+
39+
为了节省宝贵的 RAM 资源并确保程序稳定运行,**必须**对生成的数组进行修改:
40+
41+
1. **添加 `const`**:将模型数据放置在 Flash (RODATA段) 中,避免占用 RAM。
42+
2. **添加内存对齐**:TFLite Micro 要求模型数据首地址必须 16 字节对齐。
43+
44+
请打开 `model_data.cc`,复制其中的数组内容,将其直接粘贴到主程序文件 `helloxx_main.cxx` 中(推荐):
45+
46+
```C++
47+
// 添加 alignas(16) 以满足 TFLite 的内存对齐要求
48+
// 添加 const 将数据放入 Flash,节省 RAM
49+
alignas(16) const unsigned char converted_model_tflite[] = {
50+
0x18, 0x00, ...
51+
};
52+
const unsigned int converted_model_tflite_len = 18200;
53+
```
54+
55+
## 二、集成到应用程序
56+
57+
本节以修改 openvela 中的标准 C++ 示例程序 `apps/examples/helloxx` 为例,展示如何集成 TFLite Micro。
58+
59+
### 1、修改构建系统
60+
61+
在应用编译时,需要包含 TFLite Micro 的头文件路径和构建规则。编辑 `apps/examples/helloxx/CMakeLists.txt`,可以参考以下内容:
62+
63+
```Bash
64+
if(CONFIG_EXAMPLES_HELLOXX)
65+
nuttx_add_application(
66+
NAME
67+
helloxx
68+
STACKSIZE
69+
10240
70+
MODULE
71+
${CONFIG_EXAMPLES_HELLOXX}
72+
SRCS
73+
helloxx_main.cxx
74+
DEPENDS
75+
tflite_micro
76+
DEFINITIONS
77+
TFLITE_WITH_STABLE_ABI=0
78+
TFLITE_USE_OPAQUE_DELEGATE=0
79+
TFLITE_SINGLE_ROUNDING=0
80+
TF_LITE_STRIP_ERROR_STRINGS
81+
TF_LITE_STATIC_MEMORY
82+
COMPILE_FLAGS
83+
-Wno-error)
84+
endif()
85+
```
86+
87+
### 2、修改配置
88+
89+
- 参考[配置 TFLite Micro 开发环境](./configure_tflite_micro_dev_env.md),配置编译环境与依赖库。
90+
- 启用示例应用:在配置菜单 (`menuconfig`) 中,定位到 `Application Configuration` -> `Examples`,勾选 `"Hello, World!" C++ example` (即 `helloxx`)。
91+
92+
### 3、实现推理逻辑
93+
94+
在代码中集成 TFLite Micro 主要包含五个标准步骤:
95+
96+
1. **加载模型**:从 C 数组加载模型结构。
97+
2. **注册算子**:实例化 `OpResolver` 并注册模型所需的算子(Operators)。
98+
3. **准备环境**:实例化 `Interpreter` 并分配 Tensor Arena(张量内存池)。
99+
4. **写入输入**:将传感器数据或测试数据填入输入张量。
100+
5. **执行与读取**:调用 `Invoke()` 并读取输出张量。
101+
102+
打开 `apps/examples/helloxx/helloxx_main.cxx`,需包含以下核心逻辑:
103+
104+
```C++
105+
#include <cstdio>
106+
#include <syslog.h>
107+
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
108+
#include "tensorflow/lite/micro/micro_interpreter.h"
109+
#include "tensorflow/lite/schema/schema_generated.h"
110+
111+
// ==========================================================
112+
// 模型数据定义 (建议直接粘贴 xxd 生成的内容并修改修饰符)
113+
// ==========================================================
114+
alignas(16) const unsigned char converted_model_tflite[] = {
115+
// ... 这里粘贴 xxd -i 生成的具体十六进制数据 ...
116+
0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, // 示例头
117+
// ... 省略中间数据 ...
118+
};
119+
const unsigned int converted_model_tflite_len = 18200; // 请填写实际长度
120+
121+
static void test_inference(const void* file_data, size_t arenaSize) {
122+
// 1. 加载模型
123+
const tflite::Model* model = tflite::GetModel(file_data);
124+
125+
// 2. 注册算子
126+
// 注意:此处仅注册了 FullyConnected 算子,请根据实际模型需求添加
127+
tflite::MicroMutableOpResolver<1> resolver;
128+
resolver.AddFullyConnected(tflite::Register_FULLY_CONNECTED());
129+
130+
// 3. 分配内存与实例化解释器
131+
std::unique_ptr<uint8_t[]> pArena(new uint8_t[arenaSize]);
132+
// 创建一个解释器实例。解释器需要模型、算子解析器、内存缓冲区作为输入
133+
tflite::MicroInterpreter interpreter(model,
134+
resolver, pArena.get(), arenaSize);
135+
136+
// 分配张量内存
137+
interpreter.AllocateTensors();
138+
139+
// 4. 写入输入数据
140+
TfLiteTensor* input_tensor = interpreter.input(0);
141+
float* input_tensor_data = tflite::GetTensorData<float>(input_tensor);
142+
143+
// 测试用例:输入 x = π/2 (1.5708),期望模型输出 y ≈ 1.0
144+
float x_value = 1.5708f;
145+
input_tensor_data[0] = x_value;
146+
147+
// 5. 执行推理
148+
interpreter.Invoke();
149+
150+
// 读取输出结果
151+
TfLiteTensor* output_tensor = interpreter.output(0);
152+
float* output_tensor_data = tflite::GetTensorData<float>(output_tensor);
153+
printf("Output value after inference: %f\n", output_tensor_data[0]);
154+
}
155+
```
156+
157+
### 4、验证结果
158+
159+
编译并烧录固件后,运行 `helloxx` 命令,终端应输出如下推理结果:
160+
161+
```Plain
162+
Output value after inference:0.99999 (值接近 1.0 即为成功)
163+
```
164+
165+
若输出值接近 1.0,表明模型已成功在 openvela 平台上加载并完成了一次正弦波推理计算。

0 commit comments

Comments
 (0)