使用 Groovy、Deep Java Library (DJL) 和 Apache MXNet 检测对象

作者: Paul King
发布: 2022-08-01 11:52AM


这篇博客文章介绍了如何使用 Apache GroovyDeep Java Library (DJL),并以 Apache MXNet 引擎为后盾来检测图像中的对象。 (Apache MXNet 是 Apache 软件基金会 的一个 孵化项目。)

深度学习

深度学习属于 机器学习人工智能 的分支。 它涉及 人工神经网络 的多层 (因此称为 “深度”)。 配置这些网络有很多方法,具体细节超出了本文的范围,但我们可以提供一些基本信息。 我们将有四个输入节点,对应于我们四个特征的测量值。 我们将有三个输出节点,对应于每个可能的类别 (物种)。 我们还将在它们之间有一层或多层。

Deep learning network

该网络中的每个节点在某种程度上模拟了人脑中的神经元。 我们再次简化细节。 每个节点有多个输入,这些输入被赋予特定的权重,以及一个激活函数,该函数将确定我们的节点是否 “发射”。 训练模型是一个确定最佳权重应该是什么的过程。

Node in a deep learning network

Deep Java Library (DJL) & Apache MXNet

与其自己编写神经网络,不如使用像 DJL 这样的库,它们提供了高级抽象,在一定程度上自动执行了创建必要的网络层。 DJL 是引擎无关的,因此它能够支持不同的后端,包括 Apache MXNet、PyTorch、TensorFlow 和 ONNX Runtime。 我们将使用默认引擎,对于我们的应用程序 (在撰写本文时),该引擎是 Apache MXNet。

Apache MXNet 提供底层引擎。 它支持命令式和符号式执行,使用多 GPU 或多主机硬件对模型进行分布式训练,以及多种语言绑定。 Groovy 与 Java 绑定完全兼容。

使用 DJL 与 Groovy

Groovy 使用 Java 绑定。 考虑查看 DJL 的 Java 初学者教程 - 它们几乎可以不变地适用于 Groovy。

对于我们的示例,我们需要做的第一件事是下载我们要运行对象检测模型的图像

Path tempDir = Files.createTempDirectory("resnetssd")
def imageName = 'dog-ssd.jpg'
Path localImage = tempDir.resolve(imageName)
def url = new URL("https://s3.amazonaws.com/model-server/inputs/$imageName")
DownloadUtils.download(url, localImage, new ProgressBar())
Image img = ImageFactory.instance.fromFile(localImage)

它恰好是一张众所周知的已可用的图像。 我们将在临时目录中存储图像的本地副本,并且我们将使用 DJL 附带的实用程序类来提供一个不错的进度条,以便在图像下载时提供反馈。 DJL 提供它自己的图像类,因此我们将使用来自已下载图像的相应类创建一个实例。

接下来,我们要配置我们的神经网络层

def criteria = Criteria.builder()
    .optApplication(Application.CV.OBJECT_DETECTION)
    .setTypes(Image, DetectedObjects)
    .optFilter("backbone", "resnet50")
    .optEngine(Engine.defaultEngineName)
    .optProgress(new ProgressBar())
    .build()

DLJ 支持众多模型 应用程序,包括图像分类、词语识别、情感分析、线性回归等。 我们将选择 对象检测。 这种应用程序在图像中寻找已知对象的边界框。 类型 配置选项标识我们的输入将是图像,输出将是检测到的对象。 过滤器 选项表明我们将使用 ResNet-50 (一个 50 层的深度卷积神经网络,通常用作许多计算机视觉任务的骨干)。 我们将 引擎 设置为默认引擎,它恰好是 Apache MXNet。 我们还配置了一个可选的进度条,以在模型运行时提供进度反馈。

现在我们已经配置好了,我们将使用它来加载模型,然后使用该模型来进行对象预测

def detection = criteria.loadModel().withCloseable { model ->
    model.newPredictor().predict(img)
}
detection.items().each { println it }
img.drawBoundingBoxes(detection)

为了确保万无一失,我们将把边界框绘制到我们的图像中。

接下来,我们将图像保存到文件,并使用 Groovy 的 SwingBuilder 显示它。

Path imageSaved = tempDir.resolve('detected.png')
imageSaved.withOutputStream { os -> img.save(os, 'png') }
def saved = ImageIO.read(imageSaved.toFile())
new SwingBuilder().edt {
    frame(title: "$detection.numberOfObjects detected objects",
          size: [saved.width, saved.height],
          defaultCloseOperation: DISPOSE_ON_CLOSE,
          show: true) { label(icon: imageIcon(image: saved)) }
}

构建和运行我们的应用程序

我们的代码存储在名为 ObjectDetect.groovy 的源文件中。

我们使用 Gradle 作为我们的构建文件

apply plugin: 'groovy'
apply plugin: 'application'

repositories {
    mavenCentral()
}

application {
    mainClass = 'ObjectDetect'
}

dependencies {
    implementation "ai.djl:api:0.18.0"
    implementation "org.apache.groovy:groovy:4.0.4"
    implementation "org.apache.groovy:groovy-swing:4.0.4"
    runtimeOnly "ai.djl:model-zoo:0.18.0"
    runtimeOnly "ai.djl.mxnet:mxnet-engine:0.18.0"
    runtimeOnly "ai.djl.mxnet:mxnet-model-zoo:0.18.0"
    runtimeOnly "ai.djl.mxnet:mxnet-native-auto:1.8.0"
    runtimeOnly "org.apache.groovy:groovy-nio:4.0.4"
    runtimeOnly "org.slf4j:slf4j-jdk14:1.7.36"
}

我们使用 gradle run 任务运行应用程序

paulk@pop-os:/extra/projects/groovy-data-science$ ./gradlew DLMXNet:run
> Task :DeepLearningMxnet:run
Downloading: 100% |████████████████████████████████████████| dog-ssd.jpg
Loading:     100% |████████████████████████████████████████|
...
class: "car", probability: 0.99991, bounds: [x=0.611, y=0.137, width=0.293, height=0.160]
class: "bicycle", probability: 0.95385, bounds: [x=0.162, y=0.207, width=0.594, height=0.588]
class: "dog", probability: 0.93752, bounds: [x=0.168, y=0.350, width=0.274, height=0.593]

显示的图像如下所示

Detected objects

更多信息

完整的源代码可以在以下存储库中找到
https://github.com/paulk-asert/groovy-data-science/subprojects/DeepLearningMxnet

结论

我们已经研究了如何使用 Apache Groovy、DLJ 和 Apache MXNet 来检测图像中的对象。 我们使用了基于丰富的深度学习模型的模型,但我们不需要深入了解模型或其神经网络层。 DLJ 和 Apache MXNet 为我们完成了繁重的任务。 Groovy 为我们构建应用程序提供了简单的编码体验。