ขณะนี้ฉันกำลังทำงานกับวิธีแบบเบย์ที่ต้องการหลายขั้นตอนของการเพิ่มประสิทธิภาพของแบบจำลองการบันทึกหลายส่วนต่อการวนซ้ำ ฉันใช้ optim () เพื่อดำเนินการ optimisations เหล่านั้นและฟังก์ชั่นวัตถุประสงค์ที่เขียนใน R การทำโปรไฟล์เปิดเผยว่า optim () เป็นคอขวดหลัก
หลังจากขุดไปรอบ ๆ ฉันพบคำถามนี้ซึ่งพวกเขาแนะนำว่าการบันทึกฟังก์ชันวัตถุประสงค์ด้วยRcpp
สามารถทำให้กระบวนการเร็วขึ้น ฉันทำตามข้อเสนอแนะและบันทึกฟังก์ชั่นวัตถุประสงค์ของฉันRcpp
ใหม่ แต่มันก็ช้าลง (ช้าลงประมาณสองเท่า!)
นี่เป็นครั้งแรกของฉันที่มีRcpp
(หรืออะไรก็ตามที่เกี่ยวข้องกับ C ++) และฉันไม่สามารถหาวิธีการเขียนโค้ดเวกเตอร์ได้ มีความคิดอย่างไรที่จะทำให้เร็วขึ้น?
Tl; dr: การใช้งานฟังก์ชั่นปัจจุบันใน Rcpp ไม่เร็วเท่ากับ vectorised 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?) สามารถสร้างผลกำไรได้หรือไม่? เป็นความคิดที่ดีกว่าหรือไม่ที่จะบันทึกทุกอย่างใน Rcpp โดยใช้เครื่องมือเพิ่มประสิทธิภาพ C ++?
PS: การโพสต์ครั้งแรกที่ Stackoverflow!
Obs
ถือเป็นการIntegerVector
ปลดเปลื้องบางส่วนได้