PRX 第4部分:我们的数据策略

Hugging Face Blog 新闻

摘要

Photoroom 详细介绍了训练 PRX 的数据策略,包括组装多样化数据集、使用 VLM 重新生成描述,以及利用 Mosaic Data Shards 实现高效训练。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/07/06 16:35

PRX 第四部分:我们的数据策略

来源:https://huggingface.co/blog/Photoroom/prx-part4-data 返回文章列表 (https://huggingface.co/blog)

  • 1. 指导原则 (https://huggingface.co/blog/Photoroom/prx-part4-data#1-guiding-principles)- 用于预训练的多样化数据集 (https://huggingface.co/blog/Photoroom/prx-part4-data#a-diverse-dataset-for-pre-training) - 混合数据源 (https://huggingface.co/blog/Photoroom/prx-part4-data#a-mix-of-data-sources) - 我们的描述哲学 (https://huggingface.co/blog/Photoroom/prx-part4-data#our-captions-philosophy) - 数据格式 (https://huggingface.co/blog/Photoroom/prx-part4-data#data-formats) - 关于文本潜在向量 (https://huggingface.co/blog/Photoroom/prx-part4-data#on-text-latents) - 关于图像编码 (https://huggingface.co/blog/Photoroom/prx-part4-data#on-image-encoding)
  • 2. 在Lance中构建数据集 (https://huggingface.co/blog/Photoroom/prx-part4-data#2-building-the-dataset-in-lance)- 用于探索的现有描述和嵌入 (https://huggingface.co/blog/Photoroom/prx-part4-data#existing-captions-and-embeddings-for-exploration) - 数据剖析和探索 (https://huggingface.co/blog/Photoroom/prx-part4-data#profiling-and-exploring-the-data)
  • 3. 使用VLM重新描述所有内容 (https://huggingface.co/blog/Photoroom/prx-part4-data#3-re-captioning-everything-with-a-vlm)- 选择描述器 (https://huggingface.co/blog/Photoroom/prx-part4-data#choosing-the-captioner)
  • 4. 写入Mosaic数据分片 (https://huggingface.co/blog/Photoroom/prx-part4-data#4-writing-mosaic-data-shards)- 什么是MDS,为什么我们用Lance代替它 (https://huggingface.co/blog/Photoroom/prx-part4-data#what-mds-is-and-why-we-use-it-over-lance) - 分辨率 + 宽高比分桶 (https://huggingface.co/blog/Photoroom/prx-part4-data#resolution–aspect-ratio-bucketing)
  • 5. 数据过滤 (https://huggingface.co/blog/Photoroom/prx-part4-data#5-data-filtering)
  • 6. 去重 (https://huggingface.co/blog/Photoroom/prx-part4-data#6-deduplication)
  • 下一步是什么? (https://huggingface.co/blog/Photoroom/prx-part4-data#whats-next)
  • 参考文献 (https://huggingface.co/blog/Photoroom/prx-part4-data#references)

欢迎回来!这是PRX系列的第四部分。第一至第三部分涵盖了模型架构 (https://huggingface.co/blog/Photoroom/prx-part1-architectures)、训练设计 (https://huggingface.co/blog/Photoroom/prx-part2) 以及一次24小时速通 (https://huggingface.co/blog/Photoroom/prx-part3)。这次我们将掀开幕后,聚焦于默默支撑这一切的部分:数据。在所有影响PRX质量的因素中,数据管道是构建起来最不“光鲜”的部分,但却是必须做对的关键一环。以下是我们所做的、我们会做出不同选择的地方,以及一些我们经历了教训才弄明白的事情。

一句话概括:我们从公开和内部数据集的混合中组装训练数据,使用VLM重新描述图像,并将结果转换为我们用于训练PRX的可流式语料库。

从高层次看,数据管道如下所示:

数据管道:源数据集,准备图像,使用VLM重新描述,写入Mosaic数据分片

接下来我们将深入探讨其中的细节。

1. 指导原则

用于预训练的多样化数据集

目标是组装一个大规模、多样化的数据集用于预训练。在这个阶段,模型正在学习世界的外观:视觉概念、物体和场景、事物如何组合和照明,以及图像所能包含的广泛内容。这是一个覆盖范围和多样性的问题,而不是追求每张图像的完美。一个广泛、有代表性的语料库教给模型关于视觉世界结构的知识,远多于一个小而美的语料库,即使其中许多单个图像是普通的快照或略有压缩。在此阶段过度过滤美学标准实际上会适得其反,会缩小分布范围,并让模型失去无法在后阶段恢复的概念和构图多样性。让生成结果看起来精致是另一个、且是后续阶段的问题,我们将其留给在小而精挑细选的集合上进行微调和偏好对齐。预训练是为了广度;微调是为了品味。

混合数据源

我们从公开和内部数据集的混合中组装预训练数据。此阶段的重点是广度、多样性,并利用已有的数据筛选成果,而不是自己从头再做一遍。如果某个数据源已经过质量过滤、去重、NSFW内容和个人信息过滤,我们就基于这些工作,而不是大规模重复。数据源的形态各异:有些直接包含图像数据本身,其他的则是元数据加上基础描述,我们需要将其统一为通用格式。我们采取了务实的方法:不是完全从头构建语料库,而是依靠现有数据集和我们自己的工具来快速组装。事后看来,这不一定是可以构建的绝对最佳数据集,但对于预训练一个7B模型来说,它是一个坚实且轻量的起点。

我们的描述哲学

根据我们的经验,预训练中最重要的是使用准确描述图像中所有内容的长描述。我们在第二部分 (https://huggingface.co/blog/Photoroom/prx-part2) 中直接看到了这一点,从短描述切换到长描述显著提高了样本质量。如果描述是忠实的,我们就不必担心图像中偶尔出现的屏幕截图、广告、标志或文本,因为这些内容也会在描述中描述出来,因此模型将其学习为有条件的、可控的属性,而不是无条件地复制它们。准确的描述将“噪声”转变为你可以通过提示词控制或排除的内容。这正是我们稍后进行的过滤故意很轻的原因。我们移除的是真正不可用的内容,而不是所有不完美的内容。

数据格式

我们一直使用Mosaic Streaming (https://github.com/mosaicml/streaming) 和 Mosaic Data Shards (MDS) 作为分布式训练的数据集格式。结合Mosaic Composer (https://docs.mosaicml.com/projects/composer/en/latest/index.html),我们发现在分布式训练中它是一个维护成本低、灵活且性能优越的框架。此外,MDS数据集可以轻松有效地进行混合和洗牌,并且支持直接从S3或GCS等对象存储进行分布式训练。

然而,MDS数据集非常死板。添加一列或为某个过滤条件创建子集基本上意味着需要扫描并重写整个数据集。这就是为什么我们使用Lance (https://lance.org/) 来进行这类特征工程和数据集整理的原因。Lance是一种列式数据格式,具有廉价的谓词下推、标量索引和向量搜索功能,是构建和探索拥有数十亿行数据集的正确工具。

用Lance构建和探索,用MDS流式传输到训练

这两种格式在这篇文章和PRX数据管道中相互配合:Lance用于构建,MDS用于流式传输。

关于文本潜在向量

在之前的训练运行中,我们使用T5Gemma (https://deepmind.google/models/gemma/t5gemma/) 作为文本编码器,并预计算了文本潜在向量,将其以字节形式存储在MDS中。这次,在将文本编码器切换到Qwen3-VL (https://huggingface.co/collections/Qwen/qwen3-vl) 后,我们决定在训练期间即时计算文本潜在向量。在训练循环内运行文本编码器会消耗吞吐量,但具体消耗多少取决于模型:对于小的去噪器来说可能很显著,而在PRX的7B规模下,文本编码器的计算量与去噪器相比可以忽略不计,我们测量到的吞吐量成本大约只有3-4%(在一个30天的运行中大约多出1天)。作为回报,我们获得了两个好处。跳过预计算使我们的MDS分片小得多,小到足以将整个预训练数据集存储在SLURM集群的SSD后端共享文件系统中,而不是通过网络从对象存储流式传输。而且,这使我们可以在以后自由更换文本编码器,而无需重写数TB的存储潜在向量——这正是我们在转向Qwen3-VL时所做的切换类型。

关于图像编码

我们将所有图像编码为质量参数92的JPEG格式,而不是像PNG这样的无损格式。我们并没有盲目假设质量92是安全的,而是进行了测量。现实世界的图像通常已经经过多次JPEG压缩,所以真正的问题是再重新编码一次是否会有损害。在对高分辨率(1–2 MP)和低分辨率(0.25–0.5 MP)的真实图像进行多次解码/编码循环后,第一次使用质量92重新编码的效果基本上是难以察觉的。后续每轮循环几乎不增加任何东西,因为JPEG会迅速收敛到稳定状态,即使在10个循环后,图像仍然保持在难以察觉的范围内,而PNG的体积会大3-10倍,且没有感知上的收益。以下是100张图像在质量92下的平均值,并与原始图像进行比较(PSNR越高越好,LPIPS越低越好):

图像分辨率1次后的PSNR (dB) ↑1次后的LPIPS ↓10次后的PSNR (dB) ↑10次后的LPIPS ↓
1–2 MP48.70.00445.40.008
0.25–0.5 MP45.10.00542.20.010

由于大多数源图像已经以JPEG压缩形式到达,将它们无损存储为PNG收益甚微,因此我们将所有内容转换为高质量JPEG(质量92)。

我们还检查了最重要的一点:使用JPEG训练是否会改变模型生成的结果。我们的语料库大部分已经是JPEG格式,因此PNG能提供的唯一优势是避免引入新的伪影。我们特意从高分辨率来源进行比较,期望即使是原本JPEG的图像在高分辨率下也带有很少的伪影。我们在1024像素下用相同的图像训练了两个完全相同的PRX模型,一个存储为PNG,另一个存储为质量92的JPEG。根据我们的指标,两者训练得同样好,它们的生成结果几乎无法区分,包括当我们使用一种已知的通过匹配量化表来估计JPEG质量 (https://www.bitsgalore.org/2024/10/30/jpeg-quality-estimation-using-simple-least-squares-matching-of-quantization-tables.html) 的技术来估计输出看起来的JPEG压缩程度时:

模型训练自检测率平均估计JPEG质量中位数估计JPEG质量
JPEG (质量92)12.0%39.634.0
PNG10.8%42.145.0

检测率是发现任何量化结构的生成结果的比率。平均和中位数估计JPEG质量仅针对那些被标记的图像计算。这两个模型几乎无法区分:两个模型中大约只有十分之一的生成结果显示出任何可检测的量化结构,且差异足够小,我们确信训练图像格式对输出质量的影响微乎其微。因此,高质量JPEG存储不会在源数据已经包含的内容之上增加任何可测量的东西。对于大规模文生图训练来说,这已经足够好了。对于用于训练Photoroom其他模型的伪影敏感数据,例如我们的自定义AI阴影 (https://docs.photoroom.com/image-editing-api-plus-plan/ai-shadows) 模型,我们仍然依赖PNG。

2. 在Lance中构建数据集

你无法交互式地探索拥有数亿甚至数十亿行的Parquet表。因此,我们将数据存储在Lance中,在那里我们可以进行索引、查询和浏览。我们使用Ray Data (https://docs.ray.io/en/latest/data/data.html) 进行数据摄入,并行读取源表,并在集群中写入Lance表的多个碎片。

一个值得分享的经验是关于碎片化的问题。一个Lance表被分割成多个碎片,一些操作的开销与碎片总数成正比,而不是与行数成正比:一次扫描会打开每个碎片的文件,一些元数据操作的开销是O(碎片数)。因此,分割成太多小碎片的表,无论其大小如何,查询都会很慢。Lance性能指南 (https://lance.org/guide/performance/) 建议保持碎片数量较少(经验法则是即使对于数十亿行的表,碎片数量也应在数百的量级),并定期进行压缩以将小碎片合并成大碎片。

我们是经历了教训才弄明白这个问题的。我们最初的摄入只针对每个碎片10万行,这留下了数千个微小碎片,使得即使是简单的过滤和全文查询也运行缓慢。在将每个碎片的行数压缩到大约100万行后(对于我们数亿行的表来说,这意味着大约一千个碎片),查询变得很快,我们也就不再担心了。正确的目标取决于行宽、查询模式以及数据的写入方式。事后看来,更少的、更大的碎片可能是更好的默认值。Lance支持分布式压缩(例如通过Lance-Ray (https://lance.org/integrations/ray/#lance-ray-integration) 集成实现),事后调整很容易,但一开始就避免过度碎片化是值得的。

Lance碎片压缩:许多小碎片(慢)压缩成更少、更大的碎片(快)

用于探索的现有描述和嵌入

我们选择自己为每张图像重新生成描述,而不是依赖某些数据集附带提供的描述。原因在于一致性:在混合的来源之间,描述的长度、风格和质量差异很大,我们希望在整个语料库中有一个统一的标准(关于描述器的更多信息见第3节)。

尽管如此,数据集已有的元数据仍然有价值,只是用于不同的目的。预先存在的描述,以及有时伴随它们而来的向量嵌入(例如CLIP (https://arxiv.org/abs/2103.00020) 嵌入),正是使数据集能够在Lance中立即被探索的基础:对描述进行全文搜索,以及在嵌入列上进行最近邻搜索,使我们能够浏览数据,并快速判断其质量以及需要的过滤,远在我们运行自己的描述之前。因此,我们保留了这两者,当它们存在于单独的表中时将其连接进来,并依靠它们进行接下来要描述的浏览。

数据剖析和探索

数据可查询后,我们可以快速对其进行剖析。例如,分辨率分布告诉我们在哪里设置截断阈值。我们最小的训练桶是512^2像素,并且我们将放大到桶的比例上限设置为4/3(约33%),因此有效的截断阈值是384^2 ≈ 147k像素,加上宽高比在[0.5, 2.0]范围内。低于此阈值的所有数据都会被丢弃。

Lance表支持开箱即用的文本列全文搜索以及向量嵌入列上的最近邻相似度搜索,并且两者都可以通过构建索引来加速。我们对描述列和嵌入列正是这样做的,然后构建了一个小型的UI来浏览数据集:对描述进行实时文本搜索,以及通过向量搜索导航视觉相似图像的聚类。

explorer_text (https://cdn-uploads.huggingface.co/production/uploads/680a58121b2c7c159d2bd481/azqOCm90E

相似文章

UltraX:通过自适应程序化编辑大规模优化预训练数据

arXiv cs.CL

UltraX 提出了一种面向大规模预训练数据的函数调用式优化框架,在删除和修改之外引入插入操作,补全了编辑函数空间,从而实现细粒度的实例级编辑。该框架构建了可靠的程序监督生成流水线,在从头训练 1B 模型时,展示了更优的数据效率和模型性能。

生成更好训练数据的智能体(25分钟阅读)

TLDR AI

Autodata 引入了一种智能体数据科学家,它能够迭代生成并优化合成训练数据,并通过元优化进一步提升数据质量,在计算机科学和法律推理任务上取得了更好的效果。

机器人团队正在从头重建数据栈

Hacker News Top

机器人团队正在从头重建数据栈,以克服“数据层税”对机器人学习迭代和扩展的拖累,因为现有基础设施无法处理多速率和多模态数据。