跳过正文
  1. 日常记录、技术札记与转载收藏。/

智元 GO-1 / AgiBot World GO-1

目录

要点
#

GO-1整体采用“理解-规划-执行”的分层结构。首先通过InternLM2构建的VLM将视觉和语言信息编码为多层KV cache作为环境语义表示;随后Latent Planner通过少量latent query token对这些KV进行cross-attention,提取与动作相关的规划信息并生成新的planner KV;最后Action Expert在planner KV条件下,通过Transformer与diffusion机制逐步生成连续动作序列。值得注意的是,论文中提出的LAM模块在当前代码中并未显式实现,其作用被隐式融合进VLM表示与latent planner的结构瓶颈中,从而实现跨模态动作语义的建模。

Image

论文背景
#

这个是:平台 + 数据 + 模型的系统工作。论文核心做了两件事:

  1. 构建 AgiBot World Colosseo:一个大规模真实机器人操作平台 (大规模构建数据)

  2. 提出 GO-1:一个分层的通用机器人策略模型,用于把视觉语言理解转成连续动作控制 (怎么统一异构数据)

论文想解决的问题是:

机器人通用策略之所以难,不只是模型问题,更是因为缺少大规模、高质量、标准化、真实世界的操作数据。

数据构成
#

  1. 单纯的人视频数据,没有机器人action

  2. 各种不同型号机器人动作数据,有机器人action数据

  3. 文本,没有机器人数据

go1要做的本质就是:不同来源、不同形式、不同标注方式的“视觉序列 +(可选)动作信息”,最后被统一成“帧序列 + 对齐信号”(action token)的形式。

怎么解决异构数据
#

提出Latent Action Model,一个高维度的特征空间统一表达。(这里是被隐式的收藏入Latent Planner结构中)

论文里面的故事
#

LAM(统一动作表示)I_t, I_{t+H} → z

把所有序类的变化变为:“变化” → latent action

然后通过一个Latent Planner 做cross attention 得到规划后的4个action token(这个就非常像是多模态里面的桥接器Q-former)本质上就是特征压缩

代码真实操作
#

文本与图像统一到序列里面

Image

对于action state –》token

state是这样变化的
#
Image

self.state_adaptor = nn.Linear(self.state_dim, self.action_hidden_size)

state: [B, T, state_dim]

→ Linear

→ [B, T, hidden_size]

Action是这样变化
#
Image

action_trajs = self.action_adaptor(noisy_action)

action_trajs = [B, T, hidden_size]

时间信息
#
Image

[B, 1, hidden_size]

控制频率
#
Image

[B, 1, hidden_size]

state+action+timestep+freq
#

分两步骤

1 state_action_trajs

[B, 1 + T + T, hidden_size]

2 state_action_trajs_w_tfps

[B, 1 + (1 + T + T), hidden_size]

Image

最终维度

[ timestep ]

[ freq ]

[ state_1, state_2, …, state_T ]

[ action_1, action_2, …, action_T ]

在当前 GO-1 的代码实现中,VLM 只接收图像和文本输入,用于构建统一的语义 KV 表示,并不接收任何动作信息;动作(以及状态、时间步等控制变量)是在后续 Action Expert 阶段通过 adaptor 映射为 token 序列输入,并在 attention 中与 VLM 的 KV memory 交互,从而实现感知与控制的解耦。

本质上和pi0相似都是:VLM + 条件 Transformer + Diffusion 动作生成

但但 GO-1 多了一层“Latent Planner(结构性规划瓶颈)”,而 pi0 是直接从 VLM 到 action

go1
#

VLM
#

这里有自己的一个模型。go1/internvl/model/go1/modeling_internlm2_go1.py

里面还是经典的VLM模型

实例化
#

Image

输入
#

图像

vit_embeds = self.extract_feature(pixel_values)

文本

input_embeds = self.language_model.get_input_embeddings()(input_ids).clone()

一起融合

vlm_outputs = self.language_model(…)

vlm_key_values = vlm_outputs.past_key_values

输出
#

这里的输出还是KV对

Image

抽取每一层的kv 这里可能用到了cv里面对多尺度的理解

大概长这个样子

vlm_key_values = [
  (K1, V1),
  (K2, V2),
  ...
  (KL, VL)
]

kv就是包含了上下文语义信息的(通过self-attention进行关联)

Latent Planner(隐式LAM latent action model操作)
#

原理
#

Latent Planner 的位置在 VLM 和 Action Expert 中间。它不直接输出动作,而是把 VLM 的语义记忆进一步加工成更适合动作生成的 planner KV。(个人觉得这里非常像Q-former,就是一个桥接器,做特征压缩)

输入
#

Image
Image

显式输入只有两个

  • vlm_key_values_downsample

  • attention_mask

里面的kv就是VLM里面的,经过投影层变换

for vlm_key_value, k_proj, v_proj in zip(vlm_key_values, self.k_proj_layers, self.v_proj_layers):
    vlm_key_values_downsample.append((k_proj(vlm_key_value[0]), v_proj(vlm_key_value[1])))

mask是做无关特征mask包括padding

核心
#

核心就算构造4个造 4 个 latent query token

LatentPlannerModel.forward() 里:

latent_state = torch.ones((B, 1, 1), dtype=torch.bfloat16, device=attention_mask.device) * -1

然后在 latent_action_process() 里:

H = self.latent_token_nums

action = torch.cat([state] * H, dim=1) # [B, 4, 1]

也就是先造出 4 个值为 -1 的占位 token

然后将把这 4 个 token 映射到hidden空间

state_action_trajs = self.latent_state_action_adaptor(action)

变成query,维度为[B, 4, hidden_size]

然后做crossattention

outputs = self.latent_action_expert(state_action_trajs, attention_mask, vlm_key_values_downsample)

所以 planner 不是直接输出动作,而是先从 VLM 语义空间里抽取“动作相关信息”。

然后这个应该就是变成kv了给action expert使用

输出
#

接上上面的就是输出

return (
    latent_vlm_key_values_downsample,
    outputs_latent,
)

Latent Planner 不是直接生成动作,而是把 VLM 的通用语义记忆,压缩/提炼成更偏“动作规划”的 KV memory。

这个就是论文里面所谓的核心点,动作规划(讲故事)

Action expert
#

输入
#

state token + action token + 时间步 token + 控制频率 token 然后再结合上游的KV memory

然后代码里面有配置是否开启planner,也就是说维度对齐了,这个开不开都行,这也就是go air版本

state / action / timestep / freq 组成序列的

state_action_trajs = torch.cat([state_trajs, action_trajs], dim=1)

state_action_trajs_w_tfps = torch.cat(

[timestep_tokens, freq_tokens, state_action_trajs], dim=1

)

[ timestep ][ freq ][ state tokens ][ action tokens ]

融合KV,这里很粗暴,直接拼接在里面

key_states = torch.cat([vlm_key_values[0], key_states], dim=2)

value_states = torch.cat([vlm_key_values[1], value_states], dim=2)

把上游语义 memory 直接并入自己的 attention memory 里。

输出
#

ActionExpertModel.forward() 最后输出的是:

BaseModelOutputWithPast(

last_hidden_state=hidden_states,

past_key_values=next_cache,

)

在主干里只取它的 hidden states:

state_action_output_tokens = outputs[0]

action_output_tokens = state_action_output_tokens[:, -self.action_chunk_size :, …]

action_logits = self.final_layer(action_output_tokens)

所以最终:

  • Action Expert 先输出 hidden sequence

  • 再取最后那段 action token 对应的 hidden

  • 再过 final_layer

  • 得到 action_logits

概括
#

VLM 负责把图像和文本编码成统一的多层 KV memory;Latent Planner 用 4 个 latent query token 从 VLM 的 KV 中提取动作规划信息,并生成新的 planner KV;Action Expert 再把 timestep、freq、state、noisy_action 组成 token 序列,在 planner KV 条件下通过 transformer + diffusion 生成连续动作。当前主干代码里,最终显式监督只落在动作端,即用 MSE 将 action_logits 回归到 action_gts,而 VLM 和 Latent Planner 没有在这条主路径中显式单独加 loss。

#

相关文章