we are recently considering migrating our simple reinforcement learning model from JAGS to Stan.
However, when we tried the below Stan model, it wasn't really faster than running in JAGS with the same configuration (same samples/chain, burnin, thin, etc.) .
I was wondering if there is a way to speedup / optimize the code or sampling based on the current version?
int<lower=1> nSubjects; // number of subjects
int<lower=1> nTrials; // number of trials
int<lower=1,upper=2> choice[nSubjects,nTrials]; // 2nd choices, 1 or 2
real<lower=-1,upper=1> reward[nSubjects,nTrials]; // outcome, 1 or -1
}
parameters {
// group-level parameters
real<lower=0,upper=1> lr_mu;
real<lower=0,upper=1> lr_kappa0;
real<lower=0,upper=1> temp0_mu;
real<lower=0,upper=1> temp0_kappa0;
// subject-level parameters
vector<lower=0,upper=1>[nSubjects] lr;
vector<lower=0,upper=1>[nSubjects] temp0;
}
transformed parameters {
real<lower=0> lr_kappa;
real<lower=0> lr_a;
real<lower=0> lr_b;
real<lower=0> temp0_kappa;
real<lower=0> temp0_a;
real<lower=0> temp0_b;
vector<lower=0,upper=20>[nSubjects] temp;
lr_kappa <- 3.0 / (lr_kappa0 * lr_kappa0) - 1.0;
lr_a <- lr_mu * lr_kappa;
lr_b <- (1-lr_mu) * lr_kappa;
temp0_kappa <- 3.0 / (temp0_kappa0 * temp0_kappa0) - 1.0;
temp0_a <- temp0_mu * temp0_kappa;
temp0_b <- (1-temp0_mu) * temp0_kappa;
temp <- 20.0 * temp0;
}
model {
row_vector[2] v[nTrials+1]; // values
vector[nTrials] pe; // prediction errors
// hyperparameters, priors
lr_mu ~ beta(1,1);
lr_kappa0 ~ beta(1,1);
temp0_mu ~ beta(1,1);
temp0_kappa0 ~ beta(1,1);
// subject loop and trial loop
for (s in 1:nSubjects) {
lr[s] ~ beta(lr_a,lr_b);
temp0[s] ~ beta(temp0_a,temp0_b);
v[1] <- rep_row_vector(0.0,2);
for (t in 1:nTrials) {
//* compute action probs using built-in softmax function and related to choice data */
choice[s,t] ~ categorical_logit( temp[s] * v[t]' );
//* prediction error */
pe[t] <- reward[s,t] - v[t,choice[s,t]];
//* value updating (learning) */
v[t+1] <- v[t]; // make a copy of current value into t+1
v[t,choice[s,t]] <- v[t,choice[s,t]] + lr[s] * pe[t]; // overwrite chosen value with pe update
}
}
}