TiDB Vector 太香啦:以图搜图初体验!

云计算扫地僧
• 阅读 97

导读

TiDB Serverless 上的向量化功能终于开始邀约体验啦!本文是来自 TiDB 社区用户对 TiDB Vector 功能初体验的详细分享,hey-hoho 介绍了他从申请体验到实际操作的全过程,包括创建 TiDB Vector 实例、进行向量检索的初体验,以及实现以图搜图和自然语言搜图的基础应用。如果你对 TiDB Serverless 感兴趣,欢迎了解 TiDB Vector,一起开启 TiDB Serverless 数据库之旅吧!

作者丨 hey-hoho

来自神州数码钛合金战队

神州数码钛合金战队是一支致力于为企业提供分布式数据库 TiDB 整体解决方案的专业技术团队。团队成员拥有丰富的数据库从业背景,全部拥有 TiDB 高级资格证书,并活跃于 TiDB 开源社区,是官方认证合作伙伴。目前已为 10+客户提供了专业的 TiDB 交付服务,涵盖金融、证券、物流、电力、政府、零售等重点行业 。

最早知道 TiDB 要支持向量化的消息应该是在 23 年 10 月份左右,到第一次见到 TiDB Vector 的样子是在今年 1 月初,当时 dongxu 在朋友圈发了一张图:

TiDB Vector 太香啦:以图搜图初体验!

去年我研究了一段时间的向量数据库,一直对 TiDB 向量特性非常期待,看到这张图真的就激动万分,于是第一时间提交了 waitlist 等待体验 private beta。

苦等几个月,它终于来了(目前只对 TiDB Serverless 开放)。迫不及待做个小应用尝尝鲜。

创建 TiDB Vector 实例

在收到体验邀请邮件后,恭喜你可以开始 TiDB Vector 之旅了。

TiDB Serverless 提供了免费试用额度,对于测试用途绰绰有余,只需要注册一个 TiDB Cloud 账号即可。

创建 TiDB Vector 实例和普通的 TiDB 实例并没有太大区别,在创建集群页面可以看到加入了如下开关:

TiDB Vector 太香啦:以图搜图初体验!

不过要注意的是目前 TiDB Vector 只在部分区域开放,大家可以根据实际情况选择。

这里只需要填一个集群名称就可以开始创建,创建成功后的样子如下所示:

TiDB Vector 太香啦:以图搜图初体验!

下面开始进入正题。

关于向量的那些事

3.1 一些基础概念

  • 向量:向量就是一组浮点数,在编程语言中通常体现为 float 数组,数组的长度叫做维度(dim),维度越大精度越高,向量的数学表示是多维坐标系中的一个点。例如 RGB 颜色表示法就是一个简单的向量示例。
  • embedding:中文翻译叫嵌入,感觉不好理解,实质上就是把非结构化数据(文本、语音、图片、视频等)通过一系列算法加工变成向量的过程,这里面的算法叫做模型(model)。
  • 向量检索:计算两个向量之间的相似度。

3.2 向量检索初体验

连接到 TiDB Serverless 后,就可以体验文章开头图片中的向量操作。

创建一张带有向量字段的表,长度是 3 维。

CREATE TABLE vector_table (
    id int PRIMARY KEY,
    doc TEXT,
    embedding vector < float > (3)
  );

往表中插入向量数据:

INSERT INTO vector_table VALUES (1, 'apple', '[1,1,1]'), (2, 'banana', '[1,1,2]'), (3, 'dog', '[2,2,2]');

根据指定的向量做搜索:

SELECT *, vec_cosine_distance(embedding, '[1,1,3]') as distance FROM vector_table ORDER BY distance LIMIT 3;

+-----------------------+-----------------------+---------------------+
| id      | doc         | embedding             | distance            |
+-----------------------+-----------------------+---------------------+
| 2       | banana      | [1,1,2]               | 0.015268072165338209|
| 3       | dog         | [2,2,2]               | 0.1296117202215108  |
| 1       | apple       | [1,1,1]               | 0.1296117202215108  |
+---------+-------------+-----------------------+---------------------+

这里的 distance 就是两个向量之间的相似度,这个相似度是用 vec_cosine_distance 函数计算出来的,意味着两个向量之间的夹角越小相似性越高,夹角大小用余弦值来衡量。

还有以一种常用的相似度计算方法是比较两个向量之间的直线距离,称为欧式距离。

这也意味着不管两个向量是否有关联性,总是能计算出一个相似度, distance 越小相似度越高。

3.3 向量检索原理

前面大概也提到了两种常用的向量检索方式:余弦相似度和欧式距离,不妨从从最简单的二维向量开始推导一下计算过程。

二维向量对应一个平面坐标系,一个向量就是坐标系中任意一点,要计算两点之间的直线距离用勾股定理很容易就能得出,两点夹角的余弦值也有公式能直接算出来。

拓展到三维坐标系,还是套用上一步的数学公式,只是多了一个坐标。

以此类推到 n 维也是一样的方法。

TiDB Vector 太香啦:以图搜图初体验!

TiDB Vector 太香啦:以图搜图初体验!

以上内容来自我去年讲的向量数据库公开课: https://www.bilibili.com/video/BV1YP411t7Do

可以发现维数越多,对算力的要求就越高,计算时间就越长。

第一个 TiDB AI 应用:以图搜图

4.1 基础实现

借助前面介绍的理论知识,一个以图搜图的流程应该是这样子:

TiDB Vector 太香啦:以图搜图初体验!

下面我用最简洁直白的代码演示整个流程,方便大家理解。

首先肯定是先连接到 TiDB 实例,目前官方提供了 python SDK 包 tidb_vector ,对 SQLAlchemy 、 Peewee 这样的 ORM 框架也有支持,具体可参考 https://github.com/pingcap/tidb-vector-python

这里简单起见直接用 pymysql 手写 SQL 操作,以下连接参数都可以从 TiDB Cloud 控制台获取:

import pymysql

def GetConnection():
    connection = pymysql.connect(
        host = "xxx.xxx.prod.aws.tidbcloud.com",
        port = 4000,
        user = "xxx.root",
        password = "xxx",
        database = "test",
        ssl_verify_cert = True,
        ssl_verify_identity = True,
        ssl_ca = "C:\\Users\\59131\\Downloads\\isrgrootx1.pem"
    )
    return connection

再借助 Towhee 来简化 embedding 的处理,里面包含了常用的非结构化数据到向量数据的转换模型,用流水线(pipeline)的形式清晰构建整个处理过程。

from towhee import ops,pipe,AutoPipes,AutoConfig,DataCollection

image_pipe = AutoPipes.pipeline('text_image_embedding')

这里使用默认配置构建了一个 text_image_embedding 流水线 ,它专门用于对文本和图片做向量转换,从引用的源码中可以看到它使用的模型是 clip_vit_base_patch16 ,默认模态是 image 。

@AutoConfig.register
class TextImageEmbeddingConfig(BaseModel):
    model: Optional[str] = 'clip_vit_base_patch16'
    modality: Optional[str] = 'image'
    customize_embedding_op: Optional[Any] = None
    normalize_vec: Optional[bool] = True
    device: Optional[int] = -1

clip_vit_base_patch16 是一个 512 维的模型,因此需要在 TiDB 中创建 512 维的向量字段。

create table if not exists img_list 
(
    id int PRIMARY KEY, 
    path varchar(200) not null, 
    embedding vector<float>(512)
);

我准备了 3000 张各种各样的动物图片用于测试,把它们依次加载到 TiDB 中,完整代码为:

def LoadImage(connection):
    cursor = connection.cursor() 
    cursor.execute("create table if not exists img_list (id int PRIMARY KEY, path varchar(200) not null, embedding vector<float>(512));")
    img_dir='D:\\\\test\\\\'
    files = os.listdir(img_dir)
    for i in range(len(files)):
        path=os.path.join(img_dir, files[i])
        embedding = image_pipe(path).get()[0]
        cursor.execute("INSERT INTO img_list VALUE ("+str(i)+",'"+path+"' , '"+np.array2string(embedding, separator=',')+"');")
    connection.commit()

如果用 ORM 框架的话这里对数据库和向量加工操作会简单些,不需要数组到字符串之间的手工转换。

加载完成后的数据:

TiDB Vector 太香啦:以图搜图初体验!

TiDB Vector 太香啦:以图搜图初体验!

下一步定义出根据指定向量在 TiDB 中检索的函数:

def SearchInTiDB(connection,vector):
    cursor = connection.cursor() 
    begin_time = datetime.datetime.now()
    cursor.execute("select id,path,vec_cosine_distance(embedding, '"+np.array2string(vector, separator=',')+"') as distance from img_list order by distance limit 3;")
    end_time=datetime.datetime.now()
    print("Search time:",(end_time-begin_time).total_seconds())
    df =pd.DataFrame(cursor.fetchall())
    return df[1]

这里根据余弦相似度取出结果最相近的 3 张图片,返回它们的文件路径用于预览显示。

下一步用相同的 image pipeline 给指定图片做 embedding 得到向量,把这个向量传到 TiDB 中去搜索,最后把搜索结果输出显示。

def read_images(img_paths):
    imgs = []
    op = ops.image_decode.cv2_rgb()
    for p in img_paths:
        imgs.append(op(p))
    return imgs
    
def ImageSearch(connection,path):    
    emb = image_pipe(path).get()[0]
    res = SearchInTiDB(connection,emb)
    p = (
        pipe.input('path','search_result')
        .map('path', 'img', ops.image_decode.cv2('rgb'))
        .map('search_result','prev',read_images)
        .output('img','prev')
    )
    DataCollection(p(path,res)).show()

看一下最终搜索效果如何。先看一张已经在图片库存在的图(左边是待搜索的图,右边是搜索结果,按相似度由高到低):

TiDB Vector 太香啦:以图搜图初体验!

不能说非常相似,只能说是一模一样,准确度非常高! 再看一下不 在图片库的搜索效果:

TiDB Vector 太香啦:以图搜图初体验!

TiDB Vector 太香啦:以图搜图初体验!

图片库里有几十种动物,能够准确搜索出需要的是狗,特别是第一张从图片色彩、画面角度、动作神态上来说都非常相似。

4.2 使用向量索引优化

没错,向量也能加索引,但这个索引和传统的 B+ Tree 索引有些区别。前面提到向量相似度计算是一个非常消耗 CPU 的过程,如果每次计算都采用全量暴力搜索的方式那么无疑效率非常低。上一节演示的案例就是用指定的向量与表里的 3000 个向量逐一计算,最简单粗暴的办法。

向量索引牺牲了一定的准确度来提升性能,通常采用 ANN(近似最近邻搜索) 算法,HNSW 是最知名的算法之一。TiDB Vector 目前对它已经有了支持:

create table if not exists img_list_hnsw 
(
    id int PRIMARY KEY, 
    path varchar(200) not null, 
    embedding vector<float>(512) COMMENT "hnsw(distance=cosine)"
);

重新把 3000 张图片加载到新的 img_list_hnsw 表做搜索测试。

以下分别是不带索引和带索引的查询耗时,第二次明显要快很多,如果数据量越大这个差距会越明显,只是目前还无法通过执行计划或其他方式区分出索引使用情况。

E:\GitLocal\AITester>python tidb_vec.py
Search time: 0.320241
+------------------------------------+------------------------------------------------------------------------------------------------------+
| img                                | prev                                                                                                 |
+====================================+======================================================================================================+
| Image shape=(900, 900, 3) mode=RGB | [Image shape=(84, 84, 3) mode=RGB,Image shape=(84, 84, 3) mode=RGB,Image shape=(84, 84, 3) mode=RGB] |
+------------------------------------+------------------------------------------------------------------------------------------------------+

E:\GitLocal\AITester>python tidb_vec.py
Search time: 0.239746
+------------------------------------+------------------------------------------------------------------------------------------------------+
| img                                | prev                                                                                                 |
+====================================+======================================================================================================+
| Image shape=(900, 900, 3) mode=RGB | [Image shape=(84, 84, 3) mode=RGB,Image shape=(84, 84, 3) mode=RGB,Image shape=(84, 84, 3) mode=RGB] |
+------------------------------------+------------------------------------------------------------------------------------------------------+

实际在本次测试中发现,使用 HNSW 索引对搜索结果准确度没有任何影响。

自然语言实现图片搜索

本来到这里测试目的已经达到了,突发奇想想试一下用自然语言也来实现图片搜索。于是对代码稍加改造:

def TextSearch(connection,text):
    text_conf = AutoConfig.load_config('text_image_embedding')
    text_conf.modality = 'text'

    text_pipe = AutoPipes.pipeline('text_image_embedding', text_conf)
    embedding = text_pipe(text).get()[0]
    
    res=SearchInTiDB(connection,embedding)
    p = (
        pipe.input('text','search_result')
        .map('search_result','prev',read_images)
        .output('text','prev')
    )
    DataCollection(p(text,res)).show()

还是用的 clip_vit_base_patch16 模型,只是使用模态改成了文本。通过对文本做 embedding 后得到向量数据送到 TiDB 中进行搜索,流程和前面基本一样。

看一下最终效果:

TiDB Vector 太香啦:以图搜图初体验!

TiDB Vector 太香啦:以图搜图初体验!

可以发现英文的搜索效果要很多,这个主要是因为模型对于中文理解能力比较差,英文语义下 TiDB 的向量搜索准确度依然非常高。

基于 TiDB Vector,前后不到 100 行代码就实现了以图搜图和自然语言搜图。

未来展望

反正第一时间体验完的感受就是:太香了,强烈推荐给大家!

在以往,想在关系型数据库中对非结构化数据实现搜索是一件不敢想象的事,哪怕是号称无所不能的 PostgreSQL 在向量插件的加持下也没有获得太多关注,这其中有场景、性能、生态等各方面的因素制约。而如今在 AI 大浪潮中,应用场景变得多样化,生态链变得更丰富,TiDB Vector 的诞生恰逢其时。

但是不可忽视的是,传统数据库集成向量化的能力已经是大势所趋,哪怕是 Redis 这样的产品也拥有了向量能力。前有专门的向量数据库阻击,后有各种传统数据库追赶,这注定是一个惨烈的赛道,希望 TiDB 能深度打磨产品,突围成功。

期待的功能:更多的索引类型、GPU 加速等。

当然了,最大的愿望必须是 TiDB On-Premises 中能尽快看到 Vector 的身影。

给 TiDB 点赞!

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
2019 年 CNCF 中国云原生调查报告
!头图.jpg(https://ucc.alicdn.com/pic/developerecology/6db0c465111b4d9a96eb1ffe85c00e7a.jpg)中国72%的受访者生产中使用Kubernetes在CNCF,为更好地了解开源和云原生技术的使用,我们定期调查社区。这是第三次中国云原生调查,以中文进行
Stella981 Stella981
4年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
4年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Easter79 Easter79
4年前
TiDB 的现在和未来
本文根据黄东旭在PingCAPD轮融资线上发布会的演讲实录进行整理。!(https://oscimg.oschina.net/oscnet/upceee1b1ad10e2bcde45dbe1cc00dc0688fc.png)TiDB的现在和未来大家好,我是黄东旭,是PingCAP的联合创始人和CTO
Stella981 Stella981
4年前
Django初体验
Django初体验创建工程及应用https://www.imooc.com/learn/458djangoadminstartprojectmysitecdmysiteDjango创建工程及应用1.工程目录详解manage.py管理项目:包括数据库建立、服务器运行、测试...python3manag
Wesley13 Wesley13
4年前
R 语言代写绘制功能富集泡泡图
功能富集泡泡图功能富集分析用来展示某一组基因(一般是单个样品上调或下调的基因)倾向参与哪些功能调控通路,对从整体理解变化了的基因的功能和潜在的调控意义具有指导作用,也是文章发表中一个有意义的美图。通常会用柱状图、泡泡图和热图进行展示。热图的画法之前已经介绍过,这次介绍下富集分析泡泡图,其展示的信息是最为全面的,也是比较抓人眼球的。做基因功能富集分
Easter79 Easter79
4年前
TiDB 初体验
其实从2017年就打算测试下TiDB了,因为工作安排的关系,这个事情在年后才开始计划来做。而根据时间线来看,2015年的那个时候,我正和老杨张罗DBAplus的事情,而东旭已经在构思TiDB的雏形了,几年过去了,TiDB已经很火热,发展势头很不错,难得有这样一批热爱技术的人通过自己的行动来助力开源社区。其实一直以来,我感觉国内的很多开源产品,开源项目
燕青 燕青
2年前
Macos思维导图推荐:XMind for mac中文版 支持M1
XMindforMac是一款强大的思维导图软件,专为Mac用户设计。它可以帮助用户创建、组织和编辑复杂的思维导图,以清晰地表达思路和概念。XMindforMac的主要特点和功能包括:丰富的模板选择:XMind提供了多种思维导图模板,包括组织结构图、流程图、
铁扇公主 铁扇公主
2年前
Mac电脑轻量级思维导图软件 ClickCharts激活最新
ClickCharts是一款流程图创建器,可以创建流程图、组织图、思维导图和其他图表。以下是ClickCharts软件的一些特点和功能:提供多种图表模板,包括流程图、组织图、思维导图等,方便用户快速入门。支持从多种符号和线条连接符样式中选择,帮助用户更好地