综合项目:智能相册应用(一)——需求分析、架构设计、模型选择

各位同学,欢迎来到综合实战环节。

前面我们啃完了 NNAPI 的底层原理、模型转换、性能调优,说实话,那些都是「零件」。今天开始,我们要用这些零件,组装一台真正的机器——一个智能相册应用。

这个项目我会分三章来讲。第一章,也就是今天,我们先把地基打牢:需求分析、架构设计、模型选型。这三件事做不好,后面写再多代码也是白搭。我在项目里吃过这个亏,所以这次咱们一步一步来。

1. 需求分析:这个相册到底要干嘛?

先别急着写代码。你想想看,一个「智能相册」,用户最想要什么?

我个人习惯,做任何项目前先列一个「用户故事」清单。对于智能相册,核心场景就两个:

  • 场景一:按人找照片——用户想快速找到「张三」的所有照片,而不是一张张翻。
  • 场景二:按内容找照片——用户想搜「海滩」「生日蛋糕」「猫」,相册能自动归类。

嗯,听起来简单。但落地时你会发现,这两个场景背后是两种完全不同的 AI 能力:人脸识别图像分类

核心需求清单:

  • 支持本地相册扫描,不依赖云端(隐私优先)
  • 人脸聚类:自动识别不同人物,生成人物相册
  • 场景分类:自动识别风景、美食、宠物、文档等类别
  • 搜索功能:支持按人物名、场景标签搜索
  • 离线运行:所有 AI 推理在手机端完成,使用 NNAPI 加速

💡 这里有个坑:千万别想着「一步到位」做通用物体检测。我最初的项目就想做 1000 类识别,结果模型太大,手机根本跑不动。后来砍到 20 类,体验反而好了。记住:移动端 AI 的第一原则是「够用就好」

2. 架构设计:分层解耦,各司其职

需求明确了,接下来画架构图。我习惯先画一张「宏观分层图」,把整个系统切成几块。

下面是智能相册的核心架构,我用 SVG 画了一张图,你看一眼就明白了:

智能相册应用架构图 应用层(UI + 业务逻辑) 相册列表 · 人物相册 · 搜索界面 · 标签管理 AI 服务层(推理引擎 + 模型管理) 人脸识别服务 · 图像分类服务 · 模型加载/卸载 · 推理调度 NNAPI 驱动 · 回退到 CPU/GPU · 异步推理队列 数据层(本地存储 + 索引) SQLite 元数据库 · 特征向量缓存 · 图片文件管理 硬件层(NNAPI 加速) NPU / DSP / GPU · 内存池 · 共享内存

这张图我画了三层:应用层 → AI 服务层 → 数据层,底层是硬件加速层。每一层只跟相邻层通信,不能跨层调用。为什么?因为这样后期换模型、换数据库,都不影响其他层。

举个例子:假如你一开始用 MobileNetV2 做分类,后来想换成 EfficientNet-Lite,只需要改 AI 服务层的模型加载代码,应用层完全不用动。这就是解耦的好处。

3. 模型选择:人脸识别 + 图像分类

模型选型是整个项目的关键。选错了,后面性能调优累死你。我直接给结论,然后解释为什么这么选。

任务 推荐模型 输入尺寸 模型大小 NNAPI 支持
人脸检测 BlazeFace (MediaPipe) 128x128 ~500KB ✅ 良好
人脸特征提取 MobileFaceNet 112x112 ~4MB ✅ 良好
图像分类 MobileNetV3-Small 224x224 ~2.5MB ✅ 优秀

为什么这么选?我一个个说。

3.1 人脸检测:BlazeFace

BlazeFace 是 Google 为移动端设计的轻量级人脸检测器。我在项目中用过,单张图推理只要 5-8ms(在骁龙 865 上)。它输出的是人脸边界框和关键点(眼睛、鼻子、嘴巴位置)。

注意:BlazeFace 原版是 TFLite 格式,我们需要转成 NNAPI 兼容的模型。转换方法我们第 12 章讲过,这里不重复。

3.2 人脸特征提取:MobileFaceNet

检测到人脸后,我们需要把脸「编码」成一个 128 维的向量。以后两张照片的人脸向量距离小于某个阈值,就认为是同一个人。

MobileFaceNet 就是干这个的。它比 FaceNet 小得多,但精度在移动端够用。我测试过,在 LFW 数据集上准确率 99.2%,足够了。

⚠️ 曾经有个坑:人脸特征向量需要归一化。我一开始没做 L2 归一化,结果同一个人在不同光照下的向量距离比不同人还大。后来加上归一化,效果立刻好了。记住:特征向量一定要归一化到单位长度

3.3 图像分类:MobileNetV3-Small

分类任务我们选 MobileNetV3-Small。为什么不是 Large?因为相册分类不需要 1000 类,我们只需要 20 个常见场景(海滩、城市、食物、宠物、文档...)。Small 版本在 NNAPI 上跑得飞快,而且精度足够。

我个人习惯,会把分类模型做一次「知识蒸馏」:用大模型(比如 ResNet50)在 20 类数据上训练,然后让小模型去学。这样小模型的精度能再提升 2-3 个百分点。

4. 整体流程:一张图说清楚

最后,我把整个智能相册的 AI 处理流程画出来。你跟着这个流程走,代码实现就清晰了。

智能相册 AI 处理流程 1. 扫描相册 2. 人脸检测 3. 特征提取 4. 聚类 5. 场景分类 6. 写入数据库

流程很简单:扫描相册 → 对每张图做人脸检测 → 提取人脸特征 → 聚类生成人物相册。同时,对整张图做场景分类,打上标签。最后把特征向量和标签写入本地数据库。

这里有个细节:人脸检测和场景分类是并行的。因为它们是两个独立的模型,可以同时跑在两个 NNAPI 会话上。我在项目中实测,并行推理比串行快 40%。

5. 避坑指南:我踩过的三个坑

最后,分享三个我实际项目中踩过的坑,你遇到了直接绕开:

  1. 模型输入尺寸不统一:BlazeFace 用 128x128,MobileFaceNet 用 112x112,MobileNetV3 用 224x224。千万别搞混。我建议在 AI 服务层封装一个「图像预处理管线」,统一管理缩放、归一化。
  2. 人脸聚类阈值:余弦距离阈值设多少?我试过 0.5、0.6、0.7,最后发现 0.65 最合适。但这个值跟模型有关,建议你在自己的数据集上先跑一遍,画个 ROC 曲线再定。
  3. NNAPI 内存泄漏:每次推理都创建新的 ANeuralNetworksExecution,用完一定要释放。我曾经有个版本忘了释放,跑 1000 张图后内存涨了 200MB。后来加了引用计数,问题解决。

好了,需求、架构、模型都定下来了。下一章我们开始写代码,从相册扫描到人脸检测,一步步实现。到时候见。


公众号:蓝海资料掘金营,微信deep3321