Jina 开箱即用的云原生多模态系统解决方案
Jina 是一个基于云原生的多模态应用框架,开发者使用 Jina 可以轻松构建、部署和维护高性能的云原生应用。你可能认为这些都只是空泛的营销口号,甚至产生疑问,到底什么是云原生?对构建多模态应用有什么帮助?它是否只是 Jina 为了获得投资而许下的空洞承诺呢?
在本文里,我们将跟随一家电商公司的机器学习工程师小博,一起回顾他最近所负责的项目:搭建一个 以图搜图服务。通过这项服务,用户只需上传一张图片,便可以使用机器学习技术精准地搜索出相似的商品。我们将深入探究小博是如何完成这一挑战的,并解答文章开头提到的云原生相关问题。
小博的开发之旅
01
原型设计
以图搜图系统通常有两种模式:
索引,创建库存中所有商品的可视化表示。
检索,接收用户上传的照片,并搜索库存中相似的商品。
索引就是创建所有商品的可视化表示,首先利用卷积神经网络提取商品图像的特征,再将提取到的特征存储到数据库中。
检索则是根据用户上传的图片搜索外观相似的商品,因此,需要提取用户上传图像的特征,然后就可以根据向量间的相似度度量(如余弦相似度),搜索得到相似的商品。
为了完成以上任务,小博需要像 PyTorch 这样的深度学习框架,类似 MongoDB 的键值数据库,可能还需要像 Faiss 或 Elasticsearch 这样的向量搜索引擎。作为一名机器学习工程师,小博很熟悉 PyTorch 和原型设计,并且他聪明过人,精力充沛,所以很轻松就将它们连接在一起,完成了第一个原型设计。
原型 —— 工程界最性感的工具
02
将原型升级为服务
这样就完成了吗?当然没有,一切才刚刚开始。小博的目标可不只是写一堆 Python 函数,为了建立 Web 服务,并且方便其它服务调用,小博还需要利用带有 API 的 Web 框架重构应用。
建立 Web 服务的方法很多,例如:利用 Django 框架。小博创建了一个接收用户上传图片的终端,根据相似度度量,从库存中检索相似的商品。最后,检索的结果会以 JSON 对象的格式返回给用户。
在建立 Web 服务的过程中,小博学习了很多新知识,例如 REST API、Web 服务和 Web 框架,但这些似乎已经超出“机器学习工程师”的能力范围。所以他内心开始产生疑问,是否值得花费这么多时间来学习,但学习新知识总归是好的。
但在内心深处,小博其实觉得他的技能可能还不足以让 Web 服务投入生产。但无论如何,经过一段时间的努力,终于把它们粘合在一起了。
SaaS,Soft-as-Service ——商业中最性感的东西
03
在云端部署
小博的进展成功地吸引了产品团队的注意,他们要求小博将服务部署在 AWS 上,并且提供一些真实的流量进行 A/B 测试。这意味着这个 PoC 将面向公众并拥有第一批用户。在将 Web 服务迁移到云端的过程中,小博遇到了很多问题,主要是依赖问题、CUDA 驱动以及 GPU 的麻烦。最终,他通过将所有内容打包在一个 30 GB的 Docker 镜像中解决了这些问题。虽然这是一个很大的单实例容器,但它易于部署和管理。
04
提高可拓展性和性能
现在以图搜图构建完成了吗?还没有。产品团队要求在实际应用的过程中保证服务的可扩展性,这意味着特征提取必须并行进行,并且无延迟地处理并发的用户请求。除此之外,产品团队还要求一定的 QPS,每秒查询次数。
小博尝试使用多线程和多进程编程,提高服务的可扩展性和性能,但在他的深度学习技术栈中,没有开箱即用的工具。于是他决定学习高性能计算框架,如 Dask 或 Ray。经过一些试验和错误,终于将所有东西连接在一起,并使它们正常工作。但这个过程让小博非常疲惫,因为这些和他的专业知识相差太远了。
可扩展性是如此重要,以至于小博情愿放弃其他两条腿。
05
确保可用性并尽量减少停机时间
产品经理:"如果我们的数据库由于更新,导致短期内出现故障怎么办?”
于是,小博设计了一些原生的故障安全机制,这些都是他刚刚翻博客学到的,同时,配置了一些 AWS 服务来确保 Web 服务的可用性,希望它能做到 fire-and-forget,即用即走。
06
获得可观测性
产品经理:“我怎样才能看到流入的流量?“
小博将所有的 print 换成了 logger.info,并且不耐烦地启动了 dashboard。
07
解决安全问题
产品经理:“我们可以添加一些身份验证头吗?”
产品经理:“这个服务容易受到攻击吗?”
此时,小博已经精疲力尽。这与他的专业知识相去甚远,所以,他决定将项目移交给团队一位高级后端工程师,她在软件基础设施和云服务方面有着丰富的经验,并且她很乐意提供帮助。
于是小博和她一起坐下来,滚动浏览胶水代码,证明他使用的技巧和决策都是合理的,同时还向她解释了所有的警告。这位前辈不断地点头,最后她慢慢地喝了一口咖啡,然后说:
“我们为什么不重写呢?“
启发和教训
上面的例子很真实,因为小博可以是你、我或者任何机器学习工程师。最重要的是,它揭示了在生产中开发多模态 AI 系统面临一些阻碍:
首先是缺乏多模态 AI 系统的设计模式。开发者并不清楚怎么表示、计算、存储和传输多模态数据,以及如何在不同的工具之间切换并避免胶水代码。
其次是概念验证和生产系统之间的巨大鸿沟。 产品系统通常需要云原生技术来确保系统的专业性和可扩展性。微服务、协调、容器化和可观察性是产品系统的四大支柱。然而,对于许多机器学习工程师来说,这个学习曲线实在是太陡峭了。如此复杂的技术栈使得开发者难以构建生产就绪系统。
最后是进入市场的时间很长。如果公司选择了错误的技术栈,就会需要更长的时间将产品推向市场。因为公司需要花费很长的时间以及资源开发产品、重构产品,并反复进行。而且,错误的技术栈会导致产品本身出现问题,增加失败的风险。
云原生拯救世界
云原生是一种通过云计算来构建和运行应用的方式,它是一种基于微服务架构开发的方法,开发者可以把应用拆分成许多独立服务,以便更轻松地开发、部署和维护。它由以下概念组成:
微服务:云原生系统的“积木块”
编排:管理微服务的过程
容器化:将微服务打包成容器
可观察性:监控系统运行的过程
DevOps 和 CI/CD:自动化集成系统
听起来也许很酷但好像无关,但我们真的需要所有这些东西吗?
答案是肯定的,下面的表格总结了具体的原因:
多模态系统是一个完整的流水线,要保证不同的模块能在不同的环境里面,独立并且分布式地运行。 | 微服务对应每个任务模块,可以保证每一个模块独立的分布式的运行,再利用编排将它们协调成流水线。 |
多模态系统涉及的软件依赖十分复杂。 | 容器化确保服务的可复用性和隔离性。 |
多模态系统通常需要后端或者软件基础设施服务提供额外的稳定性。 | DevOps 和 CI/CD 促进了系统的整合, 可观察性则提供了监测与诊断系统状态的一体化方案。 |
浅尝 Jina
接下来,让我们一起看看 Jina 的承诺吧。Jina 提供了一个统一的、云原生的全链路解决方案,用于帮助开发者构建多模态系统。Jina 给每一位开发人员提供了从 PoC 到生产就绪产品的最佳体验,不再有技术债,不再需要重构,不再需要在不同的系统间来回切换。
现在一切都开始有意义了,对吧?让我们一起看看 Jina 项目的运行和工作情况吧。
我们从 Hello, World 开始:我们写一个函数,将hello, world添加至一个 Document,在两个 Document 应用两次函数,然后返回并打印结果。
from jina import DocumentArray, Executor, Flow, requests
class MyExec(Executor):
@requests
async def foo(self, docs: DocumentArray, **kwargs):
for d in docs:
d.text += 'hello, world!'
f = Flow().add(uses=MyExec).add(uses=MyExec)
with f:
r = f.post('/', DocumentArray.empty(2))
print(r.texts
────────────────────────── 🎉 Flow is ready to serve! ──────────────────────────
╭────────────── 🔗 Endpoint ───────────────╮
│ ⛓ Protocol GRPC │
│ 🏠 Local 0.0.0.0:52570 │
│ 🔒 Private 192.168.1.126:52570 │
│ 🌍 Public 87.191.159.105:52570 │
╰──────────────────────────────────────────╯
['hello, world!hello, world!', 'hello, world!hello, world!']
虽然这是一个非常简单的程序,但是它抽象出了多模态系统的复杂性,并留下了一个基本逻辑:创建一个数据结构,对其进行操作,并返回结果。
当然,你也可以 14 行纯 Python 代码完成相同的功能。
class Document:
text: str = ''
def foo(docs, **kwargs):
for d in docs:
d.text += 'hello, world!'
docs = [Document(), Document()]
foo(docs)
foo(docs)
for d in docs:
print(d.text)
那么既然使用 Python 也可以完成同样的功能,为什么还需要 Jina 呢?Jina 的优势究竟是什么呢?
以下是 Jina 为你提供的开箱即用的功能
只需一行代码就能实现复制、分片和可扩展性。
具有双工流(duplex streams)的 C/S 架构。
异步非阻塞式的数据工作流。
支持 gRPC、WebSockets、HTTP、GraphQL 网关。
从系统构建之初就采用微服务,无缝 Docker 容器化。
清晰的版本和依赖控制。
来自 Executor Hub 的可复用模块。
利用 Prometheus 和 Grafana 获得实时可观察性。
Kubernetes 无缝集成。
你可能会认为以上的功能只是浮夸的营销,其实并不是,这些仅仅只触及了 Jina 能力的表面。
设计原则
拥有如此强大的功能,你可能会认为 Jina 的学习曲线一定非常陡峭。但其实只需要掌握 3 个概念,你就能上手 Jina:Document、Executor 和 Flow,这三个元素在 基本概念中有介绍。尤其是:
Document 是 Jina 生态的通用数据结构,用于表示非结构化多模态数据,对应数据层。
Executor 是 Jina 的算法单元,对应逻辑层。
Flow 将多个 Executor 连接起来,协调成流水线,对应编排层。
Jina 一直追求极致的易用性,也在一直致力于平缓云原生技术的学习曲线,让开发者能够基于 Jina 轻松利用云原生技术搭建和部署自己的服务。
Jina 与 MLOps 的关系
MLOps 也就是用于机器学习的 DevOps,是将 DevOps 和机器学习工具结合起来的实践。与 MLOps 类似,Jina 也致力于提高机器学习的自动化程度,改进 AI 模型的构建、训练和部署过程。
使用 Jina 的好处包括:
更高的开发效率、更可靠的交付性能:自动化的机器学习工作流(Jina 中的 Flow)加快了模型的开发速度,同时保证进程的可靠性。
更高效的 ML 科学家和工程师的协作:Jina 有助于改善 ML 科学家和工程师之间的沟通与协作,因为 Jina 使得工程师更多地参与到机器学习模型的开发进程中。
更好的模型性能(Jina 中的 Executor):自动化机器学习工作流确保了模型的质量,并提升了模型测试、验证的表现。
基础设施即代码(Jina 中的 Flow):基础设施是另一个关键的用于机器学习的DevOps实践。它就是指用代码配置和管理基础架构,使其更加灵活并且可扩展。
更强大的可观测性:监控和日志记录对于确保机器学习模型的质量至关重要。它们有助于及时发现错误和问题,以便快速修复。
更灵活的模型管理:模型管理通过跟踪不同版本的机器学习模型,确保为每个任务都能使用正确的模型。
小博对 Jina 很满意,再也不用玩胶水代码了。
总结
以往在云上构建多模态系统既繁琐又耗时,并且需要用大量的胶水代码,反复的重构。经过好几个月的努力,最终得到的可能也只是一个脆弱且不可维护的系统。我们了解开发过程中的痛苦,并从中汲取经验教训,这就是我们建立 Jina 的原因。
Jina 的创立初衷就是极大地简化 AI 基础设施的复杂性,帮助开发者和企业快速将 AI 模型落地。使用 Jina,你从第一天起就会做得很专业,因为从 PoC 到生产,从部署到扩展,从监控到分析 —— 每一个环节都由 Jina 把关。你将拥有一个更方便、更高效、更愉快的开发多模态 AI 应用体验。
💻 GitHub: get.jina.ai
📖 文档:docs.jina.ai
🔗 原文链接:https://jina.ai/news/cloud-native-helps-you-build-multimodal-ai-in-production-here-is-how/
更多技术文章📖 Jina AI创始人肖涵博士解读多模态AI的范式变革🎨 语音生成图像任务|🚀 模型微调神器Finetuner
💨 DocArray + Redis:快到飞起来的推荐系统😎 Jina AI正式将DocArray捐赠给Linux基金会🧬 搜索是过拟合的生成;生成是欠拟合的搜索