19 views

Skip to first unread message

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)}))

### 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

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.

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

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))

})

},

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)

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

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

To view this discussion on the web visit https://groups.google.com/d/msgid/nimble-users/1147bfdb-8f46-40e5-80e0-15aee1670b43n%40googlegroups.com.

Reply all

Reply to author

Forward

0 new messages

Search

Clear search

Close search

Google apps

Main menu