在机器学习和深度学习领域,视频数据的准备工作至关重要。鉴于视频数据庞大的体量和高昂的计算成本,针对特定应用场景对其进行高效处理变得尤为关键。这涉及多方面任务,例如元数据分析、数据标准化、数据增强、镜头与对象检测以及张量加载等。本文将深入探讨这些处理方法及其背后的必要性。为此,一个名为 vid-prepper 的开源 Python 工具包应运而生。该工具包旨在为视频数据提供快速高效的预处理技术,它整合了机器学习和深度学习领域诸多顶尖成果,将它们汇聚在一个通用且易于使用的框架中,极大地便利了开发者。
视频在数据处理领域扮演着日益重要的角色。数据专家们曾在一家为顶尖视频公司(例如 NPAW)构建视频分析 SaaS 平台的公司开启数据职业生涯,并随后在英国广播公司(BBC)等知名机构工作,积累了丰富的视频处理经验。当前,视频内容在互联网上占据主导地位,尽管人工智能在视频领域的应用仍处于发展初期,但其增长速度惊人。为了加速研究人员和开发者在该有趣领域进行探索和贡献,开发高效工具成为了迫切需求。本文将从元数据分析开始,详细介绍 vid-prepper 工具包不同模块的功能及其使用方法。
元数据分析
from vid_prepper import metadata
在专业机构如英国广播公司(BBC),视频制作团队能够产出广播级的优质视频。然而,实际情况是,大多数视频数据并非如此理想。视频文件常常混合着不同的格式、色彩空间和尺寸,甚至可能出现损坏、部分内容缺失,或包含来自旧视频的特殊问题,例如隔行扫描。在对视频数据进行机器学习处理之前,充分了解并识别这些潜在问题至关重要。
深度学习模型的训练通常依赖于图形处理器(GPU),GPU在大规模张量计算方面表现出色,但其运行成本也相对较高。在GPU上训练大型模型时,为了避免高昂的开销,实现尽可能高的效率至关重要。如果视频数据包含损坏文件或是不支持的格式,不仅会浪费时间和资源,还可能降低模型的准确性,甚至导致整个训练流程中断。因此,在正式处理之前对文件进行检查和筛选是必不可少的步骤。

元数据分析几乎总是视频数据准备过程中的重要第一步。(图片来源:Pexels)
vid-prepper 工具包中的元数据分析模块是基于 ffprobe 库构建的,而 ffprobe 又是用 C 语言和汇编语言编写的 FFmpeg 库的一部分。FFmpeg 是一个功能强大且高效的库,在专业领域被广泛应用。该模块能够对单个视频文件或批量视频文件进行分析,具体使用方法如下面的代码示例所示。
# Extract metadata
video_path = [“sample.mp4”]
video_info = metadata.Metadata.validate_videos(video_path)
# Extract metadata batch
video_paths = [“sample1.mp4”, “sample2.mp4”, “sample3.mp4”]
video_info = metadata.Metadata.validate_videos(video_paths)
通过上述方法,工具包将输出一个包含视频元数据的字典,其中包括编解码器、分辨率、帧率、时长、像素格式、音频元数据等详细信息。这些元数据对于识别存在问题或异常的视频数据极其有用。此外,它还能帮助用户精确选择特定视频数据,或根据常用标准决定统一的格式和编解码器,从而提高数据处理的效率和一致性。
基于元数据问题进行筛选
鉴于对视频列表进行筛选是一个常见需求,vid-prepper 工具包内置了根据一系列检查条件筛选视频的功能。例如,当视频或音频缺失、编解码器或格式不符合指定要求,或者帧率或时长与设定值不一致时,通过设置 filter 和 only_errors 参数,即可轻松识别出这些有问题的视频,具体示例如下。
# Run tests on videos
videos = ["video1.mp4", "video2.mkv", "video3.mov"]
all_filters_with_params = {
"filter_missing_video": {},
"filter_missing_audio": {},
"filter_variable_framerate": {},
"filter_resolution": {"min_width": 1280, "min_height": 720},
"filter_duration": {"min_seconds": 5.0},
"filter_pixel_format": {"allowed": ["yuv420p", "yuv422p"]},
"filter_codecs": {"allowed": ["h264", "hevc", "vp9", "prores"]}
}
errors = Metadata.validate_videos(
videos,
filters=all_filters_with_params,
only_errors=True
)
在进入模型训练这一计算密集型工作之前,通过移除或识别数据中的问题,可以有效避免时间和金钱的浪费,使其成为数据预处理过程中至关重要的第一步。
标准化处理
from vid_prepper import standardize
在视频机器学习的预处理阶段,标准化通常是一个相当重要的环节。它能够显著提升处理效率和数据一致性,并且深度学习模型往往对输入数据的尺寸有特定要求(例如 224 x 224)。如果拥有大量视频数据,那么在此阶段投入的时间和精力,将在后续的模型训练阶段获得数倍的回报。

标准化视频数据可以大幅提高处理效率并获得更好的结果。(图片来源:Pexels)
编解码器
视频文件通常经过结构化处理,以实现互联网上的高效存储和分发,从而确保低成本和快速传输。这通常涉及高强度的压缩,旨在将视频文件体积最小化。然而,这种优化策略与深度学习对视频数据的需求几乎是完全相反的。
在深度学习任务中,主要的性能瓶颈几乎总是出现在视频解码和将其加载到张量的环节。因此,视频文件压缩程度越高,解码所需的时间就越长,效率也就越低。这意味着在选择编解码器时,通常应避免使用 H265 和 VVC 等超高压缩率的格式。相反,推荐选择 H264 或 VP9 这类具备硬件加速能力的轻量级压缩格式。如果能够有效避免I/O瓶颈,使用未压缩的 MJPEG 格式也是一个非常高效的选择,因为它是将帧加载到张量中速度最快的方法之一,常用于生产环境。
帧率
视频的标准帧率(FPS)通常设定为:电影为 24 帧每秒,电视和在线内容为 30 帧每秒,而快速运动内容则达到 60 帧每秒。这些帧率的设定是为了确保每秒显示足够数量的图像,使人眼感知到流畅的运动。然而,深度学习模型在训练视频中并不一定需要如此高的帧率,也能有效创建运动的数值表示并生成流畅的视频。鉴于每一帧都意味着额外的张量计算量,因此在不影响模型性能的前提下,应尽可能将帧率降至最低。
视频类型以及模型的使用场景将共同决定帧率可以降低的程度。视频中运动量越小,在不影响结果的前提下,输入帧率就可以设置得越低。例如,一个包含演播室新闻片段或访谈节目的数据集,其所需的帧率会低于由冰球比赛组成的体育数据集。此外,如果研究工作聚焦于视频理解或视频到文本的模型,而非生成供人类观看的视频,那么帧率甚至可以设置得更低,以进一步优化计算效率。
计算最小帧率
实际上,可以基于运动统计数据,通过数学方法为视频数据集确定一个相当理想的最小帧率。具体做法是,在数据集的样本上运用 RAFT 或 Farneback 算法,计算每个帧变化时每个像素的光流。这提供了每个像素的水平和垂直位移,进而可以计算出变化的幅度(即平方值之和的平方根)。
将每个帧上的光流幅度值进行平均,即可得到该帧的“帧动量”。随后,计算所有帧动量的中位数和第 95 百分位数,这些数值可以代入以下公式,从而获得训练数据可能的最优最小帧率范围。
Optimal FPS (Lower) = Current FPS x Max model interpolation rate / Median momentum
Optimal FPS (Higher) = Current FPS x Max model interpolation rate / 95th percentile momentum
其中,“最大模型插值率”指的是模型能够处理的每帧最大动量,该数值通常在模型卡(model card)中提供。

计算动量原理上仅需运用勾股定理,并非高深的数学。(图片来源:Pexels)
随后,可以对训练管线进行小规模测试,以确定在保证最优性能的前提下能够实现的最低帧率。
Vid Prepper 工具包
vid-prepper 工具包中的标准化模块能够对单个视频或批量视频的尺寸、编解码器、色彩格式以及帧率进行统一标准化处理。
同样,此模块也构建于 FFmpeg 之上,并且在具备 GPU 条件时,能够利用 GPU 进行加速处理。要对视频进行标准化,只需运行以下代码即可。
# Standardize batch of videos
video_file_paths = [“sample1.mp4”, “sample2.mp4”, “sample3.mp4”]
standardizer = standardize.VideoStandardizer(
size="224x224",
fps=16,
codec="h264",
color="rgb",
use_gpu=False # Set to True if you have CUDA
)
standardizer.batch_standardize(videos=video_file_paths, output_dir="videos/")
为了进一步提高效率,尤其是在使用昂贵的 GPU 且希望避免视频加载带来的 I/O 瓶颈时,该模块还支持处理 webdatasets。webdatasets 的加载方式类似于以下代码示例:
# Standardize webdataset
standardizer = standardize.VideoStandardizer(
size="224x224",
fps=16,
codec="h264",
color="rgb",
use_gpu=False # Set to True if you have CUDA
)
standardizer.standardize_wds("dataset.tar", key="mp4", label="cls")
张量加载器
from vid_prepper import loader
视频张量通常是 4 维或 5 维的,包含像素颜色(通常为 RGB)、帧的高度和宽度、时间以及批次(可选)等组成部分。如前所述,将视频解码为张量往往是预处理管线中最大的性能瓶颈。因此,在此之前所采取的各项步骤对于张量加载的效率具有决定性的影响。
此模块利用 FFmpeg 进行帧采样,并结合 NVDec 实现 GPU 加速,将视频转换为 PyTorch 张量。用户可以根据模型需求调整张量的大小,并选择每个视频片段的采样帧数以及帧步幅(帧之间的间隔)。与标准化模块类似,此加载器也支持使用 webdatasets。以下代码展示了具体操作示例。
# Load clips into tensors
loader = VideoLoader(num_frames=16, frame_stride=2, size=(224,224), device="cuda")
video_paths = ["video1.mp4", "video2.mp4", "video3.mp4"]
batch_tensor = loader.load_files(video_paths)
# Load webdataset into tensors
wds_path = "data/shards/{00000..00009}.tar"
dataset = loader.load_wds(wds_path, key="mp4", label="cls")
检测器
from vid_prepper import detector
在视频预处理中,通常需要对视频内容中的特定元素进行检测。这些元素可能包括特定的对象、镜头切换或转场效果。vid-prepper 工具包的检测模块整合了 PySceneDetector、HuggingFace、IDEA Research 和 PyTorch 等多个强大框架和模型,旨在提供高效的检测能力。

视频检测通常是一种有效的方法,用于将视频分割成独立的片段,并仅提取模型所需的特定片段。(图片来源:Pexels)
镜头检测
在许多视频机器学习应用场景中(例如语义搜索、seq2seq 预告片生成等),将视频分割成独立的镜头是一个重要步骤。实现这一目标有多种方法,其中 PySceneDetect 是更为准确和可靠的选择之一。vid-prepper 库通过调用以下方法,为 PySceneDetect 的内容检测功能提供了封装。该方法会输出每个镜头的起始帧和结束帧。
# Detect shots in videos
video_path = "video.mp4"
detector = VideoDetector(device="cuda")
shot_frames = detector.detect_shots(video_path)
转场检测
尽管 PySceneDetect 是一个将视频分割成独立场景的强大工具,但其准确性并非总是百分之百。在某些情况下,可以利用重复性内容(例如转场效果)来进一步辅助镜头分割。例如,BBC 新闻节目中片段间向上滑动的红白转场,就能够利用 PyTorch 等工具轻松检测出来。
转场检测直接在张量上进行操作,通过检测像素块中超出用户设定阈值的像素变化来识别转场。下面的代码示例展示了其工作原理。
# Detect gradual transitions/wipes
video_path = "video.mp4"
video_loader = loader.VideoLoader(num_frames=16,
frame_stride=2,
size=(224, 224),
device="cpu",
use_nvdec=False # Use "cuda" if available)
video_tensor = loader.load_file(video_path)
detector = VideoDetector(device="cpu" # or cuda)
wipe_frames = detector.detect_wipes(video_tensor,
block_grid=(8,8),
threshold=0.3)
对象检测
对象检测在视频数据中寻找所需片段时常常是必不可少的一环。例如,用户可能需要包含人物或动物的视频片段。此方法利用开源的 Dino 模型,结合标准 COCO 数据集标签中的一小部分对象进行检测。模型选择和对象列表均可完全自定义。模型加载器基于 HuggingFace transformers 包,因此所使用的模型需要在该平台上可用。对于自定义标签,默认模型在 text_queries 参数中接受形如 “dog. cat. ambulance.” 的字符串结构。
# Detect objects in videos
video_path = "video.mp4"
video_loader = loader.VideoLoader(num_frames=16,
frame_stride=2,
size=(224, 224),
device="cpu",
use_nvdec=False # Use "cuda" if available)
video_tensor = loader.load_file(video_path)
detector = VideoDetector(device="cpu" # or cuda)
results = detector.detect_objects(video,
text_queries=text_queries # if None will default to COCO list,
text_threshold=0.3,
model_id=”IDEA-Research/grounding-dino-tiny”)
数据增强
视频 Transformer 模型等技术功能强大,能够用于创建卓越的新模型。然而,这些模型通常需要海量数据,而视频数据往往难以轻松获取。在这种情况下,需要一种方法来生成多样化的数据,以防止模型过拟合。数据增强正是解决数据有限性问题的一种有效方案。
针对视频数据,存在多种标准的数据增强方法,并且大多数主流框架都提供了支持。Vid-prepper 工具包整合了其中两个顶尖库:Kornia 和 Torchvision。借助 Vid-prepper,用户可以执行各种独立的增强操作,例如裁剪、翻转、镜像、填充、高斯模糊、调整亮度、色彩、饱和度和对比度,以及粗略丢弃(即遮蔽视频帧的某些部分)。此外,用户还可以将这些操作链式组合,以实现更高的处理效率。
所有数据增强操作均直接在视频张量上进行,而非直接修改视频文件,并且在具备 GPU 条件时支持 GPU 加速。以下代码示例展示了如何单独调用这些方法以及如何将它们链式组合使用。
# Individual Augmentation Example
video_path = "video.mp4"
video_loader = loader.VideoLoader(num_frames=16,
frame_stride=2,
size=(224, 224),
device="cpu",use_nvdec=False # Use "cuda" if available)
video_tensor = loader.load_file(video_path)
video_augmentor = augmentor.VideoAugmentor(device="cpu", use_gpu=False)
cropped = augmentor.crop(video_tensor, type="center", size=(200, 200))
flipped = augmentor.flip(video_tensor, type="horizontal")
brightened = augmentor.brightness(video_tensor, amount=0.2)
# Chained Augmentations
augmentations = [
('crop', {'type': 'random', 'size': (180, 180)}),
('flip', {'type': 'horizontal'}),
('brightness', {'amount': 0.1}),
('contrast', {'amount': 0.1})
]
chained_result = augmentor.chain(video_tensor, augmentations)
总结
在深度学习领域,视频预处理的重要性不言而喻,这主要源于视频数据相较于文本数据而言巨大的体量。Transformer 模型对海量数据的需求,进一步凸显了视频预处理的关键作用。深度学习过程主要涉及三个核心要素:时间、金钱和性能。通过优化输入视频数据,可以最大限度地减少前两个要素的投入,从而在最后一个要素——性能上获得最佳产出。
