面向启元 Q1 的手势交互:12 组 MobileNetV3 微调实验与 Skill 接入方案
- 写在最前面
- [一、先拆解任务:手势识别模型和机器人 Skill 各做什么](#一、先拆解任务:手势识别模型和机器人 Skill 各做什么)
- 二、实验环境与数据准备
- 三、微调设计:只训练分类头,还是同时解冻部分骨干?
- [四、12 组实验:有限样本下,微调到底带来了什么?](#四、12 组实验:有限样本下,微调到底带来了什么?)
- 五、看混淆矩阵:模型已经分清了哪些手势?
- 六、训练成本之外,还要看实际推理开销
- [七、分类结果如何接成机器人 Skill 意图?](#七、分类结果如何接成机器人 Skill 意图?)
- [八、接入启元 Q1 的下一步:把模型放在合适的位置](#八、接入启元 Q1 的下一步:把模型放在合适的位置)
- 九、写在最后

🌌你好!这里是 晓雨的笔记本 在所有感兴趣的领域扩展知识,感谢你的陪伴与支持~ 👋 一起探索具身智能、开源模型和机器人开发
写在最前面
版权声明:本文为原创技术实践记录,遵循 CC 4.0 BY-SA 协议。转载请注明出处。
给机器人增加一个新交互方式,一定要重新训练昂贵的视觉语言动作模型吗?
我最近在准备启元 Q1 探索版的交互应用时,想先实现一个简单的功能:人站在机器人面前,伸出手掌、握拳、比出剪刀手或竖起大拇指,系统就能把这些视觉信号变成不同的 Skill 意图。例如,张开手掌对应挥手,剪刀手对应语音问候,竖起大拇指对应表情反馈。
这个需求中,真正需要学习的首先是**"图像里出现了哪种手势"**。动作如何执行,可以交给机器人已有的 SDK 和 Skill;并不需要把一个轻量分类任务变成整套 VLA 的重新训练。
为此,我在 52 服务器上实际完成了 12 组 MobileNetV3-Small 微调实验,测量了识别效果、不同数据量的收益和单张图片推理延迟,最后把分类结果接成一个不会触发真实机器人动作的 Skill 意图 dry run。本文就沿着这次开发过程,拆解这个小模型怎样训练、结果有什么变化,以及未来如何接入启元 Q1。
一、先拆解任务:手势识别模型和机器人 Skill 各做什么
我把整个交互流程分为五个部分:
text
启元 Q1 摄像头画面
↓
手部检测 / ROI 提取
↓
轻量视觉分类模型(MobileNetV3-Small)
↓
置信度阈值 + 连续帧稳定判断
↓
交互意图与安全 Skill 映射
↓
Q1 SDK:语音 / 表情 / 允许的动作
这样的划分有两个好处。
第一,视觉识别与动作执行解耦。新增一种手势,只需要调整视觉模型和意图映射,不必把所有机器人控制能力重新学习一遍。
第二,系统可以分别检查每个环节。识别错误,就查看数据和混淆矩阵;识别正确但动作没有响应,则检查门控逻辑、SDK 的控制模式和实际 Skill 执行状态。
本次实验已经完成中间的视觉分类器训练与离线意图映射。机器人摄像头、手部 ROI 检测和动作执行接口,则列在最后的 Q1 接入步骤中。
二、实验环境与数据准备
这次训练使用了 52 服务器的一张 RTX 3090 24GB(GPU 3),PyTorch 和 torchvision 训练栈采用服务器中已有的依赖,没有更改其他正在运行的 GPU 实验。
模型选择 ImageNet 预训练的 MobileNetV3-Small。它能够从成熟的视觉特征出发完成四分类,而且模型和训练成本都适合交互应用中一个小型感知模块的定位。
数据来自公开的 HandGesture-Recognizer 项目,原仓库为 MIT 许可。我从中准备了 4 种手势,每类 50 张真实图片:
| 类别 | 交互含义(应用层示例) | 总图数 |
|---|---|---|
| Fist | 停止当前候选交互 / 空闲 | 50 |
| OpenPalm | 挥手 | 50 |
| PeaceSign | 语音问候 | 50 |
| ThumbsUp | 表情反馈 | 50 |
总共 200 张图。每类序号 1--30 进入训练集、31--40 进入验证集、41--50 进入测试集,因此整套实验固定为 训练 120 张、验证 40 张、测试 40 张。
这里有一个数据细节值得说明:公开图片没有提供可用于可靠分组的人员身份标识,所以当前是按图片编号分块的工程预实验,不是跨人员泛化评测。数据规模虽然小,但足以把数据准备、训练、测试和意图映射这条技术链路真正跑通。
三、微调设计:只训练分类头,还是同时解冻部分骨干?
我没有直接把预训练网络的所有参数打开,而是比较两个训练策略。
方案 A:Head-only。 冻结 MobileNetV3-Small 的视觉主干,只训练末端分类头,相当于直接利用 ImageNet 特征区分四类手势。
方案 B:Partial fine-tuning。 在训练分类头的同时,进一步解冻视觉主干最后三个特征模块,使高层视觉表示可以适应手势纹理与局部形状。
关键 PyTorch 逻辑可以概括为:
python
import torch
from torchvision import models
weights = models.MobileNet_V3_Small_Weights.IMAGENET1K_V1
model = models.mobilenet_v3_small(weights=weights)
model.classifier[-1] = torch.nn.Linear(
model.classifier[-1].in_features, 4
)
# 先冻结所有参数
for p in model.parameters():
p.requires_grad = False
# 分类头总是参与训练
for p in model.classifier.parameters():
p.requires_grad = True
# Partial 策略额外训练最后三个视觉模块
for p in model.features[-3:].parameters():
p.requires_grad = True
optimizer = torch.optim.AdamW([
{"params": model.classifier.parameters(), "lr": 1e-3},
{"params": model.features[-3:].parameters(), "lr": 1e-4},
], weight_decay=1e-4)
上面是 Partial 的核心参数设置;Head-only 则保留分类头这一组即可。
全部实验统一使用 224×224 输入、ImageNet 标准化、AdamW、8 个 epoch、batch size 16。训练时使用轻量翻转、旋转和颜色增强。最佳模型只按验证集 Macro-F1选择,随后在同一套测试图上评价。

图 1|Head-only 与 Partial 微调的训练表现。我们关心的不只是最终识别分数,也看训练过程中两种策略何时产生差异。
四、12 组实验:有限样本下,微调到底带来了什么?
除了两种训练方式,我还测试了训练数据量。Partial 分别使用每类 10、20、30 张训练图;每个条件固定运行 20261019、20261020、20261021 三个随机种子。同样的测试集不随实验组切换。
以下是全部 12 组 GPU 实验按条件汇总后的结果,均为三个种子的均值 ± 样本标准差:
| 方法 | 每类训练图数 | 测试 Accuracy | 测试 Macro-F1 | 单次训练平均耗时 |
|---|---|---|---|---|
| Head-only | 30 | 68.33% ± 5.20pp | 0.6804 ± 0.0605 | 17.36 s |
| Partial | 10 | 52.50% ± 12.50pp | 0.4910 ± 0.1217 | 19.11 s |
| Partial | 20 | 79.17% ± 1.44pp | 0.7820 ± 0.0128 | 18.77 s |
| Partial | 30 | 88.33% ± 3.82pp | 0.8835 ± 0.0367 | 21.06 s |
可以看到两个有意思的现象。
首先,微调并不是"只要解冻就会更好"。每类只有 10 张训练图时,Partial 的平均 Accuracy 只有 52.50%,不同随机种子之间波动也较大。对这种局部纹理差异很敏感的任务,数据不足时,额外可训练参数未必能得到稳定的收益。
但当每类训练数据增加到 20 和 30 张时,Partial 的表现明显改善。每类 30 张条件下,Partial 平均准确率达到 88.33% ,较相同数据量的 Head-only 提高 20.00 个百分点;两种方案的平均单次训练耗时分别约为 21 秒和 17 秒。

图 2|每类 10、20、30 张训练图时,三种随机种子的测试 Macro-F1 均值及标准差。图中误差条呈现了小样本条件下的实际波动。
这正是我认为值得做对照的地方:有限数据的手势任务,模型容量不一定是首要矛盾;可训练层数、数据量与结果稳定性,需要放在一起看。
五、看混淆矩阵:模型已经分清了哪些手势?
对固定种子 20261019 的 Partial(30) 模型,40 张测试图中有 35 张预测正确,对应 87.5% Accuracy、0.8813 Macro-F1。

图 3|一次固定测试的真实混淆矩阵,每类 10 张测试图。横纵轴是模型预测类别与真实类别。
从原始记录看,Fist 的 10 张测试图全部被识别成 Fist;OpenPalm 有 2 张、PeaceSign 有 2 张、ThumbsUp 有 1 张被错分成 Fist。这说明模型虽然能较好地识别几个目标手势,但仍存在朝某个类别集中误判的现象。
如果把这个分类器直接接到机器人动作上,这种误判就不只是一个分数问题。例如,把正常问候错误识别成"停止"还相对可控,但如果系统把没有手或背景中的物体识别为"挥手",就可能无端触发动作。
因此在实际应用里,手势分类器应当是整个交互入口的一部分,而不是唯一的触发依据。
六、训练成本之外,还要看实际推理开销
我额外做了 batch=1 的纯模型前向延迟测量。所选模型包含 1,521,956 个参数 ,checkpoint 约 5.924 MiB。
| 设备 | 平均单张前向延迟 | P95 延迟 |
|---|---|---|
| 52 服务器 CPU | 15.45 ms | 16.64 ms |
| RTX 3090 GPU 3 | 9.83 ms | 10.09 ms |
这里的计时只覆盖模型前向计算,不包括图像解码、手部定位、网络传输和动作执行。它告诉我们:为一个四分类手势入口单独部署大型视觉模型没有必要;能否形成流畅的交互,还需要继续看摄像头帧率、预处理、连续帧判断和 Skill 执行时间。
对端侧或边缘设备而言,模型大小、内存占用与推理时间往往和测试准确率同样重要。
七、分类结果如何接成机器人 Skill 意图?
训练完模型后,我没有只留下一个 best.pt,而是把它接到了一个简单的意图映射脚本里。
python
GESTURE_TO_INTENT = {
"OpenPalm": "wave",
"PeaceSign": "tts_hello",
"ThumbsUp": "emotion_happy",
"Fist": "idle_or_cancel",
}
def plan_intent(label, confidence, threshold=0.85):
if confidence < threshold:
return "idle_or_cancel"
return GESTURE_TO_INTENT.get(label, "idle_or_cancel")
在 52 服务器上,使用固定测试图片实际调用:
bash
python code/infer_dry_run.py \
--checkpoint runs/pilot_partial_30/best.pt \
--image data/processed/github_pilot/test/ThumbsUp/41.jpg
得到的结果包括:
json
{
"gesture": "ThumbsUp",
"confidence": 0.99046,
"intent": "emotion_happy",
"robot_action_dispatched": false
}
这一步已证明:训练好的权重可以加载、分类结果能转换为可读的 Skill 意图。至于 wave、tts_hello 等名称,目前是我在应用层定义的动作意图标签,不是已经核实的启元固件动作 ID。
完整的训练项目包含数据清单生成、训练、测试、资源评测和 dry run 模块。在具备上述数据与 PyTorch 依赖后,可按以下思路组织工程:
text
project/
├── data/processed/github_pilot/manifest.json
├── code/train_gesture.py
├── code/infer_dry_run.py
├── runs/pilot_partial_30/best.pt
└── results/figures/
我自己的实验使用 CUDA_VISIBLE_DEVICES=3 只占用其中一张 RTX 3090;一般复现时应改成自己机器上可用的 GPU 编号。
八、接入启元 Q1 的下一步:把模型放在合适的位置
启元 Q1 探索版开放了开发者接入能力。对这个手势项目,我计划采取独立视觉模块 + SDK Skill 调用的方式,而不是修改机器人已有的底层运动控制逻辑。
可以按这个顺序完成:
- 取帧。 根据启元官方 SDK 对应版本,选择相机图像服务或实时视频入口,将图像统一转为模型要求的颜色格式和分辨率。
- 手部定位。 使用手部检测得到 ROI,并添加没有手、非目标手势等拒绝分支,减少背景误识别。
- 稳定性门控。 对连续多帧的预测做投票或时序判断,再结合阈值决定是否触发一次意图;不是每一帧都重复发动作。
- Skill 接入。 将可信的
wave、tts_hello、emotion_happy等应用意图映射到当前 Q1 SDK 实际支持的接口和动作白名单,检查控制模式、状态与执行结果。 - 真机验证。 机器人到位后,再分别测量不同使用者、背景和光照下的误触发率、响应时延与 Skill 完成率。
这样做还有个好处:未来若要把 MobileNetV3 换成更强的视觉模型,或者增加新的手势类别,只要输出仍符合意图协议,机器人控制侧就不需要随之大改。
本次已经完成的是模型微调、定量对照、资源评测和离线意图 dry run。下一轮真正值得补的是带人员标识的数据评测以及真实相机流中的手部检测、稳定性门控;有了这些证据,再报告真机交互表现才有意义。
九、写在最后
这次实验让我更清楚地看到,机器人交互应用不一定要从重新训练整个具身大模型开始。
对于"看懂几个手势并选择一个 Skill"这样的明确任务,一个小模型就可以承担感知入口。更大的工程价值,来自把视觉识别、失败拒绝、Skill 路由和物理执行拆开,让每个环节都有能够验证的输入输出。
从 12 组真实 GPU 微调,到单张推理和意图 dry run,我们已经把最容易独立验证的部分做成了一个可扩展的模块。等到它连接上 Q1 相机与 SDK,真正需要回答的问题就会从"图片分类对不对",进一步变成"人在真实环境中发出的意图,机器人能否安全、稳定地响应"。
参考资料
1 HandGesture-Recognizer:本次四类手势图片的公开来源(MIT)。项目仓库
2 PyTorch torchvision:MobileNetV3-Small 的预训练权重与模型接口。官方文档
3 启元 Q1 官方产品资料。Q1 介绍
实验图 1---3 均根据本次 GPU 训练及评测的原始记录生成;数值和数据划分口径见文中说明。
启元机器人开发者社区
希望继续了解 Q1 的开放 SDK、相机接口及 Skill 开发方式,可以查阅 启元机器人开发者社区 的开发资料,并据此把自己的视觉模型接入机器人应用。
hello,这里是 晓雨的笔记本。后续会继续分享模型适配、开源技术与机器人开发实践,欢迎在评论区交流。