【论文阅读】VTP:Towards Scalable Pre-training of Visual Tokenizers for Generation

【论文阅读】VTP:Towards Scalable Pre-training of Visual Tokenizers for Generation

https://arxiv.org/html/2512.13687v1

阅读了MiniMax的这个论文,眼前一亮。

个人理解

图像生成模型,包括两部分,先通过VAE,将原始图像变换到隐空间,然后在隐空间进行图像的生成,最后再通过VAE的解码变换到图像域。但是传统的方式,对于VAE部分,也就是论文说的Pre-training of Visual Tokenizers部分,无法scaling——而且,token部分的scaling还与下游的模型生成出现相反的效果。论文分析,这里的原因,在于,传统的的token部分,主要是进行像素级重建,没有进行高级语义的理解和构建,导致过分拟合于细节,反而影响了下游的图像生成。解决方法,就是在token部分的训练,除了重建部分的训练,增加了CLIP对比学习和自监督学习,进行联合学习,于是token部分的训练就也可以scaling了。

文章解读

关于这个论文,已经有相关解读,我就直接引用:
VTP:MiniMax海螺视频团队,首次开源!
https://mp.weixin.qq.com/s/Z0HT8AiWvRdgkbvQWVkc4w
MiniMax海螺首次开源,发现了AI视觉生成领域的Scaling Law
https://mp.weixin.qq.com/s/_PkQV_3WGx7uwUZQ4bTN7g

模型架构

但是,上面的两篇解读文章,读下来,还是对模型架构不甚清晰。模型架构如下:

在这里插入图片描述


针对这个架构图,通过与kimi的多轮对话,基本理解了。(注:Kimi下面的回答,关于对比学习和自监督学习部分,似乎回答的有错误,不过不影响总体的理解,很容易辨别)

问:请对文章中的图3的架构进行详细解释

图3架构详细解释

整体架构设计

图3展示了一个统一的视觉分词器预训练框架,该框架将表示学习(representation learning)与重建任务(reconstruction)结合在一起,采用Vision Transformer(ViT)自编码器结构。

架构组件详解

1. 编码器部分(Encoder)
  • 使用**Vision Transformer (ViT)**作为基础架构
  • 将输入图像压缩到d维潜在空间(latent space)
  • 下采样比例为16倍(f16),即输入图像的H×W被压缩为H/16×W/16的潜在表示
  • 编码器输出的特征维度为:ℝ^(d×H/16×W/16)
2. 多任务学习分支

编码器输出的特征被三个不同的组件共享使用:

a) 文本编码器(Text Encoder)

  • 用于图像-文本对比学习(CLIP)
  • 12层transformer,隐藏维度768
  • 实现跨模态对齐,注入全局语义理解

b) EMA教师网络(EMA Teacher)

  • 用于自监督学习(SSL)
  • 采用指数移动平均(Exponential Moving Average)策略
  • 支持掩码图像建模(MIM)和自蒸馏(self-distillation)

c) 像素解码器(Pixel Decoder)

  • 4层ViT-Large层
  • 将潜在特征重新映射回像素空间
  • 通过像素重排层(pixel-shuffle layer)重建图像
3. 损失函数设计

框架整合了三种不同的损失函数:

ℒ_total = λ_recℒ_rec + λ_sslℒ_ssl + λ_clipℒ_clip

其中:

  • ℒ_rec:重建损失(L1损失 + 感知损失)
  • ℒ_ssl:自监督损失(MIM损失 + DINO损失)
  • ℒ_clip:对比学习损失(图像-文本对齐)
4. 批采样策略

针对不同任务的最优批大小差异:

  • CLIP训练:使用大批量(16k或32k)
  • 自监督学习:中等批量(4k)
  • 重建任务:小批量(2k)

架构创新点

1. 统一的多任务框架
  • 首次将对比学习、自监督学习和重建任务统一在一个框架中
  • 通过共享编码器实现任务间的知识传递
2. 可扩展的潜在空间
  • 潜在维度可配置(论文中主要使用d=64)
  • 平衡语义理解和重建质量
3. 两阶段训练策略
  • 第一阶段:联合优化所有损失函数
  • 第二阶段:冻结分词器,微调像素解码器(使用GAN损失)

架构优势

  1. 语义丰富性:通过CLIP和SSL任务注入高层语义理解
  2. 重建保真度:保持像素级重建能力
  3. 生成友好性:潜在空间更适合下游生成任务
  4. 可扩展性:随着计算资源、模型参数和数据规模的增加,性能持续提升

这个架构的核心思想是:理解能力是生成的关键驱动因素。通过在学习目标中引入语义理解和感知任务,可以显著提升潜在空间的生成性能,解决了传统仅基于重建的训练范式存在的"预训练扩展问题"。

问:对于对比学习部分,是把文本编码和CLS tokens做对比嘛?请解释一下

好问题!论文里对对比学习的技术细节说得比较简略,但我把上下文里所有相关片段都找出来了,可以给你一个相对完整的拼接。要点如下:

  1. 不是用 ViT 的 CLS token,而是把 encoder 输出的整张 feature map 先“压”成一个全局视觉向量,再去跟文本向量做对齐。
    原文位置:
    “Given an image I … we compress it into a latent space ℝ^{d×H/16×W/16} … Encoder features are leveraged by the text encoder …”
    以及
    “Given a batch of image-text pairs, we encode the image I and text T using a visual tokenizer and a text encoder, respectively, to obtain their visual and textual features.”
  2. 压成全局向量的方式论文没写死,但从它后面一直强调“follow CLIP”以及实验部分只报 64-dim bottleneck 上的 linear-probe 结果来看,最简单且与全文自洽的做法就是
    -先对 spatial token 做 average pooling(或 attention pooling),
    -再线性投射到 512/768 维,
    -最后跟文本端 [CLS] 向量做 normalize → dot-product → InfoNCE/sigmoid 对比损失。
    这样做既符合 CLIP 范式,也解释了为什么他们反复说“只用 bottleneck 特征就能 linear-probe”——因为那张 feature map 已经通过对比损失被强制对齐到语义空间了。
  3. 文本侧就是标准 CLIP 做法:
    -12 层 Transformer,输入是 BPE 分词后的 caption,
    -取最后一层 [CLS] 位置特征(或等价地,做 pooling)作为句子向量,
    -同样 L2 归一化后进入对比损失。
  4. 训练时为了照顾 CLIP 需要大 batch,他们单独给对比任务开了 B_clip=16 k 的 batch,而 SSL 和重建只用 2 k–4 k;同一批图像在三个任务里共享,但对比任务会额外再放大 batch。

总结:
视觉端 → 整张 feature map → global pooling → 线性投影 → 视觉向量
文本端 → [CLS] token → 文本向量
损失 → CLIP 式对比损失(InfoNCE 或 SigLIP 的 sigmoid 形式)

所以并不是直接把 CLS token 拿出来跟文本比,而是“把 encoder 输出压成全局向量后再比”,这一点在论文里虽然没有画成公式,但逻辑上是自洽且唯一合理的实现方式。

问:框架中的global crops和local craops分别是如何生成的,感觉这两部分也不是原始图像

论文里确实只用了一句话带过:“we apply data augmentation to obtain global and local views I_global and I_local”,没有给出具体参数。
不过它紧接着就说“For self-supervised learning … adhering to DINOv2”,而全文所有 SSL 超参(mask ratio、loss weight、EMA decay)都直接照抄 DINOv2,因此**“如何得到 global crops & local crops”也默认沿用 DINOv2 的同一套采样协议**。下面把 DINOv2 的默认做法搬过来,就能回答你的疑问。


  1. 输入只是一张原始图像,但会连续做两次 RandomResizedCrop,得到一对 view:这两个区间互不重叠,保证“局部”真的比“全局”小很多。
    • global crop
      – scale ∈ [0.32, 1.0]
      – 面积占比大,几乎覆盖整图
      – 最终 resize 到 224×224(ViT-B/L 常用)
    • local crop
      – scale ∈ [0.05, 0.32]
      – 面积占比小,只看局部区域
      – 同样 resize 到 224×224
  2. 额外增强
    在 RandomResizedCrop 之后,再依次叠加:
    – RandomHorizontalFlip(p=0.5)
    – ColorJitter(亮度、对比度、饱和度、色相,强度 0.4)
    – RandomGrayscale(p=0.2)
    – GaussianBlur(kernel=23,σ∈[0.1,2.0],p=0.5)
    – Normalize(ImageNet 均值方差)注意:global 与 local 各自独立抽参数,所以同一幅图得到的两个 view 可以颜色、翻转、模糊都不一样。
  3. 与 MAE/DINO 的区别
    DINOv2 为了兼顾 iBOT 的“masked image modeling”,还会给 global crop 再生成一个高掩码率版本(通常 60 % patch 被 mask),作为 encoder 的输入;而 EMA teacher 拿到的是未掩码的 global crop
    这一步在论文 3.3 节里明确写了:“I_global is patch-embedded and fed directly to an EMA teacher, while its masked version is processed by the visual tokenizer”。
  4. 形状与通道
    无论 global 还是 local,最后送进网络的都是 3×224×224 的正常 RGB tensor,不是原始分辨率,也不是单通道灰度。你觉得“不是原始图像”是因为 RandomResizedCrop 已经把像素重采样过,颜色增强也改变了分布,但本质上仍然来源于同一张原图。

一句话总结:
global / local crops 就是同一张原图用 DINOv2 的 RandomResizedCrop 参数连续裁两次,再各自做颜色、翻转、模糊等增强,最终都得到 224×224 的 RGB 图像;其中 global 覆盖 32 %–100 % 区域,local 只覆盖 5 %–32 % 区域。

问:对于自监督学习部分,mim的损失部分我看明白了,但是不理解dino部分的损失是如何定义,请详细解释一下

下面把 DINOv2(也就是论文里说的“DINO”)损失一步步拆开,告诉你它到底在跟谁做交叉熵、标签又是怎么来的。全程只涉及两个向量:

  1. student 输出的 softmax 向量(可梯度回传)
  2. teacher 输出的 softmax 向量(无梯度、作为伪标签)

  1. 网络结构
    • student:就是 VTP 的 visual tokenizer(encoder)
    • teacher:EMA 版本的同一个 encoder,权重 θ_t ← λθ_t + (1-λ)θ_s,λ≈0.996
    • 最后分类头:
      – 一个 weight-normalized fc(|w|=1)
      – 无 bias
      – 输出维度 K=65536(DINOv2 默认 vocab size)
  2. 输入视图
    • 对同一张原图采两个独立增强视图:
      v1 = global-crop-1(224×224)
      v2 = global-crop-2(224×224)
    • student 吃 v1,teacher 吃 v2(也可以反过来,对称)
    • 局部视图 local-crop 只给 MIM 用,不进 DINO 损失
  3. 得到 logit
    z_s = student(v1) # (B, K)
    z_t = teacher(v2) # (B, K)
    因为 fc 权重已单位化,logit 实际上就是 cosine similarity:
    z_s = x_s · W^T ,z_t = x_t · W^T
  4. 温度 softmax
    p_s = softmax(z_s / τ_s) # student 预测,τ_s=0.1
    p_t = softmax(z_t / τ_t) # teacher 预测,τ_t=0.05(更尖锐)
  5. 交叉熵损失
    把 teacher 的输出当成“one-hot 伪标签”,对 student 做标准交叉熵:
    L_dino = − Σ_{i=1}^B Σ_{k=1}^K p_t^{(i,k)} log p_s^{(i,k)}
    由于 p_t 已经 softmax 过,这等价于:
    L_dino = CE(p_t, p_s) # 注意方向:label=p_t, input=p_s
  6. centering & sharpening(防止 collapse)
    • center:维护一个动量更新的均值向量 c,每次 forward 把 z_t 减掉 c 再做 softmax
    • sharpen:温度 τ_t 已经很小(0.05),进一步鼓励尖锐分布
    • 这两个操作都写在 DINOv2 代码里,但论文一般一句“centering + sharpening”带过
  7. 对称分支
    反过来再算一次:student 吃 v2,teacher 吃 v1,得到 L_dino’
    最终 loss 取平均:L_dino = (L_dino + L_dino’) / 2
  8. 与 MIM 的协作
    论文 3.3 节把 L_dino 和 L_mim 直接相加:
    L_ssl = L_mim + L_dino
    两个损失共享同一套 encoder 参数,但
    • L_mim 用“masked global + EMA teacher”重建 patch
    • L_dino 用“未 masked 的两个 global view”做自蒸馏
      互不干扰,各自回传梯度

一张图看清数据流:

原图
├── global-crop-1 ──→ student ──→ p_s
└── global-crop-2 ──→ EMA teacher ──→ p_t (伪标签)

CE(p_t, p_s) = L_dino


一句话总结:
DINO 损失就是“用 EMA teacher 在网络尾部 65536-way 分类器上产生的尖锐 softmax 分布作为伪标签,对 student 的同类向量做交叉熵”,通过centering+sharpening 防止分布塌缩,从而迫使 encoder 在不同视图下输出一致的高层语义表示。

问:其中的EMA是什么意思?教师网络在训练中参数是冻结的嘛?

EMA 是 Exponential Moving Average(指数移动平均)的缩写,teacher 的参数 根本不是“冻结”,而是 每一步都用 EMA 规则从 student 那里“滑动更新”,因此 teacher 总是比 student“慢半拍”,但又时刻在变化。下面把公式和直觉都给你拆开。


  1. 更新规则(每训练迭代一次,做完反向传播后立即执行)
    θ_t ← λ·θ_t + (1−λ)·θ_s
    其中直观理解:
    teacher = 99.6 % 的“旧自己” + 0.4 % 的“新鲜 student”
    因此 teacher 永远不会跳变,而是缓慢地跟随 student。
    • θ_s:当前 student 的参数(刚被 SGD/Adam 更新完,含梯度信息)
    • θ_t:teacher 的参数(无梯度,只做滑动平均)
    • λ:动量系数,DINOv2 默认 0.996(越大越“慢”)
  2. 为什么不用“完全冻结”?
    • 完全冻结 → teacher 输出分布固定,student 很容易快速拟合这一固定分布,造成崩溃(所有图像预测到同一类)
    • EMA 持续漂移 → 给 student 提供一个移动靶,迫使它在特征空间内持续追赶,从而学到更鲁棒的表示
    • 同时 EMA 平滑了单步梯度噪声,相当于给 pseudo-label 做了“时域滤波”,质量更高
  3. 反向传播会不会穿过 teacher?
    • 不会。计算图在 teacher 处被截断:
      loss = CE( stop_gradient(teacher(x)), student(x) )
    • 因此只有 student 收到梯度;teacher 的更新完全来自上述滑动平均公式,与 loss 无关
  4. 实现细节(PyTorch 伪代码)
# 初始化 teacher.load_state_dict(student.state_dict())# 起点相同for p in teacher.parameters(): p.requires_grad =False# 不参与反向传播# 每个迭代 loss_dino = cross_entropy(teacher(v2), student(v1)) loss_dino.backward()# 只更新 student optimizer.step()# EMA 更新with torch.no_grad():for t_p, s_p inzip(teacher.parameters(), student.parameters()): t_p.data =0.996* t_p.data +0.004* s_p.data 
  1. 与“momentum encoder”异名同义
    在 MoCo、BYOL、DINO 系列论文里常把 teacher 叫 momentum encoder,就是同一个意思——用动量方式跟踪 online 网络,而非梯度优化。

一句话记住:
EMA teacher 不冻结、不梯度下降,而是每一步都用 0.996 动量把 student 的参数“滑动”到自己身上,从而提供一个稳定又缓慢变化的伪标签,防止自蒸馏崩溃。

Read more

LLaMA Factory 从入门到精通,一篇讲完

LLaMA Factory 从入门到精通,一篇讲完

目录 一、LLaMA-Factory 简介 二、安装部署 三、数据微调 1、数据集的建立 2、数据集格式 3、模型参数 4、开始运行 5、导出模型 四、webui 评估预测与对话 导出 五、SFT 训练 命令行 六、LoRA 合并 合并 量化 七、推理 原始模型推理配置 微调模型推理配置 多模态模型 批量推理 八、评估 通用能力评估 NLG 评估 评估相关参数 一、LLaMA-Factory 简介 LLaMA Factory 是一个简单易用且高效的大型语言模型(Large

AI编程工具对比:Cursor、GitHub Copilot与Claude Code

AI编程工具对比:Cursor、GitHub Copilot与Claude Code

文章目录 * AI编程工具对比:Cursor、GitHub Copilot与Claude Code * 一、产品定位与核心架构 * 1.1 Cursor:AI原生IDE的代表 * 1.2 GitHub Copilot:代码补全的行业标杆 * 1.3 Claude Code:终端Agent的革新者 * 二、核心功能深度对比 * 2.1 代码生成与理解能力 * 2.2 自动化与工作流集成 * 2.3 隐私与数据安全 * 三、成本效益分析 * 3.1 定价模式对比 * 3.2 投资回报比 * 四、适用场景与用户画像 * 4.1 最佳应用场景 * 4.2 用户反馈摘要 * 五、

node-llama-cpp安装与配置:Windows、Linux和Mac全平台教程

node-llama-cpp安装与配置:Windows、Linux和Mac全平台教程 【免费下载链接】node-llama-cppRun AI models locally on your machine with node.js bindings for llama.cpp. Force a JSON schema on the model output on the generation level 项目地址: https://gitcode.com/gh_mirrors/no/node-llama-cpp node-llama-cpp是一个基于llama.cpp的Node.js绑定库,让你能够在本地机器上运行AI模型,并在生成级别强制模型输出符合JSON模式。本文将为你提供Windows、Linux和Mac全平台的安装与配置教程,帮助你快速上手这款强大的AI工具。 一、准备工作 在开始安装node-llama-cpp之前,请确保你的系统满足以下要求:

Meta-Llama-3-8B-Instruct性能对比:不同量化方式

Meta-Llama-3-8B-Instruct性能对比:不同量化方式 1. 引言 随着大语言模型在消费级硬件上的部署需求日益增长,如何在保持推理质量的同时降低显存占用和提升推理速度,成为工程落地的关键挑战。Meta-Llama-3-8B-Instruct 作为 Llama 3 系列中兼顾性能与效率的中等规模模型,凭借其 80 亿参数、支持 8k 上下文以及出色的指令遵循能力,成为单卡部署的理想选择之一。 然而,原始 FP16 模型约需 16 GB 显存,仍超出多数消费级 GPU 的承载能力。因此,量化技术成为释放其潜力的核心手段。本文将系统性地对比 GPTQ-INT4、AWQ、GGUF(Q4_K_M)等多种主流量化方案在 vLLM 与 llama.cpp 等推理框架下的表现,涵盖显存占用、推理速度、输出质量三大维度,并结合 Open WebUI