VLA 系统学习第 12 课:为什么机器人不能只看一帧?——时间序列、Observation History 与 Action Chunk 第十一课标准答案上一课真正要建立的是一个判断习惯看到 Robot Learning / VLA 的测试结果先不要急着看 Success Rate先看它到底怎么切数据、测试了什么“没见过的东西”。1. 为什么 Robot Dataset 随机按 Frame 划分特别容易造成 Data Leakage因为同一个 Episode 中相邻 Frame 高度相关。例如Episode 7 Frame 100 → Train Frame 101 → Test Frame 102 → Train假设控制频率很高那么 Frame 100 和 Frame 101 可能只相隔几十毫秒。它们的图像Robot StateAction都可能几乎一样。于是虽然\[ Frame_{101} \]名义上属于 Test但模型训练时已经看过几乎完全相同的\[ Frame_{100},Frame_{102} \]这样得到的 Test Performance 会被高估。这就是一种典型的\[ \boxed{\text{Data Leakage}} \]2. Episode-level split 解决了什么Episode-level split 会把一整次任务轨迹作为最小划分单位。例如\[ Episode_{0\sim79}\rightarrow Train \]\[ Episode_{80\sim89}\rightarrow Validation \]\[ Episode_{90\sim99}\rightarrow Test \]这样一个 Episode 中的相邻 Frame 不会一部分进入 Train、一部分进入 Test。因此至少解决了\[ \boxed{\text{同一条轨迹内部的时间泄漏}} \]问题。3. 为什么按 Episode 划分后仍不能自动说“泛化很好”因为不同 Episode 虽然是不同的轨迹但实验条件可能几乎完全一样。例如所有 Episode 都是同一个物体 同一个背景 同一个任务 同一个相机 相近的初始位置那么 Test 只是在相似条件下重新做一遍任务。它并没有证明模型能够处理新物体新场景新任务新语言新位置分布。所以必须继续问\[ \boxed{\text{Generalize to what?}} \]4. Seen Object 和 Unseen Object 有什么区别最直接理解如果某个物体在训练数据中出现过那么测试时再次出现可以称为Seen Object如果训练阶段完全没有出现而只在测试阶段第一次出现则可以称为Unseen Object但以后看到论文写unseen不能自动理解成“整个任务都没见过”。必须看作者具体定义的是unseen objectunseen taskunseen sceneunseen instruction还是其他东西。5. IID Test 和 OOD Test 怎么直观理解IID 可以先理解成考试题是新题但仍然来自和平时练习差不多的出题规律。例如训练\[ x\sim[-0.1,0.1] \]测试也从差不多的范围随机采样。而 OOD 可以理解成考试时出现了训练数据没有覆盖好的情况。例如训练\[ x\in[-0.1,0.1] \]测试突然变成\[ x\in[0.3,0.4] \]数据条件发生明显变化。6. Train 中\[ x\in[-0.1,0.1] \]Test 中\[ x\in[0.35,0.45] \]更接近什么更接近\[ \boxed{\text{OOD}} \]因为测试位置明显超出了训练主要覆盖范围。模型需要对训练分布之外的位置进行泛化。7. 为什么 95% Success Rate 不一定强于 85%因为两篇论文可能根本不是在考同一种考试。例如论文 ASeen Object Seen Scene Seen Task成功率\[ 95\% \]论文 BUnseen Object Unseen Scene成功率\[ 85\% \]B 的测试可能明显更困难。所以模型比较不能只看\[ Success\ Rate \]还必须一起看\[ \boxed{ Dataset Split Task Evaluation\ Protocol Metric } \]8. 阅读 Robot Learning Repository除了 Dataset Class 还必须检查什么至少继续找\[ \boxed{\text{Dataset Split Protocol}} \]也就是Train / Validation / Test 到底按照什么单位划分重点看Frame-levelEpisode-levelObject-levelTask-levelScene-level以及 Test 中哪些条件属于SeenUnseenIIDOOD。这直接决定最终评估结果到底在证明什么。VLA 系统学习第 12 课为什么机器人不能只看一帧——时间序列、Observation History 与 Action Chunk到目前为止我们为了把 Behavior Cloning 讲清楚一直把 Policy 写成\[ a_t\pi(o_t) \]意思是给我当前时刻 \(t\) 的 Observation我预测当前时刻应该执行的一个 Action。这个形式很重要但它把真实机器人中的两个时间问题隐藏掉了。第一个问题只看当前这一帧真的足够判断机器人现在在干什么吗第二个问题Policy 为什么一定要每次只预测一个 Action能不能一次预测未来一串动作这两个问题分别会引出\[ \boxed{\text{Observation History}} \]以及\[ \boxed{\text{Action Chunk}} \]而 Action Chunk 正是后面 ACT 的核心入口之一。一、先理解一张静态图片经常缺少“运动信息”假设你只看到一张照片一个机械臂夹爪在物体左侧你知道夹爪现在在哪里。但你未必知道它正在往右靠近物体还是它刚刚从右边往左退回来单独看\[ I_t \]有时候两种情况看起来几乎一样。但如果同时看到\[ I_{t-2},I_{t-1},I_t \]你就可能发现前两帧夹爪更靠左 现在逐渐向右于是知道它正在向右运动。这就是时间序列信息的价值。二、Robot State 也有同样的问题假设当前关节位置\[ q_t0.5 \]只看\[ q_t \]你只知道当前关节在 0.5。但不知道它正在向正方向运动还是负方向运动。如果前一时刻\[ q_{t-1}0.4 \]那么\[ 0.4\rightarrow0.5 \]说明它最近在增大。如果\[ q_{t-1}0.6 \]那么\[ 0.6\rightarrow0.5 \]说明它最近在减小。所以\[ q_t \]只是位置而\[ (q_{t-1},q_t) \]还隐含了运动趋势。三、这就是 Observation History以前我们使用\[ o_t \]现在把过去若干个 Observation 一起给模型\[ [o_{t-k1},\ldots,o_{t-1},o_t] \]这就是Observation History也可以理解成当前时刻之前的一小段历史窗口。例如 History Length\[ T_o3 \]那么一个输入可能是\[ [o_{t-2},o_{t-1},o_t] \]Policy 就变成\[ a_t \pi( o_{t-2}, o_{t-1}, o_t ) \]而不是\[ a_t\pi(o_t) \]四、这时候 Tensor 为什么突然多了一个维度以前一个 Robot State\[ s_t:[D_s] \]例如\[ D_s10 \]那么\[ s_t:[10] \]如果现在给过去 4 个时刻\[ s_{t-3},s_{t-2},s_{t-1},s_t \]把它们堆在一起\[ [4,10] \]第一个维度\[ 4 \]就是Time / Sequence Length通常用\[ T \]表示。于是\[ [T,D_s] \]加入 Batch\[ \boxed{ [B,T,D_s] } \]例如\[ [32,4,10] \]表示32 个 Sample每个 Sample 有连续 4 个时间点每个时间点的 Robot State 是 10 维。五、一定要区分 \(B\)、\(T\)、\(D\)以后 Transformer、ACT 中会频繁看到\[ [B,T,D] \]这三个维度必须形成条件反射。\[ B \]是Batch Size表示一次训练多少个样本。\[ T \]是Sequence Length / Time Length表示每个样本内部有多少个时间位置。\[ D \]是Feature Dimension表示每一个时间位置用多少个数字表示。所以\[ [32,4,10] \]绝对不能读成32×4×10 的三维数组。虽然数学上没错但这没有理解数据语义。你应该读成32 个训练样本每个样本包含 4 个连续时间步每个时间步有 10 维特征。这就是后面读 Transformer Tensor 的基本方式。六、图像有时间维以后 Shape 怎么变化原来一张 RGB 图\[ [3,H,W] \]一个 Batch\[ [B,3,H,W] \]如果每个 Sample 现在包含 \(T\) 张连续图片\[ \boxed{ [B,T,3,H,W] } \]例如\[ [32,4,3,224,224] \]解释32个Sample ↓ 每个Sample 4个时间点 ↓ 每个时间点1张RGB图片 ↓ 3个颜色通道 ↓ 224×224这就是 Observation History 的图像版本。七、但“历史帧”不是越多越好吗不是。假设使用\[ T2 \]模型只看很短历史。优点数据量小计算量低延迟小。但可能缺少更长时间信息。如果\[ T100 \]模型看到的历史很多但Tensor 更大显存更高计算更慢很久以前的信息可能没有价值。所以\[ T \]是一个设计参数。不是越大越先进。八、到这里我们解决的是“输入看多久”也就是\[ \boxed{\text{Observation Horizon}} \]可以粗略理解Policy 决策时考虑多少历史 Observation。例如\[ T_o4 \]表示使用\[ o_{t-3:t} \]也就是最近 4 个 Observation。但是这里又出现第二个时间问题输出为什么只能是一个 Action九、以前我们一次只预测一个 Action最基础 BC\[ o_t \rightarrow a_t \]模型输入当前 Observation\[ o_t \]输出\[ a_t \]然后下一时刻\[ o_{t1} \rightarrow a_{t1} \]所以运行Observe ↓ Predict one Action ↓ Execute ↓ Observe ↓ Predict one Action ↓ Execute ...这叫single-step action prediction单步动作预测。十、单步动作预测有什么问题假设一个抓取动作需要连续向前 向前 向下 向下 关闭夹爪 向上如果模型每一步都完全重新预测第1帧 → Action1 第2帧 → Action2 第3帧 → Action3 ...那么相邻 Action 之间可能不够一致。例如Action t: 向右 1 cm Action t1: 突然向左 0.8 cm Action t2: 又向右 1.2 cm就可能表现为动作抖动、不连贯。尤其机器人控制本身具有明显的时间连续性。因此一个自然想法是能不能一次预测未来一小段连续动作答案是可以。十一、于是从一个 Action 变成一串 Action原来\[ a_t \]现在预测\[ A_t [ a_t, a_{t1}, a_{t2}, \ldots, a_{tK-1} ] \]这里\[ K \]表示一次预测多少个 Action。这串 Action 就可以称为Action Chunk动作块。如果\[ K4 \]那么模型一次预测\[ [a_t,a_{t1},a_{t2},a_{t3}] \]而不是只预测\[ a_t \]十二、Action Chunk 的 Shape 怎么来假设单个 Action\[ a_t:[D_a] \]例如\[ D_a7 \]以前一个 Sample 输出\[ [7] \]现在预测未来\[ K16 \]个 Action。那么\[ A_t:[16,7] \]加入 Batch\[ \boxed{ A:[B,K,D_a] } \]例如\[ [32,16,7] \]应该读成32 个 Sample每个 Sample 预测未来 16 个 Action每个 Action 有 7 个维度。十三、这里的 \(T\) 和 \(K\) 不一定一样这是一个很重要的点。输入可能看\[ T_o2 \]个 Observation。输出却可能预测\[ K16 \]个 Action。于是\[ Observation: [B,2,D_o] \]而\[ Action: [B,16,D_a] \]所以输入历史长度和输出动作长度是两个独立概念。不要看到两个时间维就默认它们一样。十四、为什么 Action Chunk 可能让动作更连贯因为模型不是把每一步当成完全孤立的问题。它直接学习一段\[ [a_t,a_{t1},\ldots,a_{tK-1}] \]这意味着模型可以同时考虑这一小段动作之间的整体关系。例如一次抓取动作中靠近 ↓ 下降 ↓ 闭合 ↓ 抬起这些动作在 Demonstration 中本来就是连续发生的。如果模型一起预测它有机会学习这一小段动作应该作为一个整体保持协调。这就是 Action Chunking 非常重要的直觉。十五、但预测 16 个 Action是不是一定全部执行不一定。这里必须区分两个概念\[ \boxed{\text{Prediction Horizon}} \]和\[ \boxed{\text{Execution Horizon}} \]假设模型一次预测\[ 16 \]步\[ [a_t,\ldots,a_{t15}] \]并不意味着机器人必须一口气把 16 步全部执行完。它可以只执行前\[ 4 \]步。然后重新获取 Observation再预测新的 Action Chunk。于是Observation at t ↓ Predict 16 actions ↓ Execute first 4 ↓ New Observation ↓ Predict another 16 ↓ Execute first 4 ↓ ...这个思想以后在Diffusion PolicyReceding Horizon Control中都会非常重要。十六、为什么不直接把整个 Chunk 全执行完假设\[ K100 \]模型预测未来 100 个 Action。如果全部盲目执行Action 1 Action 2 ... Action 100中间环境稍微变化后面的动作可能已经不适合当前状态。所以一个自然策略是预测得长一点但只执行其中一部分然后重新观察。这样兼顾动作连续性闭环反馈。十七、现在出现三个非常容易混淆的 Horizon以后尤其学 Diffusion Policy 时必须分清。Observation Horizon\[ T_o \]表示输入看多少历史 Observation。Prediction Horizon\[ T_p \]表示模型一次预测多长的未来 Action Sequence。Action / Execution Horizon\[ T_a \]表示预测出来以后真正执行其中多少步再重新规划。例如\[ T_o2 \]\[ T_p16 \]\[ T_a8 \]表示看过去2个Observation ↓ 预测未来16个Action ↓ 实际执行前8个 ↓ 重新观察 ↓ 再次预测不过不同论文对命名可能略有不同。所以以后不能只看到horizon就自己默认含义必须检查作者定义和代码。十八、ACT 的 Action Chunking 为什么叫“Chunking”现在终于可以第一次真正理解 ACT 这个名字中的一个核心部分。ACTAction Chunking with Transformers先只看Action Chunking它强调的就是Policy 不再只预测单个 Action而是一次预测一段未来动作。形式上\[ o_t \rightarrow [a_t,a_{t1},\ldots,a_{tK-1}] \]所以 ACT 并不是突然发明一个玄学概念。它来自一个非常自然的问题单步预测机器人动作容易受到时序不稳定和高频决策等问题影响那么能不能一次学习一段动作答案就是Action Chunking十九、但是这里有一个很重要的问题训练数据怎么得到未来 Action Chunk假设 Dataset 中原本存的是\[ a_0,a_1,a_2,\ldots,a_T \]现在训练样本在\[ t20 \]我们希望预测\[ K4 \]个 Action。那么 Target 就可以从 Dataset 中切\[ [a_{20},a_{21},a_{22},a_{23}] \]所以原本\[ (o_t,a_t) \]这个 Sample 定义变成\[ \boxed{ (o_t, [a_t,a_{t1},\ldots,a_{tK-1}]) } \]这就是为什么我们前面一直强调Dataset 中的时间结构非常重要。Action Chunk 不是模型凭空创造未来监督信号。这些 Future Actions 原本就在 Demonstration Trajectory 里。二十、这时__getitem__()的职责也变了最简单 BC Datasetdef __getitem__(self, index): obs ... action ... return obs, actionTarget 只有\[ a_t \]但 Action Chunk Dataset 的逻辑可能更接近def __getitem__(self, index): obs ... action_chunk ... return obs, action_chunk其中\[ action\_chunk [a_t,\ldots,a_{tK-1}] \]所以现在你应该重新理解__getitem__()不只是“读取第几个文件”。它还可能决定一个训练 Sample 的时间窗口到底怎么切。这就是代码阅读为什么必须看 Dataset 实现。二十一、Episode 结尾会发生什么假设 Episode 总共只有\[ 100 \]步。现在\[ t98 \]而我们要求\[ K8 \]未来需要\[ a_{98},a_{99},a_{100},\ldots \]但 Episode 已经结束。数据不够。于是这里才自然出现我们之前暂时没展开的Padding例如有效 Action 只有\[ a_{98},a_{99} \]剩下位置需要补齐到固定长度\[ K8 \]可能得到\[ [a_{98},a_{99},PAD,PAD,PAD,PAD,PAD,PAD] \]二十二、为什么 Padding 后还需要 Mask模型必须知道哪些是真实 Action哪些只是为了凑 Shape 补出来的于是可能有\[ mask [1,1,0,0,0,0,0,0] \]其中可以约定\[ 1 \]表示有效\[ 0 \]表示 Padding。那么计算 Loss 时Padding 的那些位置不应该当成真实 Action 参与训练。否则模型会被迫学习“Episode 结束以后应该预测 PAD 伪数据。”这是错误的。所以\[ \boxed{ Padding \rightarrow 通常需要配套Mask } \]这里 Padding 和 Mask 出现就很自然了——因为现在确实遇到了变长时间序列问题。二十三、现在看一次完整 Tensor假设\[ B32 \]Observation History\[ T_o3 \]Robot State Dimension\[ D_s10 \]那么\[ state:[32,3,10] \]如果图像也保留时间\[ image:[32,3,3,H,W] \]注意这里出现两个 3第一个\[ 3T_o \]表示 3 个时间点。第二个\[ 3C \]表示 RGB 三个 Channel。所以必须根据位置和语义区分。Action Chunk\[ K16 \]Action Dimension\[ D_a7 \]于是\[ action:[32,16,7] \]这就是一个典型时间序列 Robot Learning Sample 在 Batch 后可能出现的形态。二十四、为什么这个[B,T,D]会直接把我们带向 Transformer现在出现了一个新问题。以前\[ [B,D] \]每个 Sample 只是一个向量。现在\[ [B,T,D] \]每个 Sample 内部变成了一串\[ x_1,x_2,\ldots,x_T \]也就是Sequence序列。例如\[ [x_{t-2},x_{t-1},x_t] \]或者 Action Query\[ [q_1,q_2,\ldots,q_K] \]那么模型需要理解序列中不同位置之间是什么关系这正是 Attention / Transformer 擅长处理的问题。所以 Transformer 并不是突然切换到另一个主题。它是从\[ \boxed{ Robot\ Data开始具有Sequence结构 } \]自然出现的。二十五、ACT 的问题已经逐渐显现出来了现在我们已经能提出 ACT 要解决的一部分问题问题 1Robot Manipulation 是时间连续的。问题 2单步 Action Prediction 可能缺少一整段动作协调性。问题 3Demonstration 本身就是\[ a_0,a_1,\ldots,a_T \]这样的 Sequence。于是可以考虑\[ Observation \rightarrow Action\ Sequence \]也就是\[ o_t \rightarrow A_t \]其中\[ A_t:[K,D_a] \]然后用能够处理 Sequence 的 Transformer 建模。现在“Action Chunking with Transformers”这几个词已经第一次真正连起来了\[ \boxed{ Action\ Chunk Sequence\ Modeling \rightarrow Transformer } \]但现在还不能直接进入 ACT 源码。因为我们还缺一个关键基础Transformer 到底如何理解 Sequence 中不同位置之间的关系这就是 Attention。第二十六、整章链路回看这一课从最简单 BC\[ o_t\rightarrow a_t \]进行了两个方向的扩展。输入端\[ o_t \]扩展为\[ [o_{t-k1},\ldots,o_t] \]也就是\[ \boxed{\text{Observation History}} \]因此 Tensor 出现\[ [B,T,D] \]输出端\[ a_t \]扩展为\[ [a_t,a_{t1},\ldots,a_{tK-1}] \]也就是\[ \boxed{\text{Action Chunk}} \]因此 Action Tensor 变成\[ [B,K,D_a] \]最终\[ \boxed{ Sequence\ Input \rightarrow Sequence\ Modeling \rightarrow Sequence\ Output } \]这就是我们接下来进入 Attention / Transformer 的直接原因。第十二课自测为什么只看当前一帧 \(o_t\) 有时候无法判断机器人当前的运动趋势什么叫 Observation HistoryTensor\[ [32,4,10] \]中的 32、4、10 分别表示什么图像 Tensor\[ [16,3,3,224,224] \]如果第一个 3 表示时间长度那么第二个 3 表示什么什么叫 Single-step Action Prediction什么叫 Action Chunk如果\[ B32,\quad K20,\quad D_a7 \]那么 Action Chunk Batch 的 Shape 是什么Observation Horizon 和 Prediction Horizon 为什么不是同一个东西为什么“预测 16 个 Action”不一定意味着“一口气执行完 16 个 Action”如果 Episode 只剩 3 个 Action但模型要求固定预测 10 个 Action为什么可能需要 PaddingPadding 后为什么通常还需要 Mask为什么 Robot Data 一旦变成\[ [B,T,D] \]这种 Sequence 结构就会自然把我们带向 Attention / Transformer下一课第 13 课——Transformer 前最后一块真正必要的基础Sequence、Token 和 Embedding下一课我们暂时还不会直接写 Q/K/V。因为如果现在直接写\[ QXW_Q,\qquad KXW_K,\qquad VXW_V \]你很可能会知道怎么算却不知道这里的\[ X \]到底是什么。所以第 13 课只解决这一件事Transformer 看到的到底不是“图片”“语言”“关节状态”而是一串 Token 表示。我们会把\[ [B,T,D] \]进一步解释成\[ \boxed{ Batch \times Token/Sequence \times Embedding\ Dimension } \]并讲清Sequence 和 Token 到底是什么关系一个数字为什么不能直接代表 TokenEmbedding 到底是什么Language Token 怎么变成向量Robot State 怎么变成 TokenImage 为什么也能变成 Visual Token为什么 Transformer 最终可以统一处理语言、视觉、机器人状态Position Information 为什么必须补进去。这一步完成以后第 14 课就可以正式进入\[ \boxed{ Q,\ K,\ V,\ Attention } \]然后再进入完整 Transformer Block。