gpt4 book ai didi

r - 在不同的上下文中, "vectorization"一词是否意味着不同的事物?

转载 作者:行者123 更新时间:2023-12-04 12:08:10 24 4
gpt4 key购买 nike

根据我之前阅读的内容,矢量化是一种并行化形式,称为SIMD。它允许处理器在阵列上同时执行相同的指令(例如加法)。

但是,在阅读The Relationship between Vectorized and Devectorized Code时,我对Julia和R的矢量化性能感到困惑。该帖子声称经过向量化的Julia代码(通过循环)比在Julia和R中的向量化代码更快,因为:

This confuses some people who are not familiar with the internals of R. It is therefore worth noting how one improves the speed of R code. The process of performance improvement is quite simple: one starts with devectorized R code, then replaces it with vectorized R code and then finally implements this vectorized R code in devectorized C code. This last step is unfortunately invisible to many R users, who therefore think of vectorization per se as a mechanism for increasing performance. Vectorization per se does not help make code faster. What makes vectorization in R effective is that it provides a mechanism for moving computations into C, where a hidden layer of devectorization can do its magic.



它声称R将用R编写的矢量化代码转换为C中的去矢量化代码。如果矢量化更快(作为并行化的一种形式),为什么R会对代码进行去矢量化,为什么加号呢?

最佳答案

R中的“向量化”是R解释器认为的向量处理。以cumsum函数为例。进入时,R解释器看到将向量x传递到此函数中。但是,该工作随后传递给R解释器无法分析/跟踪的C语言。 C在工作时,R在等待。在R的解释器恢复工作时,已经处理了向量。因此,在R看来,它发出了一条指令,但处理了一个向量。这类似于SIMD的概念-“单个指令,多个数据”。

在R中,不仅接受向量并返回向量的cumsum函数被视为“向量化”,接受向量并返回标量的sum之类的函数也被称为“向量化”。

简而言之:每当R为循环调用某些已编译的代码时,它就是“向量化”。如果您想知道为什么这种“向量化”有用,那是因为用编译语言编写的循环比用解释语言编写的循环要快。 C循环被翻译成CPU可以理解的机器语言。但是,如果CPU要执行R循环,则需要R的解释器的帮助来逐次读取。这就好比,如果您会说中文(最难的人类语言),则可以更快地回应说中文的人。否则,您需要翻译人员先用英语在句子中翻译中文,然后再用英语回答,然后翻译人员逐句将其翻译回中文。沟通的效率大大降低。

x <- runif(1e+7)

## R loop
system.time({
sumx <- 0
for (x0 in x) sumx <- sumx + x0
sumx
})
# user system elapsed
# 1.388 0.000 1.347

## C loop
system.time(sum(x))
# user system elapsed
# 0.032 0.000 0.030

请注意,R中的“向量化”只是SIMD的 类比,而不是实际的。真正的SIMD使用CPU的向量寄存器进行计算,因此是通过数据并行性进行的真正的并行计算。 R不是可以编程CPU寄存器的语言;为此,您必须编写编译后的代码或汇编代码。

R的“向量化”并不关心如何真正执行以编译语言编写的循环。毕竟这是R口译员所不具备的。关于是否将使用SIMD执行这些编译后的代码,请阅读 Does R leverage SIMD when doing vectorized calculations?

有关R 中“矢量化”的更多信息

我不是Julia用户,但 Bogumił Kamiński演示了该语言的一个令人印象深刻的功能:循环融合。 Julia可以做到这一点,因为正如他指出的那样,“Julia中的矢量化是在Julia中实现的”,而不是在语言之外。

这揭示了R的向量化的缺点:速度通常是以内存使用为代价的。我并不是说Julia不会遇到这个问题(因为我不使用它,我也不知道),但是对于R来说绝对是正确的。

这是一个示例: Fastest way to compute row-wise dot products between two skinny tall matrices in RrowSums(A * B)是R中的“向量化”,因为 "*"rowSums均以C语言编码为一个循环。但是,R无法将它们融合到单个C循环中,以避免将临时矩阵 C = A * B生成到RAM中。

另一个示例是R的回收规则或任何依赖该规则的计算。例如,当您通过 a将标量 A添加到矩阵 A + a时,实际发生的是,首先将 a复制为与 B具有相同维数的矩阵 A,即 B <- matrix(a, nrow(A), ncol(A)),然后计算两个矩阵之间的加法: A + B显然,不希望生成临时矩阵 B,但是遗憾的是,除非您为 A + a编写自己的C函数并在R中调用它,否则您无法做得更好。这被描述为“只有在明确实现的情况下,这种融合才可能“在 Bogumił Kamiński's answer中。

为了处理许多临时结果的内存效应,R具有称为“垃圾收集”的复杂机制。它有帮助,但是如果您在代码中的某个地方生成了一些非常大的临时结果,则内存仍然会爆炸。函数 outer是一个很好的例子。我已经使用此功能编写了许多答案,但是它特别不便于内存。

当我开始讨论“向量化”的副作用时,我可能在本次编辑中脱节。小心使用。
  • 记住内存使用情况;可能会有一种内存效率更高的矢量化实现。例如,如在两个矩阵之间的按行点积的链接线程中所述,c(crossprod(x, y))sum(x * y)更好。
  • 准备使用已编译代码的CRAN R软件包。如果在R中发现现有的矢量化函数只能完成您的任务,请在CRAN中寻找可能的R软件包来完成此任务。您可以在Stack Overflow上遇到编码瓶颈的问题,有人可能会在正确的包中指出您正确的功能。
  • 很高兴编写自己的编译代码。
  • 关于r - 在不同的上下文中, "vectorization"一词是否意味着不同的事物?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51681978/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com