VLA 系统学习第 17 课:正式进入 ACT——为什么需要 CVAE、潜变量 z 和 KL Loss? 第十六课标准答案上一课我们已经从 Transformer 的内部结构走到了一个能预测 Action Chunk 的 Encoder–Decoder Policy。现在先解决 9 道题然后正式进入 ACTAction Chunking with Transformers。1. 为什么 Encoder 的输出叫 Memory是不是电脑内存不是电脑的 RAM。在 Transformer Encoder–Decoder 架构中Memory 通常指 Encoder 对输入信息进行上下文编码后产生的特征序列。例如\[ M\operatorname{Encoder}(X) \]这里的 \(M\) 包含 Encoder 对 Observation 的编码结果供后续 Decoder 通过 Cross-Attention 查询。可以理解成Encoder 把观察信息整理好Decoder 再根据自己的 Query从这些特征中读取所需信息。Memory 不一定具有跨时间长期保存的能力。在我们上一课的模型中每次 Forward 都会根据本次输入重新计算。2. Observation[B,4,10]经过 Linear 和 Encoder 后是什么 Shape首先state_proj nn.Linear(10, 64)tokens state_proj(obs)因为 Linear 作用于最后一维\[ [B,4,10]\rightarrow[B,4,64] \]随后 Transformer Encoder 通常保持形状\[ \boxed{M:[B,4,64]} \]虽然 Shape 不变但是每个 Token 已经经过 Self-Attention 和 FFN 处理。3. 为什么 Encoder 有 4 个 Token不代表 Decoder 只能输出 4 个因为 Encoder Memory 的序列长度与Decoder Query 的序列长度可以不同。例如\[ M:[B,4,64] \]而我们给 Decoder 准备\[ Q:[B,8,64] \]Cross-Attention 让 8 个 Query 分别读取 4 个 Memory Token 的信息得到 8 个输出位置。因此\[ \boxed{\text{Decoder输出长度由Query长度决定}} \]在这种并行预测结构中8 个 Query 可以对应 8 个未来动作位置。4. Action Query 是真正的 7 维 Action 吗不是。Action Query 是 Decoder 内部使用的查询表示例如\[ q_i\in\mathbb R^{64} \]它本身不是关节角、末端位置或者电机命令。需要经过 Decoder 和 Action Head\[ [B,8,64] \xrightarrow{\text{Action Head}} [B,8,7] \]才得到模型所定义的 7 维 Action Prediction。注意不同实现对 Query 的组织方式可能不同不能认为所有 ACT/VLA 模型都使用完全相同的 Query 结构。5. 为什么 Cross-Attention Score 是[B,8,4]因为\[ Q:[B,8,64] \]\[ K:[B,4,64] \]转置 K\[ K^T:[B,64,4] \]因此\[ QK^T: [B,8,64]\times[B,64,4] \]得到\[ \boxed{[B,8,4]} \]其中 8 是 Query 数量4 是 Key 数量。每一行都在回答当前这个 Action Query 对 4 个 Observation Memory Token 分别有多高的关注程度6. Decoder 的 Self-Attention 和 Cross-Attention 有什么区别Self-Attention 让 Decoder 自己的 Action Query Token 之间交换信息\[ [B,8,64]\rightarrow[B,8,64] \]Cross-Attention 则让 Action Query 从 Encoder Memory 中提取信息\[ Q_{\text{action}} \quad\text{与}\quad K_{\text{memory}},V_{\text{memory}} \]二者的核心差别是信息来源。Self-Attention 处理目标侧内部关系Cross-Attention 建立目标侧与输入侧的关系。7.tgtqueries是不是 Expert Action不是。在上一课的教学代码中action_features self.decoder( tgtqueries, memorymemory)tgt是传给 Decoder 的目标侧特征序列即当前使用的 Action Queries。训练时的 Expert Action 另外存在expert_actions它用于构造监督信号、计算 Loss并不会因为变量名叫tgt就自动变成 Decoder 输入。8. 为什么[B,8,64]经过nn.Linear(64,7)得到[B,8,7]因为 Linear 只修改最后一维\[ 64\rightarrow7 \]前面的 Batch 和 Action Query 数量保持不变\[ \boxed{[B,8,64]\rightarrow[B,8,7]} \]所以一次输出 8 个动作每个动作 7 维。9. 为什么上一课的 TinyActionChunkPolicy 还不是完整 ACT因为它只是一个教学用的确定性 Transformer BC Policy\[ Observation \rightarrow Encoder \rightarrow Decoder \rightarrow Action\ Chunk \]它缺少 ACT 原方法中的重要机制特别是用专家 Action Sequence 参与训练的 CVAE 潜变量分支潜变量 \(z\) 的分布学习及 KL 正则化训练与推理阶段不同的潜变量处理原方法针对视觉和机器人状态设计的具体输入结构动作块重叠预测时可采用的 Temporal Ensembling。所以我们已经理解了 ACT 所需的 Transformer 基础但还没有理解完整 ACT 的训练方法。接下来就处理这个缺口。VLA 系统学习第 17 课正式进入 ACT——为什么需要 CVAE、潜变量 \(z\) 和 KL Loss论文与代码基础Learning Fine-Grained Bimanual Manipulation with Low-Cost HardwareTony Z. Zhao 等2023 · ACT 官方 GitHub这一课开始我们不再只讲通用 Transformer而是把之前的 Behavior Cloning、Action Chunk、Encoder–Decoder、Loss 和 Backward 连接到 ACT 的真实方法中。一、为什么普通 BC 即使预测 Action Chunk也可能遇到困难我们已经知道最普通的 Behavior Cloning 是\[ \hat a_t\pi_\theta(o_t) \]上一课进一步扩展为\[ \hat A_t\pi_\theta(o_t) \]其中\[ A_t[a_t,a_{t1},\ldots,a_{tK-1}] \]表示一段未来 Action。现在考虑一种情况两个专家从相同或非常相近的 Observation 出发却采用两条不同的合理轨迹。例如物体正好挡在前面机械臂可以从左侧绕过去也可以从右侧绕过去。为了把问题简化到最容易计算的程度假设某一个时刻存在两种合理动作\[ a^{(1)}-1 \]\[ a^{(2)}1 \]含义分别是向左和向右。如果模型只能对相同的 Observation 输出一个固定数值\[ \hat af_\theta(o) \]并且使用 MSE\[ L\frac12[(\hat a1)^2(\hat a-1)^2] \]展开得到\[ L\hat a^21 \]当\[ \hat a0 \]时Loss 最小。但问题是\[ \boxed{\hat a0} \]既不是“向左”也不是“向右”而是两个动作的中间值。这就是在多模态示范数据中确定性回归预测可能出现的平均化问题。这里需要严谨区分上面的推导针对 MSE。对于 L1最优解不一定唯一但它同样没有明确机制保证模型选择一条完整、一致的动作模式。ACT 原论文也明确把人类示范的可变性作为引入生成式模型的一个重要动机。现在真正需要解决的是在同样 Observation 下存在多种合理 Action Chunk 时模型能否获得额外的信息区分不同的示范方式二、CVAE 的核心想法除了 Observation再给模型一个潜变量 \(z\)我们之前的确定性 Policy 是\[ \hat A\pi_\theta(o) \]也就是说输入 \(o\)输出一段预测动作。ACT 引入一个新的变量\[ z \]于是 Policy 变成\[ \boxed{ \hat A\pi_\theta(o,z) } \]这个 \(z\) 通常称为Latent Variable潜变量。它是一个模型内部的向量不是另一个相机不是机器人关节位置也不是语言指令。可以把它理解成让模型有机会使用一份额外的内部信息表示当前 Action Sequence 的某些变化因素。ACT 论文把它解释为动作序列的 style variable也就是动作风格变量。例如概念上\[ z_1\rightarrow\text{某一种动作执行方式} \]\[ z_2\rightarrow\text{另一种动作执行方式} \]但要注意这只是帮助理解的例子不能直接认为 \(z_1\) 就等于“左绕”\(z_2\) 就等于“右绕”。真实的潜变量没有预先规定的语义模型可能学习到不同的内部因素也可能没有充分利用它。1. \(z\) 是一个什么 Shape假设我们人为设定\[ D_z4 \]那么一个样本的潜变量为\[ z\in\mathbb R^4 \]例如\[ z[0.2,-0.6,1.1,0.3] \]如果\[ B32 \]则\[ z:[32,4] \]这里的 4 是潜变量维度不是 Action Dimension也不是 Transformer 的 Embedding Dimension。在作者官方detr/models/detr_vae.py中存在self.latent_dim 32也就是说当前核实的这份 ACT 实现使用 32 维潜变量而不是我们教学示例中的 4 维。2. 现在问题来了训练时 \(z\) 从哪里来不能简单地说随便创建一个随机向量就行。因为我们希望这份 \(z\) 与专家示范中的动作差异建立联系。ACT 的方法是训练阶段使用一个额外的 Encoder读取专家 Action Chunk 和当前机器人关节状态生成潜变量的分布参数。因此需要明确区分两条计算链。训练时的潜变量分支这两条分支会在训练期间联合工作。第一条负责从示范中学习潜变量分布第二条利用 Observation 和 \(z\) 预测动作。这里必须特别强调ACT 的 CVAE Encoder 与用于处理图像、状态的 Transformer Encoder 不是同一个概念。 它们属于架构中的不同部分承担不同职责。原论文和官方实现都能核实这一设计。三、为什么 Encoder 不直接输出一个 \(z\)反而要输出 \(\mu\) 和 \(\sigma\)这是理解 VAE 与普通 Autoencoder 区别的关键。普通 Encoder 可以直接写成\[ zf_\phi(A,o) \]也就是输入一段示范动作直接输出一个固定的 \(z\)。但 VAE 的 Encoder 不是直接预测一个确定的潜变量而是预测一个概率分布。ACT 使用的是高斯形式的潜变量分布\[ \boxed{ q_\phi(z\mid A,q) \mathcal N(\mu,\operatorname{diag}(\sigma^2)) } \]其中\(A\)专家 Action Chunk\(q\)当前关节状态\(\mu\)高斯分布的均值向量\(\sigma^2\)各维度的方差\(\operatorname{diag}\)将各维方差放在协方差矩阵对角线上\(\phi\)CVAE Encoder 的可训练参数。为什么使用分布因为模型不再把每条示范压缩为一个完全固定的编码点而是学习一套可以采样的潜在表示。1. 先用一个数字理解高斯分布假设\[ \mu2 \]\[ \sigma0.5 \]意思是分布中心在 2标准差为 0.5。每次采样可能得到\[ z_11.8 \]\[ z_22.3 \]\[ z_31.9 \]这些都是示意值。真正重要的是Encoder 决定分布的位置和宽度随后我们从这个分布中取样。2. 为什么代码中不是sigma而是logvar你在 ACT 官方代码中会看到mu latent_info[:, :self.latent_dim]logvar latent_info[:, self.latent_dim:]这里\[ logvar\log(\sigma^2) \]意思是方差的自然对数。使用logvar的一个好处是网络可以输出任意实数再通过指数函数还原出严格为正的方差。如果\[ \log(\sigma^2)0 \]那么\[ \sigma^2e^01 \]于是\[ \sigma1 \]而一般情况下\[ \boxed{ \sigma\exp\left(\frac{logvar}{2}\right) } \]因为\[ \log(\sigma^2)2\log\sigma \]所以\[ \log\sigma\frac{logvar}{2} \]再取指数就得到了标准差。3. 代码中的 \(\mu\) 和logvar怎么得到我们先使用一个简单教学示例。假设\[ B2,\quad K8,\quad D_a7,\quad D_s10,\quad D_z4 \]则\[ state:[2,10] \]\[ actions:[2,8,7] \]为了暂时避开复杂的 Transformer Encoder我们先把动作序列展平成一个向量flat_actions actions.flatten(start_dim1)那么\[ [2,8,7]\rightarrow[2,56] \]再把 State 拼进去encoder_input torch.cat( [state, flat_actions], dim-1)于是\[ [2,10][2,56]\rightarrow[2,66] \]现在使用一个 MLPstyle_encoder nn.Sequential( nn.Linear(66, 64), nn.ReLU(), nn.Linear(64, 8))为什么输出 8因为需要同时生成两组 4 维数字\[ \mu:[2,4] \]\[ logvar:[2,4] \]所以总共需要\[ 2D_z8 \]个输出。运行latent_info style_encoder(encoder_input)mu, logvar torch.chunk( latent_info, chunks2, dim-1)这里torch.chunk(..., chunks2, dim-1)的作用就是把最后一维平均分成两块\[ [2,8]\rightarrow[2,4][2,4] \]所以mu.shape# [2, 4]logvar.shape# [2, 4]这已经完整解释了为什么 ACT 的 CVAE Encoder 最后需要输出两倍的 Latent Dimension。这里的 MLP 是教学替身。真实 ACT 使用 Transformer Encoder 处理示范动作序列而不是简单将动作全部展平。四、有了 \(\mu\) 和logvar怎么得到 \(z\)——Reparameterization Trick我们已经让 Encoder 预测了一个概率分布。但现在还要从这个分布中采样\[ z\sim\mathcal N(\mu,\sigma^2) \]如果把采样直接当成一个不可微的黑盒训练时就不容易把梯度从 Decoder 传回 Encoder 的分布参数。于是 VAE 使用Reparameterization Trick重参数化技巧。它的核心式子非常值得记住\[ \boxed{ z\mu\sigma\odot\epsilon } \]其中\[ \epsilon\sim\mathcal N(0,I) \]符号 \(\odot\) 表示逐元素相乘。这个公式的思想是把随机性放到一个独立的噪声 \(\epsilon\) 中而把 \(\mu\) 和 \(\sigma\) 放在可微的确定性计算路径里。例如\[ \mu2,\quad\sigma0.5,\quad\epsilon-0.4 \]得到\[ z20.5\times(-0.4)1.8 \]这样我们仍然能从目标高斯分布中采样但 \(z\) 对 \(\mu\) 和 \(\sigma\) 的运算关系是明确的。代码非常短std torch.exp(0.5 * logvar)eps torch.randn_like(std)z mu std * epstorch.randn_like(std)会生成一个与stdShape 相同的标准正态随机 Tensor。假设\[ mu:[2,4] \]\[ logvar:[2,4] \]那么\[ std:[2,4] \]\[ eps:[2,4] \]最后\[ \boxed{z:[2,4]} \]这也与 ACT 官方reparametrize()中使用的数学结构一致。现在第一条训练分支已经走通\[ \boxed{ Expert\ Action\ Chunk Joint\ State \rightarrow Encoder \rightarrow (\mu,logvar) \rightarrow z } \]下一步就是用这个 \(z\) 生成 Action Chunk。五、为什么 Decoder 已经有 \(z\)还需要 KL Loss现在我们已经知道CVAE Encoder 可以利用专家动作生成\[ z:[B,D_z] \]之后 Policy 使用\[ \hat A\pi_\theta(o,z) \]预测动作。但这里出现一个重要问题既然 Encoder 已经看到了专家动作那它会不会直接把专家动作的信息编码进 \(z\)使 Decoder 只需要“照着抄”如果完全不限制 \(z\)确实可能出现这个问题。训练时Encoder 可以依赖 Expert Action 生成特别有针对性的编码使 Decoder 很容易重建专家动作。但推理时没有 Expert Action于是训练时非常好用的潜变量在推理时可能根本无法得到。因此需要限制潜变量分布。这就是 KL Loss 的意义。1. 什么是 Prior在 ACT 中我们希望潜变量的分布接近一个简单的标准正态分布\[ \boxed{ p(z)\mathcal N(0,I) } \]这里的 \(p(z)\) 叫 Prior先验分布。可以理解成我们提前规定希望潜变量大体处在一个标准化、可预测的分布空间中。而 Encoder 根据示范动作预测的是\[ q_\phi(z\mid q,A) \]它叫近似后验分布。训练时希望两者不要相差太远\[ q_\phi(z\mid q,A) \approx p(z) \]于是引入\[ D_{\mathrm{KL}}(q_\phi\|p) \]KL DivergenceKL 散度。它用于衡量两个概率分布之间的差异。它不是普通欧氏距离而且通常不对称。2. KL Loss 的数学公式对 ACT 使用的对角高斯分布其 KL 可以写为\[ \boxed{ L_{\mathrm{KL}} \frac12 \sum_{i1}^{D_z} \left( \mu_i^2 e^{logvar_i} -1-logvar_i \right) } \]先不要被公式吓到。这里每一项都有明确意义\[ \mu_i^2 \]对均值偏离 0 产生惩罚。\[ e^{logvar_i} \]就是该维度的方差\[ \sigma_i^2 \]而其余项一起构成完整的高斯 KL 表达式。如果\[ \mu_i0,\quad logvar_i0 \]那么\[ \sigma_i^21 \]恰好对应标准正态分布。此时这一维 KL 为\[ \frac12(01-1-0)0 \]因此 KL Loss 会约束 Encoder 输出的潜变量分布不要任意偏离先验。3. PyTorch 中怎么算我们已经有mu.shape# [B, Dz]logvar.shape# [B, Dz]可以写kl_per_dim -0.5 * ( 1 logvar - mu.pow(2) - logvar.exp())kl_loss kl_per_dim.sum(dim-1).mean()这与官方代码中kl_divergence()的核心公式一致。这段代码的数据流是\[ [B,D_z] \rightarrow \text{每一维KL} \rightarrow [B,D_z] \]再通过sum(dim-1)对每个 Sample 的全部潜变量维度求和\[ [B,D_z]\rightarrow[B] \]最后通过mean()求 Batch 平均\[ [B]\rightarrow[] \]得到一个标量 KL Loss。六、现在终于能看懂完整 ACT Loss到这里我们有了两个不同的目标。第一个是希望模型预测的 Action Chunk 接近专家动作\[ L_{\mathrm{recon}}(\hat A,A) \]这叫Reconstruction Loss重建损失。第二个是希望潜变量分布不要任意偏离标准正态先验\[ L_{\mathrm{KL}} \]所以完整训练目标为\[ \boxed{ L_{\mathrm{total}} L_{\mathrm{recon}} \beta L_{\mathrm{KL}} } \]其中\[ \beta \]用于控制 KL 正则化强度。如果\[ \beta \]太小潜变量可能携带大量只在训练时容易获取的动作信息使推理时与训练时的潜变量使用方式出现不匹配。如果\[ \beta \]太大模型可能倾向于忽略 \(z\)导致潜变量难以表达不同示范之间的变化。这种情况与 VAE 中的 Posterior Collapse后验坍塌问题有关。所以 KL 的作用并不是越小越好、越接近标准正态越好。而是要在动作重建能力和潜变量正则化之间取得平衡。一个必须说明的论文与代码差异这里我核对到了一个值得专门标记的地方【来源冲突】 ACT 原论文的训练算法伪代码中重建项写为 MSE但作者官方 GitHub 的policy.py里ACTPolicy实际计算的是 L1 Loss KL Loss。官方代码的关键表达是all_l1 F.l1_loss( actions, a_hat, reductionnone)l1 ( all_l1 * ~is_pad.unsqueeze(-1)).mean()loss l1 kl_weight * kl这里is_pad也是我们之前学过的 Mask。Padding 位置不应该被当成真实专家动作因此代码先对无效位置的误差进行屏蔽。另外当前代码是在屏蔽后对完整 Tensor 求mean()所以 Padding 位置仍然影响平均值的分母这与“只除以有效元素数量”的另一种 Masked Mean 写法并不完全等价。以后我们做官方复现时应严格检查这个细节而不是擅自替换。七、训练时使用专家 Action推理时为什么能没有专家 Action这是整节课最重要的逻辑必须彻底打通。训练阶段数据集中有\[ (o_t,A_t) \]所以\[ A_t \]不仅可以用来计算 Loss还可以送入 CVAE Encoder获得\[ \mu,\quad logvar \]然后通过重参数化获得\[ z \]预测\[ \hat A_t\pi_\theta(o_t,z) \]最后联合训练 Encoder 与 Policy。推理阶段真实运行时只有\[ o_t \]没有未来专家动作\[ A_t \]因此无法运行那个依赖专家 Action Chunk 的 CVAE Encoder。原始 ACT 的处理方式很明确\[ \boxed{z0} \]即使用标准正态先验\[ \mathcal N(0,I) \]的均值作为潜变量。这不是猜测。ACT 论文和官方detr_vae.py都明确使用这一处理。因此这里也暴露出一个值得思考的局限ACT 使用 CVAE 的动机之一是建模示范变化但原始 ACT 在推理时固定 \(z0\)并不是每次都随机抽取不同的动作风格。因此不能简单宣称“原始 ACT 推理时能根据 \(z\) 自动随机选择多条完整轨迹”。这需要具体检查模型如何利用潜变量以及实际推理机制。八、用最小 PyTorch 代码把 CVAE 的训练与推理贯通现在把前面分散的代码连接起来。为了教学方便以下模型使用 MLP 替代真实 ACT 的 Transformer CVAE Encoder 和视觉 Policy。它的目标只是让你看清楚 Expert Actions → \(\mu,\logvar\) → \(z\) → Predicted Actions → Loss 这一条链。import torchimport torch.nn as nnimport torch.nn.functional as Fclass MiniChunkCVAE(nn.Module): def __init__(self): super().__init__() self.chunk_size 8 self.action_dim 7 self.z_dim 4 # State Action Chunk - mu、logvar self.style_encoder nn.Sequential( nn.Linear(10 8 * 7, 64), nn.ReLU(), nn.Linear(64, 2 * self.z_dim) ) # State z - Predicted Action Chunk self.action_decoder nn.Sequential( nn.Linear(10 self.z_dim, 64), nn.ReLU(), nn.Linear(64, 8 * 7) ) def forward(self, state, actionsNone): B state.shape[0] if actions is not None: # 训练利用专家动作得到潜变量分布 flat_actions actions.flatten(start_dim1)这份代码中的forward()有两条不同路径。训练时\[ state:[2,10] \]\[ actions:[2,8,7] \]先展平并拼接\[ [2,10][2,56]\rightarrow[2,66] \]经过 Style Encoder\[ [2,66]\rightarrow[2,8] \]拆成\[ \mu:[2,4],\quad logvar:[2,4] \]再采样\[ z:[2,4] \]把 State 和 \(z\) 拼接\[ [2,10][2,4]\rightarrow[2,14] \]经 Decoder\[ [2,14]\rightarrow[2,56] \]重新 reshape\[ \boxed{pred\_actions:[2,8,7]} \]推理时 不再传入actions所以if actions is not None条件不成立直接设置\[ z[0,0,0,0] \]然后继续使用同一个 Action Decoder 预测动作。如何真正训练它model MiniChunkCVAE()optimizer torch.optim.Adam( model.parameters(), lr1e-3)state torch.randn(2, 10)expert_actions torch.randn(2, 8, 7)optimizer.zero_grad()pred, mu, logvar model( state, expert_actions)recon_loss F.l1_loss( pred, expert_actions)kl_loss -0.5 * ( 1 logvar - mu.pow(2) - logvar.exp()).sum(dim-1).mean()beta 0.01loss recon_loss beta * kl_lossloss.backward()optimizer.step()注意这里的随机数据只用于验证代码调用和 Tensor Shape没有真实机器人示范语义。代码中最重要的是这句pred, mu, logvar model(state, expert_actions)它告诉你当前执行的是训练路径因此模型可以利用专家 Action 计算后验潜变量。随后loss recon_loss beta * kl_loss联合约束动作重建与潜变量分布。最后loss.backward()计算包括 Style Encoder 和 Action Decoder 在内的可训练参数梯度。再optimizer.step()更新这些参数。推理时怎么调用model.eval()with torch.no_grad(): pred, mu, logvar model(state)print(pred.shape)预期torch.Size([2, 8, 7])并且此时mu is Nonelogvar is None因为根本没有执行 CVAE Encoder 分支。现在训练与推理的区别终于不只是理论描述而是直接体现在model(state, expert_actions)与model(state)这两个调用方式上。九、回到 ACT 官方代码对应哪些真实模块我们已经可以把刚才的教学实现映射到作者的真实仓库而不需要一下子阅读几百行。下面这些位置均来自核实过的 detr/models/detr_vae.py 及 policy.py。我们学的概念ACT 官方代码CVAE EncoderDETRVAE.encoder专家 Action Projectionencoder_action_proj当前关节状态 Projectionencoder_joint_proj聚合示范序列cls_embed再取 Encoder 的 CLS 输出预测分布参数latent_proj取出均值mu取出对数方差logvar重参数化采样reparametrize(mu, logvar)将 \(z\) 投影到模型特征空间latent_out_proj动作预测action_head重建与 KL LossACTPolicy中的 Loss 计算还有一个非常容易忽略的 Shape 细节真实 ACT 的 CVAE Encoder 将一个 CLS Token、一个当前关节状态 Token 和 \(K\) 个专家 Action Token 拼在一起。因此总 Token 数是\[ \boxed{K2} \]例如\[ K8 \]则\[ [CLS,q,a_0,\ldots,a_7] \]总共有\[ 10 \]个 Token。注意官方文件中相邻的部分行内注释写作seq1但根据实际torch.cat的输入数量正确的总长度是 \(K2\)。这也是为什么真实 GitHub 审读不能只看注释要结合 Tensor 操作本身判断。另外原始ACTPolicy在policy.py中还直接实现了__call__()而不是我们教学代码采用的常规forward()。这与你之前专门研究的 Python 魔术方法有关。它是该仓库实际存在的实现选择不应误认为所有 PyTorch Policy 都要这样写。第十七课整章回看这节课真正建立起来的因果链是\[ \boxed{ \text{人类示范可能有多种合理轨迹} \rightarrow \text{确定性BC可能难以统一拟合} \rightarrow \text{引入潜变量}z \rightarrow \text{CVAE} } \]训练阶段\[ \boxed{ (q,A) \rightarrow CVAE\ Encoder \rightarrow (\mu,logvar) \rightarrow z } \]然后\[ (o,z) \rightarrow Policy \rightarrow \hat A \]使用\[ \boxed{ L_{\mathrm{total}} L_{\mathrm{recon}} \beta L_{\mathrm{KL}} } \]进行联合训练。推理阶段\[ \boxed{ oz0 \rightarrow Policy \rightarrow \hat A } \]不再需要专家 Action也不需要 CVAE Encoder。这就是原始 ACT 中 CVAE 的核心训练与推理逻辑。第十七课自测1. 为什么相同 Observation 对应多条合理专家轨迹时普通确定性 MSE 回归可能出现平均化问题2. ACT 中的 \(z\) 是机器人真实状态吗它具体属于什么3. 如果 \(D_z32\)为什么latent_proj常需要输出 \(64\) 维数字4. \(\mu\)、\(\sigma\)、logvar分别是什么意思为什么\[ \sigma\exp(0.5\,logvar) \]5. Reparameterization Trick 为什么要写成\[ z\mu\sigma\odot\epsilon \]而不是把采样当成不可微黑盒6. Reconstruction Loss 和 KL Loss 分别希望模型学会什么7. 为什么训练时的 CVAE Encoder 可以读取 Expert Action Chunk而推理时不能8. 原始 ACT 推理时把 \(z\) 设置成多少这是否意味着它推理时会随机选择不同风格9. 为什么 ACT 中存在两种不同意义上的 Encoder分别负责什么10. 如果\[ B32,\quad K8,\quad D_a7,\quad D_z4 \]请说明专家 Action Chunk、潜变量 \(z\) 和最终预测动作各自的 Shape。