分享一个最近的项目。今天午饭的时候我突然想到一个问题，就是家里的车库门是没有装磁控传感器的。之前出现过几次晚上忘关门的事情。因为没有传感器，所以我家安防系统也没有报警。车库门就这么开了一晚上，非常不安全。

我手头正好有一个拇指指甲盖大小的单片机ESP32-CAM（图一），带Wifi，带摄像头，又有一定程度的算力，所以我就在想有没有可能就把这个单片机做成一个传感器。它通过拍照+片上深度神经网络的方式判断车库门是开着的还是关着的。我给它发一个HTTP请求，它就告诉我现在车库门关没关。

<img src="https://yage.ai/images/esp32_garage_door_1.jpg" alt="ESP32-CAM单片机" style="max-width: 480px; width: 100%; height: auto;" />

这个想法乍一看起来很疯狂。但它的难度比看起来要低。原因是我们要做的不是一个通用的分类器（比如hotdog or not hotdog）来处理各种各样的边界情况。我们在这里想做的是一个非常overfit的分类器。它只要解决我家车库的问题，别人家车库长得再稀奇古怪也没关系。它的位置一旦定下来之后就完全不动，车库门永远在一个地方。甚至它都不需要有太多的泛化智能，就把不同时间段车门开关的样子记下来就行了。我要的就是overfit。

因此我就把这个想法跟AI说了一下。让GPT-5.6 SOL去给我做一下这件事情，给了它我之前接近同机位的监控相机录的像。中间每过一两个小时看一下它的情况，花两到五分钟用语音识别给它下一步的建议。到了晚上我发现它做了这样的事情：

## AI做了什么

它首先用自己标注了一组数据。然后发现一个问题：车库门绝大部分的时间是关着的。所以这个分类器要想训练好的核心在于找到足够多的车库门开着的例子。所以它就自己标注了一些初始数据（用的我本地有个Vision LLM，然后它自己用contact sheet复查，见图二。哇感慨一下现在摄影的是不是都不知道什么是contact sheet）。然后训练了一个初始的vision transformer。接着用这个神经网络过了我过去几天的几十万张监控视频帧。找到了更多的车库门没关的例子，再用新数据重新训练，这么来回几次，找到了足够的数据，构建了原始的训练和测试数据。

![AI标注与Contact Sheet复查](https://yage.ai/images/esp32_garage_door_2.jpg)

在这个基础上，它就开始去试着部署到单片机上了。因为单片机的算力极度有限。这里它选用了MobileNet V4，是一个大约九十万个参数的纯卷积神经网络。（想一想现在LLM动不动几百上千亿个参数。这样几十万个参数的模型真的好小巧。）它首先做了个opportunity sizing，用开放的权重测了一下，发现端到端推理要200毫秒左右（相比之下拍照这件事本身需要400毫秒）。温度上升的也不高，用来做零散的推理没问题。接着它就把刚才收集的的训练数据在这个MobileNet V4上进行微调，得到了一个新模型。

这个模型的效果特别好，但还不能直接在部署到单片机上。为了性能需要再进行int8量化。它量化完之后发现一个问题，就是效果下降了很多，甚至有30%以上的分类结果反转了。它觉得这个不能接受。所以在我的建议下用了quantization aware training（QAT）重新训练了一个模型（它选的是LSQ-based QAT）。这下quantization error小很多了AP只掉了八个点（图三）。

![LSQ-based QAT效果曲线](https://yage.ai/images/esp32_garage_door_3.jpg)

接着它又做了一个专门用来测试的固件，烧录到了单片机上，在面跑了一个HTTP server和我们量化好的模型。我们通过HTTP POST给它一个图像，单片机就会去做预处理、推理和后处理，把最终的结果给我们。在这个基础上我们进一步用几百张测试图实测验证了我们对精度、内存、速度和温度的要求都是满足的（一些示例分类结果见图四）。于是最后AI写了一个生产版的固件，每十分钟开一张照片做推理，然后打开WiFi把结果传到我的Mac上。

![示例分类结果](https://yage.ai/images/esp32_garage_door_4.jpg)

它还特别提醒我，因为中间单片机处于深度睡眠的状态，电流非常微小，有些充电宝可能会切断电流，单片机就挂了。所以还提醒我去不同的充电宝上测了一下。最终发现有一个充电宝是不会切断电流的。于是就先用这个做了一个临时部署，现在还在采集实际数据，做更多的精度测量。

所以回头想想从中午十二点到晚上十点这十个小时的时间AI干了哪些事情？这不是一个教科书的小demo。它最厉害的是发现这个问题有一些非常独特的挑战。然后真的攻关解决了。比如说数据特别不对称，训练数据很难拿，量化误差太大等等。当然我也不是谦虚，中央的决定也是很重要的。我在方向的把握上也做了一些微小的贡献。但其中任何一个问题对哪怕是senior scientist都是一个坎。事实上如果一个senior scientist可以在一个月里面把整套流程推完，从零开始真的在一个单片机上把神经网络跑起来，我都会觉得相当不错了。但是现在我现在手上就拿着一个真的能摄像能推理的单片机，10个小时，而且整个过程我基本上没干什么事，就是过一两个小时看一眼，给点指示。

## 我们做了什么

但我讲这些也不是说AI就要取代大家的工作了，或者随便一个人用AI都能做出这样的效果。我也介绍一下我在这里面做的两件最重要的事情是什么。

第一件事是非常强调给AI足够的环境让它能够自我迭代。比如一般的开发流程可能是AI写一个固件烧到单片机里。人去按一个按钮触发拍摄和推理。单片机把结果显示在某一个地方，比如屏幕上。人跟AI说结果怎么样，AI再做下一轮迭代。但在这种开发模式里人需要始终在电脑旁边。因此我在[单片机开发skill](https://skills.superlinear.academy/?skill=m5stack-sticks3-development)里面反复和AI强调要尽最大努力打通自我开发的闭环。比如它写一个固件烧录到单片机里，接着从串口发一个指令过去。单片机就会做拍摄、做运算，接着把所有的信息包括温度、延时、计算的结果通过串口发回来。AI拿到这些数据又可以去改进程序，再一次烧录。就可以全自动地往前走了。费劲去写一个人用不上，只有AI能用上的特殊版固件，对于传统开发来说完全是浪费时间。但是对于AI自主开发来说，这是最关键的一点，让我可以用极大的杠杆率花五分钟的时间就撬动AI几个小时的干活。

第二件事是给AI技术指导。比如我会事先想好这里面有什么坑，而且跟它说怎么做。比如车库门分离器训练的难点在于不对称的训练数据。这个是我一开始就跟它讲好的。所以它就没有走弯路，直接从问题的核心开始着手解决。怎么解决也是我给它建议：用local LLM去做标注，你来做复核。QAT也是我看到quantization loss太大给它建议的。这里最关键的一点是，我百分之八九十的精力都花在这些最技术的事情上面，而不用天天想着influence without authority，作为IC跟小弟们开会，跟领导拍胸脯，align整个组去照我说的做。终于可以把时间花在自己又擅长又享受的事情上面。这是我觉得最开心的一点。

所以这几年我对AI时代人要怎么适应的判断[从来没变过](/ai-paddler.html)。就是我们码农就好像人力船上的划桨手一样。不论是学校训练还是公司升职用的标准都是看你划桨划得快不快。但AI像蒸汽机一样进来把桌子直接掀了。你划得再快，吃得再少也没有AI 24x7跑得快。但这并不意味着AI就不需要人类了。人跟人之间的差距从以前谁划桨划得快，变成了谁能让AI尽可能长时间地自主工作，而不用老停下来休整，被人拖累。但这是一个全新的技能，甚至和以前划桨划得好不好是相冲突的。因此，只有先尽快地忘却那些根深蒂固的肌肉记忆，积极去拥抱新时代的价值观，才有可能在速度上进行数量级的提升。当然在这个新前提下，往哪划可能比划得多快更重要。但怎么去提升认知，知道往哪划就是另一个故事了。

<script async data-uid="49b08a3e73" src="https://yage-ai.kit.com/49b08a3e73/index.js"></script>
