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

news2025/8/2 19:28:49

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 os

raw_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 Image

def 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_line
    return 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, utility

connections.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 towhee

device = '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 gradio

interface = 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://www.coloradmin.cn/o/16073.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Matlab点云处理及可视化第1期—基于KD树的邻域点搜索(柱状邻域、球状邻域及KNN)

目录 1 概述 2 代码实现 3 可视化验证 数据及完整代码获取方式&#xff1a; 观前提示&#xff1a;本文文字内容请勿直接用于论文写作&#xff0c;否则后果自负。 特别提示&#xff1a;《Matlab点云处理及可视化》系列文章旨在为初入点云处理领域的朋友提供一份较为权威、可…

MR直播(混合现实直播)做一场高品质企业培训

阿酷TONY / 2022-11-18 / 长沙 MR&#xff0c;是英文Mixed Reality两个单词的缩写&#xff0c;中文翻译为混合现实。 MR混合现实直播技术是通过在现实环境中引入虚拟场景信息&#xff0c;增强用户体验的真实感&#xff0c;具有真实性、实时互动性等特点。 MR直播解决方案是深…

基于springboot农产品交易平台的设计与实现

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于特色农产品电商平台 当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了特色农产品电商平台&#xff0c;它彻底…

软件需求分析——需求的理论基础

如果有兴趣了解更多相关内容&#xff0c;可以来我的个人网站看看&#xff1a;瞳孔空间 一&#xff1a;需求的涵义 研究对象&#xff1a;软件加强型系统中的软件 软件加强型系统&#xff1a;泛指由计算机技术支持的互相联系着的一组人类活动组成的系统。与物理设备和人类社会…

linux网络协议栈源码分析 - 传输层(TCP的输出)

1、TCP write系统调用(tcp_sendmsg) 1.1、write系统调用 socket的write系统调用栈: write最终调用tcp_sendmsg发送消息。 1.2、tcp_sendmsg报文分段 tcp_sendmsg主要是对用户的消息按MSS进行分段、添加到发送队列并将用户数据拷贝到分段里面&#xff0c;根据相关判断设置PSH标…

[附源码]SSM计算机毕业设计超市收银系统论文JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

学生台灯是灯管的好还是led的好?分享学生专用台灯第一品牌

给学生使用的话肯定是led灯更好的&#xff0c;主要是对眼睛有保护作用的&#xff0c;灯管一般当做主要照明灯具是可以的&#xff0c;在家中客厅里&#xff0c;卧室就是灯管&#xff0c;使用led灯是想要补足亮度的&#xff0c;全光谱的国AA级台灯&#xff0c;更健康、更适应人类…

计算机网络---ARP、DHCP与ICMP

&#xff08;一&#xff09;IP 地址与硬件地址 IP地址是网络层使用的地址&#xff0c;它是分层次等级的。硬件地址是数据链路层使用的地址&#xff08;MAC地址&#xff09;&#xff0c;它是平面式的。在网络层及网络层之上使用IP地址&#xff0c;IP地址放在IP数据报的首部&…

并肩刘德华,对战周杰伦,腾格尔老师线上演唱会即将拉开帷幕

在刚刚结束的第三十五届金鸡奖上面&#xff0c;著名爱国艺人刘德华&#xff0c;又一次出现在大众的视野当中。来自香港的天王刘德华&#xff0c;是一个著名的音乐人和演员&#xff0c;他拳拳的爱国之情&#xff0c;也感动了无数的粉丝。 刘德华作为中国华语乐坛的中坚力量&…

22071班(11月18日)

1.在串口工具进行输入&#xff1a; echo 1 > /dev/myled0 ---->led1灯点亮 echo 0 > /dev/myled0 ---->led1灯熄灭 echo 1 > /dev/myled1 ---->led1灯点亮 echo 0 > /dev/myled1 ---->led1灯熄灭 echo 1 > /dev/myled2 ----…

【附源码】计算机毕业设计JAVA校园跑腿平台

【附源码】计算机毕业设计JAVA校园跑腿平台 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA mybati…

什么是PaaS平台

PaaS平台概述 PaaS平台通常是基于IaaS平台构建的&#xff0c;PaaS平台和IaaS平台最大的差别是需求即服务。所有的管理都是以服务为粒度的&#xff0c;在IaaS以资源管理为中心的平台上提供了更高层次的抽象。 PaaS的本质 &#xff08;1&#xff09;运维自动化&#xff0c;故障…

统计聚类法的基本步骤:

统计聚类法的基本步骤&#xff1a; 1>形成数据框 2>计算距离阵 计算n个样品两两间的距离D。 3>进行系统聚类 (I&#xff09;构造n个类,每个类只包含一个样品; (2&#xff09;合并距离最近的两类为一新类; (3&#xff09;计算新类与当前各类的距离,若类个数为1,…

观测云产品更新|Pipeline 使用体验优化;支持写入用户的自定义事件;自定义查看器支持选择更多类型的数据等

观测云更新 Pipeline 使用体验优化 Pipeline 支持过滤条件配置多选 支持将任意一个 Pipeline 脚本设置为“默认 Pipeline 脚本“&#xff0c;若当前数据类型在匹配 Pipeline 处理的时候&#xff0c;未匹配到其他的 Pipeline 脚本&#xff0c;则数据会按照默认 Pipeline 脚本的…

vs2017编译的64位libssh2库

需求&#xff1a;使用sftp上传下载文件 环境&#xff1a;windows vs2017 参考 链接: link 链接: link 编译 环境准备 libssh2依赖于openssl和zlib&#xff0c;所以需要有所以需要先编译&#xff1a;openssl和zlib才行。openssl和zlib。openssl和zlib我是下载人家编译好的…

【MySQL基础】数据库系统之关系型数据库与非关系型数据库

目录 一、数据库系统 1. 数据库 2. 数据库应用 3. 数据库管理系统&#xff08;数据库软件&#xff09; 3.1关系型数据库【RDBMS】 3.2非关系型数据库【NoSQL】 4. SQL和数据库管理系统的关系 5. 关系型数据库管理系统的组成 &#x1f49f; 创作不易&#xff0c;不妨点…

DIY CY7C68013A模块为逻辑分析仪

DIY CY7C68013A模块为逻辑分析仪摘要工具软件步骤参考资料&#xff1a;摘要 将淘宝购买的CY7C68013A模块修改为8通道逻辑分析仪。 购买的CY7C68013A模块如下&#xff1a; 工具软件 Zadig&#xff1a;用于安装逻辑分析仪驱动。 PulseView&#xff1a;Sigrok逻辑分析仪应用软…

Python面向对象2-继承-

文章目录目标一. 继承的概念二. 单继承三. 多继承 [python又支持多继承了]四. 子类重写父类同名方法和属性 #TODO目标 继承的概念单继承多继承子类重写父类的同名属性和方法子类调用父类的同名属性和方法多层继承super()私有属性和私有方法 一. 继承的概念 生活中的继承&…

实验(三):单片机I/O口实验-模拟开关灯

一、实验目的与任务 实验目的&#xff1a; 1&#xff0e;掌握单片机I/O口输入输出使用&#xff1b; 2&#xff0e;掌握单片机I/O口位操作的编程。 任务&#xff1a; 1.根据要求编写程序&#xff0c;并写出原理性注释&#xff1b; 2. 检查程序运行的结果&#xff0c;分析一下是…

VLAN和VLAN间路由

VLAN和VLAN间路由一 交换机二 vlan2.1 华为交换机的特性2.2 access接口2.2.1 在华为交换机上配置access接口2.2.2 access接口接收到报文的处理流程&#xff08;打vlan tag&#xff09;2.2.3 access接口发送报文的处理流程&#xff08;剥离\弹出vlan tag&#xff09;![在这里插入…