现在,我已经在matlab, fortran中遇到过几次这个术语…其他的…但我从来没有找到一个解释,它是什么意思,它是什么?所以我在这里问,什么是向量化,例如,“一个循环是向量化的”是什么意思?
它指的是在一个步骤中对一个数字列表(或“向量”)进行单一数学运算的能力。你经常在Fortran中看到它,因为它与科学计算有关,而科学计算又与超级计算有关,向量化算术就是在那里首次出现的。如今,几乎所有的桌面cpu都提供某种形式的向量化算法,比如通过英特尔的SSE等技术。gpu还提供了一种向量化算法。
许多cpu都有“vector”;或“;SIMD"同时对两个、四个或多个数据应用相同操作的指令集。现代x86芯片有SSE指令,许多PPC芯片有“altivec”指令;指令,甚至一些ARM芯片也有一个矢量指令集,叫做NEON。
“Vectorization"(简化)是重写循环的过程,这样它就不是处理数组中的单个元素N次,而是同时处理(比如说)数组中的4个元素N/4次。
我选择4是因为它是现代硬件最可能直接支持的32位浮点数或整型数。
向量化和循环展开的区别: 考虑以下非常简单的循环,它添加了两个数组的元素,并将结果存储到第三个数组中
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"是一个占位符,表示编译器用于指定向量指令的任何固有值。
请注意,大多数现代提前编译器都能够汽车vectorize像这样非常简单的循环,这通常可以通过compile选项启用(在现代C和c++编译器中,默认情况下是完全优化的,如gcc -O3 -march=native)。OpenMP #pragma omp simd有时有助于提示编译器,特别是对于“reduce”;循环,比如对FP数组求和,其中向量化要求假设FP数学是关联的。
gcc -O3 -march=native
#pragma omp simd
更复杂的算法仍然需要程序员的帮助来生成良好的矢量代码;我们称其为手册向量化,通常使用像x86 _mm_add_ps这样的intrinsic,映射到Intel cpu上的SIMD前缀和或如何计数字符出现使用SIMD中的单个机器指令。或者甚至使用SIMD来解决短的非循环问题,如最疯狂的最快的方法将9字符数字转换为int或unsigned int或如何将二进制整数转换为十六进制字符串?
_mm_add_ps
术语“矢量化”;也会用到来描述一个更高层次的软件转换,在这里你可以完全抽象掉循环,只描述操作数组而不是组成数组的元素。例如,用某种语言写C = A + B,当它们是数组或矩阵时,不像C或c++。在这样的低级语言中,您可以将调用BLAS或Eigen库函数描述为一种向量化编程风格,而不是手动编写循环。关于这个问题的其他一些答案集中在向量化的含义和更高级的语言上。
C = A + B
请看上面的两个答案。我只是想补充一下,想要做向量化的原因是,这些操作可以很容易地由超级计算机和多处理器并行执行,从而产生巨大的性能增益。在单处理器计算机上不会有性能提升。
向量化是将标量程序转换为矢量程序的术语。向量化程序可以从一条指令运行多个操作,而标量程序一次只能对操作数对进行操作。
从维基百科:
标量的方法:
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]; }
向量化在科学计算中被广泛使用,在科学计算中需要有效地处理大量数据。
在真正的编程应用中,我知道它在NUMPY中使用(不确定其他)。
Numpy (python中用于科学计算的包)使用向量化来快速操作n维数组,如果使用内置的python选项来处理数组,通常会较慢。
尽管有大量的解释,下面是向量化在Numpy文档页中的定义
向量化描述了代码中没有任何显式的循环、索引等——当然,这些事情只是在优化的、预编译的C代码的“幕后”发生。向量化代码有很多优点,其中包括:
向量化的代码更简洁,更易于阅读
更少的代码行通常意味着更少的错误
代码更接近于标准的数学符号 (这使得正确编写数学代码更容易 李构造)< / p > < / >
向量化会产生更多的“python”代码。没有 向量化,我们的代码就会充斥着低效的和
简而言之,矢量化意味着优化算法,使其能够利用处理器中的SIMD指令。
AVX, AVX2和AVX512是在一条指令中对多个数据执行相同操作的指令集(intel)。如。AVX512意味着您可以一次操作16个整数值(4字节)。这意味着如果你有一个16个整数的向量你想让每个整数的值都翻倍然后再加上10。您可以将值加载到通用寄存器[a,b,c] 16次并执行相同的操作,也可以将所有16个值加载到SIMD寄存器[xmm,ymm]并执行相同的操作,并执行一次操作。这样可以加快矢量数据的计算速度。
在向量化中,我们利用了这一点,通过重构数据,我们可以对其执行SIMD操作,并加快程序的速度。
矢量化的唯一问题是处理条件。因为条件分支了执行流。这可以通过屏蔽来处理。通过将条件建模成算术运算。如。如果我们想在value上加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,它允许你使用pragmas向量化代码。我认为这是一个很好的起点。OpenACC也是如此。
由英特尔人我想是很容易把握的。
矢量化是将算法从操作转换为运算的过程 对单个值一次操作到对一组值一次操作 时间< /强> < / em >。现代cpu直接支持向量操作 .一个指令应用于多个数据(SIMD) 例如,一个512位寄存器的CPU可以存储16个32位寄存器 单精度加倍,做单次计算 比一次执行单个指令快16倍。结合 这与线程和多核cpu一起导致了数量级 性能改善。< / p >
矢量化是将算法从操作转换为运算的过程 对单个值一次操作到对一组值一次操作 时间< /强> < / em >。现代cpu直接支持向量操作
比一次执行单个指令快16倍。结合 这与线程和多核cpu一起导致了数量级 性能改善。< / p >
链接https://software.intel.com/en-us/articles/vectorization-a-key-tool-to-improve-performance-on-modern-cpus
在Java中,有一个选项可以包含在2020年的JDK 15或2021年的JDK 16中。请看这个官方的问题。
希望你一切都好!
向量化指的是所有将标量实现(即单个操作一次处理单个实体)转换为向量实现(即单个操作同时处理多个实体)的技术。
矢量化指的是一种技术,在这种技术的帮助下,我们优化代码以有效地处理大量数据。在NumPy、pandas等科学应用中看到的向量化应用,你也可以在Matlab、图像处理、NLP等工作时使用这种技术。总的来说,它优化了程序的运行时和内存分配。
希望你能得到你的答案!
谢谢你!🙂
我会将矢量化定义为给定语言的一个特性,其中如何遍历某个集合的元素的责任可以从程序员委托给该语言提供的一些方法(例如显式循环元素)。
我们为什么要这么做呢?
注意,对于第3点和第4点,一些语言(特别是Julia)允许这些硬件并行也使用程序员定义的顺序处理(例如for循环),但这是自动发生的,在使用语言提供的向量化方法时。
for
现在,虽然向量化有许多优点,但有时算法使用显式循环比向量化更直观地表达(可能我们需要求助于复杂的线性代数运算、单位和对角矩阵……保留我们的“矢量化”;方法),如果使用显式排序形式没有计算上的缺点,则应该首选这种形式。