数据集文档

创建图像数据集

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

创建图像数据集

有两种方法可以创建和分享图像数据集。本指南将向你展示如何

  • 使用 python 和 Dataset.push_to_hub() 从本地文件创建图像数据集。这是一种简单的方法,只需要在 python 中进行几个步骤。

  • 使用 ImageFolder 和一些元数据创建图像数据集。这是一种无需代码的解决方案,可以快速创建包含数千张图像的图像数据集。

你可以通过要求用户先分享他们的联系信息来控制对数据集的访问。查看 Gated datasets 指南,了解有关如何在 Hub 上启用此功能的更多信息。

ImageFolder

ImageFolder 是一个数据集构建器,旨在快速加载包含数千张图像的图像数据集,而无需编写任何代码。

💡 查看 Split pattern hierarchy 以了解更多关于 ImageFolder 如何根据你的数据集仓库结构创建数据集拆分的信息。

ImageFolder 会根据目录名称自动推断数据集的类别标签。将你的数据集存储在如下目录结构中:

folder/train/dog/golden_retriever.png
folder/train/dog/german_shepherd.png
folder/train/dog/chihuahua.png

folder/train/cat/maine_coon.png
folder/train/cat/bengal.png
folder/train/cat/birman.png

如果数据集遵循 ImageFolder 结构,那么你可以使用 load_dataset() 直接加载它

>>> from datasets import load_dataset

>>> dataset = load_dataset("path/to/folder")

这等同于在 load_dataset() 中手动传递 imagefolder,并在 data_dir 中传递目录

>>> dataset = load_dataset("imagefolder", data_dir="/path/to/folder")

你也可以使用 imagefolder 加载涉及多个拆分的数据集。为此,你的数据集目录应具有以下结构

folder/train/dog/golden_retriever.png
folder/train/cat/maine_coon.png
folder/test/dog/german_shepherd.png
folder/test/cat/bengal.png

如果所有图像文件都包含在单个目录中,或者它们不在同一目录结构级别,则不会自动添加 label 列。如果需要,请显式设置 drop_labels=False

如果想包含关于数据集的额外信息,例如文本描述或边界框,请将它作为 metadata.csv 文件添加到你的文件夹中。这使你可以快速为不同的计算机视觉任务(如文本描述或物体检测)创建数据集。你也可以使用 JSONL 文件 metadata.jsonl 或 Parquet 文件 metadata.parquet

folder/train/metadata.csv
folder/train/0001.png
folder/train/0002.png
folder/train/0003.png

你也可以压缩你的图像,在这种情况下,每个 zip 文件都应包含图像和元数据

folder/train.zip
folder/test.zip
folder/validation.zip

你的 metadata.csv 文件必须具有 file_name*_file_name 字段,该字段将图像文件与其元数据链接起来

file_name,additional_feature
0001.png,This is a first value of a text feature you added to your images
0002.png,This is a second value of a text feature you added to your images
0003.png,This is a third value of a text feature you added to your images

或者使用 metadata.jsonl

{"file_name": "0001.png", "additional_feature": "This is a first value of a text feature you added to your images"}
{"file_name": "0002.png", "additional_feature": "This is a second value of a text feature you added to your images"}
{"file_name": "0003.png", "additional_feature": "This is a third value of a text feature you added to your images"}

这里的 file_name 必须是元数据文件旁边图像文件的名称。更一般地,它必须是从包含元数据的目录到图像文件的相对路径。

每行数据集中可以指向多个图像,例如,如果你的输入和输出都是图像

{"input_file_name": "0001.png", "output_file_name": "0001_output.png"}
{"input_file_name": "0002.png", "output_file_name": "0002_output.png"}
{"input_file_name": "0003.png", "output_file_name": "0003_output.png"}

你也可以定义图像列表。在这种情况下,你需要将字段命名为 file_names*_file_names。这是一个例子

{"frames_file_names": ["0001_t0.png", "0001_t1.png"], label: "moving_up"}
{"frames_file_names": ["0002_t0.png", "0002_t1.png"], label: "moving_down"}
{"frames_file_names": ["0003_t0.png", "0003_t1.png"], label: "moving_right"}

图像描述

图像描述数据集包含描述图像的文本。一个 metadata.csv 示例可能如下所示:

file_name,text
0001.png,This is a golden retriever playing with a ball
0002.png,A german shepherd
0003.png,One chihuahua

使用 ImageFolder 加载数据集,它将为图像描述创建一个 text

>>> dataset = load_dataset("imagefolder", data_dir="/path/to/folder", split="train")
>>> dataset[0]["text"]
"This is a golden retriever playing with a ball"

物体检测

物体检测数据集具有边界框和类别,用于标识图像中的物体。一个 metadata.jsonl 示例可能如下所示:

{"file_name": "0001.png", "objects": {"bbox": [[302.0, 109.0, 73.0, 52.0]], "categories": [0]}}
{"file_name": "0002.png", "objects": {"bbox": [[810.0, 100.0, 57.0, 28.0]], "categories": [1]}}
{"file_name": "0003.png", "objects": {"bbox": [[160.0, 31.0, 248.0, 616.0], [741.0, 68.0, 202.0, 401.0]], "categories": [2, 2]}}

使用 ImageFolder 加载数据集,它将创建一个包含边界框和类别的 objects

>>> dataset = load_dataset("imagefolder", data_dir="/path/to/folder", split="train")
>>> dataset[0]["objects"]
{"bbox": [[302.0, 109.0, 73.0, 52.0]], "categories": [0]}

将数据集上传到 Hub

创建数据集后,你可以使用 push_to_hub() 方法将其分享到 Hub。确保你已安装 huggingface_hub 库,并且已登录到你的 Hugging Face 帐户(请参阅 使用 Python 上传教程 了解更多详细信息)。

使用 push_to_hub() 上传你的数据集

>>> from datasets import load_dataset

>>> dataset = load_dataset("imagefolder", data_dir="/path/to/folder", split="train")
>>> dataset.push_to_hub("stevhliu/my-image-captioning-dataset")

WebDataset

WebDataset 格式基于 TAR 归档,适用于大型图像数据集。实际上,你可以将图像分组到 TAR 归档中(例如,每个 TAR 归档 1GB 的图像),并拥有数千个 TAR 归档

folder/train/00000.tar
folder/train/00001.tar
folder/train/00002.tar
...

在归档中,每个示例都由共享相同前缀的文件组成

e39871fd9fd74f55.jpg
e39871fd9fd74f55.json
f18b91585c4d3f3e.jpg
f18b91585c4d3f3e.json
ede6e66b2fb59aab.jpg
ede6e66b2fb59aab.json
ed600d57fcee4f94.jpg
ed600d57fcee4f94.json
...

你可以使用 JSON 或文本文件等格式放置图像标签/描述/边界框。

加载你的 WebDataset,它将为每个文件后缀创建一个列(此处为“jpg”和“json”)

>>> from datasets import load_dataset

>>> dataset = load_dataset("webdataset", data_dir="/path/to/folder", split="train")
>>> dataset[0]["json"]
{"bbox": [[302.0, 109.0, 73.0, 52.0]], "categories": [0]}

每个示例也可以有多个图像,如下所示

e39871fd9fd74f55.input.jpg
e39871fd9fd74f55.output.jpg
e39871fd9fd74f55.json
f18b91585c4d3f3e.input.jpg
f18b91585c4d3f3e.output.jpg
f18b91585c4d3f3e.json
...

有关 WebDataset 格式和 python 库的更多详细信息,请查看 WebDataset 文档

(旧版) 加载脚本

编写数据集加载脚本以分享数据集。它定义了数据集的拆分和配置,并处理数据集的下载和生成。该脚本与数据集位于同一文件夹或仓库中,并且应具有相同的名称。

my_dataset/
├── README.md
├── my_dataset.py
└── data/  # optional, may contain your images or TAR archives

此结构允许你的数据集在一行代码中加载

>>> from datasets import load_dataset
>>> dataset = load_dataset("path/to/my_dataset")

本指南将向你展示如何为图像数据集创建数据集加载脚本,这与为文本数据集创建加载脚本略有不同。你将学习如何:

  • 创建数据集构建器类。
  • 创建数据集配置。
  • 添加数据集元数据。
  • 下载并定义数据集拆分。
  • 生成数据集。
  • 生成数据集元数据(可选)。
  • 将数据集上传到 Hub。

最好的学习方法是打开一个现有的图像数据集加载脚本,例如 Food-101,并跟随学习!

为了帮助你入门,我们创建了一个加载脚本 模板,你可以复制并用作起点!

创建数据集构建器类

GeneratorBasedBuilder 是从字典生成器生成的数据集的基础类。在此类中,有三种方法可以帮助你创建数据集

  • info 存储关于你的数据集的信息,例如其描述、许可证和特征。
  • split_generators 下载数据集并定义其拆分。
  • generate_examples 为每个拆分生成图像和标签。

首先创建一个数据集类,作为 GeneratorBasedBuilder 的子类,并添加这三种方法。不用担心现在就填写这些方法,你将在接下来的几个部分中逐步开发它们

class Food101(datasets.GeneratorBasedBuilder):
    """Food-101 Images dataset"""

    def _info(self):

    def _split_generators(self, dl_manager):

    def _generate_examples(self, images, metadata_path):

多个配置

在某些情况下,一个数据集可能具有多个配置。例如,如果你查看 Imagenette 数据集,你会注意到有三个子集。

要创建不同的配置,请使用 BuilderConfig 类为你的数据集创建一个子类。在 data_urlmetadata_urls 中提供下载图像和标签的链接

class Food101Config(datasets.BuilderConfig):
    """Builder Config for Food-101"""
 
    def __init__(self, data_url, metadata_urls, **kwargs):
        """BuilderConfig for Food-101.
        Args:
          data_url: `string`, url to download the zip file from.
          metadata_urls: dictionary with keys 'train' and 'validation' containing the archive metadata URLs
          **kwargs: keyword arguments forwarded to super.
        """
        super(Food101Config, self).__init__(version=datasets.Version("1.0.0"), **kwargs)
        self.data_url = data_url
        self.metadata_urls = metadata_urls

现在你可以在 GeneratorBasedBuilder 的顶部定义你的子集。假设你想在 Food-101 数据集中创建两个子集,基于它是早餐食物还是晚餐食物。

  1. BUILDER_CONFIGS 的列表中使用 Food101Config 定义你的子集。
  2. 对于每个配置,提供名称、描述以及从何处下载图像和标签。
class Food101(datasets.GeneratorBasedBuilder):
    """Food-101 Images dataset"""
 
    BUILDER_CONFIGS = [
        Food101Config(
            name="breakfast",
            description="Food types commonly eaten during breakfast.",
            data_url="https://link-to-breakfast-foods.zip",
            metadata_urls={
                "train": "https://link-to-breakfast-foods-train.txt", 
                "validation": "https://link-to-breakfast-foods-validation.txt"
            },
        ,
        Food101Config(
            name="dinner",
            description="Food types commonly eaten during dinner.",
            data_url="https://link-to-dinner-foods.zip",
            metadata_urls={
                "train": "https://link-to-dinner-foods-train.txt", 
                "validation": "https://link-to-dinner-foods-validation.txt"
            },
        )...
    ]

现在,如果用户想加载 breakfast 配置,他们可以使用配置名称

>>> from datasets import load_dataset
>>> ds = load_dataset("ethz/food101", "breakfast", split="train")

添加数据集元数据

添加关于你的数据集的信息对于用户了解更多信息很有用。此信息存储在 DatasetInfo 类中,该类由 info 方法返回。用户可以通过以下方式访问此信息:

>>> from datasets import load_dataset_builder
>>> ds_builder = load_dataset_builder("ethz/food101")
>>> ds_builder.info

你可以指定关于数据集的许多信息,但一些重要的信息包括:

  1. description 提供数据集的简洁描述。
  2. features 指定数据集列类型。由于你正在创建图像加载脚本,因此你需要包含 Image 特征。
  3. supervised_keys 指定输入特征和标签。
  4. homepage 提供数据集主页的链接。
  5. citation 是数据集的 BibTeX 引用。
  6. license 说明数据集的许可证。

你会注意到许多数据集信息在加载脚本的早期就已定义,这使其更易于阅读。还有其他你可以输入的 ~Datasets.Features,因此请务必查看完整列表以获取更多详细信息。

def _info(self):
    return datasets.DatasetInfo(
        description=_DESCRIPTION,
        features=datasets.Features(
            {
                "image": datasets.Image(),
                "label": datasets.ClassLabel(names=_NAMES),
            }
        ),
        supervised_keys=("image", "label"),
        homepage=_HOMEPAGE,
        citation=_CITATION,
        license=_LICENSE,

    )

下载并定义数据集拆分

既然您已经添加了一些关于数据集的信息,下一步是下载数据集并生成拆分。

  1. 使用 DownloadManager.download() 方法下载数据集以及您想要关联的任何其他元数据。此方法接受:

    • Hub 数据集仓库中文件的名称(换句话说,data/ 文件夹)
    • 托管在其他位置的文件的 URL
    • 文件名或 URL 的列表或字典

    在 Food-101 加载脚本中,您会再次注意到 URL 在脚本的早期定义。

  2. 下载数据集后,使用 SplitGenerator 来组织每个拆分中的图像和标签。使用标准名称命名每个拆分,例如:Split.TRAINSplit.TESTSPLIT.Validation

    gen_kwargs 参数中,指定要迭代和加载的 images 文件路径。如有必要,您可以使用 DownloadManager.iter_archive() 来迭代 TAR 存档中的图像。您还可以在 metadata_path 中指定关联的标签。imagesmetadata_path 实际上会传递到下一步,您将在下一步实际生成数据集。

要流式传输 TAR 存档文件,您需要使用 DownloadManager.iter_archive()DownloadManager.download_and_extract() 函数不支持流式模式下的 TAR 存档。

def _split_generators(self, dl_manager):
    archive_path = dl_manager.download(_BASE_URL)
    split_metadata_paths = dl_manager.download(_METADATA_URLS)
    return [
        datasets.SplitGenerator(
            name=datasets.Split.TRAIN,
            gen_kwargs={
                "images": dl_manager.iter_archive(archive_path),
                "metadata_path": split_metadata_paths["train"],
            },
        ),
        datasets.SplitGenerator(
            name=datasets.Split.VALIDATION,
            gen_kwargs={
                "images": dl_manager.iter_archive(archive_path),
                "metadata_path": split_metadata_paths["test"],
            },
        ),
    ]

生成数据集

GeneratorBasedBuilder 类中的最后一个方法实际上会生成数据集中的图像和标签。它根据 info 方法中 features 指定的结构生成数据集。如您所见,generate_examples 接受上一个方法中的 imagesmetadata_path 作为参数。

要流式传输 TAR 存档文件,需要先打开并读取 metadata_path。TAR 文件是按顺序访问和生成的。这意味着您需要首先掌握元数据信息,以便将其与其对应的图像一起生成。

现在您可以编写一个函数,用于从数据集打开和加载示例

def _generate_examples(self, images, metadata_path):
    """Generate images and labels for splits."""
    with open(metadata_path, encoding="utf-8") as f:
        files_to_keep = set(f.read().split("\n"))
    for file_path, file_obj in images:
        if file_path.startswith(_IMAGES_DIR):
            if file_path[len(_IMAGES_DIR) : -len(".jpg")] in files_to_keep:
                label = file_path.split("/")[2]
                yield file_path, {
                    "image": {"path": file_path, "bytes": file_obj.read()},
                    "label": label,
                }

生成数据集元数据(可选)

数据集元数据可以生成并存储在数据集卡片(README.md 文件)中。

运行以下命令以在 README.md 中生成数据集元数据,并确保您的新加载脚本工作正常:

datasets-cli test path/to/<your-dataset-loading-script> --save_info --all_configs

如果您的加载脚本通过了测试,您现在应该在数据集文件夹中 README.md 文件的标头中看到 dataset_info YAML 字段。

将数据集上传到 Hub

脚本准备就绪后,创建数据集卡片将其上传到 Hub

恭喜,您现在可以从 Hub 加载您的数据集了! 🥳

>>> from datasets import load_dataset
>>> load_dataset("<username>/my_dataset")
< > 在 GitHub 上更新