前言
近来,疫情得到了控制,各个地方也都慢慢恢复了往常的热闹。在疫情期间,踊跃出来了很多不错的项目,可以提供我们了解学习。
对于机器学习,对于普通技术人员有种望而止步的既视感。现在,我们结合SpringBoot加Deep Java Library (DJL)构建示例Web应用程序。
Deep Java Library(DJL)是Java的开源深度学习库,用于诊断X射线图像上的COVID-19。
它具有一个使用Twitter Bootstrap和JQuery构建的简单静态HTML页面,用户可以将图像URL提交到REST api,DJL库将在其中下载图像和预测是否是被COVID-19感染的肺部的X射线图像。
免责声明:这只是基于github.com/ieee8023/co… 不应将其用于实际医学诊断。
DJL
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
参数创建的 对象。
有关该模型的更多详细信息,请访问:www.pyimagesearch.com/2020/03/16/… 。
一旦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的诊断。要使用的示例图像参考如下:
- COVID-19 被感染的肺