【发布时间】:2019-11-16 03:42:01
【问题描述】:
我尝试使用 Rcpp 重写一些 R 代码。但是,我发现性能有所下降。我已经针对有问题的代码的特定部分。在这一部分中,我从 R 中的stats 包中导入了optimise 函数。
我要重写的 R 代码是:
###################################
# R implementation
phi_R <- function(x, mean = 0, beta) {
return(2*(beta^2)*((x-mean)^6) - 3*beta*((x-mean)^2))
}
bound_phi_R <- function(beta, mean = 0, lower, upper) {
# finding maxima and minimma in the interval
maxim <- optimise(function(x) phi_R(x, mean, beta), interval = c(lower, upper),
maximum = TRUE)$objective
minim <- optimise(function(x) phi_R(x, mean, beta), interval = c(lower, upper),
maximum = FALSE)$objective
# checking end points
at_lower <- phi_R(lower, mean, beta)
at_upper <- phi_R(upper, mean, beta)
# obtaining upper and lower bounds
upper_bound <- max(maxim, at_lower, at_upper)
lower_bound <- min(minim, at_lower, at_upper)
return(list('low_bound' = lower_bound, 'up_bound' = upper_bound))
}
这个函数试图找到一个特定的一维函数的上限和下限,称为 phi。 我的 Rcpp 实现是:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::plugins("cpp17")]]
// [[Rcpp::depends(stats)]]
double phi_rcpp(const double &x,
const double &mean,
const double &beta) {
return ((2*beta*beta*pow(x-mean, 6))-(3*beta*(x-mean)*(x-mean)));
}
// [[Rcpp::export]]
Rcpp::List bound_phi_rcpp(const double &mean,
const double &beta,
const double &lower,
const double &upper) {
// Obtaining namespace of stats package in R
Rcpp::Environment stats("package:stats");
// Picking up optimise function
Function optimise = stats["optimise"];
// using optimise to find the maximum and minimum of phi within the interval
Rcpp::List maxim = optimise(_["f"] = Rcpp::InternalFunction(&phi_rcpp),
_["lower"] = lower,
_["upper"] = upper,
_["maximum"] = true,
_["mean"] = mean,
_["beta"] = beta);
Rcpp::List minim = optimise(_["f"] = Rcpp::InternalFunction(&phi_rcpp),
_["lower"] = lower,
_["upper"] = upper,
_["maximum"] = false,
_["mean"] = mean,
_["beta"] = beta);
// check the end points are not greater or less than the minimum and maximums from optimise
double at_upper = phi_rcpp(upper, mean, beta);
double at_lower = phi_rcpp(lower, mean, beta);
double upper_bound = std::max(as<double>(maxim[1]), std::max(at_lower, at_upper));
double lower_bound = std::min(as<double>(minim[1]), std::min(at_lower, at_upper));
// return bounds as vector
return Rcpp::List::create(Named("low_bound") = lower_bound,
Named("up_bound") = upper_bound);
}
接下来,我做一些基准测试:
library(Rcpp)
sourceCpp(file = 'rcpp.cpp')
pcm <- proc.time()
set.seed(42)
for (i in 1:10000) {
limits <- runif(2, -2, 2)
bound_phi_rcpp(beta = 1/4, mean = 0, lower = min(limits), upper = max(limits))
}
test1_time <- proc.time()-pcm
pcm <- proc.time()
set.seed(42)
for (i in 1:10000) {
limits <- runif(2, -2, 2)
bound_phi_R(beta = 1/4, mean = 0, lower = min(limits), upper = max(limits))
}
test2time <- proc.time()-pcm
print(paste('rcpp:', test1_time['elapsed'])) # 5.69 on my machine
print(paste('R:', test2_time['elapsed'])) # 0.0749 on my machine
# benchmarking with rbenchmark
set.seed(42)
limits <- runif(2, -2, 2)
identical(bound_phi_rcpp(beta = 1/4, mean = 0, lower = min(limits), upper = max(limits)),
bound_phi_R(beta = 1/4, mean = 0, lower = min(limits), upper = max(limits)))
rbenchmark::benchmark(cpp = bound_phi_rcpp(beta = 1/4, mean = 0, lower = min(limits), upper = max(limits)),
R = bound_phi_R(beta = 1/4, mean = 0, lower = min(limits), upper = max(limits)),
replications = 1000)
我得到以下基准:
test replications elapsed relative user.self sys.self user.child sys.child
1 cpp 1000 0.532 10.231 0.532 0.001 0 0
2 R 1000 0.052 1.000 0.052 0.000 0 0
从 stats 导入函数似乎有相当多的开销。有什么方法可以加快这个过程,或者 Rcpp 中是否有等效的优化功能?
【问题讨论】:
-
请检查
optimise()调用在c++中占用了多少时间。 -
您在 R 和 C++ 之间来回切换。这不可能是有效的。尝试用 C++ 实现的优化算法,例如boost.org/doc/libs/1_70_0/libs/math/doc/html/math_toolkit/… 应该是 BH 包的一部分。
标签: r optimization rcpp