学习 VLA 第 4 天:Transformer 原理与复现实战
1. 引言

今天是学习视觉-语言-动作模型(Vision-Language-Action,VLA)的第 4 天。前三天分别了解了 VLA 的整体架构等,今天终于进入 VLA 中最核心的组件——Transformer。
Transformer 是当前几乎所有大模型的基础架构,VLA 模型同样离不开它。无论是处理视觉 token、语言 token,还是生成动作 token,Transformer 的自注意力机制都扮演着关键角色。今天的目标是:深入理解 Transformer 的核心原理,并动手复现一个可运行的简化版本。
为什么 Transformer 如此重要?因为它解决了传统循环神经网络(RNN)的两个致命问题:一是无法并行计算,训练速度慢;二是难以捕捉长距离依赖关系,容易遗忘早期信息。Transformer 通过自注意力机制,让序列中的任意两个位置都能直接交互,既实现了并行计算,又完美解决了长距离依赖问题。这也是它能够成为大模型基石的根本原因。
2. Transformer 为什么对 VLA 如此重要
在 VLA 模型中,Transformer 承担着三个关键职责。这三个职责分别对应了 VLA 模型处理不同模态信息的能力,也是理解 VLA 工作原理的核心线索:
- 跨模态融合:将视觉特征和语言特征在统一的 token 空间中进行交互,让模型理解"看到什么"与"指令说什么"之间的关系。
- 序列建模:处理变长的输入序列(图像 patch 序列、文本 token 序列),捕捉长距离依赖关系。
- 动作解码:自回归地生成动作 token 序列,将高层语义决策转化为具体的动作指令。
可以说,没有 Transformer,就没有今天的 VLA 模型。理解 Transformer 是复现和理解 VLA 的必经之路。
以 RT-2 为例,它本质上就是一个将视觉-语言模型(VLM)与机器人动作空间结合起来的 Transformer 模型。RT-2 将机器人动作表示为文本 token,从而可以直接利用互联网规模的图文数据进行预训练,再在机器人数据上进行微调。这种设计思路正是建立在 Transformer 强大的序列建模能力之上的。理解了 Transformer,你就能看懂 RT-2、OpenVLA 等主流 VLA 模型的内部机制。
下面是 Transformer 在 VLA 中承担的三个关键职责的示意图:
3. Transformer 核心原理
3.1 整体架构
Transformer 采用编码器-解码器(Encoder-Decoder)结构,但在 VLA 中,我们更常使用编码器部分(如 ViT)或仅使用解码器部分(如 GPT 风格的自回归模型)。其核心组件包括:
原始 Transformer 论文(“Attention Is All You Need”)提出的架构包含两个部分:编码器负责将输入序列编码为上下文相关的特征表示,解码器则根据这些特征自回归地生成输出序列。在 VLA 模型中,这种结构被灵活运用:视觉编码器(如 ViT)使用 Transformer 编码器提取图像特征,而动作生成部分则常使用类似 GPT 的解码器结构,逐步预测动作 token。
无论使用哪种结构,Transformer 的核心组件都是相同的,它们共同构成了一个强大的特征提取和序列建模工具:
- 自注意力机制(Self-Attention):让序列中的每个 token 都能关注到其他所有 token。
- 多头注意力(Multi-Head Attention):将注意力拆分成多个子空间,捕捉不同类型的依赖关系。
- 前馈网络(Feed-Forward Network):对每个 token 独立进行非线性变换。
- 位置编码(Positional Encoding):为模型注入序列顺序信息。
- 残差连接与层归一化(Residual Connection & LayerNorm):稳定训练,加速收敛。
3.2 自注意力机制

自注意力的核心思想是:对于输入序列中的每个 token,计算它与序列中所有 token 的相关性(注意力权重),然后加权聚合所有 token 的信息。
具体计算过程如下:
- 将输入 ( X ) 分别乘以三个权重矩阵 ( W_Q )、( W_K )、( W_V ),得到查询(Query)、键(Key)、值(Value)矩阵。
- 计算注意力分数:Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)VAttention(Q,K,V)=softmax(dkQKT)V
- 除以 ( \sqrt{d_k} ) 是为了防止点积结果过大导致 softmax 梯度消失。
下面是自注意力机制的计算流程示意图:
3.3 多头注意力
多头注意力将 Q、K、V 分别拆分成 ( h ) 个头,每个头独立计算注意力,最后拼接并经过一个线性变换。这样做的好处是:
- 不同的头可以关注不同的关系模式(如语法关系、语义关系、位置关系)。
- 在不增加计算量的情况下,增强了模型的表达能力。
下面是多头注意力的拆分与拼接流程:
3.4 位置编码
由于自注意力机制本身不具备顺序感知能力,需要显式地注入位置信息。常用的方法有两种:
- 正弦位置编码:使用不同频率的正弦和余弦函数生成位置向量。
- 可学习位置编码:将位置编码作为可学习的参数,随模型一起训练。
下面是 Transformer 编码器的整体架构图,直观展示各组件之间的数据流向:
4. 从零复现 Transformer
下面用 PyTorch 从零实现一个简化但完整的 Transformer 编码器。这个实现将作为后续复现 VLA 模型的基础模块。
4.1 环境准备
pip install torch numpy
4.2 多头注意力实现
import torch
import torch.nn as nn
import math
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, n_heads, dropout=0.1):
super().__init__()
assert d_model % n_heads == 0, "d_model 必须能被 n_heads 整除"
self.d_model = d_model
self.n_heads = n_heads
self.d_k = d_model // n_heads
self.w_q = nn.Linear(d_model, d_model)
self.w_k = nn.Linear(d_model, d_model)
self.w_v = nn.Linear(d_model, d_model)
self.w_o = nn.Linear(d_model, d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask=None):
batch_size, seq_len, _ = x.size()
# 线性变换并拆分为多头
Q = self.w_q(x).view(batch_size, seq_len, self.n_heads, self.d_k).transpose(1, 2)
K = self.w_k(x).view(batch_size, seq_len, self.n_heads, self.d_k).transpose(1, 2)
V = self.w_v(x).view(batch_size, seq_len, self.n_heads, self.d_k).transpose(1, 2)
# 计算注意力分数
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
attn = torch.softmax(scores, dim=-1)
attn = self.dropout(attn)
# 加权聚合
context = torch.matmul(attn, V)
context = context.transpose(1, 2).contiguous().view(batch_size, seq_len, self.d_model)
return self.w_o(context)
4.3 前馈网络与编码器层
class FeedForward(nn.Module):
def __init__(self, d_model, d_ff, dropout=0.1):
super().__init__()
self.linear1 = nn.Linear(d_model, d_ff)
self.linear2 = nn.Linear(d_ff, d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
return self.linear2(self.dropout(torch.relu(self.linear1(x))))
class EncoderLayer(nn.Module):
def __init__(self, d_model, n_heads, d_ff, dropout=0.1):
super().__init__()
self.self_attn = MultiHeadAttention(d_model, n_heads, dropout)
self.feed_forward = FeedForward(d_model, d_ff, dropout)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout1 = nn.Dropout(dropout)
self.dropout2 = nn.Dropout(dropout)
def forward(self, x, mask=None):
# 自注意力子层(残差连接 + LayerNorm)
attn_output = self.self_attn(x, mask)
x = self.norm1(x + self.dropout1(attn_output))
# 前馈子层(残差连接 + LayerNorm)
ff_output = self.feed_forward(x)
x = self.norm2(x + self.dropout2(ff_output))
return x
4.4 位置编码与完整编码器
class PositionalEncoding(nn.Module):
def __init__(self, d_model, max_len=512):
super().__init__()
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len).unsqueeze(1).float()
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0)
self.register_buffer('pe', pe)
def forward(self, x):
return x + self.pe[:, :x.size(1)]
class TransformerEncoder(nn.Module):
def __init__(self, vocab_size, d_model, n_heads, d_ff, n_layers, max_len, dropout=0.1):
super().__init__()
self.embedding = nn.Embedding(vocab_size, d_model)
self.pos_encoding = PositionalEncoding(d_model, max_len)
self.layers = nn.ModuleList([
EncoderLayer(d_model, n_heads, d_ff, dropout) for _ in range(n_layers)
])
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask=None):
x = self.dropout(self.pos_encoding(self.embedding(x)))
for layer in self.layers:
x = layer(x, mask)
return x
4.5 快速验证
# 参数设置
vocab_size = 1000
d_model = 128
n_heads = 8
d_ff = 512
n_layers = 4
max_len = 64
batch_size = 2
seq_len = 32
# 初始化模型
model = TransformerEncoder(vocab_size, d_model, n_heads, d_ff, n_layers, max_len)
# 随机输入
input_ids = torch.randint(0, vocab_size, (batch_size, seq_len))
# 前向传播
output = model(input_ids)
print(f"输出形状: {output.shape}") # 期望: torch.Size([2, 32, 128])
运行上述代码,如果输出形状为 torch.Size([2, 32, 128]),说明我们的 Transformer 编码器已经可以正常工作了。
5. 从 Transformer 到 VLA 的桥梁
复现完 Transformer 编码器后,来看看它是如何融入 VLA 模型的。一个典型的 VLA 模型(如 RT-2、OpenVLA)通常包含以下流程:
关键点在于:
- 视觉 Token 化:将图像切分为 patch,通过 ViT 编码为视觉 token 序列。
- Token 拼接:将视觉 token 和语言 token 拼接成统一序列,送入 Transformer。
- 动作生成:在序列末尾添加动作 token,通过自回归方式逐步生成动作。
6. 今日总结与下一步计划
今天从零复现了 Transformer 编码器,包括多头注意力、前馈网络、位置编码和残差连接等核心组件。通过动手实现,对自注意力机制有了更直观的理解。
今日收获:
- 理解了自注意力的计算流程和缩放点积注意力的原理。
- 掌握了多头注意力的拆分与拼接逻辑。
- 能够独立实现一个可运行的 Transformer 编码器。
- 明白了 Transformer 在 VLA 中承担跨模态融合和动作解码的关键角色。
7. 参考资料
- Vaswani et al., “Attention Is All You Need”, 2017
- Dosovitskiy et al., “An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale”, 2020
- Brohan et al., “RT-2: Vision-Language-Action Models Transfer Web Knowledge to Robotic Control”, 2023
- Kim et al., “OpenVLA: An Open-Source Vision-Language-Action Model”, 2024
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)