先交代一下背景做机器人相关开发的人最近大概率被一类工作刷过屏——给机器人“看”一段普通视频它就能理解面前的桌子、椅子、沙发分别在哪甚至能估算出一个两米见方房间的大致三维结构。SpatialLM 就是这一类把“空间理解”做成本地可部署开源模型的代表项目之一核心能力是输入手机拍摄的普通 RGB 视频输出带语义信息的稠密 3D 点云。这套能力往小了说是“给视觉模型加空间脑”往大了说是在帮机器人补上“知道自己在哪、东西在哪、接下来怎么动”的关键一环。因为项目完全开源模型权重挂在 HuggingFace 上这几天我抽空把整个流程从环境配置到视频推理完整跑了一遍中间踩了不少文档里没写明白的坑。这篇文章会尽量把“我实际怎么做的”讲清楚包括模型原理快速扫盲、本地部署选型、HuggingFace 权重拉取附带国内下载加速方案、手机视频推理流程、点云可视化以及最后怎么样把结果接进机器人导航或机械臂操作链路。无论你是做 ROS 开发、机械臂抓取还是搞具身智能相关研究这套流程照着重跑一遍基本都能在自己的机器上把 demo 拉起来。1. SpatialLM 到底是个什么东西手机视频背后藏着怎样的空间理解能力1.1 它不是 SLAM也不是传统三维重建先说个容易混淆的点。很多人一听“视频建图”第一反应是 ORB-SLAM、COLMAP、NeRF 这一脉。这些方案在各自领域都足够成熟但它们解决的是“几何恢复”问题尽量准确地算出相机位姿和场景结构。SpatialLM 的思路不太一样它在做的是“空间语义几何重建”不仅要知道墙在哪、地板在哪还要在同一个点云里区分出哪些点属于桌面、哪些点属于椅子靠背甚至给出每个点属于某个语义类别的置信度。从技术路线上看它可以归到 3D VLAVision-Language-Action这个更大的框架里。简单说它把视频帧编码成 token通过一个类似大语言模型的自回归结构逐步预测出稠密空间特征再解码成带标签的点云。对于下游机器人任务来说这种输出的价值在于机器人拿到的不再只是一堆无意义的坐标点而是一份“带有物体边界和类别信息”的结构化描述规划路径、做抓取位姿估计都会省力很多。1.2 为什么“手机拍视频”就够了传统做法想要获得稠密点云通常要用深度相机RealSense、Kinect或者激光雷达。专用设备能给出相对精确的深度值但缺点也同样明显贵、笨重、室内外切换麻烦、部署环境受限。而手机摄像头是现成的、每个人手里都有的传感器普通 RGB 视频本身在时间序列里隐含了多视角几何信息。只要拍摄时动作别太快、光线别太暗模型就能从帧间的视差和运动信息里恢复出空间结构。这一点对机器人行业特别有价值。想想看如果一条机械臂产线需要“看懂”一个新的工位过去要先架深度相机做标定、采深度图现在直接用手机录 20 秒视频送到模型里就能得到一份初步布局点云。虽然精度肯定不如专业设备但胜在门槛足够低尤其适合做快速原型验证、数据预标注、仿真场景搭建这些对厘米级精度要求不那么苛刻的场景。1.3 标题里的“训练”二字到底指什么这里需要把话说明白手机拍视频本身并不会“重新训练”SpatialLM 的几十亿参数。标题里说“手机拍视频就能训练机器人”更准确的理解是先用手机上录好的空间视频通过预训练好的 SpatialLM 模型完成“空间理解 结构化输出”再用这个输出结果去训练机器人的导航策略、抓取策略或者作为仿真环境的初始输入。当然如果你想做进阶玩法也可以用自己采集的多视角视频数据集在官方权重基础上做微调让模型更适应特定场景——比如只在仓库货架、诊室台面这类相对固定的环境里工作时微调一轮通常能把语义边界修正得更干净。后面我会单独讲怎么做轻量化适配。2. 部署之前的环境准备显卡、CUDA、Python 依赖一次配齐2.1 硬件门槛实测显存到底要多大先说结论一张 24GB 显存的 RTX 3090 / 4090 跑起来最舒服显存 11GB 左右的卡也能跑但要把输入视频裁短一些、推理尺寸调小否则很容易被 OOM 打断。我自己的测试环境是两张卡一张 RTX 409024GB和一张 RTX 2080 Ti11GB。4090 上默认配置跑 30 秒视频毫无压力显存峰值大约在 13GB 左右2080 Ti 上如果不做任何改动直接跑大概到第 15 秒就会报 CUDA out of memory。后来我把输入分辨率从 720p 缩到 480p、帧数从 8 帧降到 4 帧2080 Ti 也能稳定跑到结束只是输出点云的稠密度会打些折扣。提示如果你是 NVIDIA 卡显存低于 8GB 的话不建议尝试光加载模型权重 激活值就很容易超限。2.2 系统与 CUDA 版本选择项目官方主要面向 Linux 环境开发Windows 用户建议直接用 WSL2 或者 Docker否则依赖编译环节容易出幺蛾子。如果你的机器是纯 Windows 裸环境并且已经装好了 CUDA理论上也能跑但 open3d、torch-scatter 这些依赖在 Windows 上编译是真的折磨人我实测下来 WSL2 的效率损失几乎可以忽略。版本搭配我验证过可以直接用的组合组件推荐版本备注Ubuntu20.04 / 22.04WSL2 也没问题CUDA11.8 或 12.1取决于 PyTorch 版本Python3.10太新太旧都可能踩依赖坑PyTorch2.1.0对应 CUDA 版本自行匹配GCC9.4源码编译点云库时需要2.3 用 Conda 创建环境并安装依赖这是最省精力的一套流程照着敲就行conda create -n spatillm python3.10 -y conda activate spatillm # 安装 PyTorch这里以 CUDA 12.1 为例 pip install torch2.1.0 torchvision0.16.0 torchaudio2.1.0 --index-url https://download.pytorch.org/whl/cu121 # 克隆项目并安装依赖 git clone https://github.com/OpenRobotLab/SpatialLM.git cd SpatialLM pip install -r requirements.txt pip install open3d依赖里比较耗时间的是 torch-scatter 和点云相关库如果 pip 下载慢可以把临时镜像源加上pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple装完以后建议立刻验证一下 PyTorch 的 CUDA 是否可用省得到后面推理阶段才发现问题python -c import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))输出是True加显卡型号就可以进入下一步了。3. HuggingFace 模型下载与部署实操从拉权重到跑通入口3.1 模型仓库里主要有哪些文件SpatialLM 的权重托管在 HuggingFace 的SpatialLM/Llama-3.2-3B-Instruct-uncensored-spatiallm仓库具体仓库名以官方 README 里放的链接为准。仓库里通常包含这几个部分config.json模型结构参数加载时需要读取model-*.safetensors或pytorch_model.bin权重文件体积一般在 6GB 以上tokenizer*分词器相关文件preprocessor_config.json输入视频预处理参数README.md官方的调用说明。下载的时候别去浏览器里点“下载”按钮体验太差。HuggingFace 提供了huggingface_hub这个命令行工具几行就能搞定。3.2 用 huggingface-cli 拉取权重先安装并登录pip install -U huggingface_hub huggingface-cli login登录的时候会要求填 Access Token到 HuggingFace 账号 Settings → Access Tokens 里生成一个读权限 token 就行。填完之后用下面的命令把整个仓库拉下来huggingface-cli download SpatialLM/Llama-3.2-3B-Instruct-uncensored-spatiallm --local-dir ./models/spatiallm如果网络状况不好下载到一半经常断建议加个环境变量启用断点续传export HF_HUB_ENABLE_HF_TRANSFER1 huggingface-cli download SpatialLM/Llama-3.2-3B-Instruct-uncensored-spatiallm --local-dir ./models/spatiallm这个hf_transfer是官方出的高速下载插件实测对大文件的下载速度提升非常明显。3.3 国内下载太慢用镜像源加速HuggingFace 官方站点在国内的访问速度确实一言难尽几十 GB 的权重硬拉不现实。好在 HuggingFace 官方社区给了方案使用hf-mirror.com镜像站点。这不是什么非正规渠道而是社区维护的官方镜像之一直接设置环境变量切换下载源即可export HF_ENDPOINThttps://hf-mirror.com设置完以后huggingface-cli和transformers的下载请求都会自动走镜像域名。下载前先确认一下镜像上是否同步了你要的仓库因为个别新仓库可能同步有延迟。我的实测结果是走镜像后6GB 左右的权重文件大概 10 分钟能下完速度稳定在每秒 8-10MB基本不需要额外折腾。提示切换镜像源只影响 HuggingFace 相关下载不会改变 PyTorch、CUDA 等其他库的行为可以放心用。3.4 写一个最小可用推理入口模型下载完成后先在项目目录下确认目录结构正确SpatialLM/ ├── models/ │ └── spatiallm/ │ ├── config.json │ ├── model-00001-of-0000X.safetensors │ └── ... ├── inference.py └── ...接着写一个极简入口文件inference.py先把“模型能加载成功”验证掉import torch from transformers import AutoModelForCausalLM, AutoProcessor model_path ./models/spatiallm print(Loading processor...) processor AutoProcessor.from_pretrained(model_path, trust_remote_codeTrue) print(Loading model...) model AutoModelForCausalLM.from_pretrained( model_path, torch_dtypetorch.float16, device_mapauto, trust_remote_codeTrue, ) print(Model loaded successfully.)这一步如果没报错说明权重文件完整、依赖齐全可以进入正式的视频推理环节了。4. 用手机视频跑完整推理流程拍摄、抽帧、重建、可视化4.1 拍摄视频的“慢、稳、亮、全”四字诀输入视频的质量直接决定输出点云的质量这一步比想象中重要得多。我前后测了室内客厅、办公室桌面、室外墙角三个场景经验可以浓缩成四个字慢手机移动速度一定要慢每秒大概平移 5-10 厘米转角度数不超过 5 度稳最好是固定在三脚架上做平移旋转纯手持拍摄抖动太厉害会导致帧间几何估计漂移亮环境光要充足避免大面积的逆光和镜头反光全保证想重建的物体在画面中完整出现不要刚拍到一半就移出镜头。视频时长建议控制在 15-30 秒分辨率 720p 足够太高反而增加解码压力。注意拍完后不要用短视频平台的“动态模板”或者加滤镜原汁原味的普通视频最合适。4.2 跑推理前的关键参数调整官方推理脚本里比较影响结果的是分段帧数和推理尺寸。我用的参数跑下来效果还不错python inference.py \ --video_path ./data/living_room.mp4 \ --output_dir ./output/living_room \ --num_frames 8 \ --height 480 \ --width 640 \ --half参数含义拆开说参数作用建议值video_path输入视频路径绝对路径更稳output_dir输出目录会自动创建num_frames从视频中抽取的帧数8 帧左右均衡速度与质量height/width推理尺寸480x640 是速度和质量平衡点half半精度推理能省一半显存抽取的帧数不是越多越好。num_frames太大比如 16 帧以上会让自回归生成序列变长显存占用快速上升而且视频里相邻帧非常相似时增加的输入并不一定能带来明显的几何精度提升。我自己的测试里 8 帧和 12 帧的差异肉眼几乎看不出但 8 帧的显存占用少了接近 3GB。4.3 用 Open3D 查看生成的点云推理完成后输出目录里会出现一个.ply文件这就是重建结果。直接用 Open3D 可视化import open3d as o3d pcd o3d.io.read_point_cloud(./output/living_room/scene.ply) o3d.visualization.draw_geometries([pcd])如果你的点云文件带了语义颜色通常是每个点一个 RGB 值比如墙面浅灰、地面深灰、物体高亮在 Open3D 里可以直接看到颜色区分。如果渲染出来是纯白色或者灰蒙蒙一片检查一下.ply文件的 header 里有没有property float red/green/blue这几列没有的话说明语义颜色没写进文件需要用可视化脚本单独做映射。我实测出来的效果是客厅点云能清晰看出沙发靠背边界、茶几顶面和地面交界线墙壁与地面的夹角也比较干净但玻璃茶几的台面区域会出现明显空洞说明透明物体仍是这类方法的薄弱点。4.4 点云后处理降噪和降采样直接生成的原始点云通常带一些漂浮的离群点如果直接拿去给下游用很容易让机器人的代价地图里多出一些“幽灵障碍物”。我习惯先做一轮统计滤波再做一个体素降采样import open3d as o3d pcd o3d.io.read_point_cloud(scene.ply) # 统计滤波去掉孤立噪点 cl, ind pcd.remove_statistical_outlier(nb_neighbors20, std_ratio2.0) pcd_filtered pcd.select_by_index(ind) # 体素降采样到 0.02m 分辨率 pcd_down pcd_filtered.voxel_down_sample(voxel_size0.02) o3d.io.write_point_cloud(scene_clean.ply, pcd_down)这步做完点云会干净很多而且点数减少后后续跑路径规划或者导入仿真引擎的压力也会小很多。5. 重建出来的点云如何真正喂给机器人5.1 导航场景转成 2D 代价地图或八叉树地图拿到点云后如果你做的是轮式机器人导航最常见的做法是把它投影成 2D 栅格地图或者转成 OctoMap 直接用。由于点云里已经分出了地面和障碍物这一步比传统 SLAM 建图要省心先把地面点云通过 RANSAC 平面拟合提取出来然后障碍物点云按高度阈值映射到二维栅格。这里有一个实用命令组合用 PCL 工具集直接做平面分割pcl_plane_segmentation scene_clean.ply plane.ply obstacles.ply \ --axis z --distance_threshold 0.03把地面点云拽掉之后剩余点云就能用octomap_server直接发到 ROS 的/maptopic或者用grid_map库转成 costmap。整个链路相当于把“空间语义感知”下沉到了地图构建之前后续导航规划器只负责在干净的代价地图上跑路径不用再花大力气处理动态障碍物分类。5.2 机械臂操作场景提取物体位姿如果你做的是机械臂抓取SpatialLM 输出里的语义标签就派上大用场了。比如场景里有一个“杯子”的聚类你可以直接用欧式聚类把杯子点云单独切出来然后计算它的包围盒质心和主轴方向作为机械臂抓取位姿的候选输入import open3d as o3d import numpy as np labels pcd_down.cluster_dbscan(eps0.03, min_points50) for label in np.unique(labels): if label 0: continue cluster pcd_down.select_by_index(np.where(labels label)[0]) bbox cluster.get_axis_aligned_bounding_box() center bbox.get_center() size bbox.get_extent() print(fCluster {label}: center{center}, size{size})拿到包围盒以后把中心点和姿态发给机械臂的逆解模块就能做粗对齐。实测下来对于桌面上的水瓶、玩具车这一类形状规则物体粗对齐精度足够让吸盘式末端执行器完成抓取如果是夹爪抓取复杂曲面物体还需要再用点云配准算法做一遍细对齐。5.3 进阶玩法用点云微调模型适配自家场景官方模型在常见室内场景上表现已经不错但如果你需要它在特定环境里更“懂行”——比如医院病房、工业货架、甚至某种特殊摆设的厨房——最直接的办法是收集一批自家场景的视频做一次轻量级微调。常见的做法是 LoRA 微调只训练模型参数里一小部分低秩矩阵单卡 24GB 显存就能跑。微调的数据格式需要把视频抽帧 标注点云配对这一步工作量大但可控。如果你只是想让模型对某类特定物体更敏感可以用少量样本做偏好优化不需要把整个模型重训一遍。需要提醒的是SpatialLM 模型的幻觉率在罕见物体上不低比如把盆栽认成桌子、把显示器支架认成椅子腿这类情况只能通过场景数据微调缓解不能靠改提示词解决。6. 常见问题与避坑实录6.1 问题速查表我把实际跑下来遇到的高频问题整理成一个表方便直接对照排查现象可能原因解决方案显存不足直接 OOM输入帧数太多 / 用了全精度调低num_frames加--half缩分辨率到 480x640模型下载到一半中断网络不稳定设置HF_ENDPOINThttps://hf-mirror.com走镜像加载模型时提示 key 不匹配权重文件损坏或版本不匹配删除本地目录重新用 huggingface-cli 拉取输出点云全是地面、主体物体漏重建相机移动太快 / 物体反光重新拍摄慢速环绕物体移动避免玻璃、高反光表面视频解码失败或帧率为 0ffmpeg 不支持编码格式用 ffmpeg 重新压制ffmpeg -i input.mp4 -vcodec libx264 -crf 23 output.mp4生成的.ply文件在 Open3D 里打不开文件写入不完整检查输出目录磁盘空间重新推理CPU 占用异常高、GPU 利用率却很低视频抽帧阻塞预先用 ffmpeg 抽帧再单独跑模型重建点云里出现大量漂浮噪点拍摄时手抖、运动模糊上三脚架放慢移动速度后处理加统计滤波6.2 我说一下最容易翻车的两个细节第一个是权重文件完整性。我在第二次部署时遇到过一次模型加载后推理结果完全乱掉的情况查了半天发现是上次下载被中断后残留了一个只有几十 MB 的损坏文件模型加载时居然没报错但输出就是垃圾。这个非常坑排查方式是把模型目录清空重下一遍别心存侥幸。第二个是输入视频的编码格式。很多手机录出来的默认视频是 HEVCH.265部分 Linux 环境没装对应解码器抽帧时会抽出一堆黑帧或者直接报错。最稳妥的做法是下载完视频后先用 ffmpeg 统一转成 H.264ffmpeg -i phone_video.mov -vcodec libx264 -crf 23 -preset fast input.mp4转换不影响视觉内容但能避免一堆解码相关的隐性问题。6.3 怎么判断当前点云质量是否够用判断重建结果能不能给机器人用我一般看三个指标几何完整性墙面、地面、主要物体是不是都在有没有大面积破洞语义正确性点云标签分布是否符合常识桌子是不是被标成了墙空间尺度一致性场景里的桌子高度、门的宽度和真实环境的误差在不在可接受范围其中第三点最容易出问题。SpatialLM 的单目重建结果天生缺少绝对尺度也就是说它输出的是“比例正确但不知道具体多少米”的点云。要拿到绝对尺度要么在拍摄时放一个已知尺寸的标定物体比如 A4 纸、已知边长的小盒子要么在后期用一个真实距离做全局缩放校准。这一步不做的话导航路径规划直接使用点云坐标会出大问题。我个人在实际操作中的体会是SpatialLM 这类“从普通视频直接出语义点云”的模型真正改变的是机器人感知系统里“语义建图”的成本结构。以前做语义地图要把语义分割、深度估计、位姿解算串成一条长链路任何一个环节精度掉链子后面全部白搭现在用一个端到端模型直接输出结构化场景描述虽然细节上还达不到工业级精度但作为快速原型、仿真预搭建和数据预标注工具性价比已经高到值得每个做机器人感知的团队都试一遍。最后再分享一个小技巧拍摄时除了慢速环绕主物体记得在视频开头和结尾各停顿两秒给足模型“观察”稳定帧的时间。这个细节我对比过有停顿的版本比全程匀速移动的版本地面平面拟合质量明显更干净下游做栅格地图投影时少踩很多坑。后面我打算继续试试点云多视角拼接、以及把输出接进机械臂仿真环境做抓取姿态预筛选等跑通再来补充。