0x0. 楔子
最近有个活动小游戏,界面长这样:

玩法很简单,遇到「好材料」按左方向键获取,「坏材料」按右方向键丢弃,判定正确就一次记分,判错则会有一个错误小动画停顿一段时间作为惩罚。这是一个典型的计算机视觉(CV)擅长的任务,正好一直久闻 Yolo 大名但没什么机会实践,这次便想从头开始试试能否用 Yolo 实现一个自动帮我玩这个小游戏的玩具。
0x1. 框架设计
不过在开始之前得先解决一些基础问题。 The very first thing is, 这是个网游。 它有着严苛的反作弊限制。 我一开始想直接在这台游戏机上用 conda 安装 yolo 来跑检测器,但惊讶地发现连 python 之类的程序也在反作弊检测范围内。 当我仅仅想跑一下官方的 demo 用例,我的游戏客户端都会直接断开连接并退出。
所以我需要
- 在另一台电脑上运行 CV 检测器;
- 用一种非常 Native 的方式输入键盘和鼠标消息,以避免反作弊识别为非法操作;
0x11. 双机屏幕识别方案
我脑中的第一个念头是在第二台电脑上用远程桌面连进去玩。但这个方案我以前试过,动不动就会产生秒级的延迟,对于这个实时判定类的游戏来说太慢了。后来我借鉴了 双机推流直播 的方案,用 OBS 的 Teleport 插件把游玩电脑的画面镜像到工作机上,再借助 OBS 的 Virtual Camera Feature,把视频流转换为虚拟摄像头设备,这样就可以在 yolo 中直接作为 source 打开了.效果如图:
0x12. 程控输入方案
由于反作弊系统都会严防死守各种模拟输入 API 机制,我这次没有尝试软件方案,而是直接掏出了家中常备的 ESP32 板子,把它模拟为 HID 设备,再用任意信道(蓝牙、Wi-Fi)给它发送要输入的键盘鼠标指令即可。至于怎么实现,只需要简单问问 Claude:

不过正巧这块板子我之前装过 CircuitPython 在玩其它东西,所以:
Claude 的编程能力现在已经非常强,这种简单的任务几乎可以保留 80% 的代码,去掉的 20% 里还有 10% 左右是不需要的注释、日志等逻辑。以前程序员键盘只有 ctrl-c ctrl-v 两个键的 Meme 现在可以改为只有 按键说话 ctrl-c ctrl-v 和 del 了。
0x2. Detector
搞定了画面输出和键鼠输入的问题后,现在可以在工作机上使用 yolo detect predict source=1 打开游戏机的画面推流,完成检测后发起 HTTP 请求 curl http://192.168.x.x/send-control/ 通知模拟成 HID 设备的 ESP32 执行按键操作了。那么最关键的检测器部分,在我翻阅完官网的 tutorio 后,发现整个流程已经相当简便且标准化、工业化。 所以我决定直接 follow 官网提到的所有步骤和平台。
0x21. annotate(打标)
我们的游戏任务是识别一系列在画面中上下排列的对象,需要识别出物体并找到它在画面中的位置。这是一个 detect 类型的任务。为了训练模型,首先需要制作一套标注了对象名称以及位置大小的数据集。目前已经有很多专为此设计的平台产品,甚至有了专门进行该种工作的工种(人工智能训练师)。 官方严选平台是 RoboFlow, 这个平台包揽了计算机视觉项目的各种 SOP,包括各类型任务的数据集拆分、打标、版本管理、模型训练、上线部署等,完全可以只使用一段录制好的视频,只用这一个平台,开发部署一个新的计算机视觉产品。 并且可以团队化协作,把打标任务分配给团队一起完成。
0x211. 数据集生成
创建好 Project 后,第一个功能就是 Upload Data。 注意到上传数据支持文件夹和视频,于是我直接录了一小段手工游玩这个小游戏的视频上去。上传成功后会弹出一个自动采样对话框,按需切分出若干张图片以便进行后续步骤。

0x212. 标注
生成数据集后,工作流进入 annotate 打标步骤。 作为一个工业级平台, RoboFlow 对于各项任务步骤的管理考虑也非常完善。真实产品的数据集可能非常大,要多次逐步完成,所以 annotate 也有多个批次(job)可供管理。 打标完成后,还可能有 review 环节,还可能 split 到训练、验证、测试等不同分类的数据集中,这些都可以很方便清晰地管理。 至于打标本身,用法就跟所有人常识能想象的过程一样,给你一张图片,在上面把物体框出来并标记它的名字(class,分类)。 我这里把需要的材料标记为「好木头」,要丢弃的标记为「坏木头」,并且选了几张有一点干扰的图片(鼠标遮挡、特效遮挡)来作为训练数据。


0x213. 数据集增强
完成标注并Review后,就可以把它加入数据集。在我过去的记忆里,模型要使用数据集训练前,要先进行归一化和增强处理,比如先统一大小,然后随机添加一点噪点和图像变化,来增强模型 robustness. 然而在这个平台上,数据集有个 version 概念,可以用相同的数据集创建不同的版本,每个版本可以选择不同的归一化和增强方式。这就可以用同样的原料快速调整炼丹配方,比如切分、画面比例、颜色曝光变化等等,尽可能减少最繁复的打标过程。

可以看到我先后尝试了几个不同版本,并且把仅进行了36张图片标注的数据扩展成了279张图片的数据集。 由于我们这次的任务仅有原始图片对象的平移缩放,所以我感觉用一个小数据集和简单的变形也足够应对了。
0x22. Training
数据集制作完成后接下来自然是训练了。 在 RoboFlow 平台上提供了一站式的模型训练-部署功能,但这是需要付费的。由于我刚开账号,有一点 credit 点数,所以姑且也尝试了一下自带的模型训练。训练过程可以实时可视化地观察模型表现曲线,完成后可以直接在平台上部署为 Web App,但想要把模型下载下来自行使用则需要付费账号,所以我没有进一步探索。
0x221. Training on Google Colab
如果想要自行部署模型,我们就必须自己训练。平台支持数据集打包下载,或者干脆直接提供了 API, 以便你在各种在线算力平台上直接用代码下载数据集。我这里选择后者,平台极其周到地提供了现成的训练用 Google Colab Jupyter 文件,只需把里面的下载代码换成自己的即可。


「令人发指」的是,Google Colab 现在 GPU 机器也有免费额度,所以我这种简单任务的模型训练完全就是白嫖。

可以看到我使用了很小的 30个 epoch 就达到了还不错的效果,虽然模型稳定性可能还欠佳,但玩这个小游戏肯定是足够了。就算出现误识别之类的情况,手动修复起来也很简单——我在游戏里换个地方或者干脆在 OBS 里把画面遮挡一下就好了。训练时间也非常短,这 30 个 epoch 好像只用了十几分钟。
跑一下测试数据,可以看到模型已经能识别我们新标注的「好木头」和「坏木头」了。
0x3. Let it play
剩下的事就很简单了,把模型下载下来,然后再让 Claude 打工给我们写一个 Python 脚本,用给 ESP32 发指令的方式不断重复游玩这个小游戏,之后挂机等着分数慢慢涨就好了😎,我最后用这个模型爬到了排行榜第六名,获得了666660分(当然手工调整了一下):


0x4. 后记 & 不足之处
说实话,现代 AI 工业程度的发达程度超出了我的想象,我原本以为至少打标和处理数据集会是一项有点折腾/费时的工作,可能要编程调试这那的细枝末节与 edge case,但其实打标训练反而是整个项目中最简单最完善的一环,你不需要知道任何技术细节和原理,所有操作都非常直观且普适,任何人都可以参与到 AI 产业中的某一环中,不再是仅有专家才能驾驭的领域。
反而是基础框架中的一些特性我还不太满意,最大的问题是 屏幕镜像。 obs-teleport 这个插件使用 TCP 协议和每帧 jpeg 压缩的方式来发送数据,这对带宽和网络质量是不小的考验。我尝试使用线缆来互联两台电脑,带宽的问题可以改善,但 TCP 丢包重传导致的延迟(最长达1秒!)却还是不可避免。有机会可能会再进一步研究一下这个插件,给它加上丢帧无延迟的udp传输方式🤔。这样这个模型就不仅能完成分数累积任务,识别速率也有希望超过人类。