--- title: "Sampling from TMB models using Stan" author: "Kasper Kristensen" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: toc: true vignette: > %\VignetteIndexEntry{Sampling from TMB models using Stan} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE, message=FALSE} ##library(knitr) library(RTMB) library(tmbstan) set.seed(1) formals(MakeADFun)$silent <- TRUE ``` # How to sample We consider the random regression example from the `RTMB` introduction vignette: ```{r} ## Data data(ChickWeight) ## Parameters and random effects parameters <- list( mua=0, ## Mean slope sda=1, ## Std of slopes mub=0, ## Mean intercept sdb=1, ## Std of intercepts sdeps=1, ## Residual Std a=rep(0, 50), ## Random slope by chick b=rep(0, 50) ## Random intercept by chick ) ## Negative log likelihood f <- function(parms) { getAll(ChickWeight, parms, warn=FALSE) ## Optional (enables extra RTMB features) weight <- OBS(weight) ## Initialize joint negative log likelihood nll <- 0 ## Random slopes nll <- nll - sum(dnorm(a, mean=mua, sd=sda, log=TRUE)) ## Random intercepts nll <- nll - sum(dnorm(b, mean=mub, sd=sdb, log=TRUE)) ## Data predWeight <- a[Chick] * Time + b[Chick] nll <- nll - sum(dnorm(weight, predWeight, sd=sdeps, log=TRUE)) ## Get predicted weight uncertainties ADREPORT(predWeight) ## Return nll } ``` We build the `TMB` model object (following the original example, we specify the `random` effects although that is redundant here): ```{r} obj <- MakeADFun(f, parameters, random=c("a", "b")) ``` A full Bayesian analysis is run by: ```{r} out <- tmbstan(obj, chains=1, seed=1) ``` # Improving sampling speed MCMC runs for large models can take a very long time. A simple strategy for improving sampling speed is to speed up the objective function and gradient by enabling vectorization. ```{r} TapeConfig(vectorize="enable") ## Enable vectorization obj_vect <- MakeADFun(f, parameters, random=c("a", "b")) TapeConfig(vectorize="disable") ## Restore previous settings ``` We can check the effect of this optimization before starting the potentially long MCMC run. For accurate timing, excluding R overhead, we use the `RTMB` tape `timer()` method, and report an average over `1e4` evaluations of the `total` tape pass: ```{r} ## Timing without vectorization t <- GetTape(obj)$timer(rep=1e4,total=TRUE) ## Timing with vectorization t_vect <- GetTape(obj_vect)$timer(rep=1e4,total=TRUE) ## speedup ? c(speedup = unname(t / t_vect)) ``` In this case vectorization appears to be beneficial. Let's compare the MCMC runs: ```{r} system.time(out <- tmbstan(obj, chains=1, seed=1, refresh = 0)) system.time(out_vect <- tmbstan(obj_vect, chains=1, seed=1, refresh = 0)) ```