- 人工智能
- 深度学习
- 推理引擎
- 本地部署
- 嵌入式
- 物联网
【免费下载链接】tflite-micro
Infrastructure to enable deployment of ML models to low-power resource-constrained embedded targets (including microcontrollers and digital signal processors).
tflite-micro 的data/continuous_builds目录沉淀着一套由持续构建(Continuous Build)工作流自动生成的监控产物,其核心是若干记录二进制体积的 CSV 时序数据与配套的趋势图。本文以 data/continuous_builds/README.md 为骨架,结合仓库内真实产物与tensorflow/lite/micro/tools/metrics/下的生成脚本,系统讲解这套体积监控体系的产物格式、生成管线、三个被监控二进制的测量语义、阈值回归检测机制,以及如何在本地完整复现这套流程,帮助你掌握"用尺寸数据度量并发现性能波动"的完整实战方案。
目录结构:一次 CI 构建沉淀下来的监控产物
依据 data/continuous_builds/README.md,该目录"包含持续构建工作流自动生成的产物(artifacts),意图是监控这些产物(例如体积数据),以度量并发现任何性能波动";长期目标则是"基于这些产物,通过某种 Dashboard 持续监控这些性能数据点"。
当前仓库中实际的产物布局如下:
data/continuous_builds/ ├── README.md └── size_profiling/ └── linux_x86_64_release/ # 目标平台 + 架构 + 构建类型 ├── baseline_memory_footprint.csv ├── baseline_memory_footprint.png ├── interpreter_memory_footprint.csv ├── interpreter_memory_footprint.png ├── keyword_benchmark.csv └── keyword_benchmark.png目录命名linux_x86_64_release由TARGET(linux)、TARGET_ARCH(x86_64)与BUILD_TYPE(release)三部分拼接而成,即"每个目标平台/构建配置"各占一个子目录。目录内每个被监控的二进制对应一对文件:.csv是可追加的时序体积记录,.png是脚本自动绘制的历史趋势图(另外两个图见 baseline_memory_footprint.png 与 interpreter_memory_footprint.png)。这套 CI 的整体机制(分层测试、审批门、Merge Queue 等)可参见 docs/continuous_integration.md。
CSV 数据格式:把二进制体积变成可追溯的时间序列
每个.csv文件都是一张扁平时序表,表头固定为:
| 字段 | 含义 |
|---|---|
date | 采样时间戳(YYYY-MM-DD HH:MM:SS.ffffff,来自datetime.datetime.now()) |
sha | 构建时仓库 HEAD 的 40 位 Git commit SHA |
text | ELF 可执行文件中 text 段(代码段)体积,单位字节 |
data | data 段(已初始化数据)体积,单位字节 |
bss | bss 段(未初始化数据)体积,单位字节 |
total | 三者之和,即体积总量,单位字节 |
字段定义可在 create_size_log.py 中直接看到:脚本先按这六列创建(或复用)CSV,再把size命令输出的text、data、bss与dec四列逐一追加为一行,其中dec列被映射为total。
以baseline_memory_footprint.csv为例,仓库内首行与末行的真实数据为:
date,sha,text,data,bss,total 2022-01-10 23:04:44.309131,c53927869b2ce15345c6c1751164ca6e4aa47c02,1394,520,8,1922 ... 2022-07-14 13:15:35.665349,0e825b99b34596907f53e1fa245028576414cfd0,1433,568,8,2009可以看到total恒等于text + data + bss(如1394+520+8=1922)。这份数据从 2022-01-10 持续采样到 2022-07-14,接近半年、整体高频(多数日期 1~2 条)的累积记录,并保留了每次采样对应的 commit SHA,使任何一次体积变化都能回溯到具体提交——这正是"可监控、可检测、可追溯"的数据基础。
生成管线:脚本如何从"编译"走到"检测"
体积产物的生成与检测由tensorflow/lite/micro/tools/metrics/下三个脚本接力完成,全程可在本地复现。
入口脚本:create_size_log_x86.sh
create_size_log_x86.sh 是面向 x86-64 Linux release 构建的入口,流程如下:
- 清理本地构建与第三方依赖下载缓存:
make -f tensorflow/lite/micro/tools/make/Makefile clean clean_downloads; - 下载第三方依赖:
make -f tensorflow/lite/micro/tools/make/Makefile third_party_downloads; - 指定三个被监控的二进制(见第 35 行):
BINARY_LIST="keyword_benchmark,baseline_memory_footprint,interpreter_memory_footprint" python3 tensorflow/lite/micro/tools/metrics/create_size_log.py --build_type=release --target=linux --target_arch=x86_64 --binary_list=${BINARY_LIST} - 对产物目录执行阈值检测与绘图(第 47-48 行):
LOG_DIR="${ROOT_DIR}/data/continuous_builds/size_profiling/${TARGET}_${TARGET_ARCH}_${BUILD_TYPE}" python3 tensorflow/lite/micro/tools/metrics/detect_size_increase_and_plot_history.py --input_dir=${LOG_DIR} --output_dir=${LOG_DIR} --binary_list=${BINARY_LIST} - 若脚本检测到体积增长超阈值则退出码非 0,脚本打印
Size increase may exceed threshold并exit -1,从而让 CI 任务失败、触发人工介入;否则输出Size does not increase or size increase does not exceed threshold。
构建与采样:create_size_log.py
create_size_log.py 的_build_and_profile对每个二进制依次执行"构建 → 测量 → 追加记录":
- 构建:
_build_a_binary调用make -f tensorflow/lite/micro/tools/make/Makefile <binary_name> BUILD_TYPE=... TARGET=... TARGET_ARCH=...; - 测量:
_profile_a_binary对gen/<target_dir>/bin/<binary_name>执行 GNU binutils 的size命令(源码第 51、61 行),把输出按空白切分为 DataFrame,再以build_info(当前时间 +git rev-parse HEAD得到的 SHA)补全date与sha后追加写回 CSV(report.to_csv(csv_path, index=False, header=False, mode='a'))。
脚本支持的参数与默认值如下(均可覆盖):
| 参数 | 默认值 | 说明 |
|---|---|---|
--binary_list | keyword_benchmark,baseline_memory_footprint,interpreter_memory_footprint | 逗号分隔的二进制列表 |
--build_type | release | 构建类型 |
--target | linux | 主机目标平台 |
--target_arch | x86_64 | 目标架构 |
脚本依赖 Python 3 与pandas(源码第 20 行import pandas as pd)。
阈值检测与绘图:detect_size_increase_and_plot_history.py
detect_size_increase_and_plot_history.py 承担"回归检测 + 可视化"双重职责,两个关键常量定义在第 22-27 行:
# 仅回溯最近 60 天的体积历史 SIZE_HISTORY_DEPTH = 60 # text 与 total 段单次增量超过该阈值(字节)即判定失败 SIZE_THRESHOLD_SETTING = { "text": 512, "total": 512, }检测逻辑为:读取 CSV 最后 60 行,用size_log[section_name].diff()求最近一次增量,若text或total的最近增量超过 512 字节,则收集一条失败消息;所有二进制的消息汇总后抛出RuntimeError,脚本退出非 0。也就是说,这套机制检测的是"最近一次提交导致的体积突增是否越过阈值",而不是绝对体积上限。
绘图部分(第 39-56 行)为每个二进制生成一张 3×2 的子图:三行分别对应text、data、total,左列为绝对体积(纵轴Abs Sz(bytes),折线o-),右列为逐次增量(纵轴Incr Sz (bytes)),并以Source: <binary_name>与采样起止日期作为总标题,保存为<binary_name>.png。本仓库linux_x86_64_release/目录下的三张 PNG 正是该脚本的输出(依赖matplotlib)。
三个被监控的二进制:测量方法论
为什么偏偏监控这三个二进制?它们的语义与测量方法论在 tensorflow/lite/micro/examples/memory_footprint/README.md 中有完整说明,核心思路是用"减法"把 TFLite Micro 的体积开销拆解开。
baseline_memory_footprint:无操作基线
构建 memory_footprint 下的baseline_memory_footprint目标(构建规则见 Makefile.inc),得到的是一个"无操作应用"(no-op application),通常只包含平台相关的初始化代码。它被视为与 TFLM 无关的固定开销基线。
interpreter_memory_footprint:TFLM 框架
同目录下的interpreter_memory_footprint(源码 interpreter_memory_footprint.cc)会拉入创建解释器实例所需的全部 TFLM 框架代码(解释器、内存规划器等),但刻意不注册任何内核,因此该二进制无法真正执行推理。两个体积之差即为 TFLM 框架(Framework)的代码量估算:interpreter_memory_footprint − baseline_memory_footprint。
keyword_benchmark:完整应用与内核开销
keyword_benchmark.cc(构建规则见 Makefile.inc)基于带打乱权重/偏置的关键词检测模型(tensorflow/lite/micro/models/keyword_scrambled.tflite),仅用于平台性能与体积测量而非精度验证。它包含框架 + 该模型所需内核 + 系统库,因此:
keyword_benchmark − interpreter_memory_footprint≈ 该应用引入的内核代码量;- 其运行逻辑封装在 micro_benchmark.h 的
MicroBenchmarkRunner模板类中——它通过RecordingMicroAllocator与RecordingMicroInterpreter创建解释器、AllocateTensors()分配张量、Invoke()执行推理,并提供PrintAllocations()打印内存分配明细。
一个值得注意的方法论细节:由于baseline/interpreter目标未注册内核,MicroMutableOpResolver 产生的代码量会被计入"内核开销"而非"框架开销";文档明确这是为了简单、稳健并纳入系统库贡献而有意为之的取舍。文档还给出过参考快照:按此法测得 64 位 x86 平台 TFLM 框架约 20411 字节(旧数据快照,仅作参考)。
差值方法论总结
TFLM 框架代码量 ≈ interpreter_memory_footprint − baseline_memory_footprint 关键字模型内核代码量 ≈ keyword_benchmark − interpreter_memory_footprint文档同时提醒:完整应用通常还包含 FlatBuffer 格式的 TFLite 模型与内存 arena,它们一般落在 ELF 的 data 段,同样是整体内存占用的重要部分,但不属于本文讨论的代码量范畴。
从数据看趋势:仓库内 CSV 揭示的体积演变
仓库内三份 CSV 记录了 2022-01 至 2022-07 的真实演变,可以直接观察到几次阶梯式增长(与提交 SHA 一一对应):
baseline_memory_footprint.csv(单位字节):
| 时间点 | text | data | bss | total |
|---|---|---|---|---|
| 2022-01-10 | 1394 | 520 | 8 | 1922 |
| 2022-01-31 | 1433 | 568 | 8 | 2009 |
| 2022-07-14 | 1433 | 568 | 8 | 2009 |
interpreter_memory_footprint.csv:
| 时间点 | text | data | bss | total |
|---|---|---|---|---|
| 2022-01-10 | 22599 | 1464 | 24 | 24087 |
| 2022-01-31 | 23756 | 1600 | 24 | 25380 |
| 2022-03-09 | 26232 | 1648 | 24 | 27904 |
| 2022-04-27 | 27648 | 1824 | 24 | 29496 |
| 2022-07-14 | 27616 | 1824 | 24 | 29464 |
keyword_benchmark.csv:
| 时间点 | text | data | bss | total |
|---|---|---|---|---|
| 2022-01-10 | 81657 | 1568 | 22400 | 105625 |
| 2022-01-31 | 83141 | 1696 | 22448 | 107285 |
| 2022-03-09 | 85877 | 1744 | 22448 | 110069 |
| 2022-04-27 | 87277 | 1920 | 22480 | 111677 |
| 2022-06-16 | 88645 | 1920 | 22480 | 113045 |
| 2022-07-12 | 88597 | 1920 | 22480 | 112997 |
几个可验证的观察点:
- 框架开销:按差值法,2022-01-10 时框架约为
24087−1922=22165字节,到 2022-07-14 增至29464−2009=27455字节,半年内框架体积增长了约 5KB; - 内核开销:keyword_benchmark 与 interpreter 之差从 2022-01-10 的
105625−24087=81538字节增至 2022-07-14 的112997−29464=86533字节; - bss 差异:keyword_benchmark 的 bss 段(约 22.4KB 起步)显著大于前两者(8~24 字节),这与完整应用携带的大规模静态缓冲区形态一致(具体段归属可结合 memory_footprint README 中"模型与 arena 通常落在 data 段"的说明进一步分析);
- 每次跃迁都伴随新的
sha字段,例如 interpreter 在 2022-01-31 的746f880a...提交后从 24087 跳到 25380,体现了"体积变化可回溯到具体提交"的设计意图。
本地复现:把监控管线跑起来
在仓库根目录按以下步骤即可完整复现整套体积监控(需要make、GNUsize、Python 3、pandas、matplotlib):
# 1. 清理构建缓存并下载第三方依赖 make -f tensorflow/lite/micro/tools/make/Makefile clean clean_downloads make -f tensorflow/lite/micro/tools/make/Makefile third_party_downloads # 2. 构建三个二进制、用 size 采样并追加到 CSV python3 tensorflow/lite/micro/tools/metrics/create_size_log.py \ --build_type=release --target=linux --target_arch=x86_64 \ --binary_list=keyword_benchmark,baseline_memory_footprint,interpreter_memory_footprint # 3. 回溯最近 60 天历史、检测 text/total 增量是否超过 512 字节阈值,并生成趋势图 python3 tensorflow/lite/micro/tools/metrics/detect_size_increase_and_plot_history.py \ --input_dir=data/continuous_builds/size_profiling/linux_x86_64_release \ --output_dir=data/continuous_builds/size_profiling/linux_x86_64_release \ --binary_list=keyword_benchmark,baseline_memory_footprint,interpreter_memory_footprint产物写入data/continuous_builds/size_profiling/linux_x86_64_release/(二进制位于gen/linux_x86_64_release/bin/)。如需监控其他平台,可仿照 create_size_log_x86.sh 把--target/--target_arch换成目标配置(例如 ARM Cortex-M 平台),并保持输出目录命名规则一致。想单独运行基准本身,也可直接使用 benchmarks README 中的make -f tensorflow/lite/micro/tools/make/Makefile run_keyword_benchmark等目标。
长期愿景:以产物为数据源的性能 Dashboard
data/continuous_builds/README.md 明确写到:"长期目标是通过基于这些产物的 Dashboard 来监控这些性能数据点。"当前这套 CSV + PNG 的落地形态已经为这一目标铺好了路:
- 时序友好:记录以追加方式持续累积,天然是按时间排序的序列数据,可直接喂给时序数据库或图表组件;
- 可追溯:每条记录携带 commit SHA,异常体积跃迁可一键定位到具体提交;
- 阈值化:512 字节的 text/total 增量阈值已内置到检测脚本中,Dashboard 可以在此基础上做趋势告警、跨平台对比与长期漂移分析。
换句话说,现阶段"持续构建 → 采样体积 → 追加 CSV → 检测阈值 → 输出趋势图"的闭环,已经是一个轻量、可扩展、可本地复现的性能监控雏形。
小结
本文以 data/continuous_builds/README.md 为线索,完整还原了 tflite-micro 持续构建体积监控体系的三个层次:产物层(linux_x86_64_release/下的 CSV 与 PNG,字段为date/sha/text/data/bss/total)、管线层(create_size_log_x86.sh→create_size_log.py采样 →detect_size_increase_and_plot_history.py阈值检测与绘图)、语义层(baseline/interpreter/keyword_benchmark三个二进制的减法方法论)。这套体系的价值在于:把"体积与性能波动"从一次性的静态检查,变成了可追溯、可阈值告警、可持续观测的动态闭环——这既是文档所述意图的直接落地,也是未来 Dashboard 化监控的现成数据源。
- 人工智能
- 深度学习
- 推理引擎
- 本地部署
- 嵌入式
- 物联网
【免费下载链接】tflite-micro
Infrastructure to enable deployment of ML models to low-power resource-constrained embedded targets (including microcontrollers and digital signal processors).
相关推荐
OpenBLAS 持续基准测试(pybench)实践指南:基于 pytest-benchmark 与 CodSpeed 的性能回归监控
OpenBLAS 持续基准测试(pybench)实践指南:基于 pytest benchmark 与 CodSpeed 的性能回归监控 导读 本文围绕 Open
高性能计算科学计算Modin ASV 基准测试:从本地性能回归检查到持续性能看板
Modin ASV 基准测试:从本地性能回归检查到持续性能看板 导读 本文以 asv_bench/README.md https://link.gitcode.
数据分析数据工程大数据Resume-Matcher 的 Agentic 端到端监控(e2e_monitor):基于证据包的智能质量巡检与回归检测设计
Resume Matcher 的 Agentic 端到端监控(e2e_monitor):基于证据包的智能质量巡检与回归检测设计 本文是一份技术设计解析,核心素材
AI 应用人工智能大模型后端前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考