ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

037、RT-2视觉-语言-动作大模型:从互联网预训练到动作生成迁移

2026/8/20 16:21:46 拓冰建站 浏览量
037、RT-2视觉-语言-动作大模型:从互联网预训练到动作生成迁移 037、RT-2视觉-语言-动作大模型从互联网预训练到动作生成迁移调试机器人策略的时候我盯着终端里那一行行loss曲线心里直犯嘀咕——明明仿真里跑得好好的怎么一上真机就各种抽风后来想明白了问题不在你的策略网络结构也不在超参调得不够细在于你喂给它的“世界观”太窄了。你让一个从没见过真实世界多样性的模型去操作真实物体它当然只能靠猜。这就是为什么RT-2出来的时候圈子里会那么兴奋——它第一次把互联网级别的视觉语言预训练和机器人动作输出焊死在了一个模型里。今天这篇笔记咱们就把它从里到外拆一遍。从“看”到“做”的那道坎先聊个我踩过的坑。早先做机械臂抓取用的是CLIP特征接一个MLP直接回归末端位姿。仿真里精度还行一到真实桌面换个没见过的杯子模型直接懵掉。原因不复杂CLIP是给“理解”设计的它的特征空间里压根没有“怎么抓”这个维度。你硬要用理解的特征去做控制中间那个域间隙大得能跑火车。RT-2的思路是别绕弯子直接把动作当成一种“语言”来生成。它把机器人动作表示成文本token和图像、文本一起塞进同一个序列让模型在预测下一个token的时候既能看到视觉输入又能参考互联网学来的语义知识最后吐出来的就是动作。这个迁移不是简单的特征拼接而是让模型在预训练阶段学到的“物体是什么、该怎么用”这类知识直接参与动作token的预测。动作token化的那些细节这里有个关键设计动作到底怎么变成tokenRT-2的做法是把连续的动作向量离散化。比如7自由度机械臂加夹爪那就是8维连续量每个维度归一化到[-1, 1]然后均匀切分成256个bin每个bin对应一个token id。模型输出的logits经过softmax取argmax得到token id再映射回连续值。写代码的时候这里有个坑别直接对原始动作值做离散化。我一开始图省事把关节角度直接映射到token结果模型训练半天不收敛。后来查了RT-2的论文细节人家是先做归一化而且用的是对称的bin划分。你想想关节角度的分布往往集中在某个区间直接均匀切分会导致大部分token落在无效区域。归一化到[-1,1]之后再切256份每个bin的宽度就是2/256≈0.0078这个分辨率对于大多数操作任务够用了。defaction_to_tokens(action,num_bins256):# 这里踩过坑action必须是归一化到[-1, 1]的别直接拿原始弧度值来# 我之前就是忘了这步模型loss降不下去查了半天才发现是输入分布问题actionnp.clip(action,-1.0,1.0)# 映射到[0, num_bins-1]的整数区间tokens((action1.0)/2.0*(num_bins-1)).round().astype(int)returntokensdeftokens_to_action(tokens,num_bins256):# 反变换注意这里要加一个小的偏移量不然还原出来的值会偏# 别问我是怎么知道的问就是真机上机械臂抖了一下action(tokens.astype(float)/(num_bins-1))*2.0-1.0returnaction模型架构把VLM的脖子拧到机器人身上RT-2的骨干网络用的是预训练好的视觉语言模型比如PaLI-X或者PaLM-E这类。核心改动在输出头——原来VLM输出的是文本token的logits现在额外加了一组动作token的logits。训练的时候输入是“图像 文本指令 历史动作序列”输出是“下一个动作token”。这里有个设计细节值得注意动作token和文本token共享同一个embedding空间吗RT-2论文里是分开的动作token有独立的embedding层。我当时觉得共享能省参数试了一下效果差不少。原因可能是动作token的语义和文本token差异太大硬塞进同一个空间会互相干扰。所以别省那点参数独立embedding更稳。训练分两个阶段。第一阶段冻结VLM的权重只训练动作token的embedding和输出头。第二阶段解冻全部参数用机器人数据微调整个模型。这个两阶段策略很关键直接端到端训练的话VLM的预训练知识会被机器人数据冲掉那就白瞎了互联网预训练的好处。classRT2Policy(nn.Module):def__init__(self,base_vlm,num_action_tokens256,action_dim8):super().__init__()# 这里用预训练好的VLM别自己从头训不然效果差一个数量级self.vlmbase_vlm# 动作token的独立embedding别和文本embedding共享self.action_embednn.Embedding(num_action_tokens,base_vlm.hidden_size)# 动作输出头从hidden_size映射到num_action_tokensself.action_headnn.Linear(base_vlm.hidden_size,num_action_tokens)defforward(self,images,text_tokens,action_tokens_history):# 把历史动作token转成embeddingaction_embedsself.action_embed(action_tokens_history)# 和文本embedding拼接注意这里要处理好位置编码# 我一开始忘了给动作token加位置编码模型训练时loss震荡得厉害inputs_embedstorch.cat([text_embeds,action_embeds],dim1)# 过VLM主干outputsself.vlm(inputs_embedsinputs_embeds,pixel_valuesimages)# 预测下一个动作tokenaction_logitsself.action_head(outputs.last_hidden_state[:,-1,:])returnaction_logits从互联网知识到动作的迁移路径RT-2最妙的地方在于它让模型在推理的时候能调用预训练阶段学到的“常识”。比如你告诉它“把香蕉放到红色碗里”模型在预测动作token的时候会同时参考图像里香蕉的位置、碗的位置以及预训练阶段学到的“香蕉是软的抓的时候要轻一点”这类知识。这个迁移是怎么发生的关键在于训练数据的配比。RT-2的训练数据里互联网图文对占了绝大多数机器人操作数据只占一小部分。模型在预训练阶段学会了“看到什么物体就知道它是什么、该怎么用”然后在微调阶段把这种“理解”映射到动作空间。这就是为什么RT-2在零样本泛化上比之前的模型强那么多——它见过的世界足够大。但这里有个坑别把机器人数据比例调太高。我试过把机器人数据占比从5%提到20%想着能提升操作精度结果泛化能力反而下降了。原因不难理解机器人数据多了模型会过度拟合操作场景的分布互联网知识被稀释了。RT-2论文里用的比例大概是99%互联网数据 1%机器人数据这个比例不是随便定的。推理时的动作解码策略推理的时候模型输出的是动作token的logits怎么转成连续动作值最直接的做法是取argmax但这样会丢失概率信息。我试过用softmax加权平均效果反而更好——因为动作token的分布往往是多峰的argmax会选到概率最高的那个bin但真实动作可能落在两个bin之间。defdecode_action(logits,num_bins256):# 别直接argmax用softmax加权平均更稳# 这个技巧是从RT-2的代码里学来的实测能减少动作抖动probsF.softmax(logits,dim-1)bin_centerstorch.linspace(-1.0,1.0,num_bins,devicelogits.device)# 加权求和得到连续动作值actiontorch.sum(probs*bin_centers,dim-1)returnaction还有一个细节推理的时候要不要用历史动作作为输入RT-2是用的把过去几步的动作token拼到输入序列里这样模型能感知到当前的运动状态。但这里有个时序长度的问题别把历史步数设太长我试过10步推理速度慢得没法用5步左右比较合适。真机部署的那些坑模型训好了上真机又是一堆问题。RT-2的推理延迟是个大问题VLM模型动辄几十亿参数单次推理要几百毫秒。对于机器人控制来说这个延迟有点高。我当时的做法是把模型量化到int8推理速度能快3倍左右精度损失在可接受范围内。另一个坑是动作频率。RT-2的输出频率大概在1-3Hz但机械臂的底层控制需要100Hz甚至更高。解决办法是加一个插值层把RT-2输出的低频动作平滑插值成高频控制信号。这里别用简单的线性插值用三次样条插值会更平滑机械臂运动不会那么生硬。definterpolate_action(low_freq_actions,target_freq100):# 低频率动作插值到高频率# 这里用三次样条别用线性插值不然机械臂会有明显的顿挫感fromscipy.interpolateimportCubicSpline t_lownp.arange(len(low_freq_actions))t_highnp.linspace(0,len(low_freq_actions)-1,int(len(low_freq_actions)*target_freq/3))csCubicSpline(t_low,low_freq_actions,axis0)returncs(t_high)迁移学习的效果边界RT-2的迁移能力确实强但它不是万能的。我测试过几种场景发现它对“语义明确”的任务迁移效果最好比如“把红色方块放到蓝色杯子里”。但遇到需要精细力控的任务比如插USB接口RT-2就有点力不从心了——因为互联网数据里没有“插USB需要多大的力”这种信息。另外RT-2对动态场景的适应性也有限。它本质上还是开环预测没有闭环反馈。如果物体在运动过程中被碰了一下位置变了RT-2不会重新规划动作。解决办法是加一个视觉反馈循环每隔几步重新推理一次动作但这样推理延迟又上来了。这是个两难目前没有特别好的解法。个人经验总结RT-2这个方向我觉得最大的价值不在于它本身的效果而在于它证明了“互联网预训练 机器人微调”这条路是走得通的。但真要落地有几个点值得注意第一别迷信大模型。RT-2的参数量动辄几百亿不是每个团队都有资源训得动。我试过用7B的VLM做底座效果虽然不如175B的但配合好的数据配比也能达到可用的水平。关键是数据质量不是模型大小。第二动作表示的设计比模型架构更重要。RT-2用离散token表示动作这个选择很关键。如果你用连续回归模型很难利用预训练的知识。离散化让动作变成了“语言”模型才能用语言模型的训练方式去学。第三两阶段训练策略别省。直接端到端微调预训练知识会被冲掉。我见过有人图省事直接拿机器人数据微调整个模型结果泛化能力比随机初始化好不了多少。先冻结VLM训动作头再解冻微调这个顺序不能乱。第四真机部署的延迟问题目前没有完美的解法。量化、剪枝、蒸馏能用的手段都用上但延迟还是比传统控制方法高一个数量级。如果任务对实时性要求极高RT-2可能不是最佳选择。最后说一句RT-2这个方向还在快速演进现在回头看它的一些设计选择可能不是最优的。但它的核心思想——把动作当成语言、用互联网知识驱动机器人操作——这个方向我觉得是对的。后续的工作比如RT-2-X、RT-2-3D都在这个基础上做改进。如果你要入坑这个方向先把RT-2吃透再去看后续的变体会轻松很多。