Towhee,开源的 embedding 框架与社区

2022-02-21 15:32:07 浏览数 (1)

Towhee 是什么

Towhee 是一个开源的 embedding 框架,包含丰富的数据处理算法与神经网络模型。通过 Towhee,能够轻松地处理非结构化数据(如图片、视频、音频、长文本等),完成原始数据到向量的转换。

同时,Towhee 也是一个开放的算法与模型交流社区。在这里,来自世界各地的开发者可以自由地的分享模型与流水线,促进技术与效率的提升。

Towhee website: https://towhee.io

GitHub: https://github.com/towhee-io/towhee

Slack: https://slack.towhee.io

Twitter: https://twitter.com/towheeio

为什么需要 Towhee?

当前,由神经网络模型来驱动数据应用已经成为业界的标准实践。在商品推荐、版权保护、数据管理、软件安全、短视频、制药、金融、保险等诸多领域中,都能看到 embedding 的大量应用。「万物皆可 embedding」的理念在近些年受到了学术界与工业界的广泛认可。如何根据业务需求,对原始数据进行合理的 embedding,成为了工业界亟需解决的问题。Towhee 项目的发起初衷,就是为了搬开这块挡在路中间的大石头。

一个常见的 embedding 流水线的构建流程如上图所示。从最开始的数据准备,到模型调研,模型选型,模型编码,训练与调优,构建流水线,流水线部署,一共经过七个阶段。这些阶段横跨数据管理、算法调研与调优、流水线的工程部署等多个专业领域。另一方面,AI 应用往往面向传统产业升级。对于超过 95% 的用户来说,完成一条具有专业水准的 embedding 流水线都是极具技术挑战的,当然,在大多数情况下,也是远超预算的。

AI 领域以往的工作基本都是以模型为中心,这就导致模型成果与工业界落地应用之间产生了一道鸿沟。以视频中物品 embedding 为例,其中用到的核心模型是目标检测与物品图像的 embedding。这两个方向的模型都有非常丰富的成果,如 RetinaNet,YOLO,CornerNet,ResNet,EfficientNet,ViT 等等。然而,要对一个视频中出现的物品进行 embedding,在算法层面需要视频解码与关键帧提取、关键帧去冗余、图像变换、目标检测、图像裁剪、图像 embedding 等多个算子,在系统层面需要数据并行、数据处理流水线、计算资源管理、内存资源管理等多项系统能力。对应到上述七个阶段中,就形成了模型应用中必须要面对的两项核心工作:一个是「有这么多模型,要根据业务需要依次实现,并选型比较」,另一个是「完成 embedding 流水线中模型以外缺失的部分」。而这些工作,为数据应用落地引入了巨大的技术挑战与成本问题。

与以往的项目相比,Towhee 最大的特点是以应用场景为中心,而非以模型为中心。针对典型的 embedding 场景需要,Towhee 从中抽象出一系列 embedding 流水线。一个典型的 Towhee 流水线的创建与调用如上所示。仅三行代码,即可将一个图片编码为向量。

Towhee 的设计初衷是在轻巧友善的接口下,封装大量的算法与系统实现细节。上面的例子只是 Towhee 能力的一小部分,项目愿景是覆盖 embedding 流水线构建过程中的全部七个阶段:

  • 精心组织的开源数据集与工具
  • 社区共建的 SOTA 预训练模型
  • 紧贴学术前沿与业界前沿的模型热度趋势
  • 遵循标准接口的算子/流水线开源代码库
  • 轻便的 fine-tuning 能力
  • 端到端的流水线,覆盖 embedding 过程中的每个步骤,不再局限于神经网络模型
  • 多平台的部署能力

流水线与算子

目前大家熟悉的 ML 流水线框架,如 kubeflow 等,主要面向模型的训练过程。Towhee 的流水线则主要侧重预测过程,弥补了现有流水线框架在这个方面的不足。

在 Towhee 中,算子是数据处理的基本算法单元,流水线由多个算子组成。在算子与流水线两个层面,都具有标准的接口,这构成了 Towhee 中算子与流水线的复用与灵活组合的基础。流水线按照场景被分为若干个类别,每个类别都具有统一的接口标准。如上面代码例子中的流水线名称为 image-embedding-resnet101,其遵循 image embedding pipeline接口标准。遵循同一接口标准的流水线构成了一个流水线族(pipeline family),如:

  • image-embedding-resnet50
  • image-embedding-resnet101
  • image-embedding-skresnext50d
  • image-embedding-inceptionv4
  • image-embedding-efficientnetb7
  • image-embedding-swinbase
  • image-embedding-swinlarge
  • image-embedding-vitlarge
  • ......

流水线族的统一接口大幅度简化了流水线的选型与升级。用户在流水线选型的过程中,只需要向流水线构建接口 pipeline(pipeline_name:str) 中传入不同的流水线名称,即可快速完成多条同功能流水线的快速构建。由于同一个流水线族内的所有流水线具有完全一致的接口,用户在升级迭代流水线的过程中也不会引发上层代码的改动。

在算子层面,也对应的有算子族(operator family)的概念。如一个 image embedding pipeline 中,会包含 image loader、image transform、image embedding 三类算子,功能分别是图像加载、图像变换、图像特征的向量化编码。每类算子都是一个算子族。如 image embedding 这类算子具有同样的接口,针对这套接口有大量不同的算子实现,如基于 ResNet,EfficientNet,swin-transformer,ViT 等的算子。这些算子就如同具有标准制式的积木一般,在组装成流水线的过程中可以灵活组合或替换。

聚焦 Embedding 的开源社区

Towhee 系统整体上由两部分组成,分别是云上的 Towhee hub,以及驱动具体流水线执行的执行框架。与之对应,Towhee 技术社区的工作也聚焦在流水线执行与流水线内容这两方面。一方面,执行框架主要解决流水线的图表示、图构建、多平台部署、数据并行、执行调度、本地资源管理等关键系统问题。另一方面,Towhee hub 面向社区提供 embedding 流水线与算子的托管服务,构建内容丰富的内容共享与交流平台。

在 Towhee hub 中,流水线族与算子族的接口标准构成了社区成员共享工作的基础。算子与流水线内容以业务场景为中心进行迭代。业务场景-算子-流水线三部分内容的迭代闭环如下。通常,在五种情况下会产生新的算子或流水线:

  • 添加新的流水线族:新的场景需求无法被已有流水线族覆盖,或无法拆解为已有流水线族的功能组合
  • 添加新的流水线:流水线内新的算子组合,或置换原有流水线中部分算子以达到更好的效果
  • 添加新的算子族:新的场景需求无法被已有算子族覆盖
  • 添加新的算子:需要纳入新的数据处理方法,或新的神经网络结构
  • 调优后的算子:对预训练模型进行调优,改变了模型参数

在 Towhee 框架中,对上图五类工作提供了丰富的工具支持:

  • 针对流水线提供了一套描述标准,可以通过 yaml 格式进行流水线的书写或调整
  • 提供了对神经网络中经典 layer 的封装,能够帮助算子开发者更便捷的构建新的神经网络模型
  • 在算子层面提供了支持模型 fine-tuning 的接口

模型调优,自定义算子与流水线

在多数应用中,都需要对预训练模型进行调优。Towhee 的算子是神经网络模型的基本封装单元,因此 Towhee 在每个神经网络类型的算子上都提供了对 fine-tuning 的支持。

一个典型的 fine-tuning 流程如上图所示。用户根据业务场景,在流水线族中选取一到多个能力最接近需要的流水线。如果在此基础上需要进一步调优,那么用户就需要深入到算子层,找到影响效果的关键算子。之后就进入调优环节,准备数据,并调用 Towhee 提供的接口进行模型的 fine-tuning。期间可以将得到的模型配置回原流水线进行效果验证。一切满意后,用最终完成的算子将原算子替换,就得到了一条全新的流水线。

上方给出了一个使用默认训练参数的 fine-tuning 过程。fine-tuning 的接口保持了 Towhee 一贯的简洁。仅五行代码即可完成一次算子的调优。对于高级用户,train 接口提供了对训练参数的控制,可以通过 training_args 这个参数进行调节。

Layer block

Towhee 对工业界与学术界积累的优秀模型进行分解,将常用结构封装到一系列 layer block 中。Layer block 是对基础神经网络层的进一步封装,每一个 layer block 都包含一组具有特定功能的 layer 组合,目的是进一步提高神经网络的模块化程度,提高代码的复用性。例如,在 SwinTransformer 中,构建网络结构的主要单元是 PatchEmbed2D,PatchMerging 和 SwinTransformerBlock,SwinTransformerBlock 包含 LN,MLP,W-MSA 和 SW-WSA 等 layer,使用 pytorch 接口描述一个这样的结构,需要约 500 行 python 代码。在 Towhee 中,抽象并封装了 Transformer 的通用 layer block,通过向这个 layer block 传入一组特定的初始化参数,即可获得一个 SwinTransformerBlock。

目前,Towhee 内置的 layer block 共有 29 种,覆盖了常见的 CNN,GAN,Transformer 等网络结构。在后续的版本中,Towhee 将持续的增加、更新 layer block,帮助开发者更加便捷的构建神经网络。与此同时,在现有的 layer block 基础上,Towhee 还将提供更便捷的 embedding 提取方式,可以灵活获取指定 layer block 的 embedding 输出。

流水线的描述与执行

在系统方面,Towhee 的主要目标是提高 embedding 流水线的表示能力与执行效率,当前系统的能力涵盖:流水线的图表示,计算资源管理,内存资源管理,算子缓存,多流水线并行,算子并行,数据并行等。

每个流水线都由一个有向无环图表示(DAG),其中的节点是流水线中的算子,边描述了算子间的计算依赖关系。在目前的版本中,流水线的 DAG 可以被存储为一个 yaml 文件。给定一个 yaml 格式的流水线描述文件,Towhee 即可实例化完整的流水线。因此,通过描述文件,社区用户可以非常便捷的共享彼此在流水线方面的工作。为了提高流水线的创作效率与可读性,Towhee 在后续的版本中还计划推出流水线的高级语法,类似 Spark 的 RDD 操作。

Towhee 可以根据一个 DAG 创建多组运行期的流水线实例,这些流水线实例可以并发的执行同一组输入数据上的 embedding 任务,更多的流水线实例意味着更高的流水线级并行度。每个流水线实例内包含多个算子实例。在算子层面,同样提供了并发执行能力。算子内的数据处理是基本的任务调度单元,每个任务的执行过程通过 Runner 进行控制。Executor 封装了 CPU 与 GPU 资源,调度器将任务指派给 Excutor,Excutor 为任务分配计算资源,驱动任务的执行。

值得注意的是,Towhee 封装了上述的大量系统细节,并为上层用户提供便捷的调用接口。绝大多数 Towhee 用户都不必关心底层系统问题,从而更聚焦业务。

0 人点赞