☰
Sora背后的Diffusion Transformer:视频生成新范式深度拆解
2026/10/27 3:42:28 网站建设 项目流程

2024年2月那几天,我朋友圈里全是同一条Sora demo:一个女人走在雨后的东京街头,镜头跟着她穿过霓虹灯,雨滴打在路面上,反光随着脚步晃动。作为做大模型相关事情的人,我当时第一反应确实是被画面质量震到了,但真正让我睡不着的不是那几十秒视频,而是OpenAI顺手放出来的技术报告。报告里几乎没有放架构图,却在字里行间反复出现同一个词:Diffusion Transformer,简称DiT。

那一夜之后,整个视频生成圈基本坐不住了。原因也很直白:Sora没开源,但它等于在所有人面前把牌摊开了一角。大家转头一查就发现,DiT并不是OpenAI的新发明,它来自伯克利和Google在2023年发的一篇论文《Scalable Diffusion Models with Transformers》。Sora真正做的事,是把DiT从图像搬到了视频,并在前面加上了视频压缩网络和时空patch。更关键的是,这套组合拳很快在开源社区里被反复验证——从Latte到Open-Sora,从CogVideoX到后来的各家视频模型,几乎都在按同一个剧本走:用扩散模型做生成、用Transformer做主干、再在前面套一个时空VAE。

这篇文章就想把这个"剧本"从头到尾拆一遍,聊聊为什么偏偏是DiT、它的核心骨架长什么样、以及我在实际训练和复现过程中踩过的那些坑。

1. Sora掀桌那一夜:让整个视频生成圈失眠的其实是一页技术报告

1.1 技术报告里真正有料的那几段

OpenAI这份视频生成模型技术报告的标题叫《Video generation models as world simulators》,翻译过来是"把视频生成模型当作世界模拟器"。比起标题这个野心,正文反而很克制,讲清楚了三个东西:视频压缩网络、时空patch、以及扩散Transformer。

很多人对Sora的误解是"它发明了一种新模型",实际上不是。报告明确指出,模型是Diffusion Transformer,稀疏的patch作为token输入,训练时先对视频做时空压缩,再在低维空间里做denoising。换句话说,扩散模型负责生成,Transformer负责建模patch之间的关系,视频压缩网络负责把高维像素变成低维token。这三层各干各的,边界非常清楚。

技术报告里还有一句很容易被忽略的话:他们用重新标注(re-captioning)的方式为所有训练视频生成了详细字幕。这和DALL·E 3的图像重标注思路一脉相承。后来大量实验也证明,视频生成质量的上限很大程度取决于训练数据里的文本质量和粒度。你喂给模型的字幕如果只是"一个人在走路",那模型学到的就是"一个人在走路"的模糊先验;如果字幕是"身穿红色风衣的女人在雨后东京街头行走,霓虹灯光映照在湿润的柏油路上",模型才能把画面细节和文本细节对齐。

1.2 为什么说"所有视频模型都在抄同一个剧本"不是夸张

"Sora之后大家都在抄DiT"这句话,不是社区里的一句玩笑,而是过去一年多开源项目的真实走向。我列几个有代表性的动作:

  • Latte在2024年初挂到arXiv上,标题就叫Video Diffusion Transformers,结构上比Sora更接近"DiT原版",直接对3D patch做token化。
  • Open-Sora最初一版比较粗糙,但到了1.2版本,已经完整采用了时空DiT(ST-DiT)加因果视频VAE的组合,明摆着往Sora的框架上靠。
  • CogVideoX开源时,用的是3D因果VAE加DiT,支持长时间视频生成。
  • 国内外的商业视频模型,包括Wan、HunyuanVideo,以及大量闭源方案,公开的技术分享里也都能看到DiT的身影。

为什么大家愿意抄同一个剧本?因为DiT这套组合是目前权衡效果、算力、工程复杂度之后最稳的答案。U-Net在图像领域很强,但放到"长视频+复杂运动+文本条件"的尺度下,它的卷积归纳偏置反而成了限制。Transformer没有那么多先验限制,给它更多数据和算力,它就还你更强的生成能力。这种可扩展性,正是大模型时代最稀缺的品质。

2. 先搞清楚两件事:扩散模型在做什么,Transformer又能补什么

2.1 扩散模型的本质:从噪点里一层层"修"出视频

要理解DiT为什么成立,得先把扩散模型这层皮剥开。扩散模型做生成,可以理解成从一块纯噪点的画布里,一点点"雕刻"出图像或视频。训练时,我们给真实视频加上越来越多的高斯噪声,直到它彻底变成一片雪花;然后让模型学反过程:给定一个加了噪的中间状态,预测"刚才加进去的噪声长什么样"。

推理时,模型拿一块纯随机噪声出发,反复预测噪声并剥离,每剥一次,画面就清晰一点。这个反复迭代的过程,本质上是在估计一个概率分布的得分函数(score function),也就是朝着高概率密度区域走的方向。你把它想成在满是雾气的山谷里下山,每一步都朝着坡度最陡的方向走,最后总能走到谷底最像真实数据的地方。

扩散模型发展到今天,经历了从像素空间扩散到隐空间扩散的关键变化。隐空间扩散就是先把真实的视频帧用VAE压缩成更小的latent,在这个latent空间里去加噪、去噪。好处是计算量大幅下降,模型可以把算力集中到更抽象的时间建模和语义建模上。Sora所用的路径就是这个,DiT运行在视频压缩网络输出的latent序列上,而不是原始像素上。

2.2 为什么视频生成比图像更依赖Transformer的全局视野

图像生成时代,U-Net已经够用了,但视频生成有一个图像领域没那么突出的问题:长距离依赖和时间一致性。一个视频里,第1帧的一只猫和第30帧的一只猫应该是同一只,动作要连贯,光线要一致,甚至连远处广告牌上的字都不能乱闪。

U-Net的卷积结构天然擅长捕捉局部纹理,但要让信息从画面的左上角传到右下角,或者从第1帧传到第30帧,需要非常深的层级和不断的下采样/上采样。视频信号里这种"跨时间、跨空间"的依赖密度实在太高了,U-Net处理起来越来越吃力。

Transformer的注意力机制则完全相反。它在计算某个patch的表示时,可以一次性"看到"序列里的所有其他patch,不管它们离自己多远。这种全局感受野对视频生成几乎是量身定做的:要保证前后帧物体一致,注意力可以直接把当前patch和几十帧之前的patch关联起来。用大白话说,U-Net是"各管各的片区,有事逐级上报",Transformer是"所有片区代表拉一个全员大会,每件事当场对齐"。

2.3 两者合体后的DiT到底改了什么

DiT论文做的事,说白了就是把扩散模型中原本最耗算力的U-Net主干替换成了Transformer,其他扩散流程基本不变。论文在ImageNet上做了一组非常干净的对比实验,得到的结论是:在相同的训练算力下,DiT不仅效果追平甚至超过了U-Net,而且计算复杂度随模型规模和token数量上升得更平滑。

U-Net的优势是参数效率高,因为它给网络强加了大量的空间局部性先验;但这个先验在复杂场景里也是枷锁。DiT放弃这些先验,换来的是更强的expressiveness和可扩展性。我把核心区别整理成一张表,方便你对照着看:

维度U-Net类架构DiT类架构
感受野局部卷积累积,需深层堆叠注意力直接全序列可见
条件注入多为cross-attention或AdaINAdaLN-Zero,统一由MLP调制
扩展性加大模型收益边际递减明显接近Scaling Law,算力可换效果
视频时间建模3D卷积+光流等复杂设计时间维与空间维统一token化
工程实现卷积算子成熟稳定Attention并行度高,适配大集群

DiT真正的贡献,是把"扩散生成"和"大模型框架"这两个原本属于不同社区的东西焊在了一起。一旦焊上,后面很多大模型时代的工程技巧——混合精度训练、序列并行、分布式推理、权重微调——都可以直接复用到视频生成上,这也就是它"剧本"魅力的来源。

3. DiT骨架解剖:一个能跑通的Patchify-Adapter-VAE链路

3.1 从像素到token的第一公里:patchify和位置编码

DiT处理图像时,第一步叫patchify:把一张H×W的图切成一堆大小为p×p的小块,每个小块线性投影成一个向量。这其实和ViT的做法很像。这个操作的意义在于,把连续像素压缩成离散的token序列,让后面的Transformer不用面对几百万像素点的超长序列。

到了视频场景,patch就多了一个时间维度。典型做法是切出时空patch,比如时间上取1帧,空间上取2×2像素,这样一个patch覆盖的是"一帧里的一个小区域",得到的token序列长度和视频时长成正比。假设一个视频被VAE压缩后latent维度是T×H×W,patch size是(1,2,2),那token数量就是T×(H/2)×(W/2)。这个数字直接影响计算量:注意力复杂度是token数的平方,所以视频越长时间越长,DiT的计算消耗越吓人。

位置编码在这条链路里容易被低估。图像DiT通常给每个patch加一个可学习的位置向量,视频版不能直接照搬,因为视频的时长在训练和推理时是变化的。现在更通用的是RoPE这类旋转位置编码,或者把位置编码归一化到[-1,1]再插值,保证模型在训练分辨率之外也能外推。Sora能生成不同宽高比的视频,靠的就是这类设计带来的自由度。

3.2 把文字和帧数喂进Transformer:AdaLN-Zero的条件注入

DiT和普通ViT最大的区别在于它必须把"条件"融进网络里。生成视频时,我们给模型的条件通常是文本提示("一只猫在沙发上打滚")和时间步t(当前去噪步在第几步)。怎么把这两个条件高效送进去,直接影响生成质量。

DiT论文实验了几种方式:concat、cross-attention、AdaLN、AdaLN-Zero。测试结果最优的是AdaLN-Zero。这个方案里,模型不再把条件拼在token后面,而是让条件embedding过一个MLP,输出三组向量:scale、shift、gate。这三组向量分别用来缩放Transformer block里LayerNorm的输出、平移它、以及控制这个block的输出权重。

更有意思的是它的初始化:论文把每个block里输出scale/shift/gate的那个线性层权重初始化为全零。这样一来,网络刚初始化时每个block都退化成近似恒等映射,整个DiT在初始阶段相当于一个很浅的网络,训练稳定性大幅提高。这是一个细节,但很多复现者漏掉它之后发现训练特别容易崩。

我在纸上给你写一个简化的骨架,方便理解数据流:

class DiTBlock(nn.Module): def __init__(self, hidden_size, num_heads, cond_dim): super().__init__() self.norm1 = nn.LayerNorm(hidden_size) self.attn = nn.MultiheadAttention(hidden_size, num_heads, batch_first=True) self.norm2 = nn.LayerNorm(hidden_size) self.mlp = nn.Sequential( nn.Linear(hidden_size, hidden_size * 4), nn.GELU(), nn.Linear(hidden_size * 4, hidden_size), ) # AdaLN-Zero: 条件向量 -> 6组调制参数(scale/gate/shift 各两组) self.adaLN = nn.Sequential( nn.Linear(cond_dim, hidden_size), nn.SiLU(), nn.Linear(hidden_size, 6 * hidden_size), # 偏置通常置零初始化 ) def forward(self, x, cond_emb): shift_1, scale_1, gate_1, shift_2, scale_2, gate_2 = \ self.adaLN(cond_emb).chunk(6, dim=-1) x = x + gate_1.unsqueeze(1) * self.attn(self.norm1(x) * (1 + scale_1.unsqueeze(1)) + shift_1.unsqueeze(1)) x = x + gate_2.unsqueeze(1) * self.mlp(self.norm2(x) * (1 + scale_2.unsqueeze(1)) + shift_2.unsqueeze(1)) return x

实际工程里,时间步t的embedding和文本条件一般各自过一个编码器,再逐层注入到每个DiTBlock里。这个结构从图像搬到视频时几乎不需要改动,只要把注意力改成同时覆盖空间和时间维度的注意力,block骨架可以原样沿用。

3.3 视频版DiT的空间时间两把刀:Spatial-Temporal Attention

图像DiT的注意力只处理空间位置之间的关系,视频DiT多了一个时间轴,怎么处理这个多出来的维度,有几种思路。

最简单的是factorized attention,也就是把视频DiT的注意力拆成空间注意力和时间注意力两次操作。先让同一帧内不同空间patch互相看,再让同一个空间位置的不同时间patch互相看。这种拆分的优势是计算量明显小于全局3D注意力,缺点是时间维度只能通过"同一个位置"传递信息,跨位置的长时间运动依赖可能要绕路。

更彻底的是full 3D attention,把所有时空patch放在一个序列里做全局注意力。表达能力最强,但token数量一多,显存和计算量直接爆炸。Open-Sora的ST-DiT实际上采用了类似factorized的思路,把attention拆成了空间部分和时间部分,同时保留了部分全局信息交互。实践下来,这种拆法在效果和成本之间取得了不错的平衡。

不管用哪种注意力,你都要给模型提供时间位置信息,否则它分不清第2帧和第20帧谁先谁后,生成出来的动作时序就是乱的。工程上常见做法是给时间维加RoPE,或者直接把帧索引编码进条件向量里。别小看这一小步,我见过不少初版实验迭代很久效果一直不好,最后发现时间位置编码根本没加对。

4. 没有代码的Sora怎么追:开源圈复现DiT视频模型的路线图

4.1 从DiT到Latte:中间隔着一个视频token化的难题

DiT论文发布之后,很多人第一时间就想过把它搬到视频上。但要照搬,中间卡着一个绕不开的问题:视频比图像多一个时间轴,如果直接把每一帧都当图像patch喂进Transformer,序列长度会膨胀到完全没法训练。

Latte这篇工作就处在这样一个节点上。它的做法是先用一个VAE把视频映射到隐空间,再做3D patch tokenization,然后交给DiT block处理。在projection阶段,Latte尝试了几种不同的patch embedding方式,比如先做空间token化再做时间合并,以及直接3D卷积token化,结论是让时间信息在token化阶段就参与进来,效果比"先逐帧图像化再合并"好。这个结论后来被很多视频DiT项目采纳,基本成了默认操作。

4.2 Open-Sora的三步棋:用开源复现验证"DiT通用剧本"

Open-Sora是OpenMMLab和HPC-AI Tech社区一起推的项目,目标很直接:用开源方式复现Sora的能力,并且把每一步都开源出来。

Open-Sora 1.0相对粗糙,更像是一个"先把训练链路跑通"的验证。但到了1.2版本,架构已经非常完整:CausalVideoVAE负责时空压缩,ST-DiT负责生成,再配合一个文本编码器把提示词映射成条件向量。我印象里1.2分支出来后,社区很快用它做了一批"一句话生成视频"的 demo,质量虽然和Sora差距还很大,但最小可行的DiT视频链路已经完整闭环了。

Open-Sora给后来者最重要的贡献,倒不是某一个架构创新,而是把"数据清洗、视频VAE训练、DiT训练、文本对齐"这条长链路的工程细节摊开了。你去看它的代码和配置,能学到很多sora doc里不会写的实操:视频如何抽帧、如何按运动分数筛选片段、VAE训练时的因果卷积pad方向、DiT训练时的图像视频混合比例、推理时的classifier-free guidance scale。这些经验,恰恰是闭源报告和论文里最容易缺失的部分。

4.3 Sora没写进报告的三个细节:视频压缩网络、重标注与可变分辨率

我在复现和参考开源实现时,反复琢磨过Sora技术报告里没写透的三个点,这里分享下我的推测和验证思路。

第一个是视频压缩网络的具体设计。Sora说它用了一个视频压缩网络把时空维度都压下来,但没说压多少、用什么结构。开源社区从生成效果反推,比较合理的估计是空间每维压缩8倍、时间压缩4倍量级。CausalVideoVAE这类做法的目的很清晰:只有把视频压缩到足够小的latent,后面的DiT才跑得动;但压缩太狠会丢细节,生成视频容易出现"水彩糊"质感。这个度要自己实验拿捏。

第二个是re-captioning的价值。Sora强调会给训练视频重新生成详细字幕,这个动作看起来不起眼,实操里影响巨大。我用中文视频数据训练时对比过:一组用原始模糊标签,另一组用多模态模型重新打标。同样的模型结构、同样的算力,重标注那组的生成质量明显更稳定,尤其是指令跟随能力——你说"雨夜霓虹灯下的街道",它能真的给到对应氛围。文本和视频在训练数据里没有对齐,后面再怎么调损失函数都是白费。

第三个是可变分辨率。DiT的位置编码可以做到训练分辨率之外的外推,这让模型不用把视频强行缩放到固定尺寸,原生宽高比得以保留。实现起来不算难,但要在训练时刻意混入不同分辨率、不同时长的样本,模型才能真正学会。很多复现项目不舍得在数据多样性上花钱,结果生成固定分辨率还可以,一换长宽比就开始崩。

5. DiT视频训练实战:从数据管线到Loss调试的硬碰硬

5.1 数据管线:把MP4变成3D latent token的全过程

如果只是看图或读论文,很容易以为DiT视频训练就是"准备一个视频数据集,然后开训"。真上手才发现,最花时间的往往是数据管线。

我的标准流程大致是这样:先用ffmpeg抽帧,按固定fps抽成帧序列,再做一轮帧质量过滤,模糊的、纯色的、带水印的扔掉。然后是运动筛选:完全静止的监控画面或镜头毫无变化的访谈视频,对生成模型几乎没帮助,通常会把运动分数太低且太长的片段切掉。视频进VAE前,还要做分辨率适配和时序切段,比如一段60秒的素材会被切成多个时长一致的clip。

之后才是关键步骤:把视频clip交给预训练的video VAE编码成latent。这一步的输出是一堆3D latent张量,存储下来供训练时读取。它的质量直接决定训练上限:VAE重建得不好,DiT生成得再好也只是在"重放模糊"。严格说,视频VAE需要单独训练和验收,别指望拿图像VAE直接替代,时间维度的压缩和因果性它处理不了。

这里我放一张我平时训练用的超参参考表,具体的数值会随数据和算力浮动,但可以作为起步配置:

超参数常用范围备注
Learning Rate1e-4到2e-4,配合warmupDiT比U-Net更吃LR,过高容易中期崩
Batch Size尽量大,至少等价32张图视频样本大,注意用gradient accumulation
Precisionbf16优先fp16在视频训练里溢出风险更高
AdamW betas(0.9, 0.999)常规
Guidance Scale推理时7到10训练时记得带10%的空条件
EMA Decay0.9999视频生成强烈建议开EMA
Video-Image Ratio视频:图像=7:3或8:2混入图像样本稳定训练

5.2 显存、算力与收敛的三角博弈

视频DiT的显存压力比图像DiT高一个量级。每次前传,你要在内存里同时装着t个帧的latent、注意力矩阵和梯度。一条4秒、256分辨率、30fps的短视频,在latent空间可能也要上千个token。这时候几个常用的缓解手段是:gradient checkpointing(用计算换显存)、序列切分给多卡、以及把时间和空间注意力分开算。这些都该在写训练代码时就预留好,别等OOM了再重构。

算力分配的优先级也值得聊。我个人的感受是,视频DiT训练中,数据能力比模型规模更容易成为瓶颈。小算力情况下,与其堆一个巨大的DiT,不如把卡集中起来处理更高清、更多样的数据,效果反而提升快。模型的scaling law只有在你数据管线稳定之后才有意义,否则就是拿算力放大了数据的缺陷。

收敛判断也别只盯训练loss。扩散模型的loss掉到一定程度后视觉上还在明显变化,更好的监控方式是在固定步数做一次评测生成,用肉眼和简单指标(FVD、CLIP score)综合判断。而且视频模型在不同时间步上的判别力天差地别,sampling时的step数和noise schedule选择对最终画质影响很大,值得单独做小网格搜索。

5.3 踩过的坑:闪烁、南ID漂移和诡异NaN

训练过程中最常遇到的坑有三个:

第一个是生成视频闪烁。画面单帧看还行,连起来看像老式荧光灯在闪。根因多数出在视频VAE的时间压缩不够,或者DiT的时间注意力没训起来。排查方法是先看VAE重建一段真实视频会不会闪,会闪就是VAE的问题,不会闪再怀疑DiT的时间建模。如果DiT这边的问题,试试加强时间位置编码、增大时间注意力的权重,或者把p_t从1改成4,逼模型一次性看更多帧。

第二个是同一视频里物体身份漂移。比如一只狗走到一半毛色变了。这种问题往往不是模型结构错,而是训练数据里时间一致性不够——如果数据管线切段切得太碎,模型根本学不到"同一个物体在连续帧里要保持同一外观"的强先验。解决办法是训练时加入更长片段、降低augmentation强度(尤其是颜色抖动),同时检查VAE是否对每一帧独立编码导致latent间不连续。

第三个是训练中后期突然出现NaN。遇到过几次,基本都和fp16的梯度溢出有关,切到bf16能缓解;另外学习率过高在扩散模型里也会触发loss爆炸。一个可行的急救包:降低LR、加梯度裁剪、回到EMA权重重新评估,通常能救回训练。

我把这些问题整理成一张排查表:

症状最可能原因优先排查动作
生成闪烁VAE时间压缩不足 / 时间注意力弱单独测VAE重建;调整patch时间跨度
物体身份漂移数据/VAE跨帧不一致清洗长片段;降低帧级强增强
NaN / loss暴涨fp16溢出 / LR过高切bf16;梯度裁剪;砍LR
指令跟随差字幕粒度不够对训练视频统一re-caption
长视频后段质量崩位置编码外推失效换RoPE;训练中混入长样本

6. 剧本还没写完:DiT的下一代正在长出来

6.1 MMDiT:当图像和文字在同一张桌子里开会

DiT本身默认是把文本条件通过AdaLN-Zero注入进去,文本不参与token序列的正面对话。到了SD3和Flux这一代,出现了MMDiT,也就是多模态DiT。它把文本token和图像token拼接在同一个序列里,一起进Transformer做注意力,文本和图像不是"条件与生成目标"的关系,而是"同桌开会的两个代表"。

这个变化对视频生成也有参考价值。视频生成同样需要强文本条件,如果文本只是注入scale/shift,它对token细节的影响是间接的;如果文本token能直接attend到视频patch,指令跟随能力和语义对齐会更强。现在不少新的视频DiT已经在往这个方向调整了。

6.2 Mamba和线性注意力:向平方复杂度开刀

DiT的Achilles heel是注意力机制的平方复杂度。视频token一多,这个平方项就是天价。社区里已经有不少工作在尝试用Mamba这类选择性状态空间模型替换注意力,或者把注意力和Mamba混合起来。Mamba的推理是线性复杂度的,理论上可以支持更长的视频和更高分辨率,但在长距离细节保持上,它暂时还没完全追平注意力。

另一个方向是线性注意力、flash attention等工程优化。即使架构不变,注意力算子的优化空间也还很大。我对这个方向的判断是:视频模型未来不太可能完全抛弃注意力,更可能走"混合内核"路线——关键位置用注意力,长序列快速通道用线性算子,两者搭配。

6.3 更大的变量:自回归路径与视频世界模型

扩散模型虽然在视频生成里坐稳了王座,但自回归路径一直没有放弃追赶。图像领域有VAR把自回归和连续值结合,视频领域也在试探把词表式的token预测用于视频帧生成。这类路线的优势是生成过程更接近大语言模型,可以复用成熟的序列建模和推理基础设施,但量化误差和累积漂移的问题还比较明显。

Sora那份报告把视频生成定义为"世界模拟器",这个说法比"视频生成"野心大得多。世界模型要求模型不光会补帧,还要理解物理规律、因果链条、交互反馈。DiT这代架构更多在做"基于先验的逼真合成",还没有真正做到"基于物理的推演"。下一代的架构,很可能是DiT提供的强生成能力加上某种显式的世界状态表征。

说回我自己的习惯。现在不管是自己上手试新项目,还是帮团队评估一个视频生成方案,我第一件事都是先拆开看它的架构属于哪个流派:是不是扩散打底、是不是Transformer主干、前面挂的是不是因果视频VAE。如果是,那不管它宣传语包装得多新鲜,本质都还是在DiT这个剧本上做局部优化。这不是坏事,反而说明DiT这个框架足够结实,值得你在上面深耕;但如果你想找真正的结构突破,就要盯紧MMDiT、Mamba混合和自回归路径这几个变量,它们才是下一幕的主角。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询