Tôi hiện đang làm việc trên một phương pháp Bayes yêu cầu nhiều bước tối ưu hóa mô hình logit đa phương trên mỗi lần lặp. Tôi đang sử dụng Optim () để thực hiện các tối ưu hóa đó và một hàm mục tiêu được viết bằng R. Một hồ sơ tiết lộ rằng Optim () là nút cổ chai chính.
Sau khi đào xung quanh, tôi thấy câu hỏi này trong đó họ đề nghị rằng mã hóa lại hàm mục tiêu có Rcpp
thể tăng tốc quá trình. Tôi đã làm theo gợi ý và mã hóa lại hàm mục tiêu của mình Rcpp
, nhưng cuối cùng nó chậm hơn (chậm hơn khoảng hai lần!).
Đây là lần đầu tiên của tôi với Rcpp
(hoặc bất cứ điều gì liên quan đến C ++) và tôi không thể tìm ra cách vectơ mã. Bất kỳ ý tưởng làm thế nào để làm cho nó nhanh hơn?
Tl; dr: Việc triển khai chức năng hiện tại trong Rcpp không nhanh bằng vector R; Làm thế nào để làm cho nó nhanh hơn?
Một ví dụ tái sản xuất :
1) Xác định các hàm mục tiêu trong R
và Rcpp
: khả năng đăng nhập của một mô hình đa phương chỉ chặn
library(Rcpp)
library(microbenchmark)
llmnl_int <- function(beta, Obs, n_cat) {
n_Obs <- length(Obs)
Xint <- matrix(c(0, beta), byrow = T, ncol = n_cat, nrow = n_Obs)
ind <- cbind(c(1:n_Obs), Obs)
Xby <- Xint[ind]
Xint <- exp(Xint)
iota <- c(rep(1, (n_cat)))
denom <- log(Xint %*% iota)
return(sum(Xby - denom))
}
cppFunction('double llmnl_int_C(NumericVector beta, NumericVector Obs, int n_cat) {
int n_Obs = Obs.size();
NumericVector betas = (beta.size()+1);
for (int i = 1; i < n_cat; i++) {
betas[i] = beta[i-1];
};
NumericVector Xby = (n_Obs);
NumericMatrix Xint(n_Obs, n_cat);
NumericVector denom = (n_Obs);
for (int i = 0; i < Xby.size(); i++) {
Xint(i,_) = betas;
Xby[i] = Xint(i,Obs[i]-1.0);
Xint(i,_) = exp(Xint(i,_));
denom[i] = log(sum(Xint(i,_)));
};
return sum(Xby - denom);
}')
2) So sánh hiệu quả của chúng:
## Draw sample from a multinomial distribution
set.seed(2020)
mnl_sample <- t(rmultinom(n = 1000,size = 1,prob = c(0.3, 0.4, 0.2, 0.1)))
mnl_sample <- apply(mnl_sample,1,function(r) which(r == 1))
## Benchmarking
microbenchmark("llmml_int" = llmnl_int(beta = c(4,2,1), Obs = mnl_sample, n_cat = 4),
"llmml_int_C" = llmnl_int_C(beta = c(4,2,1), Obs = mnl_sample, n_cat = 4),
times = 100)
## Results
# Unit: microseconds
# expr min lq mean median uq max neval
# llmnl_int 76.809 78.6615 81.9677 79.7485 82.8495 124.295 100
# llmnl_int_C 155.405 157.7790 161.7677 159.2200 161.5805 201.655 100
3) Bây giờ gọi họ vào optim
:
## Benchmarking with optim
microbenchmark("llmnl_int" = optim(c(4,2,1), llmnl_int, Obs = mnl_sample, n_cat = 4, method = "BFGS", hessian = T, control = list(fnscale = -1)),
"llmnl_int_C" = optim(c(4,2,1), llmnl_int_C, Obs = mnl_sample, n_cat = 4, method = "BFGS", hessian = T, control = list(fnscale = -1)),
times = 100)
## Results
# Unit: milliseconds
# expr min lq mean median uq max neval
# llmnl_int 12.49163 13.26338 15.74517 14.12413 18.35461 26.58235 100
# llmnl_int_C 25.57419 25.97413 28.05984 26.34231 30.44012 37.13442 100
Tôi hơi ngạc nhiên khi việc triển khai véc tơ trong R nhanh hơn. Việc triển khai một phiên bản hiệu quả hơn trong Rcpp (giả sử với RcppArmadillo?) Có thể tạo ra bất kỳ lợi ích nào? Có phải là một ý tưởng tốt hơn để mã hóa lại mọi thứ trong Rcpp bằng trình tối ưu hóa C ++?
PS: lần đầu tiên đăng bài tại Stackoverflow!
Obs
như là mộtIntegerVector
loại bỏ một số phôi.