10. 介绍 Decord: 一个高效的视频读取器

在视频上训练深度神经网络非常耗时。例如,使用配备 8 块 V100 GPU 的服务器在 Kinetics400 数据集上训练最先进的 SlowFast 网络需要 10 天以上。慢速训练导致研究周期长,对新手和学生研究视频相关问题不友好。造成速度慢的原因有几个:大数据批次、视频读取器效率低下以及巨大的模型计算量。

另一个令人头疼的问题是复杂的数据预处理和巨大的存储成本。以 Kinetics400 数据集为例,该数据集包含约 24 万个训练视频和 2 万个验证视频。所有视频占用 450G 磁盘空间。然而,如果我们把视频解码成帧,并使用图像加载器来训练模型,解码后的帧将占用 6.8T 磁盘空间,这是大多数人无法接受的。此外,解码过程也很慢。使用 60 个 worker 需要 1.5 天才能将所有视频解码成帧。如果我们使用 8 个 worker(就像在普通笔记本电脑或标准工作站中一样),甚至在实际训练开始之前,进行这样的数据预处理就需要一周时间。

鉴于上述挑战,在本教程中,我们介绍了一种新的视频读取器:Decord。Decord 高效且灵活。它提供基于硬件加速视频解码器(例如 FFMPEG/LibAV 和 Nvidia Codecs)包装的便捷视频切片方法。它旨在解决繁琐的视频打乱体验,从而为深度学习提供类似于随机图像加载器的流畅体验。此外,它还跨平台工作,例如 Linux、Windows 和 Mac OS。有了新的视频读取器,您不再需要将视频解码成帧,只需在视频数据集上开始训练,训练速度甚至会更快。

安装

Decord 易于安装,只需

pip install decord

用法

我们在这里提供一些用法示例,帮助您入门。有关完整的 API,请参阅官方文档。

假设我们要读取一个视频。首先下载示例视频。

from gluoncv import utils
url = 'https://github.com/bryanyzhu/tiny-ucf101/raw/master/abseiling_k400.mp4'
video_fname = utils.download(url)

from decord import VideoReader
vr = VideoReader(video_fname)

输出

Downloading abseiling_k400.mp4 from https://github.com/bryanyzhu/tiny-ucf101/raw/master/abseiling_k400.mp4...

  0%|          | 0/782 [00:00<?, ?KB/s]
100%|##########| 782/782 [00:00<00:00, 77468.66KB/s]

如果我们要以特定维度加载视频,以便将其馈送到 CNN 进行处理,

vr = VideoReader(video_fname, width=320, height=256)

现在我们已经加载了视频,如果想知道视频中有多少帧,

duration = len(vr)
print('The video contains %d frames' % duration)

输出

The video contains 250 frames

如果我们要访问索引为 10 的帧,

frame = vr[9]
print(frame.shape)

输出

(256, 320, 3)

对于深度学习,通常我们希望一次获取多个帧。现在可以使用 get_batch 函数。假设我们想通过跳过中间的一帧来获取一个包含 32 帧的视频片段,

frame_id_list = range(0, 64, 2)
frames = vr.get_batch(frame_id_list).asnumpy()
print(frames.shape)

输出

(32, 256, 320, 3)

还有另一个高级功能,您可以按如下方式获取所有关键帧,

key_indices = vr.get_key_indices()
key_frames = vr.get_batch(key_indices)
print(key_frames.shape)

输出

(1, 256, 320, 3)

非常灵活,对吧?在您的视频上试试吧。

速度对比

现在我们将 Decord 的速度与 Opencv VideoCapture 进行比较,以展示其效率。我们将使用这两种解码器加载同一个视频并随机获取所有帧,以比较它们的性能。我们将加载 11 次:第一次用于热身,其余 10 次的平均值作为平均速度。

import cv2
import time
import numpy as np

frames_list = np.arange(duration)
np.random.shuffle(frames_list)

# Decord
for i in range(11):
    if i == 1:
        start_time = time.time()
    decord_vr = VideoReader(video_fname)
    frames = decord_vr.get_batch(frames_list)
end_time = time.time()
print('Decord takes %4.4f seconds.' % ((end_time - start_time)/10))

# OpenCV
for i in range(11):
    if i == 1:
        start_time = time.time()
    cv2_vr = cv2.VideoCapture(video_fname)
    for frame_idx in frames_list:
        cv2_vr.set(1, frame_idx)
        _, frame = cv2_vr.read()
    cv2_vr.release()
end_time = time.time()
print('OpenCV takes %4.4f seconds.' % ((end_time - start_time)/10))

输出

Decord takes 3.5792 seconds.
OpenCV takes 0.0002 seconds.

我们可以看到 Decord 比 OpenCV VideoCapture 快 2 倍。我们还与 Pyav container 进行了比较,同样展示了 2 倍的加速。

总之,Decord 是一个高效且灵活的视频读取器。它支持 get_batch、GPU 加载、快速随机访问等,完美设计用于训练视频深度神经网络。我们在大型数据集的视频模型训练中使用了 Decord,观察到其速度与在解码后的视频帧上使用图像加载器相似。这显著减少了大规模视频数据集的数据预处理时间和存储成本。

脚本总运行时间:( 0 分 39.780 秒)

图库由 Sphinx-Gallery 生成