使用Spring Boot和DJL进行深度学习


概述 这是Spring Boot上的另一篇文章,该文章将展示如何使用Deep Java Library(DJL)构建示例Web应用程序,Deep Java Library(DJL)是Java的开源深度学习库,用于诊断X射线图像上的COVID-19。

该示例应用程序是DJL类似的COVID-19示例的基于Spring Boot的版本,它具有一个使用Twitter Bootstrap和JQuery构建的简单静态HTML页面,用户可以将图像URL提交到REST api,DJL库将在其中下载图像和预测是否是被COVID-19感染的肺部的X射线图像。

到源代码的链接包含在这篇文章的结尾。

免责声明:这只是一个基于https://github.com/ieee8023/covid-chestxray-dataset上的数据集的演示应用程序,不应将其用于实际医学诊断。

深度Java库 如前所述,DJL是一个基于Java的库,它支持多个 深度学习框架,例如Apache MxNet,PyTorch和Tensorflow。由于大多数深度学习引擎都是使用Python而不是Java构建的,因此DJL内置了引擎适配器来访问这些引擎的本机共享库。

DJL以一种优雅的方式做到了这一点,这使得根据用例从一个框架切换到另一个框架变得非常简单。

Dependencies 该应用程序需要Spring Boot Web Starter:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

还有commons-io库,用于一些基本的I / O操作:

<dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
       </dependency>

Lombok库也是如此,因为我懒得编写getter和setter方法:

<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
       </dependency>

最后是此示例应用程序的DJL依赖项:

<dependency>
            <groupId>ai.djl</groupId>
            <artifactId>api</artifactId>
            <version>${ai.djl.version}</version>
       </dependency>
       <dependency>
            <groupId>ai.djl.tensorflow</groupId>
            <artifactId>tensorflow-api</artifactId>
            <version>${ai.djl.version}</version>
       </dependency>
       <dependency>
            <groupId>ai.djl.tensorflow</groupId>
            <artifactId>tensorflow-engine</artifactId>
            <version>${ai.djl.version}</version>
       </dependency>
       <dependency>
            <groupId>ai.djl.tensorflow</groupId>
            <artifactId>tensorflow-native-auto</artifactId>
            <version>${tensorflow-native-auto.version}</version>
            <scope>runtime</scope>
       </dependency>
       <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>${jna.version}</version>      <!-- overrides default spring boot version to comply with DJL -->
       </dependency>

这是DJL依赖版本所需的Maven属性的列表:

<properties>
        <java.version>1.8</java.version>
        <ai.djl.version>0.5.0</ai.djl.version>
        <jna.version>5.3.0</jna.version>
        <tensorflow-native-auto.version>2.1.0</tensorflow-native-auto.version>
   </properties>

XRayApplication class 此类的main()方法将启动Spring Boot应用程序,并且看起来像大多数其他Application类文件:

@SpringBootApplication public class XRayApplication { 
    public static void main(String[] args) {
         SpringApplication.run(XRayApplication.class, args);
    } 
}

Configuration 为了配置DJL库,让我们创建一个DjlConfig带有@Configuration注释的类。

此类将定义一个ZooModelSpring Bean,它将有助于预测所提交的图像URL是否属于受COVID-19感染的肺:

@Bean
    public ZooModel xrayModel() throws Exception {
        Criteria<BufferedImage, Classifications> criteria =
                Criteria.builder()
                        .setTypes(BufferedImage.class, Classifications.class)
                        .optTranslator(new XrayTranslator())
                        .build();
        return ModelZoo.loadModel(criteria);
    }

这段代码说明的是,我们创建了一个带BufferedImage输入和Classifications输出类型的ZooModel对象(稍后会详细介绍),并且它使用一个XrayTranslator对象将输入图像转换为深度学习模型正常运行所需的格式。

这是的代码,XrayTranslator它是内部的一个内部类DjlConfig:

public static final class XrayTranslator implements Translator<BufferedImage, Classifications> {
         private static final List<String> CLASSES = Arrays.asList("covid-19", "normal");

         @Override
         public NDList processInput(TranslatorContext ctx, BufferedImage input) {
            NDArray array =
                    BufferedImageUtils.toNDArray(
                            ctx.getNDManager(), input, NDImageUtils.Flag.COLOR);
            array = NDImageUtils.resize(array, 224).div(255.0f);
            return new NDList(array);

        }

        @Override
        public Classifications processOutput(TranslatorContext ctx, NDList list) {
            NDArray probabilities = list.singletonOrThrow();
            return new Classifications(CLASSES, probabilities);
        }
    }

Covid19Service 该Covid19Service班将处理业务逻辑来诊断X射线图像,正如你所看到的,奇怪的是,它的代码实际上只是几行:

@Service
public class Covid19Service {
    @Autowired
    private ZooModel xrayModel;

    public String diagnose(String imageUrl) {
        try (Predictor<BufferedImage, Classifications> predictor = xrayModel.newPredictor()) {
            Classifications result = predictor.predict(BufferedImageUtils.fromUrl(imageUrl));
            return "Diagnose: "
                    + result.best().getClassName()
                    + " , probability: "
                    + result.best().getProbability();
        } catch (Exception e) {
            throw new RuntimeException("Failed to diagnose", e);
        }
    }
}

ZooModelDjlConfig类中创建的bean是自动装配的,并在diagnose()具有imageUrl参数的方法中使用。

在该方法内,我们通过预训练的Tensorflow模型Predictor使用该try-resource 块创建一个对象(因为预测器在执行后需要关闭),并使用它来运行BufferedImage(使用imageUrl参数创建的对象。

有关该模型的更多详细信息,请访问:https://www.pyimagesearch.com/2020/03/16/detecting-covid-19-in-x-ray-images-with-keras-tensorflow-and-deep-learning/

一旦diagnose()运行该方法,Classifications结果对象将显示X射线图像上的肺部是否被COVID-19感染,以及感染的可能性是多少。

Covid19Controller 控制器类定义了REST API以诊断X射线图像,这些图像将由我们的简单前端应用程序消耗:

@RestController
@RequestMapping(value = "/api/v1", produces = MediaType.APPLICATION_JSON_VALUE)
public class Covid19Controller {
    private final Covid19Service covid19Service;

    public Covid19Controller(Covid19Service covid19Service) {
        this.covid19Service = covid19Service;
    }

    @GetMapping("/covid19/diagnose")
    public ResponseEntity diagnose(@RequestParam String imageUrl) {
        String answer = covid19Service.diagnose(imageUrl);
        return ResponseEntity.ok(Collections.singletonMap("result", answer));
    }
}

@RestController注解告诉春天,在我们的MVC设计,这是一个ç ontroller豆定义REST API

@RequestMapping注解告诉Spring,这个类中的所有REST API的路径应为前缀/api/v1,所有的REST APIapplication\json的响应。

Covid19Service我们前面所讨论的是在构造函数自动装配,并使用由以后diagnoseREST APIGET /api/v1/covid19/diagnose路径。

诊断api接受imageUrl请求参数,并返回带有结果的String表示形式的JSON文档。

Front-end Spring Boot应用程序具有一个简单的静态index.html文件作为诊断REST API的前端客户端,它使用Twitter Bootstrap进行响应式设计,并使用JQuery进行REST API调用:

<head>
    <link rel="stylesheet" href="/css/bootstrap.min.css"/>
    <script src="/js/jquery.min.js"></script>
</head>

该文件具有HTML格式,可以捕获用户的X射线图像URL:

<form id="diagnoseForm" class="mb-4">
            <div class="input-group">
                <input type="url" id="imageUrl" class="form-control" required
                       placeholder="Enter a image url"
                       aria-label="Image URL">
                <div class="input-group-append">
                    <button class="btn btn-outline-primary">Submit</button>
                </div>
            </div>
       </form>

提交表单后,REST API可能需要一段时间才能做出响应。同时,页面将显示一个微调器,一旦收到响应,该文本将显示在diagnosediv中:

<div class="row ml-1">
            <div id="spinnerDiagnose" class="text-primary" role="status">
                <span class="sr-only">Loading...</span>
            </div>
            <div id="diagnose"></div>
       </div>

参见下面的Javascript代码:

$( "#diagnoseForm" ).submit(function( event ) {
  const imageUrl = $('#imageUrl').val();
  $('#spinnerDiagnose').addClass('spinner-border');
  $('#diagnose').html('');
  $.ajax('/api/v1/covid19/diagnose?imageUrl='+imageUrl)
  .done(data => {
    $('#spinnerDiagnose').removeClass('spinner-border');
    $('#diagnose').html(data.result);
  })
  .fail(err => {

    $('#spinnerDiagnose').removeClass('spinner-border');
    $('#diagnose').html('Failed to get answer');
  });
  event.preventDefault();
});

触发表单的Submit事件时,代码将获取imageUrl值,显示为微调框,diagnose从先前的运行中清除div的内容,并使用调用诊断REST api imageUrl。

如果响应成功,则代码将隐藏微调框,并在diagnosediv中显示结果。

发生错误时,代码还将隐藏微调框并显示一般错误消息。

Running the app 该应用需要先下载Tensorflow才能运行。

在项目的根文件夹中运行以下命令:

mkdir models
cd models
curl https://djl-tensorflow-javacpp.s3.amazonaws.com/tensorflow-models/covid-19/saved_model.zip | jar xv cd .. ./mvnw spring-boot:run -Dai.djl.repository.zoo.location=models/saved_model


原文链接:http://codingdict.com