
简介一份来自北京大学深圳研究生院的学术分享PPT围绕‘生成未必理解’这一核心命题系统梳理扩散模型在视觉生成中的能力边界及其与视觉理解模型的关系。内容涵盖扩散模型与GAN的图像合成对比以及Latent Diffusion、DDIM、LDM、PixArt-α等代表性技术演进并通过灰狼幼崽数量变化、杯子碎裂、跑步机反向奔跑等Prompt案例揭示当前模型在复杂场景逻辑一致性上的局限。资源还比较了视觉生成模型与理解模型在参数规模上的差异并探讨了生成与理解两条路径是否完全割裂以及统一多模态世界模型的可能方向。资源共1个PPTX文件压缩包大小约10.05MB内容精炼但前沿信息集中适合关注大模型、视觉生成与多模态理解的研究者快速把握关键观点。已有98人学习对于想要理解扩散模型作为视觉世界模型可行性与局限的人而言是一份兼具学术深度和思辨价值的参考资料。1. 从会画到能预测扩散模型与视觉世界模型的边界在哪生成未必理解这句话在扩散模型身上格外扎眼。今天扩散模型渲染出的图像和视频已经能让普通观众难辨真假但会生成和会理解从来不是一回事。视觉世界模型的目标与图像生成不同它要学习的是环境的状态转移规律给定当前观测和动作模型得在脑子里推演出下一步会发生什么再把这些想象用于规划。扩散模型天然擅长输出高保真未来帧又容易接受条件控制于是很多人把它当作视觉世界模型的实现底座。问题也随之而来扩散模型学会的是训练数据里的概率关系还是真正掌握了物体运动和交互的规律这篇文章我用 PyTorch 搭一个最小的扩散世界模型讨论训练、评估和踩坑重点把生成和理解分开验证。适合正在做视频预测、具身智能和预训练模型的工程师。2. 扩散模型的生成机理为什么它看起来像世界模型2.1 扩散模型的去噪过程与视觉世界模型的前向动态扩散模型模仿的是热力学中的扩散过程。前向过程逐步向真实样本加噪直到变成纯高斯噪声反向过程学习从噪声恢复原始样本。视觉世界模型要做的事情相似给定 t 时刻的状态预测 t1 时刻的状态。如果把状态序列看成连续帧那么扩散模型去噪的一步就是在条件约束下从噪声中重构出一个处在正确位置的下一帧。常见做法是用重参数化生成带噪样本训练时不需要真正跑完整个马尔可夫链。代码里通常先预计算噪声系数 alpha_bardef q_sample(x0, t, noise, alpha_bar): # 前向加噪从真实帧 x0 出发按 alpha_bar 插值出带噪帧 b alpha_bar[t].view(-1, 1, 1, 1) return torch.sqrt(b) * x0 torch.sqrt(1 - b) * noisex0 是真实视频帧批次t 是随机采样的扩散时间步alpha_bar 是每个时间步的累积保留比例noise 是标准高斯噪声。这个函数只用于构造训练目标模型反过去预测 noise 或 x0。因为 alpha_bar 越靠近 t0 越接近 1带噪帧与原帧越接近越靠近 tT 则噪声占比越高。这个思路和世界模型的区别在于扩散模型预测的是数据流形上的位置而世界模型需要预测从当前位置出发的动态变化。很多初做视频预测的人认为去噪过程就是动态预测其实去噪只回答了什么样的下一帧看起来真实并没有回答为什么下一帧会是这样。所以训练之前要明确扩散世界模型必须把动作和历史状态作为条件输入否则它只是一个高保真视频生成器。2.2 潜在扩散模型与数据流形扩散模型和 Manifold 的关系潜在扩散模型LDM先通过 VAE 把像素空间压缩到潜在空间再把扩散过程放在潜在表示上执行。这样做不只节省显存还暗含了一个关键假设自然图像和视频分布在潜在空间中的一个低维流形上扩散模型学习的正是这个流形的概率密度结构。扩散模型和 Manifold 的关系可以从得分匹配的角度理解模型估计的是对数概率密度的梯度也就是从任意噪声点指向数据流形的方向。去噪过程本质上是在流形上做一个收敛移动。对于视觉世界模型来说这个性质很有吸引力因为视频序列中单帧的画面通常落在一个比较光滑的流形上模型不会轻易生成不可能的像素组合。流形视角也揭示了生成未必理解的根源。扩散模型只在流形上做插值和采样它没有时间变量的显式概念。对模型来说未来帧和过去帧的关系只是条件分布 p(x_{t1}|x_t,a) 中的统计依赖而不是力学方程。一旦遇到训练中没见过的边界条件比如物体碰撞后的反弹角度模型会选择一个看起来还在流形上的结果而不是符合物理直觉的结果。这也是后面做行为验证时最容易暴露的问题。2.3 条件扩散模型动作条件和状态转移的嵌入方式要让扩散模型成为世界模型动作条件不能只是拼在输入端需要让动作和观测在同一个中间表示上发生交互。最基本的做法是把动作向量通过 MLP 嵌入然后与时间步嵌入拼在一起注入 UNet 的每个 block。更可靠的做法是用交叉注意力让动作以 Query 形式关注视频特征。我一般会先用最轻量的拼接方式验证数据流程再升级为交叉注意力。下面是一个简化版条件注入def inject_condition(x, act_emb): # x: [B, C, H, W]act_emb: [B, D] act_feat act_emb[:, :, None, None].expand(-1, -1, x.size(2), x.size(3)) return torch.cat([x, act_feat], dim1)act_emb 由动作的 one-hot 或连续向量过两层 MLP 得到D 通常设为 64 或 128。expand 操作把动作特征复制到每个空间位置让卷积层在空间的每一处都能看到动作信息。这样设置会让动作对图像所有区域施加相同的影响对全局控制足够但无法表达动作只影响屏幕左侧的小球这类空间局部交互。三种常见条件注入方式对比如下。条件机制实现方式优点局限特征拼接通道维拼接实现简单训练稳定空间上无区分能力FiLM按通道缩放与偏移适合全局风格调整对局部交互不敏感交叉注意力Q 来自动作K/V 来自视觉特征可以建立空间对应关系显存消耗高收敛慢如果任务里物体位置和动作有空间关系我会直接选择交叉注意力。在这条路上扩散模型才能从根据历史猜未来慢慢变成根据指令推未来。3. 构建一个可复现的最小视觉世界模型从 PyTorch 开始3.1 数据与任务设计用仿真环境生成短序列真实视频数据带有相机运动、光照变化和传感器噪声会干扰对世界模型因果能力的评估。第一版我会用几十行代码生成一个弹球视频数据集一个圆球在矩形平面内发生弹性碰撞动作表示外力方向目标是根据前几帧预测未来若干帧。这类数据保留了运动学规律又足够简单方便观察模型到底有没有理解碰撞边界。这里用 numpy 生成弹球轨迹然后渲染成视频帧def gen_bounce_frames(num_frames32, img_size64): pos np.array([16.0, 16.0]) vel np.array([1.8, 1.2]) radius 4 frames [] for _ in range(num_frames): img np.zeros((img_size, img_size), dtypenp.float32) yy, xx np.mgrid[0:img_size, 0:img_size] mask (xx - pos[0])**2 (yy - pos[1])**2 radius**2 img[mask] 1.0 frames.append(img[None, ...]) # 单通道 pos pos vel if pos[0] radius or pos[0] img_size - radius: vel[0] -vel[0] if pos[1] radius or pos[1] img_size - radius: vel[1] -vel[1] return np.stack(frames, axis0)pos 是球心位置vel 是每帧的移动步长radius 是像素半径。碰到边界时对应轴速度取反模拟弹性碰撞。生成的数据形状是[T, 1, H, W]即帧数、通道、高、宽。这个设计的重点是让模型面对明确的物理规则球的运动由初速度和边界反弹决定。如果扩散世界模型只能记住球运动的大致轨迹而不知道反弹条件那么在边界附近生成的下一帧就会穿模或者消失。这个数据生成过程可以随时扩展成多球、变半径和随机重力用来做更细的物理一致性测试。3.2 模型结构与参数表用 UNet 做条件扩散扩散世界模型的核心网络使用标准的 2D UNet输入是带噪的下一帧条件包括上一帧、动作向量和时间步。上一帧和带噪帧在通道维拼接动作向量按前面提到的方式注入时间步用 Sinusoidal 嵌入加到 UNet 每个 block 中。模型规模不需要大关键是参数要能配合短序列训练。我常用的设置如下。参数值说明输入帧数1 帧用上一帧做条件通道数2带噪帧 上一帧动作维度4上下左右 one-hotUNet 基础通道32每层通道数时间步数500扩散步数噪声调度cosine比线性调度更稳定优化器AdamW学习率 1e-4Batch size32显存不够可调 16时间步数不用太大短序列数据 500 步已经够用。cosine 噪声调度在高分辨率生成时会避免过早进入纯噪声区对小球这种低维数据同样有效。3.3 训练循环的实现细节训练时每次从序列中随机采样一个时间索引取前一帧作为条件当前帧作为目标然后对当前帧加噪并让模型预测噪声。损失只计算噪声的均方误差。for step, (cond_frame, x0, action, t) in enumerate(loader): noise torch.randn_like(x0) x_noisy q_sample(x0, t, noise, alpha_bar) noise_pred model(x_noisy, t, cond_frame, action) loss nn.functional.mse_loss(noise_pred, noise) optimizer.zero_grad() loss.backward() optimizer.step()cond_frame 是 t 时刻的观测x0 是 t1 时刻的真实帧action 是在这一次状态转移期间施加的动作t 是随机采样的扩散步。模型输入为带噪帧 x_noisy输出与 noise 同形状目标是逼真还原加噪用的噪声。用 MSE 是因为得分匹配的最优解就是条件期望噪声。训练初期要确认 loss 曲线确实从较高值下降不要因为数据简单就跳过观察。如果 loss 在几十步内不下降优先检查 alpha_bar 的数值范围以及 cond_frame 是否和 x0 对齐。很多人把 cond_frame 当成无条件输入结果模型只学会了复制输入帧这是最常见的问题。视频数据的内存开销随序列长度线性增长一个 64x64 的 32 帧样本就会占据大量显存。如果训练时 OOM可以把序列切短或者只取未来 4 帧做预测不要一次把 32 帧全塞进 UNet。4. 评估生成未必理解怎么知道模型真的是视觉世界模型4.1 常规生成指标不够用FVD、PSNR 和 LPIPS 的局限做视频生成的同行习惯用 FVDFréchet Video Distance或者 PSNR、SSIM、LPIPS 来给模型打分。但这类指标衡量的是生成帧与真实帧在特征空间的距离不是生成帧是否符合物理规则。一个模型只要记忆了训练集中出现过的球位置也能在 FVD 上拿到好分数但当你给出一个训练集之外的初始速度时它可能完全预测错反弹点。下表给出常用指标对视觉世界模型的诊断能力。指标衡量内容对理解的诊断能力PSNR / SSIM像素级相似度弱对模糊和偏移敏感LPIPS感知特征距离中等能反映结构差异FVD视频分布距离弱擅长判断风格和分布动作条件准确性生成结果是否随动作变化强直接反映条件建模能力物理一致性物体是否碰撞、穿模、消失强直接反映因果规律我建议在论文里先报 FVD 和 PSNR再单独做物理一致性测试。否则很容易出现生成画面非常漂亮、但球的运动轨迹完全违反动量守恒的情况。视觉世界模型的评价核心应该放在测试分布之外的泛化能力上而不是训练分布内的重建精度。4.2 行为层面验证物理一致性最直接的行为验证是检测生成帧中物体的位置看它是否满足已知的物理约束。以弹球数据为例球在边界内运动半径不会变化位置不会瞬移。下面这段代码从生成视频里提取球的质心并检查是否越界def check_ball_trajectory(frames, img_size64, radius4): # frames: [T, 1, H, W]灰度图 invalid [] for t in range(len(frames)): frame frames[t][0] ys, xs np.where(frame 0.5) if len(xs) 0: invalid.append(t) continue cx, cy np.mean(xs), np.mean(ys) if cx - radius 0 or cx radius img_size: invalid.append(t) if cy - radius 0 or cy radius img_size: invalid.append(t) return invalid如果 invalid 列表非空说明模型在圆球运动到边界时要么产生了穿模要么漏画了球。还要看相邻帧质心位移是否连续如果某两帧中心位置发生突变那模型就不是在推演运动而是在拼接不同时间步的图像。你可以把相邻帧质心差超过 3 个像素的位置标记出来再看这些位置是否对应碰撞时刻。4.3 分布外测试把生成和理解彻底分开分布外测试是检验理解力的关键。训练时把初始速度固定在 1.8 和 1.2测试时改用 2.5 和 0.8或者把球半径从 4 改为 6。如果模型是记住了训练分布那么分布外生成结果会迅速变形如果模型真的学到了碰撞规则正确率会保持稳定。实现上只需要生成新的验证集保持训练代码不变def gen_ood_frames(speed_x2.5, speed_y0.8, radius6): # 与 gen_bounce_frames 逻辑相同仅替换初始条件 return gen_bounce_frames(num_frames64, img_size64)用全部测试视频逐帧计算异常碰撞比例。我一般会画一张曲线横轴是扩散采样步数或推理窗口长度纵轴是物理违规率。如果违规率随预测步长快速上升说明模型只是在做单步状态复制累积起来就崩溃了。这个指标比 FVD 对世界模型的质量更敏感。5. 让扩散世界模型更接近理解的三个可执行技巧5.1 技巧一先解耦前景和背景世界模型中大部分像素的变化其实是背景静止不变的让去噪网络同时处理背景和物体会把大量网络容量浪费在重建静态纹理上。常见做法是用一个浅层背景编码器把背景单独建模扩散模型只负责生成前景 mask 和物体图像。这样模型不需要重新学习背景每一帧长什么样而是把容量集中在物体运动上。5.2 技巧二用自回归窗口切断误差累积单步扩散模型在多步推理时会因为输入帧不准确而产生级联误差。与其让模型一次预测未来 10 帧不如每次只预测第 t1 帧然后把第 t1 帧和真实历史帧一起作为新条件重复生成 t2。推理时可以按步长设置置信区间超过 5 步就让模型退回真实观测重新校准。5.3 技巧三用 classifier-guided 采样引入目标函数理解并不止于预测还要能服务于任务。在采样过程中可以用目标函数例如“球最终落到目标区域”对去噪均值做梯度引导让未来帧满足目标约束。实现时只需要在去噪循环里加一小步with torch.enable_grad(): x.requires_grad_(True) score target_loss(x).backward() x x - guidance_scale * x.gradx 是正在去噪的潜在表示target_loss 是外部目标函数guidance_scale 控制目标约束的强度。这个技巧把世界模型从被动的未来帧生成器改造成面向目标的想象引擎也是扩散模型在规划任务里最有价值的应用方式。遇到目标损失抖动过大时先调小 guidance_scale再考虑用更平滑的感知损失替代像素级损失。本文还有配套的精品资源点击获取