建立于2025-11-27,继承自MVIG

ACTION CHUNKING WITH TRANSFORMERS

这个东西很重要

A. Action Chunking and Temporal Ensemble

Temporal ensembling(时间融合) 问题:

  • 每k步才更新一次,会让机器人“隔几步突然变个方向”,动作变得断断续续、不平滑 怎么办?
  • 改成:每一步都预测一“整段”动作(chunk),让这些动作块重叠,每一时刻可能有多个预测,那就用加权平均法融合一下,动作会更平滑
  • 加权策略是“越新越重、越老越轻”,保证动作“随时对当前外部观察敏感”

感觉这个东西看起来和ICS1五级流水线比较像

关于读论文

  • 比方说这个ACT是个很复杂的东西
  • 让ai解读一下
  • 我先看A的解读,然后去看原文

CVAE这个东西,在CS231n笔记l13里面提到过vae,此外,2025课程花了2节课时间讲生成模型,但是主要是 Lecture 13: Generative Models 1
Variational Autoencoders
Generative Adversarial Network
Autoregressive Models

可以看看

我觉得具体内容的批注还是在zotero里面进行比较好,对于更抽象层面的笔记可以写入ob。此外,可以研究一下ob和zotero的结合,我觉得可能会比较有意思 参见Obsidian折腾日志

B. Modeling human data

CVAE 的总损失 L = 重建误差(Lreconst)+ β × KL 距离(LKL

  • 重建误差:模型输出的动作和人演示的动作差得有多远。这个要求模型必须“还原得像”。
  • KL 距离(KL 散度):要求编码器输出的 z 分布,要接近标准高斯分布 N(0, I)(就是均值为0,协方差为单位阵的正态分布),别乱跑。

β 的具体作用

  • β 前面乘的是 KL 正则,也就是限制 z 不能带太多“专属私货” 的开关。
  • β 越大,相当于告诉模型:“z 不许特别跑偏,离 N(0,I) 太远你就吃大罚!”
  • 这样,模型会更强烈地克制自己“往 z 里塞更多信息”,不敢有太复杂的花样。

C. Implementing ACT

CVAE Encoder(左边)

  • 只要“全看一遍输入” 得出一个z分布
  • 结构用bert-like transformer encoder最合适
  • 不需要生成序列,不需要逐步输出

CVAE Decoder/Policy(右边)

  • 要干两件事:
    1. 全局融合上下文(各种图像+关节+z) ——靠transformer encoder
    2. 序列化地生成动作块(一个k*14序列) ——靠transformer decoder自回归一帧一帧地产生
  • 必须包含encoder(输入特征混合)和decoder(动作序列生成)两个transformer部分

(99 封私信 / 82 条消息) 读懂BERT,看这一篇就够了 - 知乎 bert可以看看这个

17点33分 妈的,终于看到V. EXPERIMENTS了,不容易

https://shuiyuan.sjtu.edu.cn/t/topic/436157/4 终于做出这个一直很想做的工具,我把它叫做 VibeReading。它是专门为阅读学术论文而设计的,不是那种简单的“对照翻译”或“Chat with PDF”工具,而是更像一个会陪你一起读论文、不断指给你关键内容的“AI学长”。

2025-11-29

消融实验

本节要做“消融实验”,也就是把 ACT 里的“关键设计(动作分块、时间加权、CVAE)”逐个拆掉或替换,看看哪个对表现最关键,以及加一个用户实验说明高频控制的重要性。目标是让你看明白:ACT里的每一个模块,都是不是简单叠加,而是确实对解决难题有巨大贡献

  • L1 loss(或叫重建损失)定义为“预测输出和真实动作每一帧的数据绝对值差的总和/平均”。
  • 这种只能“死记硬背”、“平均取中间值”,而不能泛化到有人类风格变化/多解的情况。

1. 50Hz是什么意思?

  • Hz = 赫兹 = 次/秒
  • 在本论文和机器人操控场景里,“50Hz”= 每秒刷新(发送新控制命令)50次。
  • 也就是每隔 1/50 秒(= 20毫秒)一次,系统会:
    1. 读取传感器/相机/状态
    2. 把最新状态输入到控制/动作神经网络
    3. 让神经网络算出新的动作(比如下一个关节角度)
    4. 把这个动作指令下发给机器人

2. 和采样频率的关系

  • 和采样频率其实很接近。
    • 采样频率通常指“每秒采集环境状态/观察数据的次数”。
    • 控制频率指“每秒对机器人更新动作命令的次数”。
  • 论文里的“50Hz”往往同时代表感知→决策→执行这一整套循环的刷新频率(事实上它就是控制系统的“刷新频率”)。

这里的50Hz控制频率在论文实验中主要是指“人为操作采集数据阶段”的操作刷新频率,即人类操作者通过远程遥控(teleoperation)机器人时,系统每秒会将新的人类控制输入(比如操纵杆/按钮等动作指令)刷新并执行50次。

2025-11-29 14点52分 看到了ACKNOWLEDGEMENT,真是不容易

A sample of z is obtained using reparameterization, a standard way to allow back-propagating through the sampling process so the encoder and decoder can be jointly optimized

  • 上文说:encoder 会输出一个 分布 来表示风格变量 z
    • 比如:均值 μ(一个向量),方差 σ²(一个向量)
    • 表示:z ~ N(μ, σ²I),也就是一个高斯分布
  • 我们想从这个分布里“抽一个 z”,然后交给 decoder 去预测动作序列。

问题:

  • 这一步“抽 z(sampling)”是一个随机操作。
  • 神经网络训练需要“从输出算损失,再把梯度往前传回每一层”,叫 back-propagation(反向传播)
  • 普通的“随机采样”是不可导的,梯度没法顺畅地传回去给 encoder 学习。

换句话说
如果我们只是简单写 z = sample_from_gaussian(μ, σ),那 z 这一步“掐断了链路”,encoder 那些参数就不知道自己哪里做得好/不好,无法被更新好。

2. reparameterization 是什么鬼?

reparameterization(重参数化技巧) 就是想办法把:

“从一个分布里抽样(随机 z)”

改写成:

“从一个固定简单分布抽样一个 ε,再用一个可导的公式算出 z”

通常我们这样写:

  • 先从标准正态分布中采样:
    ε ~ N(0, I) (均值为0,方差为1的高斯)
  • 然后用 encoder 输出的 μ 和 σ 来算 z:
    z = μ + σ ⊙ ε
    (⊙ 表示按元素相乘)

这样一来:

  • “随机性”集中在 ε 上(ε 和网络参数无关,只是外部噪声)
  • μ 和 σ 通过一个完全可导的公式“搬运” ε,生成 z
  • 因为 z 是 μ, σ 的光滑函数(加减乘),所以:
    • 损失 L 对 z 的导数 可以通过链式法则传到 μ 和 σ
    • 于是 encoder 网络就能得到梯度,继续学习。

这整个改写的过程就叫 reparameterization trick

4. 用生活类比讲一下

想象你在教一个学生(encoder + decoder)画画:

  • 你先让学生根据风格参数(μ, σ)想象一个“风格随机数 z”
  • 再用 z 来画画(decoder 输出画作)
  • 然后你看画作评分(loss),要告诉学生哪里画得不好

如果“z 是硬抽的,没有可导关系”,那相当于:

  • 学生脑子“随机冒出一个点子 z”
  • 你只知道画坏了,但不知道是“脑子生成风格参数的那部分”问题,还是“画画技术(decoder)有问题”,没法细分反馈。

reparameterization做法相当于:

  • 告诉学生:
    • 先从“公共灵感池”里随便抽一个 ε(大家都能抽到,和个人无关)
    • 再用你自己的参数 μ, σ 进行“可导的加工”得到 z
  • 这样当画差时,你就能追着 μ, σ 和画技两个部分都给具体反馈(反向传播),两部分都会改进。

5. 一句话极简总结

reparameterization 就是把“随机抽 z”改写成“z = μ + σ·ε”这种可导的形式,让随机性通过 ε 承担,而 μ、σ 仍然可以接受梯度,从而 encoder 和 decoder 能一起被优化。

在 Step 3 里,CVAE decoder(也就是策略网络)的做法是:
先用 ResNet18 把每个摄像头的图像变成带有空间位置信息的特征序列,再把四个摄像头的特征序列连起来,加上当前关节状态和风格变量 z,一起送入 Transformer Encoder,得到对当前观测+状态+风格的高层表示;然后 Transformer Decoder 把这些表示作为 keys/values,用固定位置编码作为 queries,通过 cross-attention 逐步预测出整个动作序列。


The “queries” are fixed sinusoidal embeddings for the first layer.

这句话的意思是:
在解码器的第一层里,为了预测第1步、第2步、第3步……这些动作,他们不是用“前一步动作”当输入,而是给每个时间步一个固定的、只表示“我是第几步”的位置向量(正弦位置编码),把这些当作 queries。

也就是说:
每个要预测的动作时间步都有一个“我在第 t 步”的标签,这个标签就是一个固定的正弦向量,用来问:“在当前观察和状态下,我这第 t 步应该干什么?”

下面超细致地拆开。


1. 先搞清楚:queries / keys / values 是谁在干嘛?

在 Transformer 的 注意力机制(attention) 里:

  • keys(K)和 values(V)
    你可以想象是“知识库”里的内容:

    • keys:用来判断“这个位置和我现在的问题相关不相关?”
    • values:真正存的信息,被根据相关性加权平均后给当前步使用。
  • queries(Q)
    就像“提问的人”带着一个问题向量去问:“我现在要预测第 t 步动作,我该关心哪些输入信息?”

在本模型里:

  • Encoder 输出:当作 keys & values(机器人当前看到的图像特征 + 关节 + z 的理解)
  • Decoder:每个时间步都生成一个 query,去从这些 keys / values 里“取信息”,然后输出这个时间步的动作。

2. 一般情况下,queries 可以怎么来?

常见两种做法(你不用都记,只是帮你区分这篇论文在做什么):

  1. 自回归方式

    • 第 t 步的 query 用“前 t−1 步已经预测出的动作”再做个投影得到。
    • 就像语言模型那样:“我已经说了前面这些词,现在我要说下一个词”。
  2. 位置编码方式(这篇论文用的):

    • 不依赖前面的输出,而是直接给每个时间步一个“固定的位置信号”,表示“现在是第1步”、“第2步”、“第3步”。
    • 然后靠 cross-attention 从 Encoder 里取必要信息。

这篇论文明确说:

The “queries” are fixed sinusoidal embeddings for the first layer.

也就是:
Decoder 第一层的 query,不是来自前一步预测,而是来自“固定的正弦位置编码”。


3. 什么是 fixed sinusoidal embeddings?

我们分拆成两个词:

3.1 sinusoidal(正弦)位置编码

  • 常见于 Transformer(比如原始 Transformer 论文),用 sin 和 cos 函数给每个“位置 index”生成一个向量。
  • 举个概念上的例子(不必记公式):
    • 对于位置 1,我们用不同频率的 sin(1)、cos(1)、sin(1/10000)… 拼成一个向量
    • 对于位置 2,用 sin(2)、cos(2)、sin(2/10000)… 拼成另一个向量
  • 这样一来:
    • 不同位置有不同向量
    • 模型可以从这些向量中“感知顺序”:哪个是前、哪个是后,谁距离谁近

所以:
正弦位置嵌入 = 一种用 sin/cos 函数生成“带顺序意义”的向量的方法。

3.2 fixed(固定的)

  • “固定”的意思是:这些向量不靠训练学出来,而是用公式直接算。
  • 所以网络不会改变它们,只是使用它们。
  • 每次训练/测试时,对于第1步、第2步 … 的向量始终相同。

4. 把它们当 queries 是什么意思?

我们假设要预测未来 k 步动作:
t = 1, 2, ..., k

对于每个 t:

  1. 用“正弦位置编码公式”生成一个向量 PE(t)
  2. 这个向量就是这一时间步的 query(第一层的输入)

于是:

  • 第1步的 query:一个固定的“我是第1步”的向量
  • 第2步的 query:一个固定的“我是第2步”的向量
  • 第k步的 query:一个固定的“我是第k步”的向量

这些 query 不含任何动作内容,只告诉模型两件事:

  1. “我现在代表第 t 个动作槽位”
  2. “我需要从 Encoder 提供的图像+关节+z 信息中,取出对第 t 步最有用的东西”

接着 Decoder 会用这些 query 通过 cross-attention 去读 Encoder 的 keys / values,然后输出每步动作向量。


5. 为什么要这样设计?

几点直观原因(不需要你全都背下来,只是帮助理解逻辑):

  1. 让动作序列的每一步有独立的“时间位置身份”

    • 第1步和第10步虽然都在同一个观察下预测,但它们的“使命”不一样:
      • 第1步可能是“先伸手”
      • 第10步可能是“拔出来”
    • query 里加入“我是第 t 步”的位置信息,可以帮模型区分每一步的角色。
  2. 不用依赖之前是否预测正确

    • 如果 query 来自前一步动作,那么一旦前面预测有误,后面会层层传染(error accumulation)。
    • 用固定位置编码做第一层 query,可以减少这种连锁错误的影响,让每一步都直接依据 Encoder 的“观察理解”来决定。
  3. 结构简单、易训练

    • 因为 query 是固定的,不需要额外学这些向量,它只负责“占位”和表明“第几步”。

6. 再用一个生活比喻说明

假设你是老师(Decoder),你有一本说明书(Encoder 输出的理解:当前图像+状态+风格z)。

你要写下一个“做菜步骤清单” 1~k 步。
你这样做:

  • 你先写一个空白步骤格子:“步骤1:_____”

    • 这个“步骤1”的标题就是 query1(固定模板)
    • 然后你根据说明书里的内容(keys/values)来填:这一步要干啥
  • 然后你写“步骤2:_____”

    • 这个“步骤2”的标题就是 query2(另一个固定模板)
    • 再次去说明书里查:第二步应该做什么动作

每个“步骤标题”本身没有内容,只说明“这是第几步”,真正的内容从说明书(Encoder 输出)里查出来。

这里的“步骤标题模板”就是 fixed sinusoidal embeddings,
把它作为 query,就是让它充当“第 t 步动作的提问者”。


7. 一句话压缩总结

“The ‘queries’ are fixed sinusoidal embeddings for the first layer.” 的意思是:
在解码器预测动作序列的第一层中,针对将要输出的每一个时间步,他们不给它任何前一步动作信息,而是只给它一个固定的、只编码“我是第几步”的正弦位置向量,这个向量就作为这个时间步在 cross-attention 里向 Encoder 提问的 query。


Fig. 11: Detail architecture of Action Chunking with Transformers (ACT).

这个图很有必要看看

图里画的 Weight matrix (512) → [CLS] (512),可以理解成:

  • 他们没有把 [CLS] 当成“一个固定常数向量”,
    而是当成一个 可学习的参数向量

  • 这个参数向量本质上就是一个大小为 512 的权重向量(或者是一个 1×512 的权重矩阵), 在训练过程中和模型其它参数一起更新。

  • 画成 “Weight matrix (512)” → [CLS] (512),只是为了说明:

    “这个 [CLS] 不是输入数据算出来的,而是模型里直接存着的一块参数,维度 512。”

所以:

  • 为什么是由 Weight matrix (512) 得到?
    因为 [CLS] 向量本身就是一个 learnable weight,用一个 512 维的权重矩阵/向量来表示;
    每次前向传播时,直接把这块权重取出来(或者用一个很简单的线性层)当作 [CLS] token 的嵌入。

所以这个token不是一个单纯的标记符,而是一个复杂矩阵

step 3

Sinusoidal Position Embedding(正弦位置编码)是 Transformer 里常用的一种 位置编码方式,用来告诉模型“序列中第几个元素”。

  • 左边 encoder 部分:
    ResNet 特征 + Sinusoidal PosEmb → 告诉 encoder 每个图像 patch / 时间帧在序列中的位置。
  • 右边 decoder 部分:
    position embeddings (fixed) → 给每个要预测的动作时间步一个独特的位置向量,作为解码器输入 token。

图里的 position embeddings (fixed) 是什么?

在这张图里,decoder 下面那一排彩色小方块标的 position embeddings (fixed) 表示:

  • 解码器输入端有一串长度为 T 的向量(T = 要预测的 action 的时间步数)。
  • 第 t 个向量只编码“这是第 t 个时间步”,不包含具体动作信息。
  • 这些向量是 固定不学习的(fixed),通常就是 正弦位置编码(sinusoidal position embedding)

换句话说:
decoder 的输入 token = “时间步 query”,每个 query 仅由一个固定的位置向量表示。

就是那个固定的Q

15点52分 2025-11-29 不错,差不多看完了。