LingBot-VLA 2.0机械臂抓取任务推理失灵,排查时要先放下“是不是模型坏了”的念头。抓取动作不对或没有输出,问题可能出在输入图像、文字指令、推理输出、后处理坐标变换中任意一环。日志是唯一能快速定位出环节的手段,按 preprocess/infer/postprocess 三个阶段分段确认,通常能在几分钟内把范围缩小到某一层。
判断方向:先在日志中定位 preprocess、infer、postprocess 三个阶段标记,看请求停在哪一层;再核对图像尺寸、编码格式和指令模板是否与模型输入要求一致;然后检查推理输出张量的 shape 与数值范围;若输出正常但抓空,则转向坐标变换和单位常量。保存失败输入为回归测试,防止同类问题再次出现。
先从日志确认请求在哪一层失败
在应用日志中搜索阶段标记,LingBot-VLA 2.0 的推理链路通常会打印类似 preprocess、infer、postprocess 的阶段起始和结束记录。执行以下命令快速定位最后一条成功记录:
grep -E 'preprocess|infer|postprocess' robot_vision.log | tail -50逐条看阶段标记的配对情况:
- 如果 preprocess 之后的 infer 没有出现,说明输入图像或指令在预处理阶段被拦截,常见原因是图片读取失败、尺寸不匹配、文本指令为空。
- 如果 infer 开始后没有结束记录,或出现异常堆栈,说明模型推理环节异常,需要进一步检查张量输出。
- 如果 infer 正常但 postprocess 没有坐标输出,说明解析阶段出了问题,模型可能输出了空检测框或置信度低于阈值。
建议把错误级别日志和阶段标记一起看,不要只看 error 行。失败可能表现为警告后静默返回空坐标。
检查图像与语言指令是否对齐
如果没有发现模型侧异常,先排除非模型原因。图像和指令需要严格匹配模型训练时的输入形式。使用 Python 直接检查图像属性:
python3 -c "from PIL import Image; im=Image.open('grasp.png'); print(im.size, im.mode)"核对两件事:
- 图像尺寸:模型要求的输入尺寸是否与当前图像一致;如果代码里有 resize,确认 resize 后通道数和位深没有改变。
- 编码格式:多数 VLA 模型默认接收 RGB 图像,如果上游给的是 BGR 或 RGBA,颜色通道错位会直接影响抓取判断。可以用
im.convert('RGB')强制转换后对比结果。
语言指令部分需要检查是否符合固定模板。以文本文件方式传入的指令,可以用以下命令确认是否有不可见字符或换行符混入:
printf '%s' 'grasp the red cup' | xxd如果模型要求指令以固定前缀开头,例如“instruction:”,模板缺失时同样会导致推理输出偏离。建议将模板和输入日志一起打印,确认最终送入模型的文本与预期一致。
观察推理输出张量的形状与数值范围
当 preprocess 和 infer 都有记录,仍得不到正确抓取点时,需要打印模型输出张量本身。以通用接口为例:
out = model(**inputs)
print(out.logits.shape)
print(out.logits.min().item(), out.logits.max().item())判断规则分三种情况:
- shape 与模型配置不一致:说明当前模型权重与代码中的输出头不匹配,可能是加载了错误版本的 checkpoint。
- 数值范围异常:如果出现 NaN、Inf,或所有值恒为 0,推理过程存在数值问题,需要回溯输入是否有异常值或归一化错误。
- 数值范围合理但动作不正确:模型输出的是抓取点坐标或动作分布,建议检查输出是否经过 softmax/sigmoid,以及阈值是否设置过高导致没有可取坐标。
这一步要把“模型没输出”和“输出被解析丢弃”区分开。打印原始张量后,如果确认输出有值,问题就转移到后处理坐标变换。
定位抓取点后处理坐标变换错误
机械臂动作不对或抓空,通常是模型输出的图像坐标被错误地映射到机械臂基座坐标。图像坐标到基座坐标的通用变换链路是:像素坐标 -> 相机坐标 -> 机械臂基座坐标。以下是一个可替换的骨架:
def pixel_to_base(u, v, depth_mm, fx, fy, cx, cy, ext_mat):
# 相机坐标(毫米)
x_cam = (u - cx) * depth_mm / fx
y_cam = (v - cy) * depth_mm / fy
z_cam = depth_mm
# 外参矩阵将相机坐标转换到机械臂基座坐标
point_cam = np.array([x_cam, y_cam, z_cam, 1.0])
point_base = ext_mat @ point_cam
return point_base[:3]排查时先确认几个常量:
- 深度单位:深度值到底是毫米还是米,换算错了会让抓取点偏移一个量级。
- 相机内参:fx、fy、cx、cy 是否与当前相机分辨率匹配,分辨率改变后内参要同步更新。
- 外参矩阵:相机安装角度和机械臂基座标定值是否一致,旋转和平移向量不能沿用旧标定结果。
验证时,在机械臂可达范围内放置一个已知位置标记物,用上述变换计算坐标并操作机械臂指向该点,观察误差方向。如果误差固定,通常是平移向量或单位问题;如果误差随位置变化,则可能是旋转矩阵或内参方向问题。
复现并固化失败case作为回归测试
每次失败排查完成后,把原始输入和推理输出保存下来。使用 npz 格式可以同时保存图像数组、文本指令和模型输出:
np.savez('fail_case.npz', image=img, prompt=text, output=out)之后写一条复现脚本,加载 npz 并重新走一遍预处理和推理,在每个阶段打印状态:
data = np.load('fail_case.npz')
img, text = data['image'], data['prompt']
print('image shape:', img.shape)
print('prompt:', text)
# 重新执行预处理、推理和后处理,并保留日志重点是在复现脚本中输出与线上相同的阶段标记,方便下次直接对比正常 case 与失败 case 的差异。固化后的 fail_case.npz 可以放入回归测试集,每次修改模型或后处理代码时重新运行一次,避免同类问题在更新后再次出现。注意不要只保存最终结果,预处理后的中间张量也要保存,否则无法定位到具体环节。