img2dataset
轻松将大量图像 URL 转换为图像数据集。 可以在一台机器上 20 小时内下载、调整大小并打包 1 亿个 URL。
还支持为 URL+标题数据集保存标题。
如果你相信制作可重用的工具以便于机器学习使用数据,并且你想做出贡献,请加入 DataToML 聊天。
安装
pip install img2dataset
为了获得更好的性能,强烈建议设置一个快速的 DNS 解析器,请参阅此部分
退出指令
网站可以传递 HTTP 头部 X-Robots-Tag: noai
、X-Robots-Tag: noindex
、X-Robots-Tag: noimageai
和 X-Robots-Tag: noimageindex
默认情况下,img2dataset 将忽略带有此类头部的图像。
要禁用此行为并下载所有图像,你可以传递 --disallowed_header_directives '[]'
请参阅 AI 使用影响,以更好地理解为什么你可能决定启用或禁用此功能。
示例
可在 dataset_examples 文件夹中找到带有示例命令的数据集下载示例。特别是:
- mscoco 60 万个图像/文本对,可在 10 分钟内下载
- sbucaptions 86 万个图像/文本对,可在 20 分钟内下载
- cc3m 300 万个图像/文本对,可在一小时内下载
- cc12m 1200 万个图像/文本对,可在五小时内下载
- laion400m 4 亿个图像/文本对,可在 3.5 天内下载
- laion5B 50 亿个图像/文本对,可使用 10 个节点在 7 天内下载
- laion-aesthetic Laion aesthetic 是 laion5B 的一个 1.2 亿子集,美学 > 7,水印 < 0.8,不安全 < 0.5
- laion-art Laion aesthetic 是 laion5B 的一个 800 万子集,美学 > 8,水印 < 0.8,不安全 < 0.5
- laion-coco Laion-COCO 是 LAION2B-EN 的一个 6 亿子集,由 BLIP L/14 和 2 个 CLIP 版本(L/14 和 RN50x64)的集成进行标注
- laion-high-resolution Laion high resolution 是 laion5B 的一个 1.7 亿分辨率 >= 1024x1024 的子集
- laion-face Laion face 是 LAION-400M 的人脸子集,用于大规模人脸预训练。它包含 5000 万个图像-文本对
- coyo-700m COYO 是一个大规模数据集,包含 7.47 亿个图像-文本对以及许多其他元属性,以增加训练各种模型的可用性
- commonpool CommonPool 是一个从 CommonCrawl 收集的大规模数据集,包含 128 亿个图像-文本对
- datacomp-1b DataComp-1B 是一个大规模数据集,从 CommonPool 中筛选出 14 亿个图像-文本对
对于所有这些示例,你可能想根据自己的偏好调整调整大小的设置。默认值为 256x256,带白色边框。 请参阅下面的选项。
使用方法
首先获取一些图像 URL 列表。例如:
echo 'https://placekitten.com/200/305' >> myimglist.txt
echo 'https://placekitten.com/200/304' >> myimglist.txt
echo 'https://placekitten.com/200/303' >> myimglist.txt
然后,运行工具:
img2dataset --url_list=myimglist.txt --output_folder=output_folder --thread_count=64 --image_size=256
该工具将自动下载 URL,调整它们的大小,并以以下格式存储:
- output_folder
- 00000
- 000000000.jpg
- 000000001.jpg
- 000000002.jpg
- 00000
或者如果选择 webdataset,则以这种格式:
- output_folder
- 00000.tar 包含:
- 000000000.jpg
- 000000001.jpg
- 000000002.jpg
- 00000.tar 包含:
每个数字代表列表中的位置。子文件夹可避免在单个文件夹中有太多文件。
如果提供了标题,它们将被保存为 0.txt、1.txt、...
这可以轻松地用于机器学习训练或任何其他用途。
同时,还会保存名为 0.json、1.json、... 的 .json 文件,包含以下键:
- url
- caption
- key,形式为 000010005:前 5 位是分片 ID,后 4 位是分片中的索引
- status:下载是否成功
- error_message
- width
- height
- original_width
- original_height
- exif
还会保存一个与子文件夹/tar 文件同名的 .parquet 文件,包含相同的元数据。 它可以用于高效分析结果。
还会保存以相同名称加上 _stats 后缀的 .json 文件,它们包含下载过程中收集的统计信息(下载时间、成功次数等)。
Python 示例
查看这些示例,了解如何将其作为库调用:
API
该模块暴露了一个名为 download
的函数,它接受与命令行工具相同的参数:
- url_list 要下载的图片URL列表文件。可以是包含此类文件的文件夹。(必需)
- image_size 调整图片大小的目标尺寸(默认为256)
- output_folder 输出文件夹的路径。(默认为*"images"*)
- processes_count 用于下载图片的进程数。这对性能很重要,应设置较高。(默认为1)
- thread_count 用于下载图片的线程数。这对性能很重要,应设置较高。(默认为256)
- resize_mode 调整图片大小的方式,可以是no、border或keep_ratio(默认为border)
- no 完全不调整大小
- border 将图片调整为image_size x image_size并添加边框
- keep_ratio 保持比例,使图片的最小边等于image_size
- keep_ratio_largest 保持比例,使图片的最大边等于image_size
- center_crop 保持比例,对最大边进行中心裁剪使图片成为正方形
- resize_only_if_bigger 仅当图片大于image_size时才调整大小(默认为False)
- upscale_interpolation 用于放大的插值方法(默认为*"lanczos"*)
- downscale_interpolation 用于缩小的插值方法(默认为*"area"*)
- encode_quality 编码质量,范围0到100,使用png时为0到9的压缩因子(默认为95)
- encode_format 编码格式(默认为jpg)
- jpg jpeg格式
- png png格式
- webp webp格式
- skip_reencode 如果没有进行调整大小,是否跳过重新编码(默认为False)
- output_format 决定如何保存图片(默认为files)
- files 保存为包含图片的一组子文件夹
- webdataset 保存为包含图片的tar文件
- parquet 保存为包含图片字节的parquet文件
- tfrecord 保存为包含图片字节的tfrecord文件
- dummy 不保存。用于基准测试
- input_format 决定如何加载URL(默认为txt)
- txt 将URL加载为每行一个URL的文本文件
- txt.gz 将URL加载为每行一个URL的压缩(gzip)txt.gz文件
- csv 将URL和可选的说明加载为csv文件
- csv.gz 将URL和可选的说明加载为压缩(gzip)的csv.gz文件
- tsv 将URL和可选的说明加载为tsv文件
- tsv.gz 将URL和可选的说明加载为压缩(gzip)的tsv.gz文件
- json 将URL和可选的说明加载为json文件
- json.gz 将URL和可选的说明加载为压缩(gzip)的json.gz文件
- jsonl 将URL和可选的说明加载为jsonl文件。详见jsonlines
- jsonl.gz 将URL和可选的说明加载为压缩(gzip)的jsonl.gz文件。详见jsonlines
- parquet 将URL和可选的说明加载为parquet文件
- url_col parquet和csv中URL列的名称(默认为url)
- caption_col parquet和csv中说明列的名称(默认为None)
- bbox_col 边界框列的名称。边界框假定格式为
[x_min, y_min, x_max, y_max]
,所有元素都是*[0,1]范围内的浮点数(相对于图像大小)。如果为None*,则不执行边界框模糊处理(默认为None) - number_sample_per_shard 每个分片中将下载的样本数(默认为10000)
- extract_exif 如果为true,提取图像的EXIF信息并保存到元数据中(默认为True)
- save_additional_columns 从csv/parquet文件中提取并保存到元数据文件中的额外列列表(默认为None)
- timeout 尝试下载图像时等待的最长时间(秒)(默认为10)
- enable_wandb 是否启用wandb日志记录(默认为False)
- wandb_project 使用的W&B项目名称(默认为img2dataset)
- oom_shard_count 分片数量的数量级,仅用于决定命名分片文件时使用的零填充(默认为5)
- compute_hash 计算并存储在元数据中的原始图像哈希,可选None、md5、sha256、sha512(默认为sha256)
- verify_hash 如果不为None,则这是一个包含两个元素的列表,用于根据提供的输入验证哈希。列表的第一个元素是输入文件中包含哈希的列的标签,而第二个元素是正在检查的哈希类型(默认为None)
- distributor 选择如何分配下载任务(默认为multiprocessing)
- multiprocessing 使用多处理池生成进程
- pyspark 使用pyspark会话在spark集群上创建工作节点(详见下文)
- ray 使用ray集群。参见ray示例。
- subjob_size 在支持的每个子任务中下载的分片数量,例如一个子任务可以是pyspark作业(默认为1000)
- retries 下载应重试的次数(默认为0)
- disable_all_reencoding 如果设置为True,这将保持图像文件的原始状态,不进行调整大小和转换,甚至不检查图像是否有效。用于基准测试。仅在计划通过另一个程序对图像进行后处理且有大量存储空间可用时使用。(默认为False)
- min_image_size 要下载的图像的最小尺寸(默认为0)
- max_image_area 要下载的图像的最大面积(默认为inf)
- max_aspect_ratio 要下载的图像的最大纵横比(默认为inf)
- incremental_mode 可以是"incremental"、"overwrite"或"extend"。对于"incremental",img2dataset将下载所有未下载的分片;对于"overwrite",img2dataset将递归删除输出文件夹然后从零开始;对于"extend",img2dataset将从下一个可用的分片编号开始下载分片(默认为incremental)
- max_shard_retry 在最后重试失败分片的次数(默认为1)
- user_agent_token 将添加到下载图像时发送的HTTP请求的User-Agent头部的附加标识令牌;例如:"img2downloader"。(默认为None)
- disallowed_header_directives 下载图像时,如果HTTP响应中存在这些X-Robots-Tags头部指令,将导致该图像被排除在输出数据集之外。要忽略x-robots-tags,传递'[]'。(默认为'["noai", "noimageai", "noindex", "noimageindex"]')
增量模式
如果第一次下载因任何原因中断,你可以再次运行时使用--incremental "incremental"(这是默认设置),并使用相同的输出文件夹、相同的number_sample_per_shard和相同的输入URL,img2dataset将完成下载。
输出格式选择
Img2dataset支持多种格式。选择哪种格式需要权衡利弊:
-
files:这是最简单的格式,图片直接保存为文件。适用于本地文件系统上不超过100万个样本的情况。超过这个数量,性能问题会很快显现。标准文件系统处理超过百万个文件的效果并不理想。
-
webdataset:webdataset格式将样本保存在tar文件中,借助webdataset库,可以在pytorch、tensorflow和jax中快速加载生成的数据集。大多数情况下建议选择这种格式。它适用于任何文件系统。
-
parquet:parquet是一种列式格式,允许快速过滤。使用pyarrow和pyspark读取特别容易。如果您的数据生态系统主要基于pyspark,可以选择这种格式。可以使用petastorm读取数据,但使用起来不如webdataset那么简便。
-
tfrecord:tfrecord是一种基于protobuf的格式。在tensorflow和tf data中使用特别方便。如果您计划仅在tensorflow生态系统中使用数据集,可以选择这种格式。tensorflow写入器不使用fsspec,因此仅支持有限的文件系统,包括本地、hdfs、s3和gcs。在写入本地以外的文件系统时,它的效率也低于webdataset写入器,性能损失约30%。
编码格式选择
图像可以用jpeg、png或webp格式编码,并有不同的质量设置。
以下是100万张256 x 256图像在不同格式下所占空间的比较:
格式 | 质量 | 压缩 | 大小 (GB) |
---|---|---|---|
jpg | 100 | 不适用 | 54.2 |
jpg | 95 | 不适用 | 29.9 |
png | 不适用 | 0 | 187.9 |
png | 不适用 | 9 | 97.7 |
webp | 100 | 不适用 | 31.0 |
webp | 95 | 不适用 | 23.8 |
注意:
- 质量为100的jpeg并非无损
- png格式是无损的
- 质量>100的webp是无损的(参见OpenCV文档)
- 不同格式之间相同的质量数值并不意味着相同的图像质量
过滤数据集
只要可行,您应该在下载之前预先过滤数据集。
如果需要,您可以使用:
- --min_image_size SIZE:过滤掉一边小于SIZE的图像
- --max_image_area SIZE:过滤掉面积大于SIZE的图像
- --max_aspect_ratio RATIO:过滤掉纵横比大于RATIO的图像
在过滤数据时,建议预先打乱数据集,以减少对分片大小分布的影响。
哈希和安全性
一些数据集(例如laion5B)公开了原始图像的哈希值。
如果您想要格外安全,可以自动丢弃与这些哈希值不匹配的图像。
在这种情况下,您可以使用--compute_hash "md5" --verify_hash '["md5","md5"]'
有些图像实际上仍然是好的,但已被网站稍微修改。
如何调整选项
对于小型数据集,默认值应该足够好。对于较大的数据集,以下提示可能有助于您获得最佳性能:
- 将processes_count设置为机器的核心数
- 增加thread_count,直到您的带宽和CPU达到极限
- 如果您的数据集有超过100万个元素,我建议将output_format设置为webdataset,操作少量tar文件比操作数百万个文件更容易
- 将metadata保持为True可能有助于检查哪些项目已经保存,避免重复下载
要对您的系统和img2dataset与系统的交互进行基准测试,启用这些选项可能会很有趣(仅用于测试,不适用于实际下载)
- --output_format dummy:不会保存任何内容。有助于消除存储瓶颈
- --disable_all_reencoding True:不会重新编码任何内容。有助于消除CPU瓶颈 当这两个选项都启用时,剩下的瓶颈只与网络有关:例如DNS设置、您的带宽或URL服务器的带宽。
文件系统支持
得益于fsspec,img2dataset支持读写多种文件系统中的文件。
要使用它,只需在路径前加上文件系统的前缀。例如hdfs://
、s3://
、http://
、gcs://
、ssh://
或hf://
(包括Dataset Viewer)。
其中一些文件系统需要安装额外的包(例如s3需要s3fs,gcs需要gcsfs,ssh需要fsspec/sshfs,hf需要huggingface_hub)。
详情请参阅fsspec文档。
如果您需要为文件系统进行特定配置,可以使用fsspec配置系统来解决这个问题。它可以创建一个类似.config/fsspec/s3.json
的文件,其中包含如下信息:
{
"s3": {
"client_kwargs": {
"endpoint_url": "https://some_endpoint",
"aws_access_key_id": "your_user",
"aws_secret_access_key": "your_password"
}
}
}
这在使用兼容S3的文件系统(如minio)时可能是必要的。这种配置也适用于所有其他fsspec支持的文件系统。
分发模式
Img2dataset支持几种分发器。
- multiprocessing:生成一个进程池,使用这些本地进程进行下载
- pyspark:在spark池中生成worker来进行下载
multiprocessing是在单机下载的好选择,因此它是默认选项。 Pyspark让img2dataset可以使用多个节点,使其速度与机器数量成正比。 如果下载超过十亿张图像的数据集,这可能特别有用。
pyspark配置
要使用pyspark的img2dataset,您需要执行以下操作:
pip install pyspark
- 使用
--distributor pyspark
选项 - 调整
--subjob_size 1000
选项:这是每个子任务要下载的图像数量。增加它会意味着准备时间更长,将feather文件放入临时目录;减少它会意味着一次向pyspark任务发送更少的分片。
默认情况下,将创建一个本地spark会话。 根据您的特定spark集群,您可能想要创建自定义spark会话。 要做到这一点,请查看pyspark_example.py,您可以在那里插入自定义代码来创建spark会话,然后 运行img2dataset,它将使用该会话进行下载。
要创建spark集群,请查看distributed img2dataset教程
与Weights & Biases的集成
要启用wandb,请使用--enable_wandb=True
选项。
性能指标通过Weights & Biases进行监控。
此外,最常见的错误会被记录下来,以便更容易调试。
还有其他可用功能:
- 环境配置日志记录(操作系统、Python版本、CPU数量、主机名等)
- 硬件资源监控(GPU/CPU、内存、硬盘、网络等)
- 自定义图表和报告
- 运行对比(在优化线程/CPU数量等参数时很方便)
首次运行脚本时,你可以选择将指标关联到你的账户或匿名记录。
你也可以通过运行wandb login
提前登录(或创建账户)。
路线图
该工具在当前状态下对多达1亿个元素运行良好。未来目标包括:
- 10亿张图片的基准测试,可能需要
- 进一步优化调整大小部分
- 更好的多节点支持
- 集成增量支持(只下载新元素)
架构说明
该工具旨在尽可能快地下载图片。 这会对各种资源造成压力。假设每秒1350张图片,一些数据如下:
- 带宽:每秒下载一千张平均大小的图片需要约130MB/s
- CPU:调整一张图片大小可能需要几毫秒,每秒几千张可能会占用多达16个核心
- DNS查询:数百万个URL意味着数百万个域名,默认操作系统设置通常不够。可能需要设置本地bind9解析器
- 磁盘:如果使用调整大小,需要高达30MB/s的写入速度。如果不调整大小,则需要高达130MB/s。写入少量tar文件可以使用机械硬盘而不是SSD。
考虑到这些信息,设计选择如下:
- URL列表被分成K个分片。选择K使得每个分片在磁盘上有合理的大小(例如256MB),默认K = 10000
- 启动N个进程(使用多进程进程池)
- 每个进程启动M个线程。应该最大化M以尽可能多地使用网络,同时保持CPU使用率低于100%。
- 每个线程下载1张图片并返回
- 父线程处理调整大小(这意味着最多同时运行N个调整大小的操作,充分利用核心但不超过)
- 父线程保存到一个与其他进程不同的tar文件中
这种设计使得可以通过每个核心只进行1次调整大小来高效使用CPU资源,通过每个核心打开1个文件来减少磁盘开销,同时通过每个进程使用M个线程来尽可能多地使用带宽资源。
另请参阅architecture.md了解Python模块的精确划分。
设置高性能DNS解析器
为了获得img2dataset的最佳性能,需要使用高效的DNS解析器。
- knot解析器可以并行运行
- bind解析器是历史悠久的解析器,虽然是单核但经过高度优化
设置knot解析器
按照官方快速入门或在Ubuntu上运行以下命令:
安装knot:
wget https://secure.nic.cz/files/knot-resolver/knot-resolver-release.deb
sudo dpkg -i knot-resolver-release.deb
sudo apt update
sudo apt install -y knot-resolver
sudo sh -c 'echo `hostname -I` `hostname` >> /etc/hosts'
sudo sh -c 'echo nameserver 127.0.0.1 > /etc/resolv.conf'
sudo systemctl stop systemd-resolved
然后启动4个实例:
sudo systemctl start kresd@1.service
sudo systemctl start kresd@2.service
sudo systemctl start kresd@3.service
sudo systemctl start kresd@4.service
检查是否正常工作:
dig @localhost google.com
设置bind9解析器
为了保持高成功率,有必要使用高效的DNS解析器。 我尝试了几个选项:systemd-resolved、dnsmaskq和bind9,得出结论是bind9在这种用例下达到最佳性能。 以下是在Ubuntu上如何设置。运行:
sudo apt install bind9
sudo vim /etc/bind/named.conf.options
在options
中添加以下内容:
recursive-clients 10000;
resolver-query-timeout 30000;
max-clients-per-query 10000;
max-cache-size 2000m;
然后运行:
sudo systemctl restart bind9
echo nameserver 127.0.0.1 | sudo tee -a /etc/resolv.conf
这将使得在进行数千次DNS查询时保持高成功率成为可能。 你可能还想设置bind9日志记录以检查是否发生少量DNS错误。
AI使用影响
img2dataset用于从网上检索图像并使其易于用于机器学习用例。用例包括:
- 进行推理和索引以更好地理解网络中的内容(https://rom1504.github.io/clip-retrieval/ 是一个例子)
- 训练模型
可以使用图像/文本数据集训练的模型包括:
- CLIP:一个图像理解模型,可以用来判断图像是否安全、美观、包含什么动物等
- 文本到图像模型:根据文本生成图像
关于文本到图像模型的后果有很多讨论。一些观点包括:
- AI艺术正在使艺术民主化,让数亿人能够通过艺术表达自己。使艺术变得更加普及和独特
- AI模型不应该在创作者不愿分享的图像上进行训练
选择退出指令试图让不想分享其艺术作品的创作者不被用于索引和训练。
开发
可以在本地或gitpod中进行(在那里执行export PIP_USER=false
)
设置虚拟环境:
python3 -m venv .env
source .env/bin/activate
pip install -e .
运行测试:
pip install -r requirements-test.txt
然后
make lint
make test
你可以使用make black
重新格式化代码
python -m pytest -x -s -v tests -k "dummy"
可以运行特定测试
基准测试
10000张图片基准测试
cd tests/test_files
bash benchmark.sh
1800万张图片基准测试
首先下载crawling at home第一部分,然后:
cd tests
bash large_bench.sh
下载1800万张图片需要3.7小时
目前观察到的性能是每秒1350张图片。每小时480万张图片,每24小时1.16亿张图片。
3600万张图片基准测试
下载2个包含1800万项的parquet文件(结果936GB)花了7小时24分钟 平均每秒1345张图片
1.9亿基准测试
从crawling at home数据集下载1.9亿张图片花了41小时(结果5TB) 平均每秒1280张图片
50亿基准测试
从laion5B数据集下载58亿张图片花了7天(结果240TB),10台机器平均每秒9500个样本,技术细节
引用
@misc{beaumont-2021-img2dataset,
author = {Romain Beaumont},
title = {img2dataset: Easily turn large sets of image urls to an image dataset},
year = {2021},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/rom1504/img2dataset}}
}