第十二课标准答案1. 为什么只看当前一帧 \(o_t\) 有时候无法判断运动趋势因为\[ o_t \]只能描述“现在是什么样”不一定包含“刚才是怎么变过来的”。例如当前关节位置\[ q_t0.5 \]仅凭这一点无法判断它正在\[ 0.4\rightarrow0.5 \]还是\[ 0.6\rightarrow0.5 \]所以加入过去 Observation\[ [o_{t-1},o_t] \]就能提供一定时间信息。2. 什么叫 Observation History就是Policy 不只看当前 Observation而是同时看过去若干个 Observation。例如\[ T_o3 \]那么\[ [o_{t-2},o_{t-1},o_t] \]就是一个长度为 3 的 Observation History。3. Tensor\[ [32,4,10] \]分别是什么\[ 32B \]Batch Size一次 32 个训练样本。\[ 4T \]每个样本包含 4 个时间步。\[ 10D \]每个时间步由 10 个特征描述。所以应该读成32 个样本每个样本有 4 个时间位置每个时间位置是 10 维特征。4. 图像 Tensor\[ [16,3,3,224,224] \]如果第一个 3 是时间长度那么第二个 3 是什么第二个\[ 3 \]表示 RGB Channel\[ R,G,B \]所以\[ [B,T,C,H,W] \]这里是\[ [16,3,3,224,224] \]即16 个样本每个样本有 3 帧每帧 RGB 三通道图片尺寸 224×224。5. 什么叫 Single-step Action Prediction就是一次只预测\[ a_t \]一个 Action。形式\[ o_t\rightarrow a_t \]执行后重新观察再预测\[ o_{t1}\rightarrow a_{t1} \]6. 什么叫 Action Chunk不是只预测一个 Action而是一次预测一串未来 Action\[ A_t [a_t,a_{t1},\ldots,a_{tK-1}] \]这一小段连续 Action 就叫Action Chunk7. 如果\[ B32,\quad K20,\quad D_a7 \]Action Chunk Shape 是什么\[ \boxed{[32,20,7]} \]含义32 个 Sample每个 Sample 预测 20 个未来 Action每个 Action 是 7 维。8. Observation Horizon 和 Prediction Horizon 为什么不是一个东西Observation Horizon 回答模型往过去看多久例如\[ T_o3 \]输入\[ [o_{t-2},o_{t-1},o_t] \]Prediction Horizon 回答模型往未来预测多长例如\[ T_p16 \]输出\[ [a_t,a_{t1},\ldots,a_{t15}] \]所以完全可以\[ T_o2,\qquad T_p16 \]两者没有必须相等的关系。9. 为什么预测 16 个 Action不一定执行完 16 个因为真实环境会变化。可以观察 ↓ 预测16步 ↓ 只执行前4步 ↓ 重新观察 ↓ 再预测16步这样既保留一定动作连续性又保持闭环反馈。10. Episode 只剩 3 个 Action但要求固定 10 个怎么办因为模型通常希望固定 Shape\[ [K,D_a] \]如果\[ K10 \]但真实只剩\[ 3 \]个 Action就可能需要用 Padding 补齐剩下 7 个位置。11. Padding 后为什么还需要 Mask因为模型必须知道哪些是真数据哪些只是为了凑长度补出来的。例如\[ mask [1,1,1,0,0,0,0,0,0,0] \]前 3 个有效后面 7 个是 Padding。否则 Loss 可能错误地把 Padding 当成真实动作训练。12. 为什么[B,T,D]会自然把我们带向 Transformer因为\[ T \]代表一个Sequence。模型现在不只处理单个向量而是\[ x_1,x_2,\ldots,x_T \]这样一串位置。于是问题变成第 1 个位置和第 5 个位置有什么关系哪个时间步对当前决策更重要不同位置之间的信息应该怎样交互这正是 Attention / Transformer 最擅长处理的问题。VLA 系统学习第 13 课Transformer 到底看到什么——Sequence、Token、Embedding 和 Position上一课我们已经自然得到\[ [B,T,D] \]也就是说每个 Sample 不再只是一个向量而是一个 Sequence\[ x_1,x_2,\ldots,x_T \]接下来真正进入 Transformer 前必须先解决一个很容易被讲模糊的问题Transformer 里的“Token”到底是什么因为后面一上来就会出现\[ X\in\mathbb R^{B\times T\times D} \]然后\[ QXW_Q \]如果现在连 \(X\) 里面装的是什么都不清楚Q/K/V 很容易沦为背公式。一、Sequence 不等于 Language很多人第一次接触 Transformer是从语言模型开始的。于是容易形成Token 单词这种印象。但严格来说不是。Token 更准确的理解是Transformer Sequence 中的一个“位置单位”。语言里一个 Token 可以来自pick up the block图像里一个 Token 可以对应一块图像 Patch。机器人状态里一个 Token 可以对应某一个时间步经过编码后的 Robot State。所以\[ \boxed{ Token不是某一种具体数据 } \]而是Transformer 序列中的一个信息单元。二、先看最熟悉的 Language Token假设一句话pick up the red blockTokenizer 处理以后可能得到若干 Token。为了教学假设得到[pick, up, the, red, block]实际上现代 Tokenizer 往往还会进行 subword 切分所以真实结果不一定正好等于单词。然后每个 Token 会映射成一个 Token ID。例如教学示意pick → 17 up → 52 the → 4 red → 91 block → 33于是\[ tokens [17,52,4,91,33] \]Shape\[ [T] \]其中\[ T5 \]三、为什么不能直接把 Token ID 喂进 Transformer因为\[ 17 \]和\[ 52 \]只是编号。不能理解成52 比 17 大所以up比pick多 35 个单位。Token ID 没有这种连续数值意义。它更像学生1号 学生17号 学生52号编号只是身份标识。因此需要把\[ Token\ ID \]转换成一个向量\[ Embedding \]四、Embedding 到底是什么假设\[ D4 \]每个 Token 被表示成 4 维向量。例如\[ 17 \rightarrow [0.2,-0.4,0.8,0.1] \]\[ 52 \rightarrow [-0.5,0.3,0.1,0.9] \]那么一句 5 Token 的话\[ [17,52,4,91,33] \]经过 Embedding 以后就从\[ [5] \]变成\[ [5,4] \]也就是\[ [T,D] \]加入 Batch\[ \boxed{ [B,T,D] } \]看到没有这正好和上一课的 Sequence Tensor 接上了。五、代码里 Embedding 长什么样PyTorchimport torchimport torch.nn as nnembedding nn.Embedding( num_embeddings100, embedding_dim4)这里num_embeddings100意思是我的词表中有 100 个不同 Token ID。而embedding_dim4表示每个 Token 最终变成一个 4 维向量。现在输入token_ids torch.tensor([ [17, 52, 4, 91, 33], [12, 8, 7, 31, 2]])Shape\[ [2,5] \]也就是Batch 2每句话 5 个 Token。执行x embedding(token_ids)输出 Shape\[ [2,5,4] \]所以代码链就是Token ID [B,T] ↓ nn.Embedding ↓ Token Embedding [B,T,D]六、nn.Embedding本质上里面是什么它内部可以先理解成有一张大表\[ E\in\mathbb R^{V\times D} \]其中\[ V \]是 Vocabulary Size\[ D \]是 Embedding Dimension。例如\[ E:[100,4] \]每一行对应一个 Token 的向量。如果 Token ID\[ 17 \]就取\[ E_{17} \]这一行。因此embedding(token_ids)本质上是在根据 Token ID从 Embedding Table 里查对应的向量。所以 Embedding 很像\[ \boxed{ ID\rightarrow Vector } \]七、Embedding 也是可训练 Parameter这点很重要。nn.Embedding(100, 4)内部的 Embedding Table 不是固定死的。它也是\[ Parameter \]训练时loss.backward()可以计算\[ \frac{\partial L}{\partial E} \]Optimizer 再更新它。所以最开始red对应的向量可能是随机的。训练以后模型会逐渐学习哪种向量表示更有利于当前任务。这和我们前面学习\[ W,b \]完全是一回事。八、那 Robot State 怎么变成 Token语言有 Token ID可以查 Embedding Table。Robot State 不一样。假设某个时间步\[ s_t\in\mathbb R^{10} \]它本身已经是连续数值\[ [0.1,-0.3,0.8,\ldots] \]所以通常不需要State → Token ID → Embedding Table更自然的做法是用 Linear Projection\[ s_t\in\mathbb R^{10} \]映射到 Transformer 使用的\[ D64 \]维度\[ e_tW_ss_tb_s \]于是\[ [10]\rightarrow[64] \]这个\[ [64] \]就可以作为一个 Robot State Token。九、代码里 Robot State Token 怎么做例如state_encoder nn.Linear(10, 64)现在 Batch 中有\[ state:[32,4,10] \]其中32 个 Sample4 个时间步每个 State 10 维。直接state_tokens state_encoder(state)nn.Linear会作用在最后一个维度。所以\[ [32,4,10] \rightarrow [32,4,64] \]也就是\[ [B,T,D_s] \rightarrow [B,T,D_{model}] \]现在每个时间步\[ [10] \]变成\[ [64] \]于是 Transformer 可以把它理解成长度为 4 的 Robot State Token Sequence。十、为什么nn.Linear(10,64)能直接处理[32,4,10]这是非常重要的 PyTorch Shape 规则。我们以前一直用\[ [32,10] \]输入nn.Linear(10,64)得到\[ [32,64] \]实际上nn.Linear主要要求输入最后一个维度必须等于in_features。所以nn.Linear(10, 64)可以处理\[ [32,4,10] \]因为最后一维是\[ 10 \]它会把每一个\[ [10] \]向量分别变成\[ [64] \]所以\[ [32,4,10] \rightarrow [32,4,64] \]前面的\[ 32,4 \]都保留。以后这一点非常有用。十一、Language 和 Robot State 为什么最后都能变成[B,T,D]语言Token IDs ↓ Embedding变成\[ [B,T_l,D] \]Robot StateContinuous State ↓ Linear Projection变成\[ [B,T_s,D] \]关键在于虽然原始数据形式完全不同但最后都被编码成 D 维 Token。比如\[ D64 \]那么Language Token → [64] Robot State Token → [64]这就给后面的统一 Sequence Modeling 创造了条件。十二、那 Image 怎么变成 Token现在是第三种模态。一张图\[ I\in\mathbb R^{3\times224\times224} \]Transformer 不适合直接把\[ 224\times224 \]每个像素都当一个 Token。一种常见思想是把图片切成很多小 Patch。例如 Patch Size\[ 16\times16 \]那么\[ 224/1614 \]横向 14 个 Patch纵向 14 个 Patch。一共\[ 14\times14196 \]个 Patch。于是图片变成\[ 196 \]个视觉位置。十三、一个 Patch 里面有多少原始数字一个 RGB Patch\[ 16\times16 \]每个像素 3 个 Channel。所以\[ 16\times16\times3768 \]个数字。即一个 Patch 原始可以看成\[ [768] \]然后再通过 Linear Projection\[ [768]\rightarrow[D] \]例如\[ [768]\rightarrow[64] \]于是每个 Patch 就变成一个\[ [64] \]Visual Token。最终\[ 196 \]个 Patch\[ [196,64] \]加入 Batch\[ [B,196,64] \]这就是\[ [B,T,D] \]结构。只是这里\[ T196 \]不是时间步而是Visual Patch Sequence Length。十四、这里非常关键\(T\) 不一定表示“时间”上一课我们用\[ T \]表示时间长度。进入 Transformer 以后更广义地应该理解成Sequence Length例如 Language\[ T句子Token数 \]Robot History\[ T时间步数量 \]Image\[ TPatch数量 \]所以以后看到\[ [B,T,D] \]不能机械翻译成Batch × Time × Dimension。更准确的是\[ \boxed{ Batch \times Sequence \times Feature/Embedding } \]至于 Sequence 到底是时间文字PatchAction Query要根据上下文判断。十五、图片 Patch 化在代码里可以怎么理解教学上可以用 Conv2d 很方便地做 Patch Embeddingpatch_embed nn.Conv2d( in_channels3, out_channels64, kernel_size16, stride16)输入\[ image:[B,3,224,224] \]经过x patch_embed(image)得到\[ [B,64,14,14] \]为什么因为\[ 224/1614 \]每个 Patch 被映射成 64 维 Feature。但 Transformer 想要\[ [B,T,D] \]所以还需要把\[ 14\times14 \]展平。例如x x.flatten(2)变成\[ [B,64,196] \]再x x.transpose(1, 2)变成\[ [B,196,64] \]于是Image [B,3,224,224] ↓ Patch Embedding [B,64,14,14] ↓ Flatten [B,64,196] ↓ Transpose [B,196,64]现在\[ 196 \]就是 Visual Token 数量\[ 64 \]就是 Embedding Dimension。十六、为什么这里要transpose(1,2)因为Conv2d输出习惯是\[ [B,C,H,W] \]Patch Embedding 后\[ [B,D,H_p,W_p] \]展平空间后\[ [B,D,T] \]但是 Transformer 常见输入更希望\[ [B,T,D] \]所以需要把第 1 和第 2 维互换\[ [B,D,T] \rightarrow [B,T,D] \]代码x x.transpose(1, 2)这就是 Tensor Shape 真正服务代码理解的地方。十七、所以三种完全不同的数据最后居然能统一现在我们有Language\[ [B,T_l,D] \]Robot State\[ [B,T_s,D] \]Visual Tokens\[ [B,T_v,D] \]注意最后一维全部是\[ D \]于是理论上可以进一步组织成统一 Token Sequence。例如概念上[Visual Token 1] [Visual Token 2] ... [Language Token 1] [Language Token 2] ... [State Token 1] [State Token 2] ...最后形成\[ X\in\mathbb R^{B\times T_{total}\times D} \]其中\[ T_{total} T_vT_lT_s \]实际模型到底是否这样直接拼接要看具体架构不能一概而论。但是这个思想非常重要Transformer 不需要原始输入都是同一种模态它需要的是这些模态最后都能变成某种 Token Representation。十八、这就是 Multimodal Transformer 的一个基础思想原始输入Image Language Robot State差异巨大。但经过各自 Encoder / ProjectionImage ↓ Visual Tokens Language ↓ Language Tokens Robot State ↓ State Tokens最后都变成\[ D\text{维向量} \]于是 Transformer 可以对它们进行统一的信息交互。这也是为什么 VLA 中会频繁看到Vision Encoder Language Encoder State Projection Transformer Action Head十九、但是现在出现一个严重问题Transformer 怎么知道顺序假设两个 Token Sequence\[ [A,B,C] \]和\[ [C,B,A] \]如果每个 Token 只有自己的 EmbeddingA → vector_A B → vector_B C → vector_C那么模型还缺一个信息A 是第 1 个还是第 3 个Sequence 的顺序没有自动写在向量里。所以需要Position Information位置编码。二十、为什么 Robot Sequence 更需要 Position例如\[ [s_{t-2},s_{t-1},s_t] \]如果模型不知道位置那么最早的状态 当前状态 中间状态之间的时间顺序可能不明确。但是对 Robot Policy 来说\[ s_{t-2}\rightarrow s_{t-1}\rightarrow s_t \]和\[ s_t\rightarrow s_{t-1}\rightarrow s_{t-2} \]含义完全不同。所以必须告诉模型这是第几个位置。二十一、最简单的位置 Embedding 思想假设\[ X:[B,T,D] \]我们准备\[ P:[T,D] \]其中每个位置都有一个 Position Vector\[ p_1,p_2,\ldots,p_T \]然后\[ XXP \]也就是说 Token 自己的内容\[ x_t \]加上\[ p_t \]得到\[ x_tx_tp_t \]于是一个 Token 同时包含我是谁 我在第几个位置二十二、代码里最简单可以怎么写例如class SimpleSequenceEncoder(nn.Module): def __init__(self, input_dim, d_model, max_len): super().__init__() self.input_proj nn.Linear(input_dim, d_model) self.pos_embedding nn.Parameter( torch.randn(max_len, d_model) ) def forward(self, x): x self.input_proj(x) T x.shape[1] x x self.pos_embedding[:T] return x假设输入\[ x:[32,4,10] \]第一步x self.input_proj(x)得到\[ [32,4,64] \]然后T x.shape[1]此时\[ T4 \]取self.pos_embedding[:4]Shape\[ [4,64] \]然后x x self.pos_embedding[:T]这里利用了 PyTorch Broadcasting\[ [32,4,64] [4,64] \]得到\[ [32,4,64] \]每个 Batch 都加上同样的位置向量。二十三、这里第一次自然遇到 Broadcasting不用展开成 NumPy 大课。这里只需要理解\[ [32,4,64] [4,64] \]PyTorch 会把\[ [4,64] \]视为对 32 个 Batch 都使用同样的位置编码。所以不用手工复制 32 份。最终 Shape 仍然\[ [32,4,64] \]二十四、Position Embedding 是固定的吗不一定。常见方案很多例如fixed positional encodinglearned positional embeddingrotary position embeddingrelative positional information。现在不要往旁支扩。我们当前只需要掌握核心原因\[ \boxed{ Transformer本身需要额外获得位置/顺序信息 } \]具体模型采用哪种 Position Encoding以后读真实代码再查。二十五、Token 和 Embedding 最容易混淆在哪里必须严格区分Token表示一个序列位置上的“信息单位”。例如一个词片段 一个图像Patch 一个时间步StateToken ID语言中经常存在。例如\[ 17 \]只是词表索引。EmbeddingToken 被编码后真正送入 Transformer 的向量\[ e_t\in\mathbb R^D \]所以 Language 中\[ Token \rightarrow Token\ ID \rightarrow Embedding \]而 Robot State 可能直接\[ Continuous\ State \rightarrow Linear\ Projection \rightarrow Embedding \]不一定存在 Token ID。这一点要分清。二十六、现在终于可以解释后面 Attention 里的 \(X\)以后会看到\[ QXW_Q \]\[ KXW_K \]\[ VXW_V \]那么这里\[ X \]不应该再是一个抽象字母。它通常可以理解成一批已经变成统一 Embedding Dimension 的 Token Sequence。例如\[ X:[B,T,D] \]其中\[ B \]Batch Size\[ T \]Token / Sequence Length\[ D \]Embedding Dimension。例如\[ X:[32,16,64] \]意思32 个 Sample每个 Sample 有 16 个 Token每个 Token 是 64 维向量。下一课的 Q/K/V 全部从这里出发。二十七、代码里一个最小“进入 Attention 前”的数据流现在可以组合成class RobotTokenEncoder(nn.Module): def __init__(self): super().__init__() self.state_proj nn.Linear(10, 64) self.pos_embedding nn.Parameter( torch.randn(16, 64) ) def forward(self, state): x self.state_proj(state) T x.shape[1] x x self.pos_embedding[:T] return x假设state.shape是\[ [32,4,10] \]经过x self.state_proj(state)得到\[ [32,4,64] \]再加 Position\[ [32,4,64] \]Shape 不变。于是x encoder(state)最终\[ X:[32,4,64] \]这已经是一个非常标准的 Transformer Sequence Representation。下一步就可以\[ X \rightarrow Q,K,V \]二十八、这一课和 ACT 已经有什么联系ACT 后面会处理Robot StateImage FeatureAction SequenceTransformerQueryPosition Embedding。如果现在没有建立\[ [B,T,D] \]以及\[ Token \rightarrow Embedding \]和\[ Position \]这些概念以后看到 ACT 代码中的query_embed pos_embed encoder decoder就很容易全部混成名词。所以这一课真正是在给 ACT 搭最后的 Transformer 地基。第十三课整章链路回看上一课我们已经得到\[ Sequence \]这一课进一步回答Sequence 中每个位置到底用什么形式进入 Transformer答案是\[ \boxed{ Token\ Representation } \]语言\[ Token\ ID \rightarrow Embedding \]Robot State\[ State \rightarrow Linear\ Projection \]Image\[ Image \rightarrow Patch \rightarrow Visual\ Embedding \]最终统一得到\[ X:[B,T,D] \]再加入\[ Position\ Information \]告诉模型每个 Token 在 Sequence 的哪个位置。因此下一课终于可以正式开始\[ \boxed{ X \rightarrow Q,K,V \rightarrow Attention } \]第十三课自测Token 为什么不能简单等同于“单词”Language Token ID 为什么不能直接当连续数值输入神经网络nn.Embedding(100,64)中的 100 和 64 分别是什么输入 Token ID Shape\[ [32,20] \]经过nn.Embedding(1000,64)后 Shape 是什么Robot State\[ [32,4,10] \]经过nn.Linear(10,64)为什么会得到\[ [32,4,64] \]一张\[ [3,224,224] \]图片如果 Patch Size 16×16一共有多少 Patch为什么 Visual Patch 也可以称为 Token[B,T,D]中的 \(T\) 为什么不一定表示时间为什么 Transformer 需要 Position Information下面x x pos_embedding[:T]为什么通常不会改变\[ [B,T,D] \]的 ShapeLanguage、Image、Robot State 原始形式完全不同为什么最后有可能被同一个 Transformer 处理当下一课写\[ QXW_Q \]时这里的\[ X \]现在应该怎样解释