
Transformers 中的 TimeSformer首个视频 Transformer 的架构拆解与视频分类实战【免费下载链接】transformers Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers导读TimeSformerTime-Space Transformer由 Facebook Research 于 2021 年提出是动作识别领域的首个视频 Transformer以仅用自注意力建模空间与时间的方式摆脱了 3D 卷积。本文以官方模型文档 docs/source/en/model_doc/timesformer.md 为主体结合 modeling_timesformer.py、configuration_timesformer.py 与 video_processing_timesformer.py 等源码与测试帮你掌握 divided attention 的原理、每个配置项的取值与作用以及从视频解码、预处理到模型推理/微调的完整链路。TimeSformer 是什么TimeSformer 论文标题为《TimeSformer: Is Space-Time Attention All You Need for Video Understanding?》作者来自 Facebook Research。该工作在动作识别领域具有里程碑意义——它是第一个视频 Transformer并启发了大量基于 Transformer 的视频理解与视频分类研究。论文要点可概括为来自原文档引用的论文摘要提出一种无卷积的视频分类方法完全建立在空间与时间上的自注意力之上将标准 Transformer 架构适配到视频直接从一帧帧的图像块序列中学习时空特征通过实验对比了不同的自注意力方案发现divided attention分离式注意力——在每个 block 内分别执行时间注意力与空间注意力——在所比较的设计中取得了最佳视频分类精度相比 3D 卷积网络TimeSformer 训练更快在精度仅有小幅下降时可获得显著更高的测试效率并且能够处理更长的视频片段超过一分钟。在本文所研究的transformers仓库中TimeSformer 于 2022-12-02 被合入由 fcakyon模块目录下包含 5 个文件文件职责configuration_timesformer.pyTimesformerConfig配置类modeling_timesformer.pyTimesformerModel/TimesformerForVideoClassification等 PyTorch 模块749 行video_processing_timesformer.pyTimesformerVideoProcessor视频处理器convert_timesformer_to_pytorch.py官方 PyTorch 权重转换脚本__init__.py模块导出惰性导入Usage tips如何挑选预训练模型与帧数原文档特别强调两点使用经验这也是 TimeSformer 容易踩坑的地方存在很多预训练变体请根据其训练数据集选择模型。例如在文档与测试用例中出现的facebook/timesformer-base-finetuned-k400、配置类 docstring 中默认标注的facebook/timesformer-base-finetuned-k600分别对应在 Kinetics-400、Kinetics-600 上微调的权重。慢速测试 test_modeling_timesformer.py 中也直接加载facebook/timesformer-base-finetuned-k400并断言输出 logits 形状为(1, 400)。每个 clip 的输入帧数会随模型规模变化选择预训练模型时应一并考虑num_frames参数。默认配置num_frames 8但你使用其他变体时必须以该权重训练/推理时所采用的帧数为准这直接对应配置中的num_frames字段。架构核心Divided Space-Time Attention 源码解读TimeSformer 的核心创新是注意力组织方式。配置项attention_type决定了使用哪种方案取值必须是divided_space_time默认时间注意力与空间注意力分开、按序执行space_only仅做空间注意力joint_space_time在全部 token 上联合做时空注意力。在 modeling_timesformer.py 中TimesformerLayer的forward对非法取值会直接抛出ValueError。以默认的divided_space_time为例其执行流程可拆为两步第一步时间注意力Temporal Attention去掉[CLS]token把剩余 token 从形状(batch, H//p × W//p × frames, dim)重排为(batch × H//p × W//p, frames, dim)使同一空间位置的所有帧排在一起经由temporal_layernorm→ 独立的temporal_attention→drop_path→temporal_dense完成时间维交互结果加回到原始 token 序列作为后续空间注意力的输入。第二步空间注意力Spatial Attention将时间注意力输出按帧拆开重排为(batch × frames, H//p × W//p, dim)并把初始[CLS]复制到每一帧作为该帧的类别 token每帧内部执行标准的空间自注意力layernorm_before→self.attention→drop_path空间注意力输出的各帧[CLS]最后通过torch.mean(cls_token, 1, keepdimTrue)在时间维上取平均得到整段视频统一的类别表示再拼接回序列走 MLP。从源码结构看时间与空间两个子块各自带独立的 LayerNorm 与残差并且都依赖层间随机深度drop_pathdrop_path_rate在各层之间按torch.linspace(0, config.drop_path_rate, num_hidden_layers)线性递增。输入嵌入Patch 时空位置编码TimesformerEmbeddings负责把原始视频张量转成 token 序列其中TimesformerPatchEmbeddings用一个nn.Conv2d(num_channels, hidden_size, kernel_sizepatch_size, stridepatch_size)完成逐帧分块投影num_patches (W//p) × (H//p)每个视频拼接 1 个可学习的cls_token空间位置编码维度为num_patches 1当attention_type ! space_only时额外引入帧级时间位置编码time_embeddings维度num_frames位置编码与时间编码均具备长度插值能力推理时若输入帧数或空间分辨率与预训练不一致代码会用nn.functional.interpolate(..., modenearest)动态 resize 位置编码后再相加这正是能用更长视频片段推理的实现基础。模型外壳与输出TimesformerModel裸模型embeddings→TimesformerEncoder12 层→ 末尾layernorm。输出为BaseModelOutput其中last_hidden_state形状为(batch, 1 num_frames × num_patches, hidden_size)。例如 8 帧、224×224、patch 16 时得到(1, 1569, 768)1 个 CLS 8×196 个 token。TimesformerForVideoClassification在裸模型之上叠加一个线性分类头输入取last_hidden_state[:, 0]即平均后的 CLS 表示映射到config.num_labels。两者都支持output_attentions、output_hidden_states、return_dict、梯度检查点supports_gradient_checkpointing True主输入名为pixel_values输入张量形状约定为(batch_size, num_frames, num_channels, height, width)。TimesformerConfig 配置参数一览从 configuration_timesformer.py 可以拿到全部默认值。TimesformerConfig的model_type为timesformer下面是完整字段表参数默认值说明image_size224输入视频每帧的短边分辨率可传 int 或(H, W)二元组patch_size16分块尺寸可传 int 或(H, W)二元组num_channels3输入通道数RGBnum_frames8每个 clip 采样的帧数选择预训练变体时需一致hidden_size768token 嵌入维度num_hidden_layers12Transformer 层数num_attention_heads12注意力头数intermediate_size3072MLP 中间层维度hidden_actgelu隐藏层激活函数hidden_dropout_prob0.0隐藏层 dropout 概率attention_probs_dropout_prob0.0注意力权重 dropoutinitializer_range0.02权重截断正态初始化标准差layer_norm_eps1e-6LayerNorm epsilonqkv_biasTrueQKV 投影是否带 biasattention_typedivided_space_time注意力方案divided_space_time/space_only/joint_space_timedrop_path_rate0随机深度Stochastic Depth最大概率随层线性递增base规模即上表默认组合768/12/12/3072与经典 ViT-Base 一致。从一个配置直接构建模型的方式如下配置类自带示例from transformers import TimesformerConfig, TimesformerModel # 以 timesformer-base 风格初始化配置 configuration TimesformerConfig() # 由配置构建模型随机初始化未加载权重 model TimesformerModel(configuration) # 读取模型配置 configuration model.configTimesformerVideoProcessor视频如何变成模型输入TimeSformer 的预处理逻辑封装在 video_processing_timesformer.py 的TimesformerVideoProcessor中。它继承自BaseVideoProcessor类级默认值直接写明了预处理流水线的每一环属性值含义resamplePILImageResampling.BILINEAR缩放采用双线性插值size{shortest_edge: 224}先按最短边缩放到 224default_to_squareFalse不强制方形缩放crop_size{height: 224, width: 224}随后中心裁剪到 224×224rescale_factor1 / 255像素值缩放到[0, 1]image_mean/image_stdImageNet 默认值标准化do_resize/do_center_crop/do_rescale/do_normalize/do_convert_rgb均True各步骤默认开启do_sample_framesFalse处理器不负责帧采样model_input_names[pixel_values]输出张量键名注意do_sample_frames默认为False意味着帧采样需要你在读取视频时自行完成通常用 PyAV 解码并按均匀间隔抽取num_frames帧处理器只负责把抽好的帧做 resize、crop、归一化并组装为pixel_values。其preprocess方法会把内部产出的pixel_values_videos改名为pixel_values再返回保证与模型输入名对齐。对应的常规属性测试见 test_video_processing_timesformer.py。实战一抽取特征TimesformerModel加载一个预训练模型做前向推理得到视频的最后一层隐藏状态。官方在forward的 docstring 中给出的完整示例以 PyAV 解码视频、均匀采样 8 帧其流程具有代表性import av import numpy as np from transformers import TimesformerModel, TimesformerVideoProcessor from huggingface_hub import hf_hub_download np.random.seed(0) def read_video_pyav(container, indices): 用 PyAV 解码视频返回 (num_frames, height, width, 3) 的 np.ndarray frames [] container.seek(0) start_index indices[0] end_index indices[-1] for i, frame in enumerate(container.decode(video0)): if i end_index: break if i start_index and i in indices: frames.append(frame) return np.stack([x.to_ndarray(formatrgb24) for x in frames]) def sample_frame_indices(clip_len, frame_sample_rate, seg_len): 从视频中均匀抽取 clip_len 个帧索引实际间隔由 frame_sample_rate 控制 converted_len int(clip_len * frame_sample_rate) end_idx np.random.randint(converted_len, seg_len) start_idx end_idx - converted_len indices np.linspace(start_idx, end_idx, numclip_len) indices np.clip(indices, start_idx, end_idx - 1).astype(np.int64) return indices # 10 秒、30 FPS 的视频约 300 帧 file_path hf_hub_download( repo_idnielsr/video-demo, filenameeating_spaghetti.mp4, repo_typedataset ) container av.open(file_path) # 采样 8 帧并解码 indices sample_frame_indices(clip_len8, frame_sample_rate4, seg_lencontainer.streams.video[0].frames) video read_video_pyav(container, indices) # 预处理TimesformerVideoProcessor 或 AutoVideoProcessor 均可加载该模型处理器 processor TimesformerVideoProcessor.from_pretrained(facebook/timesformer-base-finetuned-k400) model TimesformerModel.from_pretrained(facebook/timesformer-base-finetuned-k400) # 组装输入并前向 inputs processor(list(video), return_tensorspt) outputs model(**inputs) last_hidden_states outputs.last_hidden_state list(last_hidden_states.shape) # [1, 1569, 768]1 个 CLS 8 帧 × 196 个 patch实战二视频分类TimesformerForVideoClassification用于下游分类时把TimesformerModel换成带分类头的TimesformerForVideoClassification。分类头只需输入最后一帧聚合得到的 CLS 向量outputs[0][:, 0]由nn.Linear(hidden_size, num_labels)映射到类别数。import av import torch import numpy as np from transformers import TimesformerForVideoClassification, TimesformerVideoProcessor from huggingface_hub import hf_hub_download np.random.seed(0) # read_video_pyav / sample_frame_indices 定义同前此处省略 file_path hf_hub_download( repo_idnielsr/video-demo, filenameeating_spaghetti.mp4, repo_typedataset ) container av.open(file_path) indices sample_frame_indices(clip_len8, frame_sample_rate1, seg_lencontainer.streams.video[0].frames) video read_video_pyav(container, indices) processor TimesformerVideoProcessor.from_pretrained(facebook/timesformer-base-finetuned-k400) model TimesformerForVideoClassification.from_pretrained(facebook/timesformer-base-finetuned-k400) inputs processor(list(video), return_tensorspt) with torch.no_grad(): outputs model(**inputs) logits outputs.logits # 预测 Kinetics-400 中的某一类 predicted_label logits.argmax(-1).item() print(model.config.id2label[predicted_label]) # eating spaghetti关于 labels 与损失在训练/微调时传入labels形状为(batch_size,)的torch.LongTensor即可自动计算损失无需手动拼接 loss 函数。源码中根据num_labels与 label 类型自动选择num_labels 1走回归使用MSELossnum_labels 1且 label 为整型单标签分类使用CrossEntropyLoss其余情况多标签分类使用BCEWithLogitsLoss。输出封装为ImageClassifierOutput同时携带loss、logits以及可选的hidden_states/attentions。权重来源与验证仓库自带的慢速测试slow直接验证了真实权重与预处理对齐test_modeling_timesformer.py 加载facebook/timesformer-base-finetuned-k400断言 logits 形状为(1, 400)并与保存的期望输出做rtol2e-4级别的数值比对。如果你希望从官方原始实现转换权重可以参考 convert_timesformer_to_pytorch.py其中包含 checkpoint 下载、键名映射rename_key与状态字典转换逻辑时间序列相关的键会按 TimeSformer 的命名规则对齐到 HF 格式。延伸阅读官方视频分类任务指南 docs/source/en/tasks/video_classification.md 提供了从数据集、图像处理器到训练与评估的完整任务级教程是使用本模型的直接下一步分类任务示例脚本可参考examples/pytorch中其他任务的同类写法配合 视频分类任务指南 快速落地更多用法可查看模型原始文档 docs/source/en/model_doc/timesformer.md。【免费下载链接】transformers Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考