使用深度学习库DJL和Spring Boot在微服务中实现机器学习 - idk.dev


通过DJL和Spring Boot进行机器学习是一种简单而强大的方法,通过DJL和DJL提供的便捷抽象层,将现有的经过实践测试的微服务技术堆栈SpringBoot与MXNet,PyTorch和Tensorflow等最成熟的深度学习框架相结合。
Spring Boot是用于微服务开发的最流行和广泛使用的开源框架之一,它简化了分布式系统的实现。
尽管此框架具有广泛的吸引力,但几乎没有其他选项可以轻松地将其与机器学习(ML)集成。现有的解决方案(例如库存API)通常无法满足定制的应用程序要求,并且开发定制的解决方案既耗时又不具成本效益。
在这篇博客文章中,我们将演示Java用户如何使用Spring Boot Starter for Deep Java Library(DJL)将ML集成到他们的Spring应用程序中。我们将回顾如何将这些框架付诸实践,并将ML功能集成到微服务中,展示围绕对象检测和分类的常见深度学习用例。

DJL概述
深度Java库(DJL)是用于深度学习的开源,高级别,与框架无关的Java API。它被设计为易于入门,并且对于Java开发人员来说易于使用。DJL提供了本机Java开发经验和功能,就像其他任何常规Java库一样。
DJL是基于最流行的AI/ML框架(例如Apache MXNet,PyTorch和TensorFlow)提供了便利的抽象层。使用DJL API,您将获得一个统一且一致的API层,可以与所有这些框架进行交互,从而使您可以换出您选择的框架,而不会影响客户端代码。
将这种独特的功能与丰富的模型Zoo仓库(具有预先训练的模型的仓库)相结合,可使ML工程师能够为手头任务找到最佳模型,而无需考虑基础模型的实现。
有关DJL的更多信息,请参考DJL GitHub存储库和常见问题解答。

DJL Spring Boot Starter
Spring Boot Starter是您项目中所需的所有Spring和相关技术的一站式商店,不必搜寻示例代码和依赖描述符的复制粘贴负载。请参阅官方的Spring Boot文档以获取有关启动器的更多信息。
按照此定义,DJL Spring Boot Starter提供了在Spring中作为单个工件开始使用DJL所需的所有依赖项。除了依赖关系管理之外,启动程序还包括一个自动配置,该配置使得可以根据用户提供的配置文件自动关联依赖关系,并使它们在Spring Application上下文中可以作为bean使用。

依赖管理
DJL库是特定于平台的,但是它提供了基于目标操作系统自动查找正确依赖关系的方法。DJL也可以使用不同的基础引擎(例如MXNet,PyTorch或TensorFlow)进行配置;用户应在使用启动器之前做出选择。但是,即使做出选择,也可以通过修改Maven(或Gradle)依赖项来更改基础引擎以及目标操作系统体系结构,而不会影响代码。
这是一个针对Linux架构的MXNet依赖关系的示例,它针对容器工作负载进行了优化:

<parent>
  <artifactId>spring-boot-starter-parent</artifactId>
  <groupId>org.springframework.boot</groupId>
  <version>2.2.6.RELEASE</version>
</parent>

<properties>
  <java.version>11</java.version> <!-- 11 is the lowest supported java version, however 12 and 13 should work fine -->
  <jna.version>5.3.0</jna.version> <!-- Required to override default JNA version for Spring Boot parent-->
</properties> 

<dependency>
  <groupId>ai.djl.spring</groupId>
  <artifactId>djl-spring-boot-starter-mxnet-linux-x86_64</artifactId>
  <version>${djl.starter.version}</version> <!-- e.g. 0.2 -->
</dependency>

如果使用PyTorch作为底层引擎,依赖关系是:

<dependency>
  <groupId>ai.djl.spring</groupId>
  <artifactId>djl-spring-boot-starter-pytorch-auto</artifactId>
  <version>${djl.starter.version}</version> <!-- e.g. 0.2 and above -->
</dependency>

Spring自动配置
一旦在Spring Boot应用程序中正确配置了依赖项,下一步就是配置bean并正确地连接它们以进行注入。配置与DJL相关的bean并使它们在Spring应用程序上下文中可用是相当容易的,但是它需要库的内部知识以及各个类的特殊性才能进行适当的作用域确定-一些bean是线程安全的,其他bean应该是线程安全的。范围取决于每个请求/线程。为了协助进行此配置,DJL Spring Boot启动器提供了自动配置。
该组件与依赖项组件分开,并且需要显式依赖项。我们这样做的原因有两个:

  1. 一些开发人员更喜欢完全控制配置选项,并且可能不希望Spring“自动魔术”。在这种情况下,入门者将仅支持基本的依赖关系集,并允许开发人员显式地连接组件。
  2. 自动配置组件对于所有DJL配置都是通用的:无论基础目标操作系统或实际引擎如何,自动配置组件均保持不变。因此,使用相同的自动配置,开发人员可以将基础依赖项交换为一步操作,而不会对代码产生任何影响。

在Maven中声明对自动配置的依赖:

<dependency>
  <groupId>ai.djl.spring</groupId>
  <artifactId>djl-spring-boot-starter-autoconfigure</artifactId>
  <version>${djl.starter.version}</version>
</dependency>

声明依赖关系后,Spring Boot框架将自动找到配置并连接所需的组件。目前,为了进行推理,它将从模型存储库中查找模型,并创建一个随时可用于进行推理的预测器。
用户可通过定义标准的Spring配置(application.yml或application.properties)模型来使用其中一个受支持的应用程序类型:

  QUESTION_ANSWER(NLP.QUESTION_ANSWER),
  TEXT_CLASSIFICATION(NLP.TEXT_CLASSIFICATION),
  IMAGE_CLASSIFICATION(CV.IMAGE_CLASSIFICATION),
  OBJECT_DETECTION(CV.OBJECT_DETECTION),
  ACTION_RECOGNITION(CV.ACTION_RECOGNITION),
  INSTANCE_SEGMENTATION(CV.INSTANCE_SEGMENTATION),
  POSE_ESTIMATION(CV.POSE_ESTIMATION),
  SEMANTIC_SEGMENTATION(CV.SEMANTIC_SEGMENTATION);

例如,为了在图像中运行对象检测,用户可以将应用程序类型设置为OBJECT_DETECTION。与DJL相关的配置应在djl根目录下命名,例如如果application.properties使用的话,配置djl.application-type=OBJECT_DETECTION。
这是yamlDJL自动配置的配置示例:

djl:
    # Define application type
    application-type: OBJECT_DETECTION
    # Define input data type, a model may accept multiple input data type
    input-class: java.awt.image.BufferedImage
    # Define output data type, a model may generate different out put
    output-class: ai.djl.modality.cv.output.DetectedObjects
    # Define filters that matches your application's need
    model-filter:
      size: 512
      backbone: mobilenet1.0
    # Override default pre-processing/post-processing behavior
    arguments:
      threshold: 0.5 # Display all results with probability of 0.5 and above

IDE支持
配置创建不必完全是手动的,DJL Spring Boot Starter通过Spring IDE插件(已在IntelliJ IDEA上进行了测试,但有望在具有STS和NetBeans IDE的Eclipse中运行)为大多数IDE提供了一个配置内容助手。
对于IntelliJ,您可以使用Ctrl + Space来自动完成,并使用Ctrl + J来获取任何属性的快速文档。

简单的应用演练
以下是基于Simple Spring Boot应用程序的代码示例,该示例演示了使用DJL和MXNet进行单次对象检测。
每个Maven依赖项部分都设置了依赖项。配置设置与application.yml示例中的相同。

注入预测器以进行对象检测

@Resource
  private Supplier<Predictor> predictorProvider;

建议在try-with-resources块中使用predictor以确保每次使用后都将其关闭,因此刚注入的predictor供供者能方便实例化。

Java中的对象检测

try (var predictor = predictorProvider.get()) {
    var results = predictor.predict(ImageIO.read(this.getClass()
          .getResourceAsStream("/puppy-in-white-and-red-polka.jpg")));

    for(var result : results.items()) {
        LOG.info(
"results: {}", result.toString());
    }
}

上面的代码将在提供的图像(预期在类路径中)上运行对象检测,并将结果以以下形式输出到记录器:

a.d.s.e.console.ConsoleApplication: results: class: "dog", probability: 0.90820, bounds: {x=0.487, y=0.057, width=0.425, height=0.484}

构建和运行
假设您已签出存储库,并且现在位于存储库的根目录中:

> git clone git@github.com:awslabs/djl-spring-boot-starter.git 
> cd djl-spring-boot-starter/djl-spring-boot-console-sample
> ../mvnw package
> ../mvnw spring-boot:run

或者,您可以使用以下java -jar命令直接运行它:

java -jar target/djl-spring-boot-console-sample-${version}.jar

更复杂的应用示例
以下是基于REST API示例的代码示例,该示例利用DJL Spring Boot Starter演示了RESTful API实现,该实现可以从Amazon Simple Storage Service(Amazon S3)存储桶中获取图像并将对象检测结果存储回S3中。详情点击标题见原文。