
这份文档用一条主线讲清楚三个模型数据怎么进来- state / action 怎么表示- 网络 forward 怎么走- mask 和位置编码怎么起作用- 损失函数怎么训练- 推理时怎么生成动作三个模型都是 VLA 策略模型也就是Vision Language robot state - future action chunk它们不是只预测下一步动作而是一次预测未来 H 步动作通常叫 action chunk 或 action horizon。共同前提不同机器人 state 怎么统一不同平台的 state 物理含义不一样ALOHA:双臂关节角 双夹爪常见 14 维DROID:Franka 7 个关节位置 gripper常见 8 维LIBERO:末端位姿 gripper常见 7 或 8 维openpi 统一的是模型接口不是自动统一物理语义。平台适配层把各平台原始数据整理成统一格式images:base_0_rgbleft_wrist_0_rgbright_wrist_0_rgbimage_masks:每路相机是否真实存在没有的相机可以补零图并把 mask 设为 Falsestate:平台适配后的低维状态向量prompt:任务文本actions:训练时的未来 H 步动作所以换机器人时真正要保证的是state 每一维是什么意思action 每一维是什么意思单位和坐标系是什么动作是 absolute 还是 delta归一化统计量是否匹配训练0.1 归一化和 action padding平台适配之后state 和 action 还会归一化。普通归一化x_norm (x - mean) / (std eps)PI0.5 / PI0-FAST 常用分位数归一化让大部分值落到近似 [-1, 1]x_norm (x - q01) / (q99 - q01 eps) * 2 - 1这很重要因为 PI0.5 / PI0-FAST 会把 state 离散成 256 个桶。归一化错了离散后的数字文本也会错。另外模型内部常用统一 action_dim例如 32但真实机器人可能只有 7、8 或 14 维动作。所以训练:真实动作 padding 到模型 action_dim推理:模型输出裁剪回真实机器人动作维度PI0PI0 是连续动作空间里的 flow matching 模型。一句话PI0 从一段随机动作噪声开始根据图像、语言和 state把噪声逐步修正成未来 H 步动作。1.1 数据处理PI0 的训练样本包含输入:多路图像当前 stateprompt 文本标签:未来 H 步连续动作处理流程原始平台数据- 平台适配成 images / image_masks / state / prompt / actions- state 和 actions 归一化- 图像 resize 到 224 x 224- prompt 用 PaliGemma tokenizer 编码- state/actions padding 到模型 action_dimPI0 不把 state 放进文本里。prompt 只会变成语言 tokenprompt:“pick up the fork”tokenized prompt:[BOS] pick up the fork [newline] [PAD] …state 仍然是连续向量后面会变成一个单独的 state token。1.2 网络结构PI0 可以看成三部分视觉编码器images - image tokens第 0 个专家流image tokens text embeddings使用 PaliGemma/Gemma 那一路参数第 1 个专家流state token action tokens使用 Action Expert 参数最容易混淆的是不是先完整跑一个 PaliGemma再把 PaliGemma 输出送进动作网络。真正 forward 是prefix_tokens image tokens text embeddingssuffix_tokens state token action tokensprefix_out, suffix_out two_expert_transformer([prefix_tokens, suffix_tokens],mask,positions,)也就是说两路 token 一开始就一起进入双专家 Transformer。它的思想和 MMDiT 类似不同类型 token 有自己的参数流但每层 attention 在同一个空间里融合。结构图images - vision encoder - image tokens --------prompt ids - embedding table - text embeddings — 双专家 Transformer - suffix_out - action velocity/state - Linear - state token ------------------/noisy action x_t - Linear time MLP - action tokens1.3 双专家 Transformer 长什么样每层 block 可以理解成输入:xs[0] prefix tokensxs[1] suffix tokens两路分别 RMSNorm把两路 Q/K/V 沿 sequence 维拼起来做同一个 attentionattention 输出再按长度拆回两路两路各自残差更新两路分别过自己的 FFN/MLP两路各自残差更新更具体一点def two_expert_block(xs, attn_mask, positions, adarms_condNone):# 中文注释xs[0] 是 prefix 专家流xs[1] 是 action 专家流normed [] gates [] for i, x in enumerate(xs): # 中文注释每个专家有自己的 RMSNorm。 # PI0.5 的 action 专家会在这里吃 time condition。 y, gate rms_norm_i(x, condadarms_cond[i]) normed.append(y) gates.append(gate) # 中文注释跨分支融合发生在 attention。 attn_out shared_attention( normed, maskattn_mask, positionspositions, ) for i in range(2): xs[i] residual(xs[i], attn_out[i], gates[i]) ffn_out [] ffn_gates [] for i, x in enumerate(xs): y, gate rms_norm_i(x, condadarms_cond[i]) y ffn_i(y) # 中文注释FFN 不共享每个专家自己的参数。 ffn_out.append(y) ffn_gates.append(gate) for i in range(2): xs[i] residual(xs[i], ffn_out[i], ffn_gates[i]) return xsPI0 里通常是普通残差x x updatePI0.5 的 Action Expert 里可能带 adaRMS gatex x gate * update1.4 PI0 forward 怎么走训练时PI0 一次性把 prefix 和 suffix 都送进双专家 Transformer。图像编码images - image_tokens文本 embeddingtokenized_prompt - text_embeddings构造 prefixprefix_tokens concat(image_tokens, text_embeddings)构造 flow 中间动作noise ~ N(0, I)t ~ Beta(…)x_t t * noise (1 - t) * real_actions构造 suffixstate - Linear - state_tokenx_t - Linear - action_tokenst - sin/cos time embeddingaction_tokens time embedding - MLP - action_expert_tokenssuffix_tokens concat(state_token, action_expert_tokens)构造 mask 和 positionsinput_mask concat(prefix_mask, suffix_mask)ar_mask concat(prefix_ar_mask, suffix_ar_mask)attn_mask make_attn_mask(input_mask, ar_mask)positions cumsum(input_mask) - 1双专家 Transformerprefix_out, suffix_out llm([prefix_tokens, suffix_tokens], attn_mask, positions)只读 action token 输出pred_velocity action_out_proj(suffix_out[:, -H:])伪代码def pi0_train_forward(obs, real_actions):noise random_normal_like(real_actions)t sample_time()x_t t * noise (1 - t) * real_actionstarget_velocity noise - real_actionsimage_tokens vision_encoder(obs.images) text_embeddings embed_text(obs.tokenized_prompt) prefix_tokens concat(image_tokens, text_embeddings) state_token linear_state(obs.state)[:, None, :] action_tokens linear_action(x_t) time_emb sincos_time_embedding(t) time_tokens repeat(time_emb, H) action_tokens mlp(concat(action_tokens, time_tokens)) suffix_tokens concat(state_token, action_tokens) attn_mask build_pi0_attn_mask(prefix_tokens, suffix_tokens) positions build_positions_from_input_mask() prefix_out, suffix_out two_expert_transformer( [prefix_tokens, suffix_tokens], maskattn_mask, positionspositions, adarms_cond[None, None], ) pred_velocity action_out_proj(suffix_out[:, -H:]) loss mean_square(pred_velocity - target_velocity) return loss注意suffix [state_token] [H 个 action tokens]所以最后取 suffix_out[:, -H:]。state token 是条件不是输出动作。1.5 mask 怎么理解PI0 / PI0.5 里有两个关键 maskinput_mask:哪些 token 真实存在哪些是 paddingar_mask:哪些位置开启新的 attention block最终 attention maskblock_id cumsum(ar_mask)attn_mask[i, j] block_id[j] block_id[i]attn_mask 还会结合 input_mask屏蔽 paddingPI0 的简化 token 顺序[I1, I2, T1, T2, S, A1, A2, A3]其中I: image tokenT: text tokenS: state tokenA: action tokenPI0 的 ar_mask 大致是token: I1 I2 T1 T2 S A1 A2 A3ar_mask: 0 0 0 0 1 0 0 0block_id: 0 0 0 0 1 1 1 1因此prefix token:只能看 prefix不看 state/actionstate/action token:可以看 prefix也可以看整个 suffix矩阵直观如下行是 query列是 key1 表示能看I1 I2 T1 T2 S A1 A2 A3I1 1 1 1 1 0 0 0 0I2 1 1 1 1 0 0 0 0T1 1 1 1 1 0 0 0 0T2 1 1 1 1 0 0 0 0S 1 1 1 1 1 1 1 1A1 1 1 1 1 1 1 1 1A2 1 1 1 1 1 1 1 1A3 1 1 1 1 1 1 1 1这不是语言模型式的严格因果 mask。PI0 是 flow 模型一次预测整个 action chunk所以同一个 suffix block 内的 action tokens 可以互看。1.6 位置编码在哪里这里有三种容易混淆的“位置/时间”信号信号 用在哪里 作用图像 patch position embedding 视觉编码器 告诉模型 patch 在图像哪个空间位置RoPE positions Gemma/PaliGemma attention 告诉模型 token 在序列中的位置flow time sin/cos embedding Action Expert 告诉模型当前去噪时间 t视觉位置编码image - patch tokenspatch_token patch_content_embedding image_position_embeddingTransformer 序列位置用 RoPE不是给文本/action token 直接加 learned absolute position embeddingdef apply_rope(q_or_k, positions):# 中文注释positions 是每个 token 的整数位置。angle positions / frequency_by_head_dim()sin, cos sin(angle), cos(angle)x1, x2 split_last_dim(q_or_k)return concat([x1 * cos - x2 * sin, x2 * cos x1 * sin])PI0 / PI0.5 的 positions 根据有效 token 生成positions cumsum(input_mask) - 1这样 padding 不会占真实位置。例子token: I1 I2 T1 PAD T2 S A1 A2input_mask: 1 1 1 0 1 1 1 1cumsum: 1 2 3 3 4 5 6 7positions: 0 1 2 2 3 4 5 6padding 位置虽然也有数字但会被 input_mask/attn_mask 屏蔽。1.7 损失函数PI0 用 flow matching MSE。给真实动作 a 和噪声 zx_t t * z (1 - t) * atarget_velocity z - apred_velocity model(obs, x_t, t)loss mean((pred_velocity - target_velocity)^2)直观理解t 1:x_t 接近纯噪声t 0:x_t 接近真实动作模型学的是:在任意 t把 x_t 往正确方向推的速度1.8 推理过程推理时没有真实动作从随机噪声开始反向积分处理观测得到 image / state / prompt编码 prefix并缓存 prefix 的 KV cache初始化 x 随机动作噪声从 t1 开始循环 num_steps 次每步构造 suffix_tokenssuffix 通过 KV cache 读取 prefix预测 velocityEuler 更新 x x dt * velocity其中 dt 0得到动作 chunk反归一化、裁剪动作维度、必要时 delta 转 absolute训练和推理的关键区别训练:prefix 和 suffix 一起 forward推理:prefix 先 forward 一次并缓存每个去噪 step 只 forward suffix伪代码def infer_pi0(obs, num_steps10):prefix_tokens, prefix_mask encode_prefix(obs)kv_cache prefill_prefix(prefix_tokens, prefix_mask)x random_normal([batch, H, action_dim]) t 1.0 dt -1.0 / num_steps for _ in range(num_steps): suffix_tokens build_pi0_suffix(obs.state, x, t) velocity forward_suffix_with_cache(suffix_tokens, kv_cache) x x dt * velocity t t dt return postprocess_actions(x)PI0.5PI0.5 仍然是 flow matching 连续动作模型。它和 PI0 的核心区别是state 离散成数字文本放进 prefixtime 条件通过 adaRMS 调制 Action Expert一句话PI0.5 还是从动作噪声生成连续动作但 state 更早进入语言上下文time 更深地调制动作专家。2.1 数据处理PI0.5 的图像、action padding、归一化和 PI0 基本一样。区别在 prompt token 化。PI0prompt - text tokensstate - 连续 state token放进 suffixPI0.5prompt 离散 state - text/state tokenssuffix 里不再有单独 state token2.2 state 怎么离散化并放进 token 序列先归一化 state然后用 256 个桶离散化bins linspace(-1, 1, 257)[:-1]bin digitize(x, binsbins) - 1这相当于把 [-1, 1) 切成 256 段。边界行为x 1:通常落到 255x -1:可能得到 -1所以归一化统计量必须匹配训练否则离散 state 文本会变味。例子normalized_state [2.20, -0.25, 0.40, 0.30]discrete_state [255, 96, 179, 166]state_str “255 96 179 166”拼进文本模板Task: pick up the fork, State: 255 96 179 166;Action:再用 tokenizer 得到 token ids[BOS] Task : pick up the fork , State : 255 96 179 166 ; \n Action : [PAD] …注意“255” 不一定刚好是一个 token。真正流程是连续 state- 归一化- 256 桶整数- 数字字符串- prompt 文本- tokenizer ids伪代码def build_pi05_prompt(prompt, normalized_state):boundaries linspace(-1.0, 1.0, 257)[:-1]bins [] for x in normalized_state: b digitize(x, boundaries) - 1 bins.append(int(b)) state_str .join(str(b) for b in bins) text fTask: {prompt}, State: {state_str};\nAction: tokens tokenizer.encode(text, add_bosTrue) return pad_or_truncate(tokens)2.3 网络结构和 forwardPI0.5 的输入组织prefix_tokens:image tokensprompt/state text embeddingssuffix_tokens:noisy action tokenstime_cond:t - sin/cos embedding - MLP - adaRMS conditionforward 仍然是一次双专家 Transformerprefix_out, suffix_out llm([prefix_tokens, suffix_tokens],adarms_cond[None, time_cond],maskattn_mask,positionspositions,)和 PI0 的结构差异项目 PI0 PI0.5state 位置 suffix 里的连续 state token prefix 里的离散 state 文本suffix 内容 state token action tokens action tokenstime 进入方式 和 action token 拼接后过 MLP 作为 adaRMS 条件调制 Action ExpertPI0.5 的训练 forward数据阶段构造 tokenized_promptprompt discrete state - text/state tokens构造 flow 中间动作x_t t * noise (1 - t) * actionstarget_velocity noise - actionsprefiximages - image tokenstokenized_prompt - text/state embeddingsprefix_tokens concat(image tokens, text/state embeddings)suffixx_t - action_in_proj - action tokenssuffix_tokens action tokenstime conditiont - sin/cos - MLP - time_condmask / positions和 PI0 一样prefix 不看 suffixsuffix 可以看 prefix双专家 Transformerllm([prefix_tokens, suffix_tokens], adarms_cond[None, time_cond])输出action_out_proj(suffix_out[:, -H:]) - pred_velocity伪代码def pi05_train_forward(obs, actions):noise random_normal_like(actions)t sample_time()x_t t * noise (1 - t) * actionstarget_velocity noise - actionsimage_tokens vision_encoder(obs.images) text_state_embeddings embed_text(obs.tokenized_prompt) prefix_tokens concat(image_tokens, text_state_embeddings) suffix_tokens action_in_proj(x_t) time_emb sincos_time_embedding(t) time_cond swish(time_mlp_in(time_emb)) time_cond swish(time_mlp_out(time_cond)) attn_mask build_pi05_attn_mask() positions build_positions_from_input_mask() prefix_out, suffix_out two_expert_transformer( [prefix_tokens, suffix_tokens], maskattn_mask, positionspositions, adarms_cond[None, time_cond], ) pred_velocity action_out_proj(suffix_out[:, -H:]) return mean_square(pred_velocity - target_velocity)2.4 adaRMS 怎么理解普通 RMSNormnormed rms_norm(x)PI0.5 的 Action Expert 会把 time condition 变成 scale、shift、gatescale, shift, gate f(time_cond)normed rms_norm(x) * (1 scale) shiftresidual residual gate * update直觉t 接近 1:当前动作很像噪声需要大幅修正t 接近 0:当前动作接近最终动作需要细调PI0 是把 time embedding 融到 action token 里PI0.5 是让 time 直接调制 Action Expert 每层。2.5 mask、loss、推理PI0.5 的 mask 思想和 PI0 一样prefix:image prompt state text不看 action suffixsuffix:action tokens可以看 prefix也可以看整个 suffix简化序列PI0:[I, T, S, A1, A2, A3]PI0.5:[I, TStateText, A1, A2, A3]损失和 PI0 一样仍然是 flow matching MSEx_t t * noise (1 - t) * actionstarget_velocity noise - actionspred_velocity model(obs, x_t, t)loss mean((pred_velocity - target_velocity)^2)推理也和 PI0 一样从噪声反向积分只是 prefix 里多了离散 state 文本def infer_pi05(obs, num_steps10):obs.tokenized_prompt build_pi05_prompt(obs.prompt, obs.normalized_state)kv_cache prefill_prefix(obs.images, obs.tokenized_prompt)x random_normal([batch, H, action_dim]) t 1.0 dt -1.0 / num_steps for _ in range(num_steps): suffix_tokens action_in_proj(x) time_cond build_time_cond(t) velocity forward_suffix_with_cache(suffix_tokens, kv_cache, time_cond) x x dt * velocity t t dt return postprocess_actions(x)PI0-FASTPI0-FAST 和前两个模型差别最大。它不是 flow matching也不在连续动作空间里多步去噪。一句话PI0-FAST 先把连续动作变成 action tokens然后像语言模型写句子一样从左到右生成动作 token。3.1 数据处理PI0-FAST 的输入仍然来自平台适配images / image_masks / state / prompt / actions处理方式images:resize 到 224 x 224视觉编码器变成 image embeddingsstate:归一化256 桶离散化变成数字文本prompt:小写、清洗和 state 拼成 prefixactions:训练时用 FAST tokenizer 编成 action tokens文本 prefixTask: pick up the fork, State: 255 96 179 166;训练时再接动作 postfixAction: action_token_1 action_token_2 … |完整序列可以理解成[image embeddings][BOS] Task: …, State: …;Action: A1 A2 A3 … | [EOS]3.2 FAST action tokenizerPI0-FAST 需要把连续动作 [H, action_dim] 编成离散 tokencontinuous actions - FAST tokenizer - raw action tokens然后 raw action tokens 会映射到 PaliGemma/Gemma 词表末尾附近的一段 token idlm_action_token vocab_size - 1 - skip_tokens - raw_action_token直观理解语言模型原本预测文字 tokenPI0-FAST 让动作也变成词表 token于是动作生成变成 next-token prediction3.3 网络结构和 forwardPI0-FAST 是单路自回归 Gemma Transformer没有 PI0/PI0.5 的 Action Expert 双分支。结构images - vision encoder - image embeddings ----- Gemma autoregressive Transformer - vocab logitstext/state/action token ids - token embeddings --/forwardimage embeddingstokenized prompt/action ids - token embeddingsconcat 成一个长序列make_attn_mask(token_mask, ar_mask)Gemma Transformer输出每个位置的 vocab logits伪代码def pi0_fast_forward(obs):image_embeddings vision_encoder(obs.images)token_embeddings gemma_embed(obs.tokenized_prompt)sequence concat(image_embeddings, token_embeddings) attn_mask make_attn_mask(obs.token_mask, obs.ar_mask) # 中文注释训练时可以用默认 positions # decode 使用 KV cache 时必须显式传 positions。 hidden gemma_transformer(sequence, maskattn_mask) logits vocab_projection(hidden) return logits位置编码图像部分:视觉编码器内部有 patch position embeddingGemma token 序列:attention 的 Q/K 使用 RoPEdecode 阶段:新 token 的 position 要接在 prefix 已生成 token 后面3.4 mask 和损失PI0-FAST 有三种 masktoken_mask:哪些位置有效哪些是 paddingar_mask:哪些位置进入自回归区域loss_mask:哪些位置计算交叉熵损失假设序列是[I1, I2, T1, T2, ST1, ST2, “Action:”, A1, A2, A3, “|”, EOS, PAD]mask 大致是token: I1 I2 T1 T2 ST1 ST2 Act A1 A2 A3 | EOS PADtoken_mask: 1 1 1 1 1 1 1 1 1 1 1 1 0ar_mask: 0 0 0 0 0 0 1 1 1 1 1 1 0loss_mask: 0 0 0 0 0 0 1 1 1 1 1 1 0ar_mask 累加后token: I1 I2 T1 T2 ST1 ST2 Act A1 A2 A3 | EOSar_mask: 0 0 0 0 0 0 1 1 1 1 1 1block_id: 0 0 0 0 0 0 1 2 3 4 5 6因此prefix:图像 Task State作为条件不算 lossAction: / action tokens / |:自回归区域当前 token 只能看 prefix 和过去 token这些位置计算 lossPI0/PI0.5 和 PI0-FAST 的关键区别PI0 / PI0.5:一次整体生成连续 action chunkaction tokens 在 suffix 内部可以互看loss 是 velocity MSEPI0-FAST:从左到右生成 action tokens当前 action token 不能看未来 action tokenloss 是 next-token cross entropy交叉熵损失loss - sum(loss_mask[i] * log P(token[i] | previous tokens)) / sum(loss_mask)伪代码def train_pi0_fast(obs):logits pi0_fast_forward(obs)targets obs.tokenized_prompt[:, 1:] pred logits[:, :-1] mask obs.token_loss_mask[:, 1:] return cross_entropy(pred, targets, mask)3.5 推理过程推理时没有 action tokens模型自己从 “Action:” 后面生成平台适配得到 images / state / promptstate 归一化并离散成数字文本构造 prefix: Task State编码图像和 prefix建立 KV cache每次生成一个 token遇到 EOS 或达到最大步数停止解析 Action: 后、| 前的 action tokensFAST tokenizer 解码成连续动作反归一化并裁剪动作维度伪代码def infer_pi0_fast(obs, max_steps256):prefix_tokens build_fast_prefix(obs.prompt, obs.normalized_state)image_embeddings vision_encoder(obs.images)cache, last_logits gemma_prefill(image_embeddings, prefix_tokens) generated [] for step in range(max_steps): token sample_or_argmax(last_logits) generated.append(token) if token EOS: break # 中文注释decode 时新 token 的 position 接在 cache 后面。 cache, last_logits gemma_decode_one_step(token, cache) action_tokens parse_action_tokens(generated) actions fast_tokenizer_decode(action_tokens) return postprocess_actions(actions)三个模型对比项目 PI0 PI0.5 PI0-FAST动作生成 flow matching flow matching 自回归 token 生成动作表示 连续动作 连续动作 FAST action tokensstate 位置 连续 state token放 suffix 离散数字文本放 prefix 离散数字文本放 prefix网络 双专家 Transformer 双专家 Transformer 单路 Gemmatime 条件 拼到 action token 后过 MLP adaRMS 调制 Action Expert 无 flow timemask 重点 suffix 内 action 可互看 suffix 内 action 可互看 action tokens 严格自回归loss velocity MSE velocity MSE token cross entropy推理 噪声多步积分 噪声多步积分 逐 token 生成后解码一句话总结PI0:连续 state 连续动作 flow。PI0.5:离散 state 文本 连续动作 flow time adaRMS。PI0-FAST:离散 state 文本 离散 action tokens 自回归生成。5. 一条真实推理请求怎么走以 LIBERO 风格输入为例raw_obs:observation/imageobservation/wrist_imageobservation/stateprompt “pick up the fork”平台适配base_0_rgb - observation/imageleft_wrist_0_rgb - observation/wrist_imageright_wrist_0_rgb - zerosimage_mask - [True, True, False]state - observation/stateprompt - “pick up the fork”PI0prompt - text embeddingsstate - continuous state tokenrandom action noise - flow denoising - continuous actionsPI0.5state - normalize - 256-bin numbers - state textprompt state text - prefix tokensrandom action noise - flow denoising - continuous actionsPI0-FASTstate - normalize - 256-bin numbers - state textprompt state text - prefix tokensmodel generates action tokens after “Action:”FAST tokenizer decodes tokens - continuous actions最后都会做动作反归一化裁剪回真实机器人动作维度如果训练用 delta action则还原成 absolute action返回 action chunk实际执行时机器人通常只执行 action chunk 的前几步然后重新观察、重新规划。最容易混淆的点6.1 PaliGemma 不是先完整跑完再接动作头PI0 / PI0.5 的关键 forward 是llm([prefix_tokens, suffix_tokens], …)prefix_tokens 和 suffix_tokens 同时进入双专家 Transformer每层 attention 融合。PaliGemma/Gemma 参数流是第 0 个专家流不是一个前置完整模型阶段。6.2 state 统一不等于语义自动统一模型接口都叫 state但每个平台的 state 维度、单位、坐标系可能不同。适配器和训练配置必须定义清楚每一维含义。6.3 PI0.5 的 state 不是专用 state tokenPI0.5 的 state 是连续值 - 归一化 - 256 桶整数 - 数字字符串 - prompt 文本 - tokenizer ids它属于 prefix 文本条件。6.4 PI0 和 PI0.5 损失一样二者都是 flow matching MSE。区别不在损失而在state 放在哪里time 怎么进入 Action Expert6.5 PI0-FAST 的 action tokens 不是普通文本它们来自 FAST tokenizer再映射到语言模型词表的一段 token id。模型像语言模型一样训练但最后会把 token 解码回连续动作。6.6 位置编码不是只有一种图像位置:视觉编码器的 patch position embeddingtoken 顺序:Gemma/PaliGemma attention 里的 RoPE去噪时间:flow matching 的 time embedding