4. ACT模型架构详解:编码器-解码器结构、CNN Backbone、Transformer核心与动作分块
好,咱们今天来啃一块硬骨头——ACT模型的内部架构。说实话,我第一次看ACT论文的时候,也被它那套编码器-解码器加Transformer的组合拳搞得有点晕。但后来在实际项目中调通了之后,发现它其实是一个很优雅的设计。
ACT全称是Action Chunking Transformer,核心思路就是把模仿学习里的动作预测问题,转化成一个序列生成问题。说白了,就是让机器人学会“写一段动作代码”,而不是每次只蹦出一个字。
4.1 整体架构:编码器-解码器结构
ACT沿用了经典的编码器-解码器架构。这个结构在NLP里已经被验证过无数次了,但搬到机器人领域,还是有一些独特的调整。
编码器负责把当前的视觉信息(比如摄像头拍到的画面)压缩成一个特征向量。我习惯把它理解成“眼睛”,它看到什么,就提取出什么关键信息。
解码器则负责根据这个特征向量,以及一个特殊的“开始令牌”,逐步生成未来的动作序列。它就像“手”,根据眼睛看到的东西,决定接下来怎么动。
这里有个关键点:ACT的解码器不是一次只预测一个动作,而是一次预测一整段动作序列。这就是后面要讲的动作分块。
核心逻辑:编码器把图像变成特征,解码器把特征变成动作序列。两者通过交叉注意力机制连接。
4.2 CNN Backbone:ResNet vs EfficientNet
编码器的第一步,是用一个CNN Backbone来提取图像特征。ACT论文里主要用了两种:ResNet和EfficientNet。
ResNet 是经典中的经典。它的残差连接解决了深层网络梯度消失的问题。我在项目中用ResNet-50比较多,稳定,好调,社区支持也强。
EfficientNet 则更注重效率。它用神经架构搜索找到了一组最优的缩放系数,在同等计算量下,精度往往更高。但说实话,我在真机部署时发现,EfficientNet在边缘设备上的推理速度并没有理论那么快,因为它的深度可分离卷积在某些硬件上优化得不够好。
| 特性 | ResNet | EfficientNet |
|---|---|---|
| 参数量 | 较大(ResNet-50约25M) | 较小(B0约5M) |
| 推理速度 | 中等 | 理论快,实际看硬件 |
| 精度 | 稳定 | 同等计算量下更高 |
| 部署友好度 | 高(几乎所有框架都支持) | 中等(部分算子需手动优化) |
我的建议:如果你刚开始做ACT,先用ResNet-18或ResNet-34跑通流程。等模型收敛了,再换成EfficientNet-B4试试精度提升。别一上来就上最大的模型,不然调试周期会让你崩溃。
4.3 Transformer核心:自注意力与交叉注意力
ACT里的Transformer模块,是连接视觉和动作的桥梁。它包含两种注意力机制:自注意力和交叉注意力。
自注意力 让模型在同一个序列内部建立关联。比如在编码器里,图像的不同区域之间互相“看”一眼,理解全局上下文。我遇到过一个问题:如果图像里有多个相似物体,自注意力能帮模型区分它们各自的位置关系。
交叉注意力 则是编码器和解码器之间的通信通道。解码器通过交叉注意力,从编码器输出的特征中“检索”出当前动作最需要关注的视觉信息。说白了,就是让手知道眼睛在看哪里。
这里有个实现细节:ACT的交叉注意力通常采用多头机制(Multi-Head Attention)。每个头关注不同的特征子空间,最后拼接起来。我习惯用8个头,效果比较均衡。
# 伪代码:ACT中的交叉注意力模块
def cross_attention(query, key, value):
# query: 来自解码器的动作特征
# key, value: 来自编码器的视觉特征
scores = torch.matmul(query, key.transpose(-2, -1)) / sqrt(d_k)
attention_weights = softmax(scores, dim=-1)
output = torch.matmul(attention_weights, value)
return output
注意:交叉注意力的计算量跟序列长度平方成正比。如果你处理的图像分辨率很高,特征图很大,显存会爆炸。我建议先下采样到合适尺寸,比如7x7或14x14的特征图。
4.4 动作分块(Action Chunking)
这是ACT最核心的创新点之一。传统的模仿学习每次只预测一个动作,然后重新观测、再预测。这样做的缺点是:一旦某一步预测有偏差,后续动作就会越跑越偏。
动作分块的做法是:一次预测未来k个时间步的动作序列。比如k=100,模型一次性输出未来100步的关节角度或末端位姿。
这样做的好处很明显:
- 减少累积误差:模型必须规划一段连续的动作,而不是走一步看一步
- 提高执行平滑性:分块内的动作是联合优化的,不会出现突变
- 降低控制频率:你可以用更低的频率运行模型,比如每100ms推理一次
我在实际部署时,k值一般取50到100之间。太小了起不到分块的效果,太大了模型难以收敛。你可以根据任务的复杂度和控制周期来调整。
4.5 时间集成(Temporal Ensemble)
有了动作分块,又出现一个新问题:相邻两个分块之间怎么平滑过渡?
时间集成就是解决这个问题的。它的做法是:维护一个滑动窗口,把当前分块和之前的分块重叠部分进行加权平均。
举个例子:假设分块长度k=100,滑动步长s=10。那么每次推理,模型输出100个动作,但只执行前10个,然后丢弃。下一次推理时,新的100个动作和上一次剩下的90个动作在重叠区域做加权平均。
这样做的好处是:
- 动作更平滑:不会出现分块边界处的跳变
- 鲁棒性更强:即使某次推理结果有噪声,也会被平均掉
- 延迟更低:你可以用异步推理,当前分块执行的同时,后台已经在计算下一个分块
关键参数:滑动步长s决定了推理频率。s越小,动作越平滑,但计算开销越大。我一般设s = k/10,也就是每个分块执行10%就更新。
嗯,到这里,ACT的模型架构就讲完了。从CNN Backbone提取图像特征,到编码器-解码器用Transformer做序列建模,再到动作分块和时间集成保证执行质量——每一步都有它的设计逻辑。我在调通第一个ACT模型时,最大的感受就是:这套架构把视觉理解和动作生成真正融合在了一起,而不是简单拼凑。
下一章我们会深入训练细节,包括数据采集、损失函数设计和超参数调优。到时候再聊。