NVIDIA Cosmos 平台架构全解¶
Cosmos WFM Pipeline(原论文 arXiv:2501.03575 Figure 2)

最后更新: 2026-04-14 | 深度调研
Cosmos Tokenizer¶
-
编码器-解码器架构, 时序因果卷积 + 因果注意力 + 二级小波变换
-
最大压缩比: 2048x (时序8x × 空间16x16)
-
PSNR 37.27 (SOTA), 比竞品快2-12x, 压缩量提升8x
-
连续型(CV)供扩散模型 + 离散型(DV, 64K词汇量)供自回归
-
12个预训练变体开源
Cosmos-Predict¶
-
扩散路线(7B/14B): 整流流速度预测, 3D Patchification, AdaLN-LoRA(减36%参数)
-
自回归路线(4B-13B): 解码器only Transformer, 3D RoPE, 渐进预训练(17→121帧)
-
Predict2.5: 统一Text/Image/Video2World, 集成Reason1编码器, RL后训练, 30秒生成
-
训练: 2亿高质量视频片段
Cosmos-Transfer¶
-
多ControlNet并联: 分割/深度/边缘/人体关键点/LiDAR/HD地图/3D bbox
-
Transfer2.5(2B): 模型缩小3.5x, 自动驾驶检测精度提升60%
-
7路相机交叉注意力实现多视角一致性
Cosmos-Reason2¶
-
基于Qwen3-VL(2B/8B), 256K上下文窗口
-
三阶段训练: 预训练→SFT(物理AI专项)→RL
-
Physical AI Bench排行榜第一
-
56B版本物理常识: 60.2%(超OpenAI o1的59.9%)
训练规模¶
-
9000万亿tokens, 2000万小时视频
-
10,000台H100 x 3个月
-
5阶段数据流水线: 切分→过滤→标注→去重→分片
开源组件¶
-
全系列模型权重(NVIDIA Open Model License)
-
Tokenizer/Predict/Transfer/Reason均开源
-
训练脚本(Apache 2.0), TokenBench评测数据集
-
专有: 内部VLM标注模型, 原始训练数据集
参考¶
工程实现细节¶
DiT 单块张量流(AdaLN-Zero)¶
AdaLN-Zero 是 DiT 区别于普通 Transformer 的核心:从条件 c(时间步+文本)预测每层的 scale/shift 参数,并用初始化为零的 gate 门控残差。
import torch
import torch.nn as nn
class DiTBlock(nn.Module):
"""
一个 DiT 块的完整张量流 (Cosmos Predict 采用此架构)
输入:
x: (B, N, D) - token sequence, N = T/t H/h W/w
c: (B, D_cond) - condition (time embedding + text pooled)
"""
def __init__(self, d_model=4096, num_heads=32, mlp_ratio=4.0):
super().__init__()
self.norm1 = nn.LayerNorm(d_model, elementwise_affine=False, eps=1e-6)
self.norm2 = nn.LayerNorm(d_model, elementwise_affine=False, eps=1e-6)
self.attn = nn.MultiheadAttention(d_model, num_heads, batch_first=True)
self.mlp = nn.Sequential(
nn.Linear(d_model, int(d_model * mlp_ratio)),
nn.GELU(approximate='tanh'),
nn.Linear(int(d_model * mlp_ratio), d_model),
)
# AdaLN-Zero: 6 sets of modulation params per block
# shift/scale/gate for both attention and MLP
self.adaLN_modulation = nn.Sequential(
nn.SiLU(),
nn.Linear(d_model, 6 * d_model, bias=True)
)
# 关键初始化: 最后的 Linear 权重+偏置全零
# 使得早期训练时 gate=0, attention 和 mlp 对输出贡献为 0
nn.init.zeros_(self.adaLN_modulation[-1].weight)
nn.init.zeros_(self.adaLN_modulation[-1].bias)
def forward(self, x, c):
# x: (B, N, D), c: (B, D)
# 1. 从条件预测 6 个 modulation 参数
mod = self.adaLN_modulation(c) # (B, 6D)
shift_msa, scale_msa, gate_msa, \
shift_mlp, scale_mlp, gate_mlp = mod.chunk(6, dim=1) # 各 (B, D)
# 2. Attention 分支: LN → scale+shift → Attn → gate
x_norm1 = self.norm1(x) # (B, N, D)
x_mod = x_norm1 * (1 + scale_msa.unsqueeze(1)) + shift_msa.unsqueeze(1)
attn_out, _ = self.attn(x_mod, x_mod, x_mod) # (B, N, D)
x = x + gate_msa.unsqueeze(1) * attn_out # gated residual
# 3. MLP 分支
x_norm2 = self.norm2(x)
x_mod = x_norm2 * (1 + scale_mlp.unsqueeze(1)) + shift_mlp.unsqueeze(1)
mlp_out = self.mlp(x_mod)
x = x + gate_mlp.unsqueeze(1) * mlp_out
return x # (B, N, D)
# ========== AdaLN-LoRA: 11B → 7B 参数压缩 ==========
# 标准 AdaLN: 每个 block 的 modulation MLP 是 d_model × 6*d_model = 4096 × 24576
# Cosmos 用低秩分解:
class AdaLNLoRA(nn.Module):
def __init__(self, d_model=4096, lora_rank=64):
# 共享 Embedding → LoRA down/up projection per block
self.down = nn.Linear(d_model, lora_rank, bias=False)
self.up = nn.Linear(lora_rank, 6 * d_model, bias=True)
nn.init.zeros_(self.up.weight); nn.init.zeros_(self.up.bias)
def forward(self, c):
return self.up(self.down(c))
# 参数对比:
# 标准 AdaLN per block: 4096 * 24576 = 100.7M
# AdaLN-LoRA per block: 409664 + 6424576 = 0.26M + 1.57M = 1.83M
# 36 blocks × 节省 ≈ 3.56B 参数!
Rectified Flow Matching 训练与采样¶
# ============ 训练 Loss ============
def flow_matching_loss(model, x0, c):
"""
x0: (B, T, H, W, C) - 真实数据 (经 VAE/Tokenizer 编码后的 latent)
c: 条件 (text + ego_dynamics 等)
核心: 学习速度场 v_θ(x_t, t) 使得插值路径是直线
"""
B = x0.shape[0]
# 采样随机噪声和时间
x1 = torch.randn_like(x0) # (B, T, H, W, C)
t = torch.rand(B, 1, 1, 1, 1).to(x0.device) # (B, 1, 1, 1, 1)
# GAIA-2/Cosmos 实际使用双峰 logit-normal:
# if rand < 0.8: t ~ LogitNormal(0.5, 1.4)
# else: t ~ LogitNormal(-3.0, 1.0)
# 这让训练重点落在中段去噪(μ=0.5)和纯噪声附近(μ=-3.0)
# 线性插值 (Rectified Flow 的精髓)
x_t = (1 - t) x1 + t x0 # t=1 → x0, t=0 → x1
# 目标速度 = x0 - x1 (常数向量!)
v_target = x0 - x1
# 预测速度
v_pred = model(x_t, t.squeeze([-1,-2,-3,-4]), c)
return F.mse_loss(v_pred, v_target)
# ============ 采样 (Euler ODE) ============
@torch.no_grad()
def sample_flow_matching(model, shape, c, num_steps=50, cfg_scale=4.0):
"""
Rectified Flow 的 ODE: dx/dt = v_θ(x_t, t)
Euler 法: x_{t+dt} = x_t + dt * v_θ(x_t, t)
"""
x = torch.randn(shape).cuda() # t=0: 纯噪声
dt = 1.0 / num_steps
for step in range(num_steps):
t_cur = step * dt
t_tensor = torch.full((shape[0],), t_cur).cuda()
# Classifier-Free Guidance
v_cond = model(x, t_tensor, c) # 条件预测
v_uncond = model(x, t_tensor, None) # 无条件预测
v = v_uncond + cfg_scale * (v_cond - v_uncond)
x = x + dt * v # Euler 一步
return x # t=1: 生成样本
# ============ 为什么 Rectified Flow 需要更少步? ============
# DDPM 前向过程: 弯曲扩散路径 → 求解需多步
# Rectified Flow: 直线路径 (v 是常数) → 理论上 1 步就够, 实际 25-50 步足以
#
# 关键洞察: E[x0 - x1 | x_t] 是 noisy target, 模型学到的是条件期望的速度
# 30 次 Euler 迭代 vs DDPM 的 1000 次 ≈ 33× 加速
Cosmos Tokenizer: FSQ 与 3D 因果卷积¶
# ============ 3D 因果卷积 ============
class CausalConv3d(nn.Module):
"""
保证时序因果性: 当前帧只依赖过去帧, 不看未来
空间维度正常 padding
"""
def __init__(self, in_ch, out_ch, kernel=(3,3,3)):
super().__init__()
kt, kh, kw = kernel
self.kt = kt
# 时间维度 padding 只在前面 (kt-1), 空间正常对称
self.conv = nn.Conv3d(
in_ch, out_ch, kernel,
padding=(0, kh//2, kw//2) # T 维度 padding=0, 手动 pad 前面
)
def forward(self, x):
# x: (B, C, T, H, W)
# 前面 pad (kt-1) 个 0, 保证 output[:, :, t] 只依赖 input[:, :, <=t]
x = F.pad(x, (0, 0, 0, 0, self.kt - 1, 0))
return self.conv(x)
# ============ FSQ (Finite Scalar Quantization) ============
class FSQ(nn.Module):
"""
替代 VQ-VAE 的无码本量化方法
将连续向量的每一维量化到预定义的几个 level 上
"""
def __init__(self, levels=[8, 5, 5, 5, 6, 4]):
super().__init__()
self.levels = levels
self.num_dim = len(levels)
# 词表大小 = ∏ levels = 85556*4 = 24,000 (Cosmos 用 64,000)
self.codebook_size = 1
for l in levels: self.codebook_size *= l
def forward(self, z):
"""
z: (B, D, T, H, W) with D = num_dim
"""
# Step 1: bound into [-1, 1]
z = torch.tanh(z)
# Step 2: 每维映射到 [-(L-1)/2, (L-1)/2] 并四舍五入
out = []
for i, L in enumerate(self.levels):
z_i = z[:, i:i+1]
half_l = (L - 1) / 2
z_scaled = z_i * half_l
# 直通估计器 (STE): forward 取 round, backward 用恒等梯度
z_quant = z_scaled + (z_scaled.round() - z_scaled).detach()
out.append(z_quant / half_l) # 归一化回 [-1, 1]
z_q = torch.cat(out, dim=1)
return z_q
def to_index(self, z_q):
"""从量化向量得到单个 codebook 索引"""
idx = 0
multiplier = 1
for i, L in enumerate(self.levels):
# z_q[:,i] ∈ {-1, ..., 1} 有 L 个值
half_l = (L - 1) / 2
bucket = ((z_q[:, i] * half_l) + half_l).long() # 0..L-1
idx = idx + bucket * multiplier
multiplier *= L
return idx # (B, T, H, W)
# ============ 为什么 FSQ > VQ-VAE ============
# VQ-VAE 痛点:
# 1. 码本崩溃 (大量码字从未被用)
# 2. 需要 commitment loss, EMA codebook update 等 tricks
# FSQ 优势:
# 1. 无码本, 不会崩溃
# 2. 无辅助 loss
# 3. 训练更稳定, 重建质量相当或更好
Tokenizer 整体架构与压缩比¶
Grouped Query Attention 与 KV Cache¶
# ============ GQA 实现 ============
class GroupedQueryAttention(nn.Module):
"""
Dreamer V4 / Cosmos AR 使用 GQA: 16 Q heads, 4 KV heads
相比 MHA: KV 内存降至 1/4
相比 MQA: 性能损失少, 灵活性高
"""
def __init__(self, d_model=4096, num_q_heads=16, num_kv_heads=4):
super().__init__()
self.num_q_heads = num_q_heads
self.num_kv_heads = num_kv_heads
self.head_dim = d_model // num_q_heads # 256
self.group_size = num_q_heads // num_kv_heads # 4 Q heads share 1 KV head
# Q 全大小, KV 小 4 倍
self.W_q = nn.Linear(d_model, num_q_heads * self.head_dim, bias=False)
self.W_k = nn.Linear(d_model, num_kv_heads * self.head_dim, bias=False)
self.W_v = nn.Linear(d_model, num_kv_heads * self.head_dim, bias=False)
self.W_o = nn.Linear(num_q_heads * self.head_dim, d_model, bias=False)
def forward(self, x, kv_cache=None, causal=True):
B, N, D = x.shape
Q = self.W_q(x).reshape(B, N, self.num_q_heads, self.head_dim) # (B, N, 16, 256)
K = self.W_k(x).reshape(B, N, self.num_kv_heads, self.head_dim) # (B, N, 4, 256)
V = self.W_v(x).reshape(B, N, self.num_kv_heads, self.head_dim) # (B, N, 4, 256)
# KV Cache: 增量生成时只处理新 token
if kv_cache is not None:
K_cached, V_cached = kv_cache # (B, N_past, 4, 256)
K = torch.cat([K_cached, K], dim=1) # (B, N_past+N_new, 4, 256)
V = torch.cat([V_cached, V], dim=1)
# Repeat KV 以匹配 Q 的 heads
# Flash Attention 2 内部优化: 不实际 repeat, 用广播
K_rep = K.repeat_interleave(self.group_size, dim=2) # (B, N, 16, 256)
V_rep = V.repeat_interleave(self.group_size, dim=2)
# (B, heads, N, head_dim)
Q = Q.transpose(1, 2)
K_rep = K_rep.transpose(1, 2)
V_rep = V_rep.transpose(1, 2)
# Scaled Dot-Product Attention (用 flash attention 加速)
out = F.scaled_dot_product_attention(Q, K_rep, V_rep, is_causal=causal)
out = out.transpose(1, 2).reshape(B, N, -1)
new_cache = (K, V) if kv_cache is not None else None
return self.W_o(out), new_cache
# ============ KV Cache 内存节省 ============
# 标准 MHA: 16 heads × seq_len × head_dim × 2 (K+V) × 2 bytes (bf16)
# seq_len=8192, 16 heads, head_dim=256:
# MHA Cache: 16 × 8192 × 256 × 2 × 2 = 134 MB per layer
# GQA Cache: 4 × 8192 × 256 × 2 × 2 = 33 MB per layer (4× 节省)
# 36 层: MHA 4.8 GB vs GQA 1.2 GB — 关键于长上下文自回归生成
Cosmos EDM 预条件化(数值稳定核心)¶
# ============ EDM (Elucidating Diffusion Models) ============
# 不同 σ 下网络的输入/输出尺度差异巨大
# 若不预条件化, 在 σ=80 (纯噪声) vs σ=0.002 (几乎干净) 时网络行为完全不同
# EDM 的 4 个预条件化系数让网络在所有 σ 下看到 ~O(1) 的输入输出
def edm_denoise(model, x, sigma, sigma_data=0.5):
"""
EDM 预条件化去噪函数
x: 带噪声的输入
sigma: 噪声水平 (scalar 或 per-sample)
sigma_data: 数据标准差 (超参数, Cosmos ~0.5)
"""
# 预条件化系数
c_in = 1.0 / torch.sqrt(sigma2 + sigma_data2) # 归一化输入
c_noise = sigma.log() / 4 # 输入网络的 σ 表示
c_skip = sigma_data2 / (sigma2 + sigma_data2) # skip 连接权重
c_out = sigma * sigma_data / torch.sqrt(sigma2 + sigma_data2) # 输出缩放
# 网络预测在规约空间
F_theta = model(c_in * x, c_noise) # (B, ...) 目标是 ~N(0,I)
# 反预条件化: 还原为原始尺度的去噪预测
D = c_skip x + c_out F_theta
return D # 预测的 clean x
# ============ EDM Sampling (Heun 二阶求解器) ============
@torch.no_grad()
def edm_sample(model, shape, num_steps=30, sigma_min=0.002, sigma_max=80, rho=7):
"""
EDM σ 调度: σ_i = (σ_max^{1/ρ} + i/(N-1) * (σ_min^{1/ρ} - σ_max^{1/ρ}))^ρ
ρ=7 让步长在高 σ 处密集, 低 σ 处稀疏 — 更好利用算力
"""
# 非均匀 σ schedule
step_indices = torch.arange(num_steps)
t = (sigma_max(1/rho) + step_indices / (num_steps - 1) *
(sigma_min(1/rho) - sigma_max(1/rho))) rho
t = torch.cat([t, torch.zeros_like(t[:1])]) # 末尾加 0
x = torch.randn(shape) * sigma_max
for i in range(num_steps):
t_cur, t_next = t[i], t[i+1]
# 去噪
denoised = edm_denoise(model, x, t_cur.expand(shape[0]))
# Heun 二阶修正 (除最后一步)
d_cur = (x - denoised) / t_cur
x_next = x + (t_next - t_cur) * d_cur
if t_next > 0:
denoised_next = edm_denoise(model, x_next, t_next.expand(shape[0]))
d_next = (x_next - denoised_next) / t_next
x = x + (t_next - t_cur) 0.5 (d_cur + d_next) # 平均斜率
else:
x = x_next
return x
Cosmos 14B 训练并行化策略¶
训练规模¶
训练配置: 9000 万亿 tokens / 10,000 × H100 / 3 个月 ≈ 1e22 FLOPs 总计算量。每个 batch 大约 5-10M tokens,总步数约 9-18 亿步(分阶段)。
关键数学公式¶
DiT AdaLN-Zero 调制¶
从条件 c 预测 6 组参数(scale/shift/gate 各 2 对):
\([\gamma_1,\beta_1,\alpha_1,\gamma_2,\beta_2,\alpha_2] = \operatorname{MLP}(c)\)
Attention 分支:\(x \leftarrow x + \alpha_1\cdot\operatorname{Attn}\!\left(\gamma_1\cdot\operatorname{LN}(x) + \beta_1\right)\)
MLP 分支:\(x \leftarrow x + \alpha_2\cdot\operatorname{MLP}\!\left(\gamma_2\cdot\operatorname{LN}(x) + \beta_2\right)\)
最后一层 MLP 权重初始化为零 → 早期训练 \(\alpha \approx 0\),残差分支“冷启动”。
AdaLN-LoRA(11B→7B 关键)¶
标准 AdaLN 每层参数 O(d²);LoRA 分解为低秩:
\(\operatorname{MLP}(c) = W_{\text{up}}\,W_{\text{down}}\,c,\quad W_{\text{down}}\in\mathbb{R}^{r\times d},\ W_{\text{up}}\in\mathbb{R}^{6d\times r}\)
\(r=64\) → 每层 100.7M 降到 1.83M,36 层共节省约 3.56B 参数。
Rectified Flow / Flow Matching¶
线性插值路径:\(x_t = (1-t)\,x_1 + t\,x_0,\quad t\in[0,1]\)
目标速度(常数!):\(v^*_t = x_0 - x_1\)
训练目标:\(\mathcal{L}_{\text{FM}} = \mathbb{E}_{t,x_0,x_1}\!\left[\|v_\theta(x_t,t) - (x_0-x_1)\|_2^2\right]\)
Euler 采样:\(x_{t+dt} = x_t + dt\cdot v_\theta(x_t,t)\)
Classifier-Free Guidance¶
\(\tilde v_\theta(x_t,t,c) = v_\theta(x_t,t,\varnothing) + w\cdot\left[v_\theta(x_t,t,c) - v_\theta(x_t,t,\varnothing)\right]\)
等效于隐式分类器引导 \(\nabla \log p(c|x)\)。\(w \in [2, 20]\),小 w 多样性高、大 w 条件保真度高。
EDM 预条件化(4 个系数)¶
输入缩放:\(c_{\text{in}}(\sigma) = 1/\sqrt{\sigma^2 + \sigma_d^2}\)
输出缩放:\(c_{\text{out}}(\sigma) = \sigma\cdot\sigma_d / \sqrt{\sigma^2 + \sigma_d^2}\)
Skip 权重:\(c_{\text{skip}}(\sigma) = \sigma_d^2 / (\sigma^2 + \sigma_d^2)\)
σ 编码:\(c_{\text{noise}}(\sigma) = \ln(\sigma)/4\)
去噪函数:
\(D(x;\sigma) = c_{\text{skip}}(\sigma)\cdot x + c_{\text{out}}(\sigma)\cdot F_\theta\!\left(c_{\text{in}}(\sigma)\cdot x,\ c_{\text{noise}}(\sigma)\right)\)
Karras σ Schedule¶
\(\sigma_i = \left(\sigma_{\max}^{1/\rho} + \frac{i}{N-1}\left(\sigma_{\min}^{1/\rho} - \sigma_{\max}^{1/\rho}\right)\right)^\rho\)
\(\rho=7\) → 高 \(\sigma\) 处步长密集、低 \(\sigma\) 处稀疏,更好利用算力。
EDM Heun 二阶求解器¶
当前斜率:\(d_i = (x_i - D(x_i,\sigma_i))/\sigma_i\)
试探步:\(x_{i+1}^{\text{tmp}} = x_i + (\sigma_{i+1}-\sigma_i)\cdot d_i\)
Heun 修正:\(x_{i+1} = x_i + (\sigma_{i+1}-\sigma_i)\cdot\frac{1}{2}\left(d_i + d_{i+1}\right)\)
FSQ(有限标量量化)¶
对每一维独立量化到 L 个 level(无需 codebook):
\(z_q^{(i)} = \frac{1}{L_i/2}\cdot\operatorname{round}\!\left(\frac{L_i}{2}\cdot\tanh(z^{(i)})\right)\)
词表大小 = \(\prod L_i\)。Cosmos 用 [8,5,5,5,6,4] → 24,000 词;实际部署 64,000。
GQA 注意力¶
Q 头数 H_q,KV 头数 H_{kv},groupsize g = H_q/H_{kv}:
\(\operatorname{GQA}(Q,K,V) = \operatorname{Softmax}\!\left(\frac{Q\,\operatorname{repeat}(K)^\top}{\sqrt{d_h}}\right)\operatorname{repeat}(V)\)
Dreamer V4 / Cosmos AR 用 16:4 = 4×,KV cache 内存降至 \(1/4\)。
Code 引用索引与可信度¶
✓=官方代码直接移植, △=基于论文描述重构, ⚠=推测填充 ——
注: 所有 "✓" 级代码的完整版本请参考对应 GitHub repo;本文的 PyTorch 伪代码经过简化以突出核心逻辑。
↑ 上级 · 02 技术架构与核心方法