- 示例工程
【免费下载链接】examples
TensorFlow examples
Classification-by-Retrieval(CbR,按检索分类)是 TensorFlow Lite 官方示例仓库(examples/lite)中提供的一种"零训练"建模技术:借助预训练的特征提取模型加一组由索引数据计算(而非反向传播训练)出来的检索层,仅用每类一张图片就能在数秒内生成一个可部署的 TFLite 图像分类模型。读完本文,你将理解 CbR 相对传统训练流程与纯检索流程的差异、其检索层在 TFLite 算子图上的真实构建方式(含浮点与 INT8 量化两条路径),并掌握通过 iOS 示例应用或 C++ModelBuilderAPI 亲手构建、验证 CbR 模型的完整方法。
1. 什么是 Classification-by-Retrieval
CbR 提供了一种创建基于神经网络的分类器的简易途径,全程不需要计算密集的反向传播训练(README)。这带来两个极端方向的建模能力:
- 少样本下限:每类最少只需一张图片即可建立分类器;
- 大规模上限:可以构建能区分数万甚至更多类别的端侧模型。官方曾基于 CbR 技术构建过可识别数万个地标(landmarks)的移动端模型。
CbR 的典型适用场景包括:
- 机器学习教学(例如教育性质的 hackathon 活动);
- 快速原型验证或 ML 分类能力的演示;
- 中小企业的自定义商品识别(无需收集海量训练数据,也无需编写大量代码)。
仓库提供了两种直接的体验入口:一个 iOS 应用,可以从照片图库选取图片并打标签,在数秒内(图片数量较少时)创建一个 TfLite 分类器并立即用摄像头测试;以及一套位于 lib/ 目录下的 C++ 构建库(README 指出lib/tests中还提供用于构建分类器的命令行工具)。
2. 技术背景:分类、检索与 CbR 的中间定位
图像识别存在两条技术路线,理解它们是理解 CbR 的前提:
| 维度 | 典型分类(Classification) | 检索(Retrieval) |
|---|---|---|
| 建模方式 | 构建神经网络分类器并用大量训练数据(常为数千张以上)训练 | 使用预训练特征提取模型(如图像嵌入模型)+ 基于最近邻搜索的特征匹配 |
| 类别规模 | 受训练集限制,扩展需重训 | 可扩展,可处理百万级类别;增删类别无需重新训练 |
| 每类数据量 | 通常需要大量样本 | 每类一张图片即可,本质上是一种 few-shot 学习 |
| 使用门槛 | 直觉直观 | 需要额外基础设施(索引、搜索服务),使用上不如分类模型直观 |
CbR 的定位正是两者的折中:它是一个"把图像检索层烘焙进模型内部"的神经网络。检索所需的索引数据不再依赖外部服务,而是直接固化成模型里的权重张量与算子,从而获得一个可以像普通分类模型一样直接加载、推理的标准 TFLite 模型——"你不需要任何训练就能轻松创建一个 TensorFlow 分类模型"(README 原意)。
3. 检索层如何工作:从概念到 TFLite 算子
README 将 CbR 模型描述为"嵌入模型的扩展",附加的检索层是由训练数据(即索引数据)计算出来的,而非训练出来的。检索层由两部分组成:
3.1 最近邻匹配分量
概念上,这是一个全连接层,其权重就是索引数据的归一化嵌入。关键数学依据是:两个归一化向量的点积(余弦相似度)与 L2 距离的平方之间是线性的(带负系数)关系,因此该全连接层的输出在效果上等价于最近邻匹配结果。
源码印证:tflite_cbr_builder.cc 中的AddRetrievalBlock正是这样实现的——
- 对每条索引嵌入调用
Normalize()(L2 归一化,零向量除外)后拼接为权重矩阵{num_instances, embedding_dim},作为常量张量加入模型; - 先插入一个
L2_NORMALIZATION算子归一化输入的嵌入向量(注释明确说明"这一步对保证最终分数有意义是必需的"); - 再接一个
FULLY_CONNECTED算子,输出即每个训练样本(而非每个类别)的相似度得分{1, num_instances}。
3.2 结果聚合分量
最近邻匹配的输出是针对每个训练样本的得分,而分类需要的是每个类别的得分,因此需要第二个分量:每个类别先经过一个"选择层"挑选出属于该类别的样本得分,再经过一个聚合层(例如取最大值),最后把所有类别的聚合结果拼接成单一输出向量。
源码印证:tflite_cbr_builder.cc 的AddAggregationBlock实现了这条链路——
- 将
{1, num_instances}的得分RESHAPE为{num_instances, 1}; - 每个类别持有一张常量张量(该类别包含的样本下标),用
EMBEDDING_LOOKUP算子从得分中选出本类样本; - 对每个类别用
REDUCE_MAX沿样本轴聚合出单一分数; - 用
CONCATENATION把所有类别分数拼成{num_classes},最后再RESHAPE为最终输出{1, num_classes}。
类别与样本的对应关系在BuildCbRModel()中通过label_to_class_id映射建立:相同标签的样本归入同一类,且校验 embeddings 与 labels 数量必须一致(tflite_cbr_builder.cc#L360-L389)。
3.3 INT8 量化检索路径
BuildCbRModel()会检查嵌入输出张量的类型:若基座嵌入模型输出为 FLOAT32,走AddRetrievalBlock;若输出为量化类型,则走 AddQuantizedRetrievalBlock。从源码注释可以看到这条量化路径的设计要点:
- 量化版本整体小 4 倍(INT8 权重替代 FLOAT32);
- 由于归一化与矩阵乘法算子不处理 UINT8 张量的零点位(无法表示负值),数据流设计为:
UINT8 → 反量化 → FLOAT32 → 归一化 → 量化 → INT8 → 全连接检索 → INT8 → 反量化 → FLOAT32; - 权重量化步长固定取
1/128:源码注释解释,理论上最优步长约为1/(sqrt(d)*64)(d 为嵌入维度),但步长过大会导致全连接结果溢出(超过 128),因此采用标准步长 1/128 以保证相似嵌入之间结果的精度; - 聚合块与最终输出目前尚不支持 INT8(源码中留有 TODO),所以检索结果会被反量化回 FLOAT32 再送入聚合块。
3.4 完整模型构建调用链
上面的算子拼装由 lib/model_builder.cc 中的ModelBuilder统一编排,其对外 API 与约束如下(以 model_builder.h 的接口注释为准):
| 方法 | 作用与约束 |
|---|---|
CreateFromImageEmbedderOptions(options) | 由ImageEmbedderOptions初始化;不支持quantize选项开启的标量量化,也不支持多头(multi-head)ImageEmbedder(model_builder.cc#L41-L68) |
AddLabeledImage(label, frame_buffer) | 对每张带标签图片调用嵌入模型,保存特征向量与标签;需在构建前对每张索引图片多次调用 |
BuildModel() | 终结构建:要求至少两张带标签图片,否则返回FailedPreconditionError(model_builder.cc#L163-L197);成功时返回带元数据的ExternalFile(可直接用于初始化ImageClassifier,或写盘为.tflite文件),并重置内部状态以便构建下一个模型 |
SetMetadata(...) | 设置名称、描述、作者、版本、许可证及关联文件,在BuildModel()返回时随模型一并固化 |
值得注意的元数据细节:PopulateMetadata()会把按顺序收集的类别标签写入内嵌的labelmap.txt,并将其登记为输出张量的TENSOR_AXIS_LABELS关联文件(model_builder.cc#L95-L161)。这意味着产出的模型开箱即可被 Task API 的ImageClassifier识别标签,无需额外携带标签文件。
辅助工具 labeled_image_helper.h 还提供了AddLabeledImageFromPath(),可直接从文件路径读图、转FrameBuffer并加入构建器,是命令行构建器的底层支撑。
4. 基座嵌入模型的选择
CbR 的检索能力完全依赖所选基座嵌入模型,因此应按领域选择最合适的嵌入模型。TensorFlow Hub 上为不同领域提供了多种嵌入模型可选。仓库自带的 iOS 演示 使用的是在 ImageNet 上训练的MobileNet V3 Small(100% 输入 224x224)feature vector 模型——一个通用且高效的端侧模型。
这一点在构建配置中有直接印证:CbR 的独立 Bazel 工作区 WORKSPACE 通过http_file规则锁定下载该 MobileNet V3 嵌入模型(imagenet-mobilenet_v3_small_100_224-feature_vector.tflite,带 sha256 校验),并固定了tflite-support(f5dadc83提交)与 TensorFlow(a221f72e,2021-09-29)的依赖版本。换言之,该工作区是一个可独立构建的 CbR 构建环境,基座模型即示例所用的 MobileNet V3 嵌入模型。
5. 与 Few-Shot Learning 的精度关系
在某种意义上,CbR(索引式)可以视为一种免训练的 few-shot 学习。README 也审慎地指出,把 CbR 与任意预训练基座模型下的典型 few-shot 学习方法直接对比并非完全公平(apples to apples)。但有一篇研究(arXiv:1911.04623)将最近邻检索(与 CbR 等价)与多种 few-shot 学习方法进行了比较,结论是最近邻检索的精度可以与许多 few-shot 学习方法相当,甚至更好。因此,在类别数量多、每类样本极少或需要频繁增删类别的场景下,CbR 是一个值得优先考虑的方案。
6. 用 iOS 示例应用亲手构建 CbR 模型
CbR iOS 示例(ImageClassifierBuilder)完整演示了"选取图片 → 打标签 → 秒级建模 → 实时测试"的闭环。环境要求与构建步骤如下(摘自其 README):
要求
- iOS 14.0 或更高版本的设备
- Xcode 12.5 或更高版本
- 有效的 Apple Developer ID
- Xcode 命令行工具(
xcode-select --install)
注意:该应用依赖摄像头,必须在真实 iOS 设备上运行;模拟器可以构建运行,但会抛出Camera not found异常。
模拟器构建
$ git clone https://github.com/tensorflow/examples.git $ cd examples/lite/examples/classification_by_retrieval $ bazel build -c opt --config=ios_x86_64 ios:ImageClassifierBuilder真机构建
- 先从 Apple 获取移动设备描述文件(mobile provisioning profile);
- 建立符号链接:
ln -s <path/to/your/profile.mobileprovision> ProvisioningProfile.mobileprovision; - 在 ios/BUILD 中取消所有
ProvisioningProfile.mobileprovision相关行的注释; - 执行:
bazel build -c opt --config=ios_arm64 ios:ImageClassifierBuilder。
安装后需授予相机与照片图库权限。使用流程是:先从照片图库的相册创建模型(每选一个相册/图片即形成一个类别),随后用摄像头对准训练过的物体,即可实时查看分类效果。应用的核心 Swift 代码(ModelTrainer.swift、ModelTrainingUtils.mm 等)通过桥接层调用上文第 3、4 节所述的 C++ModelBuilder,把图库图片逐张嵌入并累积进检索层,最终产出一个可直接用于实时分类的 TFLite 模型。
7. 负责任地构建模型
仓库在 README 末尾同样强调了负责任的 AI 实践:鼓励构建公平、负责任的分类器,并建议参考 TensorFlow 官方的 Responsible AI 资料(tensorflow.org/responsible_ai)、Google 的 "Fair is Not the Default" 设计指南以及 Google Machine Learning Crash Course 中的公平性视频课程等公开资源,在面向真实用户发布 CbR 模型前完成公平性评估。
8. 小结:何时选择 CbR
结合本示例仓库的文档与源码,CbR 的技术画像可以归纳为:
- 零训练:检索层权重由索引嵌入"计算"得到,
BuildModel()之前无需任何梯度更新; - 标准模型输出:产物是普通 TFLite 分类模型,内嵌
labelmap.txt元数据,可直接被 Task API 加载,部署路径与传统分类模型完全一致; - 灵活的类别管理:新增/删除类别只需重建索引块,无需重训,且支持每类单图(few-shot)到数万类的跨度;
- 明确的实现边界:当前实现要求嵌入模型为单输出头、不经过额外标量量化(量化检索路径依赖嵌入输出本身为量化类型),且构建至少需要两张带标签图片——这些约束都可在 model_builder.cc 与 model_builder.cc 中逐条得到验证。
对于需要"少数据、快交付、易增删类别"的端侧图像识别需求,这套由 README、lib/ C++ 库与 iOS 示例 共同构成的 CbR 方案,提供了从原理、构建器到成品应用的完整参考。
- 示例工程
【免费下载链接】examples
TensorFlow examples
相关推荐
TensorFlow Lite图像分类:模型训练与部署完整指南
TensorFlow Lite图像分类:模型训练与部署完整指南 TensorFlow Lite图像分类技术让移动端AI应用开发变得前所未有的简单!🚀 这个强大
文档教程知识库如何快速构建你的第一个TensorFlow Lite图像分类器:从入门到实战
如何快速构建你的第一个TensorFlow Lite图像分类器:从入门到实战 TensorFlow Lite图像分类器项目是一个基于Android Things
TensorFlow Lite 图像分类器项目教程
TensorFlow Lite 图像分类器项目教程 项目介绍 TensorFlow Lite 图像分类器项目是一个开源项目,旨在通过 TensorFlow Li
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考