目录
- 视频理解基础理论
- 时序建模方法
- 动作识别
- 视频分类与检测
- 视频分割
- 视频生成基础
- 扩散模型视频生成
- 视频预测与插值
- 评估指标与数据集
- 应用与前沿
1. 视频理解基础理论
1.1 什么是视频理解
视频理解的目标:
从视频序列中提取语义信息
┌─────────────────────────────────────────────────────────────────┐
│ 视频理解任务 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 分类任务: │
│ ├── 动作识别: 识别视频中的动作 (跑步、游泳、吃饭) │
│ ├── 视频分类: 将视频分类到预定义类别 │
│ └── 事件检测: 检测视频中的事件 │
│ │
│ 定位任务: │
│ ├── 时间动作定位: 定位动作的起止时间 │
│ ├── 时空动作检测: 定位动作的时间和空间 │
│ └── 视频摘要: 提取视频的关键片段 │
│ │
│ 跟踪任务: │
│ ├── 多目标跟踪: 跟踪视频中的多个物体 │
│ ├── 单目标跟踪: 跟踪特定物体 │
│ └── 行人重识别: 跨摄像头跟踪行人 │
│ │
│ 生成任务: │
│ ├── 视频生成: 从文本/图像生成视频 │
│ ├── 视频预测: 预测未来帧 │
│ ├── 视频插值: 生成中间帧 │
│ └── 视频编辑: 编辑视频内容 │
│ │
└─────────────────────────────────────────────────────────────────┘
1.2 视频数据特性
视频数据的特殊性:
图像: [H, W, C] --- 静态
视频: [T, H, W, C] --- 动态 (T 帧)
特性:
1. 时序性: 帧之间有时间顺序
2. 冗余性: 相邻帧高度相似
3. 运动信息: 帧间差异包含运动信息
4. 长时依赖: 理解需要长时上下文
挑战:
1. 计算量: T 帧 × 每帧计算量
2. 内存: 存储 T 帧特征
3. 时序建模: 如何有效建模时间关系
4. 长视频: 处理数分钟甚至数小时的视频
1.3 视频表示
视频表示方法:
1. 帧级表示:
每帧独立处理
优点: 简单,可用图像模型
缺点: 忽略时序关系
2. 片段级表示:
采样固定长度的片段 (如 16 帧)
优点: 平衡计算和时序信息
缺点: 固定窗口,可能错过关键帧
3. 视频级表示:
处理整个视频
优点: 完整时序信息
缺点: 计算量大
2. 时序建模方法
2.1 早期方法
时序建模的演进:
1. 双流网络 (Two-Stream, 2014):
空间流: 单帧图像 → CNN → 空间特征
时间流: 光流图 → CNN → 运动特征
融合: 空间 + 时间 → 分类
理论:
光流编码了帧间运动
空间流捕获外观信息
两者互补
2. 3D 卷积 (C3D, 2015):
使用 3D 卷积核处理视频
输入: [T, H, W, C]
卷积核: [k_t, k_h, k_w]
理论:
3D 卷积同时建模空间和时间
但计算量大
3. SlowFast (2019):
Slow 路径: 低帧率,捕获空间语义
Fast 路径: 高帧率,捕获运动信息
理论:
视频中的运动速度快
需要高帧率捕获
但空间信息不需要那么高帧率
import torch
import torch.nn as nn
class TwoStreamNetwork(nn.Module):
"""
双流网络
空间流: 处理单帧图像
时间流: 处理光流图
理论:
空间流: 捕获外观信息 (物体、场景)
时间流: 捕获运动信息 (光流)
融合: 结合两者进行分类
"""
def __init__(self, num_classes):
super().__init__()
# 空间流 (图像)
self.spatial_stream = nn.Sequential(
nn.Conv2d(3, 64, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(64, 128, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.AdaptiveAvgPool2d(1),
nn.Flatten(),
nn.Linear(128, num_classes)
)
# 时间流 (光流)
self.temporal_stream = nn.Sequential(
nn.Conv2d(2 * 10, 64, 3, padding=1), # 10 帧的光流 (x, y)
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(64, 128, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.AdaptiveAvgPool2d(1),
nn.Flatten(),
nn.Linear(128, num_classes)
)
# 融合权重
self融合_weight = nn.Parameter(torch.ones(2) / 2)
def forward(self, frame, optical_flow):
"""
frame: [B, 3, H, W] 单帧图像
optical_flow: [B, 20, H, W] 10 帧光流
"""
# 空间流
spatial_out = self.spatial_stream(frame)
# 时间流
temporal_out = self.temporal_stream(optical_flow)
# 加权融合
weights = torch.softmax(self融合_weight, dim=0)
output = weights[0] * spatial_out + weights[1] * temporal_out
return output
"""
光流 (Optical Flow):
定义: 像素在相邻帧之间的位移向量
光流场: F = (u, v)
u: 水平位移
v: 垂直位移
计算方法:
1. 稀疏光流: Lucas-Kanade (只计算特征点)
2. 稠密光流: Farneback, RAFT (计算所有像素)
应用:
- 双流网络的时间流输入
- 运动估计
- 视频稳定
"""
2.2 3D 卷积
class C3D(nn.Module):
"""
C3D (3D Convolutional Network)
使用 3D 卷积核处理视频
理论:
3D 卷积同时建模空间和时间维度
卷积核: [k_t, k_h, k_w]
缺点:
- 参数量大
- 计算量大
- 难以训练
"""
def __init__(self, num_classes):
super().__init__()
# 3D 卷积层
self.features = nn.Sequential(
nn.Conv3d(3, 64, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(1, 2, 2), stride=(1, 2, 2)),
nn.Conv3d(64, 128, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(2, 2, 2), stride=(2, 2, 2)),
nn.Conv3d(128, 256, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(2, 2, 2), stride=(2, 2, 2)),
nn.Conv3d(256, 512, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(2, 2, 2), stride=(2, 2, 2))
)
# 分类器
self.classifier = nn.Sequential(
nn.AdaptiveAvgPool3d(1),
nn.Flatten(),
nn.Linear(512, 4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096, num_classes)
)
def forward(self, x):
"""
x: [B, C, T, H, W]
"""
x = self.features(x)
x = self.classifier(x)
return x
"""
3D 卷积的参数量:
2D 卷积: C_in × C_out × k_h × k_w
3D 卷积: C_in × C_out × k_t × k_h × k_w
当 k=3 时:
2D: 9 × C_in × C_out
3D: 27 × C_in × C_out (3 倍)
"""
2.3 SlowFast 网络
论文: "SlowFast Networks for Video Recognition" (Feichtenhofer et al., 2019)
核心思想:
Slow 路径: 低帧率 (如每 16 帧取 1 帧)
捕获空间语义 (物体、场景)
Fast 路径: 高帧率 (如每 2 帧取 1 帧)
捕获运动信息 (快速变化)
融合: 侧向连接 + 最终拼接
理论:
视频中的信息有多时间尺度:
- 空间语义: 变化慢 (背景、物体)
- 运动信息: 变化快 (手势、动作)
Slow 路径处理慢变化的信息
Fast 路径处理快变化的信息
class SlowFast(nn.Module):
"""
SlowFast 网络
Slow 路径: 低帧率,捕获空间语义
Fast 路径: 高帧率,捕获运动信息
理论:
不同时间尺度的信息需要不同的帧率
Slow: 每 16 帧取 1 帧
Fast: 每 2 帧取 1 帧
"""
def __init__(self, num_classes, slow_frames=4, fast_frames=32):
super().__init__()
self.slow_frames = slow_frames
self.fast_frames = fast_frames
# Slow 路径 (低帧率,大通道数)
self.slow_path = nn.Sequential(
nn.Conv3d(3, 64, kernel_size=(1, 7, 7), stride=(1, 2, 2), padding=(0, 3, 3)),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(1, 2, 2), padding=(0, 1, 1)),
nn.Conv3d(64, 128, kernel_size=(1, 3, 3), padding=(0, 1, 1)),
nn.ReLU(),
nn.Conv3d(128, 256, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.ReLU(),
nn.AdaptiveAvgPool3d(1)
)
# Fast 路径 (高帧率,小通道数)
self.fast_path = nn.Sequential(
nn.Conv3d(3, 8, kernel_size=(5, 7, 7), stride=(1, 2, 2), padding=(2, 3, 3)),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(1, 2, 2), padding=(0, 1, 1)),
nn.Conv3d(8, 16, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.ReLU(),
nn.Conv3d(16, 32, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.ReLU(),
nn.AdaptiveAvgPool3d(1)
)
# 侧向连接 (Fast → Slow)
self.lateral_connections = nn.ModuleList([
nn.Conv3d(8, 64, kernel_size=(1, 1, 1)),
nn.Conv3d(16, 128, kernel_size=(1, 1, 1)),
nn.Conv3d(32, 256, kernel_size=(1, 1, 1))
])
# 分类器
self.classifier = nn.Linear(256 + 32, num_classes)
def forward(self, slow_input, fast_input):
"""
slow_input: [B, 3, T_slow, H, W]
fast_input: [B, 3, T_fast, H, W]
"""
# Slow 路径
slow_features = self.slow_path(slow_input)
# Fast 路径
fast_features = self.fast_path(fast_input)
# 融合
combined = torch.cat([slow_features.flatten(1), fast_features.flatten(1)], dim=1)
# 分类
output = self.classifier(combined)
return output
"""
SlowFast 的通道比例:
Slow: β = 1 (正常通道数)
Fast: β = 1/8 或 1/16 (小通道数)
理论:
Fast 路径主要捕获运动
运动信息可以用较少的通道表示
减少计算量
"""
2.4 时间注意力
class TemporalAttention(nn.Module):
"""
时间注意力机制
理论:
不同时间步的重要性不同
注意力机制学习关注重要的时间步
应用:
- 视频分类中关注关键帧
- 动作识别中关注动作发生的时间
"""
def __init__(self, d_model):
super().__init__()
self.query = nn.Linear(d_model, d_model)
self.key = nn.Linear(d_model, d_model)
self.value = nn.Linear(d_model, d_model)
self.scale = d_model ** 0.5
def forward(self, x):
"""
x: [B, T, D] 时间序列特征
"""
Q = self.query(x)
K = self.key(x)
V = self.value(x)
# 时间注意力
attn = torch.bmm(Q, K.transpose(1, 2)) / self.scale
attn = torch.softmax(attn, dim=-1)
# 加权聚合
output = torch.bmm(attn, V)
return output
"""
时间注意力的理论:
自注意力: 每个时间步关注所有其他时间步
因果注意力: 只关注过去的时间步
对于视频:
非因果: 可以看到整个视频 (分类任务)
因果: 只能看到过去 (在线任务)
"""
3. 动作识别
3.1 动作识别概述
动作识别任务:
输入: 视频片段
输出: 动作类别
数据集:
- Kinetics-400: 400 类动作,300K 视频
- Kinetics-700: 700 类动作
- UCF-101: 101 类动作
- HMDB-51: 51 类动作
挑战:
- 类内差异大 (同一动作有多种方式)
- 类间差异小 (不同动作可能相似)
- 背景干扰
- 相机运动
3.2 时空建模方法
时空建模的演进:
1. 双流网络 (2014):
空间流 + 时间流
2. C3D (2015):
3D 卷积
3. I3D (2017):
膨胀 3D 卷积
从 2D 模型膨胀为 3D
4. SlowFast (2019):
双路径,不同帧率
5. X3D (2020):
高效 3D 网络
6. TimeSformer (2021):
视频 Transformer
7. VideoMAE (2022):
掩码自编码器预训练
class I3D(nn.Module):
"""
I3D (Inflated 3D ConvNet)
核心思想:
将 2D 预训练模型膨胀为 3D
复用 ImageNet 预训练权重
膨胀方法:
2D 卷积核 [k, k] → 3D 卷积核 [k, k, k]
权重复制: 沿时间维度复制 k 次,再除以 k
理论:
空间特征可以从 ImageNet 迁移
时间维度需要从头学习
"""
def __init__(self, num_classes):
super().__init__()
# 膨胀的 Inception 模块
self.features = nn.Sequential(
Inception3D(3, 64),
nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(1, 2, 2)),
Inception3D(64, 192),
nn.MaxPool3d(kernel_size=(3, 3, 3), stride=(2, 2, 2)),
Inception3D(192, 256),
Inception3D(256, 320),
nn.MaxPool3d(kernel_size=(2, 2, 2), stride=(2, 2, 2)),
Inception3D(320, 576),
Inception3D(576, 576),
nn.AdaptiveAvgPool3d(1)
)
self.classifier = nn.Linear(576, num_classes)
def forward(self, x):
"""
x: [B, 3, T, H, W]
"""
x = self.features(x)
x = x.flatten(1)
x = self.classifier(x)
return x
class Inception3D(nn.Module):
"""
3D Inception 模块
多尺度 3D 卷积
"""
def __init__(self, in_channels, out_channels):
super().__init__()
# 分支 1: 1×1×1
self.branch1 = nn.Conv3d(in_channels, out_channels // 4, 1)
# 分支 2: 1×1×1 → 3×3×3
self.branch2 = nn.Sequential(
nn.Conv3d(in_channels, out_channels // 4, 1),
nn.Conv3d(out_channels // 4, out_channels // 4, 3, padding=1)
)
# 分支 3: 1×1×1 → 3×3×3 × 2
self.branch3 = nn.Sequential(
nn.Conv3d(in_channels, out_channels // 4, 1),
nn.Conv3d(out_channels // 4, out_channels // 4, 3, padding=1),
nn.Conv3d(out_channels // 4, out_channels // 4, 3, padding=1)
)
# 分支 4: MaxPool → 1×1×1
self.branch4 = nn.Sequential(
nn.MaxPool3d(3, stride=1, padding=1),
nn.Conv3d(in_channels, out_channels // 4, 1)
)
def forward(self, x):
b1 = self.branch1(x)
b2 = self.branch2(x)
b3 = self.branch3(x)
b4 = self.branch4(x)
return torch.cat([b1, b2, b3, b4], dim=1)
论文: "Is Space-Time Attention All You Need for Video Understanding?"
(Bertasius et al., 2021)
TimeSformer 核心思想:
将 Transformer 应用于视频
使用时空注意力
注意力模式:
1. 时间注意力: 每个 patch 关注所有时间步的同一位置
2. 空间注意力: 每个 patch 关注同一时间步的所有位置
3. 联合时空注意力: 关注所有位置 (计算量大)
4. 分离时空注意力: 先时间后空间 (推荐)
class TimeSformer(nn.Module):
"""
TimeSformer
视频 Transformer,使用分离的时空注意力
理论:
先进行时间注意力 (不同时间的同一位置)
再进行空间注意力 (同一时间的不同位置)
分离降低计算复杂度
"""
def __init__(self, img_size=224, patch_size=16, num_frames=8,
num_classes=400, d_model=768, n_heads=12, n_layers=12):
super().__init__()
self.patch_size = patch_size
self.num_patches = (img_size // patch_size) ** 2
# Patch Embedding
self.patch_embedding = nn.Conv3d(
3, d_model,
kernel_size=(1, patch_size, patch_size),
stride=(1, patch_size, patch_size)
)
# 位置编码
self.position_embedding = nn.Parameter(
torch.randn(1, num_frames * self.num_patches + 1, d_model)
)
# CLS Token
self.cls_token = nn.Parameter(torch.randn(1, 1, d_model))
# Transformer 层 (分离时空注意力)
self.layers = nn.ModuleList([
SpatioTemporalAttention(d_model, n_heads)
for _ in range(n_layers)
])
# 分类头
self.norm = nn.LayerNorm(d_model)
self.head = nn.Linear(d_model, num_classes)
def forward(self, x):
"""
x: [B, C, T, H, W]
"""
B, C, T, H, W = x.shape
# Patch Embedding
x = self.patch_embedding(x) # [B, d_model, T, H/P, W/P]
x = x.flatten(2).transpose(1, 2) # [B, T*H/P*W/P, d_model]
# 添加 CLS Token
cls_tokens = self.cls_token.expand(B, -1, -1)
x = torch.cat([cls_tokens, x], dim=1)
# 位置编码
x = x + self.position_embedding
# Transformer 层
for layer in self.layers:
x = layer(x, T, self.num_patches)
# 分类
x = self.norm(x[:, 0])
x = self.head(x)
return x
class SpatioTemporalAttention(nn.Module):
"""
分离时空注意力
先时间注意力,后空间注意力
理论:
时间注意力: 每个 patch 关注不同时间的同一位置
空间注意力: 每个 patch 关注同一时间的不同位置
分离降低计算量从 O((THW)²) 到 O(T(HW)² + (T²)HW)
"""
def __init__(self, d_model, n_heads):
super().__init__()
self.time_attn = nn.MultiheadAttention(d_model, n_heads, batch_first=True)
self.space_attn = nn.MultiheadAttention(d_model, n_heads, batch_first=True)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.norm3 = nn.LayerNorm(d_model)
self.mlp = nn.Sequential(
nn.Linear(d_model, d_model * 4),
nn.GELU(),
nn.Linear(d_model * 4, d_model)
)
def forward(self, x, T, num_patches):
"""
x: [B, N, D] 其中 N = T * num_patches + 1 (CLS)
"""
B, N, D = x.shape
cls_token = x[:, :1]
patches = x[:, 1:]
# 重塑为 [B, T, P, D]
patches = patches.view(B, T, num_patches, D)
# 时间注意力 (每个 patch 位置独立)
# [B*P, T, D]
patches_flat = patches.permute(0, 2, 1, 3).reshape(B * num_patches, T, D)
time_out, _ = self.time_attn(patches_flat, patches_flat, patches_flat)
patches = patches + time_out.reshape(B, num_patches, T, D).permute(0, 2, 1, 3)
# 空间注意力 (每个时间步独立)
# [B*T, P, D]
patches_flat = patches.reshape(B * T, num_patches, D)
space_out, _ = self.space_attn(patches_flat, patches_flat, patches_flat)
patches = patches + space_out.reshape(B, T, num_patches, D)
# 重塑回 [B, T*P, D]
patches = patches.reshape(B, T * num_patches, D)
# 加回 CLS Token
x = torch.cat([cls_token, patches], dim=1)
# MLP
x = x + self.mlp(self.norm3(x))
return x
"""
TimeSformer 的复杂度分析:
联合时空注意力: O((T·P)²) = O(T²·P²)
分离时空注意力: O(T·P² + T²·P)
当 T=8, P=196 时:
联合: (8×196)² = 2.5M
分离: 8×196² + 8²×196 = 320K
加速比: ~8x
"""
4. 视频分类与检测
4.1 视频分类
class VideoClassifier(nn.Module):
"""
视频分类器
使用预训练的视频模型进行分类
策略:
1. 单片段: 采样一个片段进行分类
2. 多片段: 采样多个片段,取平均
3. 密集采样: 采样所有帧
"""
def __init__(self, backbone, num_classes, num_clips=10):
super().__init__()
self.backbone = backbone
self.num_clips = num_clips
# 分类头
self.head = nn.Linear(backbone.output_dim, num_classes)
def forward(self, video):
"""
video: [B, C, T, H, W]
"""
if self.training:
# 训练时: 单片段
features = self.backbone(video)
logits = self.head(features)
else:
# 测试时: 多片段平均
clips = self.sample_clips(video, self.num_clips)
logits = []
for clip in clips:
features = self.backbone(clip)
logit = self.head(features)
logits.append(logit)
logits = torch.stack(logits).mean(dim=0)
return logits
def sample_clips(self, video, num_clips):
"""
采样多个片段
"""
T = video.shape[2]
clip_length = min(16, T)
clips = []
for _ in range(num_clips):
start = torch.randint(0, T - clip_length + 1, (1,)).item()
clip = video[:, :, start:start+clip_length]
clips.append(clip)
return clips
"""
视频分类的测试策略:
1. 单片段: 采样中心片段
2. 多片段: 均匀采样 N 个片段
3. 密集采样: 滑动窗口
多片段 + 平均: 提高稳定性
"""
4.2 时间动作定位
时间动作定位 (Temporal Action Localization):
任务: 定位动作的起止时间并分类
输入: 长视频
输出: [(start_1, end_1, class_1), (start_2, end_2, class_2), ...]
方法:
1. 自顶向下: 生成候选片段 → 分类
2. 自底向上: 逐帧分类 → 合并
class TemporalActionLocalization(nn.Module):
"""
时间动作定位
理论:
1. 生成候选片段 (proposal)
2. 对每个片段分类
3. 后处理 (NMS)
"""
def __init__(self, feature_dim, num_classes):
super().__init__()
# 特征提取 (使用预训练模型)
self.feature_extractor = None # 预训练的视频模型
# 候选生成网络
self.proposal_net = nn.Sequential(
nn.Conv1d(feature_dim, 512, 3, padding=1),
nn.ReLU(),
nn.Conv1d(512, 2, 1) # 前景/背景
)
# 分类网络
self.classifier = nn.Sequential(
nn.AdaptiveAvgPool1d(1),
nn.Flatten(),
nn.Linear(feature_dim, num_classes)
)
def forward(self, video_features):
"""
video_features: [B, D, T]
"""
# 候选生成
proposal_scores = self.proposal_net(video_features) # [B, 2, T]
# 分类
class_scores = self.classifier(video_features) # [B, num_classes]
return proposal_scores, class_scores
"""
时间动作定位的评估:
mAP@IoU:
计算不同 IoU 阈值下的平均精度
IoU 阈值: 0.5, 0.75, 0.95
tIoU = |预测 ∩ 真实| / |预测 ∪ 真实|
"""
5. 视频分割
5.1 视频目标分割
视频目标分割 (Video Object Segmentation, VOS):
任务: 在视频中分割特定目标
类型:
1. 半监督 VOS: 给定第一帧的掩码,跟踪分割后续帧
2. 无监督 VOS: 自动分割显著目标
3. 参考 VOS: 根据参考图像分割
挑战:
- 目标形变
- 遮挡
- 快速运动
- 相似物体干扰
class VideoObjectSegmentation(nn.Module):
"""
视频目标分割
半监督: 给定第一帧掩码,分割后续帧
理论:
记忆网络: 存储历史帧的特征和掩码
匹配: 当前帧与记忆匹配
分割: 基于匹配结果分割
"""
def __init__(self, feature_dim=256):
super().__init__()
# 特征编码器
self.encoder = nn.Sequential(
nn.Conv2d(3, 64, 3, padding=1),
nn.ReLU(),
nn.Conv2d(64, feature_dim, 3, padding=1),
nn.ReLU()
)
# 记忆网络
self.memory_key = nn.Linear(feature_dim, feature_dim)
self.memory_value = nn.Linear(feature_dim, feature_dim)
# 分割头
self分割_head = nn.Sequential(
nn.Conv2d(feature_dim * 2, 128, 3, padding=1),
nn.ReLU(),
nn.Conv2d(128, 1, 1),
nn.Sigmoid()
)
def forward(self, frame, memory_frames, memory_masks):
"""
frame: [B, 3, H, W] 当前帧
memory_frames: [B, N, 3, H, W] 记忆帧
memory_masks: [B, N, 1, H, W] 记忆掩码
"""
# 当前帧特征
query = self.encoder(frame)
# 记忆特征
memory_features = []
for i in range(memory_frames.shape[1]):
feat = self.encoder(memory_frames[:, i])
memory_features.append(feat)
memory_features = torch.stack(memory_features, dim=1)
# 匹配 (注意力)
query_flat = query.flatten(2).permute(0, 2, 1) # [B, HW, D]
memory_flat = memory_features.flatten(3).permute(0, 1, 3, 2) # [B, N, D, HW]
# 注意力匹配
attn = torch.bmm(query_flat, memory_flat.flatten(0, 1)).view(
query_flat.shape[0], query_flat.shape[1], memory_features.shape[1], -1
)
attn = torch.softmax(attn, dim=-1)
# 加权聚合记忆
memory_values = self.memory_value(memory_flat.flatten(0, 1))
aggregated = torch.bmm(attn.flatten(2), memory_values).view(query.shape)
# 分割
combined = torch.cat([query, aggregated], dim=1)
mask = self分割_head(combined)
return mask
"""
视频分割的挑战:
1. 目标形变: 目标形状变化
2. 遮挡: 目标被遮挡
3. 快速运动: 目标移动快
4. 相似物体: 背景中有相似物体
解决:
- 记忆网络: 存储历史信息
- 注意力匹配: 灵活的特征匹配
- 在线更新: 随时更新目标模型
"""
5.2 全景视频分割
class PanopticVideoSegmentation(nn.Module):
"""
全景视频分割
统一语义分割和实例分割的视频版本
理论:
stuff (背景): 语义分割 + 时序一致性
things (物体): 实例分割 + 跟踪
"""
def __init__(self, num_things, num_stuff):
super().__init__()
self.num_things = num_things
self.num_stuff = num_stuff
# 语义分割分支
self.semantic_head = SemanticHead(num_things + num_stuff)
# 实例分割分支
self.instance_head = InstanceHead(num_things)
# 跟踪分支
self.tracking_head = TrackingHead()
def forward(self, video):
"""
video: [B, C, T, H, W]
"""
# 语义分割
semantic_logits = self.semantic_head(video)
# 实例分割
instance_masks, instance_ids = self.instance_head(video)
# 跟踪
tracks = self.tracking_head(instance_masks)
return semantic_logits, instance_masks, tracks
6. 视频生成基础
6.1 视频生成任务
视频生成任务:
1. 文本到视频 (Text-to-Video):
输入: 文本描述
输出: 视频
2. 图像到视频 (Image-to-Video):
输入: 单张图像
输出: 视频
3. 视频预测 (Video Prediction):
输入: 历史帧
输出: 未来帧
4. 视频插值 (Video Interpolation):
输入: 起始帧和结束帧
输出: 中间帧
5. 视频编辑 (Video Editing):
输入: 视频 + 编辑指令
输出: 编辑后的视频
6.2 视频生成的挑战
视频生成的挑战:
1. 时间一致性:
相邻帧应该平滑过渡
物体应该保持一致
2. 运动合理性:
运动应该符合物理规律
物体应该有合理的轨迹
3. 计算量:
生成 T 帧比生成 1 帧难 T 倍
需要大量显存
4. 长视频:
生成长视频容易累积误差
需要特殊的策略
7. 扩散模型视频生成
7.1 视频扩散模型
视频扩散模型的核心思想:
将扩散模型扩展到视频
在时空维度上进行扩散
前向过程:
对视频的每一帧添加噪声
反向过程:
从噪声中恢复视频
关键: 如何建模帧间关系
class VideoDiffusionModel(nn.Module):
"""
视频扩散模型
核心组件:
1. 时空 UNet: 处理视频的去噪网络
2. 时间注意力: 建模帧间关系
3. 条件注入: 文本/图像条件
"""
def __init__(self, in_channels=3, model_channels=128,
out_channels=3, num_frames=16):
super().__init__()
self.num_frames = num_frames
# 时空 UNet
self.unet = SpatioTemporalUNet(
in_channels=in_channels,
model_channels=model_channels,
out_channels=out_channels,
num_frames=num_frames
)
# 时间嵌入
self.time_embed = nn.Sequential(
SinusoidalPositionEmbedding(model_channels),
nn.Linear(model_channels, model_channels * 4),
nn.SiLU(),
nn.Linear(model_channels * 4, model_channels)
)
def forward(self, x, t, text_embedding=None):
"""
x: [B, C, T, H, W] 噪声视频
t: [B] 时间步
text_embedding: [B, L, D] 文本嵌入 (可选)
"""
# 时间嵌入
t_emb = self.time_embed(t)
# 去噪
noise_pred = self.unet(x, t_emb, text_embedding)
return noise_pred
class SpatioTemporalUNet(nn.Module):
"""
时空 UNet
在空间 UNet 的基础上添加时间注意力
结构:
空间卷积 → 时间注意力 → 空间卷积 → ...
"""
def __init__(self, in_channels, model_channels, out_channels, num_frames):
super().__init__()
# 空间编码器
self.spatial_enc = nn.ModuleList([
ResBlock(in_channels, model_channels),
ResBlock(model_channels, model_channels * 2),
ResBlock(model_channels * 2, model_channels * 4)
])
# 时间注意力层
self.time_attns = nn.ModuleList([
TemporalAttention(model_channels),
TemporalAttention(model_channels * 2),
TemporalAttention(model_channels * 4)
])
# 瓶颈
self.bottleneck = ResBlock(model_channels * 4, model_channels * 4)
# 空间解码器
self.spatial_dec = nn.ModuleList([
ResBlock(model_channels * 8, model_channels * 2),
ResBlock(model_channels * 4, model_channels),
ResBlock(model_channels * 2, model_channels)
])
# 输出
self.out = nn.Conv3d(model_channels, out_channels, 1)
def forward(self, x, t_emb, text_embedding=None):
"""
x: [B, C, T, H, W]
t_emb: [B, D]
"""
B, C, T, H, W = x.shape
# 编码器
skips = []
for enc, t_attn in zip(self.spatial_enc, self.time_attns):
x = enc(x)
# 时间注意力
x_flat = x.flatten(3).permute(0, 2, 3, 1) # [B, T, HW, C]
x_flat = t_attn(x_flat)
x = x_flat.permute(0, 3, 1, 2).view(B, -1, T, H, W)
skips.append(x)
# 瓶颈
x = self.bottleneck(x)
# 解码器
for dec in self.spatial_dec:
skip = skips.pop()
x = torch.cat([x, skip], dim=1)
x = dec(x)
# 输出
x = self.out(x)
return x
"""
视频扩散模型的关键技术:
1. 时间注意力:
建模帧间关系
保持时间一致性
2. 分层生成:
先生成低分辨率视频
再逐步超分辨率
3. 条件注入:
文本条件: CLIP 文本嵌入
图像条件: 参考图像特征
"""
7.2 Stable Video Diffusion
Stable Video Diffusion (SVD):
基于 Stable Diffusion 的视频生成模型
架构:
图像条件 → 图像编码器 → 条件嵌入
↓
噪声 → 时空 UNet → 去噪视频
↑
时间步 + 文本嵌入
训练策略:
1. 图像预训练: 在图像上预训练 UNet
2. 视频微调: 在视频上微调
3. 高质量数据: 使用高质量视频数据集
class StableVideoDiffusion(nn.Module):
"""
Stable Video Diffusion
基于图像条件的视频生成
理论:
使用预训练的图像扩散模型
添加时间层进行视频生成
"""
def __init__(self):
super().__init__()
# 图像编码器 (冻结)
self.image_encoder = CLIPImageEncoder()
# 视频 UNet (从图像 UNet 初始化)
self.unet = SpatioTemporalUNet(
in_channels=4, # 潜在空间
model_channels=320,
out_channels=4,
num_frames=25
)
# VAE
self.vae = AutoencoderKL()
def forward(self, video, image_condition):
"""
video: [B, C, T, H, W]
image_condition: [B, C, H, W] 参考图像
"""
# 编码参考图像
image_emb = self.image_encoder(image_condition)
# 编码视频到潜在空间
video_latent = self.vae.encode(video)
# 扩散过程
t = torch.randint(0, 1000, (video.shape[0],))
noise = torch.randn_like(video_latent)
noisy_latent = self.q_sample(video_latent, t, noise)
# 去噪
noise_pred = self.unet(noisy_latent, t, image_emb)
return noise_pred
"""
SVD 的应用:
1. 图像动画:
给定一张图片,生成动画
2. 视频编辑:
编辑视频内容
3. 视频插值:
生成中间帧
"""
8. 视频预测与插值
8.1 视频预测
视频预测 (Video Prediction):
输入: 历史帧 [f₁, f₂, ..., f_t]
输出: 未来帧 [f_{t+1}, f_{t+2}, ..., f_{t+T}]
方法:
1. 确定性预测: 直接预测未来帧
2. 随机预测: 从分布中采样
3. 条件预测: 基于动作/文本预测
class VideoPredictionModel(nn.Module):
"""
视频预测模型
输入历史帧,预测未来帧
理论:
编码器提取历史特征
解码器生成未来帧
"""
def __init__(self, input_frames=4, future_frames=4):
super().__init__()
self.input_frames = input_frames
self.future_frames = future_frames
# 编码器
self.encoder = nn.Sequential(
nn.Conv3d(3, 64, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.ReLU(),
nn.Conv3d(64, 128, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(2, 2, 2))
)
# 循环网络 (LSTM)
self.rnn = nn.LSTM(128, 256, batch_first=True)
# 解码器
self.decoder = nn.Sequential(
nn.ConvTranspose3d(256, 128, kernel_size=(2, 2, 2), stride=(2, 2, 2)),
nn.ReLU(),
nn.Conv3d(128, 64, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.ReLU(),
nn.Conv3d(64, 3, kernel_size=(3, 3, 3), padding=(1, 1, 1)),
nn.Sigmoid()
)
def forward(self, history_frames):
"""
history_frames: [B, C, T, H, W]
"""
# 编码历史帧
features = self.encoder(history_frames)
# 重塑为序列
B, C, T, H, W = features.shape
features = features.flatten(3).permute(0, 2, 1, 3).reshape(B, T, -1)
# RNN 处理
output, (h, c) = self.rnn(features)
# 生成未来帧
future_features = []
for _ in range(self.future_frames):
output, (h, c) = self.rnn(output[:, -1:], (h, c))
future_features.append(output)
future_features = torch.cat(future_features, dim=1)
future_features = future_features.reshape(B, -1, C, H, W).permute(0, 2, 1, 3, 4)
# 解码
future_frames = self.decoder(future_features)
return future_frames
"""
视频预测的挑战:
1. 不确定性: 未来有多种可能
2. 模糊: 预测往往模糊
3. 累积误差: 自回归生成会累积误差
4. 长期预测: 长期预测困难
"""
8.2 视频插值
class VideoInterpolation(nn.Module):
"""
视频插值模型
输入两帧,生成中间帧
理论:
光流估计: 估计两帧之间的运动
融合: 基于光流融合两帧
"""
def __init__(self):
super().__init__()
# 光流估计网络
self.flow_estimator = FlowEstimationNet()
# 融合网络
self融合_net = nn.Sequential(
nn.Conv2d(3 * 2 + 2, 64, 3, padding=1), # 两帧 + 光流
nn.ReLU(),
nn.Conv2d(64, 64, 3, padding=1),
nn.ReLU(),
nn.Conv2d(64, 3, 3, padding=1),
nn.Sigmoid()
)
def forward(self, frame1, frame2):
"""
frame1: [B, 3, H, W]
frame2: [B, 3, H, W]
"""
# 估计光流
flow_forward = self.flow_estimator(frame1, frame2)
flow_backward = self.flow_estimator(frame2, frame1)
# 变形
warped1 = warp_frame(frame1, flow_forward * 0.5)
warped2 = warp_frame(frame2, flow_backward * 0.5)
# 融合
combined = torch.cat([warped1, warped2, flow_forward], dim=1)
interpolated = self融合_net(combined)
return interpolated
"""
视频插值的方法:
1. 基于光流: 估计运动,变形融合
2. 基于核: 学习插值核
3. 基于相位: 频域方法
4. 基于深度学习: 端到端学习
"""
9. 评估指标与数据集
9.1 评估指标
┌─────────────────────────────────────────────────────────────────────┐
│ 视频任务评估指标 │
├─────────────────┬───────────────────────────────────────────────────┤
│ 任务 │ 指标 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 动作识别 │ Top-1 Accuracy, Top-5 Accuracy │
│ │ mAP (多标签分类) │
├─────────────────┼───────────────────────────────────────────────────┤
│ 时间动作定位 │ mAP@tIoU (0.5, 0.75, 0.95) │
│ │ Average mAP │
├─────────────────┼───────────────────────────────────────────────────┤
│ 视频生成 │ FVD (Frechet Video Distance) │
│ │ IS (Inception Score) │
│ │ LPIPS, SSIM, PSNR │
├─────────────────┼───────────────────────────────────────────────────┤
│ 视频分割 │ mIoU (语义), AP (实例) │
│ │ J&F (VOS 指标) │
├─────────────────┼───────────────────────────────────────────────────┤
│ 视频预测 │ SSIM, PSNR, LPIPS │
│ │ FVD │
└─────────────────┴───────────────────────────────────────────────────┘
class VideoMetrics:
"""视频评估指标"""
@staticmethod
def top_k_accuracy(predictions, labels, k=1):
"""
Top-K 准确率
"""
_, pred_topk = predictions.topk(k, dim=1)
correct = pred_topk.eq(labels.view(-1, 1).expand_as(pred_topk))
return correct.float().sum(1).mean().item()
@staticmethod
def temporal_iou(pred_segments, gt_segments):
"""
时间 IoU
tIoU = |预测 ∩ 真实| / |预测 ∪ 真实|
"""
intersection_start = torch.max(pred_segments[:, 0], gt_segments[:, 0])
intersection_end = torch.min(pred_segments[:, 1], gt_segments[:, 1])
intersection = torch.clamp(intersection_end - intersection_start, min=0)
pred_duration = pred_segments[:, 1] - pred_segments[:, 0]
gt_duration = gt_segments[:, 1] - gt_segments[:, 0]
union = pred_duration + gt_duration - intersection
iou = intersection / (union + 1e-8)
return iou
@staticmethod
def fvd(real_features, fake_features):
"""
FVD (Frechet Video Distance)
类似于 FID,但用于视频
FVD = ‖μ_r - μ_f‖² + Tr(Σ_r + Σ_f - 2(Σ_r Σ_f)^(1/2))
"""
mu_real = real_features.mean(dim=0)
mu_fake = fake_features.mean(dim=0)
sigma_real = torch.cov(real_features.T)
sigma_fake = torch.cov(fake_features.T)
diff = mu_real - mu_fake
covmean = torch.linalg.sqrtm(sigma_real @ sigma_fake)
fvd = diff @ diff + torch.trace(sigma_real + sigma_fake - 2 * covmean)
return fvd.real
"""
FVD 的理论:
FVD 衡量生成视频与真实视频的分布距离
使用视频特征 (如 I3D 特征)
计算 Fréchet 距离
越低越好
"""
9.2 主要数据集
┌─────────────────────────────────────────────────────────────────────┐
│ 视频数据集 │
├─────────────────┬───────────┬───────────────────────────────────────┤
│ 数据集 │ 规模 │ 用途 │
├─────────────────┼───────────┼───────────────────────────────────────┤
│ Kinetics-400 │ 300K 视频│ 动作识别 (400 类) │
│ Kinetics-700 │ 650K 视频│ 动作识别 (700 类) │
│ UCF-101 │ 13K 视频 │ 动作识别 (101 类) │
│ HMDB-51 │ 7K 视频 │ 动作识别 (51 类) │
│ ActivityNet │ 20K 视频 │ 时间动作定位 │
│ THUMOS │ 1K 视频 │ 时间动作定位 │
│ DAVIS │ 60 视频 │ 视频目标分割 │
│ YouTube-VOS │ 4K 视频 │ 视频目标分割 │
│ WebVid-10M │ 10M 视频 │ 视频生成预训练 │
│ UCF-101 │ 13K 视频 │ 视频生成评估 │
└─────────────────┴───────────┴───────────────────────────────────────┘
10. 应用与前沿
10.1 应用领域
视频理解与生成的应用:
1. 自动驾驶:
视频理解: 场景理解、行为预测
3D 检测: 多帧融合
2. 安防监控:
行为分析: 异常检测
人员跟踪: 跨摄像头跟踪
3. 短视频:
内容理解: 标签、分类
推荐: 基于内容的推荐
生成: 自动剪辑
4. 影视制作:
视频生成: AI 生成视频
视频编辑: 自动编辑
特效: 视觉特效
5. 医学:
手术视频: 动作识别
医学影像: 时序分析
6. 体育:
动作分析: 运动员动作
战术分析: 比赛分析
10.2 前沿方向
视频理解与生成的前沿:
1. 长视频理解:
处理数分钟甚至数小时的视频
层次化表示
2. 高质量视频生成:
Sora 等模型
长视频生成
3. 视频编辑:
文本引导的视频编辑
保持一致性
4. 多模态视频理解:
视觉 + 音频 + 文本
统一理解
5. 实时视频处理:
边缘设备部署
低延迟推理
6. 3D 视频:
3D 场景视频
自由视角视频
附录
A. 视频技术发展时间线
2014 ──┬── 双流网络
│
2015 ──┼── C3D (3D 卷积)
│
2017 ──┼── I3D (膨胀 3D 卷积)
│
2019 ──┼── SlowFast
│
2020 ──┼── X3D (高效 3D 网络)
│
2021 ──┼── TimeSformer (视频 Transformer)
│
2022 ──┼── VideoMAE (掩码自编码器)
│
2023 ──┼── Stable Video Diffusion
│
2024 ──┼── Sora (大规模视频生成)
│
2025+ ──┴── 更长、更高质量的视频生成
B. 核心公式速查
| 公式 |
含义 |
| C® = ∫ T(t)·σ·c dt |
体渲染方程 |
| tIoU = |P∩G| / |P∪G| |
时间交并比 |
| FVD = ‖μ_r-μ_f‖² + Tr(Σ_r+Σ_f-2√(Σ_rΣ_f)) |
Frechet 视频距离 |
| Attention(Q,K,V) = softmax(QK^T/√d)V |
注意力机制 |
C. 推荐资源
- Feichtenhofer, C., et al. (2019). SlowFast Networks
- Bertasius, G., et al. (2021). TimeSformer
- Tong, Z., et al. (2022). VideoMAE
- Blattmann, A., et al. (2023). Stable Video Diffusion