几行代码,轻松实现目标检测和图像分类任务——基于 Spring Boot 和 DJL搭建企业级机器学习微服务

image

现在 AI 应用领域似乎有一种趋势,大多数学习应用在 Python 中。Spring Boot 作为在微服务领域中广泛应用的开源平台,用户可以通过使用 Stock API 创建一个基于 C++ 或者 Python 应用的 RPC API 来实现不同语言的推理任务。但是这将带来大量的维护成本及效率问题——单纯就 RPC 通信来说,仅仅通信的时间消耗就已经达到了推理的时间消耗,这成为整体应用速度提升的瓶颈。现在好啦,AWS 云服务推出了基于深度学习的开源 Java 库, DeepJavaLibrary (DJL),简化繁琐的开发流程,将更好更稳定的解决方案带给广大的开发者。

前言

许多 AWS 云服务的用户,无论是初创企业还是大公司,都在逐步将机器学习 (ML) 和深度学习 (DL) 任务搭载在他们已有产品之上。大量的机器学习任务应用在商业和工业领域,例如应用在图像和视频中的目标检测,文档中的情感分析,大数据中的欺诈识别。尽管机器学习应用广泛应用在其他语言中(例如 Python),但是对于广大已有产品的开发者学习和集成成本依然很高。试想一下,如果要用另一种语言集成在已有的Java服务中,从写代码,编译,测试到最后部署都要做出大量改变。为了解决用户在这方面上的痛点,这篇文章将提出一种解决问题的新思路:用户无需对已有的资源和人员重新调配,可以直接部署机器学习应用在现有的服务中。

Spring Boot在生产环境中的应用

Spring Boot 是一个在微服务领域中广泛应用的开源平台。它的主要特色就是简化了分布式系统分发管理应用的过程。但是就目前来看,用户可选的部署 ML 应用方案屈指可数。就拿推理应用来说,用户可以通过使用 Stock API 创建一个基于 C++ 或者 Python 应用的 RPC API 来实现不同语言的推理任务。尽管这个解决方案可以在最短时间内解决部署的燃眉之急,但是从长期运行的效果来看,它造成了大量的维护成本以及效率问题。单纯就 RPC 通信这一方面来说,可能仅仅通信的时间消耗就已经达到了推理的时间消耗,造成这个解决方案成为整体应用速度提升的瓶颈。

为了更好的解决开发者的困境,AWS 云服务推出了基于深度学习的开源 Java 库, DeepJavaLibrary (DJL)。DJL 的服务宗旨是简化昂贵且繁琐的开发流程,将更好更稳定的解决方案带给广大的开发者。这篇文章会从一个基本的 Spring boot 应用出发,利用 Deep Java Library (DJL),来集成机器学习应用在微服务中。仅通过几行代码,就可以轻松实现目标检测和图像分类任务。

配置 Spring Boot Starter (SBS)

Spring Boot Starter 是一个一站式的 Spring 库管理工具。它简化了诸多引用新的库需要进行的操作,比如复制粘贴样本代码,修改配置文件等。请参考 Spring Boot Starter 官方指南以获取更多信息。在我们今天的教学中,我们将使用 DJL Spring Boot Starter, 一个增加了深度学习部署功能的 SBS。在现有架构的基础上,DJL SBS 增添了自动配置的功能。它使得用户无需担心依赖项,几行代码就可以将它们作为 beans 。如果后面有任何一步不是很清楚,可以参考我们示例应用

依赖项管理

DJL 库可以应用在各种操作系统平台上,也同时支持多种深度学习引擎,比如 TensorFlow 2.0, PyTorch 以及 MXNet。DJL 内建了一系列自动选择机制,用户无需选择运行的操作系统。但是 DJL 仍旧需要用户选择一种或多种深度学习引擎。以 MXNet 为例,用户可以选择进行如下的配置 (pom.xml):

<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 是Java最低支持的版本 -->
  <jna.version>5.3.0</jna.version> <!-- 需要覆写 JNA 版本-->
</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>

用户可以自己选择需要运行的平台,上面 <dependency> 中, linux-x86_64 (Linux) 可以被替换为 win-x86_64 (Windows), 或者 osx-x86_64 (Mac OS)。

我们也提供了一种在运行时自动寻找相应系统的全自动依赖项 auto
`<dependency>
<groupId>ai.djl.spring</groupId>
<artifactId>djl-spring-boot-starter-mxnet-auto</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>

Gradle 的配置也十分相似,只需要如下几行:

plugins {
  ...
  id("org.springframework.boot")
}
repositories {
  mavenCentral() // 发布的包在maven central
}

dependencies {
  implementation("ai.djl.spring:djl-spring-boot-starter-mxnet-auto:0.2")
}

注意,由于 SpringBoot 本身使用了一个旧版的 JNA 库,我们需要手动设置gradle.properties 里面的"jna.version=5.3.0"

使用Spring 全自动选择功能

接下来,我们可以通过添加如下依赖项来使用 Spring 的 auto-configuration 来实现自动选择功能:

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

在 gradle:

dependencies {
  implementation("ai.djl.spring:djl-spring-boot-starter-autoconfigure:${djl.starter.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。可以参考下面的 yaml 来配置:

djl:
    # 设定应用种类
    application-type: OBJECT_DETECTION
    # 设定输入数据格式, 有的模型支持多种数据格式
    input-class: java.awt.image.BufferedImage
    # 设定输出数据格式
    output-class: ai.djl.modality.cv.output.DetectedObjects
    # 设定一个筛选器来筛选你的模型
    model-filter:
      size: 512
      backbone: mobilenet1.0
    # 覆写已有的输入输出配置
    arguments:
      threshold: 0.5 # 只展示预测结果大于等于 0.5

IDE 支持

我们推荐用户使用 IDE,如 intelliJ 或者 Eclipse:

Image URL: https://github.com/awslabs/djl-spring-boot-starter-demo/raw/master/docs/media/djl-start-ide-support-low-frame-30s.gif

intelliJ 可以通过
Ctrl+Space 来自动完成
Ctrl+J 来快速查询文档

运行你的应用

现在我们赶紧试试看之前配置的效果吧。从现在开始,我们只需要两步就可以完成所有的模型部署运行任务。在此之前,开发者只需要创建一个简单的单一类 Spring 应用即可。

第一步:注入 predictor 用来做目标检测

 @Resource 
 private Supplier<Predictor> predictorProvider;

第二步: 运行目标检测

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());
    }
}

如果你使用了我们的示例,那么在 console 会显示如下结果:

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

我们也提供了一个更复杂的例子,你可以使用多种插件,快速实现一个 Restful 的分类器微服务。

了解DJL

image
DJL是 AWS 云服务在2019年 re:Invent 大会推出的专为 Java 开发者量身定制的深度学习框架,现已运行在亚马逊数以百万的推理任务中。如果要总结 DJL 的主要特色,那么就是如下三点:

DJL不设限制于后端引擎:用户可以轻松的使用 MXNet, PyTorch, TensorFlow 和 fastText 来在 Java 上做模型训练和推理。
DJL 的算子设计无限趋近于 numpy:它的使用体验上和 numpy 基本是无缝的,切换引擎也不会造成结果改变。
DJL 优秀的内存管理以及效率机制:DJL 拥有自己的资源回收机制,100个小时连续推理也不会内存溢出。

现在可以在 Mac/Linux/Windows 全平台运行 DJL。DJL 具有自检测 CUDA 版本的功能,也会自动采用对应的 CUDA 版本包来运行 gpu 任务。想了解更多,请参见下面几个链接:

https://djl.ai
https://github.com/awslabs/djl
也欢迎加入 DJL slack 论坛

image

阅读 1.8k

推荐阅读
AWS_AI开发社区
用户专栏

AWS_AI 开发者社区是专注于人工智能领域 IT 人士交流与互动的平台。在这里,你可以分享和获取一切有关人...

882 人关注
79 篇文章
专栏主页