현재 반복마다 다항식 로짓 모델을 여러 단계로 최적화 해야하는 베이지안 방법을 연구 중입니다. 이러한 최적화를 수행하기 위해 optim ()을 사용하고 있으며 R로 작성된 목적 함수입니다. 프로파일 링에서 optim ()이 주요 병목 현상 인 것으로 나타났습니다.
주위를 파고 들자, 이 질문 을 통해 목적 함수를 코딩 Rcpp
하면 프로세스 속도를 높일 수 있다고 제안했습니다 . 나는 제안을 따랐고 객관적인 함수를로 코딩 Rcpp
했지만 결국 더 느려졌습니다 (약 2 배 느립니다!).
이것은 Rcpp
(또는 C ++과 관련된 것) 처음으로 코드를 벡터화하는 방법을 찾을 수 없었습니다. 더 빨리 만드는 방법에 대한 아이디어가 있습니까?
T1; dr : Rcpp에서의 현재 기능 구현은 벡터화 된 R만큼 빠르지 않다; 더 빨리 만드는 방법?
재현 가능한 예 :
1) 객관적인 함수를 정의 R
하고 Rcpp
: 절편 만 다항식 모형의 로그 우도
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) 효율성을 비교하십시오.
## 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) 이제 전화 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
R의 벡터화 구현이 더 빠르다는 것에 다소 놀랐습니다. Rcpp에서보다 효율적인 버전을 구현하면 (예 : RcppArmadillo?) 어떤 이득을 얻을 수 있습니까? C ++ 옵티 마이저를 사용하여 Rcpp의 모든 것을 코딩하는 것이 더 좋은 아이디어입니까?
PS : Stackoverflow에 처음 게시!
Obs
것으로 취급 할 수 있습니다IntegerVector
.