FineVideo:幕后故事

发布于 2024 年 9 月 23 日
在 GitHub 上更新
FineVideo logo

开放的视频数据集稀缺,这减缓了开源视频 AI 的发展。因此,我们构建了 FineVideo,一个包含 4.3 万个视频、总时长 3.4 千小时的数据集,并附有丰富的描述、叙事细节、场景切分和问答对。

FineVideo 包含高度多样化的视频和元数据集合,使其成为训练模型理解视频内容、训练扩散模型从文本描述生成视频,或使用其结构化数据作为输入训练计算机视觉模型的优质素材。

等等,你还没看过 FineVideo 吗?快通过数据集浏览器页面了解一下吧。


FineVideo Explorer

目录

关于这篇博文

在这篇博文中,我们分享了开发 FineVideo 涉及的技术细节和代码:这段旅程始于 YouTube-Commons 中的 190 万个视频,最终得到了 4.4 万个带有详尽标注的视频。

一个好的开始方式是先了解我们整个过程的不同步骤。这些步骤涉及内容筛选、标注和输出结构化。


Dataset Creation
FineVideo 视频筛选和标注流程


在接下来的章节中,我们将讨论每个步骤,并提供相关代码的参考链接。如果你更喜欢直接浏览代码,请查看我们在 Github 上的 FineVideo 代码仓库。

首先,让我们看看我们如何获取初始的 YouTube 视频列表,以及如何应用初步的筛选。

构建原始数据集

我们的旅程始于 YouTube-Commons:这是一个收录了在 YouTube 上以 CC-By 许可证共享的视频的音频转录文本的集合。该项目由 PleIAs 创建并维护,作为其语料库收集项目的一部分。

筛选 YouTube-Commons

YouTube Commons 包含多种语言的视频和转录文本,我们最初的任务是将其中的内容缩小到同一种语言。

我们筛选出 YouTube-Commons 中的英语视频,并同时收集相关元数据。通过这次初步筛选,我们收集了 190 万个视频及其隐藏式字幕和元数据。

以下是我们保留的筛选条件和元数据字段的一些详细信息

筛选条件

字段 筛选值 描述
original_language en 英语视频
transcription_language en 英语字幕

元数据字段

点击展开元数据字段
字段 描述
acodec 音频编解码器
age_limit YouTube 视频的年龄限制
categories YouTube 视频分类
channel YouTube 频道
channel_follower_count 频道订阅用户数
channel_id YouTube 频道标识符
character_count 隐藏式字幕中的字符数
comment_count YouTube 中的评论数
description YouTube 视频描述
duration_string 视频时长,格式为 hh:mm:ss
许可证 视频许可证
like_count YouTube 上的视频点赞数
resolution 视频的像素分辨率,格式为“宽 x 高”
tags 与视频关联的 YouTube 自由文本标签
text 隐藏式字幕
title YouTube 视频标题
upload_date YouTube 上传日期
vcodec 视频编解码器
video_id YouTube 视频标识符
view_count YouTube 上的观看次数
word_count 隐藏式字幕中的单词数

内容筛选和元数据收集的代码可在此处获取 [链接]

下载视频

在确定了包含 190 万个视频的目标列表后,我们成功下载了 180 万个视频(部分视频被频道所有者移除,或更改了权限)。

我们探索了两种不同的分布式下载方法。

方案 1:Video2dataset

video2dataset 是一个开源项目 [链接],专注于分布式视频下载、转换和打包成不同数据集格式。该项目原生支持 Slurm Workload Manager,因此我们可以在我们的 CPU 集群上运行它。


Dataset Creation
来源:Video2Dataset GitHub 页面


由于我们所有的集群实例都通过同一个公共 IP 访问互联网,我们为该项目贡献了指定代理的功能以方便视频下载。虽然该功能尚未合并,但您可以通过我们的 PR [链接] 来为 video2dataset 打补丁以使用代理功能。


方案 2:云批量作业

大多数云提供商都支持运行作业,只需定义执行每个作业的实例类型、定义一个队列,并提供一个包含待执行代码的容器即可。

我们使用 Google Cloud 和 AWS 运行了一个定制的 Docker 容器,该容器使用 ytdlp 下载视频和元数据,并将结果推送到 S3。

用于构建 Docker 容器的文件可以在这里找到 [代码]。

我们的结论

虽然 Video2Dataset 在使用代理时功能正常,并允许我们执行额外的处理步骤,但我们能向代理发出的每秒请求数成了瓶颈。这使得我们转向了云批量作业。

保留动态内容

在寻找最佳视频的过程中,我们将选择范围缩小到那些既有视觉动作、又有人以中等至较快语速说话的内容。我们通过词密度筛选和视觉动态性筛选来实现这一点。

词密度筛选

我们把视频中的词密度作为音频动态性的一个代理指标。词密度的定义是

词密度 = 隐藏式字幕中的单词数 / 视频总时长(秒)

通过对不同密度阈值下的内容质量进行抽样和视觉评估,我们决定移除所有词密度低于 0.5 词/秒的视频。

示例

词密度 示例
0.25
0.5
0.75
1.0

按词密度筛选和浏览示例的代码可以在这里找到 [链接]

视觉动态性筛选

我们重新利用 FFMPEG 的 Freezedetect 滤镜 来判断视频的动态性。虽然这个滤镜本是设计用来识别视频中的静止部分(连续多个相同的帧),但通过将 noise 参数夸张地设为一个非常高的值,我们也可以识别出运动量很低的片段。

我们没有对整个视频运行 freezedetect,而是按时间段分析视频,并根据被归类为静态的段落数量来判断视频是否为静态。通过人工评估,我们设定了一个阈值:如果 40% 的分析段落运动量过低,则丢弃该视频。

此次筛选后丢弃的一些内容类型

类型 示例
带音乐的静态图片
演示文稿的屏幕录像
高度静态的人物对着镜头讲话

用于按视频动态性分类的 DockerFile 和代码可以在这里找到 [链接]

在分析的 180 万个视频中,经过这一步筛选,我们保留了 60 万个动态视频。在这个阶段,我们深入研究视频内容,这对确保数据集的多样性至关重要。

视频分类

为了实现最广泛的内容选择,我们利用隐藏式字幕和 YouTube 元数据对 60 万个筛选后的资产进行了分类。为了更好地控制分类过程,我们创建了一个分类体系,并引导标注过程遵循该体系。

定制分类体系

我们使用 GPT4-o 启动了定制分类体系的构建,并由一位信息科学家进行了审查和调整。该分类体系包含 126 个细分类别,并聚合成多个层级。这种多层级的方法允许 FineVideo 的用户根据其特定用例对数据集进行切片。

taxonomy

该分类体系也提供 JSON 格式 [链接]

在分类体系的初版基础上,我们开始了内容标注,并通过观察内容标注的结果,在信息科学家的帮助下,相应地调整了分类体系。

内容标注

我们使用通过文本生成推理 TGI 提供的 Llama 3.1 70B 对视频进行分类 [代码]。

为了确保答案严格属于我们分类体系中的一个类别,提示词经过了多次迭代。在我们的提示词评估过程中,我们发现,从提示词中移除现有的 YouTube 标签和类别,可以极大地提高结果质量:YouTube 的元数据会使 Llama 3.1 生成的文本偏向 YouTube 提供的某个类别。

prompt_template = """
Given those categories: {leaves}
Classify a youtube video given its closed captioning and some metadata details. RETURN ONLY the selected category and nothing else!
Title: {title}
Description: {description}
Channel: {channel}
Closed Caption: {closed_caption}
"""

分类体系 - 内容标注的反馈循环


Categorization feedback loop
内容分类过程中的分类体系调整


信息科学家的职责之一是随时间推移维护分类体系,以添加新类别或在需要时增加额外的区分度。

使用大语言模型进行内容分类,使得调整分类体系的周期从数月/数年缩短到数小时。此外,在某些情况下,我们专门创建了一些类别来丢弃敏感视频,例如属于 枪支与武器物质使用与毒品 的视频。

贡献描述性元数据

在流程的这个阶段,我们有三个视频级别的元数据来源

  • 视频类别(由 Llama 3.1 推断)
  • YouTube 元数据(标题、描述)
  • 来自 YouTube-Commons 的字幕

为了在视频理解领域做出贡献,我们决定深入研究时间码级别的元数据,例如活动、物体、叙事和剪辑方面。虽然我们曾考虑将人工标注作为主动学习设置的一部分,即由一个或多个模型提出标注,然后由人工进行质检,但正如我们将在下一节中讨论的,我们发现 Gemini 是一个很好的解决方案,尤其是在我们限制了输入视频长度和输出格式的情况下。

长视频与 Gemini 1.5 Pro

我们深入研究了 Gemini 1.5 Pro,迭代我们的提示词并用不同长度的内容进行测试。

考虑到其 100 万 token 的限制(大约相当于 1 小时的视频),我们不得不放弃超过 1 小时的视频。为了克服这种情况,一个想法是加速超过一小时的视频,以便适应 Gemini 的上下文。


Gemini context
探索:加速视频以在 Gemini 的上下文中容纳更多内容


虽然在高层面上看起来可行,但当我们开始审视细节时,我们意识到只有视频的前几分钟被准确标注了。

发现长视频质量下降让我们思考:这个问题是否影响了我们其余的视频?通过抽样不同长度的视频并检查标注的视频覆盖范围,我们发现在超过 10 分钟的视频中,质量有所下降。

为了与我们向社区提供高质量数据的目标保持一致,我们放弃了超过 10 分钟的视频。

内容选择

鉴于每小时视频使用 Gemini 标注的成本超过 5 美元,我们无法标注筛选后所有的视频。因此,我们希望确保对所有主题都有良好的覆盖,并寻求在内容多样性、后期预训练/微调任务和预算之间找到一个良好的平衡。我们将这个规模限制设定为 4000 小时视频。

为了从 60 万个视频中筛选出 4000 小时的内容,我们准备了一个算法,该算法平衡了内容类别、用户参与度和频道代表性,以达到目标时长。

Oracle Flow

算法流程图




内容选择算法的一些关键部分

  • 活跃度评分:我们通过加权组合评论数、观看次数和点赞数来计算每个视频的参与度指标。这个分数有助于优先选择那些在观众中反响良好的视频。


  • 视频选择:此步骤迭代选择视频以满足目标时长,同时确保多样性。它在高度参与的内容与来自不同类别和频道的代表性之间取得平衡,并使用惩罚系统来避免任何单个频道的过度代表。


  • 最终调整:我们调整选择,以尽可能接近目标时长而不超过它。它按时长对选定的视频进行排序,并将它们添加到最终列表中,直到达到最接近目标总时长的总和。

代码可以在代码仓库中找到 [链接]


使用 Gemini 1.5 Pro 进行标注,并使用 GPT4o 进行结构化输出

为什么需要结构化数据?

我们通过 FineVideo 的目标之一是提供结构化数据,以此赋能我们的社区:如果你正在研究多模态大语言模型,你可以对数据进行切片,并决定哪些类别适合你的预训练或微调组合。如果你更关注计算机视觉,你可以直接使用该数据集来训练分类器,基于 FineVideo 中包含的数值类别,如动态性得分、场景边界或音视频相关性得分。

结构化数据与 Gemini 1.5

Gemini 1.5 Pro 通过提供模式 (schema) 支持基于 JSON 的输出。我们探索了这一功能,但很快发现了两个问题

  • 由于我们的模式非常复杂,我们无法将其完全适配到 Gemini 中。
  • 当我们尝试使用稍微简单一些的模式时——尽管仍然相当复杂——Gemini 结果的质量大幅下降:大多数场景类型的数据(角色、活动、道具)都丢失了。我们尝试将提示词拆分成多个,并将不同的提示词与模式的不同部分匹配,但收效甚微。

我们观察到的情况与其他研究人员的经历完全一致:添加具体的模式约束可能会降低性能。(让我自由发言?关于格式限制对大语言模型性能影响的研究)。

我们的解决方案是先用 Gemini 1.5 生成自由文本,然后增加一个处理步骤,将 Gemini 的结果与我们的模式对齐。

我们使用的 Gemini 提示词如下

Study the video and provide the following details about the video and the semantic scenes that compose it:

- characterList: a list of characters that appear in the whole video and a visual description that should allow me to identify them just seeing an image of them.
- scenes: a list of the scenes with the following properties:
  - start/end timestamps of the scene
  - list of all the characters that appear in the scene
  - list of all activities and their timestamps
  - list of all props and their timestamps
  - list of all video editing details and their start/end timestamps. Details include transitions, effects, music as well as suggestions like segments of the scene that could be removed and why 
  - scene mood with notes on how the visuals, audio and context contribute to it. Use the following taxonomy returning only the name in your answer {"moods":{"Positive":[{"name":"Happy","description":"Feeling joyful, content, or delighted."},{"name":"Excited","description":"Feeling enthusiastic, energetic, or eager."},{"name":"Calm","description":"Feeling peaceful, relaxed, or serene."},{"name":"Grateful","description":"Feeling appreciative or thankful."},{"name":"Proud","description":"Feeling satisfied with one's achievements or the achievements of others."}],"Negative":[{"name":"Sad","description":"Feeling down, unhappy, or sorrowful."},{"name":"Angry","description":"Feeling irritated, frustrated, or furious."},{"name":"Anxious","description":"Feeling nervous, worried, or uneasy."},{"name":"Lonely","description":"Feeling isolated, disconnected, or abandoned."},{"name":"Bored","description":"Feeling uninterested, disengaged, or restless."}],"Neutral":[{"name":"Indifferent","description":"Feeling neither particularly positive nor negative."},{"name":"Content","description":"Feeling satisfied but not overly excited."},{"name":"Curious","description":"Feeling interested or inquisitive without strong emotion."},{"name":"Confused","description":"Feeling uncertain or unclear but without strong negative feelings."},{"name":"Pensive","description":"Feeling thoughtful or reflective without strong emotional engagement."}]}}
    - specific  mood changing moments inside the scene, report the timestamp and what we transition from/to in any of the dimensions (visual / auditive)
  - scene narrative progression and plot development
    - specific narrative moments inside the scene. Report the timestamp and what happened
  - character interaction and dynamics descriptions and their start/end timestamps
  - specific thematic elements and descriptions
  - specific relevant happenings to create deeper meanings and subtexts not explicitly stated that contribute to the richness and depth of the content, timestamp and descriptions
  - dynamism score of the scene. Score between 0 and 1. 1 is highly dynamic
  - audio - visual correlation score. Score between 0 and 1. 0 what we see is not correlated with the speech and 1 is highly correlated

- storylines: a list of the different storylines found and which scenes belong to it. 
  - Specify where is the climax (scene and timestamp) and if the content is being presented a narrative story, or is it more like a collection of facts or non-narrative information
  - if there are scenes not matching storylines, explain how those scenes contribute to the video
- looking at the overall video and the storylines, which segments of the video could be trimmed to make it more dynamic?
- q&a: a list of 5 questions/answers about the video that focus on fine details (objects and or activities), overall story reasoning and mood. Focus on Q&A aspects captured on the audio and the video whenever possible difficult to get only by looking at the transcription.

添加 Instructor

在 Gemini 处理完结果后,我们使用 Instructor 进行解析:这是一个构建在 Pydantic 之上的库,用于根据给定的模式实现结构化输出。请参见下表示例。

Instructor 让我们能够试验不同的模型,将 Gemini 的自由文本转换为我们在 Pydantic 中定义的模式。我们尝试了 Gemini 和 GPT4o,并最终选择了 GPT4o,因为它的成功率更高。

视频 Gemini 输出 Instructor 输出


CharacterList: Man Slim build, brown eyes, shaved sides, black hoodie with colorful logo, black pants. Scenes Scene 1 Start 0:00 End 0:55 Characters: [Man] Activities: Introduces bus Describes peaceful location with cows Props: Bus, cows, deck. Mood:Excited, adventure. Narrative Progression: Introduction to bus. Tour begins outside, highlighting nature and relaxation. Dynamism Score 0.7 Audio-Visual Correlation 1


{
  "title": "Bertie the Bus Tour",
  "description": "Guided tour of converted bus.",
  "characterList": [
    {
      "name": "Narrator",
      "description": "Slim build, brown eyes, shaved sides, black hoodie with colorful logo, black pants."
    }
  ],
  "scenes": [
    {
      "sceneId": 1,
      "title": "Introduction to Bus",
      "timestamps": {
        "start": "0:00",
        "end": "0:55"
      },
      "cast": ["Narrator"],
      "activities": [
        "Narrator speaks in front of bus",
        "Shows outdoor deck with chairs, cows nearby."
      ],
      "props": ["Bus", "Deck", "Cows"],
      "mood": "Excited, adventure."
    }
  ],
  "dynamismScore": 0.7,
  "audioVisualCorrelation": 1
}
        

值得强调的是,Gemini 的内容筛选功能丢弃了一些视频,如果你使用 Gemini,也可能会遇到这种情况。在我们的案例中,鉴于我们目标的内容量,Gemini 筛选丢弃的总内容时长可以忽略不计。

完整的视频标注代码可以在这里找到 [链接]。

精细对齐和异常筛选

在视频标注完成且数据与我们的模式正确对齐后,我们关注数据的时间维度,并确保其与视频对齐:Gemini 1.5 以每秒 1 帧的速度读取视频,而视频的帧率通常为每秒 25 - 29 帧。在我们的精细对齐中,我们确保 Gemini 1.5 提供的场景边界与视频中的正确帧匹配。

我们还利用这种时间对齐来丢弃那些 Gemini 停止提供有效数据、导致视频部分内容被错误标注的情况。需要注意的是,由于我们在流程早期丢弃了所有超过 10 分钟的内容,数据质量差的视频数量可以忽略不计(低于 0.5%)。


Fine Alignment
精细元数据 - 将视频场景边界与镜头对齐,作为一种丢弃异常值的方法


视频对齐代码链接在此 [链接]

未来工作

我们目前正在准备用 FineVideo 训练一个多模态大语言模型,并计划在完成后尽快与社区分享模型权重和训练方案。

我们也对 FineVideo 的其他扩展持开放态度,欢迎提出您的想法,告诉我们您希望看到什么!

社区

注册登录 以发表评论