乐趣区

关于人工智能:活用N维数组-Python世界有NumPyJava世界有NDArray

随着数据迷信在生产中的利用逐渐减少,应用 N 维数组灵便的表白数据变得愈发重要。咱们能够将过来数据迷信运算中的多维循环嵌套运算简化为简略几行。因为进一步开释了计算并行能力,这几行简略的代码运算速度也会比传统多维循环快很多。这种数学计算的包曾经成为于数据迷信,图形学以及机器学习畛域的规范。同时它的影响力还在一直的扩充到其余畛域。

在 Python 的世界,调用 NDArray 的规范包叫做 NumPy。然而现在在 Java 畛域中,并没有与之同样规范的库。为了给 Java 开发者发明同一种应用环境,亚马逊云服务开源了 DJL,一个基于 Java 的深度学习库。只管它蕴含了深度学习模块,然而它最外围的 NDArray 零碎能够被用作 N 维数组的规范。它具备低劣的可扩展性,全平台反对,以及弱小的后端引擎反对(TensorFlow、PyTorch、Apache MXNet)。无论是 CPU 还是 GPU,PC 还是安卓,DJL 都能够轻而易举的实现工作。

下文将介绍 NDArray,并通知大家如何写与 NumPy 同样简略的 Java 代码,以及如何将 NDArray 应用在事实中的利用之中。

装置 DJL

能够通过下方的配置来配置 gradle 我的项目,或者也能够跳过设置间接应用咱们的在线 JShell。

plugins {id 'java'}
repositories {jcenter()
}
dependencies {
implementation "ai.djl:api:0.6.0"
// PyTorch
runtimeOnly "ai.djl.pytorch:pytorch-engine:0.6.0"
runtimeOnly "ai.djl.pytorch:pytorch-native-auto:1.5.0"
}

而后,咱们就能够开始上手写代码了。

基本操作

首先尝试建设一个 Try block 来蕴含咱们的代码(如果应用在线 JShell 可跳过此步):

try(NDManager manager = NDManager.newBaseManager()) {}

NDManager 是 DJL 中的一个 Class,能够帮忙治理 NDArray 的内存应用。通过创立 NDManager,咱们能够更及时地对内存进行清理。当这个 Block 里的工作运行实现时,外部产生的 NDArray 都会被清理掉。这个设计保障了咱们在大规模应用 NDArray 的过程中,能够通过清理其中的 NDManager 来更高效地利用内存。为了做比照,咱们能够参考 NumPy 在 Python 之中的利用。

import numpy as np

创立 NDArray

Ones 是一个创立全是 1 的 N 维数组操作。

Python (Numpy)

nd = np.ones((2, 3))
[[1. 1. 1.]
[1. 1. 1.]]

Java (DJL NDArray)

NDArray nd = manager.ones(new Shape(2, 3));
/*
ND: (2, 3) cpu() float32
[[1., 1., 1.],
[1., 1., 1.],
]
*/

咱们也能够尝试生成随机数。比方须要生成一些从 0 到 1 的随机数:

Python (Numpy)

nd = np.random.uniform(0, 1, (1, 1, 4))
# [[[0.7034806 0.85115891 0.63903668 0.39386125]]]

Java (DJL NDArray)

NDArray nd = manager.randomUniform(0, 1, new Shape(1, 1, 4));
/*
ND: (1, 1, 4) cpu() float32
[[[0.932 , 0.7686, 0.2031, 0.7468],
],
]
*/

这只是简略演示一些罕用性能。当初 NDManager 反对多达 20 种在 NumPy 中创立 NDArray 的办法。

数学运算

咱们能够应用 NDArray 进行一系列数学操作。假如想对数据做一个转置操作,而后对所有数据加一个数的操作。能够参考如下的实现:

Python (Numpy)

nd = np.arange(1, 10).reshape(3, 3)
nd = nd.transpose()
nd = nd + 10
[[11 14 17]
[12 15 18]
[13 16 19]]

Java (DJL NDArray)

NDArray nd = manager.arange(1, 10).reshape(3, 3);
nd = nd.transpose();
nd = nd.add(10);
/*
ND: (3, 3) cpu() int32
[[11, 14, 17],
[12, 15, 18],
[13, 16, 19],
]
*/

DJL 当初反对 60 多种不同的 NumPy 数学运算,根本涵盖了大部分的利用场景。

Get 和 Set

其中一个对于 NDArray 最重要的亮点就是它轻松简略的数据设置 / 获取性能。咱们参考了 NumPy 的设计,将 Java 过来对于数据表白中的艰难做了精简化解决。假如想筛选一个 N 维数组所有小于 10 的数:

Python (Numpy)

nd = np.arange(5, 14)
nd = nd[nd >= 10]
# [10 11 12 13]

Java (DJL NDArray)

NDArray nd = manager.arange(5, 14);
nd = nd.get(nd.gte(10));
/*
ND: (4) cpu() int32
[10, 11, 12, 13]
*/

是不是非常简单?接下来,咱们看一个略微简单一些的利用场景。假如当初有一个 3×3 的矩阵,而后咱们想把第二列的数据都乘以 2:

Python (Numpy)

nd = np.arange(1, 10).reshape(3, 3)
nd[:, 1] *= 2
[[1 4 3]
[4 10 6]
[7 16 9]]

Java (DJL NDArray)

NDArray nd = manager.arange(1, 10).reshape(3, 3);
nd.set(new NDIndex(":, 1"), array -> array.mul(2));
/*
ND: (3, 3) cpu() int32
[[1, 4, 3],
[4, 10, 6],
[7, 16, 9],
]
*/

在下面的案例中,咱们在 Java 引入了一个 NDIndex 的 Class。它复刻了大部分在 NumPy 中对于 NDArray 反对的 get/set 操作。只须要简略的放进去一个字符串表达式,开发者在 Java 中能够轻松玩转各种数组的操作。

事实中的利用场景

上述的操作对于宏大的数据集是非常有帮忙的。当初咱们来看一下这个利用场景:基于单词的分类零碎训练。在这个场景中,开发者想要利用从用户中获取的数据来进行情感剖析预测。NDArray 被利用在了对于数据进行前后解决的工作中。

分词操作

在输出到 NDArray 数据前,咱们须要对于输出的字符串进行分词操作并编码成数字。上面代码中看到的 Tokenizer 是一个 Map<String, Integer>。它是一个单词到字典地位的映射。

String text = "The rabbit cross the street and kick the fox";
String[] tokens = text.toLowerCase().split(" ");
int[] vector = new int[tokens.length];
/*
String[9] { "the", "rabbit", "cross", "the", "street",
"and", "kick", "the", "fox" }
*/
for (int i = 0; i < tokens.length; i++) {vector[i] = tokenizer.get(tokens[i]);
}
vector
/*
int[9] {1, 6, 5, 1, 3, 2, 8, 1, 12}
*/

NDArray 解决

通过编码操作后,咱们创立了 NDArray。而后须要转化数据的构造:

NDArray array = manager.create(vector);
array = array.reshape(new Shape(vector.length, 1)); // form a batch
array = array.div(10.0);
/*
ND: (9, 1) cpu() float64
[[0.1],
[0.6],
[0.5],
[0.1],
[0.3],
[0.2],
[0.8],
[0.1],
[1.2],
]
*/

最初,咱们将数据传入深度学习模型中。如果应用 Java 要达到这些须要更多的工作量:如果须要实现相似于 Reshape 的办法,咱们须要创立一个 N 维数组:List<List<List<…List<Float>…>>> 来保障不同维度的可操作性。同时咱们须要可能反对插入新的 List<Float> 来创立最终的数据格式。

为什么应该应用 NDArray 呢?

通过了这个教程,大家应该取得了根本的 NDArray 在 Java 中的应用体验。然而这依然只是表象,它的很多外在价值只有在生产环境中能力体现进去。总结一下,NDArray 具备如下几个长处:

  • 大海捞针:轻松应用超过 60 个在 Java 中的形式实现与 NumPy 雷同的后果。
  • 快如闪电:具备各路深度学习框架加持,DJL NDArray 具备各种硬件平台的减速,比方在 CPU 上的 MKLDNN 减速以及 GPU 上的 CUDA 减速。无论多大的数据集都能够轻松应答。
  • 深度学习:同时具备高维数组反对,同时具备离散数组反对。咱们能够轻松地将 DJL 与其余大数据或者流数据平台联合起来利用:比方分布式解决的 Apache Spark 平台,以及 Apache Flink 的流数据平台。为现有的计划构建一层深度学习的中间件。
  • 离散数组当初只蕴含 PyTorch 中的 COO 以及 MXNet 中的 CSR/Row_Sparse。

NDArray 在 DJL 中的实现过程

大家兴许会好奇,NDArray 到底是如何在 DJL 之中构建的呢?接下来,咱们会解说一下 NDArray 在 DJL 外部的架构。

NDArray 架构

如上图所示,NDArray 有三个要害的层。界面层(Interface)蕴含了所用到的 NDArray,它只是一个 Java 的界面并定义了 NDArray 的输入输出构造。咱们很认真地剖析了每一个形式的应用办法以便尽可能的将它们和用户的利用场景对立以及便于应用。在引擎提供者层(EngineProvider),是 DJL 各种深度学习引擎为 NDArray 界面开发的包。这个层把原生的深度学习引擎算子表白映射在 NumPy 之上。这样通过这样一层转译,咱们在不同引擎上看到 NDArray 的体现都是统一的而且同时兼顾了 NumPy 的体现。在 C ++ 层,为了更便于 Java 应用,咱们构建了 JNI 和 JNA 暴露出 C /C++ 等办法,它能够保障咱们有足够的办法来构建 NDArray 所须要的性能。同时 C ++ 与 Java 的间接调用也能够保障 NDArray 领有最好的性能。

对于 DJL

Deep Java Library (DJL) 是一个基于 Java 的深度学习框架,同时反对训练以及推理。DJL 博取众长,构建在多个深度学习框架之上(TenserFlow、PyTorch、MXNet 等),也同时具备多个框架的低劣个性。咱们能够轻松应用 DJL 来进行训练而后部署模型。

它同时领有着弱小的模型库反对:只需一行便能够轻松读取各种预训练的模型。当初 DJL 的模型库同时反对高达 70 个来自 GluonCV、HuggingFace、TorchHub 以及 Keras 的模型。NDArray 的到来帮忙 DJL 胜利转变为 Java 在深度学习畛域中最好的工具。它具备平台自检测机制,无需任何额定设置,便能够在利用中构建基于 CPU/GPU 的代码。

在最新的版本中,DJL 0.6.0 增加了对于 MXNet 1.7.0、PyTorch 1.5.0 和 TensorFlow 2.2.0 的反对。咱们同时也增加了 ONNXRuntime 以及 PyTorch 在安卓平台的反对。

请参考咱们的 GitHub、demo repository、Slack channel 以及知乎来获取更多信息!

退出移动版