(二)TinyML 入门:Hello World 程序架构与执行流程深度解析

在嵌入式机器学习(TinyML)的学习旅程中,TensorFlow Lite for Microcontrollers 的 “Hello World” 示例是入门的绝佳起点。这个程序虽小,却完整展现了 TinyML 应用的核心架构与执行逻辑。本文将深入剖析该程序的架构设计、setuploop 函数的执行流程,帮助你夯实 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 函数,用于处理模型输出的 xy 浮点值。
    • 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.cppg_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 函数,将 xy 转换为 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 官网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值