Day719. 矢量运算 -Java8后最重要新特性

Posted 阿昌喜欢吃黄桃

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day719. 矢量运算 -Java8后最重要新特性相关的知识,希望对你有一定的参考价值。

矢量运算

Hi,阿昌来也,今天学习记录的是关于此时此刻还在预览阶段的矢量运算

Java 的矢量运算,我写这篇文章的时候还在孵化期,还没有发布预览版

这个技术代表了 Java 语言发展的一个重要方向,在未来一定会有着重要的影响。

早一点了解这样的技术,除了扩展视野之外,还能够帮助制定未来几年要学习或者要使用的技术路线。

然后,再看看矢量运算能够带来什么样的变化。

一、阅读案例

线性方程(或者说一次方程)一定不陌生。

一般情况下,我们可以把线性方程表述成下面的形式。

其中 a0​,a1​,an−1​ 表示的是常数,x0​,x1​,xn−1​ 表示的是变量,而 y 就表示 ai​ 和 xi​ 的组合结果。n 表示未知变量的数目,通常,把它称为方程的维度。

如果给定方程式右边的常数和变量,我们就能计算出方程式左边的 y 数值了。

那么,该怎么用代码表示这个方程式呢?

可以把 a0​,a1​,an−1​ 表示的常数放到一个数组里,把 x0​,x1​,xn−1​ 表示的变量放到另外一个数组里。

下面的代码里,变量 a 和 x 就可以用来表示一个有四个维度的一次方程组。

static final float[] a = new float[] 0.6F, 0.7F, 0.8F, 0.9F;
static final float[] x = new float[] 1.0F, 2.0F, 3.0F, 4.0F;

能用 Java 的变量来表示一次方程,能够计算线性方程的结果了。

下面的代码,就是一个实现的办法。

private static Returned<Float> sumInScalar(float[] a, float[] x) 
    if (a == null || x == null || a.length != x.length) 
        return new Returned.ErrorCode(-1);
    
    float[] y = new float[a.length];
    for (int i = 0; i < a.length; i++) 
        y[i] = a[i] * x[i];
    
    float r = 0F;
    for (int i = 0; i < y.length; i++) 
        r += y[i];
    
    return new Returned.ReturnValue<>(r);

在上面的代码里,先计算 ai​ 和 xi​ 的乘积,然后再计算乘积结果的总和。

其中的乘法运算,就是常说的标量运算

为了方便讨论,把乘法运算的代码单独拿出来,粘贴在下面。

float[] y = new float[a.length];
for (int i = 0; i < a.length; i++) 
    y[i] = a[i] * x[i];

仔细观察线性方程就会发现,对于每一个纬度,ai​ 和 xi​ 是互不影响的, 当然它们的乘积也是互不影响的。

既然每个维度的计算都互不影响,那么能不能并行计算呢?

二、矢量运算

Java 的矢量运算就是使用单个指令并行处理多个数据的一个尝试(单指令多数据,Single Instruction Multiple Data)。

在现代的微处理器(CPU)中,一个控制器可以控制多个平行的处理单元;

在现代的图形处理器(GPU)中呢,更是拥有强大的并发处理能力和可编程流水线。这些处理器层面的技术,为软件层面的单指令多数据处理提供了物理支持。

Java 矢量运算的设计和实现,也是希望能够借助现代处理器的这种能力,提高运算的性能。

为了使用单指令多数据的指令,需要把不同数据的运算独立出来,让并行运算成为可能。

而数学里的矢量运算,恰好就能满足这样的要求。

如果使用矢量,可以把线性方程表述成下面的形式(使用向量的数量积形式):

其中,a,x 和 y′ 是三个 n 维的矢量。

好了,现在看看 Java 是怎么表达矢量的了。

下面代码里的变量 a,和前面阅读案例里 a 是一样的,它以数组的形式表示;

变量 va,就是变量 a 的矢量表达形式。

fromArray 这个方法,可以把一个数组变量,转换成一个矢量的变量。

static final float[] a = new float[] 0.6F, 0.7F, 0.8F, 0.9F;
static final FloatVector va =
        FloatVector.fromArray(FloatVector.SPECIES_128, a, 0);
        
static final float[] x = new float[] 1.0F, 2.0F, 3.0F, 4.0F;
static final FloatVector vx =
        FloatVector.fromArray(FloatVector.SPECIES_128, x, 0);

有了表示矢量的办法,试着使用矢量运算的办法,来计算线性方程的结果了。

下面的代码,就是一个简化了的实现。

private static Returned<Float> sumInVector(FloatVector va, FloatVector vx) 
    if (va == null || vx == null || va.length() != vx.length()) 
        return new Returned.ErrorCode(-1);
    
    
    // FloatVector vy = va.mul(vx);
    float[] y = va.mul(vx).toArray();
    
    float r = 0F;
    for (int i = 0; i < y.length; i++) 
        r += y[i];
    
    return new Returned.ReturnValue<>(r);

这个运算的关键部分是其中的矢量运算,也就是下面这行代码。

FloatVector vy = va.mul(vx);

和上面的标量运算的办法相比,矢量运算的代码精简了很多。

这是矢量运算的第一个优点。但优点还不止于此。

三、飙升的性能

Java 矢量运算的设计,主要是为了性能

那么,性能的提升能有多大呢?

做了一个性能测试。虽然这个特性还处于孵化期,但是性能测试结果还是很令人振奋的。

就上面这个简单的、四维的矢量来说,和在阅读案例里使用的标量运算相比,矢量运算的性能提高了足足有 10 倍。

Benchmark                       Mode  Cnt           Score           Error  Units
VectorBench.scalarComputation  thrpt   15   180635563.597 ±  30893274.582  ops/s
VectorBench.vectorComputation  thrpt   15  1839556188.443 ± 153876900.442  ops/s

对于一个还处于孵化阶段的实现来说,这么大的性能提升是有点超出预料的。

密码学机器学习领域,通常需要处理几百甚至几千维的数据。

一般情况下,为了能够使用处理器的计算优势,经常需要特殊的设计以及内嵌于 JVM 的本地代码来获得硬件加速。

这样的限制,让普通代码的计算很难获得硬件加速的好处。

希望成熟后的 Java 矢量运算,能在这些领域有出色的表现,让普通的代码获得处理器的单指令多数据的强大运算能力。

毕竟,只有单指令多数据的优势能够被普通的 Java 应用程序广泛使用,Java 才能在机器学习、科学计算这些领域获得计算优势。

如果从机器学习在未来的重要性来说,Java 在科学计算领域的拓展来得也许正是时候。

四、总结

Java 的矢量运算这个尚处于孵化阶段的新特性,对 Java 的矢量运算这个新特性有了一个初始的印象。

如果 Java 矢量运算成熟起来,许多领域都可以从这个新特性中受益,包括但是不限于机器学习、线性代数、密码学、金融和 JDK 本身的代码。这一次学习的主要目的,就是让你对矢量运算有一个基本的印象。

这样的话,如果代码里有大量的数值计算,也许可以考虑在将来使用矢量运算获得硬件的并行计算能力,大幅度提高代码的性能

由于矢量运算尚处于孵化阶段,目前还不需要学习它的 API,知道 Java 有这个发展方向,并且能够思考你的代码潜在的改进空间就足够了。

知道了这个方向,等 Java 矢量运算正式发布的时候,你就可以尽早地改进你的代码,从而获得领先的优势了。

如果面试中聊到了数值计算的性能,你应该知道有矢量运算这么一个潜在的方向,以及“单指令多数据”这么一个术语。

以上是关于Day719. 矢量运算 -Java8后最重要新特性的主要内容,如果未能解决你的问题,请参考以下文章

模运算矢量化

矢量容器的运算符 [] - 返回参考?

矢量运算_向量积

在访问该类的函数时,如何在我的类的 2D 矢量上使用点运算符?

Python TVTK 标量数据可视化与矢量数据可视化

矢量叉乘,向量外积