5分钟实现「视频检索」:基于内容理解,无需任何标签

article/2025/9/22 17:39:34

Notebook 教程:text-video retrieval

「视频检索」任务就是输入一段文本,检索出最符合文本描述的视频。随着各类视频平台的兴起和火爆,网络上视频的数量呈现井喷式增长,「视频检索」成为人们高效查找视频的一项新需求。传统的视频检索通常要求视频带有额外的文字标签,通过匹配查询语句的关键词与视频标签实现检索。这一方案存在一个很大的缺陷,由于缺乏对语义的理解,该系统高度依赖关键词和视频标签,与真正的内容匹配存在差距。随着深度学习在计算机视觉和自然语言领域上的高速发展,「视频文本跨模态检索」能够理解文字和视频的内容,从而实现视频与文本之间的匹配。相比传统方法,基于内容理解的视频检索也更加接近人类的思考逻辑。目前主流的实践方法是将视频和文本编码成特征向量,由于含义相近的向量在空间中的位置也是相近的,我们可以通过计算向量之间的相似度实现文本-视频跨模态检索任务

视频作为一种非结构化数据,其类型丰富、信息量复杂、处理门槛较高。而视频与文本又各属不同类型的数据,处理这种跨模态的任务具有一定的难度。在本文中,借助专门处理非结构化数据的工具,如向量数据库 Milvus 和提供向量数据 ETL 框架的 Towhee ,我们可以轻松地利用针对「视频-文本」跨模态任务的深度学习网络(例如 CLIP4Clip )搭建一个“理解”内容的视频检索系统!

  「视频检索」服务 demo

在这篇文章中,我们将会使用 Milvus 和 Towhee 搭建一个基于内容理解的「视频检索」服务!

安装相关工具包

在开始之前,我们需要安装相关的工具包,我们用到了以下工具:

  • Towhee:用于构建模型推理流水线的框架,对于新手非常友好。

  • Milvus:用于存储向量并创建索引的数据库,简单好上手。

  • Gradio:轻量级的机器学习 Demo 构建工具。

  • Pillow:图像处理常用的 Python 库。

python -m pip install -q pymilvus towhee towhee.models pillow ipython gradio

数据集准备

我们在这里选用了 MSR-VTT (Microsoft Research Video to Text) 数据集的部分数据(1000个)。MSR-VTT 是一个公开的视频描述数据集,由 10000 个视频片段与对应的文本描述组成。 你可以选择从 google drive 或者通过以下代码下载和解压数据,解压后的数据包括了以下几个部分:

  • test_1k_compress: MSR-VTT-1kA 数据集中 1000 个压缩的测试视频。

  • MSRVTT_JSFUSION_test.csv: 一个 csv 文件,其中重要信息包括每个视频的id(video_id)、视频路径(video_path)、文字描述(sentence)。

curl -L https://github.com/towhee-io/examples/releases/download/data/text_video_search.zip -O
unzip -q -o text_video_search.zip

你可以通过改变以下代码中的sample_num选择使用更少的测试数据。我们简单提取和查看一下 csv 文件中包含的信息:

import pandas as pd
import osraw_video_path = './test_1k_compress' # 1k test video path.
test_csv_path = './MSRVTT_JSFUSION_test.csv' # 1k video caption csv.test_sample_csv_path = './MSRVTT_JSFUSION_test_sample.csv'sample_num = 1000 # you can change this sample_num to be smaller, so that this notebook will be faster.
test_df = pd.read_csv(test_csv_path)
print('length of all test set is {}'.format(len(test_df)))
sample_df = test_df.sample(sample_num, random_state=42)sample_df['video_path'] = sample_df.apply(lambda x:os.path.join(raw_video_path, x['video_id']) + '.mp4', axis=1)sample_df.to_csv(test_sample_csv_path)
print('random sample {} examples'.format(sample_num))df = pd.read_csv(test_sample_csv_path)df[['video_id', 'video_path', 'sentence']].head()

与「图像描述」、「以文搜图」等跨模态任务的原理类似,基于内容理解的「视频检索」通过选取视频剪辑中的关键帧,将其转换成能表达该视频的特征向量。为了节省资源和方便观察,我们先可以选择将视频转换为 GIF 动图:

from IPython import display
from pathlib import Path
import towhee
from PIL import Imagedef display_gif(video_path_list, text_list):html = ''for video_path, text in zip(video_path_list, text_list):html_line = '<img src="{}"> {} <br/>'.format(video_path, text)html += html_linereturn display.HTML(html)def convert_video2gif(video_path, output_gif_path, num_samples=16):frames = (towhee.glob(video_path).video_decode.ffmpeg(sample_type='uniform_temporal_subsample', args={'num_samples': num_samples}).to_list()[0])imgs = [Image.fromarray(frame) for frame in frames]imgs[0].save(fp=output_gif_path, format='GIF', append_images=imgs[1:], save_all=True, loop=0)def display_gifs_from_video(video_path_list, text_list, tmpdirname = './tmp_gifs'):Path(tmpdirname).mkdir(exist_ok=True)gif_path_list = []for video_path in video_path_list:video_name = str(Path(video_path).name).split('.')[0]gif_path = Path(tmpdirname) / (video_name + '.gif')convert_video2gif(video_path, gif_path)gif_path_list.append(gif_path)return display_gif(gif_path_list, text_list)

让我们看几个数据集中的视频-文本对:

# sample_show_df = sample_df.sample(5, random_state=42)
sample_show_df = sample_df[:5]
video_path_list = sample_show_df['video_path'].to_list()
text_list = sample_show_df['sentence'].to_list()
tmpdirname = './tmp_gifs'
display_gifs_from_video(video_path_list, text_list, tmpdirname=tmpdirname)

 

a girl wearing red top and black trouser is putting a sweater on a dog

young people sit around the edges of a room clapping and raising their arms while others dance in the center during a party

a person is using a phone

创建 Milvus 集合

在创建 Milvus 之前,请确保你已经安装并启动了 Milvus 。Milvus 是处理非结构化数据的好手,它能在后续的相似度检索和近邻搜索中发挥至关重要的作用。我们需要利用 Milvus 服务中创建一个集合(Collection)用于存储和检索向量,该集合包含两列:idembedding,其中id是集合的主键。另外,为了加速检索,我们可以基于embedding创建 IVF_FLAT 索引(索引的参数 ``"nlist":2048`)。同时,我们选择L2 欧式距离衡量向量之间的相似度(距离越小表示越相近):

from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utilityconnections.connect(host='127.0.0.1', port='19530')def create_milvus_collection(collection_name, dim):if utility.has_collection(collection_name):utility.drop_collection(collection_name)fields = [FieldSchema(name='id', dtype=DataType.INT64, descrition='ids', is_primary=True, auto_id=False),FieldSchema(name='embedding', dtype=DataType.FLOAT_VECTOR, descrition='embedding vectors', dim=dim)]schema = CollectionSchema(fields=fields, description='video retrieval')collection = Collection(name=collection_name, schema=schema)# create IVF_FLAT index for collection.index_params = {'metric_type':'L2', #IP'index_type':"IVF_FLAT",'params':{"nlist":2048}}collection.create_index(field_name="embedding", index_params=index_params)return collection
collection = create_milvus_collection('text_video_retrieval', 512)

提取特征,导入向量

本文教学的「视频检索」系统主要包含数据插入和检索两个部分。首先,我们将视频库里的所有视频转换成一个向量并存入数据库(Milvus 集合)中。当数据库准备完成后,该系统就可以实现检索服务。检索过程会将查询语句转换成一个向量,然后在数据库中找到与其最相近的视频向量,最终通过视频向量的id返回其对应的实际视频。

为了将视频与文本转换成向量,我们需要一个视频-文本跨模态的神经网络模型用于提取特征。Towhee 提供了一系列简单又好用的 API ,以供我们可以更便捷地操作数据处理的算子和流水线。这里我们选用了towhee clip4clip算子将视频库里的所有视频转换成向量,并插入事先准备好的 Milvus 集合中。 该算子不仅提供了预训练的 CLIP4Clip 提取特征,还包含了后处理工作(比如池化、维度处理、转数据格式),能够通过几行代码轻松提取向量。

为了加速算子与预训练模型的下载,在运行 clip4clip 算子之前,请确保你已经安装了 git 和 git-lfs(如果已安装请跳过):

sudo apt-get install git & git-lfs
git lfs install
import os
import towheedevice = 'cuda:0'
# device = 'cpu'# For the first time you run this line, 
# it will take some time 
# because towhee will download operator with weights on backend.
dc = (towhee.read_csv(test_sample_csv_path).unstream().runas_op['video_id', 'id'](func=lambda x: int(x[-4:])).video_decode.ffmpeg['video_path', 'frames'](sample_type='uniform_temporal_subsample', args={'num_samples': 12}) \.runas_op['frames', 'frames'](func=lambda x: [y for y in x]) \.video_text_embedding.clip4clip['frames', 'vec'](model_name='clip_vit_b32', modality='video', device=device) \.to_milvus['id', 'vec'](collection=collection, batch=30)
)

Wall time: 1min 19s 检查数据库集合可以看到共有 1000 条向量,通过 Towhee 提供的接口还可以查看各个数据之间的对应关系:

print('Total number of inserted data is {}.'.format(collection.num_entities))
dc.select['video_id', 'id', 'vec']().show()

Total number of inserted data is 1000.

我们在这里对上面的代码做一些接口说明:

  • towhee.read_csv(test_sample_csv_path):读取 csv 文件中的数据。

  • .runas_op['video_id', 'id'](func=lambda x: int(x[-4:])):取每一行数据的video_id 列最后 4 个数据作为 id 列的数据,并转换其数据类型为 int。

  • .video_decode.ffmpeg and runas_op:统一对视频进行二次采样,然后得到一串视频图像列表,作为 clip4clip 模型的输入。

  • .video_text_embedding.clip4clip['frames', 'vec'](model_name='clip_vit_b32', modality='video'):从视频中采样的图像帧中提取 Embedding 特征向量,然后在时间维度上平均池化它们。

  • .to_milvus['id', 'vec'](collection=collection, batch=30):将向量 30 个一批插入 Milvus 集合中。

系统评估

我们已经成功实现了「视频检索」服务的核心功能,接下来可以根据不同指标评估检索引擎。在本节中,我们将使用 recall@topk 评估我们的「视频文本检索」服务的性能:

Recall@topk 是在 top k 个结果的“查全率”。比如,共有5个目标结果,Recall@top10为40%则表示前十个结果中找到了2(5*40%)个目标结果。本案例中每次只有一个目标结果,因此 Recall@topk同时也意味着准确率(Accuracy)。

dc = (towhee.read_csv(test_sample_csv_path).unstream().video_text_embedding.clip4clip['sentence','text_vec'](model_name='clip_vit_b32', modality='text', device=device).milvus_search['text_vec', 'top10_raw_res'](collection=collection, limit=10).runas_op['video_id', 'ground_truth'](func=lambda x : [int(x[-4:])]).runas_op['top10_raw_res', 'top1'](func=lambda res: [x.id for i, x in enumerate(res) if i < 1]).runas_op['top10_raw_res', 'top5'](func=lambda res: [x.id for i, x in enumerate(res) if i < 5]).runas_op['top10_raw_res', 'top10'](func=lambda res: [x.id for i, x in enumerate(res) if i < 10])
)

我们分别返回 top 1 个、top 5 个和 top 10 个预测结果,并查看分别对应的评估结果:

dc.select['video_id', 'sentence', 'ground_truth', 'top10_raw_res', 'top1', 'top5', 'top10']().show()
# dc.show()

benchmark = (dc.with_metrics(['mean_hit_ratio',]) \.evaluate['ground_truth', 'top1'](name='recall_at_1') \.evaluate['ground_truth', 'top5'](name='recall_at_5') \.evaluate['ground_truth', 'top10'](name='recall_at_10') \.report()
)

这些评估结果与 CLIP4Clip 论文原文中的评估分数十分接近,我们可以相信这次搭建的「视频检索」服务性能达标了!

CLIP4Clip 原文中的评估分数

在线 Demo

为了更方便地使用这个「视频检索」服务,我们可以借助 Gradio 来部署一个可交互的在线可玩 Demo。

首先,我们使用 Towhee 将查询过程包装成一个函数:

milvus_search_function = (api.video_text_embedding.clip4clip(model_name='clip_vit_b32', modality='text', device=device).milvus_search(collection=collection, limit=show_num).runas_op(func=lambda res: [os.path.join(raw_video_path, 'video' + str(x.id) + '.mp4') for x in res]).as_function())

然后,我们基于 Gradio 创建一个 demo 程序:

import gradiointerface = gradio.Interface(milvus_search_function, inputs=[gradio.Textbox()],outputs=[gradio.Video(format='mp4') for _ in range(show_num)])interface.launch(inline=True, share=True)

Gradio 启动服务后,会提供了 URL 供在线访问:

点击这个 URL 链接,就会跳转到「视频检索」服务的交互界面。输入你想要搜索的文本描述,即找到视频库中最符合该描述的视频。例如,我们输入 "a man is cooking" (一个男人正在做饭) 即可得到:

 

总结

在今天的这篇文章中,我们构建了一个简单的基于内容理解的「视频检索」系统。这个系统与之前的「以文搜图」类似,输入一段文字便可找到最符合描述的视频

面对「视频-文本」检索这样的跨模态任务,我们使用提供向量数据 ETL 框架的 Towhee 获取视频和文本的 Embedding 向量,然后在向量数据库 Milvus 中创建了向量索引,实现视频到文本之间的对应,最后通过相似度检索实现了从文本到视频的跨模态检索任务。

通过对模型进行评估,我们的模型得分与 CLIP4Clip 原论文中的分数十分接近,可以说, Milvus 和 Towhee 可以让我们轻松地搭建了一个性能达标的「视频文本检索」服务!

最后,我们利用 Gradio 将我们的模型包装成一个可以交互的 demo ,方便我们在应用层面上操作跨模态检索工作。

之后的「5分钟」系列还会介绍更多丰富精彩的用 Milvus 和 Towhee 处理非结构化数据的 AI 业务系统搭建流程哦!请持续关注我们,感兴趣的朋友可以跟着一起动手试试!


http://chatgpt.dhexx.cn/article/CuAW5xJX.shtml

相关文章

视频内容检索概述

视频内容检索 针对目前多媒体搜索引擎技术&#xff0c;视频数量的井喷式增加以及多媒体视频内容的多样性和数据结构的复杂性&#xff0c;如何快速的从有效地这些视频检索出人们感兴趣的已经成为当今信息化时代的难题。 数字视频内容检索 基于内容的视频检索&#xff08;CBVR…

ad建集成库_手把手教你创建自己的Altium Designer集成元件库

一个善于规划、管理及总结的硬件开发工程师都喜欢创建自己的集成库,这样就相当于给自己打造了一款更适合自己的尖兵利器,无论是硬件设计的统一性还是硬件模块的可重用性,都会给工程师带来更多的设计便利。 一个管理规范的硬件开发企业,在集成库的制作及使用方面都会做出很多…

NC57中间表数据源的设置流程

目前场景如下&#xff1a;NC定时将数据写入中间库中&#xff0c;第三方去中间库中抓取&#xff1b; 方式一&#xff1a; 第一步&#xff1a;在NC客户端【客户化】——【二次开发工具】——【参数设置】——【参数模板管理】添加所设置的数据源数据 找到对应的数据库表pub_sysi…

分库分表介绍

目录 一、前言 二、何谓数据切分? 三、垂直切分 1、垂直分库 2、垂直分表 3、垂直切分优缺点 4、拆分需考虑的业务因素 四、水平切分 1、水平分库 2、水平分表 3、水平切分优缺点 五、垂直与水平切分的联合使用 六、数据分片规则 1、Hash取模分表 2、数…

分库分表入门介绍

本文收集网上资料&#xff0c;多合一 编撰于2020年4月21日 原文链接1 原文链接2 原文链接3 目录 为什么要分库分表读写分离&#xff0c;主从复制Why Not NoSQL/NewSQL?什么是RDBMS 分库分表概述切分策略路由规则范围路由hash算法路由配置 分库分表带来的问题join操作COUNT&…

工作区、暂存区、仓库三者关系

区分三者关系 Git最让你迷惑的无非是它里面的各种概念了&#xff0c;如果是刚开始接触Git希望看完本篇介绍之后有一个清晰的认识&#xff0c;笔者认识也有限这里只说说个人对使用Git的感受&#xff0c;说一下它里面的几个最常用的概念的理解。 在初始化git版本库之后会生成一个…

浅谈MYSQL中的基本表、中间表、临时表、派生表和视图

简单介绍 首先我们先了解一下什么叫虚拟表虚拟表&#xff0c;顾名思义就是就是实际上并不存在&#xff08;物理上不存在&#xff09;&#xff0c;但是逻辑上存在的表。 在MYSQL中存在三种虚拟表&#xff1a;临时表、内存表、视图 1、基本表 基本表是本身独立存在的表&#x…

常见的系统间接口方式(02)-中间件的数据接口模式

导读&#xff1a; 原文路径&#xff1a;https://mp.weixin.qq.com/s/uq9DfxE5_cvAsitqlcblBg 大家可以关注我个人公众号&#xff0c;所有分享内容&#xff0c;会在公众号第一时间推送&#xff0c;且阅读排版更好。 愿大家的学习&#xff0c;轻松且愉快。 如果大家觉得有用&…

python matlab库使用_python matlab库

python与matlab的优缺点比较matlab主要是用来做数值计算的(矩阵,向量是强项),当然还加入了其他的许许多多的库。主要用来模拟一些东西。 python是一门语言,现在也有模拟matlab的库,不过功能显然还是很弱的。 python与matlab哪个简单 简单对比: python和matlab的共同点都是…

MYSQL:创建中间表

mysql> create table role_to_privilege( -> id int primary key auto_increment, -> rId int not null, -> pId int not null -> ); Query OK, 0 rows affected (0.09 sec)

中间表是什么?和报表有什么关系?会带来怎样的问题?又如何解决?

在数据库中有一类用于保存中间计算结果的物理表&#xff0c;通常被称为“中间表”。中间表主要跟 OLAP&#xff08;在线联机分析&#xff09;业务有关&#xff0c;产生的原因主要有以下几方面。 中间表来源 1. 计算逻辑复杂 在 OLAP&#xff08;报表或查询&#xff09;业务中&…

mysql 中中间表是什么意思_为什么会有这么多中间表?

中间表的由来 中间表是数据库中专门存放中间计算结果的数据表。报表系统中的中间表是普遍存在的。那么,这些中间表是如何出现的?为什么中间表会越来越多?中间表会给项目组带来什么样的困扰,如何解决这些困扰?这里我们就尝试探讨一下这个问题。 中间表出现的典型场景主要有…

IT 接口对接:足迹第十二步接口对接的定义(接口对接分三种:中间库方式的接口对接,Rest格式URL对接和HTTP格式URL对接;)

1&#xff09;接口对接的定义&#xff1a;服务端通过暴露地址/参数名称/编码&#xff0c;指引客户端发送一个Rest风格的URL请求&#xff0c;服务端读取Rest风格的URL&#xff0c;并返回一个响应&#xff1b; 接口有四部分组成&#xff1a;方法、uri、请求参数、返回参数&#…

MSSQL中间库对接MySQL

需要下载MySQL ODBC数据源驱动程序&#xff0c; 在MSSQL所在服务器安装MySQL ODBC数据源驱动程序&#xff0c;安装完成之后&#xff0c;在【控制面板】->【工具管理】->【ODBC数据源(64bit)/ODBC数据源(32bit)】->【系统DSN】->【添加】下多了MySQL数据源的驱动程…

四点流程做好商机管理

企业想做好商机管理&#xff0c;仅凭员工是做不到的&#xff0c;借助CRM销售管理系统是比较明智的选择。接下来小编从客户信息管理、业务进程跟踪、设置提醒、销售漏斗等方面讲讲企业如何做好商机管理。 只有提高商机的转化率&#xff0c;企业的利润才会增长。想做好商机管理&…

想通过互联网创业,如何找到商机项目创业呢

很多人都像在互联网上创业&#xff0c;但是互联网创业看着简单&#xff0c;其实挺考验一个人的眼力和思维能力&#xff0c;最重要是经验&#xff0c;今天不说什么理论方面的&#xff0c;只说一个简单牛逼的方法 首先你创业目的是为了什么&#xff1f; 拯救世界&#xff1f;做…

与山东云蚁旅游一起,发现旅游行业的无限商机和潜力!

随着人们生活水平的不断提高&#xff0c;旅游业迅猛发展已成为大势所趋。山东云蚁旅游作为一家专业的旅游服务机构&#xff0c;一直致力于为广大消费者提供最优质的旅游服务&#xff0c;在市场上享有良好的声誉和知名度。 如今&#xff0c;随着旅游市场的进一步开放和竞争加剧…

把信息变成商机

在商界的高层管理人员看来&#xff0c;公司中充斥着各种各样的信息。他们试图对这些信息进行管理和利用&#xff0c;从而为决策、财务管理和客户服务提供支持。 但是他们没有意识到&#xff0c;即便能够实现上述目标&#xff0c;他们也仅仅只是赶上了昨天的步伐而已。信息的发展…

旅游发现商机,他开店依靠创意经营,月收入高达万元

在自己创业之前&#xff0c;黄建均在某厂当电器维修工&#xff0c;工作辛苦而且收入不高。自己创业做生意&#xff0c;他"想都没想过"。 几年前&#xff0c;黄建均一家人外出旅游。在某景区&#xff0c;他发现一个不起眼的小店外排着长龙--60多岁的老人和3岁的孩童排…

什么是企业商机管理 管理销售商机流程方法

现代企业发展道路上&#xff0c;市场竞争愈演愈烈&#xff0c;很多企业都开始重视客户信息化管理来促成销售交易&#xff0c;在销售管理中的商机需按照轻重缓急进行分类、跟进、监控&#xff0c;才能对商机进行有效管理。 从某种程度上来说&#xff0c;一个订单成功与否的关键…