- 人工智能
- 计算机视觉
- 深度学习
【免费下载链接】mmaction2
OpenMMLab's Next Generation Video Understanding Toolbox and Benchmark
视频-文本检索是多模态理解中的核心任务:给定一段视频,在大规模文本库中召回相关描述(或反之)。mmaction2 提供的 CLIP4Clip 方案,将 OpenAI CLIP 在图像-文本上预训练获得的视觉概念知识,以端到端的方式迁移到视频-文本检索任务上:用 CLIP 视觉编码器逐帧编码视频帧,再用一个轻量 adapter(默认简单均值池化)把帧级特征聚合成视频级特征,与文本特征在共享嵌入空间中做对称对比学习。读完本文,你将掌握该方案的模型结构、关键配置参数的含义(如frozen_layers、adapter 选择)、MSRVTT-9k 数据准备、数据增广流水线,以及完整的训练与测试命令,并能从源码层面理解损失计算、分布式特征聚合与评测指标的底层实现。
算法背景与仓库中的模型结构
CLIP4Clip 的原始论文为CLIP4Clip: An Empirical Study of CLIP for End to End Video Clip Retrieval(该文档在 metafile.yml 中以Paper字段登记)。论文摘要(见 configs/retrieval/clip4clip/README.md)指出,该方法通过实证研究回答了四个问题:图像特征是否足以支撑视频-文本检索、在大规模视频-文本数据上后预训练对性能的影响、建模视频帧间时序依赖的实际机制,以及超参数在检索任务上的敏感性。实验结果表明,从 CLIP 迁移而来的 CLIP4Clip 在 MSR-VTT、MSVC、LSMDC、ActivityNet 和 DiDeMo 等多个视频-文本检索数据集上取得了当时领先的结果。
在 mmaction2 中,该模型对应CLIPSimilarity,实现位于 mmaction/models/similarity/clip_similarity.py。它继承mmengine的BaseModel,通过clip_arch参数指定 CLIP 架构,官方支持的取值为'ViT-B/32'、'ViT-B/16'、'ViT-L/14'和'ViT-L/14@336px';构造时会调用clip.load(clip_arch)从 OpenAI CLIP 加载预训练权重(因此需要额外安装 CLIP 包,源码中在ImportError时给出的提示是pip install git+https://github.com/openai/CLIP.git,openai-clip亦已列入 requirements/optional.txt)。
模型前向包含三条分支,对应forward的三种 mode:
tensor模式:只走extract_feat,输出未归一化的视频特征与文本特征,用于检索时批量收集特征;loss模式:用于训练,计算对称对比损失(后文详述);predict模式:将每对样本的video_feature与text_feature(均为 512 维,见测试用例 tests/models/similarity/test_clip_similarity.py 中的断言)封装进data_sample.features供评测器使用。
视频特征与文本特征的编码器分别是encode_video与encode_text:前者把(B, N, C, H, W)的视频 reshape 成(B*N, C, H, W)送入 CLIP 视觉塔得到帧级特征,再经 adapter 聚合为视频级特征;后者直接调用 CLIP 文本塔。两个特征在extract_feat中做 L2 归一化后再返回。
帧级到视频级的聚合:两种 Adapter
帧级特征聚合到视频级特征是 CLIP4Clip 建模"帧间时序依赖"的切入点。mmaction/models/similarity/adapters.py 提供两种实现,均在 mmaction/models/similarity/init.py 中导出:
SimpleMeanAdapter:对帧维度做均值池化,即x.mean(dim=self.dim),默认dim=1。它无可学习参数,正是 MSRVTT-9k 官方配置所用的 adapter;TransformerAdapter:带可学习位置编码(num_segs个、transformer_width维)的浅层 Transformer,前向为"位置编码相加 → Transformer → 残差相加 → 帧维均值",参数包括num_segs、transformer_width、transformer_heads、transformer_layers。
单元测试 tests/models/similarity/test_adapters.py 对两种 adapter 的输入输出形状做了验证。选择哪个 adapter 属于论文实证研究的一部分:均值池化是"图像特征是否足够"这一问题的轻量验证方案,而 TransformerAdapter 则引入显式的帧间建模能力。
frozen_layers:控制 CLIP 冻结范围
CLIPSimilarity还有一个重要的调优参数frozen_layers,语义为"冻结前 N 层",取-1表示不冻结任何参数。从 _freeze_stages 的实现看,冻结规则是把 CLIP 参数分为两组:top_layers(ln_final、text_projection、logit_scale、visual.ln_post、visual.proj)永远保持可训练;mid_layers(visual.transformer.resblocks、transformer.resblocks)中只有层号>= frozen_layers的残差块保持可训练,其余全部冻结。测试用例 tests/models/similarity/test_clip_similarity.py 分别在frozen_layers取-1、0、6、12时断言了requires_grad分布,确认该逻辑对 ViT-B/32(12 个视觉残差块)逐层生效。
MSRVTT-9k 官方结果与预训练权重
CLIP4Clip 的官方结果表(继承自 configs/retrieval/clip4clip/README.md,并与 metafile.yml 的Results字段一致):
| frame sampling strategy | resolution | gpus | backbone | adapter | pretrain | Recall@1 | Recall@5 | Recall@10 | MdR | MnR | testing protocol |
|---|---|---|---|---|---|---|---|---|---|---|---|
| uniform 12 | 224x224 | 8 | ViT-B/32 | Mean | clip | 43.1 | 69.4 | 78.9 | 2.0 | 16.8 | 1 clips x 1 crop |
- 对应配置:configs/retrieval/clip4clip/clip4clip_vit-base-p32-res224-clip-pre_8xb16-u12-5e_msrvtt-9k-rgb.py
- 预训练权重与训练日志由 metafile 的
Weights/Training Log字段指向 OpenMMLab 官方下载站(download.openmmlab.com下的retrieval/clip4clip/...路径),可直接用于测试。 - metafile 元数据:
Batch Size: 16、Epochs: 5、Training Data: MSRVTT-9k、Training Resources: 8 GPUs。
从源码结构看,Recall@k、MdR(中位排名)、MnR(平均排名)这组指标由 mmaction/evaluation/metrics/retrieval_metric.py 中的RetrievalMetric计算:它把全部视频/文本特征归一化后做相似度矩阵,取每条查询对角线相似度的排序名次ind,Rk为名次< k的查询占比,MdR = median(ind) + 1,MnR = mean(ind) + 1。
数据准备:MSRVTT-9k
训练所用的数据集为 MSRVTT 的 9k 训练划分(train_9k.json)与 JSFUSION 测试集(test_JSFUSION.json)。数据准备入口在 tools/data/video_retrieval/,执行:
cd tools/data/video_retrieval bash prepare_msrvtt.sh完成后目录结构为(同一 README 中给出的结构):
mmaction2 ├── mmaction ├── tools ├── configs ├── data │ ├── video_retrieval │ │ └── msrvtt │ │ ├── train_9k.json │ │ ├── train_7k.json │ │ ├── test_JSFUSION.json │ │ └─── videos │ │ ├── video0.mp4 │ │ ├── ... │ │ └── video9999.mp4该目录下还提供prepare_msvd.sh用于准备 MSVD 数据集(生成train.json/val.json/test.json与视频文件)。
VideoTextDataset:标注文件如何变成训练样本
数据集类VideoTextDataset位于 mmaction/datasets/video_text_dataset.py。它的load_data_list逻辑:读取标注 JSON(格式为{视频相对路径: [文本1, 文本2, ...]}),对每个视频把其每条文本展开为一个(filename, text)对——即一个视频有 k 条文本就产生 k 条样本。配置中ann_file、data_prefix=dict(video='videos')与之对应。注意:VideoTextDataset本身不保存"一个视频对应几条文本"的分组信息,视频/文本计数由MsrVTT系数据集提供(见 mmaction/datasets/msrvtt_datasets.py 中self.num_videos/self.num_texts的赋值),供检索循环按视频数/文本数统计指标时使用。
训练流水线逐项解读
官方配置的train_pipeline是理解数据流的最佳入口:
train_pipeline = [ dict(type='DecordInit', **file_client_args), dict(type='UniformSample', clip_len=12, num_clips=1), dict(type='DecordDecode'), dict(type='Resize', scale=(-1, 256)), dict(type='CenterCrop', crop_size=224), dict(type='FormatShape', input_format='NCHW'), dict(type='CLIPTokenize'), dict(type='PackActionInputs', collect_keys=('imgs', 'text')) ]DecordInit:以io_backend='disk'初始化 Decord 视频解码后端;UniformSample(clip_len=12, num_clips=1):均匀采 12 帧、采 1 个 clip,对应结果表中的 "uniform 12";验证/测试流水线额外加test_mode=True;DecordDecode:解码为帧序列;Resize(scale=(-1, 256))+CenterCrop(crop_size=224):短边缩放到 256 再中心裁剪到 224,与表中的 "224x224 / 1 crop" 一致;FormatShape(input_format='NCHW'):把帧维并入 batch 维,得到模型期望的(B*N, C, H, W)输入;CLIPTokenize:位于 mmaction/datasets/transforms/text_transforms.py,内部调用clip.tokenize(text)[0]把文本转成定长 77 的 token 序列(测试用例中以torch.randint(0, 49408, (77,))模拟该输入);PackActionInputs(collect_keys=('imgs', 'text')):把两种模态分别打包进inputs['imgs']与inputs['text']。
test_pipeline = val_pipeline,训练/验证 dataloaderbatch_size=16、num_workers=8并开启persistent_workers;测试 dataloader 的batch_size=1(检索评测逐条收集特征,数值上不影响结果)。
配置详解:CLIP 前处理、优化器与调度
官方配置的model部分:
model = dict( type='CLIPSimilarity', clip_arch='ViT-B/32', to_float32=True, frozen_layers=0, data_preprocessor=dict( type='MultiModalDataPreprocessor', preprocessors=dict( imgs=dict( type='ActionDataPreprocessor', mean=[122.771, 116.746, 104.093], std=[68.500, 66.632, 70.323], format_shape='NCHW'), text=dict(type='ActionDataPreprocessor', to_float32=False))), adapter=dict(type='SimpleMeanAdapter'))to_float32=True:把 CLIP 参数转回 float32。从源码看,__init__中if to_float32: self.clip.float();配合文本侧to_float32=False的 preprocessor,意味着图像张量保持精度而 CLIP 参数以 float32 参与训练,避免混合精度下小学习率微调的不稳定;frozen_layers=0:按上文_freeze_stages的规则,视觉/文本残差块全部可训练,仅 CNN 卷积等底层参数被冻结,属于"轻冻结"的微调策略;若要全参数微调可改为-1;MultiModalDataPreprocessor:实现于 mmaction/models/data_preprocessors/multimodal_data_preprocessor.py。它按preprocessors字典为每种模态构建独立 preprocessor:图像用 BGR 格式的 ImageNet 均值/标准差做归一化(与 CLIP 视觉塔的期望一致),文本 token 不做归一化(to_float32=False保持整数 token 张量)。其forward遍历inputs的每个键,分别调用对应 preprocessor 完成 batch 化与归一化。
训练侧配置:
train_cfg = dict( type='EpochBasedTrainLoop', max_epochs=5, val_begin=1, val_interval=1) param_scheduler = [ dict(type='LinearLR', start_factor=0.05, by_epoch=True, begin=0, end=0.5, convert_to_iter_based=True), dict(type='CosineAnnealingLR', T_max=4.5, eta_min=0, by_epoch=True, begin=0.5, end=5, convert_to_iter_based=True), ] optim_wrapper = dict( optimizer=dict(type='AdamW', lr=1e-05, betas=(0.9, 0.999), eps=1e-08, weight_decay=0.05), paramwise_cfg=dict(norm_decay_mult=0., bias_decay_mult=0.), )要点:总共 5 个 epoch,前 0.5 epoch 做线性 warmup(从lr * 0.05线性升到位),随后 4.5 个 epoch 余弦退火到 0;优化器 AdamW 基础学习率1e-05,权重衰减 0.05,并通过paramwise_cfg对 norm 层参数与 bias 关闭权重衰减——这是微调大预训练模型的常规做法。配置末尾的auto_scale_lr = dict(enable=False, base_batch_size=128)给出了 LR 自动缩放基准:8 卡 × 每卡 16 样本 = 128,默认关闭,需要按卡数缩放时可将enable置True。
训练:对比损失与分布式特征聚合
CLIPSimilarity的 loss 模式完整复刻了 CLIP 的对称对比学习,代码见 mmaction/models/similarity/clip_similarity.py:
- 对归一化后的特征先做跨卡聚合:
video_features = torch.cat(GatherLayer.apply(video_features), dim=0)(文本侧同理)。GatherLayer是一个自定义的autograd.Function,前向调用mmengine.dist.all_gather收集所有进程的张量,反向只取本 rank 对应的梯度分片——这使得对比损失的负样本池扩展为所有 GPU 的样本之和,8 卡 × 16 即每个 batch 有 128 个负样本; - 用 CLIP 自带的可学习温度
logit_scale = self.clip.logit_scale.exp()缩放余弦相似度:logits_per_video = logit_scale * video_features @ text_features.t(),logits_per_text为其转置; - 标签为对角线索引
arange(N),损失默认CrossEntropyLoss(loss_weight=0.5)(类签名中的默认值),双向各算一次:
labels = torch.arange(logits_per_video.shape[0]).to(logit_scale.device) sim_loss_v2t = self.loss(logits_per_video, labels) sim_loss_t2v = self.loss(logits_per_text, labels) losses = dict(sim_loss_v2t=sim_loss_v2t, sim_loss_t2v=sim_loss_t2v)单元测试(tests/models/similarity/test_clip_similarity.py)用 2 个样本跑train_step,断言返回的loss_vars中同时包含sim_loss_v2t与sim_loss_t2v,并验证了optim_wrapper.update_params被调用一次。
此外模型重写了train():每次切换训练状态时重新执行_freeze_stages(),保证frozen_layers在训练中动态修改后立即生效。
训练与测试命令
以下命令继承自官方 README(configs/retrieval/clip4clip/README.md),训练脚本入口为 tools/train.py(基于mmengine的Runner),测试脚本为 tools/test.py。
训练
通用形式:
python tools/train.py ${CONFIG_FILE} [optional arguments]官方示例:在 MSRVTT-9k 上以固定随机种子、可复现(deterministic)方式训练,并开启周期验证:
python tools/train.py configs/retrieval/clip4clip/clip4clip_vit-base-p32-res224-clip-pre_8xb16-u12-5e_msrvtt-9k-rgb.py \ --seed 0 --deterministic测试
通用形式:
python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [optional arguments]官方示例:在 MSRVTT-9k 测试集上评测并把特征结果转储为 pkl 文件:
python tools/test.py configs/retrieval/clip4clip/clip4clip_vit-base-p32-res224-clip-pre_8xb16-u12-5e_msrvtt-9k-rgb.py \ checkpoints/SOME_CHECKPOINT.pth --dump result.pkl--dump输出的 pkl 便于离线分析检索结果。评测流程由test_dataloader+test_evaluator = dict(type='RetrievalMetric')驱动;RetrievalMetric默认指标集为('R1', 'R5', 'R10', 'MdR', 'MnR'),与结果表列一一对应。
框架还提供了面向检索任务的专用循环 mmaction/engine/runner/retrieval_loop.py(RetrievalValLoop/RetrievalTestLoop):先在逐 batch 的mode='tensor'前向中收集全部视频/文本特征并拼接,再调用predict_all生成 i2t 与 t2i 两组样本交给 evaluator,分别输出i2t/*与t2i/*两组指标。CLIP4Clip 官方配置使用的是标准ValLoop/TestLoop,从源码结构看,专用循环更适配需要按num_videos/num_texts精确分组的多模态检索数据集(如 MsrVTT 系)。更多训练/测试参数细节可参考 docs/en/user_guides/train_test.md。
引用
如果 CLIP4Clip 的研究成果对你的工作有帮助,官方 README 给出的 BibTeX 为:
@article{luo2022clip4clip, title={CLIP4Clip: An empirical study of CLIP for end to end video clip retrieval and captioning}, author={Luo, Huaishao and Ji, Lei and Zhong, Ming and Chen, Yang and Lei, Wen and Duan, Nan and Li, Tianrui}, journal={Neurocomputing}, volume={508}, pages={293--304}, year={2022}, }小结
CLIP4Clip 在 mmaction2 中的实现是一条完整的"预训练视觉-语言模型 → 视频检索"迁移路径:CLIPSimilarity复用 OpenAI CLIP 双塔编码器与logit_scale温度,通过SimpleMeanAdapter/TransformerAdapter两种 adapter 探索帧级时序建模,借助GatherLayer把对比学习的负样本池扩展到全部 GPU,再由RetrievalMetric输出 Recall@1/5/10 与 MdR/MnR。复现官方结果需要 8 卡、MSRVTT-9k 数据、5 个 epoch 的 AdamW 微调(lr=1e-5,warmup + 余弦退火),配置、权重与日志三者均可在 configs/retrieval/clip4clip/ 与 metafile.yml 中互相印证,适合作为理解"CLIP 迁移到视频多模态检索"这一方向的参考实现。
- 人工智能
- 计算机视觉
- 深度学习
【免费下载链接】mmaction2
OpenMMLab's Next Generation Video Understanding Toolbox and Benchmark
相关推荐
终极指南:如何用CLIP4Clip快速实现视频文本检索?
终极指南:如何用CLIP4Clip快速实现视频文本检索? CLIP4Clip是一个基于CLIP模型的端到端视频片段检索系统,能够高效地实现视频与文本之间的语义匹
人工智能深度学习多模态从零到一:如何用MaxKB构建企业级智能体平台的完整指南
从零到一:如何用MaxKB构建企业级智能体平台的完整指南 当企业试图将AI能力融入业务流程时,技术门槛高、部署复杂、维护困难往往是最大的障碍。传统AI解决方案要
人工智能大模型AI AgentRAG工具调用后端前端知识库CLIP4Clip终极指南:如何用AI实现视频文本智能检索
CLIP4Clip终极指南:如何用AI实现视频文本智能检索 在当今视频内容爆炸式增长的时代,如何从海量视频中快速找到你想要的片段?CLIP4Clip应运而生,这
人工智能深度学习多模态
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考