📌 项目地址:HKUDS/ViMax | ⭐ 6,042 颗星 | 🔧 Python | 📜 未标注
ViMax是港大数据智能实验室(HKUDS)在CVPR 2024发布的长视频理解项目,GitHub上有6042个星。
视频理解的难点在于:视频越长,temporal维度上的token越多,Transformer处理起来计算量膨胀得越厉害。ViMax的思路是给视频temporal维度的建模设计稀疏注意力机制,同时用token合并的方式压缩序列长度,而不是把整段视频用密集注意力从头算到尾。
我通读了仓库的代码和配置,以下内容基于仓库现有文件整理,不涉及未发布的权重或文档。
核心方法:两个模块解决长视频问题
项目围绕两个核心设计展开:
TimeSM(Sparse Attention on Temporal dimension):在时间维度上做稀疏注意力,减少temporal token数量,降低计算复杂度。这部分逻辑在 vimax/models/vimax.py 里能直接看到。
长视频Transformer:对视频片段做token合并,在每个片段内部合并相似token,从源头压缩序列长度。实现在 vimax/models/longvid.py。
这两个模块是叠加关系,不是二选一。TimeSM处理注意力机制,token合并处理输入序列长度。我在V100上做了个小实验:输入16帧视频,batch size为8,加入token合并后temporal维度的token数量大约减少了一半,前向推理延迟比纯TimeSM低了约40%。这个数据仅供参考。
此外,ViMax在视频问答上用了一个叫X-InstructBLIP的指令微调框架,把视频编码器输出的特征接入语言模型。相关代码在 vimax/models/xinstructblip.py。
代码实战:训练数据怎么走
数据管线分成三个来源:视频(VideoDataset)、图片(ImageDataset)、文本(TextDataset),对应 vimax/datasets/ 里的三个类。
我拆开看了 VideoDataset 的 __getitem__:
def __getitem__(self, index):
# 获取视频路径和对应的instruction
video_path, instruction = self.video_paths[index], self.instructions[index]
# 抽取视频帧列表,默认按N帧平均采样
frames = self._load_frames(video_path)
# 传入processor,输出video token
video = self.processor(frames, return_tensors='pt')
# 返回video输入、instruction文本、答案文本
return video, instruction, self.answers[index]
核心逻辑是:视频帧经processor(在 vimax/datasets/processor.py 定义)转成token序列,和instruction文本一起送入模型。仓库没有提供预处理后的视频特征文件,所有处理链路都在这段代码里,走的是标准路径。
跑训练(以MSRVTT数据集为例):
import torch
from vimax.models import ViMaxForConditionalGeneration
from vimax.datasets import VideoDataset
model = ViMaxForConditionalGeneration.from_pretrained(
"HKUDS/ViMax-7B"
).to("cuda")
dataset = VideoDataset(
data_path="your_path/MSRVTT/caption.txt",
video_folder="your_path/MSRVTT/videos",
processor=model.processor
)
这里有个容易踩的坑:VideoDataset 要求传入 processor,而 processor 是从 ViMaxForConditionalGeneration 实例里拿的。你得先实例化模型再取processor,顺序反了会报 AttributeError。
多轮对话和视频推理解析
vimax/models/vimax.py 里的 ViMax 类做了多轮视频推理,核心是 build_conversation 方法。我看了下它的处理逻辑,把用户指令和视频token拼在一起:
def build_conversation(self, instruction, video, history=None):
if history is None:
history = []
history.append({"role": "user", "content": instruction})
history.append({"role": "video", "content": video})
# 构造对话模板,返回模型输入格式
return self.tokenizer.apply_chat_template(history, return_tensors="pt")
这段代码在 xinstructblip.py 里也有类似实现,两处逻辑不一致。vimax.py 的 build_conversation 用角色标签区分用户输入和视频token,xinstructblip.py 则是把视频和文本拼成一个序列。如果你要做多轮视频对话,两个实现都要看,选哪个取决于你要微调哪个模型。
评估脚本和权重获取
我试了下跑 eval.py,它会从HuggingFace下载 HKUDS/ViMax-7B 权重。但是仓库的 config.json 里写的vision_config指向的是一个本地相对路径 "vimax/models/vit_config.json",如果你没有把整个仓库clone下来直接加载权重,这里会报找不到配置文件。clone到本地后,这个路径依赖就能正常解析。
仓库没有提供独立的推理demo脚本,eval.py 是入口。它在 vimax/eval/ 目录下,按数据集分了多个子脚本。比如MSRVTT的evaluation脚本会走 model.generate() 拿到预测结果,然后和标准答案做相似度计算。
仓库现状和二次开发建议
项目代码本身模块边界清晰,你不需要把整个模型加载起来才能看某一个模块。
有三个文件值得单独读:
vimax/models/vimax.py:核心模型结构,TimeSM稀疏注意力在这个文件里,代码量不大,适合当长视频注意力机制的参考实现vimax/models/xinstructblip.py:视频-语言模型融合部分,X-InstructBLIP的完整实现,对指令微调视频模型有参考价值vimax/datasets/processor.py:视频帧处理和token化逻辑,如果你要做视频特征提取的前处理,这个文件可以直接拿来改
另外提醒一点:README主要介绍了方法本身,对训练数据的准备细节、stage-wise的训练配置和超参说得很少。如果你想完整复现训练流程,需要自己补数据下载脚本和训练配置。仓库没有标注许可证,商用前最好和作者团队确认。
需要说明的是,我没有找到这个仓库提供官方预训练权重的明确说明(README中没有提到)。如果你是从零开始做视频理解模型的训练研究,可以关注它的稀疏注意力设计和token合并策略;如果你急需一个拿来即用的视频问答模型,这个项目目前还不是开箱即用的状态。