前阵子帮一位做AIoT智能硬件的朋友排查一台宠物喂食器,现象很典型:猫站在食盆前等着,机器却死活不出粮;扫地机器人路过出粮口,反倒哗啦啦掉了一堆。拆开日志一看,算法把猫的置信度判到了0.42,把扫地机器人判到了0.67。朋友苦笑说,模型在电脑上跑测试集的时候猫狗识别准确率明明有97%。这种“测试集上光辉、真实场景翻车”的情况,几乎每个垂直AIoT项目都躲不过。
这篇文章想聊的,就是“猫狗识别”在喂食器、摄像头、智能门这三个设备上的垂直落地过程。它不是一篇模型教程,而是一次完整的工程复盘:从需求约束、数据设计、模型选型,到阈值策略、误触发排查、上线后迭代,把那些真正决定项目成败、但文档里不会写的环节过一遍。适合正在做宠物类智能硬件、或者打算把视觉模型真正部署到端侧设备上的开发者看。
1. 三个设备三种性格:喂食器、摄像头、智能门对识别的需求根本不一样
很多团队拿到“猫狗识别”这个需求之后,第一反应是找个开源分类模型,训练一下,往设备里一塞就完事。实际上,同样的模型往三个设备里各塞一遍,效果差距会非常悬殊。因为“识别”只是整条链路里的一环,真正决定算法选型和工程难度的,是设备的工作方式、功耗预算和误触发代价。
1.1 喂食器:识别是被“叫醒”的,不是一直跑的
智能喂食器场景里,算法并不是每时每刻都在运行。设备通常依赖PIR被动红外传感器先感知热源靠近,或者靠定时投喂计划唤醒,然后才启动摄像头抓帧、跑推理。这意味着识别本身必须够快——从触发到出粮,最好控制在1秒左右,不然猫会等得不耐烦,转头去扒粮桶。
硬件上,很多喂食器用的是低功耗主控,内存可能只有几十MB级别,操作系统、协议栈占掉一半之后,留给推理模块的空间非常有限。这种约束决定了喂食器里的模型选型首先看内存占用,其次才看准确率,和服务器上的自由度完全不是一回事。另外,多猫家庭还有个隐性需求:粮只能给指定的一只猫吃,其他猫来了要能区分开。这就从“猫狗二分类”升级成了更细的目标,工程复杂度又上一个台阶。
1.2 智能门:误判一次,用户信任就崩一次
智能宠物门的识别逻辑听起来很简单:宠物靠近,识别是自家的猫,开锁放行;识别成狗或陌生人,坚决不开。但落地之后你会发现,这个场景的尴尬之处在于,误开的代价极高——狗跑出去、陌生动物跟进屋、甚至小孩趴门口触发开锁,一次误判就能让整个产品口碑归零。
同时,门口的物理条件也是所有场景里最差的。正午强光、傍晚逆光、下雨天镜头挂水珠、门板开关瞬间画面剧烈运动,每一帧都在考验模型的鲁棒性。时延预算比喂食器更紧,宠物在门口停留的时间通常只有几百毫秒,不会等你慢慢算。这类设备对识别策略的要求是“宁可少开,不可错开”,和喂食器“多出几次粮无所谓”的逻辑完全不同。
1.3 摄像头:画面最大、目标最小、算力相对宽裕
家用看护摄像头是三种设备里算力最宽裕的,通常可以直接跑分辨率更高的模型,甚至可以采用两阶段方案:先全图检测运动区域,再对局部区域做精细的猫狗判别。但代价是画面里的目标往往很小——猫可能在三四米外的沙发上蜷着,只占画面几十个像素,姿态还千奇百怪,侧躺、露肚皮、屁股对着镜头都是常态。
摄像头还是唯一一个7x24小时持续工作的设备,对单次功耗不敏感,但对稳定性和持久性要求极高。断线重连、夜间模式切换、多路画面轮询、存储回看,这些和识别算法无关的工程细节,反而会在上线后占据大量调试时间。
1.4 先对齐需求,再谈算法:用一张表看透差异
我在项目启动时做了一张简表,把三个场景的硬约束列出来,之后所有技术决策都对着它核对:
| 维度 | 喂食器 | 智能门 | 看护摄像头 |
|---|---|---|---|
| 触发方式 | PIR/定时唤醒 | 宠物靠近触发 | 7x24持续运行 |
| 典型主控 | 低功耗MCU/入门SoC | 中端SoC | 中高端SoC+NPU |
| 可用内存 | 往往小于64MB | 128MB-256MB | 256MB以上 |
| 时延预算 | 约1秒 | 约0.3-0.5秒 | 可放宽到2-3秒 |
| 误触发代价 | 低(多出一次粮) | 极高(开门放错) | 中(推送打扰) |
| 主要难点 | 低功耗+内存小 | 强光/逆光/运动模糊 | 小目标+遮挡+夜间 |
把这张表填完之后就能看出来:三个设备虽然用同一个识别技术,但产品逻辑完全不同。所以项目启动的第一步不是调模型,而是把每个设备的约束条件写清楚,再倒推模型该多大、该怎么做量化、阈值该往哪边偏。这个方法论比任何单个技术点都重要。
2. 数据才是一切的前提:类别设计、样本配比和采集策略
模型效果的上限由数据决定,这话虽然老套,但在垂直AIoT项目里尤其真实。通用公开数据集做得再漂亮,也替代不了你在真实设备、真实户型、真实光照条件下采集的样本。数据环节的几个决策,会直接影响后续所有工作。
2.1 类别上必须加一个“其他”,否则模型会编答案
如果只训练猫、狗两个类别,推理时所有画面都会被硬分到其中一类。因为分类模型的输出经过softmax之后总和恒等于1,模型被迫在“看起来不完全像猫、也不是狗”的图像上强行给出一个答案。实际部署时,很多莫名其妙的误报就来自这个设计缺陷。
正确做法是定义三分类:cat、dog、unknown。unknown这个类别要足够“皮实”,样本必须覆盖设备在真实环境里会遇到的各种打扰:人的手、脚、扫地机器人、宠物玩具、飞虫、墙壁上的光影、甚至一张随风飘动的塑料袋。我见过一个很有意思的unknown样本——猫爬架上的毛绒球在风扇吹动下晃动,模型一度给它打过0.6以上的“猫”置信度。
2.2 负样本的采集比正样本更花时间,但回报最大
在真实设备上,负样本才是决定误报率的关键。我们当时专门做了一轮“现场负样本大扫荡”:把设备装到不同志愿者家里,连续七天采集所有“触发了但画面里没有猫狗”的片段。结果是各种意想不到的画面:风扇吹动的窗帘、充电底座的呼吸灯、雨天玻璃上的水流纹、被风吹翻的宠物玩具、阳光在墙上投出的树影。
这些样本一张顶一百张翻拍,因为它们就是设备真正会遇到的物理世界。如果训练集里的负样本全是网上找的随机风景图,模型根本学不到“窗帘飘动”和“猫尾巴甩动”之间的微妙差别。所以我会建议所有做端侧识别的团队,把负样本采集当成正式任务排进开发计划,而不是最后补几张图了事。
2.3 样本量级参考和数据增强的边界
冷启动阶段,我建议每个目标类别准备3000到5000张正样本,负样本量做到正样本的2到3倍。类别不平衡在二分类场景里影响不大,但在加了unknown的三分类里,如果unknown样本太少,模型会把“不像猫但也不像狗”的东西全部硬分给猫或狗。
数据增强方面,亮度抖动、高斯模糊、随机裁剪、小幅透视变换都是基础操作,模拟的是早晚光线变化、运动模糊和距离远近。但有两类增强要克制:一是大角度旋转,设备挂在墙上或门边,猫狗倒立出现的概率几乎为零,转太多反而把模型教偏;二是夸张的色调偏移,尤其是夜间靠红外补光的设备,画面本来就是灰度,过度色调增强会让模型偏离真实分布。
2.4 数据质量的细节:模糊样本单独放,别污染标注
标注一致性比标注数量更影响训练效果。我们内部有一条规矩:凡是人眼都看不清的模糊样本,不参与训练,单独建一个“难例桶”,等模型基本收敛之后再把这些难例逐步加入训练,当对抗样本用。如果一开始就把模糊样本混进去,正负标注的边界会变得混乱,模型很难收敛到干净的特征。
另一个容易忽略的是时间维度。白天的猫和晚上的猫,在红外补光下的纹理特征完全不同。如果训练集全是白天彩色图,晚上大概率翻车。这个坑我在后面的量化环节还踩了一次,后面细说。
3. 从“能识别”到“能塞进设备”:模型选型、量化和部署的取舍
训练好的模型在服务器上跑得飞起,不代表能塞进设备。垂直AIoT项目的核心矛盾就在这里:模型的推理效果和它的体积、时延、内存占用,必须在设备侧达成平衡。这一章讲的取舍,决定了一个模型是“能跑”还是“能跑得动”。
3.1 三条硬约束:内存、时延、算子兼容性
部署之前先算一笔账。假设一台设备可用内存64MB,操作系统和通信协议栈占掉一半,留给推理模块的往往只有十几MB。那么模型本身最好压到5MB以内,运行时激活缓存再预留2到3MB。公式很简单,但很多人不写下来,等到板子上一跑就爆内存。
时延和功耗也是一对矛盾。粗略估算:单次推理时延乘以触发频率,决定了功耗预算能不能扛住。如果PIR每天触发一百次,每次推理200毫秒,即使算力足够,功耗也未必撑得住。所以端侧部署不是“越快越好”,而是“在功耗预算内刚好够用”。
算子兼容性则是第三个隐形杀手。模型训练时用的自定义算子,到了端侧推理框架里如果不受支持,会自动回退到CPU慢速实现,时延可能暴涨十倍。我建议在选网络结构之前,先确认目标推理框架的算子支持列表,避开那些注定要踩坑的算子。
3.2 轻量网络选型的实测对比
我们在自建数据集上做过一轮轻量级网络的横向对比,数据集是一万六千多张现场采集的猫狗和负样本,评测硬件是某入门级SoC的NPU。结果大致如下:
| 候选方案 | 参数量 | 单帧推理耗时 | 量化后准确率 | 内存占用 |
|---|---|---|---|---|
| 方案A | 约2M | 38ms | 94.2% | 约8MB |
| 方案B | 约3.5M | 51ms | 96.1% | 约11MB |
| 方案C | 约6M | 97ms | 96.5% | 约17MB |
结论很清晰:参数量在3到4M的轻量模型,准确率和内存占用之间比较平衡;再往上加参数,准确率收益不到0.5%,时延却几乎翻倍。如果还想进一步压缩,可以对最后一个卷积块的冗余通道做剪枝,通常能砍掉10%到15%的体积,精度损失控制在0.5%以内。
3.3 INT8量化:校准集里没有夜间样本,晚上就翻车
量化是端侧部署的关键一步,原理不复杂:把FP32的权重按缩放因子映射到INT8的整数范围,模型体积直接缩小到四分之一,推理速度按硬件不同提升1.5到3倍。但它不是白拿的,量化精度校准这件事,做不好会翻大车。
我第一次做量化时,校准集用了1000张白天样本,一张夜间样本都没放。结果量化模型白天表现正常,晚上准确率暴跌到70%出头。原因很简单:夜间红外画面的数值分布和白天差异太大,量化缩放因子完全没覆盖。后来重新组织了校准集,按白天、夜间、逆光、强光各四分之一混合,量化后的准确率才回到和浮点模型接近的水平,整体下降约1个百分点。
这个坑让我养成了一个习惯:校准集的组成必须和生产环境的真实光照分布对齐,而且要定期更新。抽样校准集的时候,千万不能只挑“好看的”样本。
3.4 部署阶段的格式与内存问题,能提前给你省一周
部署阶段有几个细枝末节的坑,每个都能浪费一天时间。第一,输入格式问题。很多摄像头的原始输出是YUV或NV21格式,而模型通常训练在RGB上,格式转换涉及一整块内存拷贝,处理不好会白白增加几十毫秒。第二,图像缩放尽量用设备自带的硬件编码器,而不是CPU软缩放,入门级SoC的硬件缩放通常比软件快得多。第三,推理线程尽量绑到大核上,但注意别和ISP线程抢资源,否则帧率不升反降。
还有一个容易忽略的问题:模型输入的尺寸。224×224分辨率的输入在喂食器场景够用,因为宠物离镜头近、目标占比大;但在摄像头场景就不够,目标太小时特征会被背景淹没。所以更合理的方案是整图检测加局部裁切放大,这部分后面专门讲。
4. 喂食器和智能门最容易翻车的三件事:阈值、投票和联动
就算模型精度已经做到97%,真实设备上还是会有误报。原因不在模型本身,而在决策策略。喂食器和智能门恰恰是决策代价天差地别的两个场景,策略设计必须分开对待。
4.1 置信度阈值不是“拍脑袋”定的,要看PR曲线
“狗被识别成猫放出门”的代价,和“猫在门口被挡住”的代价,完全不是一个量级。前者是安全事件,后者只是用户体验问题。所以阈值选择必须回到业务成本上,而不是简单设个0.5。
我们在验证集上画出precision-recall曲线,然后按场景成本选工作点。喂食器误触发代价低,多出一两次粮无伤大雅,就选召回优先的位置,阈值放到0.5左右;智能门误触发代价极高,必须选精度优先的位置,阈值放到0.8以上。这一步做完,你会发现同一个模型在两个设备上表现出两种性格,这是完全正常的。
4.2 连续帧投票和迟滞:单帧识别在落地中不可用
单帧推理在真实场景里基本不可用。一次快门可能正好赶上宠物甩头、扇耳朵、镜头逆光,单帧置信度会剧烈抖动。正确做法是设置观察窗口,比如500毫秒内连续采集5帧,5帧里至少3帧判定为同一个类别才动作。
在此基础上还要加迟滞:进入动作状态用较高的阈值A(0.75),离开动作状态用较低的阈值B(0.6)。这样做的目的是防止置信度在阈值附近抖动时,设备反复触发、取消、再触发。这个技巧在控制领域叫滞回比较,在识别系统里一样适用。
4.3 案例:喂食器把扫地机器人当成狗
有一次线上反馈,喂食器在没猫的时候出了粮。调日志看到置信度曲线在0.5上下反复抖动,触发源是PIR——扫地机器人的发热轮子也能触发红外。单纯调阈值没用,因为机器人和猫的热源强度接近。
我们的解法是在逻辑层增加“运动连续性”判断:扫地机器人的运动轨迹平滑往复,猫会有蹲坐、抓挠、停顿等不规则动作。用连续几帧的位移方向一致性作为特征,明显区分开这两者。同时把识别功能只在设定出粮时段内启用,其他时间段直接不唤醒算法。最终误触发率降了一个数量级。这个案例说明:很多问题的解不在模型,而在产品逻辑。
4.4 案例:主人抱猫回家,智能门把“猫”识别成狗
更棘手的一个案例是,主人抱着猫走到门口,智能门识别后却判定为狗,把猫挡在门外。原因是猫被人托住时,姿态是蜷缩的,头还被手挡住,和标准站姿差异极大,模型综合特征出现混乱。
解法是加一个前置人形检测分流:先判断画面里有没有人,一旦检测到人,直接进入“主人模式”,不执行宠物识别;确认无人之后,才做猫狗的类别判定。同时划定ROI识别区域,宠物只有走到门口特定位置才开始决策,这样门边路过的人或物体不会干扰识别。两种策略组合下来,这类误判基本消除。
5. 摄像头场景的专项优化:低照度、遮挡、小目标和人宠同框
摄像头场景虽然算力最宽裕,但它要面对的画面复杂度也是最高的。七个字总结:小、暗、杂、变。以下是我在实际调试中觉得最值得投入精力的几个方向。
5.1 夜间红外画面是另一个数据分布
夜间的红外补光画面和白天彩色画面,在像素分布上差异巨大。如果只用白天数据训练,夜间场景一定会翻车。我们的训练集里长期混入三成左右的夜间样本,并且在低照度模式下把RGB输入自动切换成灰度通道。
这样做的结果是,模型不再依赖颜色特征,而是学习纹理和轮廓。对夜间识别来说,这意味着更稳的表现。我还额外做了一步:对夜间样本单独做亮度归一化,避免红外灯强度差异导致同一只猫在远近不同距离出现亮度跳变。
5.2 遮挡和姿态:只露屁股、只伸尾巴,怎么识别?
猫缩在沙发缝隙只露尾巴,狗背对镜头趴着,单一分类器面对这种画面经常给出低置信度,最后整帧被当成“未知”丢弃。但如果结合时间线索,情况就完全不同。
做法是采用累积判定:连续若干帧里,只要有足够多的帧判定为猫,就确认这是猫。比如10帧里有6帧判定为猫,就认定目标存在。同时结合运动模式——猫会长时间盘踞在同一个区域,人通常快速穿过画面。多模态的时间线索能救回很多单帧根本做不出来的案例,这也是摄像头场景比门禁场景友好的一点:你有更长的时间窗口去判断。
5.3 小目标处理:先定位,再放大,最后分类
宠物距镜头三四米时,目标可能只占画面的几个百分点。直接整图分类,小目标特征会被背景严重淹没。我们的方案是两段式:先用帧差或背景建模框出运动区域,再把运动区域裁剪放大到分类模型的输入分辨率,最后做猫狗判别。
这个方案的单帧增加耗时通常只有几十毫秒,但对几米外小目标的识别精度提升非常明显。代价是你得额外写一个运动目标跟踪模块,把同一目标在不同帧间的检测框稳定关联起来,否则同一个活动会被反复触发多次。
5.4 人宠同框:人形检测先分流
摄像头场景最常见的用户投诉是:主人在家走动,系统推送“检测到猫”。这其实不是识别失效,而是人没被过滤掉。我们的做法是在管道最前面加一个人形检测模型,检测到人的区域直接屏蔽宠物识别;或者反过来,宠物识别只处理“人形之外”的运动区域。
表格对比一下两种方案:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 前置人形门控 | 逻辑简单,算力占用低 | 人猫同框时会漏报猫 |
| 人形区域屏蔽 | 保留人猫同框的宠物识别 | 多跑一个模型,占用更多算力 |
摄像头算力相对宽裕,我们最终选了“人形区域屏蔽”。实际效果是,人在画面里走动不再触发猫狗识别,但猫跳上沙发和人同框时,依然能正确识别并推送。
5.5 评估指标别只看准确率:要按“每24小时误报次数”来验收
很多团队汇报时说“准确率98%”,听起来很亮眼,但放到摄像头场景里,一天触发500次识别,就算98%的准确率,仍然会有10次假推送。用户感知到的是“今天被骚扰了10次”,而不是“准确率98%”。
我们的验收指标表里固定了几项:单帧分类准确率、每百帧误报率、每24小时误报推送次数、宠物出现后的漏报率、端到端时延P95。其中“每24小时误报次数”直接决定用户留存,是产品验收的一票否决项。宁可某些单帧识别场景不推送,也不要一天给用户弹十条假警报。
6. 上线之后才算真正开始:日志、数据回流与一次“地毯事故”
模型部署到设备、跑通试用,只是项目的前半程。垂直AIoT项目最花时间的阶段,恰恰是产品交付之后暴露出来的长尾问题。这一章讲几个我亲测有用的运维和迭代手段。
6.1 设备端日志要能支撑事后复盘,字段一个都不能少
没有日志体系,线上出问题就只能靠用户口头描述,根本无法定位。我们的设备日志固定记录这些字段:触发时间戳、触发源类型(PIR、运动检测还是定时)、原始帧缩略图或裁剪图、模型版本、前后处理参数、置信度、最终执行的动作。
隐私和带宽方面,图可以只回传低分辨率灰度缩略图,或者用本地提取的特征向量代替原图。但核心信息必须留全,否则一次线上误报排查往往要花几天才能复现。我个人的经验是,日志设计必须在硬件阶段就考虑进去,产品发布后再补日志,成本高到离谱。
6.2 数据回流与半自动标注:让设备帮你筛难例
线上误报和漏报的样本,是最有价值的训练数据。我们做了一条半自动回流流水线:设备端把低置信度、或者是“模型结果与实际动作不一致”的样本自动打标,云端只做二次确认。人工只需每天花十几分钟过一遍,一周汇总一次,合并进训练集做微调。
迭代节奏按周跑:每周出一个候选模型版本,灰度到10%设备上观察三天,看误报率变化,稳定后全量发布。这个节奏让模型始终贴着真实场景走,不会和现场环境脱节。
6.3 案例:一块新地毯引发的误报风暴
有一次用户反馈,家里换了一块深色地毯后,摄像头开始疯狂报警“检测到猫”,但家里根本没有猫。排查日志发现,所有的触发画面都是空无一物的深色地毯区域。
原因出在训练数据上:训练集里的猫样本,绝大多数出现在浅色地板上,模型学了“地板纹理+猫”的组合特征,深色地毯提供了相似的纹理先验,于是空白地面被误激发了。修复方法是在训练阶段引入随机背景增强——把猫的蒙版随机贴到各种颜色和纹理的背景下,同时在数据增强里增加局部纹理扰动。这个案例教育意义很大:AIoT识别模型学到的特征,可能和你以为的完全不同,必须通过对抗式的背景数据补充来纠正。
6.4 跨区域部署的差异:环境变量只能靠现场数据说话
不同地区的房子光照、户型差异很大。南向大落地窗和北向阴面、老小区昏暗楼道,光线曲线完全不同。负责任的做法是按区域分组部署、分组评估指标,跑一段时间A/B后再共享最优配置。
喂食器在南方雨季和北方供暖季的样本差异,体现在暖色调、湿度导致镜头起雾、墙体反光等看不见的环境变量上。这些变量在办公室测试时根本不会出现,只能靠现场数据说话。所以我们的原则是:模型参数可以全局统一,但环境适配参数必须按区域分组,并且每隔一个季度重新统计一次。
在这些项目做下来之后,我个人的体会是:猫狗识别本身不算新鲜,难的是把识别放在一个真实运转的产品里,让它长期稳定工作。模型精度反而是整条链路上最不稀缺的东西——触发逻辑、置信度策略、数据回流、异常日志这些“脏活累活”,才真正决定了用户的日常体验。如果让我给刚起步的团队一个建议:先别急着刷准确率,把“传感器触发—拍照—推理—执行动作”这个最小闭环打通,然后装上日志立刻去真实环境跑一周,把每天的误报和漏报分类计数,再回头优化模型。你会发现,接下来要做什么,根本不用别人告诉你。