什么是“矢量化”?

时间:2009-09-14 15:07:13

标签: vectorization

现在好几次,我在matlab,fortran ......中遇到过这个术语......但是我从来没有找到解释是什么意思,它有什么作用?所以我在这里问,什么是矢量化,例如,“循环是否被矢量化”是什么意思?

7 个答案:

答案 0 :(得分:159)

许多CPU具有“向量”或“SIMD”指令集,它们同时对两个,四个或更多个数据应用相同的操作。现代x86芯片具有SSE指令,许多PPC芯片都有“Altivec”指令,甚至一些ARM芯片都有一个矢量指令集,称为NEON。

“矢量化”(简化)是重写循环的过程,这样它不是处理数组的单个元素N次,而是同时处理(比如说)数组的4个元素N / 4次。

(我选择了4,因为它是现代硬件最有可能直接支持的;术语“矢量化”也用于描述更高级别的软件转换,您可能只是完全抽象出循环而只是描述在数组上运行组成它们的元素)


矢量化和循环展开之间的区别: 考虑以下非常简单的循环,它添加两个数组的元素并将结果存储到第三个数组。

for (int i=0; i<16; ++i)
    C[i] = A[i] + B[i];

展开此循环会将其转换为以下内容:

for (int i=0; i<16; i+=4) {
    C[i]   = A[i]   + B[i];
    C[i+1] = A[i+1] + B[i+1];
    C[i+2] = A[i+2] + B[i+2];
    C[i+3] = A[i+3] + B[i+3];
}
另一方面,

向量化它会产生类似这样的东西:

for (int i=0; i<16; i+=4)
    addFourThingsAtOnceAndStoreResult(&C[i], &A[i], &B[i]);

其中“addFourThingsAtOnceAndStoreResult”是编译器用于指定向量指令的内在函数的占位符。请注意,某些编译器能够自动向量化非常简单的循环,这通常可以通过编译选项启用。更复杂的算法仍需要程序员的帮助才能生成良好的矢量代码。

答案 1 :(得分:27)

矢量化是将标量程序转换为矢量程序的术语。向量化程序可以从单个指令运行多个操作,而标量只能同时对一对操作数进行操作。

来自wikipedia

标量方法:

for (i = 0; i < 1024; i++)
{
   C[i] = A[i]*B[i];
}

矢量化方法:

for (i = 0; i < 1024; i+=4)
{
   C[i:i+3] = A[i:i+3]*B[i:i+3];
}

答案 2 :(得分:8)

它指的是能够在一个步骤中对数字列表(或“向量”)进行单个数学运算的能力。你经常在Fortran中看到它,因为它与科学计算有关,科学计算与超级计算有关,其中矢量化算法首次出现。如今,几乎所有台式机CPU都通过英特尔的SSE等技术提供某种形式的矢量化算法。 GPU还提供了一种矢量化算法。

答案 3 :(得分:6)

矢量化在科学计算中得到了极大的应用,需要高效处理大量数据。

在真正的编程应用程序中,我知道它在NUMPY中使用(不确定其他的)。

Numpy(python中的科学计算包),使用 vectorization 来快速操作n维数组,如果使用内置的python选项来处理数组,这通常会更慢。

尽管有很多解释,但 VECTORIZATION NUMPY DOCUMENTATION PAGE

Vectorization描述了代码中没有任何显式循环,索引等 - 这些事情当然只是在优化的,预编译的C代码中“幕后”。矢量化代码有许多优点,其中包括:

  1. 矢量化代码更简洁,更易于阅读

  2. 更少的代码行通常意味着更少的错误

  3. 代码更接近于标准数学符号 (通常,更容易正确编码数学 构建体)

  4. 矢量化导致更多“Pythonic”代码。没有 矢量化,我们的代码将被低效率和 难以阅读循环。

答案 4 :(得分:3)

我认为很容易掌握Intel的人。

向量化是将算法从运算转换为运算的过程 一次处理一个值,一次处理一组值 时间 。现代CPU直接支持矢量运算,其中 一条指令应用于多个数据(SIMD)。

例如,具有512位寄存器的CPU可以容纳16个32位 单精度加倍并进行一次计算。

比一次执行一条指令快16倍。结合 线程和多核CPU导致数量级增加 性能提升。

链接https://software.intel.com/en-us/articles/vectorization-a-key-tool-to-improve-performance-on-modern-cpus

在Java中,可以选择将此选项包含在2020年的Jdk 15中或2021年的JDK 16中。

https://bugs.openjdk.java.net/browse/JDK-8201271

Vector api是第一个在JDK 16中提出的JEP。 Proposed to target

https://bugs.openjdk.java.net/secure/Dashboard.jspa?selectPageId=19517

答案 5 :(得分:2)

简单来说,向量化意味着优化算法,以便它可以在处理器中利用SIMD指令。

AVX,AVX2和AVX512是在一条指令中对多个数据执行相同操作的指令集(英特尔)。例如AVX512意味着您一次可以处理16个整数(4个字节)。这意味着如果您有16个整数的向量,并且想将每个整数的值加倍,然后再加上10。您可以将值加载到通用寄存器[a,b,c]上16次并执行相同的操作,也可以通过将所有16个值加载到SIMD寄存器[xmm,ymm]上并执行一次来执行相同的操作。这样可以加快矢量数据的计算速度。

在矢量化中,我们通过重塑数据来利用它,以发挥其优势,以便我们可以对其执行SIMD操作并加快程序速度。

向量化的唯一问题是处理条件。因为条件分支了执行流程。这可以通过掩膜来处理。通过将条件建模为算术运算。例如。如果我们想将值加10,如果该值大于100,则可以。

if(x[i] > 100) x[i] += 10; // this will branch execution flow.

或者我们可以将条件建模为算术运算,从而创建条件向量c

c[i] = x[i] > 100; // storing the condition on masking vector
x[i] = x[i] + (c[i] & 10) // using mask

这是一个非常琐碎的示例……因此,c是我们的屏蔽向量,我们根据其值执行二进制运算。这样可以避免执行流分支,并可以向量化。

向量化与并行化一样重要。因此,我们应该尽可能地利用它。所有现代处理器都具有适用于繁重计算工作负载的SIMD指令。我们可以通过向量化来优化代码以使用这些SIMD指令,这类似于并行化代码以在现代处理器上可用的多个内核上运行。

我想谈谈OpenMP,它可以让您使用编译指示对代码进行矢量化处理。我认为这是一个很好的起点。对于OpenACC也可以这样说。

答案 6 :(得分:-3)

见上面的两个答案。我只是想补充一点,想要进行矢量化的原因是这些操作可以很容易地通过超级计算机和多处理器在paraell中执行,从而产生很大的性能提升。在单处理器计算机上,没有性能提升。