RIOT 中的 uTensor MNIST 手写数字识别示例:从 TensorFlow 模型训练到 MCU 端推理
物联网嵌入式操作系统实时系统【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址https://gitcode.com/GitHub_Trending/riot/RIOT点击查看免费下载导读本文围绕 RIOT 仓库 tests/pkg/utensor/README.md 展开系统讲解如何在一个嵌入式 IoT 操作系统 RIOT 上运行 uTensor 深度学习推理引擎用 TensorFlow 训练一个 MLP多层感知机模型在 MNIST 数据集上完成手写数字识别并通过utensor-cli工具把模型与权重转换为 C 代码静态烧写进固件后在 MCU 上执行推理。读完本文你将掌握该示例的构建运行方法、如何更换待识别数字、以及如何重新训练模型并重新生成 C 模型文件的完整工作流。示例概览在 MCU 上跑一个神经网络uTensor 是面向 MCU 的轻量级深度学习推理框架。本示例应用展示了一条完整的端到端链路使用 TensorFlow 在 MNIST 数据集上训练一个 MLPMulti-Layer Perceptron模型用于识别图像中的手写数字0–9通过utensor-cli将训练好的模型Protocol Buffer 格式的.pb文件转换为 C 源码模型结构 权重将 C 模型文件作为 RIOT 的外部模块external module编译进固件把一张 MNIST 测试集图片以二进制 blob 形式嵌入固件在设备上运行推理并打印预测的标签。该应用的代码源自一个公开的博客示例Hackster.io 上的 Simple Neural Network on MCUs由 RIOT 团队Inria适配进仓库版权信息见 main.cpp 头部注释。应用运行时输出如下Simple MNIST end-to-end uTensor cli example (device) Predicted label: 7仓库自带的自动化测试 tests/01-run.py 正是通过child.expect_exact(Predicted label: 7)来校验该默认输出确保端到端推理链路可用。快速构建与运行在具备 RIOT 工具链make 对应架构的交叉编译器的机器上进入示例目录并指定目标板卡即可编译并打开串口终端make BOARDboard of your choice all term例如使用native板卡或任意 RAM/Flash 充足的开发板。term目标会编译完成后直接打开终端连接设备的串口便于观察推理输出。内存约束并非所有板卡都能跑神经网络的权重文件 deep_mlp_weight.hpp 约 650 KB包含所有层权重加上 uTensor 运行时对板卡的 RAM/Flash 有一定要求。仓库在 Makefile.ci 中显式声明了BOARD_INSUFFICIENT_MEMORY列表如bluepill-stm32f103c8、nucleo-f103rb、microbit、samd10-xmini、stm32f0discovery等数十块小内存板卡CI 会跳过这些内存不足的板卡。选择板卡时建议优先选用内存充足的型号例如nucleo-f746zg、esp32-wroom-32等否则可能链接失败。同时Makefile 中通过CFLAGS -DTHREAD_STACKSIZE_MAINTHREAD_STACKSIZE_LARGE为main线程分配更大的栈空间以满足 uTensor 推理时的栈需求。输入数字从哪来blob 机制待识别的手写数字图片存放在应用目录下的digit二进制文件中28×28 像素、每像素以 float32 存储共 28×28×4 3136 字节。构建时它通过 RIOT 构建系统的blob 机制Makefile 中的BLOBS digit被自动转换为一个 C 数组digit以静态数据的方式嵌入固件镜像。在 main.cpp 中可以看到完整的推理主流程alignas(float) #include blob/digit.h // 嵌入的 MNIST 测试图片float32 数组 #include deep_mlp.hpp // utensor-cli 生成的模型文件 #include tensor.hpp // uTensor 张量类 int main() { puts(Simple MNIST end-to-end uTensor cli example (device)\n); // 创建上下文推理在该上下文中执行 Context ctx; // blob 以字节存储借助 alignas(float) 保证对齐后转为 float 指针 float *digit_as_float (float *)(uintptr_t)digit; // 把输入图片包装成张量{1, digit_len 2}digit_len 为字节数2 得到 float 个数784 auto input_x new WrappedRamTensorfloat({1, digit_len 2}, digit_as_float); // 将输入张量的所有权移交给 context并注册模型计算图 get_deep_mlp_ctx(ctx, input_x); // 取输出张量引用并触发推理 S_TENSOR pred_tensor ctx.get(y_pred:0); ctx.eval(); // 读取预测标签one-hot 向量中的最大索引并打印 uint8_t pred_label *(pred_tensor-readint(0, 0)); printf(Predicted label: %d\r\n, pred_label); return 0; }关键点解析get_deep_mlp_ctx(ctx, input_x)由utensor-cli生成声明见 deep_mlp.hpp其实现 deep_mlp.cpp 内部通过ctx.add(...)、ctx.push(new MatMulOp()/new QuantizedMatMulOp()...)等调用把整个计算图占位符、reshape、量化、矩阵乘法、Softmax 等算子注册进Context输出张量名为y_pred:0对应 README 中utensor-cli convert命令的--output-nodesy_predctx.eval()触发整张计算图的执行。更换待识别数字默认的digit文件包含 MNIST 测试集的第一张图片——一个手写的7。你可以用示例自带的 Python 脚本 generate_digit.py 从 MNIST 测试集中选取其他图片重新生成digit文件./generate_digit.py --index 1脚本参数说明参数默认值含义-i, --index0在 MNIST 测试集中选取的图片索引-o, --outputdigit输出二进制文件名--no-plotFalse禁用 matplotlib 弹出图片窗口脚本会调用tf.keras.datasets.mnist.load_data()加载 MNIST 测试集取第index张图片将其astype(float32)后以二进制原样写入digit文件与 blob 机制的 float32 布局一致。每个选中的数字在脚本结束时都会以图像形式显示出来方便与固件预测出的标签做目测对比。需要注意每次生成新的 digit 后固件必须重新编译——图片是作为 blob 静态嵌入固件镜像的不重新烧写固件就无法生效make BOARDboard of your choice all flash term重新训练模型并更新 C 模型文件应用默认包含一个预训练模型存放在external_modules/models外部模块中除 Makefile 外所有 C 文件——模型结构 权重——均由utensor-cli从 TensorFlow 训练的模型自动生成。如果希望训练新模型并同步更新应用中的 C 文件可按以下步骤操作。1. 安装 Python3 依赖pip3 install --user utensor_cgen graphviz pip3 install --user tensorflow -U注意utensor_cgen目前仅兼容 TensorFlow 1.x请勿使用 TensorFlow 2.x 执行下述转换流程。2. 克隆 utensor-mnist-demo 仓库该仓库包含在 MNIST 数据集上训练 MLP 模型的 Python 脚本cd /tmp git clone uTensor/utensor-mnist-demo 仓库地址3. 训练 MLP 模型cd /tmp/utensor-mnist-demo python3 /tmp/utensor-mnist-demo/tensorflow-models/deep_mlp.py训练完成后模型以 Protocol Buffer 格式存放在/tmp/utensor-mnist-demo/mnist_model/deep_mlp.pb4. 生成 C 模型文件并纳入 RIOT 构建cd $RIOTBASE/tests/pkg/utensor utensor-cli convert /tmp/utensor-mnist-demo/mnist_model/deep_mlp.pb --target utensor --output-nodesy_pred该命令会在当前目录应用目录生成模型与权重 C 文件deep_mlp.cpp/deep_mlp.hpp/deep_mlp_weight.hpp随后即可重新编译固件。生成结果需覆盖或替换 external_modules/models 目录下的同名文件。外部模块如何接入 RIOT 构建生成的模型 C 文件通过 RIOT 的外部模块机制接入构建系统。相关配置集中在应用的 Makefileinclude ../Makefile.pkg_common USEPKG utensor # 引入 uTensor 包pkg/utensor # Include input data as blob BLOBS digit # 将 digit 二进制文件作为 blob 嵌入固件 # Include C model and training weights code as an external module USEMODULE models EXTERNAL_MODULE_DIRS external_modulesUSEPKG utensor声明依赖 pkg/utensor 外部包uTensor 推理引擎的源码由此获得EXTERNAL_MODULE_DIRS external_modules把external_modules目录加入外部模块搜索路径其中的models子模块含Makefile与Makefile.include被USEMODULE models拉入构建models/Makefile仅包含include $(RIOTBASE)/Makefile.base声明这是一个标准模块models/Makefile.include 则负责把头文件目录加入USEMODULE_INCLUDES并追加CXXEXFLAGS -Wno-unused-parameter抑制生成代码中未使用参数的告警生成的模型代码使用了 C如new、模板类因此该示例依赖 C 工具链支持RIOT 的 C 支持。小结一条可复用的 MCU 端 ML 流水线该示例完整演示了在 RIOT 上落地一个端到端 ML 应用的标准路径训练侧TensorFlow1.x训练 MLP → 导出.pb模型转换侧utensor-cli convert --target utensor --output-nodesy_pred生成 C 模型与权重集成侧USEPKGUSEMODULEEXTERNAL_MODULE_DIRS接入 RIOT 构建BLOBS机制静态嵌入输入数据推理侧ContextWrappedRamTensorctx.eval()在 MCU 上完成前向计算输出预测标签。对于希望把更大模型CNN、量化模型等搬到 RIOT uTensor 上的开发者本文的每一步都可直接复用更换训练脚本产出新的.pb重新执行utensor-cli convert再调整main.cpp中的输入输出张量名即可。赞分享物联网嵌入式操作系统实时系统【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址https://gitcode.com/GitHub_Trending/riot/RIOT点击查看免费下载相关推荐Caffe MNIST手写数字识别实战从数据准备到模型训练完整流程Caffe MNIST手写数字识别实战从数据准备到模型训练完整流程 想要快速入门深度学习实战Caffe框架结合MNIST手写数字识别项目是完美的起点深度学习计算机视觉机器学习使用GGML实现MNIST手写数字识别从训练到推理全流程解析使用GGML实现MNIST手写数字识别从训练到推理全流程解析 项目概述 GGML是一个专注于机器学习模型推理的轻量级库特别适合在资源受限的环境中运行。本文将人工智能机器学习深度学习算子库本地部署模型量化Caffe 实战在 MNIST 上训练 LeNet 手写数字识别模型从数据准备到训练部署全流程Caffe 实战在 MNIST 上训练 LeNet 手写数字识别模型从数据准备到训练部署全流程 本文以 Caffe 官方 MNIST 示例为线索完整讲解深度学习计算机视觉上一篇Envoy Google VRP 安全赏金计划实战双 Envoy 边界/源站架构、威胁模型与 Docker 执行环境下一篇Elasticsearch Node.js客户端错误处理与重试机制构建稳定应用的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Aider 实战:TaoToken 当默认供应商跑通仓库内 Python 模块的 Rust 重写

Aider 实战:TaoToken 当默认供应商跑通仓库内 Python 模块的 Rust 重写

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 23:31:48 阅读更多 →
Apache RocketMQ 持久化唯一 BrokerId:Controller 模式下 Broker 身份标识设计与升级实战

Apache RocketMQ 持久化唯一 BrokerId:Controller 模式下 Broker 身份标识设计与升级实战

消息队列后端微服务流处理 【免费下载链接】rocketmq Apache RocketMQ is a cloud native messaging and streaming platform, making it simple to build event-driven applications. 项目地址: https://gitcode.com/gh_mirrors/ro/rocketmq 点击查看 免费下载 导…

2026/9/20 23:31:48 阅读更多 →
Axios 投毒自查,Codex 连上 TaoToken 后能跑通 npm 检查

Axios 投毒自查,Codex 连上 TaoToken 后能跑通 npm 检查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 23:31:48 阅读更多 →

最新新闻

低功耗Bandgap设计实战:结构、启动电路与验证方法

低功耗Bandgap设计实战:结构、启动电路与验证方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 3:22:53 阅读更多 →
国产替代Simulink的工程评估:从建模、代码生成到工具链的差距与可行路径

国产替代Simulink的工程评估:从建模、代码生成到工具链的差距与可行路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 3:22:53 阅读更多 →
上千篇笔记一键整理:Foam标签、Query查询与智能文件夹进阶指南

上千篇笔记一键整理:Foam标签、Query查询与智能文件夹进阶指南

上千篇笔记一键整理:Foam标签、Query查询与智能文件夹进阶指南 【免费下载链接】foam A personal knowledge management and sharing system for VSCode 项目地址: https://gitcode.com/gh_mirrors/fo/foam Foam 是基于 VSCode 的个人知识管理与笔记分享系统…

2026/9/21 3:22:53 阅读更多 →
在 Chrome 打包应用中集成 AppEngine Channel API:WebView 代理桥接架构实战

在 Chrome 打包应用中集成 AppEngine Channel API:WebView 代理桥接架构实战

在 Chrome 打包应用中集成 AppEngine Channel API:WebView 代理桥接架构实战 【免费下载链接】chrome-extensions-samples Chrome Extensions Samples 项目地址: https://gitcode.com/gh_mirrors/ch/chrome-extensions-samples 本篇技术指南围绕 chrome-exte…

2026/9/21 3:22:53 阅读更多 →
Deep Research 对话标题

Deep Research 对话标题

AI 应用前端 【免费下载链接】voyager Enhancement suite for Gemini, AI Studio, Claude & ChatGPT — plus a prompt manager for any websites, DeepSeek Harness included. / 面向 Gemini、AI Studio、Claude 与 ChatGPT 的增强套件;其中的提示词管理器可用…

2026/9/21 3:22:53 阅读更多 →
STM32智能婴儿床毕设实战:从方案设计到答辩完整指南

STM32智能婴儿床毕设实战:从方案设计到答辩完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 3:21:53 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →