天天看點

當機器學習遇見SpringBoot,不一樣的火花哦

前言

近來,疫情得到了控制,各個地方也都慢慢恢複了往常的熱鬧。在疫情期間,踴躍出來了很多不錯的項目,可以提供我們了解學習。

對于機器學習,對于普通技術人員有種望而止步的既視感。現在,我們結合SpringBoot加

Deep Java Library

(DJL)建構示例Web應用程式。

(DJL)是Java的開源深度學習庫,用于診斷X射線圖像上的COVID-19。

它具有一個使用Twitter Bootstrap和JQuery建構的簡單靜态HTML頁面,使用者可以将圖像URL送出到REST api,DJL庫将在其中下載下傳圖像和預測是否是被COVID-19感染的肺部的X射線圖像。

到源代碼的連結包含在這篇文章的結尾。

免責聲明:這隻是基于

https://github.com/ieee8023/covid-chestxray-dataset

上的資料集的示範應用程式, 不應将其用于實際醫學診斷。

DJL

是基于Java的庫,支援多種深度學習架構,例如

Apache MxNet

PyTorch

Tensorflow

。由于大多數深度學習引擎都是使用Python而不是Java建構的,是以DJL内置了引擎擴充卡來通路這些引擎的本機共享庫。

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>
<dependencies>
    <!-- Spring Boot web starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency>
    <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>
    </dependency>
</dependencies>           

啟動類

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

配置類

與配置Redis之類的中間件一樣,我們使用DJL,需要進行關聯的配置。可以采用xml配置,當然根據SpringBoot更優雅的實作,采用@Configuration。

@Configuration
public class DjlConfig {
    @Bean
    public ZooModel xrayModel() throws Exception {
        //建立模型 輸入BufferedImage 和Classifications類别
        Criteria<BufferedImage, Classifications> criteria =
        Criteria.builder()
        .setTypes(BufferedImage.class, Classifications.class)
        .optTranslator(new XrayTranslator())
        .build();
        return ModelZoo.loadModel(criteria);
    }
    // 内部類 建構 解析器
    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);
        }
  }
}           

Service層實作

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

ZooModel

DjlConfig

類中建立的 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感染,以及出現的可能性。

Controller層實作

控制器類定義了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));
    }
}           

具體類注解的使用,應該使用過SpringBoot的小夥伴,都了解作用。不是很清晰的同學,可以去SpringBoot官方檢視相關資料。

前端頁面

Spring Boot應用程式具有一個簡單的靜态

index.html

檔案作為診斷REST api的前端用戶端,它使用Twitter Bootstrap進行響應式設計,并使用JQuery進行REST api調用

引入對應的js 、css
<head>
    <link rel="stylesheet" href="/css/bootstrap.min.css"/>
    <script src="/js/jquery.min.js"></script>
</head>           
建立表單,送出資料
<form id="diagnoseForm" class="mb-4">
    <div class="input-group">
        <input type="url" id="imageUrl" class="form-control" required placeholder="輸入圖像url" aria-label="Image URL">
        <div class="input-group-append">
            <button class="btn btn-outline-primary">送出</button>
        </div>
    </div>
</form>           
資料展示區域
<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>           
對應的js代碼
$( "#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();
});           

到此整個代碼,完畢。

運作應用

該應用環境必須需要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://localhost:8080/index.html

進行X射線圖像URL的診斷。要使用的示例圖像參考如下:

源碼在公衆号,背景回複機器學習源碼擷取