跨模态生成 跨模态生成(cross-modal generation)根据一种模态的输入产生另一种模态的输出:文生图、图生文、文生音频等等。本文件涵盖 DALL-E、Stable Diffusion、无分类器引导(classifier-free guidance)、ControlNet、图像描述生成、文生视频(Sora)以及文生音频。 在本章的第 01–03 节中,你学习了如何表征、对齐和分词不同的模态。现在进入创造性的环节:从一种模态生成另一种模态。跨模态生成是文生图工具、视频合成系统、音乐作曲模型以及图像描述生成背后的引擎。把它想象成教一台机器成为多媒体艺术家——你用文字描述你想要什么,它就画出来、动起来、或者谱写成曲。
跨模态生成(cross-modal generation)根据一种模态的输入产生另一种模态的输出:文生图、图生文、文生音频等等。本文件涵盖 DALL-E、Stable Diffusion、无分类器引导(classifier-free guidance)、ControlNet、图像描述生成、文生视频(Sora)以及文生音频。
在本章的第 01–03 节中,你学习了如何表征、对齐和分词不同的模态。现在进入创造性的环节:从一种模态生成另一种模态。跨模态生成是文生图工具、视频合成系统、音乐作曲模型以及图像描述生成背后的引擎。把它想象成教一台机器成为多媒体艺术家——你用文字描述你想要什么,它就画出来、动起来、或者谱写成曲。
核心思想是条件生成(conditional generation):给定来自模态 A(例如文本)的输入,产生模态 B(例如图像)的输出。形式上,你学习一个模型 p_\theta(y \mid x),其中 x 是条件信号,y 是生成的输出。挑战在于这个条件分布极其复杂、维度极高——一张 512x512 的图像生活在 \mathbb{R}^{786432} 中,而同一段文本提示对应着许多张合理的图像。
DALL-E(Ramesh 等,2021)把图像生成当作一个序列预测问题——与驱动语言模型的范式相同(第 7 章)。关键洞见是:如果你能把图像表示为离散词元(回忆第 03 节的 VQ-VAE),那么生成一张图像就只是逐个生成一串词元。
流水线分两个阶段。首先,一个离散 VAE(discrete VAE,dVAE)把 256x256 的图像压缩成一个 32x32 的离散词元网格,码本为 8192 项,把图像缩减为一个 1024 词元的序列。其次,训练一个transformer 解码器建模 256 个文本词元(BPE 编码)与 1024 个图像词元拼接后的联合分布,共 1280 个词元:
在生成时,你输入文本词元,模型自回归地逐个采样图像词元。这很优雅,因为它把语言建模的现成机制——注意力、因果掩码、top-k 采样——直接复用于图像合成。
缺点是自回归生成本质上是串行的:一个一个地生成 1024 个词元很慢,而且序列早期的任何错误都会累积。DALL-E 通过生成大量候选图像、再用 CLIP(见第 01 节)对它们重排序来缓解这个问题,从中挑出最匹配文本提示的。
Stable Diffusion(Rombach 等,2022)采取了根本不同的方法。它不再一个一个地预测词元,而是从纯噪声开始,在文本提示引导下,逐步把噪声去噪成一张图像。回想第 8 章的扩散模型——Stable Diffusion 在压缩的潜在空间而非像素空间中运作,效率高得多。
架构由三个协同工作的组件构成。一个 VAE 编码器把图像从像素空间(512 \times 512 \times 3)压缩成潜在表示(64 \times 64 \times 4),维度降低 48 倍。一个文本编码器(通常是 CLIP 或 OpenCLIP)把文本提示转换成一串嵌入向量。一个 U-Net 去噪器接收带噪声的潜在表示、时间步和文本嵌入,预测每一步要减去的噪声。文本条件通过**交叉注意力(cross-attention)**进入 U-Net:
其中 Q 来自带噪声的图像特征,K, V 来自文本嵌入。这让模型在每个空间位置关注相关词——当去噪「红球」应该出现的区域时,模型关注「red」和「ball」这两个词元。
在推理时,你在潜在空间采样 z_T \sim \mathcal{N}(0, I),用 U-Net 迭代去噪 T 步(通常配合 DDIM 调度约 20-50 步),再用 VAE 解码器把干净的潜在表示 z_0 解码回像素空间。整个前向传播在消费级 GPU 上几秒钟就能生成一张 512x512 的图像。
其中 s 是引导尺度。可以把 (\epsilon_\theta(x_t, c) - \epsilon_\theta(x_t, \varnothing)) 这一项理解为「朝向提示的方向」——它捕捉的是条件预测与无条件预测的差异。乘以 s > 1 会放大这个方向,把图像推向文本描述,代价是牺牲多样性。
实践中,Stable Diffusion 常用 s = 7.5 作默认值。s = 1.0 时你得到模型的原始输出(多样但与提示贴合较松)。s = 20+ 时图像变得过饱和、重复,但与文本高度一致。最佳 s 取决于应用:创意探索偏好较低的引导,而精确贴合提示则需要较高的引导。
Imagen(Saharia 等,2022)证明了一个强大的文本编码器比更大的图像模型更重要。Imagen 不用 CLIP,而是用一个冻结的 T5-XXL 语言模型(见第 7 章)作文本编码器,它对语言语义、组合性和空间关系(「一个红色球体上面的蓝色立方体」)有丰富得多的理解。
Imagen 采用**级联扩散(cascaded diffusion)**方法:一个基础扩散模型生成 64x64 图像,第一个超分辨率模型放大到 256x256,第二个超分辨率模型达到 1024x1024。每个阶段都是独立的扩散模型,以文本和(对于超分辨率模型)低分辨率图像为条件。这种级联避免了在基础分辨率上建模精细细节,让基础模型专注于构图与语义,而超分辨率模型负责纹理和锐度。
Imagen 还引入了动态阈值(dynamic thresholding):在每个去噪步骤,预测的像素值被裁剪到一个基于百分位的范围,而不是固定范围 [-1, 1]。这防止了高引导尺度下的饱和伪影,这是扩散模型中常见的问题。
Parti(Pathways Autoregressive Text-to-Image,Yu 等,2022)以巨大规模复兴了自回归方法。与 DALL-E 一样,它把图像转成离散词元(用 ViT-VQGAN),并用 transformer 顺序生成。但 Parti 用了一个 200 亿参数的编码器–解码器 transformer(基于 Pathways 架构),并表明当规模足够大时,自回归模型可以匹敌扩散模型的质量。
Parti 的编码器–解码器架构是与 DALL-E 仅解码器设计的关键区别。文本经过编码器;解码器在生成图像词元时对编码后的文本做交叉注意力。这镜像了机器翻译(第 7 章)——你从「文本语言」翻译成「图像语言」。
Diffusion Transformer(DiT,扩散 transformer)(Peebles 和 Xie,2023)用普通的 transformer 替换扩散模型中的 U-Net 骨干。每个带噪声的潜在图块被当作一个词元(类似于第 8 章的 ViT),transformer 通过自注意力和对文本条件的交叉注意力来处理这些词元。DiT 表明,在扩散任务上 transformer 的扩展比 U-Net 更可预测——计算量翻倍,FID 分数可靠地减半。
流匹配(flow matching)(回忆第 8 章)已经成为扩散噪声预测范式之外的替代方案。模型不再预测要减去的噪声 \epsilon,而是预测一个速度 v_\theta(x_t, t),沿直线路径把样本从噪声搬运到数据。Stable Diffusion 3 和 Flux 采用流匹配以及**多模态 DiT(multimodal DiT,MM-DiT)**架构,其中文本和图像词元由带双向注意力的 transformer 块联合处理——两种模态互相关注,而不是文本仅通过交叉注意力给图像特征提供条件。
Make-A-Video(Singer 等,2022)采取了务实的做法:从一个预训练的文生图模型出发,加入时间层。关键洞见是:你已经有在数十亿对图文上训练的强文图模型,你只需要从(无标签的)视频数据中学习运动。
Make-A-Video 在预训练的空间 U-Net 中插入**时间注意力(temporal attention)和时间卷积(temporal convolution)**层。空间层(在图像上预训练)处理外观,新的时间层(在视频上训练)处理运动。空间自注意力在每一帧内运作;时间注意力在每个空间位置上跨帧运作。这种因式分解很高效,因为时间模式与空间模式在很大程度上是可分离的。
生成流水线镜像 Imagen 的级联:基础模型生成 16 帧 64x64,然后空间和时间超分辨率模型放大到最终分辨率和帧率。一个帧插值网络提升时间平滑度。
VideoPoet(Kondratyuk 等,2024)在语言建模范式下统一了视频生成。所有模态——文本、图像、视频、音频——都被分词成离散序列,训练一个大型语言模型(LLM)跨所有模态自回归地预测词元。这带来了零样本能力:文生视频、图生视频、视频生音频、视频编辑和图像修复,都从同一个模型中涌现。
VideoPoet 用 MAGVIT-v2 编码器(一个 3D VQ-VAE,见第 03 节)对视频分词,联合压缩空间和时间维度。音频用 SoundStream 分词。LLM 骨干先在文本上预训练,再在多模态词元序列上微调,学习跨模态的联合分布。
Sora(OpenAI,2024)凭借生成长、连贯、物理上合理的视频的能力,把时间扩散带到了主流视野。虽然完整的架构细节未公开,但关键想法包括把 DiT 扩展到时空:视频帧被分解成时空图块(spacetime patch)(跨高度、宽度和时间的 3D 块),当作大型 transformer 的词元。
时空图块方法意味着模型把视频当作原生 3D 信号处理,而不是 2D 帧的序列。这让它能捕捉长程时间依赖——模型可以跨整段视频「提前规划」,而不是逐帧生成。
通过调整时空图块的数量,Sora 能处理可变时长、分辨率和宽高比。在原始分辨率上训练(而不是把所有内容裁剪成正方形)能提升构图和取景质量。
Wan(Wan 等,2025)是一系列开源视频生成模型(13 亿和 140 亿参数),基于 DiT 骨干和 3D VAE 时间压缩构建。Wan 用流匹配而非传统 DDPM 式扩散,学习从噪声到视频潜在表示的直线传输路径。3D VAE 在空间和时间上压缩视频(4 倍时间压缩),DiT 对得到的时空潜在词元做完整 3D 注意力。
Wan 支持文生视频、图生视频(让静态图像动起来)和视频编辑。140 亿参数的模型能在 720p 分辨率下生成长达 5 秒的连贯视频,证明只要架构和训练配方选择得当,开源模型也能逼近专有系统的质量。
AudioLM(Borsos 等,2023)通过自回归地预测离散音频词元来生成音频,沿用了与 DALL-E 用于图像相同的语言建模范式。它采用层次化的词元结构:语义词元(semantic token)(来自像 w2v-BERT 这样的自监督模型,回忆第 9 章)捕捉高层内容(在说什么或演奏什么),而声学词元(acoustic token)(来自 SoundStream,一种神经音频编解码器)捕捉细粒度的声学细节(听起来如何——音色、录音质量)。
生成分两阶段。首先,一个 transformer 在可选的音频提示条件下预测语义词元,建立高层内容计划。其次,另一个 transformer 在语义词元条件下预测声学词元,填充声学细节。这种层次结构镜像了文本转语音流水线(第 9 章)——语义词元扮演音素的角色,声学词元扮演梅尔频谱帧的角色。
AudioLM 能生成语音续写(给定 3 秒语音,生成接下来 10 秒)、音乐续写和音效,所有这些都来自一个仅在音频数据上训练的单一模型(预训练不需要文本标签)。
MusicLM(Agostinelli 等,2023)把 AudioLM 扩展到文本条件音乐生成。它增加了一个文本–音频联合嵌入(来自 MuLan,一种在音乐–文本对上训练的类 CLIP 模型)来条件化生成。MuLan 嵌入捕捉文本描述的语义含义(「带萨克斯独奏的欢快爵士」),并引导层次化词元生成。
MusicLM 以 24 kHz 生成任意时长的音乐,能在数分钟长的曲目上保持旋律与节奏的连贯性。它还可以在哼唱的旋律(由音高追踪器提取的旋律词元)加上文本描述上做条件,生成一段跟随哼唱旋律、按文本描述风格的完整编排。
MusicGen(Copet 等,2023)简化了多阶段方法。它不再用分开的语义模型和声学模型,而是用一个单一的自回归 transformer,直接从音频编解码器生成多个码本层级。关键创新是交错码本模式(interleaved codebook pattern):它不再先为某个时间步生成所有码本层级再进入下一个时间步,而是把词元在码本和时间步之间交错成一种模式,从而允许某些码本层级并行解码。
条件化很直接:文本由 T5 编码器编码,文本嵌入被前置到音频词元序列之前(就像语言模型中的前缀提示)或通过交叉注意力注入。MusicGen 还支持旋律条件:参考旋律的 chromagram(用第 9 章讨论的频谱图特征)被编码后,与文本条件一起使用。
其中 w_l 是描述的词,I 是图像表示。交叉注意力把文本解码器连接到图像特征,使模型在生成不同词时能「看」图像的不同区域——在生成「dog」时关注狗的区域,在生成「park」时关注公园的区域。
CoCa(Contrastive Captioner,对比式描述器,Yu 等,2022)在一个模型中统一了对比学习(第 01 节的 CLIP 式目标)和描述生成。图像编码器产生的特征既用于与文本的对比对齐,也用于描述解码器中的交叉注意力。这种多任务训练让 CoCa 既具备强大的零样本识别能力(来自对比学习),又具备强大的生成能力(来自描述生成)。
现代方法常用大型多模态模型(第 02 节)来做描述生成。LLaVA、Qwen-VL、GPT-4V 等模型把描述生成当作视觉问答的一个特例——「问题」隐式地是「描述这张图」。视觉编码器(CLIP ViT 或 SigLIP)产生图块词元,投影到 LLM 的嵌入空间,LLM 再生成自由格式的描述。
相比专门的编码器–解码器模型,基于 LLM 的描述生成的优势在于指令跟随(instruction following):你可以要求不同级别的细节(「用一句话描述」vs.「给出详细的一段」)、聚焦特定方面(「描述颜色」),或生成结构化输出(「列出所有物体及其位置」)。这种灵活性来自 LLM 的指令微调(第 7 章)。
核心挑战是时间同步(temporal synchronisation):鼓击的音频必须与鼓棒击鼓的视觉帧完全重合。这需要一种共享的时间表征,两种模态都能引用。
一种方法是从一个共享的潜在时间轴生成视频和音频。像 CoDi(Composable Diffusion,Tang 等,2023)这样的模型为每种模态用独立的扩散模型,但通过一个共享潜在空间对齐它们。训练时,跨模态注意力层在每个时间步学习同步视觉和音频特征。生成时,两个扩散过程同时运行,通过共享对齐互相作为条件。
VideoPoet(上面讨论过)采取了更统一的方法:由于所有模态都被分词成一个单一序列,LLM 自然就学到了视频词元与音频词元之间的时间对应关系。一段吠叫狗的视频片段后面跟着相应的音频词元,教会模型把视觉的吠叫动作与吠叫声关联起来。
**时间对齐损失(temporal alignment loss)**显式地强制同步。一种形式在帧级别用对比学习:时间 t 的音频片段应该比其他时间的帧更接近时间 t 的视频帧:
InstructPix2Pix(Brooks 等,2023)训练一个条件扩散模型,它接收一张输入图像和一条文本指令,然后产生编辑后的图像。巧妙之处在于训练数据的制作方式:GPT-3 生成编辑指令(「把它变成冬天」「把猫变成狗」)配上输入–输出的文本描述,再用一个文生图模型(Stable Diffusion)生成对应的图像对。
模型是一个修改过的 Stable Diffusion U-Net,它同时接收文本指令(通过交叉注意力)和输入图像潜在表示(按通道与带噪声的潜在表示拼接)。它使用双重无分类器引导(dual classifier-free guidance),有两个引导尺度——一个给文本指令(s_T),一个给输入图像(s_I):
SDEdit(Meng 等,2022)提供了一种更简单的编辑方式,无需特殊训练。你取输入图像,对其加噪(把前向扩散过程跑到一个中间时间步 t_0),然后用描述期望输出的文本提示去噪。噪声量控制编辑强度:低噪声保留结构(颜色改变、风格迁移),高噪声允许大幅重构(物体替换、布局改变)。
取舍是精确的:在时间步 t_0,带噪声的图像保留了原始信号的 \bar{\alpha}_{t_0} 比例。去噪过程按照新的文本提示填充被破坏的细节。这在数学上有根据:扩散模型从后验 p(x_0 \mid x_{t_0}, c) 中采样,其中 x_{t_0} 约束生成「接近」原图。
ControlNet(Zhang 等,2023)为文生图扩散增加了细粒度的空间控制。预训练 U-Net 编码器的一份副本被训练来接收额外的输入条件——边缘图(Canny 边缘)、深度图、姿态骨架、分割图——同时原始 U-Net 权重保持冻结。ControlNet 编码器的输出通过零卷积(zero convolution)(初始化为零的 1x1 卷积)加到冻结 U-Net 的跳跃连接上,确保训练从预训练模型的行为出发,逐步学习新的条件。
这种架构让你可以提供一张草图、一张深度图或一个人体姿态作为结构引导,文本提示填充外观。预训练权重负责照片级真实感和文本理解;ControlNet 层负责对条件在空间上的忠实度。
Fréchet Inception 距离(Fréchet Inception Distance,FID)(Heusel 等,2017)在预训练 Inception 网络的特征空间中,衡量生成图像分布与真实图像分布之间的距离。把它想象成比较两组图像集合的「指纹」,而不是比较单张图像。
真实图像集和生成图像集都通过 Inception-v3,收集倒数第二层的激活。这些激活被建模为多元高斯 \mathcal{N}(\mu_r, \Sigma_r) 和 \mathcal{N}(\mu_g, \Sigma_g)。FID 是这两个高斯之间的 Fréchet 距离(Wasserstein-2 距离):
FID 越低越好。FID = 0 意味着两个分布相同。FID 同时捕捉质量(如果生成的图像模糊,它们的特征会与真实图像不同)和多样性(如果模型出现模式坍缩,\Sigma_g 会比 \Sigma_r 小)。在 ImageNet 256x256 上,典型的最先进值是 FID < 2.0。
FID 有一些已知局限:它假设特征分布是高斯的(这是近似),它需要数千样本才能得到稳定估计,而且它用的是 Inception 特征(可能无法捕捉所有感知相关的差异)。
其中 E_I 和 E_T 是 CLIP 的图像和文本编码器。CLIPScore 不需要参考——它不需要真实图像,只需要文本提示。它与人类对文本–图像对齐的判断高度相关,已成为评估文生图模型提示忠实度的标准指标。
为了与参考描述比较,RefCLIPScore 引入一张参考图像:
**深度伪造(deepfake)**是旨在描绘从未发生过的事件的生成或篡改媒体。文生图和文生视频模型能创建公众人物的逼真假照片、捏造的证据和误导性的新闻图像。危险不仅在于假货存在,而在于它们的存在破坏了对所有媒体的信任——如果任何图像都可能是假的,那没有任何图像能被完全信任。
检测方法包括在真实 vs. 生成图像上训练分类器、分析统计伪影(GAN 生成的图像有微妙的光谱签名)、嵌入不可见水印(Stable Diffusion 的不可见水印、Google 的 SynthID)。然而,检测是一场军备竞赛:随着生成器改进,检测器也必须不断更新。
在互联网规模数据上训练的模型会继承并放大社会偏见。文生图模型不成比例地生成浅肤色面孔,把某些职业与特定性别关联,对于不够具体的提示默认采用西方文化规范。这些偏见根植于训练数据分布以及 CLIP/T5 等文本编码器,后者编码了自身训练语料中的偏见。
缓解策略包括精选更具代表性的训练数据、对文本编码器应用去偏技术、使用安全分类器过滤有问题的输出,以及让用户能控制人口统计属性。这些都不是完整解决方案,持续的审计必不可少。
负责任的部署需要多层保护。**输入过滤(input filtering)**在生成前拦截有害提示。**输出过滤(output filtering)**对生成内容分类并拒绝有害材料。**NSFW 分类器(NSFW classifier)**检测色情、暴力或其他有害内容。例如 Stable Diffusion 的安全检查器计算生成图像的 CLIP 嵌入与一组预定义有害概念嵌入之间的余弦相似度,标记超过阈值的图像。
许多生成模型(Stable Diffusion、Wan)的开源性质,在普及访问与防止滥用之间制造了张力。一旦模型权重发布,内容过滤就能被绕过。这引发了关于适当开放程度和模型开发者责任的辩论。
import jax import jax.numpy as jnp import matplotlib.pyplot as plt # 带无分类器引导的玩具级二维条件扩散 def noise_schedule(T): betas = jnp.linspace(1e-4, 0.02, T) alphas = 1.0 - betas return jnp.cumprod(alphas) def forward_diffuse(x0, t, alpha_bars, key): noise = jax.random.normal(key, x0.shape) return jnp.sqrt(alpha_bars[t]) * x0 + jnp.sqrt(1 - alpha_bars[t]) * noise, noise # 生成带标签的二维数据:类别 0 = 圆环,类别 1 = 簇 key = jax.random.PRNGKey(42) k1, k2, k3 = jax.random.split(key, 3) theta = jax.random.uniform(k1, (200,)) * 2 * jnp.pi ring = jnp.stack([jnp.cos(theta), jnp.sin(theta)], axis=1) * 2 ring += jax.random.normal(k2, ring.shape) * 0.1 cluster = jax.random.normal(k3, (200, 2)) * 0.3 data = jnp.concatenate([ring, cluster]) labels = jnp.concatenate([jnp.zeros(200), jnp.ones(200)]) # 模拟 CFG:展示引导如何把样本推向类别条件下的模式 # 试着把 guidance_scale 从 0.0 调到 5.0,观察结果 guidance_scales = [0.0, 1.0, 3.0, 7.0] fig, axes = plt.subplots(1, 4, figsize=(16, 4)) for ax, s in zip(axes, guidance_scales): ax.scatter(ring[:, 0], ring[:, 1], s=8, alpha=0.4, label='Ring (c=0)') ax.scatter(cluster[:, 0], cluster[:, 1], s=8, alpha=0.4, label='Cluster (c=1)') ax.set_title(f'Guidance scale s={s}') ax.set_xlim(-4, 4); ax.set_ylim(-4, 4) ax.set_aspect('equal'); ax.legend(fontsize=7) plt.suptitle('Experiment: vary guidance scale and observe quality vs diversity') plt.tight_layout(); plt.show() # 练习:训练一个带类别条件的小型 MLP 去噪器, # 然后用 CFG 公式以不同 s 值采样。
import jax import jax.numpy as jnp import matplotlib.pyplot as plt def compute_fid(real, generated): """计算两组二维样本之间的 Fréchet 距离。""" mu_r, mu_g = jnp.mean(real, axis=0), jnp.mean(generated, axis=0) sigma_r = jnp.cov(real.T) sigma_g = jnp.cov(generated.T) diff = mu_r - mu_g # 通过特征分解求矩阵平方根 product = sigma_r @ sigma_g eigvals, eigvecs = jnp.linalg.eigh(product) sqrt_product = eigvecs @ jnp.diag(jnp.sqrt(jnp.maximum(eigvals, 0))) @ eigvecs.T fid = jnp.sum(diff ** 2) + jnp.trace(sigma_r + sigma_g - 2 * sqrt_product) return fid key = jax.random.PRNGKey(0) k1, k2, k3, k4 = jax.random.split(key, 4) # 真实分布:标准二维高斯 real = jax.random.normal(k1, (1000, 2)) # 偏离程度递增的生成分布 shifts = [0.0, 0.5, 1.0, 2.0, 4.0] fig, axes = plt.subplots(1, len(shifts), figsize=(18, 3.5)) for ax, shift in zip(axes, shifts): gen = jax.random.normal(k2, (1000, 2)) * (1 + shift * 0.2) + shift fid = compute_fid(real, gen) ax.scatter(real[:, 0], real[:, 1], s=3, alpha=0.3, label='Real') ax.scatter(gen[:, 0], gen[:, 1], s=3, alpha=0.3, label='Generated') ax.set_title(f'Shift={shift}\nFID={fid:.2f}') ax.set_xlim(-5, 8); ax.set_ylim(-5, 8) ax.set_aspect('equal'); ax.legend(fontsize=7) plt.suptitle('FID increases as generated distribution diverges from real') plt.tight_layout(); plt.show() # 试试:不移动均值,仅改变生成样本的方差。 # FID 对多样性失配和位置失配的响应如何?
import jax import jax.numpy as jnp import matplotlib.pyplot as plt def cosine_similarity(a, b): return jnp.dot(a, b) / (jnp.linalg.norm(a) * jnp.linalg.norm(b)) def clip_score(img_emb, txt_emb): """CLIPScore:截断的余弦相似度。""" return jnp.maximum(0.0, cosine_similarity(img_emb, txt_emb)) key = jax.random.PRNGKey(42) dim = 512 # CLIP 嵌入维度 # 模拟对齐和不对齐的对 # 对齐:图像和文本嵌入共享一个分量 k1, k2, k3 = jax.random.split(key, 3) shared = jax.random.normal(k1, (dim,)) shared = shared / jnp.linalg.norm(shared) noise_levels = jnp.linspace(0, 5, 20) scores = [] for noise in noise_levels: noise_vec = jax.random.normal(k2, (dim,)) * noise img_emb = shared + noise_vec * 0.3 txt_emb = shared + jax.random.normal(k3, (dim,)) * noise * 0.3 scores.append(float(clip_score(img_emb, txt_emb))) plt.figure(figsize=(8, 4)) plt.plot(noise_levels, scores, 'o-', color='#2c3e50') plt.xlabel('Noise level (misalignment)') plt.ylabel('CLIPScore') plt.title('CLIPScore decreases as text-image alignment degrades') plt.grid(True, alpha=0.3) plt.tight_layout(); plt.show() # 实验:如果在加噪之前先归一化嵌入会怎样? # 维度如何影响分数分布?