UnifoLM-WLA-1.0 只喂一路相机画面能不能完成抓取,要分两层看:链路层面,只要配置里的相机 key 不是硬性多路校验,单目输入通常能把推理跑起来;动作层面,抓取是否稳定取决于任务是否只需要平面位置信息,以及夹爪闭合时机对深度方向有多敏感。这两层必须分开验证,不能因为看到单目能出动作就认为够用,也不能因为文档推荐多路就断定单目一定不行。手上只有一颗相机时,值得先花一两次运行把链路跑通,再用单目与补一路深度的并排记录来决定后续是否加硬件。
如果文档对相机路数只是推荐而非强制校验,单目输入一般能把 UnifoLM-WLA-1.0 的推理链路跑通,但能否完成抓取动作需要自己验证。建议先确认配置中相机相关字段是否为必填,再用同一任务、同一物体分别跑单目和补一路深度,各固定次数,只记录可观察差异。单目跑通不等于抓取可用,深度方向、遮挡和尺度判断仍是主要风险点;任何成功率结论都要来自自己的对照记录,而不是推测。
确认文档对相机路数有没有明确要求
先在仓库里搜这些关键词:camera、cameras、num_cameras、obs、modalities、image_keys、view、wrist、third_person。重点不是看示例配置怎么写,而是看代码里有没有对相机数量做断言或 shape 校验——assert len(cameras) == 2 这类硬性限制,和示例里恰好写了两路,是完全不同的性质。
把找到的原文逐条摘下来,填进下表。摘录要保留原句,不要转述,否则后面判断“必须 / 建议 / 未提及”时会失真。
| 文档或代码位置 | 原文摘录(原样抄) | 判定 | 对单目的影响 |
|---|---|---|---|
| README / 模型卡 | 待填 | 必须 / 建议 / 未提及 | 若为“必须”,单目不可行,需先改配置或补数据 |
| 默认 config(yaml/json/argparse) | 待填 | 必须 / 建议 / 未提及 | 看默认值是否可被覆盖,是否有断言 |
| 数据加载或 preprocessing 代码 | 待填 | 必须 / 建议 / 未提及 | 决定缺一路时是报错、补黑帧还是静默跳过 |
| 训练侧数据说明 | 待填 | 必须 / 建议 / 未提及 | 输入模态与训练模态不一致时,结果只能当链路验证 |
三种判定对应的动作也不同。写“必须两路”时,单目运行前要先确认校验点在哪、能否安全绕过;写“建议两路”时,单目可以先跑通链路,但抓取质量要按后面的对照表单独记录;完全未提及相机数量时,最需要防的是预处理阶段对缺失模态的处理方式不明,这种情况必须靠日志确认(见第三节)。此外要注意训练模态:如果权重是在包含深度或多视角的数据上训练的,单目输入属于输入分布变化,链路能通不能推出动作可用。
搭一个单目输入的最小调用骨架
这一节的目的只有一个:让一路相机画面能进到模型里,先看链路是否通,不评价动作好坏。下面所有接口名、类名、字段名都是占位,必须对照仓库实际定义替换,不确定的一律先标注待核对,不要按记忆硬写。
# 以下名称均为占位,替换前请逐项核对仓库定义
policy = <PolicyClass_待核对>.from_pretrained("<权重目录_待核对>")
obs = {
# 单目:只放一路,key 必须与训练时使用的 key 一致,待核对
"images": {
"<camera_key_待核对>": frame, # 形状 (H, W, 3),uint8,RGB,通道顺序待核对
},
# 机器人本体状态,字段名与维度待核对
"state": robot_state,
# 语言指令,是否为必填、字段名是 prompt 还是 task 待核对
"prompt": "pick up the <object_name>",
}
# 推理入口名称待核对:可能是 predict / act / infer
result = policy.<predict_待核对>(obs)
action = result["<action_key_待核对>"] # 动作维度、单位、是否归一化待核对
| 字段 | 含义 | 单目下的取值 | 待核对点 |
|---|---|---|---|
| images 的 key | 标识是哪一路相机 | 只用一路 | key 是否与权重训练时一致;不一致通常会被当未知输入 |
| frame 形状与 dtype | 送入预处理的原始画面 | (H, W, 3) | H/W 是否需与训练分辨率一致;uint8 还是 float |
| 通道顺序 | RGB 或 BGR | 按相机实际输出 | 转换发生在哪一步,转换前后是否各打一次日志 |
| state | 关节角、夹爪开度等本体信息 | 按机器人实际读 | 维度、单位、是否归一化 |
| prompt | 任务语言指令 | 描述抓取目标 | 是否必填;字段名可能是 prompt / task / language |
| action | 模型输出 | — | 动作空间、是否增量、夹爪维度的编码方式 |
跑通的最小标准是:不抛异常、能返回动作张量、动作维度与机器人控制接口对得上。把这次运行当作链路验证,不要在此阶段对抓取质量下判断。如果这一骨架跑不通,先回到第一节确认是否有硬性多路校验,再考虑改配置。
在日志里记录每次输入的分辨率、帧率与模态字段
单目最容易出的问题不是报错,而是某一模态没有被真正构造出来,或者被降级成占位张量,表面上仍然出动作。所以在预处理前后各打一次结构化日志,比看最终动作更有用。
# 结构化日志字段清单(键名按自己工程习惯命名,语义保持一致)
{
"frame_id": 0, # 递增帧号,失败样本要对得上
"t": "<时间戳>",
"camera_keys": ["<key_待核对>"], # 本轮实际构造了哪几路
"modalities": ["rgb"], # 实际生效的模态列表
"shape_before": [480, 640, 3],
"shape_after": [224, 224, 3], # 预处理后,用于确认是否被 resize/crop
"dtype": "uint8",
"fps_measured": "<实测值>", # 由相邻帧时间差算出,不引用外部数字
"is_placeholder": false # 该路是否为补零/黑帧
}
- 在数据进模型前打一次
camera_keys与modalities,在预处理后、拼 batch 前再打一次,两次对得上才说明输入真的进去了。 - 如果配置里写了两路、日志里只有一路 key,就说明另一路没有被构造,这时要回到预处理代码确认是跳过、补黑帧还是报错被吞掉。
is_placeholder用来区分“真的读到画面”和“用零张量占位”。占位情况下动作照出,但结果不能当作单目能力的证据。- 分辨率记录
shape_before和shape_after两个值,能看出是否存在未预期的缩放或中心裁剪。 - 帧率用相邻帧时间差自己算,不要引用文档里的标称值;相机实际输出帧率与配置声明不一致时,这里的差异会先暴露出来。
- 确认某一路模态确实被读到的办法:把
frame_id与画面内容绑定,例如让相机前出现明显变化的物体,再检查该帧号对应的日志条目里camera_keys是否包含这一路。
把单目与补一路深度的结果并排记录
这一步是判断单目够不够用的唯一依据。做法是固定任务与物体,分别用单目配置和补一路深度的配置各跑固定次数,例如各 5 次或各 10 次,次数自己定但两边必须一致。每次运行只记录可观察的差异,不要写“感觉还行”这类判断。失败也要照记,失败的记录往往比成功更能说明单目缺什么。
| 输入配置 | 任务对象 | 结果描述 |
|---|---|---|
| 单目(一路 RGB) | 例:桌面上的方形积木 | 待填:是否接近、是否闭合、卡在哪一步 |
| 单目(一路 RGB) | 同上同一物体 | 待填 |
| RGB + 深度 | 同上同一物体 | 待填 |
| RGB + 深度 | 同上同一物体 | 待填 |
结果描述尽量写到可复核的程度:机械臂是否到达目标上方、夹爪是否闭合、闭合后物体是否被抬起、动作在多少帧内结束。出现失败时,把当时的日志片段和对应画面帧编号一起贴上来,例如:
[frame_id=42] camera_keys=["<key_待核对>"] modalities=["rgb"]
shape_before=[480,640,3] shape_after=[224,224,3]
is_placeholder=false action_dim=<待核对> gripper=<待核对>
现象:夹爪在物体上方闭合但未夹住 → 对应画面帧 00000042
并排看记录时,重点找三类差异:单目是否在深度方向反复试探或提前闭合;单目是否只在某个高度或某个朝向下失败;补深度的那一组是否把这些失败消掉。如果单目与补深度的记录差别很小,说明这个任务对深度不敏感,单目继续试是合理的;如果单目集中在遮挡或远近判断上出错,那问题在输入模态,不在参数调优。记录同时要注明训练模态,输入与训练不一致时,这组数据只能说明“链路可行”,不能说明“单目方案可用”。