从神经搜索到多模态应用

3fd5cc0cb64274511d2ee90c95c21738.png

本文约5400字,建议阅读10分钟

从神经搜索到多模态应用,这里的神经搜索指的是在搜索系统中用神经网络模型。

提到神经搜索就必然想到多模态数据,因为神经网络相比于传统搜索方式,其最大的优势就在于可以很方便地对不同模态的数据进行融合。

本文将从以下几个方面进行介绍:

  • 从神经搜索到多模态应用

  • 多模态数据

  • 多模态应用服务

  • Jina全家桶在DocsQA中的实践

01 从神经搜索到多模态应用

首先看一个典型的多模态数据——新闻,除了文字之外还会有图片的信息,有的新闻还会有视频的信息,它就是一个不同模态数据的混合。另外一个值得注意的是多模态数据中嵌套的结构,比如新闻有不同的段落,段落又可以拆解成句子,可以进一步去分词。

fcea58b73277265590c4e004d5e6e384.png

为什么这个嵌套结构对多模态数据非常重要呢?因为多模态不仅涉及不同的模态,同时它的语义需要从不同的颗粒度上去表示。所以多模态数据有两个重要的特征,一是有多个模态,二是嵌套的结构。

常见的多模态数据还包括电商中的商品,视频网站中的视频,音乐网站上的音乐等等。近几年关于多模态的研究也越来越多,例如 OpenAI 在做 DALL·E 和 CLIP 两个模型,最近在做 DALL·E2;国内包括百度、悟道都在做相关研究;国外微软、谷歌和 Facebook 也都有相关的研究。

cbb10dbe8ac3e9148ea5bd49bb03702d.png

现在越来越多研究者开始投身于多模态领域,一个主要的原因是因为 CV 和 NLP 方向的模型越来越趋向于统一,大家也就自然而然的想到是不是可以融合到一起去做。

既然多模态应用越来越火,那么我们是不是可以轻松地从零开始搭建一套完整的、生产环境可用的多模态服务?其实如果真正的从零开始搭建,最后还要在线上进行部署的话,整个过程还是非常复杂的,我们下面就来看一下会遇到哪些问题。

02 多模态数据

首先第一个问题就是拿到多模态数据之后,我们需要去表示这个多模态的数据。再回到我们刚才看的这个新闻的例子,我们可以在 python 里面简单的写一个 dataclass,定义几个 filed,一个是存储 picture 的 URL;还可以定义 title, string 类型;定义 paragraph;还会去加一个字典,去定义这些 meta 的信息,包括作者、地点等。

122574610ded056caa44b33b7e66c18a.png

这个看起来也不是很复杂,我们通过一个 dataclass 就可以实现我们想要的对不同模态数据的支持,也可以有嵌套结构。

但是有了这个表示之后,我们还需要一些对数据的操作。比如有一个新闻的数据,希望对它进行向量表示的计算。例如用 CLIP 模型,第一步就是需要把这个图片先下载下来,存在本地的缓存,加载进来交给模型去做处理。这就需要写额外的代码。之后我们生成向量,又会产生向量如何存储的问题。一个方法是将向量存储在向量数据库里面,这就难免涉及到要配置向量数据库。

另一方面,开发一个多模态应用时,前期难免需要花一段时间去探索数据。这时,我们会需要检索数据,可能会用向量去看相似的数据都是什么样的,也可能用字段去做一些过滤,比如只看新京报写的一些新闻。想要实现这些功能,要么去数据库里直接查,要么直接写 for 循环,实现的效率都比较低。

此外,多模态数据中通常包含有不同模态的数据,比如视频、音频等,很多时候这些数据我们希望可以预览。此时我们都会需要自己动手实现这些预览功能。

最后我们还需要考虑到网络传输,因为在多模态的应用中,我们搭成的服务往往都是一个流水线,数据会在不同模块之间流转,此时就涉及到数据在流转过程中的网络传输效率。当然最简单的就是 json 做一个序列号,但这样的传输效率很低,整个服务的运行效率就会受到影响。

06de9e4b4bd0514a0f9b603d6b3ede9f.png

针对这些问题,我们开发了 DocArray,这是一个用于处理非结构化多模态数据的数据结构工具包。它能将各式各样非结构化数据,统一成同一种数据结构 Document。

还是通过之前新闻的例子来介绍一下 Document 类的用法。我们希望用 Document 对这个新闻进行封装。需要修改的代码只需要两步:第一步,使用 DocArray 提供的 dataclass 的封装来替代 python 原生的 dataclass;第二步,使用我们提供的多模态的数据类型替代 python 原生的数据类型。使用 Document 类表示多模态要比原来强大很多。

bd313efe705c5da9639de672bbcd6bf3.png

首先 ,Document 对不同模态的数据有更好的支持,比如,存图片的字段content_picture,之前只是存的 URL,加载时需要自己写图片下载的模块。用 Document 封装了之后,就可以自动完成这些操作,通过上图右边的部分可以看到,我们已经将这个图片的 URL 连同它对应的图片都保存了下来。

f4e817173825760647822c58be1fdf01.png

第二点,Document 对嵌套结构的提供原生支持。回到新闻表示的例子中,想要表示文章的段落结构,我们只要在定义 paragraph 的时候选择 List,再配上需要的模态类型,就可以自动将其转化成嵌套的结构。Document 还支持多层嵌套,可以非常方便地去表示不同语义颗粒度上的信息。

3244301af4d3c6ef52b375c5ad16220e.png

第三,Document 原生支持 embedding 的表示。我们用模型计算完 embedding 之后,就可以直接将其保存起来。

06d1947528e3bb5768ec005b9565328e.png

除此之外,Document 类还提供各种非常便捷的操作函数。例如,处理视频数据时候,经常需要抽帧,Document 原生支持抽帧操作。另外,在数据探索过程中,Document 数据类型提供预览的功能,可以直接听声音、看视频、并展示每一个嵌套结构中的信息。

cf47a3bd3e4336a6e0c7c2076794f5bb.png

Document 类还提供了 embedding 的预览,并支持不同的框架,无论是使用 pytorch,TensorFlow,还是 paddle,都可以直接把 tensor 存储在 Document 里面,直接使用在低位空间中预览向量表示。

11e68c9e52c7c59f0d4d60a241dab237.png

Document 只对单个的多模态文本做封装,在实际训练或者推理的时候,经常会需要对一组 Document 进行批处理操作。因此我们定义了 DocumentArray 数据类型,开发者可以把他当成一个 List(Document) 来使用。

cfd664212768b89b98cbe315e3d3d79e.png

DocumentArray 支持 slicing。而且,DocumentArray 支持条件查询,比如下图例子中,我们要找出 modality 字段等于 D 的所有 Document。

593589d99a46ab9bef871662908c7d1b.png

DocumentArray 支持各种不同的向量存储方案。原生的存储方案是内存存储,方便大家做快速的数据探索。如果数据太大,可以选择放到硬盘里,用 sqlite 去做存储。除此之外,DocumentArray 支持各种不同的向量存储方案,包括 weaviate,qdrant,ElasticSearch,redis 等。我们内部也提供了一套基于 SQLite 和 HNSWlib 的向量近似索引的库 ANNLite。在不同的存储方案间选择也非常方便,只要调整 storage 的参数就可以。

0d7bc7e3fbefaae78c44e5a67750edd8.png

Document 和 DocumentArray 原本是我们Jina框架的一部分,我们在打造框架的过程中,发现这两个数据结构在表示多模态数据方面非常有用,而且很多社区的小伙伴反馈说希望能单独的使用这两个类。所以,我们就把这两个数据结构单独的抽离出来,发布了一个软件包 DocArray。现在 DocArray 为我们的 Jina 全家桶提供最底层的数据结构,是整个框架中的通用语言。

03 多模态应用服务

解决了多模态数据的表示问题之后,下一个挑战是就是如何搭建多模态的应用服务。在搭建过程中,大家经常遇到的问题包括一下这些:

  • 搭建多模态应用离不开神经网络模型,当上线神经网络模型时,经常遇到框架版本和开发环境不一致的问题。这是通常是需要使用容器化,同时保证不同容器之间正常通信。这在工程上是一个非常有挑战性的问题。

  • 第二,因为需要对外提供服务,所以开发者往往需要自己搭建对外服务的接口。大家会使用 FastAPI,Flask 或者 GraphQL 等等,有时下游服务还可能要求用 gRPC,有的用 http,这些接口都需要去开发者去适配。

  • 第三点就是因为多模态的数据和应用服务往往会涉及很多模块,每个模块对算力的要求差异非常大。因此搭建服务时通常都炫耀分布式的系统,保证不同的模块在不同的机器上运行,同时保证伸缩性,比如在计算量大的模块中使用多个副本进行并行处理。

  • 第四点,现在生产环境都是在 基于 Kubernetes 的云原生环境。如果自己去完成,则需要对常用的监控、报警等工具有一定的了解。整个过程全部搭建完成,不包括模型调优的时间,也至少需要几个星期时间。

812d9c55464973165b03c7d066be740b.png

针对这些问题,我们设计了 Jina 这套框架。在 Jina 中,我们充分考虑到分布式和容器的使用,并且专门针对云原生环境进行设计。在 Jina 实现的一套多模态服务中,我们将其称之为一个 Flow。Flow 本身构成一个星型网络,它的中间核心被称为 gateway。网络中的每一个小的模块,也可以理解为处理数据过程中的每一个步骤,被称为 Executor。Executor 放在一起就构成一个 Flow,Executor 之间靠网络通信进行数据传输。

此外,我们在设计时遵循分层的设计原则。最底层是网络的通讯;中间层负责将整个服务进行编排;最上层就是 Executor,负责业务逻辑。对于绝大部分开发者来说,只需要关注 Executor 这层即可,其他两层的服务完全交给 Jina 来处理。这里有一个概念叫 Deployment,实际上就是对应中间层。就 Deployment 对一个或者多个功能相同的 Executor 进行封装,统一和 gateway 进行沟通,提供服务伸缩性的支持。

fe3f7d4bcba52b3ecfa93faa0928cbd6.png

下面来看一个用 Jina 去写 executor 的例子。在刚才用 CLIP 模型计算 embedding  的例子,其实代码唯一的变化就是使用类来取代函数。整个过程只需两步,第一步是创建一个类,继承 Executor 类;第二步是在处理数据的部分,需要加入 request 装饰器,告诉框架我们希望用这个函数去处理对应的请求。只要完成这两步,Jina 框架就可以为你的类去添加必要的 API,来保证这个类可以直接融合在 Flow 里面。

b6cf0d8f21615ab412ad56bff9f3015b.png

定义好 Executor 以后,就可以定义我们的系统了。比如下图中就是定义了一个简单的系统,其中包含两个 encoder,一个是对 text 进行 embedding 的计算,另外一个是对 image 进行 embedding 的计算,最后进行合并。Flow 可以通过 Jina 提供的客户端访问,也可以用 curl 之类工具直接发送请求。对外提供服务都是靠前面提到的 Gateway 来负责的,Gateway 是整个服务的中心,对外可以提供 http,Websocket,gRPC,GraphQL 中心不同的协议。

fc9b418d0994dae2da6df0cf1260b257.png

Jina 自动的生成 Open API,可以非常方便和下游开发同学进行对接联调。我们自己调试和追踪 bug 的时候,也可以使用这些接口进行一些调试。

b7b73fab136df273a41b38524f08f047.png

另外一方面,我们在设计的时候考虑到代码和配置一定要分离。所以,所有 Flow 的定义都可以直接使用 yaml 配置文件。在 YAML 配置文件和 Python 代码完全等价。这样的设计可以便于开发者随时随地去修改配置,比如现在某个模块算力不足,我们希望对它进行水平扩展。如果使用配置文件,就不需要去修改代码,只需要在配置文件中添加一个变量,将 replicas 设置为 3,Jina 就会自动的将服务进行伸缩。

9730e5d420049f97d879339919e66563.png

前面提到,深度学习模型往往依赖很复杂,尤其是上线的时候。一个解决方案就是使用容器化技术。在 Jina 如果想在 flow 调用的时候使用容器化,只需要在配置文件中使用 Jina Hub+docker 的协议前缀,就可以直接去启用容器,调用相应的服务。

32b12e9bd0a089362730a4f371e8e461.png

关于云原生,如果你不想使用 Jina 的编排,我们同时提供在 Kubernetes 环境的一键化部署,只需要定义好自己的 Flow,就可以导出 Kubernetes 的配置文件。同时,我们已经提供诸如 Grafana,Prometheus,fluentd 等常用的接口支持。

3e06be5f6b252f43ef7e1aa726a63c1d.png

前面提到我们有一个 Jina Hub 的协议前缀,如果想使用容器,可以使用 Jina Hub 进行发布。Jina Hub 提供大量的预制模块。比如在信息抽取工作中常用的将 PDF 文件中的文字、图片抽取出来,还有从 video 中把一些帧或者把字幕抽取出来,这些在 Jina Hub 中都可以找到。Jina Hub 的另外一个功能就是方便大家做模块的分享。比如我自己写了一个模块,过两天在另外一个项目也想使用,就可以使用 Jina Hub 进行分享。

63a742343ba2d12def5325ef9827522c.png

Jina 生态中另一个比较重要的功能就是 JCloud 托管服务。在定义好一个Flow 之后,直接使用 jc deploy 就可以将服务在我们云端环境 JCloud 中进行部署。例如当本机计算资源有限,但又想跑一些比较大的 encoding 模型时,就可以使用 JCloud 在远端启一个 embedding 的服务,然后在本地进行调用。我们同时提供了监控、日志等后台。更重要的是这些都是免费的。

07f6215adc7c6c5c10f4e469d74914b6.png

下图是我们的 Jina 代码仓库,欢迎大家关注。我们的初衷就是希望帮助大家节省时间,由我们去写框架性的代码,让大家可以更专注业务逻辑。

40e827427033be8608e9036c9cdc0745.png

04 Jina 全家桶在 DocsQA 中的实践

最后介绍 Jina 全家桶在我们内部产品中的一个实例。

在我们内部有一个产品叫 DocsQA,它本身的初衷是因为我们社区比较大,大家会经常问一些重复的问题,为了节省时间,所以就搭建了一个 QA 系统。搭建完成以后发现这个服务非常实用,于是向所有开源软件都开放了这个服务,只需要提供 GitHub 上的文档地址,我们就可以对文档进行索引,索引完成之后你会拿到一段 HTML 的代码,插到自己的网站上面就可以得到一个 QA 的对话框;在后台我们提供一个 dashboard,可以方便开发者看 QA 的统计数据,比如哪些问题是用户经常问的,方便开发者针对性的去调整文档。

36a9a797e67b3c3f8fb7ce49acbcbfe8.png

整套产品都是通过 Jina 全家桶搭建完成。下图是 Flow 的架构。其中最主要的一路召回就是通过 FAQ 去召回,背后是通过问题到问题的匹配去做召回;另外一路召回就是典型的机器阅读理解(Machine Reading Comprehension,  MRC) 召回。首先通过稀疏和稠密两种方式召回候选,然后再用 Transformer 模型把其中的答案抽取出来。值得注意的是这里的每一个节点都是一组微服务,就是前面提到的 Deployment,在实现的时候只需要去写核心的 Executor 代码,这一整套服务就可以自动启起来。图中几个空心的框框出的节点就是共享的模块。我们使用的 DPR 模型和 TransformerQA 模型,计算开销都很大,同时大部分开源网站访问量都很小,所以不太可能为每个开源网站都专门部署一个服务等待请求。我们通过 Jina 提供的共享方式,使多个服务共享 DPR 服务和 TransformerQA 服务。通过这种形式可以节省很多运维费用,也因此可以为所有开源软件免费提供服务。

852192ae02e0ebc0f3796eca56d7b9dc.png

在 DocsQA 背后,所有的部署也是使用 JCloud 完成,这里展示了当使用 JCloud 做部署时,只需要调用 Python 的 API 就可以完成部署。之前我们使用的是 AWS 的 EKS 服务进行部署,迁移到 JCloud 之后整个成本下降了 80% 以上,因为在 JCloud 上可以保证很多不同的服务共享 node,共享很多集群的资源。

892ce3caca1c3f313bf75fc13b7c967d.png

下图是整个 DocsQA系统,网站的维护者只需要在我们的服务上面提供基础的信息,主要是代码仓的地址,系统就会自动在 JCloud 上启索引服务,对代码仓库的内容进行解析,将索引存储后,接下来会启动查询的 Flow,用于创建查询的服务。查询服务会加载之前创建的索引,并对外提供服务。文档网站上对应的 UI 组件 通过调用服务接口提供服务。整个流程非常简单,属于一个比较经典的 QA 架构。

82b9aae5174886ada7bfe59647945446.png

最后是对我们目前整个开源全家桶的总结,DocArray 为大家提供了一个封装多模态数据的数据类型;Jina 帮助大家搭建一个多模态的服务应用。除此之外,还有几个组件没有时间介绍,分别是:Finetuner针对一些没有太多深度学习相关知识的开发者,提供模型微调的 SaaS 服务;Jina Now 是端到端的神经搜索方案;CLIP-as-service 是一个基于 Jina 的 embedding 服务,大家可以直接 clone 代码,启一个 embedding 服务,也可以使用 SaaS 服务。

1c5e314a5c78ffcd8b01d970cbb0e660.png

另外推荐两个在我们社区里面比较火的项目:一个是 DALL·E Flow,另外一个是 DiscoArt。属于 AI 辅助创作的项目,两个项目都是通过 Jina 全家桶完成搭建的,可玩性非常高,欢迎大家试玩。

48c42d89a2b8113a2b37206ddec93632.png

编辑:王菁

校对:林亦霖

b4a1ed5cea2161bb0ca64d30d29d457d.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值