Datasets documentation
加载视频数据
加载视频数据
视频支持目前处于实验阶段,可能会发生变化。
视频数据集包含 Video 类型的列,其中包含 torchcodec 对象。
要处理视频数据集,您需要安装
torchcodec和ffmpeg包。请参阅 安装 指南了解如何安装它们。
加载视频数据集并调用视频列时,视频会解码为 torchcodec 视频:
>>> from datasets import load_dataset, Video
>>> dataset = load_dataset("path/to/video/folder", split="train")
>>> dataset[0]["video"]
<torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61d5a0>首先使用行索引,然后使用
video列来索引视频数据集 -dataset[0]["video"]- 以避免创建数据集中的所有视频对象。否则,如果数据集很大,这可能是一个缓慢且耗时的过程。
有关如何加载任意类型数据集的指南,请参阅通用加载指南。
读取帧
使用 VideoReader 并通过 next() 直接从视频中访问帧:
>>> video = dataset[0]["video"]
>>> first_frame = video.get_frame_at(0)
>>> first_frame.data.shape
(3, 240, 320)
>>> first_frame.pts_seconds # timestamp
0.0要一次性获取多帧,可以调用 .get_frames_in_range(start: int, stop: int, step: int)。这将返回一个帧批次。
这是获取长帧列表的高效方式,请参阅 torchcodec 文档 以了解更多高效访问数据的函数:
>>> import torch
>>> frames = video.get_frames_in_range(0, 6, 1)
>>> frames.data.shape
torch.Size([5, 3, 240, 320])此外,还可以使用 .get_frames_played_in_range(start_seconds: float, stop_seconds: float) 来访问在特定时间范围内播放的所有帧。
>>> frames = video.get_frames_played_in_range(.5, 1.2)
>>> frames.data.shape
torch.Size([42, 3, 240, 320])本地文件
您可以从视频路径加载数据集。使用 cast_column() 函数接受一个包含视频文件路径的列,并使用 Video 特征将其解码为 torchcodec 视频:
>>> from datasets import Dataset, Video
>>> dataset = Dataset.from_dict({"video": ["path/to/video_1", "path/to/video_2", ..., "path/to/video_n"]}).cast_column("video", Video())
>>> dataset[0]["video"]
<torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61e080>如果只想加载视频数据集的底层路径而不解码视频对象,请在 Video 特征中设置 decode=False:
>>> dataset = dataset.cast_column("video", Video(decode=False))
>>> dataset[0]["video"]
{'bytes': None,
'path': 'path/to/video/folder/video0.mp4'}VideoFolder
您还可以使用 VideoFolder 数据集构建器来加载数据集,这无需编写自定义的数据加载器。这使得 VideoFolder 非常适合快速创建和加载包含数千个视频的数据集,以用于不同的视觉任务。您的视频数据集结构应如下所示:
folder/train/dog/golden_retriever.mp4
folder/train/dog/german_shepherd.mp4
folder/train/dog/chihuahua.mp4
folder/train/cat/maine_coon.mp4
folder/train/cat/bengal.mp4
folder/train/cat/birman.mp4如果数据集遵循 VideoFolder 结构,则可以直接使用 load_dataset() 加载:
>>> from datasets import load_dataset
>>> dataset = load_dataset("username/dataset_name")
>>> # OR locally:
>>> dataset = load_dataset("/path/to/folder")对于本地数据集,这相当于在 load_dataset() 中手动传入 videofolder 以及 data_dir 中的目录:
>>> dataset = load_dataset("videofolder", data_dir="/path/to/folder")然后,您可以将视频作为 torchcodec.decoders._video_decoder.VideoDecoder 对象进行访问:
>>> dataset["train"][0]
{"video": <torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61e080>, "label": 0}
>>> dataset["train"][-1]
{"video": <torchcodec.decoders._video_decoder.VideoDecoder object at 0x14a61e090>, "label": 1}若要忽略元数据文件中的信息,请在 load_dataset() 中设置 drop_metadata=True:
>>> from datasets import load_dataset
>>> dataset = load_dataset("username/dataset_with_metadata", drop_metadata=True)如果没有元数据文件,VideoFolder 会自动从目录名称推断标签名称。
如果要丢弃自动创建的标签,请设置 drop_labels=True。
在这种情况下,您的数据集将只包含一个视频列:
>>> from datasets import load_dataset
>>> dataset = load_dataset("username/dataset_without_metadata", drop_labels=True)最后,filters 参数允许你基于标签或元数据中的条件,仅加载数据集的一个子集。如果元数据采用 Parquet 格式,这一点尤其有用,因为该格式支持快速过滤。同时,建议将此参数与 streaming=True 一起使用,因为默认情况下,数据集会在过滤之前被完整下载。
>>> filters = [("label", "=", 0)]
>>> dataset = load_dataset("username/dataset_name", streaming=True, filters=filters)有关创建自己的
VideoFolder数据集的更多信息,请参阅 创建视频数据集 指南。
WebDataset
WebDataset 格式基于 TAR 归档文件夹,适用于大型视频数据集。
由于其体积庞大,WebDataset 通常以流式模式加载(使用 streaming=True)。
您可以按以下方式加载 WebDataset:
>>> from datasets import load_dataset
>>> dataset = load_dataset("webdataset", data_dir="/path/to/folder", streaming=True)Lance
Lance 是一种开放的多模态数据湖仓表格式。Lance 表不仅可以原生存储文本和标量值,还可以与您的表格数据一起存储大型二进制对象(blobs),例如图像、音频和视频。在 Lance 表中,像视频这样的大型 blob 以带有偏移量的字节形式存储(有关更多详细信息,请参阅 blob 指南),这使得您可以轻松扫描和过滤元数据,而无需加载较重的视频 blob,然后仅按需获取您需要的特定视频 blob。
此外,由于 Lance 是一种列式格式,您可以仅投影和筛选所需的元数据列(而无需获取大型视频文件),然后在准备好时再检索包含视频的一小部分行。这样可以将元数据和视频集中存储在一处,无需单独的文件存储或外部索引。
import lance
ds = lance.dataset("hf://datasets/lance-format/openvid-lance/data/train.lance")
# 1. Browse metadata without loading video blobs.
metadata = ds.scanner(
columns=["caption", "aesthetic_score"],
filter="aesthetic_score >= 4.5",
limit=2,
).to_table().to_pylist()
# 2. Fetch a single video blob by row index.
selected_index = 0
blob_file = ds.take_blobs("video_blob", ids=[selected_index])[0]
with open("video_0.mp4", "wb") as f:
f.write(blob_file.read())在此示例中,视频以原生形式(即其编码后的字节)存储在 Lance 表中,因此您可以直接将其写入本地文件系统中的 mp4 文件,无需任何额外的转换步骤。
有关使用 Lance 数据集的更多详细信息,请参阅 Lance 文档。
视频解码
默认情况下,当您在数据集上迭代时,视频会作为 VideoDecoders 按顺序解码。
它会按顺序解码视频的元数据,直到您访问视频帧之前,不会读取视频帧。
不过,可以使用多线程解码来显著加快数据集的处理速度:
>>> import os
>>> num_threads = num_threads = min(32, (os.cpu_count() or 1) + 4)
>>> dataset = dataset.decode(num_threads=num_threads)
>>> for example in dataset: # up to 20 times faster !
... ...您可以使用 num_threads 来启用多线程。这对于加速远程数据流式传输特别有用。
但对于位于高速磁盘上的本地数据,它可能比 num_threads=0 更慢。
如果您对以 torchcodec VideoDecoders 解码的视频不感兴趣,而是希望访问路径/字节,则可以禁用解码:
>>> dataset = dataset.decode(False)注意:IterableDataset.decode() 目前仅适用于流式数据集。
Update on GitHub