Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow/accomodate optimParallel as optimizer option #508

Open
nicebread opened this issue Mar 1, 2019 · 2 comments
Open

Allow/accomodate optimParallel as optimizer option #508

nicebread opened this issue Mar 1, 2019 · 2 comments

Comments

@nicebread
Copy link

The optimParallel package might be a way to speed up convergence by parallelisation. Currently, however, the API, resp. the optimizer function calls do not fit into lme4.

@bbolker
Copy link
Member

bbolker commented Mar 2, 2019

Hmmm. In principle this should be able to be done by defining an appropriate wrapper function, but here's how far I got.

library(lme4)
library(optimParallel)


setDefaultCluster(cl <- makeCluster(2))
optparwrap <- function(fn, par, lower, control, ...) {
    res <- optimParallel(fn=fn, par=par, lower=lower, control=control, ...)
    with(res,list(par=par, fval=value, conv=convergence,
                  message=message))
}


fm1 <- lmer(Reaction ~ Days + (Days|Subject), sleepstudy)
fm2 <- update(fm1, control=lmerControl(optimizer=optparwrap))
## Error in checkForRemoteErrors(val) : 
##  2 nodes produced errors; first error: NULL value passed as symbol address

There may be problems with scoping ... I looked at this a little bit further and see that the problem probably occurs because lme4 tries to use environments to pass information to the functions. There may not be an easy fix ... maybe someone who knows more about optimParallel could try to figure this out?

There might not be quite as much advantage as one thinks, because analytical derivatives are not available for the objective function ...

@florafauna
Copy link

I am the author of optimParallel.

optimParallel provides the larges speed improvements when no analytical derivatives are available; see the vignette https://cran.r-project.org/web/packages/optimParallel/vignettes/optimParallel.pdf. So it could be a good fit.

What optimParallel does is:

  1. take all values provided via ... as well as the objective function fn and put them into an environment e
  2. copy e once to all processes in the cluster
  3. evaluate fn in parallel within that environment with local(, envir=e).

In lmer I saw a construct similar to:

fn <- function(par) abs(par) + a
environment(fn) <- list2env(list(a=57))
cl <- makeCluster(2); setDefaultCluster(cl)
optimParallel(1, fn)[1:2]
$par
[1] 0

$value
[1] 57

This works, optimParallel_0.8.

What does not work is to access an element in the environment where fn is created:

fn2 <- function(par) abs(par) + b
b <- 2
optimParallel(1, fn2)[1:2]
Error in checkForRemoteErrors(val) : 
  2 nodes produced errors; first error: object 'b' not found

For this situation one can either proceed as in the example above or as

fn3 <- function(par, b) abs(par) + b
b <- 2
optimParallel(1, fn3, b=b)[1:2]
$par
[1] 0

$value
[1] 2

So, I think you are right and it is a scoping issue. I see no easy patch for optimParallel to avoid this issue. I tried several designs to call fn and the current one seems to be the preferred one. On the other hand, adapting lmer seems possible. What do you think? Would it require many changes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants