关于 R 中矢量化和并行化的一般问题

vri*_*ige 1 r tensorflow

我是 R 新手,但我想在 Rstudio 中使用 TensorFlow 理解和生成快速代码。我理解并行化的概念,但我在理解这些概念之间的差异时遇到了一些问题:并行化、向量化和张量化(对不起,我的英语)。我想要一些简单的例子来理解这些差异。我可以同时应用所有这些概念吗?

nik*_*iko 5

这是我在 R 中的并行化和向量化的两分钱。我不会讨论张量化,因为我对 TensorFlow 没有太多经验。然而,有微分几何背景,我最好的猜测是这意味着使用张量,即高维(数据)结构,来解决某些问题。

并行化

并行化的基本思想是同时运行任务。很多时候,尤其是在 R 中实现时,这个概念是通过处理处理的:通常这会将任务分配给计算机的 CPU(或线程查看多线程或检查这个很好的SO 答案)。此外,并行化可以被视为处理并发的一种方式:后者虽然有其他实现,例如异步编程

并行化(以及并发)的典型示例如下:假设您有一个 URL 列表,url1, url2, ...并且您需要向其中的每一个发送 GET 请求(并等待响应)。经典的(同步)方式是遍历所有 URL,发出 GET 请求,等待响应,然后(并且只有这样)继续处理下一个 URL。

# Dummy example list
urls <- rep('http://example.com', 7)
# Fetching the data
results <- rep(list(NA), length(urls))
for (k in seq_along(urls))
  results[[k]] <- httr::GET(urls[k])
Run Code Online (Sandbox Code Playgroud)

这是一个经典示例的原因是(通常)这些请求是相互独立的:理论上,我们不必等待第一个响应,然后再发出第二个请求。所以我们可以同时发送这些请求:

# Parallel
urls <- rep('http://example.com', 7)
num_cores <- parallel::detectCores() - 1
cl <- parallel::makeCluster(num_cores)
parallel::clusterEvalQ(cl, library(httr))
parallel::clusterExport(cl, varlist = c('urls'))
results <- parallel::parLapply(cl, urls, httr::GET)
parallel::stopCluster(cl)
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,大多数行都是关于设置的,但关键的行是倒数第二行:这是我们在可用的不同内核 (CPU) 之间分配和执行任务的地方。

本质上,并行化与任务时间密切相关。

矢量化

这个话题要简单得多。语言 R 天生就针对向量化操作进行了优化:向量、矩阵和数组是 R 中的内置函数 - 任何语言都不是这种情况。

此外,操作和函数也被向量化:例如,R 支持向量的除法,1:5 / 11:15并且大部分行为都符合人们的预期(典型的陷阱有很好的文档记录,例如1:5 + 11:20)。例如,Python 将列表作为内置函数,但(本质上)不支持向量化:类似的东西range(5) / range(11, 15)会抛出错误(是的,有些库可以使这变得可行)。

但这不是黑魔法:当paste0("url_", 1:5)循环发生在低级语言中时C,这使得它比在 R 中循环快几个数量级。这也是为什么循环在 R 中往往名声不佳(尽管正确的循环绝对没问题) . 这是一个非常幼稚的说明

microbenchmark::microbenchmark(
  loop = {
    v1 <- 1:5; v2 <- 6:10
    result <- rep(NA, length(v1))
    for (k in seq_along(v1))
      result[k] <- v1[k] + v2[k]
  },
  vectorization = {
    result <- 1:5 + 6:10
  }
)
# Unit: nanoseconds
#          expr     min      lq       mean  median      uq     max neval cld
#          loop 1367900 1377052 1431076.98 1396951 1407551 4317901   100   b
# vectorization     400     501    1145.95    1500    1601    4001   100  a 
Run Code Online (Sandbox Code Playgroud)

这里的底线是矢量化(主要是)R 中的每个角落,在我看来,这是 R 优雅的本质和最美丽的功能(自定义运算符也非常简洁)。例如,可以使用单行创建 sin 的泰勒展开式:

f <- function(x, n = 10) sum((-1)^(0:n) * x^(2*(0:n) + 1) / factorial((2*(0:n) + 1)))
f(0)
# 0
f(pi)
# 1.034819e-11
Run Code Online (Sandbox Code Playgroud)

最后,除了美学之外,R 的矢量化是一种哲学,是一种解决问题的方法:给定特定任务,在 R 中编码时,您将始终尝试为问题提出矢量化解决方案,而在其他语言中,您只需在其上应用循环循环顶部。