我是 R 新手,但我想在 Rstudio 中使用 TensorFlow 理解和生成快速代码。我理解并行化的概念,但我在理解这些概念之间的差异时遇到了一些问题:并行化、向量化和张量化(对不起,我的英语)。我想要一些简单的例子来理解这些差异。我可以同时应用所有这些概念吗?
这是我在 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 中编码时,您将始终尝试为问题提出矢量化解决方案,而在其他语言中,您只需在其上应用循环循环顶部。