在嵌入式机器学习(TinyML)的学习旅程中,TensorFlow Lite for Microcontrollers 的 “Hello World” 示例是入门的绝佳起点。这个程序虽小,却完整展现了 TinyML 应用的核心架构与执行逻辑。本文将深入剖析该程序的架构设计、setup 与 loop 函数的执行流程,帮助你夯实 TinyML 开发基础。
一、程序整体架构解析
该 Hello World 程序基于 TensorFlow Lite for Microcontrollers 构建,旨在在嵌入式设备(如 Arduino)上运行一个简单的机器学习模型,实现类似正弦函数的预测,并通过 LED 亮度变化直观展示结果。整体架构可分为以下几个核心模块:
1. 模型模块(model.h & model.cpp)
- 功能:存储 TensorFlow Lite 模型的二进制数据。
- 生成方式:通过命令
xxd -i model.tflite > ``model.cc(即model.cpp)将 TensorFlow Lite 模型文件(.tflite)转换为 C 语言数组,以便在无文件系统的嵌入式设备中编译执行。 - 代码解析:
model.h中声明了模型数组g_model和模型长度g_model_len,用于对外暴露模型数据。model.cpp中定义了g_model数组,存储了模型的二进制字节数据,且通过alignas(16)保证内存对齐,以兼容 CMSIS 等硬件加速库。
2. 输出处理模块(output_handler.h & arduino_output_handler.cpp)
- 功能:将模型输出转换为硬件可执行的操作(如控制 LED 亮度)。
- 代码解析:
output_handler.h声明了HandleOutput函数,用于处理模型输出的x和y浮点值。arduino_output_handler.cpp实现了HandleOutput:初始化 LED 引脚为输出模式,将模型输出的y值映射为 0-255 的亮度值,最终通过 PWM 控制 LED 亮度变化。
3. 常量定义模块(constants.h & arduino_constants.cpp)
- 功能:定义程序运行所需的常量,如输入范围、推理次数等。
- 代码解析:
constants.h定义了kXRange(模型训练的 x 范围,即 $ 2\pi $)和kInferencesPerCycle(每轮推理的次数,需在.cpp中定义具体值)。arduino_constants.cpp定义了kInferencesPerCycle = 200,用于控制一次完整周期的推理次数,从而调整 LED 变化的时间节奏。
4. 主程序模块(hello_world.ino 相关逻辑)
-
功能:串联模型加载、推理执行、输出处理等流程,是程序的控制核心。
-
核心组件:
- 模型解释器(
tflite::MicroInterpreter):负责加载模型并执行推理。 - 张量内存池(
tensor_arena):为模型推理过程中的张量运算提供内存空间。 setup函数:初始化硬件、模型解释器等资源。loop函数:循环执行推理流程,实现持续运行。
- 模型解释器(
二、setup 函数执行流程解析
setup 函数是 Arduino 程序的初始化入口,在该 TinyML 程序中,它承担了硬件初始化、模型加载、解释器配置的核心任务。以下是其执行流程图与步骤详解:
步骤 1:硬件目标初始化
tflite::InitializeTarget();
- 功能:初始化嵌入式设备的硬件环境(如时钟、外设等),为后续操作铺路。
步骤 2:加载模型二进制数据
model = tflite::GetModel(g_model);
if (model->version() != TFLITE_SCHEMA_VERSION) {
; MicroPrintf("Model version mismatch!\n");
; return;
}
- 功能:从
model.cpp的g_model数组中加载 TensorFlow Lite 模型,并校验模型版本是否与当前 TensorFlow Lite 库兼容。
步骤 3:初始化操作解析器
static tflite::AllOpsResolver resolver;
- 功能:创建操作解析器,用于识别并执行模型中的各类运算(如卷积、全连接等)。
AllOpsResolver包含了 TensorFlow Lite for Microcontrollers 支持的所有操作。
步骤 4:分配张量内存池
alignas(16) uint8_t tensor_arena[kTensorArenaSize];
- 功能:在内存中分配一块连续区域(
tensor_arena),用于存储模型推理过程中产生的张量数据。alignas(16)保证内存对齐,以提升硬件加速(如 CMSIS-NN)的效率。
步骤 5:创建模型解释器
interpreter = new tflite::MicroInterpreter(
; model, resolver, tensor_arena, kTensorArenaSize);
TfLiteStatus allocate_status = interpreter->AllocateTensors();
if (allocate_status != kTfLiteOk) {
; MicroPrintf("AllocateTensors() failed\n");
; return;
}
- 功能:实例化模型解释器,并为模型中的所有张量分配内存(通过
AllocateTensors完成)。若内存分配失败,程序会打印错误信息并退出。 - 模型解释器(tflite::MicroInterpreter) 是整个 TinyML 程序的 “核心大脑”,它的输入输出关系,其实和我们日常用的 “计算器” 很像,只不过它能处理更复杂的 “计算任务”(比如根据输入的 x 值,预测正弦函数的 y 值)。
步骤 6:获取输入 / 输出张量
input = interpreter->input(0);
output = interpreter->output(0);
- 功能:获取模型的输入张量和输出张量,方便后续向模型喂入数据并读取推理结果。
步骤 7:初始化推理计数
inference_count = 0;
- 功能:初始化推理次数计数器,用于控制模型在 “一个周期” 内的推理轮次。
三、loop 函数执行流程解析
loop 函数是 Arduino 程序的循环执行入口,在该 TinyML 程序中,它实现了数据生成、模型推理、结果输出的完整闭环。以下是其执行流程图与步骤详解:

步骤 1:计算当前推理在周期中的位置
float position = static_cast<float>(inference_count) ;
; static_cast<float>(kInferencesPerCycle);
- 功能:计算当前推理次数在 “一个周期(共
kInferencesPerCycle次推理)” 中的相对位置(范围[0, 1))。
步骤 2:生成输入 x 值
float x = position * kXRange;
- 功能:根据位置
position和模型训练范围kXRange(即 2 p i 2pi 2pi),生成当前的输入值x(范围[0, 2pi))。
步骤 3:量化输入 x 值
int8_t x_quantized = x / input->params.scale + input->params.zero_point;
- 功能:由于 TinyML 模型通常使用量化技术(如 int8 量化)以减少内存占用和计算量,因此需要将浮点型的
x量化为 int8 类型。量化公式为:量化值 = 浮点值 / 量化缩放 + 量化零点。
步骤 4:将量化后的数据送入输入张量
input->data.int8[0] = x_quantized;
- 功能:将量化后的
x_quantized存入模型的输入张量中,为推理做准备。
步骤 5:执行模型推理
TfLiteStatus invoke_status = interpreter->Invoke();
- 功能:调用模型解释器的
Invoke方法,执行模型推理过程。
步骤 6:校验推理状态
if (invoke_status != kTfLiteOk) {
; MicroPrintf("Invoke failed on x: %f\n", static_cast<double>(x));
; return;
}
- 功能:检查推理是否成功。若失败,打印错误信息并退出本轮循环。
步骤 7:反量化输出 y 值
int8_t y_quantized = output->data.int8[0];
float y = (y_quantized - output->params.zero_point) * output->params.scale;
- 功能:将模型输出的量化值
y_quantized反量化为浮点型y,公式为:浮点值 = (量化值 - 量化零点) * 量化缩放。
步骤 8:处理输出(控制 LED 亮度)
HandleOutput(x, y);
- 功能:调用
HandleOutput函数,将x和y转换为 LED 亮度控制信号。在arduino_output_handler.cpp中,y值被映射为 0-255 的亮度值,最终通过 PWM 控制 LED 亮度变化。
步骤 9:推理计数 + 1 并判断周期是否完成
inference_count++;
if (inference_count >= kInferencesPerCycle) {
; inference_count = 0;
}
- 功能:更新推理计数器,若完成一个周期(
kInferencesPerCycle次推理),则重置计数器,开始下一个周期。
四、总结
TensorFlow Lite for Microcontrollers 的 Hello World 程序虽小,却完整覆盖了 TinyML 应用的核心流程:模型加载与初始化→输入数据生成与量化→模型推理→输出数据反量化与硬件控制。
通过 setup 函数的初始化流程,程序完成了硬件、模型、解释器的配置;而 loop 函数的循环执行,则实现了 “数据输入→推理→输出” 的持续运转。理解这一架构与流程,是你深入探索 TinyML 应用(如传感器数据分类、手势识别等)的重要基石。
如果你想进一步学习,可以尝试修改 kInferencesPerCycle 调整 LED 变化速度,或替换模型以实现更复杂的任务(如识别不同的声音、动作等),亲自感受 TinyML 在嵌入式设备上的强大潜力!
推荐一个“Tiny ML”的网站:链接: Hackster 官网
TinyML 入门:Hello World 程序架构与执行流程深度解析&spm=1001.2101.3001.5002&articleId=154832036&d=1&t=3&u=deb17d45207a4f23bbf653b0dbc272d6)
1184

被折叠的 条评论
为什么被折叠?



