## 前言
这几年深度学习的爆发带来了一个未曾预料到的结果,Python 这个曾经小众的语言突然之间变得炙手可热。究其原因,在 Python 的生态中我们可以容易的找到许多的资源。例如,NumPy 用于数据计算、Matplotlib 用于数据可视化以及MXNet、PyTorch、TensorFlow 等一众深度学习框架。相比之下,尽管 Java 语言仍是最流行的语言之一,拥有为数众多的开发者,尤其在企业市场拥有最广泛的应用基础,但事实上我们很难找到合适的用于深度学习的 Java 工具或者框架。现有的为数不多的工具仍存在着许多的不足,例如:易用性不高,使用的仍是 “低级”的 API;绑定于具体的深度学习框架,缺乏框架无关的特性等等。
![image.png](https://dev-media.amazoncloud.cn/5bf09f28c27445ff97f04e190e4e3ee3_image.png "image.png")
*2020年2月的 TIOBE 程序语言指数 (<https://www.tiobe.com/tiobe-index/?trk=cndc-detail>)*
![image.png](https://dev-media.amazoncloud.cn/fbcba3b7a95e4183a661d0d47183e35c_image.png "image.png")
*StackOverflow 开发人员的调查结果 2019 (<https://insights.stackoverflow.com/survey/2019?trk=cndc-detail>)*
## Deep Java Library 概述
这就要引出今天的主角 Deep Java Library (简称 DJL)。DJL 是一个很新的项目,在2019年12月初的亚马逊云科技 re: invent大会上才正式的发布出来。。简单来说,DJL 是一个使用 Java API 简化模型训练、测试、部署和使用深度学习模型进行推理的开源库深度学习工具包,开源的许可协议是 Apache-2.0。对于 Java 开发者而言,可以在 Java 中开发及应用原生的[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)和深度学习模型,同时简化了深度学习开发的难度。通过DJL提供的直观的、高级的 API,Java 开发人员可以训练自己的模型,或者利用数据科学家用 Python 预先训练好的模型来进行推理。如果您恰好是对学习深度学习感兴趣的 Java 开发者,那么 DJL 无疑将是开始深度学习应用的一个最好的起点。
DJL 是在现有深度学习框架的基础上使用原生 Java 概念构建的的开发库。它为开发者提供了深度学习的最新创新和使用前沿硬件的能力,例如GPU、MKL等。简单的 API 抽象并简化了开发深度学习模型所涉及的复杂性,使得这个新的框架更易于学习和应用。有了 model-zoo 中绑定的预训练模型集,开发者可以立即开始将深度学习的SOTA成果集成到Java应用当中。总所周知,JAVA 的设计思想有这样的一句“Write once, run anywhere”(WORE)。同样, DJL 的设计目标也设定为不依赖于具体的引擎和深度学习框架,可以随时切换框架。原则上,基于DJL开发人员可以编写在任何引擎上运行的代码。DJL 目前提供了 Apache MXNet 的实现,预期 TensorFlow 与 PyTorch 的支持也将在不久后发布。从目前的实现来看,DJL 使用了 JNA(Java Native Access)来实现 Apache MXNet 操作的调用。
![image.png](https://dev-media.amazoncloud.cn/7308451980734957b912d8956afb768f_image.png "image.png")
Java Native Access (JNA)
JNA 是一个开源 Java 库,它为 Java 程序提供了访问 Native Shared Library 的方法,而不需要使用 Java Native Interface (JNI)。JNA 库使用一个名为 foreign function interface library (libffi)的小型的库来动态调用原生代码。JNA 库原生的函数,允许代码按名称加载库并检索指向该库中的函数的指针,然后使用 libffi 库调用它。所有这一切都不需要在头文件或任何编译阶段的静态绑定。开发人员使用 Java 接口来描述目标原生库中的函数和结构,这使得利用原生的平台特性变得非常容易。减少了配置和构建 JNI 代码的那样的复杂性。
DJL 提供了对于基础环境的管理。为了保证最佳的性能,提供了基于硬件配置的自动 CPU/GPU 选择。DJL 提供了对多 GPUs 的支持,可以自动检测是否有可用的GPU。如果GPU可用,它将默认运行在一个 GPU 上,除非程序中制定使用的 GPU 数量。
在模型的训练期间,如果希望在多个 GPU 上进行训练,或者希望限制使用 GPU 的数量(对于较小的数据集,您可能希望限制 GPU 的数量),则必须通过设置设备来配置 TrainingConfig。例如,如果您有8个可用的 GPU,并且您希望训练器在5个 GPU 上进行训练,您可以如下配置它。
```js
java
int maxNumberOfGpus = 5;
TrainingConfig config = new DefaultTrainingConfig(initializer, loss)
.setOptimizer(optimizer)
.addEvaluator(accuracy)
.setBatchSize(batchSize)
// Set the devices to run on multi-GPU
.setDevices(Device.getDevices(numberOfGpus));
```
对于 Java 开发者,DJL 的 API 抽象了用于开发模型的常用函数,使得 Java 开发人员能够利用现有的知识简化向[机器学习](https://aws.amazon.com/cn/machine-learning/?trk=cndc-detail)以及深度学习的转换。相信这一点应该是 Java 开发者最希望看到的。关于 DJL 的抽象架构我们可以通过下图进行理解。
![image.png](https://dev-media.amazoncloud.cn/e2ba3144cc724e088d9ad3d971db51cf_image.png "image.png")
来源 :<https://miro.medium.com/max/3472/1*ju6OsZqhpAHTnhFHDp4DXQ.png>
## Deep Java Library 的使用
计算机视觉(CV)是目前深度学习发展最为成熟的领域。其中,目标检测是一种与计算机视觉和图像处理相关的计算机技术,用于在数字图像和视频中检测某一类语义对象(如人、建筑物或汽车)的实例。目标检测在计算机视觉的许多领域都有应用,包括图像检索和视频监控。接下来,我们来展示一个目标检测的例子,体验一下 DJL 的实际表现。该模型使用来自 DJL 的 model-zoo 的预先训练的 Single Shot Detector (SSD)模型,帮助我们从图像中识别西雅图海鹰队(一支职业美式橄榄球球队)的队员。
要将 DJL 用于应用程序项目,可以使用 IntelliJ IDEA 来创建 gradle 项目,并将以下内容添加到 build.gradle 配置中。
![image.png](https://dev-media.amazoncloud.cn/cb17c6b0034a450e8dfd7beb8dff8076_image.png "image.png")
源代码:<https://gist.github.com/vrakesh/e287f5f0004c53ceeda8e6a547f97d49#file-build-gradle?trk=cndc-detail>
接下来,我们就用这张含橄榄球员的图片进行处理。
![image.png](https://dev-media.amazoncloud.cn/82e9038abbd74dfba99f6c9d00954b9a_image.png "image.png")
来源: [Offered under Apache-2.0 license on Gluon-CV](https://github.com/dmlc/web-data/blob/master/gluoncv/pose/soccer.png?trk=cndc-detail)
针对这张图片使用下面的这一段代码来进行推理。这段代码从 model-zoo 加载一个 SSD 模型,然后从模型中创建一个预测器,并使用 predict 函数来识别图像中的对象。然后一个通过一个 helper utility 函数在检测到的对象周围画上框线。
![image.png](https://dev-media.amazoncloud.cn/47cb314c56224258ad78933abaf456e8_image.png "image.png")
源代码:<https://gist.github.com/vrakesh/0faacec9e9f8d88c4cb96c8ae812493a#file-simplessdinference-java?trk=cndc-detail>
这一段代码标识出图像中的三个橄榄球运动员,并将结果保存为工作目录下的图片文件 ssd.png。
![image.png](https://dev-media.amazoncloud.cn/72db62450b1e49d384fd9589dfe3501a_image.png "image.png")
这段代码的长度不大,理解起来也比较容易。我们可以很容易地进行调整,可以测试来自 model-zoo 的其他模型或者针对自己的需要作出改变。但是 DJL 带来的但乐趣远不止如此。可以使用问题问答模型来训练您自己的智能化应用,或者使用图像分类模型来识别杂货架上的商品等等。在 DJL 的 github 上有更多有意思的例子,<https://github.com/awslabs/djl/tree/master/examples?trk=cndc-detail>
最后,这个介绍能够让你 DJL 产生兴趣。此外,也请记住 DJL 的三个最有意思的特性:
* 框架无关
* 为 Java 开发者而准备
* 易于开发部署
注意:
* 项目地址 :<https://github.com/awslabs/djl?trk=cndc-detail>
* DJL 需要 JDK 8(或更高版本)。建议使用JDK8,因为 JDK 11+存在一些已知的问题。问题包括 SpotBugs 与 JDK 11+不兼容。如果使用 JDK 11+, SpotBugs 将不会被执行。
* 目前 DJL 尚不支持分布式模型训练。