用于Java开发机器学习和深度学习的Vector API(翻译)

  • Post author:
  • Post category:java


本文介绍了用于Java开发机器学习和深度学习的Vector API

英语原文链接 https://software.intel.com/en-us/articles/vector-api-developer-program-for-java



介绍

如今,大数据应用程序,分布式深度学习和人工智能解决方案可以直接在现有的Apache Spark *或Apache Hadoop *集群之上运行,并可以从有效的横向扩展中受益。为了在这些应用程序中获得理想的数据并行性,Open JDK Project Panama提供了Vector API。用于Java *软件的Vector API开发人员计划 提供了广泛的方法,可以丰富Java开发人员的机器学习和深度学习体验。

视频地址:https://www.youtube.com/embed/X49ucwtwuU0?feature=oembed&enablejsapi=1

本文向Java开发人员介绍Vector API,说明了如何在Java程序中开始使用API​​,并提供了矢量算法的示例。提供了有关如何构建矢量API以及如何使用它来构建Java应用程序的分步详细信息。此外,我们提供了有关如何在Java中为自己的算法实现Vector代码(后文翻译为

矢量



向量

)以提高性能的详细教程。



什么是SIMD?

单指令多数据(SIMD)允许在多个数据点上同时执行相同的操作,这得益于应用程序中数据级别的并行性。现代CPU具有高级SIMD操作支持,例如提供SIMD(指令)加速功能的AVX2,AVX3。

大数据应用程序(例如Apache Flink,Apache Spark机器学习库和Intel Big DL,数据分析和深度学习培训工作负载等)运行高度数据并行的算法。Java中的强大的SIMD支持将为扩展其中一些领域提供途径。



什么是Vector API?

用于Java *软件的Vector API开发人员项目使使用Java编写计算密集型应用程序,机器学习和人工智能算法,在没有Java本机接口(JNI)性能开销或对不可移植的本机代码的进一步维护需求的情况下,成为可能。API引入了一组用于对分大小的vector-types进行数据并行操作的方法,以便直接在Java中进行编程,而无需任何有关底层CPU的知识。JVM JIT编译器将这些低级API进一步有效地映射到现代CPU上的SIMD指令,以实现所需的性能加速;否则,将使用默认的VM实现将Java字节码映射为硬件指令。



Vector 接口

Vector API接口如下所示:

在这里插入图片描述



Vector Type

Vector Type(Vector <E,S>)采用’E’表示元素类型和’S’表示形状或向量的按位长度。基于最近的进展,Panama 项目支持以下元素和形状的Vectors创建。

1 Element types: Byte, Short, Integer, Long, Float, and Double

2 Shape types (bit-size): 128, 256, and 512

选择矢量形状以将它们紧密映射到CPU平台上可用的最大SIMD寄存器上。



Vector 运算

所有这些Vector类型都可以使用基本的Vector-Vector功能。典型的算术和三角函数的矢量运算均以掩码格式提供。mask用于if-else类型的条件操作。

示例部分展示了如何在程序中使用 Vector mask。

01  public abstract class DoubleVector<S extends Vector.Shape<Vector<?,?>>> implements Vector<Double,S> {                                                     
02  Vector<Double, S> add (Vector<Double, S> v2);         
03  Vector<Double,S> add (Vector<Double, S> o, Mask<Double, S> m);
04  Vector<Double, S> mul (Vector<Double, S> v2);      
05  Vector<Double, S> mul (Vector<Double, S> o, Mask<Double, S> m);    
06  ….   
07 Vector<Double, S> sin ();
08  Vector<Double, S> sin (Mask<Double, S> m);
09  Vector<Double, S> sqrt (),          
10  …
11}

Vector API还提供了金融服务行业(FSI)和机器学习应用程序中经常需要的更高级的Vector操作。

01public abstract class IntVector<S extends Vector.Shape<Vector<?,?>>> implements Vector<Integer,S> {
02int sumAll ();                            
03       void intoArray(int[] a, int ix);
04       void intoArray (int [] is, int ix, Mask<Integer, S> m);
05       Vector<Integer, S> fromArray (int [] fs, int ix);   
06       Vector<Integer, S> blend (Vector<Integer, S> o, Mask<Integer, S> m);
07       Vector<Integer, S> shuffle (Vector<Integer, S> o, Shuffle<Integer, S> s);  
08       Vector<Integer, S> fromByte (byte f);     
09       …
10      }



机器学习中的性能提升



基本线性代数子程序(BLAS)

使用Vector实现BLAS I,II和III 例程可以将性能提高3-4倍。

BLAS I和II 例程通常在Apache Spark机器学习库中使用。这些适用于班轮模型和决策树的分类和回归,协同过滤和聚类以及降维问题。BLAS-III例程(例如GEMM)广泛用于解决人工智能中使用的深度学习和神经网络问题。

在这里插入图片描述

*Open JDK Project Panama source build 0918201709182017。Java Hotspot 64位服务器VM(混合模式)。操作系统版本:Cent OS 7.3 64位

英特尔®至强®铂金8180处理器(使用512字节和1024字节的浮点数据块)。

JVM选项:-XX:+ UnlockDiagnosticVMOptions -XX:-CheckIntrinsics -XX:TypeProfileLevel = 121 -XX:+ UseVectorApiIntrinsics



图像处理过滤

使用Vector API,棕褐色过滤的速度最高可提高6倍。

在这里插入图片描述



编写Vector代码



在Java *中使用Vector API

Vector接口是com.oracle.vector软件包的一部分,我们从Vector API开始,在程序中导入以下内容。根据向量类型,用户可以选择导入FloatVector,IntVector等。

1import jdk.incubator.vector.FloatVector;

2 import jdk.incubator.vector.Vector;

3 import jdk.incubator.vector.Shapes;

矢量类型(Vector <E,S>)具有两个参数。

‘E’:元素类型,广泛支持int,float和double基本类型。

“ S”指定矢量的形状或按位大小。

在使用向量运算之前,程序员必须创建一个第一个向量实例来捕获元素类型和向量形状。使用该特定大小和形状的矢量可以被创建。

1 private static final FloatVector.FloatSpecies<Shapes.S256Bit> species = (FloatVector.FloatSpecies<Shapes.S256Bit>) Vector.speciesInstance (Float.class, Shapes.S_256_BIT);

2 IntVector.IntSpecies<Shapes.S512Bit> ispec = (IntVector.IntSpecies<Shapes.S512Bit>) Vector.speciesInstance(Integer.class, Shapes.S_512_BIT);

从此以后,用户可以创建FloatVector <Shapes.S256Bit>和IntVector <Shapes.S512Bit>类型的矢量实例。



简单的矢量循环

在本节中,我们提供了矢量API编程的风格。Vector API白皮书<

使用Java 编写自矢量算法以提高性能

>中提供了有关如何编写矢量算法的详细技巧和窍门。BLAS和FSI例程的示例矢量代码示例可在后续章节中找到。

第一个示例展示两个数组的向量加法。程序使用诸如fromArray(),intoArray()之类的向量操作将向量加载/存储到数组中。

向量add()运算用于算术运算。

1 public static void AddArrays (float [] left, float [] right, float [] res, int i) {
2 FloatVector.FloatSpecies<Shapes.S256Bit> species = (FloatVector.FloatSpecies<Shapes.S256Bit>) 
3       Vector.speciesInstance (Float.class, Shapes.S_256_BIT);
4       FloatVector<Shapes.S256Bit> l  = species.fromArray (left, i);
5       FloatVector<Shapes.S256Bit> r  = species.fromArray (right, i);
6       FloatVector<Shapes.S256Bit> lr = l.add(r);
7       lr.intoArray (res, i);
8}

通过使用species.length()查询向量大小来编写向量循环。考虑下面的标量循环,它将数组A和B相加并将结果存储到数组C中。

1 for (int i = 0; i < C.length; i++) {
2     C[i] = A[i] + B[i];
3 }

向量化循环如下所示:

01 public static void add (int [] C, int [] A, int [] B) {
02        IntVector.IntSpecies<Shapes.S256Bit> species =
03        (IntVector.IntSpecies<Shapes.S256Bit>)     Vector.speciesInstance(Integer.class, Shapes.S_256_BIT);
04        int i;
05        for (i = 0; (i + species.length()) < C.length; i += species.length ()) {
06    IntVector<Shapes.S256Bit> av = species.fromArray (A, i);
07            IntVector<Shapes.S256Bit> bv = species.fromArray (B, i);
08            av.add(bv).intoArray(C, i);
09        }
10        for (; i < C.length; i++) { // Cleanup loop
11            C[i] = A[i] + B[i];
12        }
13    }

也可以以长度不可知的方式编写该程序,而与向量大小无关。随后的程序通过Shape设置矢量代码的参数。

01public class AddClass<S extends Vector.Shape<Vector<?, ?>>> {
02      private final FloatVector.FloatSpecies<S> spec;
03      AddClass (FloatVector.FloatSpecies<S> v) {spec = v; }
04      //vector routine for add
05       void add (float [] A, float [] B, float [] C) {
06        int i=0;
07        for (; i+spec.length ()<C.length;i+=spec.length ()) {
08            FloatVector<S> av = spec.fromArray (A, i);
09            FloatVector<S> bv = spec.fromArray (B, i);
10            av.add (bv).intoArray(C, i);
11        }
12       //clean up loop
13        for (;i<a.length;i++) C[i]=A[i]+B[i];

条件语句中的运算可以使用掩码以矢量形式编写。

标量例程如下,

1for (int i = 0; i < SIZE; i++) {
2    float res = b[i];
3    if (a[i] > 1.0) {
4      res = res * a[i];
5          }
6         c[i] = res;
7      }

使用mask的Vector例程如下。

01public void useMask (float [] a, float [] b, float [] c, int SIZE) {
02 FloatVector.FloatSpecies<Shapes.S256Bit> species = (FloatVector.FloatSpecies <Shapes.S256Bit>) Vector.speciesInstance   Float.class, Shapes.S_256_BIT);
03 FloatVector<Shapes.S256Bit> tv=species.broadcast (1.0f); int i = 0;
04 for (; i+ species.length() < SIZE; i+ = species.length()){
05   FloatVector<Shapes.S256Bit> rv = species.fromArray (b, i);
06   FloatVector<Shapes.S256Bit> av = species.fromArray (a, i);
07   Vector.Mask<Float,Shapes.S256Bit> mask = av.greaterThan (tv);
08   rv.mul (av, mask).intoArray(c, i);
09 }
10  //后续处理  
11}



教程:编写own-vector算法



<Vector API:在Oracle Java中编写自矢量算法以提高性能>


白皮书提供了一些使用Vector API编写Java代码的技巧和窍门,并且还介绍了一些提高性能的方法。

这些示例应为您提供一些在Oracle Java *中进行矢量编程的准则和最佳实践,以帮助您成功地编写自己的计算密集型算法的矢量版本。

更多有关信息,请参见

PDF附件



教程:所有关于Vector API的知识

网址1 https://www.youtube.com/embed/jRyD1EIOOis?feature=oembed&enablejsapi=1

网址2 https://www.youtube.com/embed/videoseries?list=PLX8CzqL3ArzXJ2EGftrmz4SzS6NRr6p2n&enablejsapi=1



入门



构筑Vector API

本节假定用户熟悉基本的Linux实用程序。



将JDK8二进制文件设置为JAVA_HOME

Panama项目需要在系统上使用JDK8。可以从此位置

下载JDK

#export JAVA_HOME = / pathto / jdk1.8-u91

#export PATH = $ JAVA_HOME / bin:$ PATH



下载并编译Panama源码

可以使用商业资源控制管理工具下载Project Panama的源码。

# hg clone http://hg.openjdk.java.net/panama/panama/
# source get_source.sh
# ./configure
# make all



使用Panama JDK构建自己的应用程序

我们需要将vector.jar文件从包含Panama源的父文件目录中复制到Java应用程序的位置。

01import jdk.incubator.vector.IntVector;
02import jdk.incubator.vector.Shapes;
03import jdk.incubator.vector.Vector;
04 
05public class HelloVectorApi {
06    public static void main(String[] args) {
07        IntVector.IntSpecies<Shapes.S128Bit> species =
08                (IntVector.IntSpecies<Shapes.S128Bit>) Vector.speciesInstance(
09                        Integer.class, Shapes.S_128_BIT);
10        int val = 1;
11        IntVector<Shapes.S128Bit> hello = species.broadcast(val);
12        if (hello.sumAll() == val * species.length()) {
13            System.out.println("Hello Vector API!");
14        }
15    }
16}



运行你的应用程序

/pathto/panama/build/linux-x86_64-normal-server-release/images/jdk/bin/java –add-modules=jdk.incubator.vector -XX:TypeProfileLevel=121 HelloVectorApi



IDE配置



配置IntelliJ以进行OpenJDK Panama开发

1)创建一个新项目。如果是刚安装IntelliJ或没有打开过项目,则在出现的窗口中点击“Create New Project”(您可以在下面的窗口中看到)。

否则,File > New > Project… 也有相同的效果。

在这里插入图片描述

2)在出现的“New Project”窗口中,确保选择左侧的Java。选择Panama编译作为Project SDK。

如果尚未将Panama build设置为Project SDK,请按右侧的“New…”按钮。否则,请转到步骤4。

在这里插入图片描述

3)弹出的窗口叫做“Select Home Directory for JDK”。您要选择的路径是/ path / to / panama / build / linux-x86_64-normal-server-release / images / jdk。点击确定。



版权声明:本文为weixin_44774463原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。