Compile Stan model in Shiny App?

Hello,

I hope this is the place to ask this. Let me know if I need to go elsewhere! I’m trying to run rstan in a shiny app I’m creating. It runs fine locally, but then when I deploy it to shinyapps.io, I seem unable to compile the model. Thing’s I’ve tried:

  1. Compile the model in global.R using stan_model(); this gives me the following error when I try to deploy to shinyapps.io (the app doesn’t work at all in this case):

    Warning in system(cmd, intern = !verbose) :
    running command ‘/opt/R/3.5.2/lib/R/bin/R CMD SHLIB file19349976b7.cpp 2> file19349976b7.cpp.err.txt’ had status 1
    Error in value[3L] : invalid connection
    Calls: local … tryCatch -> tryCatchList -> tryCatchOne ->
    Execution halted

  2. Save a locally compiled stanmodel and load it into the shiny environment in the app. The app runs but it is unable to use the pre-compiled stanmodel object. I understand that this is probably because you can’t use compiled stanmodel objects from a different computer.

  3. Include a button in the app that will trigger the stan_model() function. This seems to work for a bit, but then the app disconnects/times out because it takes too long.

I hope that anyone can help me with my problem. Let me know if I need to provide any additional information.

2 Likes

I recall someone getting this to work awhile ago; maybe @denne ? I think the real answer is that you should create a small R package that has your model precompiled following

but with the GitHub version of the rstantools package

Then presumably shinyapps.io will let you load that package an draw from the posterior distribution.

It still works on travisCI, but some of the comments in the readme might no longer be valid.

https://travis-ci.org/dmenne/brmspack

1 Like

To compile a Stan model on shinyapps.io you need to use the xxlarge instance with 4 gb ram.

Thanks for sharing this idea! I’m going to look into it… Not really experienced with creating R packages but the links you’ve shared should hopefully help.

Thanks for sharing this! I’m going to try and make it work and I’ll report back here.

when I implement Rstan in Shiny, then the following error occurred, and I guess the error message Out of memory relates your suggestion, but I do not know how to use 4Gb ram. Is it free? How to extend the memory?

I found, I should pay money to upload rstan with Shiny.
Unfortunately, I will give up. :’-D

2019-08-06T08:14:13.288608+00:00 shinyapps[system]: Out of memory!
2019-08-06T08:14:13.302116+00:00 shinyapps[1067050]: Warning in system(cmd, intern = !verbose) :
2019-08-06T08:14:13.302119+00:00 shinyapps[1067050]:   running command '/opt/R/3.6.1/lib/R/bin/R CMD SHLIB file1a3c160a9.cpp 2> file1a3c160a9.cpp.err.txt' had status 1
2019-08-06T08:14:13.378902+00:00 shinyapps[1067050]:   133: sink
2019-08-06T08:14:13.378904+00:00 shinyapps[1067050]:   132: cxxfunctionplus
2019-08-06T08:14:13.378905+00:00 shinyapps[1067050]:   131: rstan::stan_model

Yes, it seems that the free and starter plans are limited to 1 GB. So compiling on shinyapps.io requires you to have at minimum the basic plan.

If it possible for you to use a pre-compiled model then I think that’s the way to go. I think shinyapps uses AWS instances with Ubuntu based OS. If you are a mac or windows user, then following approach should work: start an instance on AWS, with for example these AMI http://www.louisaslett.com/RStudio_AMI (or use Docker on your own computer). Compile the model there and then use it for you Shiny app. I’ve not actually tested it myself, but should work.

1 Like

If someone can have any idea to publish (as web application) the following simple Shiny code with rstan , please let me know.

I knew AWS and AMI or Docker for the first time, so now I cannot understand your suggestion, or what should I do. Please let me know if you have any idea.

Error
2019-08-07T06:47:30.127423+00:00 shinyapps[1072302]: 180: rstan::stan_model
2019-08-07T06:47:30.127424+00:00 shinyapps[1072302]: 179: renderPlot [/srv/connect/apps/aaaff/app.R#42]
2019-08-07T06:47:30.127424+00:00 shinyapps[1072302]: 177: func
2019-08-07T06:47:30.127425+00:00 shinyapps[1072302]: 137: drawPlot
2019-08-07T06:47:30.127426+00:00 shinyapps[1072302]: 107: drawReactive
2019-08-07T06:47:30.127426+00:00 shinyapps[1072302]: 94: origRenderFunc
2019-08-07T06:47:30.127427+00:00 shinyapps[1072302]: 93: output$distPlot
2019-08-07T06:47:30.127425+00:00 shinyapps[1072302]: 123: reactive:plotObj
2019-08-07T06:47:30.127428+00:00 shinyapps[1072302]: 12: fn
2019-08-07T06:47:30.127427+00:00 shinyapps[1072302]: 13: runApp
2019-08-07T06:47:30.127428+00:00 shinyapps[1072302]: 7: connect$retry
2019-08-07T06:47:30.127429+00:00 shinyapps[1072302]: 6: eval
2019-08-07T06:47:30.127429+00:00 shinyapps[1072302]: 5: eval
2019-08-07T06:50:30.877478+00:00 shinyapps[system]: Out of memory!
2019-08-07T06:50:30.921102+00:00 shinyapps[1072302]: 137: drawPlot
2019-08-07T06:50:30.882856+00:00 shinyapps[1072302]: Warning in system(cmd, intern = !verbose) :
2019-08-07T06:50:30.882859+00:00 shinyapps[1072302]: running command ‘/opt/R/3.6.1/lib/R/bin/R CMD SHLIB file17f6d2353.cpp 2> file17f6d2353.cpp.err.txt’ had status 1
2019-08-07T06:50:30.914235+00:00 shinyapps[1072302]: Warning: Error in sink: invalid connection
2019-08-07T06:50:30.921098+00:00 shinyapps[1072302]: 182: sink
2019-08-07T06:50:30.921100+00:00 shinyapps[1072302]: 180: rstan::stan_model
2019-08-07T06:50:30.921101+00:00 shinyapps[1072302]: 179: renderPlot [/srv/connect/apps/aaaff/app.R#42]
2019-08-07T06:50:30.921099+00:00 shinyapps[1072302]: 181: cxxfunctionplus
2019-08-07T06:50:30.921101+00:00 shinyapps[1072302]: 177: func
2019-08-07T06:50:30.921103+00:00 shinyapps[1072302]: 107: drawReactive
2019-08-07T06:50:30.921103+00:00 shinyapps[1072302]: 94: origRenderFunc
2019-08-07T06:50:30.921104+00:00 shinyapps[1072302]: 93: output$distPlot
2019-08-07T06:50:30.921104+00:00 shinyapps[1072302]: 13: runApp
2019-08-07T06:50:30.921105+00:00 shinyapps[1072302]: 12: fn
2019-08-07T06:50:30.921105+00:00 shinyapps[1072302]: 7: connect$retry
2019-08-07T06:50:30.921140+00:00 shinyapps[1072302]: 5: eval
2019-08-07T06:50:30.921102+00:00 shinyapps[1072302]: 123: reactive:plotObj
2019-08-07T06:50:30.921105+00:00 shinyapps[1072302]: 6: eval
2019-08-07T06:51:00.989733+00:00 shinyapps[system]: Out of memory!
2019-08-07T06:51:01.033105+00:00 shinyapps[1072302]: 137: drawPlot
2019-08-07T06:51:01.033106+00:00 shinyapps[1072302]: 107: drawReactive
2019-08-07T06:51:01.033106+00:00 shinyapps[1072302]: 94: origRenderFunc
2019-08-07T06:51:00.995083+00:00 shinyapps[1072302]: Warning in system(cmd, intern = !verbose) :
2019-08-07T06:51:01.033107+00:00 shinyapps[1072302]: 93: output$distPlot
2019-08-07T06:51:00.995094+00:00 shinyapps[1072302]: running command ‘/opt/R/3.6.1/lib/R/bin/R CMD SHLIB file172b8bf365.cpp 2> file172b8bf365.cpp.err.txt’ had status 1
2019-08-07T06:51:01.033107+00:00 shinyapps[1072302]: 13: runApp
2019-08-07T06:51:01.033091+00:00 shinyapps[1072302]: 182: sink
2019-08-07T06:51:01.033108+00:00 shinyapps[1072302]: 7: connect$retry
2019-08-07T06:51:01.026390+00:00 shinyapps[1072302]: Warning: Error in sink: invalid connection
2019-08-07T06:51:01.033108+00:00 shinyapps[1072302]: 12: fn
2019-08-07T06:51:01.033093+00:00 shinyapps[1072302]: 181: cxxfunctionplus
2019-08-07T06:51:01.033109+00:00 shinyapps[1072302]: 6: eval
2019-08-07T06:51:01.033103+00:00 shinyapps[1072302]: 180: rstan::stan_model
2019-08-07T06:51:01.033109+00:00 shinyapps[1072302]: 5: eval
2019-08-07T06:51:01.033104+00:00 shinyapps[1072302]: 179: renderPlot [/srv/connect/apps/aaaff/app.R#42]
2019-08-07T06:51:01.033104+00:00 shinyapps[1072302]: 177: func
2019-08-07T06:51:01.033105+00:00 shinyapps[1072302]: 123: reactive:plotObj

Shiny code with Rstan

library(shiny);library(Rcpp);library(rstan);

 ui <- fluidPage(
  
  # Application title
  titlePanel("Old Faithful Geyser Data"),
  
   sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),
    
    # Show a plot of the generated distribution
    mainPanel(
      plotOutput("distPlot")
    )
  )
)

 server <- function(input, output) {
  
 
  fit <- shiny::reactive({
    
    model <- rstan::stan_model(
      model_code = "parameters {real y;} model {y ~ normal(0,1);}            "
    )
    
    fit <- rstan::sampling(model)
    
    return(fit)
    
  })
  
 
  output$distPlot <- renderPlot({
    # generate bins based on input$bins from ui.R
    x    <- faithful[, 2]
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    rstan::stan_hist(fit(),bins=input$bins)
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

I tried a few ways of deploying a stan program to shinyapps.io.

  1. compiling on startup directly in shinyappa.io. This works, you need to have standard plan or higher so you can set 4 gb om ram (and the timeout at startup to its maximum 300 secs). Here’s a working example: https://rokka.shinyapps.io/shiny_priors/. So the app, stan program and tool chain works. But the startup get very slow and would probably time out for any serious Stan model.

  2. precompile with stan_model() on same x86_64-pc-linux-gnu platform before deploying, then sampling from the saved .rds model file. This results in following traceback when starting the app. Any idea what going on here? Is it some permission thing, that the Stan DSO doesn’t get exec rights?

Traceback:
1: dyn.load(libLFile)
2: cxxfun_from_dso_bin(object)
4: grab_cxxfun(object@dso)
3: .local(object, ...)
5: grab_cxxfun(object@dso)
7: object@mk_cppmodule(object)
6: prep_call_sampler(object)
8: .local(object, ...)
10: sampling(stan_model, data = c(data_stan(), list(y = c(1, 1),     N = 2, y_sigma = 1)), chains = 1, iter = input$iter, warmup = as.integer(input$warmup/100 *     input$iter), control = list(metric = "diag_e"))
…
An irrecoverable exception occurred. R is aborting now ...
219: local({    if (identical(.Platform$OS.type, "unix")) {        whoami <- system("whoami", intern = TRUE)        if (identical(whoami, "root")) {            stop("Attempted to run application as whoami=", whoami,                 "; USER=", Sys.getenv("USER"))        }    }    fd <- file("stdin")    d <- read.dcf(fd)    close(fd)    config <- as.list(structure(as.vector(d), names = colnames(d)))    expectedFields <- c("ConnectDir", "Version", "InstalledRVersion",         "BundleRVersion", "AppDir", "BookmarkDir", "Host", "Port",         "SharedSecret", "WorkerId", "AppMode", "HTMLInclude",         "IgnorePackrat", "ErrorSanitization", "TraceFlushReact",         "Reconnect", "ReconnectMs", "DisabledProtocols", "TransportDebugging",         "ForcePandocVersion", "MinimumPandoc2RMarkdownVersion",         "InstalledPythonVersion")    missingFields <- setdiff(expectedFields, names(config))    unexpectedFields <- setdiff(names(config), expectedFields)    if (length(missingFields) != 0 || length(unexpectedFields) !=         0) {        fmt <- "Unexpected configuration; missing fields: %s; unexpected fields: %s"        stop(sprintf(fmt, paste0(missingFields, collapse = ", "),             paste0(unexpectedFields, collapse = ", ")))    }    PRODUCT_NAME <- "RStudio Connect"    MIN_R_VERSION <- "2.15.1"    MIN_SHINY_VERSION <- "0.7.0"    MIN_RMARKDOWN_VERSION <- "0.1.90"    MIN_KNITR_VERSION <- "1.5.32"    MIN_SHINY_RMARKDOWN_VERSION <- "0.9.1.9005"    source(file = file.path(config$ConnectDir, "R", "connect.R"),         local = TRUE)    connect$printOS(config)    connect$enforceMinimumRVersion(MIN_R_VERSION)    if (config$IgnorePackrat != "true") {        connect$enforceInstalledRVersion(config$InstalledRVersion)        connect$enforceAssumedRVersion(config$BundleRVersion)        connect$enforcePackratHealth()        connect$configureAppLibDir(config$AppDir)    }    connect$enforceInstalledPython(config$InstalledPythonVersion)    packages <- c("shiny", "httpuv", "rmarkdown", "knitr", "jsonlite",         "RJSONIO", "htmltools")    versions <- connect$getVersions(packages)    cat(paste("Server version: ", config$Version, "\n", sep = ""))    connect$printEnvironment()    connect$printVersions(packages, versions)    connect$checkReticulatePython()    connect$enforcePackageVersion("shiny", MIN_SHINY_VERSION,         versions$shiny)    if (identical(config$AppMode, "shinyrmd")) {        connect$enforcePackageVersion("rmarkdown", MIN_RMARKDOWN_VERSION,             versions$rmarkdown)        connect$enforceDependentPackageVersion("shiny", MIN_SHINY_RMARKDOWN_VERSION,             versions$shiny, "rmarkdown")        connect$enforceDependentPackageVersion("knitr", MIN_KNITR_VERSION,             versions$knitr, "rmarkdown")    }    connect$configurePandoc(config, versions)    connect$configureBrowseURL()    connect$fixupCrossPackageReferences()    library(shiny)    Sys.setenv(SHINY_PORT = config$Port, SHINY_SERVER_VERSION = config$Version)    options(shiny.sanitize.errors = (config$ErrorSanitization ==         "true"))    options(shiny.sharedSecret = config$SharedSecret)    if (exists("setServerInfo", envir = asNamespace("shiny"))) {        shiny:::setServerInfo(shinyServer = TRUE, version = config$Version,             edition = "Connect")    }    helpers <- connect$configureShinyHelpers(versions)    shinyFilter <- connect$configureShinyFilter(config, helpers,         versions)    options(shiny.http.response.filter = shinyFilter)    connect$configureShinyBookmarking(config$BookmarkDir)    port <- suppressWarnings(as.integer(config$Port))    if (is.na(port)) {        port <- config$Port        attr(port, "mask") <- strtoi("0077", 8)    }    cat(paste("\nStarting R with process ID: '", Sys.getpid(),         "'\n", sep = ""))    if (config$TraceFlushReact == "true") {        assign(".shiny__stdout", stdout(), envir = globalenv())    }    connect$retry(function() {        if (identical(config$AppMode, "shiny")) {            if ("host" %in% names(formals(shiny::runApp))) {                runApp(config$AppDir, host = config$Host, port = port,                   launch.browser = FALSE, workerId = config$WorkerId)            }            else {                runApp(config$AppDir, port = port, launch.browser = FALSE,                   workerId = config$WorkerId)            }        }        else if (identical(config$AppMode, "shinyrmd")) {            library(rmarkdown)            shiny_args <- list(port = port, launch.browser = FALSE,                 workerId = config$WorkerId)            if ("host" %in% names(formals(shiny::runApp))) {                shiny_args[["host"]] = config$Host            }            rmarkdown::run(file = NULL, dir = config$AppDir,                 shiny_args = shiny_args, render_args = if (compareVersion("1.7",                   versions$rmarkdown) <= 0)                   list(envir = globalenv()), auto_reload = FALSE)        }        else {            stop(paste("Unclear Shiny mode:", config$AppMode))        }    }, isRetryable = function(e) {        e$message == "Failed to create server"    }, delay = function(iter) {        (iter - 1) * 0.5    })    invisible(environment())})
217: eval(expr, p)
213: connect$retry(function() {    if (identical(config$AppMode, "shiny")) {        if ("host" %in% names(formals(shiny::runApp))) {            runApp(config$AppDir, host = config$Host, port = port,                 launch.browser = FALSE, workerId = config$WorkerId)        }        else {            runApp(config$AppDir, port = port, launch.browser = FALSE,                 workerId = config$WorkerId)        }    }    else if (identical(config$AppMode, "shinyrmd")) {        library(rmarkdown)        shiny_args <- list(port = port, launch.browser = FALSE,             workerId = config$WorkerId)        if ("host" %in% names(formals(shiny::runApp))) {            shiny_args[["host"]] = config$Host        }        rmarkdown::run(file = NULL, dir = config$AppDir, shiny_args = shiny_args,             render_args = if (compareVersion("1.7", versions$rmarkdown) <=                 0)                 list(envir = globalenv()), auto_reload = FALSE)    }    else {        stop(paste("Unclear Shiny mode:", config$AppMode))    }}, isRetryable = function(e) {    e$message == "Failed to create server"}, delay = function(iter) {    (iter - 1) * 0.5})
  1. make a r-package containing a precompiled stan model that get bundled if installed with install.github. I tired this with the new rstantools 2.0.0 package skeleton. I get the model to install and run on my own aws platform. But i can’t deploy it to shinyapps.io as the ´configure´ file doesn’t have exec permission during the bundling (doesn’t help giving the ´configure´ exec permission as it gets moved to another directory during the bundling, whereby it looses its exec permission). If I remove the configure file then it deploys, but I get smilar error as in item 2 above (I guess the line rstantools::rstan_config() in the configure really needs to be run for setting up things correctly)

I would appreciate any help, especially on approach 2 as that is an smoother workflow as everything can be kept within one project.

I also posted at https://community.rstudio.com/t/run-pre-compiled-stan-model-on-shinyapps-io/41376

1 Like

We need to know what is in the … between 10 and 219, but my guess is that it thinks the saved Stan model is invalid.

Exceeds the character limit so I’m attaching the full log as txt file.

logs_approach2.txt (62.2 KB)

That

*** caught illegal operation ***
stuff is usually due to having a Rcpp that was compiled with a different compiler or different compiler flags that what you are using to compile your App.

Thank you very much @bgoodri, now I got it working!

Running print(stan_model@dso@cxxflags) in the shinyapp that was compiling at startup revealed the flags used by shinyapps is CXXFLAGS = -g -O2 $(LTO).

1 Like

@lukas-rokka maybe you could share how you managed it?

Compile the model and save it with for example saveRDS(stan_model("model.stan") , "model.rds")

Then deploy the “model.rds” file with your shiny app and load it with stan_model <- readRDS("model.rds") .

If you have a Linux system then you just have to make sure that the your compiler flags also work on shinyapps. Models complied on shinyapps have the flag CXXFLAGS = -g -O2 $(LTO), so using that will work for sure.

If you have windows or mac then you need to compile your model on a unix based server (or on docker). For example this, http://www.louisaslett.com/RStudio_AMI/, comes with rstudio and stan installed and is relativly easy to setup.

5 Likes

So this avoids the memory problem?

yes. The memory is only an issue if you need to compile on shinyapps.

1 Like

Thank you so much for figuring this out and explaining the steps! I’m not very familiar with compiler flags and how to set/use them. Would it be easy(-ish) for you to explain how to make sure the compiler flags are the same in my Linux system as the one used by shinyapps.io? I’ve tried Google but I don’t think I’m using the right search terms to find an explanation that is at my level haha.

1 Like

Replying to myself because, with help from my much more tech-savvy spouse, I figured out where to change the compiler flags.

In your Rstudio instance running on a Linux machine, run makeconf_path() to find the location of the makeconf file. Go to the file (probably using the terminal) and open/edit it using vim/pico/nano/option you like.

In the makeconf file, find the line that says CXXFLAGS = [whatever the default is for your system]. Comment it out (I think you can use # for that) and add a new line. In the new line, write: CXXFLAGS = -g -O2 $(LTO). Save/write out the file.

Restart your Rstudio session, compile your model, check the CXXFLAGS using print(stan_model@dso@cxxflags) to check if the flags are now what they should be. Then you can save the compiled model object in a .rds file and it should work on shinyapps.io!

2 Likes