第十一课标准答案
上一课真正要建立的是一个判断习惯:
看到 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 State;
- Action;
都可能几乎一样。
于是虽然:
\[ 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 object;
- unseen task;
- unseen scene;
- unseen 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%?
因为两篇论文可能根本不是在考同一种考试。
例如论文 A:
Seen Object Seen Scene Seen Task成功率:
\[ 95\% \]
论文 B:
Unseen 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-level?
- Episode-level?
- Object-level?
- Task-level?
- Scene-level?
以及 Test 中哪些条件属于:
- Seen;
- Unseen;
- IID;
- OOD。
这直接决定最终评估结果到底在证明什么。
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_t=0.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-k+1},\ldots,o_{t-1},o_t] \]
这就是:
Observation History
也可以理解成:
当前时刻之前的一小段历史窗口。
例如 History Length:
\[ T_o=3 \]
那么一个输入可能是:
\[ [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_s=10 \]
那么:
\[ 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 的图像版本。
七、但“历史帧”不是越多越好吗?
不是。
假设使用:
\[ T=2 \]
模型只看很短历史。
优点:
- 数据量小;
- 计算量低;
- 延迟小。
但可能缺少更长时间信息。
如果:
\[ T=100 \]
模型看到的历史很多,
但:
- Tensor 更大;
- 显存更高;
- 计算更慢;
- 很久以前的信息可能没有价值。
所以:
\[ T \]
是一个设计参数。
不是:
越大越先进。
八、到这里我们解决的是“输入看多久”
也就是:
\[ \boxed{\text{Observation Horizon}} \]
可以粗略理解:
Policy 决策时考虑多少历史 Observation。
例如:
\[ T_o=4 \]
表示使用:
\[ o_{t-3:t} \]
也就是最近 4 个 Observation。
但是这里又出现第二个时间问题:
输出为什么只能是一个 Action?
九、以前我们一次只预测一个 Action
最基础 BC:
\[ o_t \rightarrow a_t \]
模型输入当前 Observation:
\[ o_t \]
输出:
\[ a_t \]
然后下一时刻:
\[ o_{t+1} \rightarrow a_{t+1} \]
所以运行:
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 t+1: 突然向左 0.8 cm Action t+2: 又向右 1.2 cm就可能表现为:
动作抖动、不连贯。
尤其机器人控制本身具有明显的时间连续性。
因此一个自然想法是:
能不能一次预测未来一小段连续动作?
答案是可以。
十一、于是从一个 Action 变成一串 Action
原来:
\[ a_t \]
现在预测:
\[ A_t= [ a_t, a_{t+1}, a_{t+2}, \ldots, a_{t+K-1} ] \]
这里:
\[ K \]
表示一次预测多少个 Action。
这串 Action 就可以称为:
Action Chunk
动作块。
如果:
\[ K=4 \]
那么模型一次预测:
\[ [a_t,a_{t+1},a_{t+2},a_{t+3}] \]
而不是只预测:
\[ a_t \]
十二、Action Chunk 的 Shape 怎么来?
假设单个 Action:
\[ a_t:[D_a] \]
例如:
\[ D_a=7 \]
以前一个 Sample 输出:
\[ [7] \]
现在预测未来:
\[ K=16 \]
个 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_o=2 \]
个 Observation。
输出却可能预测:
\[ K=16 \]
个 Action。
于是:
\[ Observation: [B,2,D_o] \]
而:
\[ Action: [B,16,D_a] \]
所以:
输入历史长度和输出动作长度是两个独立概念。
不要看到两个时间维就默认它们一样。
十四、为什么 Action Chunk 可能让动作更连贯?
因为模型不是把每一步当成完全孤立的问题。
它直接学习一段:
\[ [a_t,a_{t+1},\ldots,a_{t+K-1}] \]
这意味着:
模型可以同时考虑这一小段动作之间的整体关系。
例如一次抓取动作中:
靠近 ↓ 下降 ↓ 闭合 ↓ 抬起这些动作在 Demonstration 中本来就是连续发生的。
如果模型一起预测,它有机会学习:
这一小段动作应该作为一个整体保持协调。
这就是 Action Chunking 非常重要的直觉。
十五、但预测 16 个 Action,是不是一定全部执行?
不一定。
这里必须区分两个概念:
\[ \boxed{\text{Prediction Horizon}} \]
和:
\[ \boxed{\text{Execution Horizon}} \]
假设模型一次预测:
\[ 16 \]
步:
\[ [a_t,\ldots,a_{t+15}] \]
并不意味着机器人必须一口气把 16 步全部执行完。
它可以只执行前:
\[ 4 \]
步。
然后重新获取 Observation,再预测新的 Action Chunk。
于是:
Observation at t ↓ Predict 16 actions ↓ Execute first 4 ↓ New Observation ↓ Predict another 16 ↓ Execute first 4 ↓ ...这个思想以后在:
- Diffusion Policy;
- Receding Horizon Control;
中都会非常重要。
十六、为什么不直接把整个 Chunk 全执行完?
假设:
\[ K=100 \]
模型预测未来 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_o=2 \]\[ T_p=16 \]\[ T_a=8 \]
表示:
看过去2个Observation ↓ 预测未来16个Action ↓ 实际执行前8个 ↓ 重新观察 ↓ 再次预测不过不同论文对命名可能略有不同。
所以以后不能只看到horizon就自己默认含义,必须检查作者定义和代码。
十八、ACT 的 Action Chunking 为什么叫“Chunking”?
现在终于可以第一次真正理解 ACT 这个名字中的一个核心部分。
ACT:
Action Chunking with Transformers
先只看:
Action Chunking
它强调的就是:
Policy 不再只预测单个 Action,而是一次预测一段未来动作。
形式上:
\[ o_t \rightarrow [a_t,a_{t+1},\ldots,a_{t+K-1}] \]
所以 ACT 并不是突然发明一个玄学概念。
它来自一个非常自然的问题:
单步预测机器人动作容易受到时序不稳定和高频决策等问题影响,那么能不能一次学习一段动作?
答案就是:
Action Chunking
十九、但是这里有一个很重要的问题:训练数据怎么得到未来 Action Chunk?
假设 Dataset 中原本存的是:
\[ a_0,a_1,a_2,\ldots,a_T \]
现在训练样本在:
\[ t=20 \]
我们希望预测:
\[ K=4 \]
个 Action。
那么 Target 就可以从 Dataset 中切:
\[ [a_{20},a_{21},a_{22},a_{23}] \]
所以原本:
\[ (o_t,a_t) \]
这个 Sample 定义变成:
\[ \boxed{ (o_t, [a_t,a_{t+1},\ldots,a_{t+K-1}]) } \]
这就是为什么我们前面一直强调:
Dataset 中的时间结构非常重要。
Action Chunk 不是模型凭空创造未来监督信号。
这些 Future Actions 原本就在 Demonstration Trajectory 里。
二十、这时__getitem__()的职责也变了
最简单 BC Dataset:
def __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_{t+K-1}] \]
所以现在你应该重新理解:
__getitem__()不只是“读取第几个文件”。
它还可能决定:
一个训练 Sample 的时间窗口到底怎么切。
这就是代码阅读为什么必须看 Dataset 实现。
二十一、Episode 结尾会发生什么?
假设 Episode 总共只有:
\[ 100 \]
步。
现在:
\[ t=98 \]
而我们要求:
\[ K=8 \]
未来需要:
\[ a_{98},a_{99},a_{100},\ldots \]
但 Episode 已经结束。
数据不够。
于是这里才自然出现我们之前暂时没展开的:
Padding
例如有效 Action 只有:
\[ a_{98},a_{99} \]
剩下位置需要补齐到固定长度:
\[ K=8 \]
可能得到:
\[ [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
假设:
\[ B=32 \]
Observation History:
\[ T_o=3 \]
Robot State Dimension:
\[ D_s=10 \]
那么:
\[ state:[32,3,10] \]
如果图像也保留时间:
\[ image:[32,3,3,H,W] \]
注意这里出现两个 3:
第一个:
\[ 3=T_o \]
表示 3 个时间点。
第二个:
\[ 3=C \]
表示 RGB 三个 Channel。
所以必须根据位置和语义区分。
Action Chunk:
\[ K=16 \]
Action Dimension:
\[ D_a=7 \]
于是:
\[ 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 要解决的一部分问题:
问题 1
Robot Manipulation 是时间连续的。
问题 2
单步 Action Prediction 可能缺少一整段动作协调性。
问题 3
Demonstration 本身就是:
\[ 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-k+1},\ldots,o_t] \]
也就是:
\[ \boxed{\text{Observation History}} \]
因此 Tensor 出现:
\[ [B,T,D] \]
输出端:
\[ a_t \]
扩展为:
\[ [a_t,a_{t+1},\ldots,a_{t+K-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 History?
Tensor:
\[ [32,4,10] \]
中的 32、4、10 分别表示什么?
- 图像 Tensor:
\[ [16,3,3,224,224] \]
如果第一个 3 表示时间长度,那么第二个 3 表示什么?
什么叫 Single-step Action Prediction?
什么叫 Action Chunk?
如果:
\[ B=32,\quad K=20,\quad D_a=7 \]
那么 Action Chunk Batch 的 Shape 是什么?
Observation Horizon 和 Prediction Horizon 为什么不是同一个东西?
为什么“预测 16 个 Action”不一定意味着“一口气执行完 16 个 Action”?
如果 Episode 只剩 3 个 Action,但模型要求固定预测 10 个 Action,为什么可能需要 Padding?
Padding 后为什么通常还需要 Mask?
为什么 Robot Data 一旦变成:
\[ [B,T,D] \]
这种 Sequence 结构,就会自然把我们带向 Attention / Transformer?
下一课:第 13 课——Transformer 前最后一块真正必要的基础:Sequence、Token 和 Embedding
下一课我们暂时还不会直接写 Q/K/V。
因为如果现在直接写:
\[ Q=XW_Q,\qquad K=XW_K,\qquad V=XW_V \]
你很可能会知道怎么算,却不知道这里的:
\[ X \]
到底是什么。
所以第 13 课只解决这一件事:
Transformer 看到的到底不是“图片”“语言”“关节状态”,而是一串 Token 表示。
我们会把:
\[ [B,T,D] \]
进一步解释成:
\[ \boxed{ Batch \times Token/Sequence \times Embedding\ Dimension } \]
并讲清:
- Sequence 和 Token 到底是什么关系;
- 一个数字为什么不能直接代表 Token;
- Embedding 到底是什么;
- Language Token 怎么变成向量;
- Robot State 怎么变成 Token;
- Image 为什么也能变成 Visual Token;
- 为什么 Transformer 最终可以统一处理语言、视觉、机器人状态;
- Position Information 为什么必须补进去。
这一步完成以后,第 14 课就可以正式进入:
\[ \boxed{ Q,\ K,\ V,\ Attention } \]
然后再进入完整 Transformer Block。