9.3 KiB
Q1 特征提取方法说明(零基础版)
这份说明介绍本次已经完成的 100 条视频处理过程。目标是把文字、声音和画面变成电脑能处理的数字,并让这三种数字都能回到原视频的时间位置。
先用一句话理解
把每条视频想成一段带字幕的短片:
- 把字幕切成一个个词,为每个词生成一组数字;
- 把声音切成许多很短的小段,为每段记录音高、响度等声音特征;
- 每隔一小段时间取一帧画面,为每帧生成一组画面数字;
- 再估计每个字幕词在声音里出现的时间,把同一时间附近的声音和画面对到一起。
这些数字就是“特征”。它们不是视频本身,也不是情感结论,而是模型后续可以读取的数字表示。
整体流程
flowchart LR
A[100条原始视频 + 原始字幕] --> B[文字:每个词生成向量]
A --> C[声音:提取逐帧声学特征]
A --> D[画面:每秒抽取约5帧并生成特征]
B --> E[用字幕和声音估计词级时间戳]
C --> E
E --> F[按词的时间段汇总声音和画面特征]
D --> F
F --> G[100个样本文件 + 汇总表 + 对应关系图]
什么叫“对齐”
一段视频里,字幕、声音和画面各有自己的节奏。比如字幕中的词“happy”可能在 1.2 秒左右说出,那个时刻的视频画面里也可能出现说话人的表情变化。
“对齐”就是给不同模态的内容标上共同的时间位置,便于回答:
这个词出现时,声音有什么变化?同一时刻画面里有什么?
本次时间统一使用“从这条短视频开始算起的秒数”。例如 1.2 秒就是片段开始后 1.2 秒。电脑估出来的时间是模型估计值,不是人工逐帧标注的真值。
文字是怎么处理的
- 直接读取题目提供的英文 transcript(字幕文本),保留原文顺序和内容,不用模型改写或纠错。
- 按空格切成词。像
unbelievable这样的词,文字模型内部可能会再拆成更小的片段。 - 使用预训练的 BERT 英文模型,为这些更小的片段生成数字向量,再把同一个词的片段向量取平均,得到这个词的一组数字。
可以把 BERT 理解成一个读过大量英文材料的编码器:它把每个词放进一组 768 个数字里。词的向量不是情感分数,也不代表某一维就等于某种具体情绪。
声音是怎么处理的
声音分成两个用途不同的步骤。
1. 找每个词大约在什么时候说出
使用预训练的 Wav2Vec2 英语语音模型,并把题目提供的 transcript 当作已知文本。模型根据实际声音,为字幕里的字母和词寻找最可能的时间位置。这种做法叫“强制对齐”:文本固定,模型估计它在声音中的时间。
这一步不会验证字幕是不是完全正确,也不会把它当成精确的人工真值。若字幕和录音差异较大,时间估计可能不准。
2. 记录声音本身的变化
用 FFmpeg 把视频里的声音转成单声道、每秒 16,000 个采样点的音频,再使用 openSMILE 的 eGeMAPSv02 特征配置。它大约每 0.01 秒输出一行、每行 25 个数字,记录响度、音高、频谱形状等声音信息。
这些数值描述“声音怎么变化”,不等同于文字内容,也不是情感类别。
画面是怎么处理的
视频不会把每一帧都存成特征。本次每秒大约抽取 5 帧,也就是平均约每 0.2 秒取一帧。
- DeiT-Tiny 图像模型为每帧生成 192 个数字,作为通用画面特征。这组数字能表示画面信息,但单独一个数字通常没有容易读懂的名称。
- 另外,MediaPipe Face Landmarker 会尝试检测人脸,并输出 52 个脸部动作系数,例如眉毛、眼睑和嘴部的运动。这些系数描述可见的脸部动作,不是“高兴/悲伤”等情绪标签。
有 13 条视频在抽样帧中没有检测到人脸,所以这些样本没有有效的人脸动作系数;它们仍然保留了 DeiT 通用画面特征,视觉模态没有因此缺失。
三种特征怎样对应到词
对齐完成后,每个字幕词都有一个起止时间。例如(下面只是示意):
| 字幕词 | 估计时间 | 对应的声音 | 对应的画面 |
|---|---|---|---|
| happy | 1.20–1.55 秒 | 取这个时间段内的声学帧并求平均 | 取这个时间段内的视频帧特征并求平均 |
声音特征比较密,通常一个词时间段里会有多行;视频每秒只有约 5 帧,所以有些很短的词时间段里可能没有正好落入的画面帧。这种情况下,程序取时间最近的一帧,并把“使用了最近帧”的标记一并保存。
本次有 12 个词无法直接从 CTC 对齐路径中获得时间,分布在 9 条样本里。它们被放在相邻有效词之间的一个时间点上,区间长度为零,并标记 word_alignment_valid=false。程序没有把估计不出的词伪装成可靠的起止时间;下游对应特征通过最近的有效声音帧或画面帧取得,并保留回退标记。
文件里存了什么
每条视频有一个压缩的 .npz 文件,变长序列按原长存储,不在文件里填充到同一长度。主要数组包括:
| 内容 | 形状示例 | 含义 |
|---|---|---|
text_features |
词数 × 768 | 每个 transcript 词的 BERT 向量 |
audio_features |
音频帧数 × 25 | 逐帧 eGeMAPS 声学特征 |
vision_features |
画面帧数 × 192 | 逐帧 DeiT 通用画面特征 |
face_blendshape_features |
画面帧数 × 52 | 人脸动作系数;是否有效由独立掩码表示 |
word_intervals_s |
词数 × 2 | 每个词的起止时间,单位秒 |
audio_word_features |
词数 × 25 | 按词的时间段汇总后的声音特征 |
vision_word_features |
词数 × 192 | 按词的时间段汇总后的视频特征 |
时间戳以 32 位浮点数保存,特征值以 16 位浮点数保存以节省空间,掩码使用布尔值。掩码就是一张有效性清单:true 表示该位置有可用数据,false 表示缺失或使用了需要谨慎处理的回退结果。
本次处理得到的汇总
- 原始样本:100 条;标签表里的 100 个样本与视频文件一一对应,未删除或替换样本。
- 文本:1,932 个词,768 维词向量。
- 声音:77,261 个有效帧,25 维声学特征。
- 画面:3,948 帧,192 维通用视觉特征,覆盖 100/100 条样本。
- 人脸动作:87/100 条检测到有效人脸帧;其余 13 条仍有通用视觉特征。
- CTC 词级时间:1,920/1,932 个词直接对齐,12 个词带回退标记。
- 抽取错误:0 条;完整特征与报告约 10.5 MB。
审计还发现两段原始视频短于题面给出的 2.648 秒下限:-mJ2ud6oKI8/6 约 2.2356 秒,-s9qJ7ATP7w/6 约 2.4667 秒。它们按原样保留,时长差异记录在审计文件中。
如何复现
在 deep_learning 目录中运行:
cd Q1
uv sync
uv run python -m q1.audit
uv run python -m q1.extract_features --output-dir outputs/q1_features
uv.lock 固定了 Python 依赖版本;运行清单记录了模型名称与修订号、参数、工具版本、GPU 信息和输出文件哈希。特征文件、汇总表、运行清单及典型样本图位于 Q1/outputs/q1_features/。
这次结果的边界
本说明讲的是“怎么从原始视频得到三模态特征,以及如何按时间组织它们”。最初的 M3/M4 版本曾把注意力摊得很平均;后来的时间码实验使 M4 找到了较稳定的时间位置,但“找到了同一时刻”仍不能保证文字、声音、画面的具体内容相互对应。情绪 Probe 也只是 100 条小样本上的检查,不能当作一般情绪识别准确率。CTC 时间、模型生成的向量和人脸动作系数都应当视为算法输出;要确认某个词和某段声音、画面是否真的对应,仍需要人工标注一些时间片段做独立核验。
后续的 TSFA 实验:为什么还要再对齐一次
可以把一段视频想成一条从头到尾的路。M4 根据时间先告诉我们:“第 20 个位置大约在这条路的中段。”TSFA 在中段附近再比较文字与声音、画面的内容,选择更像当前文字的片段。实验把每条视频组织成 50 个位置;“附近”在主方案中指整段视频时长的前后各 10%。如果窗口里没有可用的声音或画面位置,就取最近的有效位置,并保留这项规则。
为了知道“附近”是否真的有用,还做了两种对照:一种把同样宽的窗口随机放置,另一种让模型看完整段视频。七种方法使用相同的 100 条视频、相同的 BERT 文字特征、音频特征和 DeiT 图像特征;同一原视频的片段在同一折里一起作为训练或留出数据。总共做 5 折,每条样本都轮到一次留出评价。
结果显示,TSFA 比只用 M4 时更容易把同一位置的文字与声音对应起来,但画面相关的改善很小。随机窗口和看完整段视频的方案在“内容相似度”指标上甚至更高,却经常把视频前后位置弄乱。TSFA 的局部时间窗口主要帮助模型保持先后顺序。这里的“同一位置”由时间槽定义,还不是人工确认的同一事件,因此目前不能说三种模态已经准确理解了彼此。详细数字与图见 RESULTS.md 的 TSFA 小节。