crossprod(m1, m2) 在我的机器上运行速度比 t(m1) %*% m2 慢

问题描述 投票:0回答:2

为什么

t(mat1) %*% mat2
crossprod(mat1, mat2)
工作得更快。后者的全部意义不就是它调用了更高效的低级例程吗?

r$> mat1 <- array(rnorm(100 * 600), dim = c(100, 600))

r$> mat2 <- array(rnorm(100 * 800), dim = c(100, 800))

r$> microbenchmark::microbenchmark(crossprod(mat1, mat2), t(mat1) %*% mat2)
Unit: milliseconds
                  expr     min       lq     mean   median       uq     max neval
 crossprod(mat1, mat2) 37.1905 44.35975 48.49262 47.61035 50.99725 76.1250   100
      t(mat1) %*% mat2 25.0813 31.68405 35.46811 35.18380 39.16565 49.8131   100

继续奔跑

r$> version
               _
platform       x86_64-w64-mingw32
arch           x86_64
os             mingw32
crt            ucrt
system         x86_64, mingw32
status
major          4
minor          4.1
year           2024
month          06
day            14
svn rev        86737
language       R
version.string R version 4.4.1 (2024-06-14 ucrt)
nickname       Race for Your Life

编辑:本地机器环境

r$> sessionInfo()
R version 4.4.1 (2024-06-14 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 22631)

Matrix products: default

r$> Sys.getenv("R_BLAS_LIBS")
    Sys.getenv("R_LAPACK_LIBS")

[1] ""
[1] ""

r$> getOption("matprod")
[1] "default"

r$> extSoftVersion()
                     zlib                     bzlib                        xz 
                  "1.3.1"      "1.0.8, 13-Jul-2019"                   "5.4.6" 
               libdeflate                      PCRE                       ICU 
                   "1.19"        "10.43 2024-02-16"                    "74.2" 
                      TRE                     iconv                  readline 
"TRE 0.8.0 R_fixes (BSD)"               "win_iconv"                        "" 
                     BLAS 
                       "" 
r performance matrix-multiplication blas
2个回答
2
投票

这不是答案,但评论太长了:

crossprod
和简单矩阵乘法都可以执行简单的强力三重循环,使用适当的参数调用BLAS例程
gemm
[“通用矩阵-矩阵(乘法)”],具体取决于(1)R如何已配置以及 (2) 参数中是否有任何
NA
值。因此,鉴于
t(x) %*% y
必然涉及分配空间来保存转置矩阵和进行值的实际转置的中间步骤,人们会期望
t(x) %*% y
crossprod
都会使用 BLAS,或者都不使用 BLAS ,因此
crossprod
永远不会比转置+矩阵乘法;但是,如果转置步骤相对于乘法中涉及的所有浮点运算非常快,则差异可能会在噪声中丢失。

随着矩阵变大,进行转置的成本(

O(n^2)
,不计算分配时间)相对于乘法的成本会缩小(
O(n^3)
,如果是愚蠢的,看起来BLAS使用Strassen的算法,这是有道理的
O(n^2.8)
),因此
crossprod
的优势应该会缩小。 (此外,转置只需移动内容/分配值,而矩阵乘法必须执行实际算术,因此矩阵乘法应该具有更大的常数/更昂贵,所有其他条件都相同)。评论中@ThomasIsCoding 链接的博客文章指出了这种模式。但这仍然不能解释为什么 crossprod
 应该做 
更糟 ...

如果你想深入研究代码,你可以找到例如

R_xlen_t NRX = nrx, NRY = nry, NCX = ncx; for (int i = 0; i < ncx; i++) for (int k = 0; k < ncy; k++) { sum = 0.0; for (int j = 0; j < nrx; j++) sum += x[j + i * NRX] * y[j + k * NRY]; z[i + k * NCX] = (double) sum; }

  • 类似的矩阵乘法简单循环
  • 决定是否对mmult使用BLAS的逻辑(crossprod
    有类似的逻辑)。
注意相关问题

herehere,但似乎都没有解释这种模式;后者(比我比较转置和乘法成本做得更好)解释了为什么在某些情况下 t(x) %*% y

 可能会更快 
y
 包含大量零时
- 不是这里的情况......


0
投票

评论也太长了:

由于我使用

flexiblas,我能够相对轻松地进行跨 BLAS 基准测试。

矩阵 m1、m2 是随着

缩放因子 的增加而创建的,m1

 是通过 dim = [100, 6*
fac] 创建的, m2
 是用 dim = [100, 8*
fac] 创建的, 其中大小因子 fac = [1, 8, 64, 512]。

使用 NETLIB,

t(mat1) %*% mat2

 明显快于 
crossprod(mat1, mat2)
(fac=64;d=15.959;p
crossprod()<0.0001). In contrast, for all other BLAS libraries,
 始终优于 
t(mat1) %*% mat2
,其中 OPENBLAS-SERIAL 显示出最快的性能(fac=64;d=-0.460) ;
<0.0001) among single-threaded BLAS libraries compared to NETLIB. Notably, OPENBLAS-OPENMP, being multi-threaded, showed minimal difference between the two operations (fac=64; d=-0.145; p=0.3206).

结论:

结果表明 NETLIB 处理 crossprod() 的效率可能较低。总体而言,内部效应规模减小,这支持了

@Ben Bolker
'对换位成本的机械解释。 在下面的结果表中,

wth

指的是BLAS内,btw指BLAS与NETLIB之间的BLAS作为参考BLAS。 d 指 Cohen'd d,p 指 p 值。使用 microbenchmark() 执行基准测试,每种配置重复 100 次。

缩放因子1

library expr fct mean_time median_time sd_time p_wth d_wth p_btw d_btw NETLIBv3.9.0* crossprod(m1, m2) 1 0.008 0.008 0.001 1.430e-08 -0.616 NA NA NETLIBv3.9.0* t(m1) %*% m2 1 0.011 0.011 0.006 1.430e-08 -0.616 NA NA ATLASv3.10.3 crossprod(m1, m2) 1 0.005 0.005 0.001 8.934e-13 -0.148 1.550e-57 -3.382 ATLASv3.10.3 t(m1) %*% m2 1 0.011 0.010 0.008 8.934e-13 -0.148 4.034e-01 -0.006 BLISv0.9.0 crossprod(m1, m2) 1 0.011 0.011 0.001 4.456e-03 -0.215 4.203e-77 6.260 BLISv0.9.0 t(m1) %*% m2 1 0.021 0.017 0.032 4.456e-03 -0.215 7.246e-04 0.020 OPENBLASv0.3.21-OPENMP crossprod(m1, m2) 1 0.004 0.004 0.001 6.543e-10 -0.351 5.952e-70 -4.883 OPENBLASv0.3.21-OPENMP t(m1) %*% m2 1 0.010 0.009 0.010 6.543e-10 -0.351 9.297e-03 -0.042 OPENBLASv0.3.21-SERIAL crossprod(m1, m2) 1 0.004 0.004 0.001 1.850e-09 -0.164 1.577e-71 -4.749 OPENBLASv0.3.21-SERIAL t(m1) %*% m2 1 0.011 0.009 0.011 1.850e-09 -0.164 1.557e-01 -0.019

缩放系数8

library expr fct mean_time median_time sd_time p_wth d_wth p_btw d_btw NETLIBv3.9.0* crossprod(m1, m2) 8 0.437 0.420 0.079 9.181e-22 1.464 NA NA NETLIBv3.9.0* t(m1) %*% m2 8 0.332 0.324 0.063 9.181e-22 1.464 NA NA ATLASv3.10.3 crossprod(m1, m2) 8 0.142 0.142 0.009 6.875e-47 -3.022 1.083e-60 -4.984 ATLASv3.10.3 t(m1) %*% m2 8 0.171 0.173 0.010 6.875e-47 -3.022 1.872e-46 -3.210 BLISv0.9.0 crossprod(m1, m2) 8 0.071 0.066 0.039 1.535e-10 -0.946 2.060e-65 -5.887 BLISv0.9.0 t(m1) %*% m2 8 0.099 0.099 0.015 1.535e-10 -0.946 1.614e-60 -4.769 OPENBLASv0.3.21-OPENMP crossprod(m1, m2) 8 0.088 0.072 0.167 2.691e-01 -0.129 2.640e-35 -2.665 OPENBLASv0.3.21-OPENMP t(m1) %*% m2 8 0.106 0.107 0.022 2.691e-01 -0.129 1.186e-57 -4.709 OPENBLASv0.3.21-SERIAL crossprod(m1, m2) 8 0.054 0.053 0.012 2.108e-40 -2.472 1.146e-71 -6.384 OPENBLASv0.3.21-SERIAL t(m1) %*% m2 8 0.082 0.085 0.011 2.108e-40 -2.472 7.725e-64 -4.982

缩放因子64

library expr fct mean_time median_time sd_time p_wth d_wth p_btw d_btw NETLIBv3.9.0* crossprod(m1, m2) 64 26.041 25.967 0.412 5.163e-104 15.959 NA NA NETLIBv3.9.0* t(m1) %*% m2 64 15.590 15.529 0.841 5.163e-104 15.959 NA NA ATLASv3.10.3 crossprod(m1, m2) 64 7.569 7.443 0.283 8.863e-05 -0.511 3.913e-182 -48.035 ATLASv3.10.3 t(m1) %*% m2 64 7.755 7.587 0.422 8.863e-05 -0.511 7.258e-98 -11.433 BLISv0.9.0 crossprod(m1, m2) 64 2.258 2.073 0.347 4.938e-10 -0.743 1.732e-195 -60.983 BLISv0.9.0 t(m1) %*% m2 64 2.552 2.366 0.433 4.938e-10 -0.743 1.217e-119 -18.932 OPENBLASv0.3.21-OPENMP crossprod(m1, m2) 64 1.421 0.836 1.063 2.079e-01 -0.145 4.644e-148 -22.831 OPENBLASv0.3.21-OPENMP t(m1) %*% m2 64 1.658 1.012 1.948 2.079e-01 -0.145 4.666e-84 -9.233 OPENBLASv0.3.21-SERIAL crossprod(m1, m2) 64 2.168 2.050 0.277 1.798e-04 -0.460 5.601e-198 -59.534 OPENBLASv0.3.21-SERIAL t(m1) %*% m2 64 2.330 2.173 0.406 1.798e-04 -0.460 4.006e-121 -19.346

缩放因子512

library expr fct mean_time median_time sd_time p_wth d_wth p_btw d_btw NETLIBv3.9.0* crossprod(m1, m2) 512 1733.759 1728.830 16.205 5.592e-129 25.400 NA NA NETLIBv3.9.0* t(m1) %*% m2 512 1241.799 1247.721 21.981 5.592e-129 25.400 NA NA ATLASv3.10.3 crossprod(m1, m2) 512 489.746 486.333 10.618 1.794e-01 -0.153 4.427e-181 -90.790 ATLASv3.10.3 t(m1) %*% m2 512 491.527 486.131 12.480 1.794e-01 -0.153 6.680e-149 -41.802 BLISv0.9.0 crossprod(m1, m2) 512 147.600 146.746 4.762 1.699e-17 -1.431 3.411e-204 -109.626 BLISv0.9.0 t(m1) %*% m2 512 152.862 152.876 1.994 1.699e-17 -1.431 1.190e-170 -61.923 OPENBLASv0.3.21-OPENMP crossprod(m1, m2) 512 100.148 96.742 14.906 3.206e-01 -0.136 2.568e-189 -104.908 OPENBLASv0.3.21-OPENMP t(m1) %*% m2 512 102.031 101.905 12.570 3.206e-01 -0.136 1.421e-162 -64.349 OPENBLASv0.3.21-SERIAL crossprod(m1, m2) 512 139.406 137.633 6.863 4.804e-03 -0.324 1.387e-202 -118.417 OPENBLASv0.3.21-SERIAL t(m1) %*% m2 512 141.396 139.434 5.187 4.804e-03 -0.324 8.653e-169 -69.579

*

NETLIB 是之间(顺便说一句)比较的参考。 注意

R version 4.4.1 (2024-06-14) Platform: x86_64-redhat-linux-gnu Running under: AlmaLinux 9.4 (Seafoam Ocelot) CPUs: 8

	
© www.soinside.com 2019 - 2024. All rights reserved.