खोज…


Rcpp के साथ छोरों के लिए कठिन-से-सदिश गति

लूप के लिए निम्नलिखित कठिन-से-वेक्टराइज़ पर विचार करें, जो लंबाई के len का एक वेक्टर बनाता है जहां पहला तत्व निर्दिष्ट किया जाता है ( first ) और प्रत्येक तत्व x_i cos(x_{i-1} + 1) बराबर है cos(x_{i-1} + 1) :

repeatedCosPlusOne <- function(first, len) {
  x <- numeric(len)
  x[1] <- first
  for (i in 2:len) {
    x[i] <- cos(x[i-1] + 1)
  }
  return(x)
}

इस कोड में एक तेज़ ऑपरेशन ( cos(x[i-1]+1) ) के साथ लूप शामिल है, जो अक्सर वैश्वीकरण से लाभान्वित होते हैं। हालांकि, इस ऑपरेशन को आधार आर के साथ वेक्टर करना तुच्छ नहीं है, क्योंकि आर में "x + 1" फ़ंक्शन का संचयी कोसाइन नहीं है।

इस फ़ंक्शन को गति देने के लिए एक संभव तरीका आरसीपी पैकेज का उपयोग करके सी ++ में इसे लागू करना होगा:

library(Rcpp)
cppFunction("NumericVector repeatedCosPlusOneRcpp(double first, int len) {
  NumericVector x(len);
  x[0] = first;
  for (int i=1; i < len; ++i) {
    x[i] = cos(x[i-1]+1);
  }
  return x;
}")

सटीक परिणाम देते समय यह अक्सर बड़े कम्प्यूटेशन के लिए महत्वपूर्ण स्पीडअप प्रदान करता है:

all.equal(repeatedCosPlusOne(1, 1e6), repeatedCosPlusOneRcpp(1, 1e6))
# [1] TRUE
system.time(repeatedCosPlusOne(1, 1e6))
#    user  system elapsed 
#   1.274   0.015   1.310 
system.time(repeatedCosPlusOneRcpp(1, 1e6))
#    user  system elapsed 
#   0.028   0.001   0.030 

इस स्थिति में, Rcpp कोड, बेस R दृष्टिकोण के साथ 1.31 सेकंड के बजाय 0.03 सेकंड में 1 मिलियन लंबाई का वेक्टर उत्पन्न करता है।

बाइट संकलन द्वारा लूप्स के लिए कठिन-से-वेक्टराइज़ करना

इस दस्तावेज़ प्रविष्टि में Rcpp उदाहरण के बाद, निम्नलिखित कठिन-से-वेक्टराइज़ फ़ंक्शन पर विचार करें, जो लंबाई के len का एक वेक्टर बनाता है जहां पहला तत्व निर्दिष्ट किया गया है ( first ) और प्रत्येक तत्व x_i cos(x_{i-1} + 1) बराबर है cos(x_{i-1} + 1) :

repeatedCosPlusOne <- function(first, len) {
  x <- numeric(len)
  x[1] <- first
  for (i in 2:len) {
    x[i] <- cos(x[i-1] + 1)
  }
  return(x)
}

कोड की एक पंक्ति को फिर से लिखने के बिना इस तरह के एक कार्य को तेज करने के लिए एक सरल दृष्टिकोण आर संकलन का उपयोग करके कोड को संकलित करना है:

library(compiler)
repeatedCosPlusOneCompiled <- cmpfun(repeatedCosPlusOne)

परिणामी फ़ंक्शन अक्सर उसी परिणाम को वापस करते समय काफी तेज होगा:

all.equal(repeatedCosPlusOne(1, 1e6), repeatedCosPlusOneCompiled(1, 1e6))
# [1] TRUE
system.time(repeatedCosPlusOne(1, 1e6))
#    user  system elapsed 
#   1.175   0.014   1.201 
system.time(repeatedCosPlusOneCompiled(1, 1e6))
#    user  system elapsed 
#   0.339   0.002   0.341 

इस मामले में, बाइट संकलन ने कठिन-से-वेक्टराइज़ ऑपरेशन को 1.20 सेकंड से 0.34 सेकंड की लंबाई के 1 मिलियन वेक्टर पर फैलाया।

टिप्पणी

repeatedCosPlusOne फ़ंक्शन का सार, एकल फ़ंक्शन के संचयी अनुप्रयोग के रूप में, Reduce साथ अधिक पारदर्शी रूप से व्यक्त किया जा सकता है:

iterFunc <- function(init, n, func) {
  funcs <- replicate(n, func)
  Reduce(function(., f) f(.), funcs, init = init, accumulate = TRUE)
}
repeatedCosPlusOne_vec <- function(first, len) {
  iterFunc(first, len - 1, function(.) cos(. + 1))
}

repeatedCosPlusOne_vec कैकसप्लसओने_वीच को repeatedCosPlusOne बारप्लसओप्लेन के "वैश्वीकरण" के रूप में माना जा सकता है। हालांकि, यह 2 के कारक से धीमा होने की उम्मीद की जा सकती है:

library(microbenchmark)
microbenchmark(
  repeatedCosPlusOne(1, 1e4),
  repeatedCosPlusOne_vec(1, 1e4)
)
#> Unit: milliseconds
#>                              expr       min        lq     mean   median       uq      max neval cld
#>      repeatedCosPlusOne(1, 10000)  8.349261  9.216724 10.22715 10.23095 11.10817 14.33763   100  a 
#>  repeatedCosPlusOne_vec(1, 10000) 14.406291 16.236153 17.55571 17.22295 18.59085 24.37059   100   b


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow