relative speed of calculation of log probabilities with "offline" Nimble or without Nimble

13 views
Skip to first unread message

frederic....@gmail.com

unread,
May 3, 2024, 10:41:05 AMMay 3
to nimble-users
Dear all,

I have a question on the relative speed of calculating log probabilities either with Nimble or without it. My general lesson would be that it is faster without Nimble - except maybe if done "online" - and I wished to challenge this view.

The way I do it with Nimble is though the three lines of code below:
     ### putting the x-th line of samples.List.matrix as parameter values in the model with the function setInits
     Model[[1]]$setInits(coda2NamedList(samples.List.matrix[toto,],params,Model[[1]]))
     
      ### then calculating the logProbs of all the data with the $getLogProb function and summing them: this is the value that will be returned to logliks
      Model[[1]]$calculate()
      sum(sapply(names(data),function(toto) {Model[[1]]$getLogProb(toto)}))
      
where: samples.list.matrix contains ion line the parameter values in Coda format; and coda2NamedList transforms it to named lists.

With a very simple model I find it rather long and much longer than what I would do by hand without Nimble. I would be interested to have opinions on (i) whether this is general or if with much more complicated model the trend would be reversed; and (ii) whether there would be other Nimbvle commands that could make it much faster (such as giving Nimble the whole set of samples at once ...).

I thank you very much in advance. 

All the best,

Frédéric

Chris Paciorek

unread,
May 6, 2024, 1:46:02 PMMay 6
to frederic....@gmail.com, nimble-users
Hi Frédéric,

I'm not sure if your `Model[[1]]` is compiled or not. If it's not, it will be quite slow. However, even if it is compiled, if you run `calculate` with a compiled model from R, there is a bunch of overhead to iterate through the nodes, even though the actual `calculate` operations on each node are being done using compiled code. To get this to go fast, you can write a nimbleFunction (with setup code that takes the model as an argument) that runs `calculate`, compile it and run it. Given your code looks quite simple, writing the nimbleFunction should be straightforward.

Also `setInits` is an R function and could be slow. You could write a nimbleFunction that uses `values` to set the values in a model.

-chris

-Chris

--
You received this message because you are subscribed to the Google Groups "nimble-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nimble-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/nimble-users/bd57d5c1-c741-46ba-9a36-587f26ee5d40n%40googlegroups.com.

frederic....@gmail.com

unread,
May 7, 2024, 2:26:22 AMMay 7
to nimble-users
Thank you very much Chris. Indeed, my question was not very precise: my initial test was with the uncompiled nimble model and then I realised that the compiled version was in my case roughly twice faster, and then taking care of which nodes were calculated on to avoid duplicates of calculation also yielded a factor two increase of speed. But it remained much slower on my very simple code than code ran directly in R.

Thank you very much for the advice of writing a Nimble function: just to be sure: would this function be generic or should it explicitly incorporate the nimbleCode of the model being analyzed? If generic, I will try it ASAP (but might not be very soon).

Sincerely,

Frédéric

frederic....@gmail.com

unread,
May 8, 2024, 1:22:54 AMMay 8
to nimble-users
I have actually come up with this nimbleFunction:

logProbCalcbis <- nimbleFunction(
setup = function(model,names.ref.list,notDatavarNames,DatavarNames) {
    },
    run = function(P = double(1)) {
values(model,names.ref.list) <<- P
model$calculate(notDatavarNames)
                return(model$calculate(DatavarNames))
                 returnType(double(0))
    })

Model1<-Model[[1]]
logProbCalcbisPrepared <- logProbCalcbis(Model1,dimnames(samples.List.matrix)[[2]],notDatavarNames,DatavarNames)
ClogProbCalcbisPrepared <- compileNimble(Model1, logProbCalcbisPrepared)

which is far more effective than without a nimbleFunction. It is still around 10% longer -not taking into account compilation time - than commands in R for a very simple model but this is reasonable - and maybe the ratio revereses for more complex models. And this is more than 600 times faster than crude commands  using Nimble in R with this very simples model.

So a great thank Chris. 

Sincerely,

Frédéric

Chris Paciorek

unread,
May 8, 2024, 10:51:03 AMMay 8
to frederic....@gmail.com, nimble-users
Hi Frédéric,

I'm glad you figured it out. To belatedly answer your question, we generally recommend writing nimbleFunctions in a general way, but for specific purposes it's fine to use model-specific variable and node names in the run code.

I think the relative speed will depend a lot on what you are doing. Note that in R, calls like `dnorm` and the like are just thin wrappers around C code, so there will be cases where one wouldn't expect nimble to be any faster than just calling density functions directly from R.

-chris

Reply all
Reply to author
Forward
0 new messages