├── .Rbuildignore ├── .gitattributes ├── .gitignore ├── .travis.yml ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── controlVariates.R ├── data.R ├── dynamics.R ├── install.R ├── setup.R ├── sghmc.R ├── sghmccv.R ├── sgld.R ├── sgldcv.R ├── sgmcmc.R ├── sgnht.R ├── sgnhtcv.R ├── storage.R ├── tfErrors.R ├── update.R └── zzz.R ├── README.md ├── _pkgdown.yml ├── cran-comments.md ├── docs ├── LICENSE.html ├── articles │ ├── gaussMixture.html │ ├── gaussMixture_files │ │ └── figure-html │ │ │ └── unnamed-chunk-9-1.png │ ├── index.html │ ├── logisticRegression.html │ ├── logisticRegression_files │ │ └── figure-html │ │ │ └── unnamed-chunk-10-1.png │ ├── mvGauss.html │ ├── mvGauss_files │ │ └── figure-html │ │ │ └── unnamed-chunk-9-1.png │ ├── nn.html │ └── sgmcmc.html ├── authors.html ├── index.html ├── jquery.sticky-kit.min.js ├── link.svg ├── news │ └── index.html ├── pkgdown.css ├── pkgdown.js └── reference │ ├── covertype.html │ ├── getDataset.html │ ├── getParams.html │ ├── index.html │ ├── initSess.html │ ├── installTF.html │ ├── mnist.html │ ├── sghmc.html │ ├── sghmcSetup.html │ ├── sghmccv.html │ ├── sghmccvSetup.html │ ├── sgld.html │ ├── sgldSetup.html │ ├── sgldcv.html │ ├── sgldcvSetup.html │ ├── sgmcmc.html │ ├── sgmcmcStep.html │ ├── sgnht.html │ ├── sgnhtSetup.html │ ├── sgnhtcv.html │ └── sgnhtcvSetup.html ├── man ├── getDataset.Rd ├── getParams.Rd ├── initSess.Rd ├── installTF.Rd ├── sghmc.Rd ├── sghmcSetup.Rd ├── sghmccv.Rd ├── sghmccvSetup.Rd ├── sgld.Rd ├── sgldSetup.Rd ├── sgldcv.Rd ├── sgldcvSetup.Rd ├── sgmcmc.Rd ├── sgmcmcStep.Rd ├── sgnht.Rd ├── sgnhtSetup.Rd ├── sgnhtcv.Rd └── sgnhtcvSetup.Rd ├── tests ├── testthat.R └── testthat │ ├── test1dGauss.R │ ├── test3dGauss.R │ ├── testFloat64.R │ ├── testMatrixParam.R │ ├── testOptional.R │ ├── testSeeds.R │ ├── testSparse.R │ └── testStepByStep.R └── vignettes ├── .Rhistory ├── gaussMixture.Rmd ├── logisticRegression.Rmd ├── mvGauss.Rmd ├── nn.Rmd └── sgmcmc.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^data-raw$ 2 | ^docs$ 3 | ^_pkgdown\.yml$ 4 | ^LICENSE$ 5 | ^\.travis\.yml$ 6 | ^cran-comments\.md$ 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.html linguist-documentation 2 | *.md linguist-documentation 3 | *.Rmd linguist-documentation 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | temp/ 3 | tests/tmp 4 | data-raw/MNIST-data 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | dist: trusty 3 | language: r 4 | r: 5 | - release 6 | - devel 7 | cache: packages 8 | 9 | before_install: 10 | - sudo apt-get install python 11 | - sudo apt-get install python-pip python-virtualenv 12 | - sudo pip install -U pip 13 | - R -e "install.packages('devtools')" 14 | 15 | install: 16 | - R -e 'devtools::install_deps(dep = T)' 17 | - R -e "devtools::install()" 18 | - R -e "sgmcmc::installTF()" 19 | 20 | script: 21 | - travis_wait 30 R CMD build . --no-build-vignettes 22 | - travis_wait 30 R CMD check *tar.gz --no-build-vignettes --no-vignettes 23 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: sgmcmc 2 | Type: Package 3 | Title: Stochastic Gradient Markov Chain Monte Carlo 4 | Version: 0.2.4 5 | Authors@R: c( 6 | person("Jack", "Baker", email = "j.baker1@lancaster.ac.uk", role = c("aut", "cre", "cph")), 7 | person( "Christopher", "Nemeth", role = c("aut", "cph") ), 8 | person( "Paul", "Fearnhead", role = c( "aut", "cph" ) ), 9 | person( "Emily B.", "Fox", role = c("aut", "cph") ), 10 | person( "STOR-i", role = c( "cph" ) )) 11 | Description: Provides functions that performs popular stochastic gradient Markov chain Monte Carlo (SGMCMC) methods on user specified models. The required gradients are automatically calculated using 'TensorFlow' , an efficient library for numerical computation. This means only the log likelihood and log prior functions need to be specified. The methods implemented include stochastic gradient Langevin dynamics (SGLD), stochastic gradient Hamiltonian Monte Carlo (SGHMC), stochastic gradient Nose-Hoover thermostat (SGNHT) and their respective control variate versions for increased efficiency. References: M. Welling, Y. W. Teh (2011) ; T. Chen, E. B. Fox, C. E. Guestrin (2014) ; N. Ding, Y. Fang, R. Babbush, C. Chen, R. D. Skeel, H. Neven (2014) ; J. Baker, P. Fearnhead, E. B. Fox, C. Nemeth (2017) . 12 | License: GPL-3 13 | Encoding: UTF-8 14 | Depends: R (>= 3.0), tensorflow 15 | Imports: utils, reticulate 16 | SystemRequirements: TensorFlow (https://www.tensorflow.org/), 17 | TensorFlow Probability (https://www.tensorflow.org/probability/) 18 | Suggests: 19 | testthat, 20 | MASS, 21 | knitr, 22 | ggplot2, 23 | rmarkdown 24 | LazyData: true 25 | VignetteBuilder: knitr 26 | RoxygenNote: 6.0.1 27 | URL: https://github.com/STOR-i/sgmcmc 28 | BugReports: https://github.com/STOR-i/sgmcmc/issues 29 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(initSess,sgmcmc) 4 | S3method(initSess,sgmcmccv) 5 | S3method(sgmcmcStep,sghmc) 6 | S3method(sgmcmcStep,sgld) 7 | S3method(sgmcmcStep,sgnht) 8 | export(getDataset) 9 | export(getParams) 10 | export(initSess) 11 | export(installTF) 12 | export(sghmc) 13 | export(sghmcSetup) 14 | export(sghmccv) 15 | export(sghmccvSetup) 16 | export(sgld) 17 | export(sgldSetup) 18 | export(sgldcv) 19 | export(sgldcvSetup) 20 | export(sgmcmcStep) 21 | export(sgnht) 22 | export(sgnhtSetup) 23 | export(sgnhtcv) 24 | export(sgnhtcvSetup) 25 | import(tensorflow) 26 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # sgmcmc 0.2.4 2 | 3 | * Bug fixes 4 | 5 | # sgmcmc 0.2.3 6 | 7 | * Added support for TensorFlow Probability. 8 | 9 | # sgmcmc 0.2.2 10 | 11 | * Made loading TensorFlow distribution objects cleaner. 12 | 13 | # sgmcmc 0.2.1 14 | 15 | * Added better support for sparse variables and minibatching parameters. 16 | 17 | # sgmcmc 0.2.0 18 | 19 | * Added the ability to run algorithms step by step. This allows custom storage of parameters, useful when the full chain does not fit into memory! 20 | * Added new vignette to demonstrate step by step functionality -- a Bayesian neural network model. 21 | * Changed optimizer to TensorFlow SGDOptimizer for control variate methods. 22 | 23 | # sgmcmc 0.1.0 24 | 25 | * Initial release. 26 | -------------------------------------------------------------------------------- /R/controlVariates.R: -------------------------------------------------------------------------------- 1 | # Create generic sgmcmccv object from sgmcmc object 2 | createSGMCMCCV = function( logLik, logPrior, dataset, params, stepsize, optStepsize, 3 | minibatchSize, nItersOpt, seed ) { 4 | # First create generic sgmcmc object then add specifics 5 | sgmcmccv = createSGMCMC( logLik, logPrior, dataset, params, stepsize, minibatchSize, seed ) 6 | # Add nItersOpt for optimization step 7 | sgmcmccv$nItersOpt = nItersOpt 8 | # If minibatchSize is a proportion, convert to an integer 9 | minibatchSize = convertProp( minibatchSize, sgmcmccv$N ) 10 | # Declare TensorFlow variables for initial optimizer 11 | sgmcmccv$paramsOpt = setupParams( params ) 12 | sgmcmccv$placeholdersFull = setupFullPlaceholders( dataset ) 13 | # Declare container for full gradients at mode 14 | sgmcmccv$logPostOptGrad = setupFullGradients( params ) 15 | # Declare estimated log posterior tensor for optimization 16 | sgmcmccv$estLogPostOpt = setupEstLogPost( 17 | logLik, logPrior, sgmcmccv$paramsOpt, sgmcmccv$placeholders, sgmcmccv$N, minibatchSize ) 18 | # Declare full log posterior for calculation at MAP estimate 19 | sgmcmccv$fullLogPostOpt = setupFullLogPost( 20 | logLik, logPrior, sgmcmccv$paramsOpt, sgmcmccv$placeholdersFull ) 21 | # Declare optimizer 22 | sgmcmccv$optimizer = declareOptimizer( sgmcmccv$estLogPostOpt, sgmcmccv$fullLogPostOpt, 23 | sgmcmccv$paramsOpt, sgmcmccv$params, sgmcmccv$logPostOptGrad, optStepsize ) 24 | return( sgmcmccv ) 25 | } 26 | 27 | # This function performs a single optimization step on the control variate parameters. 28 | # This initial optimization procedure is needed before SGMCMCCV is applied in order to 29 | # ensure the control variate parameters estimate the mode well. 30 | optUpdate = function( sgmcmc, sess ) { 31 | feedCurr = dataFeed( sgmcmc$data, sgmcmc$placeholders, sgmcmc$n ) 32 | sess$run( sgmcmc$optimizer$update, feed_dict = feedCurr ) 33 | } 34 | 35 | # Initial optimization of parameters for Control Variate methods. 36 | # Needed to ensure control variate parameters estimate posterior mode. 37 | getMode = function( sgmcmc, sess, verbose = TRUE ) { 38 | # If verbose parameter is TRUE, print progress 39 | if ( verbose ) { 40 | message( "\nFinding initial MAP estimates..." ) 41 | } 42 | for ( i in 1:sgmcmc$nItersOpt ) { 43 | # Single update of optimization 44 | optUpdate( sgmcmc, sess ) 45 | if ( i %% 100 == 0 ) { 46 | checkOptDivergence( sgmcmc, sess, i, verbose ) 47 | } 48 | } 49 | # Calculate the full gradient of the log posterior (i.e. using the full dataset) 50 | # at the mode estimates 51 | calcFullGrads( sgmcmc, sess ) 52 | } 53 | 54 | # Declare full log posterior density from logLik and logPrior functions 55 | setupFullLogPost = function( logLik, logPrior, params, placeholders ) { 56 | # Separate function from setupEstLogPost avoids float precision errors from correction term 57 | if ( is.null( logPrior ) ) { 58 | logPost = logLik( params, placeholders ) 59 | } else { 60 | logPost = logPrior( params ) + logLik( params, placeholders ) 61 | } 62 | return( logPost ) 63 | } 64 | 65 | # Create TensorFlow placeholders to hold full dataset for full log posterior calculation 66 | setupFullPlaceholders = function( data ) { 67 | tfPlaceholders = list() 68 | for ( dname in names( data ) ) { 69 | current_size = getShape( data[[dname]] ) 70 | tfPlaceholders[[dname]] = tf$placeholder( tf$float32, current_size ) 71 | } 72 | return( tfPlaceholders ) 73 | } 74 | 75 | # Create TensorFlow variables to hold estimates of the full log posterior gradient at the mode 76 | setupFullGradients = function( params ) { 77 | gradientContainer = list() 78 | for ( pname in names( params ) ) { 79 | gradientContainer[[pname]] = tf$Variable( params[[pname]], dtype = tf$float32 ) 80 | } 81 | return( gradientContainer ) 82 | } 83 | 84 | # Initialize optimizer which finds estimates of the mode of the log posterior 85 | declareOptimizer = function( estLogPost, fullLogPost, paramsOpt, params, gradFull, optStepsize ) { 86 | optSteps = list() 87 | optimizer = tf$train$GradientDescentOptimizer( optStepsize ) 88 | optSteps[["update"]] = optimizer$minimize( -estLogPost ) 89 | optSteps[["fullCalc"]] = list() 90 | optSteps[["reassign"]] = list() 91 | for ( pname in names( paramsOpt ) ) { 92 | # Declare current parameters 93 | paramOptCurr = paramsOpt[[pname]] 94 | paramCurr = params[[pname]] 95 | # Declare procedure to calculate the full log posterior gradient at the mode 96 | grad = tf$gradients( fullLogPost, paramOptCurr )[[1]] 97 | optSteps$fullCalc[[pname]] = gradFull[[pname]]$assign( grad ) 98 | # This procedure assigns the MCMC starting values to the mode estimates 99 | optSteps$reassign[[pname]] = paramCurr$assign( paramOptCurr ) 100 | } 101 | return( optSteps ) 102 | } 103 | 104 | # Calculates full log posterior gradient estimate at the mode 105 | calcFullGrads = function( sgmcmc, sess ) { 106 | feedCurr = feedFullDataset( sgmcmc$data, sgmcmc$placeholdersFull ) 107 | for ( pname in names( sgmcmc$params ) ) { 108 | sess$run( sgmcmc$optimizer$fullCalc[[pname]], feed_dict = feedCurr ) 109 | sess$run( sgmcmc$optimizer$reassign[[pname]] ) 110 | } 111 | } 112 | 113 | # Check divergence of optimization procedure and print progress if verbose == TRUE 114 | checkOptDivergence = function( sgmcmc, sess, iter, verbose ) { 115 | currentEstimate = sess$run( sgmcmc$estLogPostOpt, feed_dict = dataFeed( sgmcmc$data, 116 | sgmcmc$placeholders, sgmcmc$n ) ) 117 | # If log posterior estimate is NAN, chain is diverged, stop 118 | if ( is.nan( currentEstimate ) ) { 119 | stop("Chain diverged") 120 | } 121 | if ( verbose ) { 122 | message( paste0( "Iteration: ", iter, "\t\tLog posterior estimate: ", currentEstimate ) ) 123 | } 124 | } 125 | 126 | # Feeds the full dataset to the current operation, used by calcFullGrads 127 | feedFullDataset = function( data, placeholders ) { 128 | feed_dict = dict() 129 | for ( input in names( placeholders ) ) { 130 | feed_dict[[ placeholders[[input]] ]] = data[[input]] 131 | } 132 | return( feed_dict ) 133 | } 134 | 135 | -------------------------------------------------------------------------------- /R/data.R: -------------------------------------------------------------------------------- 1 | #' Load example datasets 2 | #' 3 | #' Download and load one of the example datasets for the package: 4 | #' \code{covertype} or \code{mnist}. 5 | #' These datasets are required for the vignettes in the package. 6 | #' The code generating these datasets is available at \url{https://github.com/jbaker92/sgmcmc-data}. 7 | #' 8 | #' @param dataset string which determines the dataset to load: 9 | #' either \code{"covertype"} or \code{"mnist"}. 10 | #' 11 | #' @return Returns the desired dataset. The next two sections give more details about each dataset. 12 | #' 13 | #' @section covertype: 14 | #' 15 | #' The samples in this dataset correspond to 30×30m patches of forest in the US, 16 | #' collected for the task of predicting each patch’s cover type, 17 | #' i.e. the dominant species of tree. 18 | #' We use the LIBSVM dataset, which transforms the data to a binary problem rather than multiclass. 19 | #' 20 | #' format: A matrix with 581012 rows and 55 variables. The first column is the 21 | #' classification labels, the other columns are the 54 explanatory variables. 22 | #' 23 | #' source: \url{https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary.html} 24 | #' 25 | #' @section mnist: 26 | #' 27 | #' The MNIST dataset is a dataset of handwritten digits from 0-9. Each image is 28x28 pixels. 28 | #' We can interpret this as a large matrix of numbers, representing the value at each pixel. 29 | #' These 28x28 matrices are then flattened to be vectors of length 784. For each image, there 30 | #' is an associated label, which determines which digit the image is of. This image is encoded 31 | #' as a vector of length 10, where element i is 1 if the digit is i-1 and 0 otherwise. 32 | #' The dataset is split into two parts: 55,000 data points of training data 33 | #' and 10,000 points of test data. 34 | #' 35 | #' format: A list with two elements \code{train} and \code{test}. 36 | #' \itemize{ 37 | #' \item The training set mnist$train is a list with two entries: images and labels, 38 | #' located at mnist$train$images, mnist$train$labels respectively. 39 | #' \item The dataset mnist$train$images is a matrix of size 55000x784, 40 | #' the labels mnist$train$labels is a matrix of size 55000x10. 41 | #' \item The test set mnist$test is a list with two entries: images and labels, 42 | #' located at mnist$test$images, mnist$test$labels respectively. 43 | #' \item The dataset mnist$test$images is a matrix of size 10000x784, 44 | #' the labels mnist$test$labels is a matrix of size 10000x10. } 45 | #' 46 | #' source: \url{http://yann.lecun.com/exdb/mnist/} 47 | #' 48 | #' @export 49 | #' 50 | #' @examples 51 | #' \dontrun{ 52 | #' # Download the covertype dataset 53 | #' covertype = get_dataset("covertype") 54 | #' # Download the mnist dataset 55 | #' mnist = get_dataset("mnist") 56 | #' } 57 | getDataset = function(dataset) { 58 | if ( dataset != "covertype" && dataset != "mnist" ) { 59 | stop("Only covertype and mnist datasets are available") 60 | } 61 | temp = tempfile() 62 | utils::download.file("https://github.com/jbaker92/sgmcmc-data/archive/master.tar.gz", temp) 63 | extr_temp = tempfile() 64 | utils::untar(temp, exdir = extr_temp) 65 | load(paste0(extr_temp, "/sgmcmc-data-master/data/", dataset, ".rda")) 66 | return(get(dataset)) 67 | } 68 | -------------------------------------------------------------------------------- /R/dynamics.R: -------------------------------------------------------------------------------- 1 | # Define declareDynamics generic, defined separately for each SGMCMC method 2 | # @param sgmcmc a stochastic gradient mcmc object, as defined in the respective modules sgld.r etc. 3 | declareDynamics = function( sgmcmc, seed ) UseMethod("declareDynamics") 4 | 5 | # Declare the TensorFlow steps needed for one step of SGLD 6 | # @param sgld is an sgld object 7 | declareDynamics.sgld = function( sgld, seed ) { 8 | # dynamics is returned, contains list of TensorFlow steps for SGLD 9 | dynamics = list() 10 | # Get the correct gradient estimate given the sgld object (i.e. standard sgld or sgldcv) 11 | estLogPostGrads = getGradients( sgld ) 12 | # Loop over each parameter in params 13 | for ( pname in names( sgld$params ) ) { 14 | # Declare simulation parameters 15 | theta = sgld$params[[pname]] 16 | epsilon = sgld$stepsize[[pname]] 17 | grad = estLogPostGrads[[pname]] 18 | # Check if gradient is IndexedSlices object, e.g. if tf$gather was used 19 | isSparse = checkSparse(grad) 20 | # Predeclare injected noise 21 | noise = sqrt(0.5) * getNoise(isSparse, grad, epsilon, seed) 22 | # Declare dynamics, using sparse updates if grad is IndexedSlices object 23 | if (isSparse) { 24 | updateCurr = 0.5 * epsilon * grad$values + noise 25 | dynamics[[pname]] = tf$scatter_add(theta, grad$indices, updateCurr) 26 | } else { 27 | dynamics[[pname]] = theta$assign_add(0.5 * epsilon * grad + noise) 28 | } 29 | } 30 | return( dynamics ) 31 | } 32 | 33 | # Declare the TensorFlow steps needed for one step of SGHMC, input SGHMC object 34 | # @param is an sghmc object 35 | declareDynamics.sghmc = function( sghmc, seed ) { 36 | dynamics = list( "theta" = list(), "nu" = list(), "refresh" = list(), "grad" = list() ) 37 | # Get the correct gradient estimate given the sgld object (i.e. standard sgld or sgldcv) 38 | estLogPostGrads = getGradients( sghmc ) 39 | # Loop over each parameter in params 40 | for ( pname in names( sghmc$params ) ) { 41 | dynamics$grad[[pname]] = tf$gradients( sghmc$estLogPost, sghmc$params[[pname]] )[[1]] 42 | # Declare tuning constants 43 | stepsize = sghmc$stepsize[[pname]] 44 | alpha = sghmc$alpha[[pname]] 45 | # Declare parameters 46 | theta = sghmc$params[[pname]] 47 | nu = tf$Variable( sqrt( stepsize ) * tf$random_normal( theta$get_shape(), seed = seed ) ) 48 | # Declare dynamics 49 | gradU = estLogPostGrads[[pname]] 50 | # Check if gradient is IndexedSlices object, e.g. if tf$gather was used 51 | isSparse = checkSparse(gradU) 52 | # Predeclare injected noise 53 | noise = getNoise(isSparse, gradU, stepsize, seed) 54 | # Declare dynamics, using sparse updates if grad is IndexedSlices object 55 | if (isSparse) { 56 | dynamics$refresh[[pname]] = tf$scatter_update(nu, gradU$indices, 0.5 * noise) 57 | nuCurr = tf$gather(nu, gradU$indices) 58 | updateCurr = stepsize * gradU$values - alpha * nuCurr + sqrt(alpha) * noise 59 | dynamics$nu[[pname]] = tf$scatter_add(nu, gradU$indices, updateCurr) 60 | dynamics$theta[[pname]] = tf$scatter_add(theta, gradU$indices, nuCurr) 61 | } else { 62 | dynamics$refresh[[pname]] = nu$assign(0.5 * noise) 63 | updateCurr = stepsize * gradU - alpha * nu + sqrt(alpha) * noise 64 | dynamics$nu[[pname]] = nu$assign_add(updateCurr) 65 | dynamics$theta[[pname]] = theta$assign_add(nu) 66 | } 67 | } 68 | return( dynamics ) 69 | } 70 | 71 | # Declare the TensorFlow steps needed for one step of SGNHT 72 | # @param sgnht is an sgnht object 73 | declareDynamics.sgnht = function( sgnht, seed ) { 74 | dynamics = list( "theta" = list(), "u" = list(), "alpha" = list() ) 75 | estLogPostGrads = getGradients( sgnht ) 76 | # Loop over each parameter in params 77 | for ( pname in names(sgnht$params) ) { 78 | # Get constants for this parameter 79 | stepsize = sgnht$stepsize[[pname]] 80 | a = sgnht$a[[pname]] 81 | rankTheta = sgnht$ranks[[pname]] 82 | # Declare momentum params 83 | theta = sgnht$params[[pname]] 84 | u = tf$Variable( sqrt(stepsize) * tf$random_normal( theta$get_shape(), seed = seed ) ) 85 | alpha = tf$Variable( a, dtype = tf$float32 ) 86 | # Declare dynamics 87 | gradU = estLogPostGrads[[pname]] 88 | # Check if gradient is IndexedSlices object, e.g. if tf$gather was used 89 | isSparse = checkSparse(gradU) 90 | # Predeclare injected noise 91 | noise = sqrt(a) * getNoise(isSparse, gradU, stepsize, seed) 92 | # Declare dynamics, using sparse updates if grad is IndexedSlices object 93 | if (isSparse) { 94 | uCurr = tf$gather(u, gradU$indices) 95 | uUpdate = stepsize * gradU$values - tf$multiply(alpha, uCurr) + noise 96 | dynamics$u[[pname]] = tf$scatter_add(u, gradU$indices, uUpdate) 97 | dynamics$theta[[pname]] = tf$scatter_add(theta, gradU$indices, uCurr) 98 | axes = matrix( rep( 0:( rankTheta - 1 ), each = 2 ), nrow = 2 ) 99 | axes = tf$constant( axes, dtype = tf$int32 ) 100 | aUpdate = tf$tensordot( uCurr, uCurr, axes ) / tf$size( uCurr, out_type = tf$float32 ) 101 | dynamics$alpha[[pname]] = alpha$assign_add(aUpdate - stepsize) 102 | } else { 103 | dynamics$u[[pname]] = u$assign_add(stepsize * gradU - u * alpha + noise) 104 | dynamics$theta[[pname]] = theta$assign_add(u) 105 | # Tensordot throws error if rank is 0 so catch this edge case 106 | # For parameters of higher order than vectors we use tensor contraction 107 | # to calculate the inner product for the thermostat. 108 | if ( rankTheta == 0 ) { 109 | dynamics$alpha[[pname]] = alpha$assign_add( u * u - stepsize ) 110 | } else if( rankTheta >= 1 ) { 111 | # Declare axes for tensor contraction 112 | axes = matrix( rep( 0:( rankTheta - 1 ), each = 2 ), nrow = 2 ) 113 | axes = tf$constant( axes, dtype = tf$int32 ) 114 | dynamics$alpha[[pname]] = alpha$assign_add( 115 | tf$tensordot( u, u, axes ) / tf$size( u, out_type = tf$float32 ) - stepsize ) 116 | } 117 | } 118 | } 119 | return( dynamics ) 120 | } 121 | 122 | 123 | # Check if gradient is indexed slices object 124 | checkSparse = function(grad) { 125 | isSparse = tryCatch({ 126 | temp = grad$indices 127 | TRUE 128 | }, error = function (e) { 129 | return(FALSE) 130 | }) 131 | return(isSparse) 132 | } 133 | 134 | # Declare injected noise 135 | getNoise = function(gathered, grad, epsilon, seed) { 136 | if (gathered) { 137 | noise = sqrt(2 * epsilon) * tf$random_normal(tf$shape(grad$values), seed = seed) 138 | } else { 139 | noise = sqrt(2 * epsilon) * tf$random_normal(tf$shape(grad), seed = seed) 140 | } 141 | return(noise) 142 | } 143 | -------------------------------------------------------------------------------- /R/install.R: -------------------------------------------------------------------------------- 1 | #' Install TensorFlow and TensorFlow Probability 2 | #' 3 | #' Install the python packages required by sgmcmc, including TensorFlow and TensorFlow probability. 4 | #' Uses the tensorflow::install_tensorflow function. 5 | #' @export 6 | installTF = function() { 7 | install_tensorflow() 8 | } 9 | -------------------------------------------------------------------------------- /R/setup.R: -------------------------------------------------------------------------------- 1 | # Create generic sgmcmc object 2 | createSGMCMC = function( logLik, logPrior, dataset, params, stepsize, minibatchSize, seed ) { 3 | # First check tf installation using tf_status. Throw error if it isn't installed. 4 | #checkTFInstall() #comment this out for now until we set-up a better package check 5 | # Set seed if required, TensorFlow seeds set inside dynamics 6 | if ( !is.null( seed ) ) { 7 | tf$set_random_seed(seed) 8 | set.seed(seed) 9 | } 10 | # Get dataset size 11 | N = getDatasetSize( dataset ) 12 | # If minibatchSize is a proportion, convert to an integer 13 | minibatchSize = convertProp( minibatchSize, N ) 14 | # Convert params and dataset to TensorFlow variables and placeholders 15 | paramstf = setupParams( params ) 16 | placeholders = setupPlaceholders( dataset, minibatchSize ) 17 | # Declare estimated log posterior tensor using declared variables and placeholders 18 | # Check for tf$float64 errors (we only use tf$float32), if so throw a more explanatory error 19 | estLogPost = tryCatch({ 20 | setupEstLogPost( logLik, logPrior, paramstf, placeholders, N, minibatchSize ) 21 | }, error = function ( e ) getPosteriorBuildError( e ) ) 22 | # Check stepsize tuning constants are in list format 23 | stepsize = convertList( stepsize, params ) 24 | # Declare sgmcmc object as list, return for custom tuning constants to be added by calling method 25 | sgmcmc = list( "N" = N, "data" = dataset, "n" = minibatchSize, "placeholders" = placeholders, 26 | "stepsize" = stepsize, "params" = paramstf, "estLogPost" = estLogPost ) 27 | return( sgmcmc ) 28 | } 29 | 30 | # getGradients generic defines different gradient estimates for 31 | # control variate and non-control variate methods 32 | # @param sgmcmc a stochastic gradient mcmc object, as defined in the respective modules sgld.r etc. 33 | getGradients = function( sgmcmc ) UseMethod("getGradients") 34 | 35 | # Get gradient estimates for standard SGMCMC method 36 | getGradients.sgmcmc = function( sgmcmc ) { 37 | estLogPostGrads = list() 38 | for ( pname in names( sgmcmc$params ) ) { 39 | estLogPostGrads[[pname]] = tf$gradients( sgmcmc$estLogPost, sgmcmc$params[[pname]] )[[1]] 40 | } 41 | return( estLogPostGrads ) 42 | } 43 | 44 | # Get gradient estimates for control variate methods, handle IndexedSlices gradients gracefully 45 | getGradients.sgmcmccv = function( sgmcmcCV ) { 46 | estLogPostGrads = list() 47 | for ( pname in names( sgmcmcCV$params ) ) { 48 | gradCurr = tf$gradients( sgmcmcCV$estLogPost, sgmcmcCV$params[[pname]] )[[1]] 49 | isSparse = gradIsIndexed(gradCurr) 50 | optGradCurr = tf$gradients( sgmcmcCV$estLogPostOpt, sgmcmcCV$paramsOpt[[pname]] )[[1]] 51 | optGradFull = sgmcmcCV$logPostOptGrad[[pname]] 52 | if (isSparse) { 53 | # Get the current gradient estimate but ensure to keep it as IndexedSlices object 54 | fullGradCurr = tf$gather(optGradFull, gradCurr$indices) 55 | currentVals = fullGradCurr - optGradCurr$values + gradCurr$values 56 | estLogPostGrads[[pname]] = tf$IndexedSlices(currentVals, gradCurr$indices) 57 | } else { 58 | estLogPostGrads[[pname]] = optGradFull - optGradCurr + gradCurr 59 | } 60 | } 61 | return( estLogPostGrads ) 62 | } 63 | 64 | # Check if gradCurr is IndexedSlices object for minibatched parameters 65 | gradIsIndexed = function(grad) { 66 | isSparse = tryCatch({ 67 | temp = grad$indices 68 | TRUE 69 | }, error = function (e) { 70 | return(FALSE) 71 | }) 72 | return(isSparse) 73 | } 74 | 75 | # Calculate size of dataset 76 | getDatasetSize = function( data ) { 77 | N = dim( data[[1]] )[1] 78 | # Check edge case that data[[1]] is 1d 79 | if ( is.null( N ) ) { 80 | N = length( data[[1]] ) 81 | } 82 | return( N ) 83 | } 84 | 85 | # Calculate shape of dataset and params 86 | getShape = function( input ) { 87 | shapeInput = dim( input ) 88 | # Check edge case that input[[1]] is 1d 89 | if ( is.null( shapeInput ) ) { 90 | shapeInput = c( length( input ) ) 91 | } 92 | return( shapeInput ) 93 | } 94 | 95 | # Redeclare parameters as TensorFlow variables, initialize at starting values 96 | setupParams = function( params ) { 97 | tfParams = list() 98 | for ( pname in names( params ) ) { 99 | tfParams[[pname]] = tf$Variable( params[[pname]], dtype = tf$float32 ) 100 | } 101 | return( tfParams ) 102 | } 103 | 104 | # Declare TensorFlow placeholders for each dataset based on data list and minibatch size n 105 | setupPlaceholders = function( data, n ) { 106 | tfPlaceholders = list() 107 | for ( dname in names( data ) ) { 108 | shapeCurr = getShape( data[[dname]] ) 109 | shapeCurr[1] = n 110 | tfPlaceholders[[dname]] = tf$placeholder( tf$float32, shapeCurr ) 111 | } 112 | return( tfPlaceholders ) 113 | } 114 | 115 | # Use defined logLik & logPrior functions to declare unbiased estimate of log posterior 116 | setupEstLogPost = function( logLik, logPrior, params, placeholders, N, n ) { 117 | correction = tf$constant( N / n, dtype = tf$float32 ) 118 | # If logPrior is NULL then use uninformative prior 119 | if ( is.null( logPrior ) ) { 120 | estLogPost = correction * logLik( params, placeholders ) 121 | } else { 122 | estLogPost = logPrior( params ) + correction * logLik( params, placeholders ) 123 | } 124 | return( estLogPost ) 125 | } 126 | 127 | # If minibatch size is a proportion (i.e. < 1) convert to an integer 128 | convertProp = function( minibatchSize, N ) { 129 | if ( minibatchSize < 1 ) { 130 | out = round( minibatchSize * N ) 131 | if ( out == 0 ) { 132 | stop( paste0( "minibatchSize proportion (", minibatchSize, 133 | ") too small for dataset size (", N, ")." ) ) 134 | } else { 135 | return( round( minibatchSize * N ) ) 136 | } 137 | } else { 138 | return( minibatchSize ) 139 | } 140 | } 141 | 142 | # Get the rank of each of the parameter objects, needed for sghmc 143 | # @assume paramsRaw object is the original list of numeric R arrays, not TensorFlow tensors 144 | getRanks = function( paramsRaw ) { 145 | ranks = list() 146 | for ( pname in names( paramsRaw ) ) { 147 | param = paramsRaw[[pname]] 148 | # Catch case that param is a vector 149 | if ( is.null( dim( param ) ) ) { 150 | ranks[[pname]] = as.numeric( length( param ) > 1 ) 151 | } else { 152 | ranks[[pname]] = length( dim( param ) ) 153 | } 154 | } 155 | return( ranks ) 156 | } 157 | 158 | # If stepsizes or a or alpha tuning constants are not in a list 159 | # format then convert to a list format 160 | convertList = function( tuningConst, params ) { 161 | # Do nothing if already a list 162 | if( typeof( tuningConst ) == "list" ) { 163 | return( tuningConst ) 164 | } 165 | convertedConsts = list() 166 | for ( pname in names( params ) ) { 167 | convertedConsts[[pname]] = tuningConst 168 | } 169 | return( convertedConsts ) 170 | } 171 | -------------------------------------------------------------------------------- /R/sghmc.R: -------------------------------------------------------------------------------- 1 | #' Stochastic Gradient Hamiltonian Monte Carlo 2 | #' 3 | #' Simulates from the posterior defined by the functions logLik and logPrior using 4 | #' stochastic gradient Hamiltonian Monte Carlo. The function uses TensorFlow, so needs 5 | #' TensorFlow for python installed. Currently we use the approximation \eqn{\hat \beta = 0}, 6 | #' as used in the simulations by the original reference. 7 | #' This will be changed in future implementations. 8 | #' 9 | #' @references \itemize{\item \href{https://arxiv.org/pdf/1402.4102v2.pdf}{ 10 | #' Chen, T., Fox, E. B., and Guestrin, C. (2014). Stochastic gradient Hamiltonian Monte Carlo. 11 | #' In ICML (pp. 1683-1691).}} 12 | #' 13 | #' @inheritParams sgld 14 | #' @param alpha optional. Default 0.01. 15 | #' List of numeric values corresponding to the SGHMC momentum tuning constants 16 | #' (\eqn{\alpha} in the original paper). One value should be given 17 | #' for each parameter in params, the names should correspond to those in params. 18 | #' Alternatively specify a single float to specify that value for all parameters. 19 | #' @param L optional. Default 5L. Integer specifying the trajectory parameter of the simulation, 20 | #' as defined in the main reference. 21 | #' 22 | #' @return Returns list of arrays for each parameter containing the MCMC chain. 23 | #' Dimension of the form (nIters,paramDim1,paramDim2,...) 24 | #' 25 | #' @export 26 | #' 27 | #' @examples 28 | #' \dontrun{ 29 | #' # Simulate from a Normal Distribution with uninformative, improper prior 30 | #' dataset = list("x" = rnorm(1000)) 31 | #' params = list("theta" = 0) 32 | #' logLik = function(params, dataset) { 33 | #' distn = tf$distributions$Normal(params$theta, 1) 34 | #' return(tf$reduce_sum(distn$log_prob(dataset$x))) 35 | #' } 36 | #' stepsize = list("theta" = 1e-5) 37 | #' output = sghmc(logLik, dataset, params, stepsize) 38 | #' # For more examples see vignettes 39 | #' } 40 | sghmc = function( logLik, dataset, params, stepsize, logPrior = NULL, minibatchSize = 0.01, 41 | alpha = 0.01, L = 5L, nIters = 10^4L, verbose = TRUE, seed = NULL ) { 42 | # Setup SGHMC object 43 | sghmc = sghmcSetup( logLik, dataset, params, stepsize, logPrior, minibatchSize, alpha, L, seed ) 44 | options = list( "nIters" = nIters, "verbose" = verbose ) 45 | # Run MCMC for declared object 46 | paramStorage = runSGMCMC( sghmc, params, options ) 47 | return( paramStorage ) 48 | } 49 | 50 | #' Create an sghmc object 51 | #' 52 | #' Creates an sghmc (stochastic gradient Hamiltonian Monte Carlo) object which can be passed to 53 | #' \code{\link{sgmcmcStep}} to simulate from 1 step of SGLD for the posterior defined by logLik 54 | #' and logPrior. This allows the user to code the loop themselves, as in many standard 55 | #' TensorFlow procedures (such as optimization). Which means they do not need to store 56 | #' the chain at each iteration. This is useful when the full chain needs a lot of memory. 57 | #' 58 | #' @inheritParams sghmc 59 | #' 60 | #' @return The function returns an 'sghmc' object, which is used to pass the required information 61 | #' about the current model to the \code{\link{sgmcmcStep}} function. The function 62 | #' \code{\link{sgmcmcStep}} runs one step of sghmc. The sghmc object has the following attributes: 63 | #' \describe{ 64 | #' \item{params}{list of tf$Variables with the same names as the params list passed to 65 | #' \code{\link{sghmcSetup}}. This is the object passed to the logLik and logPrior functions you 66 | #' declared to calculate the log posterior gradient estimate.} 67 | #' \item{estLogPost}{a tensor that estimates the log posterior given the current 68 | #' placeholders and params.} 69 | #' \item{N}{dataset size.} 70 | #' \item{data}{dataset as passed to \code{\link{sghmcSetup}}.} 71 | #' \item{n}{minibatchSize as passed to \code{\link{sghmcSetup}}.} 72 | #' \item{placeholders}{list of tf$placeholder objects with the same names as dataset 73 | #' used to feed minibatches of data to \code{\link{sgmcmcStep}}. These objects 74 | #' get fed to the dataset argument of the logLik and logPrior functions you declared.} 75 | #' \item{stepsize}{list of stepsizes as passed to \code{\link{sghmcSetup}}.} 76 | #' \item{alpha}{list of alpha tuning parameters as passed to \code{\link{sghmcSetup}}.} 77 | #' \item{L}{integer trajectory parameter as passed to \code{\link{sghmcSetup}}.} 78 | #' \item{dynamics}{a list of TensorFlow steps that are evaluated by \code{\link{sgmcmcStep}}.}} 79 | #' 80 | #' @export 81 | #' 82 | #' @examples 83 | #' \dontrun{ 84 | #' # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 85 | #' # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 86 | #' dataset = list("x" = rnorm(1000)) 87 | #' params = list("theta" = 0) 88 | #' logLik = function(params, dataset) { 89 | #' distn = tf$distributions$Normal(params$theta, 1) 90 | #' return(tf$reduce_sum(distn$log_prob(dataset$x))) 91 | #' } 92 | #' stepsize = list("theta" = 1e-4) 93 | #' sghmc = sghmcSetup(logLik, dataset, params, stepsize) 94 | #' nIters = 10^4L 95 | #' # Initialize location estimate 96 | #' locEstimate = 0 97 | #' # Initialise TensorFlow session 98 | #' sess = initSess(sghmc) 99 | #' for ( i in 1:nIters ) { 100 | #' sgmcmcStep(sghmc, sess) 101 | #' locEstimate = locEstimate + 1 / nIters * getParams(sghmc, sess)$theta 102 | #' } 103 | #' # For more examples see vignettes 104 | #' } 105 | sghmcSetup = function( logLik, dataset, params, stepsize, logPrior = NULL, minibatchSize = 0.01, 106 | alpha = 0.01, L = 5L, seed = NULL ) { 107 | # Create generic sgmcmc object 108 | sghmc = createSGMCMC( logLik, logPrior, dataset, params, stepsize, minibatchSize, seed ) 109 | # Add SGHMC specific tuning constants and check they're in list format 110 | sghmc$alpha = convertList( alpha, sghmc$params ) 111 | sghmc$L = L 112 | # Declare object type 113 | class( sghmc ) = c( "sghmc", "sgmcmc" ) 114 | # Declare SGHMC dynamics 115 | sghmc$dynamics = declareDynamics( sghmc, seed ) 116 | return( sghmc ) 117 | } 118 | -------------------------------------------------------------------------------- /R/sgld.R: -------------------------------------------------------------------------------- 1 | #' Stochastic Gradient Langevin Dynamics 2 | #' 3 | #' Simulates from the posterior defined by the functions logLik and logPrior using 4 | #' stochastic gradient Langevin Dynamics. The function uses TensorFlow, so needs 5 | #' TensorFlow for python installed. 6 | #' 7 | #' @references \itemize{\item \href{http://people.ee.duke.edu/~lcarin/398_icmlpaper.pdf}{ 8 | #' Welling, M., and Teh, Y. W. (2011). Bayesian learning via stochastic gradient Langevin dynamics. 9 | #' ICML (pp. 681-688).}} 10 | #' 11 | #' @param logLik function which takes parameters and dataset 12 | #' (list of TensorFlow variables and placeholders respectively) as input. 13 | #' It should return a TensorFlow expression which defines the log likelihood of the model. 14 | #' @param dataset list of numeric R arrays which defines the datasets for the problem. 15 | #' The names in the list should correspond to those referred to in the logLik and logPrior functions 16 | #' @param params list of numeric R arrays which define the starting point of each parameter. 17 | #' The names in the list should correspond to those referred to in the logLik and logPrior functions 18 | #' @param stepsize list of numeric values corresponding to the SGLD stepsizes for each parameter 19 | #' The names in the list should correspond to those in params. 20 | #' Alternatively specify a single numeric value to use that stepsize for all parameters. 21 | #' @param logPrior optional. Default uninformative improper prior. 22 | #' Function which takes parameters (list of TensorFlow variables) as input. 23 | #' The function should return a TensorFlow tensor which defines the log prior of the model. 24 | #' @param minibatchSize optional. Default 0.01. 25 | #' Numeric or integer value that specifies amount of dataset to use at each iteration 26 | #' either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer). 27 | #' @param nIters optional. Default 10^4L. Integer specifying number of iterations to perform. 28 | #' @param verbose optional. Default TRUE. Boolean specifying whether to print algorithm progress 29 | #' @param seed optional. Default NULL. Numeric seed for random number generation. The default 30 | #' does not declare a seed for the TensorFlow session. 31 | #' 32 | #' @return Returns list of arrays for each parameter containing the MCMC chain. 33 | #' Dimension of the form (nIters,paramDim1,paramDim2,...) 34 | #' 35 | #' @export 36 | #' 37 | #' @examples 38 | #' \dontrun{ 39 | #' # Simulate from a Normal Distribution with uninformative prior 40 | #' dataset = list("x" = rnorm(1000)) 41 | #' params = list("theta" = 0) 42 | #' logLik = function(params, dataset) { 43 | #' distn = tf$distributions$Normal(params$theta, 1) 44 | #' return(tf$reduce_sum(distn$log_prob(dataset$x))) 45 | #' } 46 | #' stepsize = list("theta" = 1e-4) 47 | #' output = sgld(logLik, dataset, params, stepsize) 48 | #' # For more examples see vignettes 49 | #' } 50 | sgld = function( logLik, dataset, params, stepsize, logPrior = NULL, minibatchSize = 0.01, 51 | nIters = 10^4L, verbose = TRUE, seed = NULL ) { 52 | # Create SGLD object 53 | sgld = sgldSetup( logLik, dataset, params, stepsize, logPrior, minibatchSize, seed ) 54 | options = list( "nIters" = nIters, "verbose" = verbose ) 55 | # Run MCMC for declared object 56 | paramStorage = runSGMCMC( sgld, params, options ) 57 | return( paramStorage ) 58 | } 59 | 60 | 61 | #' Create an sgld object 62 | #' 63 | #' Creates an sgld (stochastic gradient Langevin dynamics) object which can be passed to 64 | #' \code{\link{sgmcmcStep}} to simulate from 1 step of SGLD for the posterior defined by logLik 65 | #' and logPrior. This allows the user to code the loop themselves, as in many standard 66 | #' TensorFlow procedures (such as optimization). Which means they do not need to store 67 | #' the chain at each iteration. This is useful when the full chain needs a lot of memory. 68 | #' 69 | #' @inheritParams sgld 70 | #' 71 | #' @return The function returns an 'sgld' object, which is used to pass the required information 72 | #' about the current model to the \code{\link{sgmcmcStep}} function. The function 73 | #' \code{\link{sgmcmcStep}} runs one step of sgld. The sgld object has the following attributes: 74 | #' \describe{ 75 | #' \item{params}{list of tf$Variables with the same names as the params list passed to 76 | #' \code{\link{sgldSetup}}. This is the object passed to the logLik and logPrior functions you 77 | #' declared to calculate the log posterior gradient estimate.} 78 | #' \item{estLogPost}{a tensor that estimates the log posterior given the current 79 | #' placeholders and params (the placeholders holds the minibatches of data).} 80 | #' \item{N}{dataset size.} 81 | #' \item{data}{dataset as passed to \code{\link{sgldSetup}}.} 82 | #' \item{n}{minibatchSize as passed to \code{\link{sgldSetup}}.} 83 | #' \item{placeholders}{list of tf$placeholder objects with the same names as dataset 84 | #' used to feed minibatches of data to \code{\link{sgmcmcStep}}. These are the objects 85 | #' that get fed to the dataset argument of the logLik and logPrior functions you declared.} 86 | #' \item{stepsize}{list of stepsizes as passed to \code{\link{sgldSetup}}.} 87 | #' \item{dynamics}{a list of TensorFlow steps that are evaluated by \code{\link{sgmcmcStep}}.}} 88 | #' 89 | #' @export 90 | #' 91 | #' @examples 92 | #' \dontrun{ 93 | #' # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 94 | #' # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 95 | #' dataset = list("x" = rnorm(1000)) 96 | #' params = list("theta" = 0) 97 | #' logLik = function(params, dataset) { 98 | #' distn = tf$distributions$Normal(params$theta, 1) 99 | #' return(tf$reduce_sum(distn$log_prob(dataset$x))) 100 | #' } 101 | #' stepsize = list("theta" = 1e-4) 102 | #' sgld = sgldSetup(logLik, dataset, params, stepsize) 103 | #' nIters = 10^4L 104 | #' # Initialize location estimate 105 | #' locEstimate = 0 106 | #' # Initialise TensorFlow session 107 | #' sess = initSess(sgld) 108 | #' for ( i in 1:nIters ) { 109 | #' sgmcmcStep(sgld, sess) 110 | #' locEstimate = locEstimate + 1 / nIters * getParams(sgld, sess)$theta 111 | #' } 112 | #' # For more examples see vignettes 113 | #' } 114 | sgldSetup = function( logLik, dataset, params, stepsize, logPrior = NULL, minibatchSize = 0.01, 115 | seed = NULL ) { 116 | # Create generic sgmcmc object, no extra tuning constants need to be added for sgld 117 | sgld = createSGMCMC( logLik, logPrior, dataset, params, stepsize, minibatchSize, seed ) 118 | # Declare object type 119 | class( sgld ) = c( "sgld", "sgmcmc" ) 120 | # Declare SGLD dynamics 121 | sgld$dynamics = declareDynamics( sgld, seed ) 122 | return( sgld ) 123 | } 124 | -------------------------------------------------------------------------------- /R/sgldcv.R: -------------------------------------------------------------------------------- 1 | #' Stochastic Gradient Langevin Dynamics with Control Variates 2 | #' 3 | #' Simulates from the posterior defined by the functions logLik and logPrior using 4 | #' stochastic gradient Langevin Dynamics with an improved gradient estimate using Control Variates. 5 | #' The function uses TensorFlow, so needs TensorFlow for python installed. 6 | #' 7 | #' @references \itemize{ 8 | #' \item \href{https://arxiv.org/pdf/1706.05439.pdf}{ 9 | #' Baker, J., Fearnhead, P., Fox, E. B., and Nemeth, C. (2017). 10 | #' Control variates for stochastic gradient MCMC. ArXiv preprint arXiv:1706.05439.} 11 | #' \item \href{http://people.ee.duke.edu/~lcarin/398_icmlpaper.pdf}{ 12 | #' Welling, M., and Teh, Y. W. (2011). Bayesian learning via stochastic gradient Langevin dynamics. 13 | #' ICML (pp. 681-688).} } 14 | #' 15 | #' @inheritParams sgld 16 | #' @param optStepsize numeric value specifying the stepsize for the optimization 17 | #' to find MAP estimates of parameters. The TensorFlow GradientDescentOptimizer is used. 18 | #' @param nItersOpt optional. Default 10^4L. 19 | #' Integer specifying number of iterations of initial optimization to perform. 20 | #' 21 | #' @return Returns list of arrays for each parameter containing the MCMC chain. 22 | #' Dimension of the form (nIters,paramDim1,paramDim2,...) 23 | #' 24 | #' @export 25 | #' 26 | #' @examples 27 | #' \dontrun{ 28 | #' # Simulate from a Normal Distribution with uninformative prior 29 | #' dataset = list("x" = rnorm(1000)) 30 | #' params = list("theta" = 0) 31 | #' logLik = function(params, dataset) { 32 | #' distn = tf$distributions$Normal(params$theta, 1) 33 | #' return(tf$reduce_sum(distn$log_prob(dataset$x))) 34 | #' } 35 | #' stepsize = list("theta" = 1e-4) 36 | #' optStepsize = 1e-1 37 | #' output = sgldcv(logLik, dataset, params, stepsize, optStepsize) 38 | #' } 39 | sgldcv = function( logLik, dataset, params, stepsize, optStepsize, logPrior = NULL, 40 | minibatchSize = 0.01, nIters = 10^4L, nItersOpt = 10^4L, verbose = TRUE, seed = NULL ) { 41 | # Setup SGLDCV object 42 | sgldcv = sgldcvSetup( logLik, dataset, params, stepsize, optStepsize, logPrior, minibatchSize, 43 | nItersOpt, verbose, seed ) 44 | options = list( "nIters" = nIters, "nItersOpt" = nItersOpt, "verbose" = verbose ) 45 | # Run MCMC for declared object 46 | paramStorage = runSGMCMC( sgldcv, params, options ) 47 | return( paramStorage ) 48 | } 49 | 50 | 51 | #' Create an sgldcv object 52 | #' 53 | #' Creates an sgldcv (stochastic gradient Langevin Dynamics with Control Variates) object 54 | #' which can be passed to \code{\link{sgmcmcStep}} to simulate from 1 step of sgld, using a 55 | #' gradient estimate with control variates for the posterior defined by logLik and logPrior. 56 | #' This allows the user to code the loop themselves, as in many standard 57 | #' TensorFlow procedures (such as optimization). Which means they do not need to store 58 | #' the chain at each iteration. This is useful when the full chain needs a lot of memory. 59 | #' 60 | #' @inheritParams sgldcv 61 | #' 62 | #' @return The function returns an 'sgldcv' object, a type of sgmcmc object. 63 | #' Which is used to pass the required information about the current model to the 64 | #' \code{\link{sgmcmcStep}} function. The function \code{\link{sgmcmcStep}} runs one 65 | #' step of sgld with a gradient estimate that uses control variates. 66 | #' Attributes of the sgldcv object you'll probably find most useful are: 67 | #' \describe{ 68 | #' \item{params}{list of tf$Variables with the same names as the params list passed to 69 | #' \code{\link{sgldcvSetup}}. This is the object passed to the logLik and logPrior functions you 70 | #' declared to calculate the log posterior gradient estimate.} 71 | #' \item{paramsOpt}{list of tf$Variables with the same names as the \code{params} list passed to 72 | #' \code{\link{sgldcvSetup}}. These variables are used to initially find MAP estimates 73 | #' and then store these optimal parameter estimates.} 74 | #' \item{estLogPost}{a tensor that estimates the log posterior given the current 75 | #' placeholders and params.} 76 | #' \item{logPostOptGrad}{list of \code{tf$Variables} with same names as \code{params}, this stores 77 | #' the full log posterior gradient at each MAP estimate after the initial optimization step.}} 78 | #' Other attributes of the object are as follows: 79 | #' \describe{ 80 | #' \item{N}{dataset size.} 81 | #' \item{data}{dataset as passed to \code{\link{sgldcvSetup}}.} 82 | #' \item{n}{minibatchSize as passed to \code{\link{sgldcvSetup}}.} 83 | #' \item{placeholders}{list of tf$placeholder objects with the same names as dataset 84 | #' used to feed minibatches of data to \code{\link{sgmcmcStep}}. These are also the objects 85 | #' that gets fed to the dataset argument of the logLik and logPrior functions you declared.} 86 | #' \item{stepsize}{list of stepsizes as passed to \code{\link{sgldcvSetup}}} 87 | #' \item{dynamics}{a list of TensorFlow steps that are evaluated by \code{\link{sgmcmcStep}}.} 88 | #' \item{estLogPostOpt}{a TensorFlow tensor relying on \code{paramsOpt} and \code{placeholders} which 89 | #' estimates the log posterior at the optimal parameters. Used in the initial optimization step.} 90 | #' \item{fullLogPostOpt}{a TensorFlow tensor used in the calculation of the full log posterior 91 | #' gradient at the MAP estimates.} 92 | #' \item{optimizer}{a TensorFlow optimizer object used to find the initial MAP estimates.}} 93 | #' 94 | #' @export 95 | #' 96 | #' @examples 97 | #' \dontrun{ 98 | #' # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 99 | #' # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 100 | #' dataset = list("x" = rnorm(1000)) 101 | #' params = list("theta" = 0) 102 | #' logLik = function(params, dataset) { 103 | #' distn = tf$distributions$Normal(params$theta, 1) 104 | #' return(tf$reduce_sum(distn$log_prob(dataset$x))) 105 | #' } 106 | #' stepsize = list("theta" = 1e-4) 107 | #' optStepsize = 1e-1 108 | #' sgldcv = sgldcvSetup(logLik, dataset, params, stepsize, optStepsize) 109 | #' nIters = 10^4L 110 | #' # Initialize location estimate 111 | #' locEstimate = 0 112 | #' # Initialise TensorFlow session 113 | #' sess = initSess(sgldcv) 114 | #' for ( i in 1:nIters ) { 115 | #' sgmcmcStep(sgldcv, sess) 116 | #' locEstimate = locEstimate + 1 / nIters * getParams(sgldcv, sess)$theta 117 | #' } 118 | #' # For more examples see vignettes 119 | #' } 120 | sgldcvSetup = function( logLik, dataset, params, stepsize, optStepsize, logPrior = NULL, 121 | minibatchSize = 0.01, nItersOpt = 10^4L, verbose = TRUE, seed = NULL ) { 122 | # Create generic sgmcmccv object, no extra tuning constants need to be added for sgld 123 | sgldcv = createSGMCMCCV( logLik, logPrior, dataset, params, stepsize, optStepsize, 124 | minibatchSize, nItersOpt, seed ) 125 | class(sgldcv) = c( "sgld", "sgmcmccv", "sgmcmc" ) 126 | # Declare SGLD dynamics 127 | sgldcv$dynamics = declareDynamics( sgldcv, seed ) 128 | return( sgldcv ) 129 | } 130 | -------------------------------------------------------------------------------- /R/sgmcmc.R: -------------------------------------------------------------------------------- 1 | #' sgmcmc: A package for stochastic gradient MCMC 2 | #' 3 | #' The sgmcmc package implements some of the most popular stochastic gradient MCMC methods 4 | #' including SGLD, SGHMC, SGNHT. It also implements control variates as a way to increase 5 | #' the efficiency of these methods. The algorithms are implemented using TensorFlow 6 | #' which means no gradients need to be specified by the user as these are calculated 7 | #' automatically. It also means the algorithms are efficient. 8 | #' 9 | #' @section sgmcmc functions: 10 | #' The main functions of the package are sgld, sghmc and sgnht which implement the methods 11 | #' stochastic gradient Langevin dynamics, stochastic gradient Hamiltonian Monte Carlo and 12 | #' stochastic gradient Nose-Hoover Thermostat respectively. Also included are control variate 13 | #' versions of these algorithms, which uses control variates to increase their efficiency. 14 | #' These are the functions sgldcv, sghmccv and sgnhtcv. 15 | #' 16 | #' @docType package 17 | #' @name sgmcmc 18 | #' 19 | #' @import tensorflow 20 | #' 21 | #' @references Baker, J., Fearnhead, P., Fox, E. B., & Nemeth, C. (2017) 22 | #' control variates for stochastic gradient Langevin dynamics. Preprint. 23 | #' 24 | #' @references Welling, M., & Teh, Y. W. (2011). 25 | #' Bayesian learning via stochastic gradient Langevin dynamics. ICML (pp. 681-688). 26 | #' 27 | #' @references Chen, T., Fox, E. B., & Guestrin, C. (2014). 28 | #' stochastic gradient Hamiltonian Monte Carlo. In ICML (pp. 1683-1691). 29 | #' 30 | #' @references Ding, N., Fang, Y., Babbush, R., Chen, C., Skeel, R. D., & Neven, H. (2014). 31 | #' Bayesian sampling using stochastic gradient thermostats. NIPS (pp. 3203-3211). 32 | #' 33 | NULL 34 | -------------------------------------------------------------------------------- /R/sgnht.R: -------------------------------------------------------------------------------- 1 | #' Stochastic Gradient Nose Hoover Thermostat 2 | #' 3 | #' Simulates from the posterior defined by the functions logLik and logPrior using 4 | #' stochastic gradient Nose Hoover Thermostat. 5 | #' The thermostat step needs a dot product to be calculated between two vectors. 6 | #' So when the algorithm uses parameters that are higher order than vectors 7 | #' (e.g. matrices and tensors), the thermostat step uses a tensor contraction. 8 | #' Tensor contraction is otherwise known as the inner product between two tensors. 9 | #' 10 | #' @references \itemize{\item \href{http://people.ee.duke.edu/~lcarin/sgnht-4.pdf}{ 11 | #' Ding, N., Fang, Y., Babbush, R., Chen, C., Skeel, R. D., and Neven, H. (2014). 12 | #' Bayesian sampling using stochastic gradient thermostats. NIPS (pp. 3203-3211).}} 13 | #' 14 | #' @inheritParams sgld 15 | #' @param a optional. Default 0.01. List of numeric values corresponding to SGNHT diffusion factors 16 | #' (see Algorithm 2 of the original paper). One value should be given 17 | #' for each parameter in params, the names should correspond to those in params. 18 | #' Alternatively specify a single float to specify that value for all parameters. 19 | #' 20 | #' @return Returns list of arrays for each parameter containing the MCMC chain. 21 | #' Dimension of the form (nIters,paramDim1,paramDim2,...) 22 | #' 23 | #' @export 24 | #' 25 | #' @examples 26 | #' \dontrun{ 27 | #' # Simulate from a Normal Distribution with uninformative, improper prior 28 | #' dataset = list("x" = rnorm(1000)) 29 | #' params = list("theta" = 0) 30 | #' logLik = function(params, dataset) { 31 | #' distn = tf$distributions$Normal(params$theta, 1) 32 | #' return(tf$reduce_sum(distn$log_prob(dataset$x))) 33 | #' } 34 | #' stepsize = list("theta" = 5e-6) 35 | #' output = sgnht(logLik, dataset, params, stepsize) 36 | #' # For more examples see vignettes 37 | #' } 38 | sgnht = function( logLik, dataset, params, stepsize, logPrior = NULL, minibatchSize = 0.01, 39 | a = 0.01, nIters = 10^4L, verbose = TRUE, seed = NULL ) { 40 | # Declare SGNHT object 41 | sgnht = sgnhtSetup( logLik, dataset, params, stepsize, logPrior, minibatchSize, a, seed ) 42 | options = list( "nIters" = nIters, "verbose" = verbose ) 43 | # Run MCMC for declared object 44 | paramStorage = runSGMCMC( sgnht, params, options ) 45 | return( paramStorage ) 46 | } 47 | 48 | #' Create an sgnht object 49 | #' 50 | #' Creates an sgnht (stochastic gradient Nose Hoover Thermostat) object which can be passed to 51 | #' \code{\link{sgmcmcStep}} to simulate from 1 step of SGNHT for the posterior defined by 52 | #' logLik and logPrior. This allows the user to code the loop themselves, as in many standard 53 | #' TensorFlow procedures (such as optimization). Which means they do not need to store 54 | #' the chain at each iteration. This is useful when the full chain needs a lot of memory. 55 | #' 56 | #' @inheritParams sgnht 57 | #' 58 | #' @return The function returns an 'sgnht' object, which is used to pass the required information 59 | #' about the current model to the \code{\link{sgmcmcStep}} function. The function 60 | #' \code{\link{sgmcmcStep}} runs one step of sgnht. The sgnht object has the following attributes: 61 | #' \describe{ 62 | #' \item{params}{list of tf$Variables with the same names as the params list passed to 63 | #' \code{\link{sgnhtSetup}}. This is the object passed to the logLik and logPrior functions you 64 | #' declared to calculate the log posterior gradient estimate.} 65 | #' \item{estLogPost}{a tensor that estimates the log posterior given the current 66 | #' placeholders and params.} 67 | #' \item{N}{dataset size.} 68 | #' \item{data}{dataset as passed to \code{\link{sgnhtSetup}}.} 69 | #' \item{n}{minibatchSize as passed to \code{\link{sgnhtSetup}}.} 70 | #' \item{placeholders}{list of tf$placeholder objects with the same names as dataset 71 | #' used to feed minibatches of data to \code{\link{sgmcmcStep}}. This object 72 | #' gets fed to the dataset argument of the logLik and logPrior functions you declared.} 73 | #' \item{stepsize}{list of stepsizes as passed to \code{\link{sgnhtSetup}}.} 74 | #' \item{a}{list of a tuning parameters as passed to \code{\link{sgnhtSetup}}.} 75 | #' \item{dynamics}{a list of TensorFlow steps that are evaluated by \code{\link{sgmcmcStep}}.}} 76 | #' 77 | #' @export 78 | #' 79 | #' @examples 80 | #' \dontrun{ 81 | #' # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 82 | #' # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 83 | #' dataset = list("x" = rnorm(1000)) 84 | #' params = list("theta" = 0) 85 | #' logLik = function(params, dataset) { 86 | #' distn = tf$distributions$Normal(params$theta, 1) 87 | #' return(tf$reduce_sum(distn$log_prob(dataset$x))) 88 | #' } 89 | #' stepsize = list("theta" = 1e-4) 90 | #' sgnht = sgnhtSetup(logLik, dataset, params, stepsize) 91 | #' nIters = 10^4L 92 | #' # Initialize location estimate 93 | #' locEstimate = 0 94 | #' # Initialise TensorFlow session 95 | #' sess = initSess(sgnht) 96 | #' for ( i in 1:nIters ) { 97 | #' sgmcmcStep(sgnht, sess) 98 | #' locEstimate = locEstimate + 1 / nIters * getParams(sgnht, sess)$theta 99 | #' } 100 | #' # For more examples see vignettes 101 | #' } 102 | sgnhtSetup = function( logLik, dataset, params, stepsize, logPrior = NULL, minibatchSize = 0.01, 103 | a = 0.01, seed = NULL ) { 104 | # Create generic sgmcmc object 105 | sgnht = createSGMCMC( logLik, logPrior, dataset, params, stepsize, minibatchSize, seed ) 106 | # Get ranks for each parameter tensor, required for sgnht dynamics 107 | sgnht$ranks = getRanks( params ) 108 | # Declare sgnht specific tuning constants, checking they're in list format 109 | sgnht$a = convertList( a, sgnht$params ) 110 | # Declare object types 111 | class(sgnht) = c( "sgnht", "sgmcmc" ) 112 | # Declare SGNHT dynamics 113 | sgnht$dynamics = declareDynamics( sgnht, seed ) 114 | return( sgnht ) 115 | } 116 | -------------------------------------------------------------------------------- /R/storage.R: -------------------------------------------------------------------------------- 1 | #' Get current parameter values 2 | #' 3 | #' Return the current parameter values as a list of R arrays (converted from TensorFlow tensors). 4 | #' 5 | #' @param sgmcmc a stochastic gradient MCMC object returned by *Setup such as 6 | #' \code{\link{sgldSetup}}, \code{\link{sgldcvSetup}} etc. 7 | #' @param sess a TensorFlow session created using \code{\link{initSess}} 8 | #' 9 | #' @return Returns a list with the same names as \code{params}, with \code{R} arrays of the current 10 | #' parameter values 11 | #' 12 | #' @export 13 | #' 14 | #' @examples 15 | #' \dontrun{ 16 | #' # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 17 | #' # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 18 | #' dataset = list("x" = rnorm(1000)) 19 | #' params = list("theta" = 0) 20 | #' logLik = function(params, dataset) { 21 | #' distn = tf$distributions$Normal(params$theta, 1) 22 | #' return(tf$reduce_sum(distn$log_prob(dataset$x))) 23 | #' } 24 | #' stepsize = list("theta" = 1e-4) 25 | #' sgld = sgldSetup(logLik, dataset, params, stepsize) 26 | #' nIters = 10^4L 27 | #' # Initialize location estimate 28 | #' locEstimate = 0 29 | #' # Initialise TensorFlow session 30 | #' sess = initSess(sgld) 31 | #' for ( i in 1:nIters ) { 32 | #' sgmcmcStep(sgld, sess) 33 | #' locEstimate = locEstimate + 1 / nIters * getParams(sgld, sess)$theta 34 | #' } 35 | #' # For more examples see vignettes 36 | #' } 37 | getParams = function( sgmcmc, sess ) { 38 | return( sess$run( sgmcmc$params ) ) 39 | } 40 | 41 | # Initialise storage array, this will hold the MCMC chain and is the output returned by e.g. runSGLD 42 | initStorage = function( paramsRaw, n_iters ) { 43 | paramStorage = list() 44 | for ( pname in names( paramsRaw ) ) { 45 | shapeCurrent = getShape( paramsRaw[[pname]] ) 46 | # Add new dimension to parameter's current shape which holds each iteration 47 | shapeCurrent = c( n_iters, shapeCurrent ) 48 | paramStorage[[pname]] = array( 0, dim = shapeCurrent ) 49 | } 50 | return( paramStorage ) 51 | } 52 | 53 | # Store the current parameter values 54 | storeState = function( iter, sess, sgmcmc, storage ) { 55 | for ( pname in names( sgmcmc$params ) ) { 56 | paramCurrent = sgmcmc$params[[pname]]$eval( session = sess ) 57 | storage[[pname]] = updateStorage( storage[[pname]], iter, paramCurrent ) 58 | } 59 | return( storage ) 60 | } 61 | 62 | # Given a current parameter value, update storage at the current iteration 63 | # Enables slicing along the first dimension of a storage array of general dimension at index. 64 | updateStorage = function( storage, index, params ) { 65 | d = length( dim( storage ) ) 66 | # Catch edge cases of rank 1 storage array 67 | if ( d < 2 ) { 68 | storage[index] = params 69 | } else { 70 | # Use matrix indexing to specify array slice for rank > 1 71 | storageDims = dim( storage ) 72 | argList = list(index) 73 | for ( i in 2:d ) { 74 | argList[[i]] = 1:storageDims[i] 75 | } 76 | selection = as.matrix(do.call( "expand.grid", argList )) 77 | storage[selection] = params 78 | } 79 | return( storage ) 80 | } 81 | -------------------------------------------------------------------------------- /R/tfErrors.R: -------------------------------------------------------------------------------- 1 | # Check tensorflow is installed. If it isn't throw an error. 2 | checkTFInstall <- function() { 3 | if ( !get("TF", envir = tf_status) ) { 4 | stop(tfErrorMsg(), call. = FALSE) 5 | } else if ( !get("TFP", envir = tf_status) ) { 6 | stop(tfpErrorMsg(), call. = FALSE) 7 | } 8 | } 9 | 10 | # If there is an error building the posterior print a hopefully more readable error message 11 | getPosteriorBuildError <- function(e) { 12 | stop(buildErrorMsg(e), call. = FALSE) 13 | } 14 | 15 | 16 | tfErrorMsg <- function() { 17 | msg <- "\nNo TensorFlow python installation found.\n" 18 | msg <- paste0(msg, "This can be installed using the installTF() function.\n") 19 | return(msg) 20 | } 21 | 22 | 23 | tfpErrorMsg <- function() { 24 | msg <- "\nNo TensorFlow Probability python installation found.\n" 25 | msg <- paste0(msg, "This can be installed using the installTF() function.\n") 26 | return(msg) 27 | } 28 | 29 | 30 | buildErrorMsg = function(e) { 31 | msg <- "Problem building log posterior estimate from supplied logLik and logPrior functions.\n\n" 32 | msg <- paste0(msg, "Python error output:\n", e) 33 | msg <- paste0(msg, "\n", 34 | "Check your tensorflow code specifying the logLik and logPrior functions is correct.\n") 35 | msg <- paste0(msg, "Ensure constants in logLik and logPrior functions are specified as ", 36 | "type float32 using \ntf$constant(.., dtype = tf$float32) -- see the tutorials for some examples.") 37 | return(msg) 38 | } 39 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | # Environment determining status of the TensorFlow Installation. 2 | # This allows a custom error message to be displayed. 3 | tf_status <- new.env() 4 | 5 | 6 | # Load TensorFlow Probability and add the contents to tf$distributions. 7 | .onLoad <- function(libname, pkgname) { 8 | # Set default tf_status that everything is installed correctly. 9 | assign("TF", TRUE, envir = tf_status) 10 | assign("TFP", TRUE, envir = tf_status) 11 | # Check TensorFlow is installed. Update tf_status accordingly. 12 | checkTF() 13 | # If checkTF was not successful, return to avoid printing multiple messages 14 | if (!get("TF", envir = tf_status)) { 15 | return() 16 | } 17 | # Check TensorFlow Probability is installed, and load in. Update tf_status accordingly. 18 | tryCatch(loadTFP(), error = function(e) tfpMissing(e)) 19 | } 20 | 21 | 22 | # Check tensorflow installed by doing a dummy operation that will throw an error 23 | checkTF = function() { 24 | tryCatch(temp <- tf$constant(4), 25 | error = function (e) tfMissing()) 26 | } 27 | 28 | 29 | # Load tensorflow probability and assign distns to tf$distributions. 30 | # If this fails, print message and update tf_status 31 | loadTFP <- function() { 32 | import_opts <- list(priority = 5, environment = "r-tensorflow") 33 | tfp <- reticulate::import("tensorflow_probability", delay_load = import_opts) 34 | tf$distributions <- tfp$distributions 35 | } 36 | 37 | 38 | # Build message if TensorFlow missing. Update tf_status 39 | tfMissing <- function() { 40 | message("\nNo TensorFlow python installation found.") 41 | message("This can be installed using the installTF() function.\n") 42 | assign("TF", FALSE, envir = tf_status) 43 | assign("TFP", FALSE, envir = tf_status) 44 | } 45 | 46 | 47 | # Build message if TensorFlow Probability missing. Update tf_status 48 | tfpMissing <- function(e) { 49 | message("\nNo TensorFlow Probability python installation found.") 50 | message("This can be installed using the installTF() function.\n") 51 | message(paste("If TensorFlow Probability has been installed manually,", 52 | "ensure \nyour TensorFlow Probability and TensorFlow versions are compatible.\n")) 53 | assign("TFP", FALSE, envir = tf_status) 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sgmcmc: a stochastic gradient MCMC package for R 2 | 3 | [![Travis-CI Build Status](https://travis-ci.org/STOR-i/sgmcmc.svg?branch=master)](https://travis-ci.org/STOR-i/sgmcmc) 4 | [![CRAN\_Status\_Badge](https://www.r-pkg.org/badges/version/sgmcmc)](https://cran.r-project.org/package=tensorflow) 5 | 6 | `sgmcmc` implements popular stochastic gradient Markov chain Monte Carlo (SGMCMC) methods including [stochastic gradient Langevin dynamics (SGLD)](http://people.ee.duke.edu/~lcarin/398_icmlpaper.pdf), [stochastic gradient Hamiltonian Monte Carlo (SGHMC)](https://arxiv.org/pdf/1402.4102v2.pdf) and [stochastic gradient Nosé-Hoover thermostat (SGNHT)](http://papers.nips.cc/paper/5592-bayesian-sampling-using-stochastic-gradient-thermostats.pdf). The package uses automatic differentiation, so all the differentiation needed for the methods is calculated automatically. Control variate methods can be used in order to improve the efficiency of the methods as proposed in the [recent publication](https://arxiv.org/pdf/1706.05439.pdf). 7 | 8 | The package is built on top of the [TensorFlow library for R](https://tensorflow.rstudio.com/), which has a lot of support for statistical distributions and operations, which allows a large class of posteriors to be built. More details can be found at the [TensorFlow R library webpage](https://tensorflow.rstudio.com/), also see the [TensorFlow API](https://www.tensorflow.org/api_docs/) for full documentation. 9 | 10 | ## Citing sgmcmc 11 | 12 | To cite the `sgmcmc` package, please reference the [accompanying paper](https://arxiv.org/abs/1710.00578). Sample Bibtex is given below: 13 | 14 | ``` 15 | @article{sgmcmc-package, 16 | title={sgmcmc: An R package for stochastic gradient Markov chain Monte Carlo}, 17 | author={Baker, Jack and Fearnhead, Paul and Fox, Emily B and Nemeth, Christopher}, 18 | journal={Journal of Statistical Software}, 19 | volume={91}, 20 | number={3}, 21 | pages={1--27}, 22 | year={2019} 23 | } 24 | ``` 25 | 26 | ## Installation 27 | 28 | `sgmcmc` requires [TensorFlow for R](https://github.com/rstudio/tensorflow) to be installed, which requires packages that can't be automatically built by `R`, so has a few steps: 29 | - Install the `sgmcmc` R package: `install.packages("sgmcmc")`. 30 | - Install the required python packages (including TensorFlow and TensorFlow Probability) by running: `sgmcmc::installTF()`. 31 | 32 | If you already have the TensorFlow and TensorFlow probability packages installed, then this should be autodetected by the package and you can skip the final step. Make sure these are up to date though, as the TensorFlow API is under active development and still changes quite regularly. Especially ensure that your TensorFlow and TensorFlow probability modules are compatible. 33 | 34 | ## Documentation 35 | 36 | It's recommended you start [here](https://stor-i.github.io/sgmcmc///articles/sgmcmc.html). This getting started page outlines the general structure of the package and its usage. 37 | 38 | There's also worked examples for the following models (these will be extended as the package matures): 39 | - [Multivariate Gaussian](https://stor-i.github.io/sgmcmc///articles/mvGauss.html) 40 | - [Gaussian Mixture](https://stor-i.github.io/sgmcmc///articles/gaussMixture.html) 41 | - [Logistic Regression](https://stor-i.github.io/sgmcmc///articles/logisticRegression.html) 42 | 43 | The SGMCMC algorithms can also be run step by step, which allows custom storage of parameters using test functions, or sequential estimates. Useful if your chain is too large to fit into memory! This requires a better knowledge of TensorFlow. An example of this is given in the [neural network](https://stor-i.github.io/sgmcmc///articles/nn.html) vignette. 44 | 45 | Finally full details of the API can be found [here](https://stor-i.github.io/sgmcmc///reference/index.html). 46 | 47 | For the source code, and bug reporting, see the [Github page](https://github.com/STOR-i/sgmcmc). 48 | 49 | ## Issues Running Examples 50 | 51 | If you are having issues running the examples, as a first port of call please make sure your TensorFlow installation is the most up to date version. A lot of issues are simply because the TensorFlow API has changed. If you're still having issues, please file a [bug report](https://github.com/STOR-i/sgmcmc/issues). 52 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | authors: 2 | Jack Baker: 3 | href: http://lancs.ac.uk/~bakerj1/ 4 | Christopher Nemeth: 5 | href: http://www.lancs.ac.uk/~nemeth/ 6 | Paul Fearnhead: 7 | href: http://www.maths.lancs.ac.uk/~fearnhea/ 8 | Emily B. Fox: 9 | href: https://homes.cs.washington.edu/~ebfox/ 10 | STOR-i: 11 | href: http://www.stor-i.lancs.ac.uk/ 12 | html: 13 | 14 | 15 | reference: 16 | - title: "SGMCMC" 17 | desc: "Functions for running standard SGMCMC algorithms" 18 | contents: 19 | - sgld 20 | - sghmc 21 | - sgnht 22 | - title: "SGMCMC with Control Variates" 23 | desc: "Functions for running SGMCMC algorithms with improved efficiency using control variates" 24 | contents: 25 | - sgldcv 26 | - sghmccv 27 | - sgnhtcv 28 | - title: "Run SGMCMC algorithms step by step" 29 | desc: "Functions to run SGMCMC algorithms step by step within a user-defined loop, similar to standard TensorFlow optimization methods. Useful for chains with a high storage cost" 30 | contents: 31 | - sgldSetup 32 | - sgldcvSetup 33 | - sghmcSetup 34 | - sghmccvSetup 35 | - sgnhtSetup 36 | - sgnhtcvSetup 37 | - initSess 38 | - sgmcmcStep 39 | - getParams 40 | - title: "Installation" 41 | desc: "Install python packages depended on by sgmcmc, TensorFlow and TensorFlow Probability." 42 | contents: 43 | - installTF 44 | - title: "Datasets" 45 | desc: "Download and load datasets used in the examples and vignettes" 46 | contents: 47 | - getDataset 48 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Previous Submissions 2 | 3 | > Found the following (possibly) invalid URLs: https://www.kaggle.com/wiki/LogLoss 4 | 5 | Fixed 6 | 7 | ## Test environments 8 | System requirements fully met: 9 | * Ubuntu 14.04 (on travis-ci), R release and R-devel 10 | * Windows Server 2016 (Microsoft Azure Virtual Machine), R 3.4.1 11 | 12 | TensorFlow package not properly installed with `sgmcmc::installTF()`: 13 | * win-builder (devel) 14 | 15 | ## R CMD check restults 16 | There were no ERRORs, WARNINGs or NOTEs. 17 | 18 | ## Downstream dependencies 19 | There are two downstream dependencies: tensorflow, reticulate. 20 | 21 | * tensorflow: R CMD check: 0 ERRORs | 0 WARNING | 0 NOTE 22 | * reticulate: R CMD check: 0 ERRORs | 0 WARNING | 0 NOTE 23 | -------------------------------------------------------------------------------- /docs/articles/gaussMixture_files/figure-html/unnamed-chunk-9-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/STOR-i/sgmcmc/89a7b49881e363faff1cd8bbb0f48c11c3c32b79/docs/articles/gaussMixture_files/figure-html/unnamed-chunk-9-1.png -------------------------------------------------------------------------------- /docs/articles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Articles • sgmcmc 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 | 103 | 104 | 105 |
106 | 107 | 110 | 111 | 127 | 128 | 138 |
139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /docs/articles/logisticRegression_files/figure-html/unnamed-chunk-10-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/STOR-i/sgmcmc/89a7b49881e363faff1cd8bbb0f48c11c3c32b79/docs/articles/logisticRegression_files/figure-html/unnamed-chunk-10-1.png -------------------------------------------------------------------------------- /docs/articles/mvGauss_files/figure-html/unnamed-chunk-9-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/STOR-i/sgmcmc/89a7b49881e363faff1cd8bbb0f48c11c3c32b79/docs/articles/mvGauss_files/figure-html/unnamed-chunk-9-1.png -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Authors • sgmcmc 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 | 103 | 104 | 105 |
106 | 107 |
108 |
109 | 112 | 113 |
    114 |
  • 115 |

    Jack Baker. Author, maintainer, copyright holder. 116 |

    117 |
  • 118 |
  • 119 |

    Christopher Nemeth. Author, copyright holder. 120 |

    121 |
  • 122 |
  • 123 |

    Paul Fearnhead. Author, copyright holder. 124 |

    125 |
  • 126 |
  • 127 |

    Emily B. Fox. Author, copyright holder. 128 |

    129 |
  • 130 |
  • 131 |

    . Copyright holder. 132 |

    133 |
  • 134 |
135 | 136 |
137 | 138 |
139 | 140 | 141 | 151 |
152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /docs/jquery.sticky-kit.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net 3 | */ 4 | (function(){var b,f;b=this.jQuery||window.jQuery;f=b(window);b.fn.stick_in_parent=function(d){var A,w,J,n,B,K,p,q,k,E,t;null==d&&(d={});t=d.sticky_class;B=d.inner_scrolling;E=d.recalc_every;k=d.parent;q=d.offset_top;p=d.spacer;w=d.bottoming;null==q&&(q=0);null==k&&(k=void 0);null==B&&(B=!0);null==t&&(t="is_stuck");A=b(document);null==w&&(w=!0);J=function(a,d,n,C,F,u,r,G){var v,H,m,D,I,c,g,x,y,z,h,l;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);I=A.height();g=a.parent();null!=k&&(g=g.closest(k)); 5 | if(!g.length)throw"failed to find stick parent";v=m=!1;(h=null!=p?p&&a.closest(p):b("
"))&&h.css("position",a.css("position"));x=function(){var c,f,e;if(!G&&(I=A.height(),c=parseInt(g.css("border-top-width"),10),f=parseInt(g.css("padding-top"),10),d=parseInt(g.css("padding-bottom"),10),n=g.offset().top+c+f,C=g.height(),m&&(v=m=!1,null==p&&(a.insertAfter(h),h.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(t),e=!0),F=a.offset().top-(parseInt(a.css("margin-top"),10)||0)-q, 6 | u=a.outerHeight(!0),r=a.css("float"),h&&h.css({width:a.outerWidth(!0),height:u,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":r}),e))return l()};x();if(u!==C)return D=void 0,c=q,z=E,l=function(){var b,l,e,k;if(!G&&(e=!1,null!=z&&(--z,0>=z&&(z=E,x(),e=!0)),e||A.height()===I||x(),e=f.scrollTop(),null!=D&&(l=e-D),D=e,m?(w&&(k=e+u+c>C+n,v&&!k&&(v=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom"))),eb&&!v&&(c-=l,c=Math.max(b-u,c),c=Math.min(q,c),m&&a.css({top:c+"px"})))):e>F&&(m=!0,b={position:"fixed",top:c},b.width="border-box"===a.css("box-sizing")?a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(t),null==p&&(a.after(h),"left"!==r&&"right"!==r||h.append(a)),a.trigger("sticky_kit:stick")),m&&w&&(null==k&&(k=e+u+c>C+n),!v&&k)))return v=!0,"static"===g.css("position")&&g.css({position:"relative"}), 8 | a.css({position:"absolute",bottom:d,top:"auto"}).trigger("sticky_kit:bottom")},y=function(){x();return l()},H=function(){G=!0;f.off("touchmove",l);f.off("scroll",l);f.off("resize",y);b(document.body).off("sticky_kit:recalc",y);a.off("sticky_kit:detach",H);a.removeData("sticky_kit");a.css({position:"",bottom:"",top:"",width:""});g.position("position","");if(m)return null==p&&("left"!==r&&"right"!==r||a.insertAfter(h),h.remove()),a.removeClass(t)},f.on("touchmove",l),f.on("scroll",l),f.on("resize", 9 | y),b(document.body).on("sticky_kit:recalc",y),a.on("sticky_kit:detach",H),setTimeout(l,0)}};n=0;for(K=this.length;n 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/news/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | All news • sgmcmc 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 | 103 | 104 | 105 |
106 | 107 |
108 | 109 |
110 | 113 | 114 |
115 |
116 |

117 | sgmcmc 0.2.4

118 |
    119 |
  • Bug fixes
  • 120 |
121 |
122 |
123 |

124 | sgmcmc 0.2.3

125 |
    126 |
  • Added support for TensorFlow Probability.
  • 127 |
128 |
129 |
130 |

131 | sgmcmc 0.2.2

132 |
    133 |
  • Made loading TensorFlow distribution objects cleaner.
  • 134 |
135 |
136 |
137 |

138 | sgmcmc 0.2.1

139 |
    140 |
  • Added better support for sparse variables and minibatching parameters.
  • 141 |
142 |
143 |
144 |

145 | sgmcmc 0.2.0

146 |
    147 |
  • Added the ability to run algorithms step by step. This allows custom storage of parameters, useful when the full chain does not fit into memory!
  • 148 |
  • Added new vignette to demonstrate step by step functionality – a Bayesian neural network model.
  • 149 |
  • Changed optimizer to TensorFlow SGDOptimizer for control variate methods.
  • 150 |
151 |
152 |
153 |

154 | sgmcmc 0.1.0

155 |
    156 |
  • Initial release.
  • 157 |
158 |
159 |
160 |
161 | 162 | 175 | 176 |
177 | 178 | 188 |
189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /docs/pkgdown.css: -------------------------------------------------------------------------------- 1 | /* Sticker footer */ 2 | body > .container { 3 | display: flex; 4 | padding-top: 60px; 5 | min-height: calc(100vh); 6 | flex-direction: column; 7 | } 8 | 9 | body > .container .row { 10 | flex: 1; 11 | } 12 | 13 | footer { 14 | margin-top: 45px; 15 | padding: 35px 0 36px; 16 | border-top: 1px solid #e5e5e5; 17 | color: #666; 18 | display: flex; 19 | } 20 | footer p { 21 | margin-bottom: 0; 22 | } 23 | footer div { 24 | flex: 1; 25 | } 26 | footer .pkgdown { 27 | text-align: right; 28 | } 29 | footer p { 30 | margin-bottom: 0; 31 | } 32 | 33 | img.icon { 34 | float: right; 35 | } 36 | 37 | img { 38 | max-width: 100%; 39 | } 40 | 41 | /* Section anchors ---------------------------------*/ 42 | 43 | a.anchor { 44 | margin-left: -30px; 45 | display:inline-block; 46 | width: 30px; 47 | height: 30px; 48 | visibility: hidden; 49 | 50 | background-image: url(./link.svg); 51 | background-repeat: no-repeat; 52 | background-size: 20px 20px; 53 | background-position: center center; 54 | } 55 | 56 | .hasAnchor:hover a.anchor { 57 | visibility: visible; 58 | } 59 | 60 | @media (max-width: 767px) { 61 | .hasAnchor:hover a.anchor { 62 | visibility: hidden; 63 | } 64 | } 65 | 66 | 67 | /* Fixes for fixed navbar --------------------------*/ 68 | 69 | .contents h1, .contents h2, .contents h3, .contents h4 { 70 | padding-top: 60px; 71 | margin-top: -60px; 72 | } 73 | 74 | /* Static header placement on mobile devices */ 75 | @media (max-width: 767px) { 76 | .navbar-fixed-top { 77 | position: absolute; 78 | } 79 | .navbar { 80 | padding: 0; 81 | } 82 | } 83 | 84 | 85 | /* Sidebar --------------------------*/ 86 | 87 | #sidebar { 88 | margin-top: 30px; 89 | } 90 | #sidebar h2 { 91 | font-size: 1.5em; 92 | margin-top: 1em; 93 | } 94 | 95 | #sidebar h2:first-child { 96 | margin-top: 0; 97 | } 98 | 99 | #sidebar .list-unstyled li { 100 | margin-bottom: 0.5em; 101 | } 102 | 103 | /* Reference index & topics ----------------------------------------------- */ 104 | 105 | .ref-index th {font-weight: normal;} 106 | .ref-index h2 {font-size: 20px;} 107 | 108 | .ref-index td {vertical-align: top;} 109 | .ref-index .alias {width: 40%;} 110 | .ref-index .title {width: 60%;} 111 | 112 | .ref-index .alias {width: 40%;} 113 | .ref-index .title {width: 60%;} 114 | 115 | .ref-arguments th {text-align: right; padding-right: 10px;} 116 | .ref-arguments th, .ref-arguments td {vertical-align: top;} 117 | .ref-arguments .name {width: 20%;} 118 | .ref-arguments .desc {width: 80%;} 119 | 120 | /* Nice scrolling for wide elements --------------------------------------- */ 121 | 122 | table { 123 | display: block; 124 | overflow: auto; 125 | } 126 | 127 | /* Syntax highlighting ---------------------------------------------------- */ 128 | 129 | pre { 130 | word-wrap: normal; 131 | word-break: normal; 132 | border: 1px solid #eee; 133 | } 134 | 135 | pre, code { 136 | background-color: #f8f8f8; 137 | color: #333; 138 | } 139 | 140 | pre .img { 141 | margin: 5px 0; 142 | } 143 | 144 | pre .img img { 145 | background-color: #fff; 146 | display: block; 147 | height: auto; 148 | } 149 | 150 | code a, pre a { 151 | color: #375f84; 152 | } 153 | 154 | .fl {color: #1514b5;} 155 | .fu {color: #000000;} /* function */ 156 | .ch,.st {color: #036a07;} /* string */ 157 | .kw {color: #264D66;} /* keyword */ 158 | .co {color: #888888;} /* comment */ 159 | 160 | .message { color: black; font-weight: bolder;} 161 | .error { color: orange; font-weight: bolder;} 162 | .warning { color: #6A0366; font-weight: bolder;} 163 | 164 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $("#sidebar").stick_in_parent({offset_top: 40}); 3 | $('body').scrollspy({ 4 | target: '#sidebar', 5 | offset: 60 6 | }); 7 | 8 | var cur_path = paths(location.pathname); 9 | $("#navbar ul li a").each(function(index, value) { 10 | if (value.text == "Home") 11 | return; 12 | if (value.getAttribute("href") === "#") 13 | return; 14 | 15 | var path = paths(value.pathname); 16 | if (is_prefix(cur_path, path)) { 17 | // Add class to parent
  • , and enclosing
  • if in dropdown 18 | var menu_anchor = $(value); 19 | menu_anchor.parent().addClass("active"); 20 | menu_anchor.closest("li.dropdown").addClass("active"); 21 | } 22 | }); 23 | }); 24 | 25 | function paths(pathname) { 26 | var pieces = pathname.split("/"); 27 | pieces.shift(); // always starts with / 28 | 29 | var end = pieces[pieces.length - 1]; 30 | if (end === "index.html" || end === "") 31 | pieces.pop(); 32 | return(pieces); 33 | } 34 | 35 | function is_prefix(needle, haystack) { 36 | if (needle.length > haystack.lengh) 37 | return(false); 38 | 39 | for (var i = 0; i < haystack.length; i++) { 40 | if (needle[i] != haystack[i]) 41 | return(false); 42 | } 43 | 44 | return(true); 45 | } 46 | -------------------------------------------------------------------------------- /docs/reference/covertype.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Forest Covertype data — covertype • sgmcmc 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
    41 |
    42 | 103 | 104 | 105 |
    106 | 107 |
    108 |
    109 | 112 | 113 | 114 |

    The samples in this dataset correspond to 30×30m patches of forest in the US, 115 | collected for the task of predicting each patch’s cover type, 116 | i.e. the dominant species of tree. 117 | We use the LIBSVM dataset, which transforms the data to a binary problem rather than multiclass.

    118 | 119 | 120 |
    covertype
    121 | 122 |

    Format

    123 | 124 |

    A matrix with 581012 rows and 55 variables. The first column is the classification labels, the other columns are the 54 explanatory variables.

    125 | 126 |

    Source

    127 | 128 |

    https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary.html

    129 | 130 | 131 |
    132 | 142 |
    143 | 144 | 154 |
    155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /docs/reference/installTF.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Install TensorFlow and TensorFlow Probability — installTF • sgmcmc 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
    41 |
    42 | 103 | 104 | 105 |
    106 | 107 |
    108 |
    109 | 112 | 113 | 114 |

    Install the python packages required by sgmcmc, including TensorFlow and TensorFlow probability. 115 | Uses the tensorflow::install_tensorflow function.

    116 | 117 | 118 |
    installTF()
    119 | 120 | 121 |
    122 | 128 |
    129 | 130 | 140 |
    141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /docs/reference/mnist.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | MNIST handwritten digit data — mnist • sgmcmc 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
    41 |
    42 | 103 | 104 | 105 |
    106 | 107 |
    108 |
    109 | 112 | 113 | 114 |

    The MNIST dataset is a dataset of handwritten digits from 0-9. Each image is 28x28 pixels. 115 | We can interpret this as a large matrix of numbers, representing the value at each pixel. 116 | These 28x28 matrices are then flattened to be vectors of length 784. For each image, there 117 | is an associated label, which determines which digit the image is of. This image is encoded 118 | as a vector of length 10, where element i is 1 if the digit is i-1 and 0 otherwise. 119 | The dataset is split into two parts: 55,000 data points of training data 120 | and 10,000 points of test data.

    121 | 122 | 123 |
    mnist
    124 | 125 |

    Format

    126 | 127 |

    A list with two elements: train and test. 128 | The training set mnist$train is a list with two entries: images and labels, 129 | located at mnist$train$images, mnist$train$labels respectively. 130 | The dataset mnist$train$images is a matrix of size 55000x784, 131 | the labels mnist$train$labels is a matrix of size 55000x10. 132 | The test set mnist$test is a list with two entries: images and labels, 133 | located at mnist$test$images, mnist$test$labels respectively. 134 | The dataset mnist$test$images is a matrix of size 10000x784, 135 | the labels mnist$test$labels is a matrix of size 10000x10.

    136 | 137 |

    Source

    138 | 139 |

    http://yann.lecun.com/exdb/mnist/

    140 | 141 | 142 |
    143 | 153 |
    154 | 155 | 165 |
    166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /docs/reference/sgmcmc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | sgmcmc: A package for stochastic gradient MCMC — sgmcmc • sgmcmc 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
    41 |
    42 | 103 | 104 | 105 |
    106 | 107 |
    108 |
    109 | 112 | 113 | 114 |

    The sgmcmc package implements some of the most popular stochastic gradient MCMC methods 115 | including SGLD, SGHMC, SGNHT. It also implements control variates as a way to increase 116 | the efficiency of these methods. The algorithms are implemented using TensorFlow 117 | which means no gradients need to be specified by the user as these are calculated 118 | automatically. It also means the algorithms are efficient.

    119 | 120 | 121 | 122 |

    sgmcmc functions

    123 | 124 | 125 |

    The main functions of the package are sgld, sghmc and sgnht which implement the methods 126 | stochastic gradient Langevin dynamics, stochastic gradient Hamiltonian Monte Carlo and 127 | stochastic gradient Nose-Hoover Thermostat respectively. Also included are control variate 128 | versions of these algorithms, which uses control variates to increase their efficiency. 129 | These are the functions sgldcv, sghmccv and sgnhtcv.

    130 | 131 |

    References

    132 | 133 |

    Baker, J., Fearnhead, P., Fox, E. B., & Nemeth, C. (2017) 134 | control variates for stochastic gradient Langevin dynamics. Preprint.

    135 |

    Welling, M., & Teh, Y. W. (2011). 136 | Bayesian learning via stochastic gradient Langevin dynamics. ICML (pp. 681-688).

    137 |

    Chen, T., Fox, E. B., & Guestrin, C. (2014). 138 | stochastic gradient Hamiltonian Monte Carlo. In ICML (pp. 1683-1691).

    139 |

    Ding, N., Fang, Y., Babbush, R., Chen, C., Skeel, R. D., & Neven, H. (2014). 140 | Bayesian sampling using stochastic gradient thermostats. NIPS (pp. 3203-3211).

    141 | 142 | 143 |
    144 | 154 |
    155 | 156 | 166 |
    167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /man/getDataset.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \name{getDataset} 4 | \alias{getDataset} 5 | \title{Load example datasets} 6 | \usage{ 7 | getDataset(dataset) 8 | } 9 | \arguments{ 10 | \item{dataset}{string which determines the dataset to load: 11 | either \code{"covertype"} or \code{"mnist"}.} 12 | } 13 | \value{ 14 | Returns the desired dataset. The next two sections give more details about each dataset. 15 | } 16 | \description{ 17 | Download and load one of the example datasets for the package: 18 | \code{covertype} or \code{mnist}. 19 | These datasets are required for the vignettes in the package. 20 | The code generating these datasets is available at \url{https://github.com/jbaker92/sgmcmc-data}. 21 | } 22 | \section{covertype}{ 23 | 24 | 25 | The samples in this dataset correspond to 30×30m patches of forest in the US, 26 | collected for the task of predicting each patch’s cover type, 27 | i.e. the dominant species of tree. 28 | We use the LIBSVM dataset, which transforms the data to a binary problem rather than multiclass. 29 | 30 | format: A matrix with 581012 rows and 55 variables. The first column is the 31 | classification labels, the other columns are the 54 explanatory variables. 32 | 33 | source: \url{https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary.html} 34 | } 35 | 36 | \section{mnist}{ 37 | 38 | 39 | The MNIST dataset is a dataset of handwritten digits from 0-9. Each image is 28x28 pixels. 40 | We can interpret this as a large matrix of numbers, representing the value at each pixel. 41 | These 28x28 matrices are then flattened to be vectors of length 784. For each image, there 42 | is an associated label, which determines which digit the image is of. This image is encoded 43 | as a vector of length 10, where element i is 1 if the digit is i-1 and 0 otherwise. 44 | The dataset is split into two parts: 55,000 data points of training data 45 | and 10,000 points of test data. 46 | 47 | format: A list with two elements \code{train} and \code{test}. 48 | \itemize{ 49 | \item The training set mnist$train is a list with two entries: images and labels, 50 | located at mnist$train$images, mnist$train$labels respectively. 51 | \item The dataset mnist$train$images is a matrix of size 55000x784, 52 | the labels mnist$train$labels is a matrix of size 55000x10. 53 | \item The test set mnist$test is a list with two entries: images and labels, 54 | located at mnist$test$images, mnist$test$labels respectively. 55 | \item The dataset mnist$test$images is a matrix of size 10000x784, 56 | the labels mnist$test$labels is a matrix of size 10000x10. } 57 | 58 | source: \url{http://yann.lecun.com/exdb/mnist/} 59 | } 60 | 61 | \examples{ 62 | \dontrun{ 63 | # Download the covertype dataset 64 | covertype = get_dataset("covertype") 65 | # Download the mnist dataset 66 | mnist = get_dataset("mnist") 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /man/getParams.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/storage.R 3 | \name{getParams} 4 | \alias{getParams} 5 | \title{Get current parameter values} 6 | \usage{ 7 | getParams(sgmcmc, sess) 8 | } 9 | \arguments{ 10 | \item{sgmcmc}{a stochastic gradient MCMC object returned by *Setup such as 11 | \code{\link{sgldSetup}}, \code{\link{sgldcvSetup}} etc.} 12 | 13 | \item{sess}{a TensorFlow session created using \code{\link{initSess}}} 14 | } 15 | \value{ 16 | Returns a list with the same names as \code{params}, with \code{R} arrays of the current 17 | parameter values 18 | } 19 | \description{ 20 | Return the current parameter values as a list of R arrays (converted from TensorFlow tensors). 21 | } 22 | \examples{ 23 | \dontrun{ 24 | # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 25 | # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 26 | dataset = list("x" = rnorm(1000)) 27 | params = list("theta" = 0) 28 | logLik = function(params, dataset) { 29 | distn = tf$distributions$Normal(params$theta, 1) 30 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 31 | } 32 | stepsize = list("theta" = 1e-4) 33 | sgld = sgldSetup(logLik, dataset, params, stepsize) 34 | nIters = 10^4L 35 | # Initialize location estimate 36 | locEstimate = 0 37 | # Initialise TensorFlow session 38 | sess = initSess(sgld) 39 | for ( i in 1:nIters ) { 40 | sgmcmcStep(sgld, sess) 41 | locEstimate = locEstimate + 1 / nIters * getParams(sgld, sess)$theta 42 | } 43 | # For more examples see vignettes 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /man/initSess.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/update.R 3 | \name{initSess} 4 | \alias{initSess} 5 | \title{Initialise TensorFlow session and sgmcmc algorithm} 6 | \usage{ 7 | initSess(sgmcmc, verbose = TRUE) 8 | } 9 | \arguments{ 10 | \item{sgmcmc}{an sgmcmc object created using *Setup e.g. \code{\link{sgldSetup}}, 11 | \code{\link{sgldcvSetup}}} 12 | 13 | \item{verbose}{optional. Default TRUE. Boolean specifying whether to print progress.} 14 | } 15 | \value{ 16 | sess a TensorFlow session, see the 17 | \href{https://tensorflow.rstudio.com/}{TensorFlow for R website} for more details. 18 | } 19 | \description{ 20 | Initialise the TensorFlow session and the sgmcmc algorithm. For algorithms with control variates 21 | this will find the MAP estimates of the log posterior and calculate the full log posterior 22 | gradient at this point. For algorithms without control variates this will simply initialise a 23 | TensorFlow session. 24 | } 25 | \examples{ 26 | \dontrun{ 27 | # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 28 | # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 29 | dataset = list("x" = rnorm(1000)) 30 | params = list("theta" = 0) 31 | logLik = function(params, dataset) { 32 | distn = tf$distributions$Normal(params$theta, 1) 33 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 34 | } 35 | stepsize = list("theta" = 1e-4) 36 | sgld = sgldSetup(logLik, dataset, params, stepsize) 37 | nIters = 10^4L 38 | # Initialize location estimate 39 | locEstimate = 0 40 | # Initialise TensorFlow session 41 | sess = initSess(sgld) 42 | for ( i in 1:nIters ) { 43 | sgmcmcStep(sgld, sess) 44 | locEstimate = locEstimate + 1 / nIters * getParams(sgld, sess)$theta 45 | } 46 | # For more examples see vignettes 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /man/installTF.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/install.R 3 | \name{installTF} 4 | \alias{installTF} 5 | \title{Install TensorFlow and TensorFlow Probability} 6 | \usage{ 7 | installTF() 8 | } 9 | \description{ 10 | Install the python packages required by sgmcmc, including TensorFlow and TensorFlow probability. 11 | Uses the tensorflow::install_tensorflow function. 12 | } 13 | -------------------------------------------------------------------------------- /man/sghmc.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sghmc.R 3 | \name{sghmc} 4 | \alias{sghmc} 5 | \title{Stochastic Gradient Hamiltonian Monte Carlo} 6 | \usage{ 7 | sghmc(logLik, dataset, params, stepsize, logPrior = NULL, 8 | minibatchSize = 0.01, alpha = 0.01, L = 5L, nIters = 10^4L, 9 | verbose = TRUE, seed = NULL) 10 | } 11 | \arguments{ 12 | \item{logLik}{function which takes parameters and dataset 13 | (list of TensorFlow variables and placeholders respectively) as input. 14 | It should return a TensorFlow expression which defines the log likelihood of the model.} 15 | 16 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 17 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 18 | 19 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 20 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 21 | 22 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 23 | The names in the list should correspond to those in params. 24 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 25 | 26 | \item{logPrior}{optional. Default uninformative improper prior. 27 | Function which takes parameters (list of TensorFlow variables) as input. 28 | The function should return a TensorFlow tensor which defines the log prior of the model.} 29 | 30 | \item{minibatchSize}{optional. Default 0.01. 31 | Numeric or integer value that specifies amount of dataset to use at each iteration 32 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 33 | 34 | \item{alpha}{optional. Default 0.01. 35 | List of numeric values corresponding to the SGHMC momentum tuning constants 36 | (\eqn{\alpha} in the original paper). One value should be given 37 | for each parameter in params, the names should correspond to those in params. 38 | Alternatively specify a single float to specify that value for all parameters.} 39 | 40 | \item{L}{optional. Default 5L. Integer specifying the trajectory parameter of the simulation, 41 | as defined in the main reference.} 42 | 43 | \item{nIters}{optional. Default 10^4L. Integer specifying number of iterations to perform.} 44 | 45 | \item{verbose}{optional. Default TRUE. Boolean specifying whether to print algorithm progress} 46 | 47 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 48 | does not declare a seed for the TensorFlow session.} 49 | } 50 | \value{ 51 | Returns list of arrays for each parameter containing the MCMC chain. 52 | Dimension of the form (nIters,paramDim1,paramDim2,...) 53 | } 54 | \description{ 55 | Simulates from the posterior defined by the functions logLik and logPrior using 56 | stochastic gradient Hamiltonian Monte Carlo. The function uses TensorFlow, so needs 57 | TensorFlow for python installed. Currently we use the approximation \eqn{\hat \beta = 0}, 58 | as used in the simulations by the original reference. 59 | This will be changed in future implementations. 60 | } 61 | \examples{ 62 | \dontrun{ 63 | # Simulate from a Normal Distribution with uninformative, improper prior 64 | dataset = list("x" = rnorm(1000)) 65 | params = list("theta" = 0) 66 | logLik = function(params, dataset) { 67 | distn = tf$distributions$Normal(params$theta, 1) 68 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 69 | } 70 | stepsize = list("theta" = 1e-5) 71 | output = sghmc(logLik, dataset, params, stepsize) 72 | # For more examples see vignettes 73 | } 74 | } 75 | \references{ 76 | \itemize{\item \href{https://arxiv.org/pdf/1402.4102v2.pdf}{ 77 | Chen, T., Fox, E. B., and Guestrin, C. (2014). Stochastic gradient Hamiltonian Monte Carlo. 78 | In ICML (pp. 1683-1691).}} 79 | } 80 | -------------------------------------------------------------------------------- /man/sghmcSetup.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sghmc.R 3 | \name{sghmcSetup} 4 | \alias{sghmcSetup} 5 | \title{Create an sghmc object} 6 | \usage{ 7 | sghmcSetup(logLik, dataset, params, stepsize, logPrior = NULL, 8 | minibatchSize = 0.01, alpha = 0.01, L = 5L, seed = NULL) 9 | } 10 | \arguments{ 11 | \item{logLik}{function which takes parameters and dataset 12 | (list of TensorFlow variables and placeholders respectively) as input. 13 | It should return a TensorFlow expression which defines the log likelihood of the model.} 14 | 15 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 16 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 17 | 18 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 19 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 20 | 21 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 22 | The names in the list should correspond to those in params. 23 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 24 | 25 | \item{logPrior}{optional. Default uninformative improper prior. 26 | Function which takes parameters (list of TensorFlow variables) as input. 27 | The function should return a TensorFlow tensor which defines the log prior of the model.} 28 | 29 | \item{minibatchSize}{optional. Default 0.01. 30 | Numeric or integer value that specifies amount of dataset to use at each iteration 31 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 32 | 33 | \item{alpha}{optional. Default 0.01. 34 | List of numeric values corresponding to the SGHMC momentum tuning constants 35 | (\eqn{\alpha} in the original paper). One value should be given 36 | for each parameter in params, the names should correspond to those in params. 37 | Alternatively specify a single float to specify that value for all parameters.} 38 | 39 | \item{L}{optional. Default 5L. Integer specifying the trajectory parameter of the simulation, 40 | as defined in the main reference.} 41 | 42 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 43 | does not declare a seed for the TensorFlow session.} 44 | } 45 | \value{ 46 | The function returns an 'sghmc' object, which is used to pass the required information 47 | about the current model to the \code{\link{sgmcmcStep}} function. The function 48 | \code{\link{sgmcmcStep}} runs one step of sghmc. The sghmc object has the following attributes: 49 | \describe{ 50 | \item{params}{list of tf$Variables with the same names as the params list passed to 51 | \code{\link{sghmcSetup}}. This is the object passed to the logLik and logPrior functions you 52 | declared to calculate the log posterior gradient estimate.} 53 | \item{estLogPost}{a tensor that estimates the log posterior given the current 54 | placeholders and params.} 55 | \item{N}{dataset size.} 56 | \item{data}{dataset as passed to \code{\link{sghmcSetup}}.} 57 | \item{n}{minibatchSize as passed to \code{\link{sghmcSetup}}.} 58 | \item{placeholders}{list of tf$placeholder objects with the same names as dataset 59 | used to feed minibatches of data to \code{\link{sgmcmcStep}}. These objects 60 | get fed to the dataset argument of the logLik and logPrior functions you declared.} 61 | \item{stepsize}{list of stepsizes as passed to \code{\link{sghmcSetup}}.} 62 | \item{alpha}{list of alpha tuning parameters as passed to \code{\link{sghmcSetup}}.} 63 | \item{L}{integer trajectory parameter as passed to \code{\link{sghmcSetup}}.} 64 | \item{dynamics}{a list of TensorFlow steps that are evaluated by \code{\link{sgmcmcStep}}.}} 65 | } 66 | \description{ 67 | Creates an sghmc (stochastic gradient Hamiltonian Monte Carlo) object which can be passed to 68 | \code{\link{sgmcmcStep}} to simulate from 1 step of SGLD for the posterior defined by logLik 69 | and logPrior. This allows the user to code the loop themselves, as in many standard 70 | TensorFlow procedures (such as optimization). Which means they do not need to store 71 | the chain at each iteration. This is useful when the full chain needs a lot of memory. 72 | } 73 | \examples{ 74 | \dontrun{ 75 | # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 76 | # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 77 | dataset = list("x" = rnorm(1000)) 78 | params = list("theta" = 0) 79 | logLik = function(params, dataset) { 80 | distn = tf$distributions$Normal(params$theta, 1) 81 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 82 | } 83 | stepsize = list("theta" = 1e-4) 84 | sghmc = sghmcSetup(logLik, dataset, params, stepsize) 85 | nIters = 10^4L 86 | # Initialize location estimate 87 | locEstimate = 0 88 | # Initialise TensorFlow session 89 | sess = initSess(sghmc) 90 | for ( i in 1:nIters ) { 91 | sgmcmcStep(sghmc, sess) 92 | locEstimate = locEstimate + 1 / nIters * getParams(sghmc, sess)$theta 93 | } 94 | # For more examples see vignettes 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /man/sghmccv.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sghmccv.R 3 | \name{sghmccv} 4 | \alias{sghmccv} 5 | \title{Stochastic Gradient Hamiltonian Monte Carlo with Control Variates} 6 | \usage{ 7 | sghmccv(logLik, dataset, params, stepsize, optStepsize, logPrior = NULL, 8 | minibatchSize = 0.01, alpha = 0.01, L = 5L, nIters = 10^4L, 9 | nItersOpt = 10^4L, verbose = TRUE, seed = NULL) 10 | } 11 | \arguments{ 12 | \item{logLik}{function which takes parameters and dataset 13 | (list of TensorFlow variables and placeholders respectively) as input. 14 | It should return a TensorFlow expression which defines the log likelihood of the model.} 15 | 16 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 17 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 18 | 19 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 20 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 21 | 22 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 23 | The names in the list should correspond to those in params. 24 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 25 | 26 | \item{optStepsize}{numeric value specifying the stepsize for the optimization 27 | to find MAP estimates of parameters. The TensorFlow GradientDescentOptimizer is used.} 28 | 29 | \item{logPrior}{optional. Default uninformative improper prior. 30 | Function which takes parameters (list of TensorFlow variables) as input. 31 | The function should return a TensorFlow tensor which defines the log prior of the model.} 32 | 33 | \item{minibatchSize}{optional. Default 0.01. 34 | Numeric or integer value that specifies amount of dataset to use at each iteration 35 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 36 | 37 | \item{alpha}{optional. Default 0.01. 38 | List of numeric values corresponding to the SGHMC momentum tuning constants 39 | (\eqn{\alpha} in the original paper). One value should be given 40 | for each parameter in params, the names should correspond to those in params. 41 | Alternatively specify a single float to specify that value for all parameters.} 42 | 43 | \item{L}{optional. Default 5L. Integer specifying the trajectory parameter of the simulation, 44 | as defined in the main reference.} 45 | 46 | \item{nIters}{optional. Default 10^4L. Integer specifying number of iterations to perform.} 47 | 48 | \item{nItersOpt}{optional. Default 10^4L. 49 | Integer specifying number of iterations of initial optimization to perform.} 50 | 51 | \item{verbose}{optional. Default TRUE. Boolean specifying whether to print algorithm progress} 52 | 53 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 54 | does not declare a seed for the TensorFlow session.} 55 | } 56 | \value{ 57 | Returns list of arrays for each parameter containing the MCMC chain. 58 | Dimension of the form (nIters,paramDim1,paramDim2,...) 59 | } 60 | \description{ 61 | Simulates from the posterior defined by the functions logLik and logPrior using 62 | stochastic gradient Hamiltonian Monte Carlo with an improved gradient estimate 63 | that is calculated using control variates. 64 | Currently we use the approximation \eqn{\hat \beta = 0}, 65 | as used in the simulations by the original reference. 66 | This will be changed in future implementations. 67 | } 68 | \examples{ 69 | \dontrun{ 70 | # Simulate from a Normal Distribution with uninformative prior 71 | dataset = list("x" = rnorm(1000)) 72 | params = list("theta" = 0) 73 | logLik = function(params, dataset) { 74 | distn = tf$distributions$Normal(params$theta, 1) 75 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 76 | } 77 | stepsize = list("theta" = 1e-5) 78 | optStepsize = 1e-1 79 | output = sghmccv(logLik, dataset, params, stepsize, optStepsize) 80 | } 81 | } 82 | \references{ 83 | \itemize{ 84 | \item \href{https://arxiv.org/pdf/1706.05439.pdf}{ 85 | Baker, J., Fearnhead, P., Fox, E. B., and Nemeth, C. (2017). 86 | Control variates for stochastic gradient MCMC. ArXiv preprint arXiv:1706.05439.} 87 | \item \href{https://arxiv.org/pdf/1402.4102v2.pdf}{ 88 | Chen, T., Fox, E. B., and Guestrin, C. (2014). Stochastic gradient Hamiltonian Monte Carlo. 89 | In ICML (pp. 1683-1691).}} 90 | } 91 | -------------------------------------------------------------------------------- /man/sghmccvSetup.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sghmccv.R 3 | \name{sghmccvSetup} 4 | \alias{sghmccvSetup} 5 | \title{Create an sghmccv object} 6 | \usage{ 7 | sghmccvSetup(logLik, dataset, params, stepsize, optStepsize, logPrior = NULL, 8 | minibatchSize = 0.01, alpha = 0.01, L = 5L, nItersOpt = 10^4L, 9 | verbose = TRUE, seed = NULL) 10 | } 11 | \arguments{ 12 | \item{logLik}{function which takes parameters and dataset 13 | (list of TensorFlow variables and placeholders respectively) as input. 14 | It should return a TensorFlow expression which defines the log likelihood of the model.} 15 | 16 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 17 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 18 | 19 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 20 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 21 | 22 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 23 | The names in the list should correspond to those in params. 24 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 25 | 26 | \item{optStepsize}{numeric value specifying the stepsize for the optimization 27 | to find MAP estimates of parameters. The TensorFlow GradientDescentOptimizer is used.} 28 | 29 | \item{logPrior}{optional. Default uninformative improper prior. 30 | Function which takes parameters (list of TensorFlow variables) as input. 31 | The function should return a TensorFlow tensor which defines the log prior of the model.} 32 | 33 | \item{minibatchSize}{optional. Default 0.01. 34 | Numeric or integer value that specifies amount of dataset to use at each iteration 35 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 36 | 37 | \item{alpha}{optional. Default 0.01. 38 | List of numeric values corresponding to the SGHMC momentum tuning constants 39 | (\eqn{\alpha} in the original paper). One value should be given 40 | for each parameter in params, the names should correspond to those in params. 41 | Alternatively specify a single float to specify that value for all parameters.} 42 | 43 | \item{L}{optional. Default 5L. Integer specifying the trajectory parameter of the simulation, 44 | as defined in the main reference.} 45 | 46 | \item{nItersOpt}{optional. Default 10^4L. 47 | Integer specifying number of iterations of initial optimization to perform.} 48 | 49 | \item{verbose}{optional. Default TRUE. Boolean specifying whether to print algorithm progress} 50 | 51 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 52 | does not declare a seed for the TensorFlow session.} 53 | } 54 | \value{ 55 | The function returns an 'sghmccv' object, a type of sgmcmc object. 56 | Which is used to pass the required information about the current model to the 57 | \code{\link{sgmcmcStep}} function. The function \code{\link{sgmcmcStep}} runs one 58 | step of sghmc with a gradient estimate that uses control variates. 59 | Attributes of the sghmccv object you'll probably find most useful are: 60 | \describe{ 61 | \item{params}{list of tf$Variables with the same names as the params list passed to 62 | \code{\link{sghmccvSetup}}. This is the object passed to the logLik and logPrior functions you 63 | declared to calculate the log posterior gradient estimate.} 64 | \item{paramsOpt}{list of tf$Variables with the same names as the \code{params} list passed to 65 | \code{\link{sghmccvSetup}}. These variables are used to initially find MAP estimates 66 | and then store these optimal parameter estimates.} 67 | \item{estLogPost}{a tensor that estimates the log posterior given the current 68 | placeholders and params.} 69 | \item{logPostOptGrad}{list of \code{tf$Variables} with same names as \code{params}, this stores 70 | the full log posterior gradient at each MAP estimate after the initial optimization step.}} 71 | Other attributes of the object are as follows: 72 | \describe{ 73 | \item{N}{dataset size.} 74 | \item{data}{dataset as passed to \code{\link{sghmccvSetup}}.} 75 | \item{n}{minibatchSize as passed to \code{\link{sghmccvSetup}}.} 76 | \item{placeholders}{list of tf$placeholder objects with the same names as dataset 77 | used to feed minibatches of data to \code{\link{sgmcmcStep}}. These are also the objects 78 | that gets fed to the dataset argument of the logLik and logPrior functions you declared.} 79 | \item{stepsize}{list of stepsizes as passed to \code{\link{sghmccvSetup}}} 80 | \item{alpha}{list of alpha tuning parameters as passed to \code{\link{sghmcSetup}}.} 81 | \item{L}{integer trajectory parameter as passed to \code{\link{sghmcSetup}}.} 82 | \item{dynamics}{a list of TensorFlow steps that are evaluated by \code{\link{sgmcmcStep}}.} 83 | \item{estLogPostOpt}{a TensorFlow tensor relying on \code{paramsOpt} and \code{placeholders} which 84 | estimates the log posterior at the optimal parameters. Used in the initial optimization step.} 85 | \item{fullLogPostOpt}{a TensorFlow tensor used in the calculation of the full log posterior 86 | gradient at the MAP estimates.} 87 | \item{optimizer}{a TensorFlow optimizer object used to find the initial MAP estimates.}} 88 | } 89 | \description{ 90 | Creates an sghmccv (stochastic gradient Hamiltonian Monte Carlo with Control Variates) object 91 | which can be passed to \code{\link{sgmcmcStep}} to simulate from 1 step of sghmc, using a 92 | gradient estimate with control variates for the posterior defined by logLik and logPrior. 93 | This allows the user to code the loop themselves, as in many standard 94 | TensorFlow procedures (such as optimization). Which means they do not need to store 95 | the chain at each iteration. This is useful when the full chain needs a lot of memory. 96 | } 97 | \examples{ 98 | \dontrun{ 99 | # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 100 | # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 101 | dataset = list("x" = rnorm(1000)) 102 | params = list("theta" = 0) 103 | logLik = function(params, dataset) { 104 | distn = tf$distributions$Normal(params$theta, 1) 105 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 106 | } 107 | stepsize = list("theta" = 1e-4) 108 | optStepsize = 1e-1 109 | sghmccv = sghmccvSetup(logLik, dataset, params, stepsize, optStepsize) 110 | nIters = 10^4L 111 | # Initialize location estimate 112 | locEstimate = 0 113 | # Initialise TensorFlow session 114 | sess = initSess(sghmccv) 115 | for ( i in 1:nIters ) { 116 | sgmcmcStep(sghmccv, sess) 117 | locEstimate = locEstimate + 1 / nIters * getParams(sghmccv, sess)$theta 118 | } 119 | # For more examples see vignettes 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /man/sgld.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sgld.R 3 | \name{sgld} 4 | \alias{sgld} 5 | \title{Stochastic Gradient Langevin Dynamics} 6 | \usage{ 7 | sgld(logLik, dataset, params, stepsize, logPrior = NULL, 8 | minibatchSize = 0.01, nIters = 10^4L, verbose = TRUE, seed = NULL) 9 | } 10 | \arguments{ 11 | \item{logLik}{function which takes parameters and dataset 12 | (list of TensorFlow variables and placeholders respectively) as input. 13 | It should return a TensorFlow expression which defines the log likelihood of the model.} 14 | 15 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 16 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 17 | 18 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 19 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 20 | 21 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 22 | The names in the list should correspond to those in params. 23 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 24 | 25 | \item{logPrior}{optional. Default uninformative improper prior. 26 | Function which takes parameters (list of TensorFlow variables) as input. 27 | The function should return a TensorFlow tensor which defines the log prior of the model.} 28 | 29 | \item{minibatchSize}{optional. Default 0.01. 30 | Numeric or integer value that specifies amount of dataset to use at each iteration 31 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 32 | 33 | \item{nIters}{optional. Default 10^4L. Integer specifying number of iterations to perform.} 34 | 35 | \item{verbose}{optional. Default TRUE. Boolean specifying whether to print algorithm progress} 36 | 37 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 38 | does not declare a seed for the TensorFlow session.} 39 | } 40 | \value{ 41 | Returns list of arrays for each parameter containing the MCMC chain. 42 | Dimension of the form (nIters,paramDim1,paramDim2,...) 43 | } 44 | \description{ 45 | Simulates from the posterior defined by the functions logLik and logPrior using 46 | stochastic gradient Langevin Dynamics. The function uses TensorFlow, so needs 47 | TensorFlow for python installed. 48 | } 49 | \examples{ 50 | \dontrun{ 51 | # Simulate from a Normal Distribution with uninformative prior 52 | dataset = list("x" = rnorm(1000)) 53 | params = list("theta" = 0) 54 | logLik = function(params, dataset) { 55 | distn = tf$distributions$Normal(params$theta, 1) 56 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 57 | } 58 | stepsize = list("theta" = 1e-4) 59 | output = sgld(logLik, dataset, params, stepsize) 60 | # For more examples see vignettes 61 | } 62 | } 63 | \references{ 64 | \itemize{\item \href{http://people.ee.duke.edu/~lcarin/398_icmlpaper.pdf}{ 65 | Welling, M., and Teh, Y. W. (2011). Bayesian learning via stochastic gradient Langevin dynamics. 66 | ICML (pp. 681-688).}} 67 | } 68 | -------------------------------------------------------------------------------- /man/sgldSetup.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sgld.R 3 | \name{sgldSetup} 4 | \alias{sgldSetup} 5 | \title{Create an sgld object} 6 | \usage{ 7 | sgldSetup(logLik, dataset, params, stepsize, logPrior = NULL, 8 | minibatchSize = 0.01, seed = NULL) 9 | } 10 | \arguments{ 11 | \item{logLik}{function which takes parameters and dataset 12 | (list of TensorFlow variables and placeholders respectively) as input. 13 | It should return a TensorFlow expression which defines the log likelihood of the model.} 14 | 15 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 16 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 17 | 18 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 19 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 20 | 21 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 22 | The names in the list should correspond to those in params. 23 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 24 | 25 | \item{logPrior}{optional. Default uninformative improper prior. 26 | Function which takes parameters (list of TensorFlow variables) as input. 27 | The function should return a TensorFlow tensor which defines the log prior of the model.} 28 | 29 | \item{minibatchSize}{optional. Default 0.01. 30 | Numeric or integer value that specifies amount of dataset to use at each iteration 31 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 32 | 33 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 34 | does not declare a seed for the TensorFlow session.} 35 | } 36 | \value{ 37 | The function returns an 'sgld' object, which is used to pass the required information 38 | about the current model to the \code{\link{sgmcmcStep}} function. The function 39 | \code{\link{sgmcmcStep}} runs one step of sgld. The sgld object has the following attributes: 40 | \describe{ 41 | \item{params}{list of tf$Variables with the same names as the params list passed to 42 | \code{\link{sgldSetup}}. This is the object passed to the logLik and logPrior functions you 43 | declared to calculate the log posterior gradient estimate.} 44 | \item{estLogPost}{a tensor that estimates the log posterior given the current 45 | placeholders and params (the placeholders holds the minibatches of data).} 46 | \item{N}{dataset size.} 47 | \item{data}{dataset as passed to \code{\link{sgldSetup}}.} 48 | \item{n}{minibatchSize as passed to \code{\link{sgldSetup}}.} 49 | \item{placeholders}{list of tf$placeholder objects with the same names as dataset 50 | used to feed minibatches of data to \code{\link{sgmcmcStep}}. These are the objects 51 | that get fed to the dataset argument of the logLik and logPrior functions you declared.} 52 | \item{stepsize}{list of stepsizes as passed to \code{\link{sgldSetup}}.} 53 | \item{dynamics}{a list of TensorFlow steps that are evaluated by \code{\link{sgmcmcStep}}.}} 54 | } 55 | \description{ 56 | Creates an sgld (stochastic gradient Langevin dynamics) object which can be passed to 57 | \code{\link{sgmcmcStep}} to simulate from 1 step of SGLD for the posterior defined by logLik 58 | and logPrior. This allows the user to code the loop themselves, as in many standard 59 | TensorFlow procedures (such as optimization). Which means they do not need to store 60 | the chain at each iteration. This is useful when the full chain needs a lot of memory. 61 | } 62 | \examples{ 63 | \dontrun{ 64 | # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 65 | # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 66 | dataset = list("x" = rnorm(1000)) 67 | params = list("theta" = 0) 68 | logLik = function(params, dataset) { 69 | distn = tf$distributions$Normal(params$theta, 1) 70 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 71 | } 72 | stepsize = list("theta" = 1e-4) 73 | sgld = sgldSetup(logLik, dataset, params, stepsize) 74 | nIters = 10^4L 75 | # Initialize location estimate 76 | locEstimate = 0 77 | # Initialise TensorFlow session 78 | sess = initSess(sgld) 79 | for ( i in 1:nIters ) { 80 | sgmcmcStep(sgld, sess) 81 | locEstimate = locEstimate + 1 / nIters * getParams(sgld, sess)$theta 82 | } 83 | # For more examples see vignettes 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /man/sgldcv.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sgldcv.R 3 | \name{sgldcv} 4 | \alias{sgldcv} 5 | \title{Stochastic Gradient Langevin Dynamics with Control Variates} 6 | \usage{ 7 | sgldcv(logLik, dataset, params, stepsize, optStepsize, logPrior = NULL, 8 | minibatchSize = 0.01, nIters = 10^4L, nItersOpt = 10^4L, 9 | verbose = TRUE, seed = NULL) 10 | } 11 | \arguments{ 12 | \item{logLik}{function which takes parameters and dataset 13 | (list of TensorFlow variables and placeholders respectively) as input. 14 | It should return a TensorFlow expression which defines the log likelihood of the model.} 15 | 16 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 17 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 18 | 19 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 20 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 21 | 22 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 23 | The names in the list should correspond to those in params. 24 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 25 | 26 | \item{optStepsize}{numeric value specifying the stepsize for the optimization 27 | to find MAP estimates of parameters. The TensorFlow GradientDescentOptimizer is used.} 28 | 29 | \item{logPrior}{optional. Default uninformative improper prior. 30 | Function which takes parameters (list of TensorFlow variables) as input. 31 | The function should return a TensorFlow tensor which defines the log prior of the model.} 32 | 33 | \item{minibatchSize}{optional. Default 0.01. 34 | Numeric or integer value that specifies amount of dataset to use at each iteration 35 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 36 | 37 | \item{nIters}{optional. Default 10^4L. Integer specifying number of iterations to perform.} 38 | 39 | \item{nItersOpt}{optional. Default 10^4L. 40 | Integer specifying number of iterations of initial optimization to perform.} 41 | 42 | \item{verbose}{optional. Default TRUE. Boolean specifying whether to print algorithm progress} 43 | 44 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 45 | does not declare a seed for the TensorFlow session.} 46 | } 47 | \value{ 48 | Returns list of arrays for each parameter containing the MCMC chain. 49 | Dimension of the form (nIters,paramDim1,paramDim2,...) 50 | } 51 | \description{ 52 | Simulates from the posterior defined by the functions logLik and logPrior using 53 | stochastic gradient Langevin Dynamics with an improved gradient estimate using Control Variates. 54 | The function uses TensorFlow, so needs TensorFlow for python installed. 55 | } 56 | \examples{ 57 | \dontrun{ 58 | # Simulate from a Normal Distribution with uninformative prior 59 | dataset = list("x" = rnorm(1000)) 60 | params = list("theta" = 0) 61 | logLik = function(params, dataset) { 62 | distn = tf$distributions$Normal(params$theta, 1) 63 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 64 | } 65 | stepsize = list("theta" = 1e-4) 66 | optStepsize = 1e-1 67 | output = sgldcv(logLik, dataset, params, stepsize, optStepsize) 68 | } 69 | } 70 | \references{ 71 | \itemize{ 72 | \item \href{https://arxiv.org/pdf/1706.05439.pdf}{ 73 | Baker, J., Fearnhead, P., Fox, E. B., and Nemeth, C. (2017). 74 | Control variates for stochastic gradient MCMC. ArXiv preprint arXiv:1706.05439.} 75 | \item \href{http://people.ee.duke.edu/~lcarin/398_icmlpaper.pdf}{ 76 | Welling, M., and Teh, Y. W. (2011). Bayesian learning via stochastic gradient Langevin dynamics. 77 | ICML (pp. 681-688).} } 78 | } 79 | -------------------------------------------------------------------------------- /man/sgldcvSetup.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sgldcv.R 3 | \name{sgldcvSetup} 4 | \alias{sgldcvSetup} 5 | \title{Create an sgldcv object} 6 | \usage{ 7 | sgldcvSetup(logLik, dataset, params, stepsize, optStepsize, logPrior = NULL, 8 | minibatchSize = 0.01, nItersOpt = 10^4L, verbose = TRUE, seed = NULL) 9 | } 10 | \arguments{ 11 | \item{logLik}{function which takes parameters and dataset 12 | (list of TensorFlow variables and placeholders respectively) as input. 13 | It should return a TensorFlow expression which defines the log likelihood of the model.} 14 | 15 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 16 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 17 | 18 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 19 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 20 | 21 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 22 | The names in the list should correspond to those in params. 23 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 24 | 25 | \item{optStepsize}{numeric value specifying the stepsize for the optimization 26 | to find MAP estimates of parameters. The TensorFlow GradientDescentOptimizer is used.} 27 | 28 | \item{logPrior}{optional. Default uninformative improper prior. 29 | Function which takes parameters (list of TensorFlow variables) as input. 30 | The function should return a TensorFlow tensor which defines the log prior of the model.} 31 | 32 | \item{minibatchSize}{optional. Default 0.01. 33 | Numeric or integer value that specifies amount of dataset to use at each iteration 34 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 35 | 36 | \item{nItersOpt}{optional. Default 10^4L. 37 | Integer specifying number of iterations of initial optimization to perform.} 38 | 39 | \item{verbose}{optional. Default TRUE. Boolean specifying whether to print algorithm progress} 40 | 41 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 42 | does not declare a seed for the TensorFlow session.} 43 | } 44 | \value{ 45 | The function returns an 'sgldcv' object, a type of sgmcmc object. 46 | Which is used to pass the required information about the current model to the 47 | \code{\link{sgmcmcStep}} function. The function \code{\link{sgmcmcStep}} runs one 48 | step of sgld with a gradient estimate that uses control variates. 49 | Attributes of the sgldcv object you'll probably find most useful are: 50 | \describe{ 51 | \item{params}{list of tf$Variables with the same names as the params list passed to 52 | \code{\link{sgldcvSetup}}. This is the object passed to the logLik and logPrior functions you 53 | declared to calculate the log posterior gradient estimate.} 54 | \item{paramsOpt}{list of tf$Variables with the same names as the \code{params} list passed to 55 | \code{\link{sgldcvSetup}}. These variables are used to initially find MAP estimates 56 | and then store these optimal parameter estimates.} 57 | \item{estLogPost}{a tensor that estimates the log posterior given the current 58 | placeholders and params.} 59 | \item{logPostOptGrad}{list of \code{tf$Variables} with same names as \code{params}, this stores 60 | the full log posterior gradient at each MAP estimate after the initial optimization step.}} 61 | Other attributes of the object are as follows: 62 | \describe{ 63 | \item{N}{dataset size.} 64 | \item{data}{dataset as passed to \code{\link{sgldcvSetup}}.} 65 | \item{n}{minibatchSize as passed to \code{\link{sgldcvSetup}}.} 66 | \item{placeholders}{list of tf$placeholder objects with the same names as dataset 67 | used to feed minibatches of data to \code{\link{sgmcmcStep}}. These are also the objects 68 | that gets fed to the dataset argument of the logLik and logPrior functions you declared.} 69 | \item{stepsize}{list of stepsizes as passed to \code{\link{sgldcvSetup}}} 70 | \item{dynamics}{a list of TensorFlow steps that are evaluated by \code{\link{sgmcmcStep}}.} 71 | \item{estLogPostOpt}{a TensorFlow tensor relying on \code{paramsOpt} and \code{placeholders} which 72 | estimates the log posterior at the optimal parameters. Used in the initial optimization step.} 73 | \item{fullLogPostOpt}{a TensorFlow tensor used in the calculation of the full log posterior 74 | gradient at the MAP estimates.} 75 | \item{optimizer}{a TensorFlow optimizer object used to find the initial MAP estimates.}} 76 | } 77 | \description{ 78 | Creates an sgldcv (stochastic gradient Langevin Dynamics with Control Variates) object 79 | which can be passed to \code{\link{sgmcmcStep}} to simulate from 1 step of sgld, using a 80 | gradient estimate with control variates for the posterior defined by logLik and logPrior. 81 | This allows the user to code the loop themselves, as in many standard 82 | TensorFlow procedures (such as optimization). Which means they do not need to store 83 | the chain at each iteration. This is useful when the full chain needs a lot of memory. 84 | } 85 | \examples{ 86 | \dontrun{ 87 | # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 88 | # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 89 | dataset = list("x" = rnorm(1000)) 90 | params = list("theta" = 0) 91 | logLik = function(params, dataset) { 92 | distn = tf$distributions$Normal(params$theta, 1) 93 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 94 | } 95 | stepsize = list("theta" = 1e-4) 96 | optStepsize = 1e-1 97 | sgldcv = sgldcvSetup(logLik, dataset, params, stepsize, optStepsize) 98 | nIters = 10^4L 99 | # Initialize location estimate 100 | locEstimate = 0 101 | # Initialise TensorFlow session 102 | sess = initSess(sgldcv) 103 | for ( i in 1:nIters ) { 104 | sgmcmcStep(sgldcv, sess) 105 | locEstimate = locEstimate + 1 / nIters * getParams(sgldcv, sess)$theta 106 | } 107 | # For more examples see vignettes 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /man/sgmcmc.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sgmcmc.R 3 | \docType{package} 4 | \name{sgmcmc} 5 | \alias{sgmcmc} 6 | \alias{sgmcmc-package} 7 | \title{sgmcmc: A package for stochastic gradient MCMC} 8 | \description{ 9 | The sgmcmc package implements some of the most popular stochastic gradient MCMC methods 10 | including SGLD, SGHMC, SGNHT. It also implements control variates as a way to increase 11 | the efficiency of these methods. The algorithms are implemented using TensorFlow 12 | which means no gradients need to be specified by the user as these are calculated 13 | automatically. It also means the algorithms are efficient. 14 | } 15 | \section{sgmcmc functions}{ 16 | 17 | The main functions of the package are sgld, sghmc and sgnht which implement the methods 18 | stochastic gradient Langevin dynamics, stochastic gradient Hamiltonian Monte Carlo and 19 | stochastic gradient Nose-Hoover Thermostat respectively. Also included are control variate 20 | versions of these algorithms, which uses control variates to increase their efficiency. 21 | These are the functions sgldcv, sghmccv and sgnhtcv. 22 | } 23 | 24 | \references{ 25 | Baker, J., Fearnhead, P., Fox, E. B., & Nemeth, C. (2017) 26 | control variates for stochastic gradient Langevin dynamics. Preprint. 27 | 28 | Welling, M., & Teh, Y. W. (2011). 29 | Bayesian learning via stochastic gradient Langevin dynamics. ICML (pp. 681-688). 30 | 31 | Chen, T., Fox, E. B., & Guestrin, C. (2014). 32 | stochastic gradient Hamiltonian Monte Carlo. In ICML (pp. 1683-1691). 33 | 34 | Ding, N., Fang, Y., Babbush, R., Chen, C., Skeel, R. D., & Neven, H. (2014). 35 | Bayesian sampling using stochastic gradient thermostats. NIPS (pp. 3203-3211). 36 | } 37 | -------------------------------------------------------------------------------- /man/sgmcmcStep.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/update.R 3 | \name{sgmcmcStep} 4 | \alias{sgmcmcStep} 5 | \title{Single step of sgmcmc} 6 | \usage{ 7 | sgmcmcStep(sgmcmc, sess) 8 | } 9 | \arguments{ 10 | \item{sgmcmc}{a stochastic gradient MCMC object returned by *Setup such as 11 | \code{\link{sgldSetup}}, \code{\link{sgldcvSetup}} etc.} 12 | 13 | \item{sess}{a TensorFlow session created using \code{\link{initSess}}} 14 | } 15 | \description{ 16 | Update parameters by performing a single sgmcmc step with dynamics as defined in the sgmcmc 17 | object. This can be used to perform sgmcmc steps inside a loop as in standard 18 | TensorFlow optimization procedures. 19 | This is useful when high dimensional chains cannot fit into memory. 20 | } 21 | \examples{ 22 | \dontrun{ 23 | # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 24 | # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 25 | dataset = list("x" = rnorm(1000)) 26 | params = list("theta" = 0) 27 | logLik = function(params, dataset) { 28 | distn = tf$distributions$Normal(params$theta, 1) 29 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 30 | } 31 | stepsize = list("theta" = 1e-4) 32 | sgld = sgldSetup(logLik, dataset, params, stepsize) 33 | nIters = 10^4L 34 | # Initialize location estimate 35 | locEstimate = 0 36 | # Initialise TensorFlow session 37 | sess = initSess(sgld) 38 | for ( i in 1:nIters ) { 39 | sgmcmcStep(sgld, sess) 40 | locEstimate = locEstimate + 1 / nIters * getParams(sgld, sess)$theta 41 | } 42 | # For more examples see vignettes 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /man/sgnht.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sgnht.R 3 | \name{sgnht} 4 | \alias{sgnht} 5 | \title{Stochastic Gradient Nose Hoover Thermostat} 6 | \usage{ 7 | sgnht(logLik, dataset, params, stepsize, logPrior = NULL, 8 | minibatchSize = 0.01, a = 0.01, nIters = 10^4L, verbose = TRUE, 9 | seed = NULL) 10 | } 11 | \arguments{ 12 | \item{logLik}{function which takes parameters and dataset 13 | (list of TensorFlow variables and placeholders respectively) as input. 14 | It should return a TensorFlow expression which defines the log likelihood of the model.} 15 | 16 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 17 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 18 | 19 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 20 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 21 | 22 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 23 | The names in the list should correspond to those in params. 24 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 25 | 26 | \item{logPrior}{optional. Default uninformative improper prior. 27 | Function which takes parameters (list of TensorFlow variables) as input. 28 | The function should return a TensorFlow tensor which defines the log prior of the model.} 29 | 30 | \item{minibatchSize}{optional. Default 0.01. 31 | Numeric or integer value that specifies amount of dataset to use at each iteration 32 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 33 | 34 | \item{a}{optional. Default 0.01. List of numeric values corresponding to SGNHT diffusion factors 35 | (see Algorithm 2 of the original paper). One value should be given 36 | for each parameter in params, the names should correspond to those in params. 37 | Alternatively specify a single float to specify that value for all parameters.} 38 | 39 | \item{nIters}{optional. Default 10^4L. Integer specifying number of iterations to perform.} 40 | 41 | \item{verbose}{optional. Default TRUE. Boolean specifying whether to print algorithm progress} 42 | 43 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 44 | does not declare a seed for the TensorFlow session.} 45 | } 46 | \value{ 47 | Returns list of arrays for each parameter containing the MCMC chain. 48 | Dimension of the form (nIters,paramDim1,paramDim2,...) 49 | } 50 | \description{ 51 | Simulates from the posterior defined by the functions logLik and logPrior using 52 | stochastic gradient Nose Hoover Thermostat. 53 | The thermostat step needs a dot product to be calculated between two vectors. 54 | So when the algorithm uses parameters that are higher order than vectors 55 | (e.g. matrices and tensors), the thermostat step uses a tensor contraction. 56 | Tensor contraction is otherwise known as the inner product between two tensors. 57 | } 58 | \examples{ 59 | \dontrun{ 60 | # Simulate from a Normal Distribution with uninformative, improper prior 61 | dataset = list("x" = rnorm(1000)) 62 | params = list("theta" = 0) 63 | logLik = function(params, dataset) { 64 | distn = tf$distributions$Normal(params$theta, 1) 65 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 66 | } 67 | stepsize = list("theta" = 5e-6) 68 | output = sgnht(logLik, dataset, params, stepsize) 69 | # For more examples see vignettes 70 | } 71 | } 72 | \references{ 73 | \itemize{\item \href{http://people.ee.duke.edu/~lcarin/sgnht-4.pdf}{ 74 | Ding, N., Fang, Y., Babbush, R., Chen, C., Skeel, R. D., and Neven, H. (2014). 75 | Bayesian sampling using stochastic gradient thermostats. NIPS (pp. 3203-3211).}} 76 | } 77 | -------------------------------------------------------------------------------- /man/sgnhtSetup.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sgnht.R 3 | \name{sgnhtSetup} 4 | \alias{sgnhtSetup} 5 | \title{Create an sgnht object} 6 | \usage{ 7 | sgnhtSetup(logLik, dataset, params, stepsize, logPrior = NULL, 8 | minibatchSize = 0.01, a = 0.01, seed = NULL) 9 | } 10 | \arguments{ 11 | \item{logLik}{function which takes parameters and dataset 12 | (list of TensorFlow variables and placeholders respectively) as input. 13 | It should return a TensorFlow expression which defines the log likelihood of the model.} 14 | 15 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 16 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 17 | 18 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 19 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 20 | 21 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 22 | The names in the list should correspond to those in params. 23 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 24 | 25 | \item{logPrior}{optional. Default uninformative improper prior. 26 | Function which takes parameters (list of TensorFlow variables) as input. 27 | The function should return a TensorFlow tensor which defines the log prior of the model.} 28 | 29 | \item{minibatchSize}{optional. Default 0.01. 30 | Numeric or integer value that specifies amount of dataset to use at each iteration 31 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 32 | 33 | \item{a}{optional. Default 0.01. List of numeric values corresponding to SGNHT diffusion factors 34 | (see Algorithm 2 of the original paper). One value should be given 35 | for each parameter in params, the names should correspond to those in params. 36 | Alternatively specify a single float to specify that value for all parameters.} 37 | 38 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 39 | does not declare a seed for the TensorFlow session.} 40 | } 41 | \value{ 42 | The function returns an 'sgnht' object, which is used to pass the required information 43 | about the current model to the \code{\link{sgmcmcStep}} function. The function 44 | \code{\link{sgmcmcStep}} runs one step of sgnht. The sgnht object has the following attributes: 45 | \describe{ 46 | \item{params}{list of tf$Variables with the same names as the params list passed to 47 | \code{\link{sgnhtSetup}}. This is the object passed to the logLik and logPrior functions you 48 | declared to calculate the log posterior gradient estimate.} 49 | \item{estLogPost}{a tensor that estimates the log posterior given the current 50 | placeholders and params.} 51 | \item{N}{dataset size.} 52 | \item{data}{dataset as passed to \code{\link{sgnhtSetup}}.} 53 | \item{n}{minibatchSize as passed to \code{\link{sgnhtSetup}}.} 54 | \item{placeholders}{list of tf$placeholder objects with the same names as dataset 55 | used to feed minibatches of data to \code{\link{sgmcmcStep}}. This object 56 | gets fed to the dataset argument of the logLik and logPrior functions you declared.} 57 | \item{stepsize}{list of stepsizes as passed to \code{\link{sgnhtSetup}}.} 58 | \item{a}{list of a tuning parameters as passed to \code{\link{sgnhtSetup}}.} 59 | \item{dynamics}{a list of TensorFlow steps that are evaluated by \code{\link{sgmcmcStep}}.}} 60 | } 61 | \description{ 62 | Creates an sgnht (stochastic gradient Nose Hoover Thermostat) object which can be passed to 63 | \code{\link{sgmcmcStep}} to simulate from 1 step of SGNHT for the posterior defined by 64 | logLik and logPrior. This allows the user to code the loop themselves, as in many standard 65 | TensorFlow procedures (such as optimization). Which means they do not need to store 66 | the chain at each iteration. This is useful when the full chain needs a lot of memory. 67 | } 68 | \examples{ 69 | \dontrun{ 70 | # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 71 | # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 72 | dataset = list("x" = rnorm(1000)) 73 | params = list("theta" = 0) 74 | logLik = function(params, dataset) { 75 | distn = tf$distributions$Normal(params$theta, 1) 76 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 77 | } 78 | stepsize = list("theta" = 1e-4) 79 | sgnht = sgnhtSetup(logLik, dataset, params, stepsize) 80 | nIters = 10^4L 81 | # Initialize location estimate 82 | locEstimate = 0 83 | # Initialise TensorFlow session 84 | sess = initSess(sgnht) 85 | for ( i in 1:nIters ) { 86 | sgmcmcStep(sgnht, sess) 87 | locEstimate = locEstimate + 1 / nIters * getParams(sgnht, sess)$theta 88 | } 89 | # For more examples see vignettes 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /man/sgnhtcv.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sgnhtcv.R 3 | \name{sgnhtcv} 4 | \alias{sgnhtcv} 5 | \title{Stochastic Gradient Nose Hoover Thermostat with Control Variates} 6 | \usage{ 7 | sgnhtcv(logLik, dataset, params, stepsize, optStepsize, logPrior = NULL, 8 | minibatchSize = 0.01, a = 0.01, nIters = 10^4L, nItersOpt = 10^4L, 9 | verbose = TRUE, seed = NULL) 10 | } 11 | \arguments{ 12 | \item{logLik}{function which takes parameters and dataset 13 | (list of TensorFlow variables and placeholders respectively) as input. 14 | It should return a TensorFlow expression which defines the log likelihood of the model.} 15 | 16 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 17 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 18 | 19 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 20 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 21 | 22 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 23 | The names in the list should correspond to those in params. 24 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 25 | 26 | \item{optStepsize}{numeric value specifying the stepsize for the optimization 27 | to find MAP estimates of parameters. The TensorFlow GradientDescentOptimizer is used.} 28 | 29 | \item{logPrior}{optional. Default uninformative improper prior. 30 | Function which takes parameters (list of TensorFlow variables) as input. 31 | The function should return a TensorFlow tensor which defines the log prior of the model.} 32 | 33 | \item{minibatchSize}{optional. Default 0.01. 34 | Numeric or integer value that specifies amount of dataset to use at each iteration 35 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 36 | 37 | \item{a}{optional. Default 0.01. List of numeric values corresponding to SGNHT diffusion factors 38 | (see Algorithm 2 of the original paper). One value should be given 39 | for each parameter in params, the names should correspond to those in params. 40 | Alternatively specify a single float to specify that value for all parameters.} 41 | 42 | \item{nIters}{optional. Default 10^4L. Integer specifying number of iterations to perform.} 43 | 44 | \item{nItersOpt}{optional. Default 10^4L. 45 | Integer specifying number of iterations of initial optimization to perform.} 46 | 47 | \item{verbose}{optional. Default TRUE. Boolean specifying whether to print algorithm progress} 48 | 49 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 50 | does not declare a seed for the TensorFlow session.} 51 | } 52 | \value{ 53 | Returns list of arrays for each parameter containing the MCMC chain. 54 | Dimension of the form (nIters,paramDim1,paramDim2,...). Names are the same as the params list. 55 | } 56 | \description{ 57 | Simulates from the posterior defined by the functions logLik and logPrior using 58 | stochastic gradient Nose Hoover Thermostat with an improved gradient estimate 59 | that is calculated using control variates. 60 | The thermostat step needs a dot product to be calculated between two vectors. 61 | So when the algorithm uses parameters that are higher order than vectors 62 | (e.g. matrices and tensors), the thermostat step uses a tensor contraction. 63 | Tensor contraction is otherwise known as the inner product between two tensors. 64 | } 65 | \examples{ 66 | \dontrun{ 67 | # Simulate from a Normal Distribution with uninformative prior 68 | dataset = list("x" = rnorm(1000)) 69 | params = list("theta" = 0) 70 | logLik = function(params, dataset) { 71 | distn = tf$distributions$Normal(params$theta, 1) 72 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 73 | } 74 | stepsize = list("theta" = 1e-4) 75 | optStepsize = 1e-1 76 | output = sgnhtcv(logLik, dataset, params, stepsize, optStepsize) 77 | } 78 | } 79 | \references{ 80 | \itemize{ 81 | \item \href{https://arxiv.org/pdf/1706.05439.pdf}{ 82 | Baker, J., Fearnhead, P., Fox, E. B., and Nemeth, C. (2017). 83 | Control variates for stochastic gradient MCMC. ArXiv preprint arXiv:1706.05439.} 84 | \item \href{http://people.ee.duke.edu/~lcarin/sgnht-4.pdf}{ 85 | Ding, N., Fang, Y., Babbush, R., Chen, C., Skeel, R. D., and Neven, H. (2014). 86 | Bayesian sampling using stochastic gradient thermostats. NIPS (pp. 3203-3211).}} 87 | } 88 | -------------------------------------------------------------------------------- /man/sgnhtcvSetup.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sgnhtcv.R 3 | \name{sgnhtcvSetup} 4 | \alias{sgnhtcvSetup} 5 | \title{Create an sgnhtcv object} 6 | \usage{ 7 | sgnhtcvSetup(logLik, dataset, params, stepsize, optStepsize, logPrior = NULL, 8 | minibatchSize = 0.01, a = 0.01, nItersOpt = 10^4L, verbose = TRUE, 9 | seed = NULL) 10 | } 11 | \arguments{ 12 | \item{logLik}{function which takes parameters and dataset 13 | (list of TensorFlow variables and placeholders respectively) as input. 14 | It should return a TensorFlow expression which defines the log likelihood of the model.} 15 | 16 | \item{dataset}{list of numeric R arrays which defines the datasets for the problem. 17 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 18 | 19 | \item{params}{list of numeric R arrays which define the starting point of each parameter. 20 | The names in the list should correspond to those referred to in the logLik and logPrior functions} 21 | 22 | \item{stepsize}{list of numeric values corresponding to the SGLD stepsizes for each parameter 23 | The names in the list should correspond to those in params. 24 | Alternatively specify a single numeric value to use that stepsize for all parameters.} 25 | 26 | \item{optStepsize}{numeric value specifying the stepsize for the optimization 27 | to find MAP estimates of parameters. The TensorFlow GradientDescentOptimizer is used.} 28 | 29 | \item{logPrior}{optional. Default uninformative improper prior. 30 | Function which takes parameters (list of TensorFlow variables) as input. 31 | The function should return a TensorFlow tensor which defines the log prior of the model.} 32 | 33 | \item{minibatchSize}{optional. Default 0.01. 34 | Numeric or integer value that specifies amount of dataset to use at each iteration 35 | either as proportion of dataset size (if between 0 and 1) or actual magnitude (if an integer).} 36 | 37 | \item{a}{optional. Default 0.01. List of numeric values corresponding to SGNHT diffusion factors 38 | (see Algorithm 2 of the original paper). One value should be given 39 | for each parameter in params, the names should correspond to those in params. 40 | Alternatively specify a single float to specify that value for all parameters.} 41 | 42 | \item{nItersOpt}{optional. Default 10^4L. 43 | Integer specifying number of iterations of initial optimization to perform.} 44 | 45 | \item{verbose}{optional. Default TRUE. Boolean specifying whether to print algorithm progress} 46 | 47 | \item{seed}{optional. Default NULL. Numeric seed for random number generation. The default 48 | does not declare a seed for the TensorFlow session.} 49 | } 50 | \value{ 51 | The function returns an 'sgnhtcv' object, a type of sgmcmc object. 52 | Which is used to pass the required information about the current model to the 53 | \code{\link{sgmcmcStep}} function. The function \code{\link{sgmcmcStep}} runs one 54 | step of sgnht with a gradient estimate that uses control variates. 55 | Attributes of the sgnhtcv object you'll probably find most useful are: 56 | \describe{ 57 | \item{params}{list of tf$Variables with the same names as the params list passed to 58 | \code{\link{sgnhtcvSetup}}. This is the object passed to the logLik and logPrior functions you 59 | declared to calculate the log posterior gradient estimate.} 60 | \item{paramsOpt}{list of tf$Variables with the same names as the \code{params} list passed to 61 | \code{\link{sgnhtcvSetup}}. These variables are used to initially find MAP estimates 62 | and then store these optimal parameter estimates.} 63 | \item{estLogPost}{a tensor relying on \code{params} and \code{placeholders}. 64 | This tensor estimates the log posterior given the current placeholders and params.} 65 | \item{logPostOptGrad}{list of \code{tf$Variables} with same names as \code{params}, this stores 66 | the full log posterior gradient at each MAP estimate after the initial optimization step.}} 67 | Other attributes of the object are as follows: 68 | \describe{ 69 | \item{N}{dataset size.} 70 | \item{data}{dataset as passed to \code{\link{sgnhtcvSetup}}.} 71 | \item{n}{minibatchSize as passed to \code{\link{sgnhtcvSetup}}.} 72 | \item{placeholders}{list of tf$placeholder objects with the same names as dataset 73 | used to feed minibatches of data to \code{\link{sgmcmcStep}}. These are also the objects 74 | that gets fed to the dataset argument of the logLik and logPrior functions you declared.} 75 | \item{stepsize}{list of stepsizes as passed to \code{\link{sgnhtcvSetup}}} 76 | \item{alpha}{list of alpha tuning parameters as passed to \code{\link{sgnhtSetup}}.} 77 | \item{L}{integer trajectory parameter as passed to \code{\link{sgnhtSetup}}.} 78 | \item{dynamics}{a list of TensorFlow steps that are evaluated by \code{\link{sgmcmcStep}}.} 79 | \item{estLogPostOpt}{a TensorFlow tensor relying on \code{paramsOpt} and \code{placeholders} which 80 | estimates the log posterior at the optimal parameters. Used in the initial optimization step.} 81 | \item{fullLogPostOpt}{a TensorFlow tensor used in the calculation of the full log posterior 82 | gradient at the MAP estimates.} 83 | \item{optimizer}{a TensorFlow optimizer object used to find the initial MAP estimates.}} 84 | } 85 | \description{ 86 | Creates an sgnhtcv (stochastic gradient Nose Hoover thermostat with Control Variates) object 87 | which can be passed to \code{\link{sgmcmcStep}} to simulate from 1 step of sgnht, using a 88 | gradient estimate with control variates for the posterior defined by logLik and logPrior. 89 | This allows the user to code the loop themselves, as in many standard 90 | TensorFlow procedures (such as optimization). Which means they do not need to store 91 | the chain at each iteration. This is useful when the full chain needs a lot of memory. 92 | } 93 | \examples{ 94 | \dontrun{ 95 | # Simulate from a Normal Distribution, unknown location and known scale with uninformative prior 96 | # Run sgmcmc step by step and calculate estimate of location on the fly to reduce storage 97 | dataset = list("x" = rnorm(1000)) 98 | params = list("theta" = 0) 99 | logLik = function(params, dataset) { 100 | distn = tf$distributions$Normal(params$theta, 1) 101 | return(tf$reduce_sum(distn$log_prob(dataset$x))) 102 | } 103 | stepsize = list("theta" = 1e-4) 104 | optStepsize = 1e-1 105 | sgnhtcv = sgnhtcvSetup(logLik, dataset, params, stepsize, optStepsize) 106 | nIters = 10^4L 107 | # Initialize location estimate 108 | locEstimate = 0 109 | # Initialise TensorFlow session 110 | sess = initSess(sgnhtcv) 111 | for ( i in 1:nIters ) { 112 | sgmcmcStep(sgnhtcv, sess) 113 | locEstimate = locEstimate + 1 / nIters * getParams(sgnhtcv, sess)$theta 114 | } 115 | # For more examples see vignettes 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(sgmcmc) 3 | 4 | test_check("sgmcmc") 5 | -------------------------------------------------------------------------------- /tests/testthat/test1dGauss.R: -------------------------------------------------------------------------------- 1 | # Declare constants and data for simulation from 1d gaussian 2 | declareConsts = function() { 3 | testData = list() 4 | # Simulate data 5 | testData$N = 10^4 6 | testData$mu = 0 7 | testData$sigma = 1 8 | testData$X = rnorm( testData$N, testData$mu, testData$sigma ) 9 | testData$n = 100 10 | testData$data = list( "X" = testData$X ) 11 | testData$params = list( "theta" = rnorm( 1, mean = 0, sd = 1 ) ) 12 | testData$optStepsize = 1e-5 13 | testData$nIters = 1100 14 | testData$nItersOpt = 1000 15 | testData$burnIn = 100 16 | return( testData ) 17 | } 18 | 19 | logLik = function( params, data ) { 20 | baseDist = tf$distributions$Normal( params$theta, 1 ) 21 | return( tf$reduce_sum( baseDist$log_prob( data$X ) ) ) 22 | } 23 | 24 | logPrior = function( params ) { 25 | baseDist = tf$distributions$Normal( 0, 5 ) 26 | return( tf$reduce_sum( baseDist$log_prob( params$theta ) ) ) 27 | } 28 | 29 | sgldTest = function( testData ) { 30 | stepsize = list( "theta" = 1e-4 ) 31 | storage = sgld( logLik, testData$data, testData$params, stepsize, testData$n, logPrior = logPrior, nIters = testData$nIters, verbose = FALSE, seed = 13 ) 32 | # Remove burn in 33 | thetaOut = storage$theta[-c(1:testData$burnIn)] 34 | return( thetaOut ) 35 | } 36 | 37 | sgldcvTest = function( testData ) { 38 | stepsize = list( "theta" = 1e-4 ) 39 | storage = sgldcv( logLik, testData$data, testData$params, stepsize, testData$optStepsize, logPrior = logPrior, minibatchSize = testData$n, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE, seed = 13 ) 40 | # Remove burn in 41 | thetaOut = storage$theta[-c(1:testData$burnIn)] 42 | return( thetaOut ) 43 | } 44 | 45 | sghmcTest = function( testData ) { 46 | eta = list( "theta" = 1e-5 ) 47 | alpha = list( "theta" = 1e-1 ) 48 | L = 3 49 | storage = sghmc( logLik, testData$data, testData$params, eta, logPrior = logPrior, minibatchSize = testData$n, alpha = alpha, L = L, nIters = testData$nIters, verbose = FALSE, seed = 13 ) 50 | # Remove burn in 51 | thetaOut = storage$theta[-c(1:testData$burnIn)] 52 | return( thetaOut ) 53 | } 54 | 55 | sghmccvTest = function( testData ) { 56 | eta = list( "theta" = 5e-5 ) 57 | alpha = list( "theta" = 1e-1 ) 58 | L = 3 59 | storage = sghmccv( logLik, testData$data, testData$params, eta, testData$optStepsize, logPrior = logPrior, minibatchSize = testData$n, alpha = alpha, L = L, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE, seed = 13 ) 60 | # Remove burn in 61 | thetaOut = storage$theta[-c(1:testData$burnIn)] 62 | return( thetaOut ) 63 | } 64 | 65 | sgnhtTest = function( testData ) { 66 | eta = list( "theta" = 5e-6 ) 67 | a = list( "theta" = 1e-2 ) 68 | # SGNHT tends to need a good starting point to work well 69 | sgnht = list( "theta" = testData$mu ) 70 | storage = sgnht( logLik, testData$data, testData$params, eta, logPrior = logPrior, minibatchSize = testData$n, a = a, nIters = testData$nIters, verbose = FALSE, seed = 13 ) 71 | # Remove burn in 72 | thetaOut = storage$theta[-c(1:testData$burnIn)] 73 | return( thetaOut ) 74 | } 75 | 76 | sgnhtcvTest = function( testData ) { 77 | eta = list( "theta" = 1e-4 ) 78 | a = list( "theta" = 1e-2 ) 79 | storage = sgnhtcv( logLik, testData$data, testData$params, eta, testData$optStepsize, logPrior = logPrior, minibatchSize = testData$n, a = a, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE, seed = 13 ) 80 | # Remove burn in 81 | thetaOut = storage$theta[-c(1:testData$burnIn)] 82 | return( thetaOut ) 83 | } 84 | 85 | test_that( "Check SGLD chain reasonable for 1d Gaussian", { 86 | tryCatch({ 87 | tf$constant(c(1, 1)) 88 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 89 | testData = declareConsts() 90 | thetaOut = sgldTest( testData ) 91 | # Check sample is reasonable 92 | expect_lte(max(thetaOut), 0.5) 93 | expect_gte(min(thetaOut), -0.5) 94 | # Check close to zero 95 | expect_lte(mean(thetaOut)^2, 0.1) 96 | } ) 97 | 98 | 99 | test_that( "Check SGLDCV chain reasonable for 1d Gaussian", { 100 | tryCatch({ 101 | tf$constant(c(1, 1)) 102 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 103 | testData = declareConsts() 104 | thetaOut = sgldcvTest( testData ) 105 | # Check sample is reasonable 106 | expect_lte(max(thetaOut), 0.5) 107 | expect_gte(min(thetaOut), -0.5) 108 | # Check close to zero 109 | expect_lte(mean(thetaOut)^2, 0.1) 110 | } ) 111 | 112 | test_that( "Check SGHMC chain reasonable for 1d Gaussian", { 113 | tryCatch({ 114 | tf$constant(c(1, 1)) 115 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 116 | testData = declareConsts() 117 | thetaOut = sghmcTest( testData ) 118 | # Check sample is reasonable 119 | expect_lte(max(thetaOut), 0.5) 120 | expect_gte(min(thetaOut), -0.5) 121 | # Check close to zero 122 | expect_lte(mean(thetaOut)^2, 0.1) 123 | } ) 124 | 125 | test_that( "Check SGHMCCV chain reasonable for 1d Gaussian", { 126 | tryCatch({ 127 | tf$constant(c(1, 1)) 128 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 129 | testData = declareConsts() 130 | thetaOut = sghmccvTest( testData ) 131 | # Check sample is reasonable 132 | expect_lte(max(thetaOut), 0.5) 133 | expect_gte(min(thetaOut), -0.5) 134 | # Check close to zero 135 | expect_lte(mean(thetaOut)^2, 0.1) 136 | } ) 137 | 138 | test_that( "Check SGNHT chain reasonable for 1d Gaussian", { 139 | tryCatch({ 140 | tf$constant(c(1, 1)) 141 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 142 | testData = declareConsts() 143 | thetaOut = sgnhtTest( testData ) 144 | # Check sample is reasonable 145 | expect_lte(max(thetaOut), 0.5) 146 | expect_gte(min(thetaOut), -0.5) 147 | # Check close to zero 148 | expect_lte(mean(thetaOut)^2, 0.1) 149 | } ) 150 | 151 | test_that( "Check SGNHTCV chain reasonable for 1d Gaussian", { 152 | tryCatch({ 153 | tf$constant(c(1, 1)) 154 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 155 | testData = declareConsts() 156 | thetaOut = sgnhtcvTest( testData ) 157 | # Check sample is reasonable 158 | expect_lte(max(thetaOut), 0.5) 159 | expect_gte(min(thetaOut), -0.5) 160 | # Check close to zero 161 | expect_lte(mean(thetaOut)^2, 0.1) 162 | } ) 163 | -------------------------------------------------------------------------------- /tests/testthat/test3dGauss.R: -------------------------------------------------------------------------------- 1 | # Declare constants and data for simulation from 1d gaussian 2 | declareConsts = function() { 3 | testData = list() 4 | # Simulate data 5 | testData$N = 10^4 6 | testData$d = 3 7 | testData$mu = rep(0, 3) 8 | testData$Sigma = matrix( c( 1, 0.3, 0.5, 0.3, 1, 0.2, 0.5, 0.2, 1 ), ncol = 3 ) 9 | testData$X = MASS::mvrnorm( testData$N, testData$mu, testData$Sigma ) 10 | testData$n = 100 11 | testData$data = list( "X" = testData$X ) 12 | testData$params = list( "theta" = rnorm( 3, mean = 0, sd = 1 ) ) 13 | testData$optStepsize = 1e-5 14 | testData$nIters = 1100 15 | testData$nItersOpt = 1000 16 | testData$burnIn = 100 17 | return( testData ) 18 | } 19 | 20 | logLik = function( params, data ) { 21 | Sigma = matrix( c( 1, 0.3, 0.5, 0.3, 1, 0.2, 0.5, 0.2, 1 ), ncol = 3 ) 22 | Sigma = tf$constant( Sigma, dtype = tf$float32 ) 23 | baseDist = tf$distributions$MultivariateNormalFullCovariance( params$theta, Sigma ) 24 | return( tf$reduce_sum( baseDist$log_prob( data$X ) ) ) 25 | } 26 | 27 | logPrior = function( params ) { 28 | baseDist = tf$distributions$Normal( 0, 5 ) 29 | return( tf$reduce_sum( baseDist$log_prob( params$theta ) ) ) 30 | } 31 | 32 | sgldTest = function( testData ) { 33 | stepsize = list( "theta" = 1e-4 ) 34 | storage = sgld( logLik, testData$data, testData$params, stepsize, testData$n, logPrior = logPrior, nIters = testData$nIters, verbose = FALSE, seed = 13 ) 35 | # Remove burn in 36 | thetaOut = storage$theta[-c(1:testData$burnIn),] 37 | return( thetaOut ) 38 | } 39 | 40 | sgldcvTest = function( testData ) { 41 | stepsize = list( "theta" = 1e-4 ) 42 | storage = sgldcv( logLik, testData$data, testData$params, stepsize, testData$optStepsize, logPrior = logPrior, minibatchSize = testData$n, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE, seed = 13 ) 43 | # Remove burn in 44 | thetaOut = storage$theta[-c(1:testData$burnIn),] 45 | return( thetaOut ) 46 | } 47 | 48 | sghmcTest = function( testData ) { 49 | eta = list( "theta" = 1e-5 ) 50 | alpha = list( "theta" = 1e-1 ) 51 | L = 3 52 | storage = sghmc( logLik, testData$data, testData$params, eta, logPrior = logPrior, minibatchSize = testData$n, alpha = alpha, L = L, nIters = testData$nIters, verbose = FALSE, seed = 13 ) 53 | # Remove burn in 54 | thetaOut = storage$theta[-c(1:testData$burnIn),] 55 | return( thetaOut ) 56 | } 57 | 58 | sghmccvTest = function( testData ) { 59 | eta = list( "theta" = 5e-5 ) 60 | alpha = list( "theta" = 1e-1 ) 61 | L = 3 62 | storage = sghmccv( logLik, testData$data, testData$params, eta, testData$optStepsize, logPrior = logPrior, minibatchSize = testData$n, alpha = alpha, L = L, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE, seed = 13 ) 63 | # Remove burn in 64 | thetaOut = storage$theta[-c(1:testData$burnIn),] 65 | return( thetaOut ) 66 | } 67 | 68 | sgnhtTest = function( testData ) { 69 | eta = list( "theta" = 5e-6 ) 70 | a = list( "theta" = 1e-2 ) 71 | # SGNHT tends to need a good starting point to work well 72 | sgnht = list( "theta" = testData$mu ) 73 | storage = sgnht( logLik, testData$data, testData$params, eta, logPrior = logPrior, minibatchSize = testData$n, a = a, nIters = testData$nIters, verbose = FALSE, seed = 13 ) 74 | # Remove burn in 75 | thetaOut = storage$theta[-c(1:testData$burnIn),] 76 | return( thetaOut ) 77 | } 78 | 79 | sgnhtcvTest = function( testData ) { 80 | eta = list( "theta" = 1e-4 ) 81 | a = list( "theta" = 1e-2 ) 82 | storage = sgnhtcv( logLik, testData$data, testData$params, eta, testData$optStepsize, logPrior = logPrior, minibatchSize = testData$n, a = a, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE, seed = 13 ) 83 | # Remove burn in 84 | thetaOut = storage$theta[-c(1:testData$burnIn),] 85 | return( thetaOut ) 86 | } 87 | 88 | test_that( "Check SGLD chain reasonable for 3d Gaussian", { 89 | tryCatch({ 90 | tf$constant(c(1, 1)) 91 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 92 | testData = declareConsts() 93 | thetaOut = sgldTest( testData ) 94 | # Check true theta contained in chain 95 | for ( d in 1:testData$d ) { 96 | expect_gte(min(thetaOut[,d]), -0.5) 97 | expect_lte(max(thetaOut[,d]), 0.5) 98 | # Check close to zero 99 | expect_lte(mean(thetaOut[,d]^2), 0.1) 100 | } 101 | } ) 102 | 103 | 104 | test_that( "Check SGLDCV chain reasonable for 3d Gaussian", { 105 | tryCatch({ 106 | tf$constant(c(1, 1)) 107 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 108 | testData = declareConsts() 109 | thetaOut = sgldcvTest( testData ) 110 | # Check true theta contained in chain 111 | for ( d in 1:testData$d ) { 112 | expect_gte(min(thetaOut[,d]), -0.5) 113 | expect_lte(max(thetaOut[,d]), 0.5) 114 | # Check close to zero 115 | expect_lte(mean(thetaOut[,d]^2), 0.1) 116 | } 117 | } ) 118 | 119 | test_that( "Check SGHMC chain reasonable for 3d Gaussian", { 120 | tryCatch({ 121 | tf$constant(c(1, 1)) 122 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 123 | testData = declareConsts() 124 | thetaOut = sghmcTest( testData ) 125 | # Check true theta contained in chain 126 | for ( d in 1:testData$d ) { 127 | expect_gte(min(thetaOut[,d]), -0.5) 128 | expect_lte(max(thetaOut[,d]), 0.5) 129 | # Check close to zero 130 | expect_lte(mean(thetaOut[,d]^2), 0.1) 131 | } 132 | } ) 133 | 134 | test_that( "Check SGHMCCV chain reasonable for 3d Gaussian", { 135 | tryCatch({ 136 | tf$constant(c(1, 1)) 137 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 138 | testData = declareConsts() 139 | thetaOut = sghmccvTest( testData ) 140 | # Check true theta contained in chain 141 | for ( d in 1:testData$d ) { 142 | expect_gte(min(thetaOut[,d]), -0.5) 143 | expect_lte(max(thetaOut[,d]), 0.5) 144 | # Check close to zero 145 | expect_lte(mean(thetaOut[,d]^2), 0.1) 146 | } 147 | } ) 148 | 149 | test_that( "Check SGNHT chain reasonable for 3d Gaussian", { 150 | tryCatch({ 151 | tf$constant(c(1, 1)) 152 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 153 | testData = declareConsts() 154 | thetaOut = sgnhtTest( testData ) 155 | # Check true theta contained in chain 156 | for ( d in 1:testData$d ) { 157 | expect_gte(min(thetaOut[,d]), -0.5) 158 | expect_lte(max(thetaOut[,d]), 0.5) 159 | # Check close to zero 160 | expect_lte(mean(thetaOut[,d]^2), 0.1) 161 | } 162 | } ) 163 | 164 | test_that( "Check SGNHTCV chain reasonable for 3d Gaussian", { 165 | tryCatch({ 166 | tf$constant(c(1, 1)) 167 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 168 | testData = declareConsts() 169 | thetaOut = sgnhtcvTest( testData ) 170 | # Check true theta contained in chain 171 | for ( d in 1:testData$d ) { 172 | expect_gte(min(thetaOut[,d]), -0.5) 173 | expect_lte(max(thetaOut[,d]), 0.5) 174 | # Check close to zero 175 | expect_lte(mean(thetaOut[,d]^2), 0.1) 176 | } 177 | } ) 178 | -------------------------------------------------------------------------------- /tests/testthat/testFloat64.R: -------------------------------------------------------------------------------- 1 | # Declare constants and data for simulation from 1d gaussian 2 | declareConsts = function() { 3 | testData = list() 4 | # Simulate data 5 | testData$N = 10^4 6 | testData$x = rnorm( testData$N ) 7 | testData$n = 100 8 | testData$data = list( "x" = testData$x ) 9 | testData$params = list( "theta" = rnorm( 1, mean = 0, sd = 10 ) ) 10 | testData$optStepsize = 1e-5 11 | testData$nIters = 1100 12 | testData$nItersOpt = 1000 13 | testData$burnIn = 100 14 | testData$alpha = 0.01 15 | testData$width = 1 16 | return( testData ) 17 | } 18 | 19 | logLik = function( params, data ) { 20 | sigma = tf$constant( 1, dtype = tf$float64 ) 21 | baseDist = tf$distributions$Normal(params$theta, sigma) 22 | return(tf$reduce_sum(baseDist$log_prob(data$x))) 23 | } 24 | 25 | logPrior = function( params ) { 26 | baseDist = tf$distributions$Normal(0, 5) 27 | return( baseDist$log_prob( params$theta ) ) 28 | } 29 | 30 | sgldTest = function( testData ) { 31 | stepsize = list( "theta" = 1e-4 ) 32 | storage = sgld( logLik, testData$data, testData$params, stepsize, logPrior = logPrior, minibatchSize = testData$n, nIters = testData$nIters, verbose = FALSE ) 33 | thetaOut = storage$theta[-c(1:testData$burnIn)] 34 | return( thetaOut ) 35 | } 36 | 37 | sgldcvTest = function( testData ) { 38 | stepsize = list( "theta" = 1e-4 ) 39 | storage = sgldcv( logLik, testData$data, testData$params, stepsize, testData$optStepsize, logPrior = logPrior, minibatchSize = testData$n, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE ) 40 | return( storage ) 41 | } 42 | 43 | sghmcTest = function( testData ) { 44 | eta = list( "theta" = 1e-5 ) 45 | alpha = list( "theta" = 1e-1 ) 46 | L = 3 47 | storage = sghmc( logLik, testData$data, testData$params, eta, logPrior = logPrior, minibatchSize = testData$n, alpha = alpha, L = L, nIters = testData$nIters, verbose = FALSE ) 48 | thetaOut = storage$theta[-c(1:testData$burnIn)] 49 | return( thetaOut ) 50 | } 51 | 52 | 53 | sghmccvTest = function( testData ) { 54 | eta = list( "theta" = 1e-4 ) 55 | alpha = list( "theta" = 1e-1 ) 56 | L = 3 57 | storage = sghmccv( logLik, testData$data, testData$params, eta, testData$optStepsize, logPrior = logPrior, minibatchSize = testData$n, alpha = alpha, L = L, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE ) 58 | return( storage ) 59 | } 60 | 61 | sgnhtTest = function( testData ) { 62 | eta = list( "theta" = 1e-6 ) 63 | a = list( "theta" = 1e-2 ) 64 | storage = sgnht( logLik, testData$data, testData$params, eta, logPrior = logPrior, minibatchSize = testData$n, a = a, nIters = testData$nIters, verbose = FALSE ) 65 | thetaOut = storage$theta[-c(1:testData$burnIn)] 66 | return( thetaOut ) 67 | } 68 | 69 | sgnhtcvTest = function( testData ) { 70 | eta = list( "theta" = 1e-5 ) 71 | a = list( "theta" = 1e-2 ) 72 | storage = sgnhtcv( logLik, testData$data, testData$params, eta, testData$optStepsize, logPrior = logPrior, minibatchSize = testData$n, a = a, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE ) 73 | return( storage ) 74 | } 75 | 76 | test_that( "sgld: Check Error thrown for float64 input", { 77 | tryCatch({ 78 | tf$constant(c(1, 1)) 79 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 80 | testData = declareConsts() 81 | expect_error( sgldTest( testData ) ) 82 | } ) 83 | 84 | test_that( "sgldcv: Check Error thrown for float64 input", { 85 | tryCatch({ 86 | tf$constant(c(1, 1)) 87 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 88 | testData = declareConsts() 89 | expect_error( sgldcvTest( testData ) ) 90 | } ) 91 | 92 | test_that( "sghmc: Check Error thrown for float64 input", { 93 | tryCatch({ 94 | tf$constant(c(1, 1)) 95 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 96 | testData = declareConsts() 97 | expect_error( sghmcTest( testData ) ) 98 | } ) 99 | 100 | test_that( "sghmccv: Check Error thrown for float64 input", { 101 | tryCatch({ 102 | tf$constant(c(1, 1)) 103 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 104 | testData = declareConsts() 105 | expect_error( sghmccvTest( testData ) ) 106 | } ) 107 | 108 | test_that( "sgnht: Check Error thrown for float64 input", { 109 | tryCatch({ 110 | tf$constant(c(1, 1)) 111 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 112 | testData = declareConsts() 113 | expect_error( sgnhtTest( testData ) ) 114 | } ) 115 | 116 | test_that( "sgnhtcv: Check Error thrown for float64 input", { 117 | tryCatch({ 118 | tf$constant(c(1, 1)) 119 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 120 | testData = declareConsts() 121 | expect_error( sgnhtcvTest( testData ) ) 122 | } ) 123 | -------------------------------------------------------------------------------- /tests/testthat/testMatrixParam.R: -------------------------------------------------------------------------------- 1 | # Declare constants and data for simulation from 1d gaussian 2 | declareConsts = function() { 3 | testData = list() 4 | # Simulate data 5 | testData$N = 10^4 6 | testData$Sigma = diag(2) + 0.5 7 | testData$X = MASS::mvrnorm( testData$N, c( 0, 0 ), testData$Sigma ) 8 | testData$n = 100 9 | testData$data = list( "X" = testData$X ) 10 | testData$params = list( "Sigma" = diag(2) ) 11 | testData$optStepsize = 1e-5 12 | testData$nIters = 100 13 | testData$nItersOpt = 1000 14 | return( testData ) 15 | } 16 | 17 | logLik = function( params, dataset ) { 18 | # Declare distribution of each observation 19 | baseDist = tf$distributions$MultivariateNormalFullCovariance( c(0, 0), params$Sigma ) 20 | # Declare log likelihood function and return 21 | logLik = tf$reduce_sum( baseDist$log_prob( dataset$X ) ) 22 | return( logLik ) 23 | } 24 | 25 | logPrior = function( params ) { 26 | Sigma0 = tf$constant( diag(2), dtype = tf$float32 ) 27 | baseDist = tf$distributions$Wishart( 2, scale = Sigma0 ) 28 | logPrior = baseDist$log_prob( params$Sigma ) 29 | return( logPrior ) 30 | } 31 | 32 | sgldTest = function( testData ) { 33 | stepsize = 1e-4 34 | storage = sgld( logLik, testData$data, testData$params, stepsize, logPrior = logPrior, nIters = testData$nIters, verbose = FALSE ) 35 | return( storage ) 36 | } 37 | 38 | sgldcvTest = function( testData ) { 39 | stepsize = 1e-4 40 | storage = sgldcv( logLik, testData$data, testData$params, stepsize, testData$optStepsize, logPrior = logPrior, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE ) 41 | return( storage ) 42 | } 43 | 44 | sghmcTest = function( testData ) { 45 | stepsize = 1e-4 46 | storage = sghmc( logLik, testData$data, testData$params, stepsize, logPrior = logPrior, nIters = testData$nIters, verbose = FALSE ) 47 | return( storage ) 48 | } 49 | 50 | sghmccvTest = function( testData ) { 51 | stepsize = 1e-4 52 | storage = sghmccv( logLik, testData$data, testData$params, stepsize, testData$optStepsize, logPrior = logPrior, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE ) 53 | return( storage ) 54 | } 55 | 56 | sgnhtTest = function( testData ) { 57 | stepsize = 1e-6 58 | storage = sgnht( logLik, testData$data, testData$params, stepsize, logPrior = logPrior, nIters = testData$nIters, verbose = FALSE ) 59 | return( storage ) 60 | } 61 | 62 | sgnhtcvTest = function( testData ) { 63 | stepsize = 1e-4 64 | storage = sgnhtcv( logLik, testData$data, testData$params, stepsize, testData$optStepsize, logPrior = logPrior, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE ) 65 | return( storage ) 66 | } 67 | 68 | test_that( "sgld: matrix parameters", { 69 | tryCatch({ 70 | tf$constant(c(1, 1)) 71 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 72 | testData = declareConsts() 73 | i = sample( testData$nIters, 1 ) 74 | output = sgldTest( testData )$Sigma[i,,] 75 | expect_equal( dim( output )[1], 2 ) 76 | expect_equal( dim( output )[2], 2 ) 77 | } ) 78 | 79 | test_that( "sgldcv: matrix parameters", { 80 | tryCatch({ 81 | tf$constant(c(1, 1)) 82 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 83 | testData = declareConsts() 84 | i = sample( testData$nIters, 1 ) 85 | output = sgldcvTest( testData )$Sigma[i,,] 86 | expect_equal( dim( output )[1], 2 ) 87 | expect_equal( dim( output )[2], 2 ) 88 | } ) 89 | 90 | test_that( "sghmc: matrix parameters", { 91 | tryCatch({ 92 | tf$constant(c(1, 1)) 93 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 94 | testData = declareConsts() 95 | i = sample( testData$nIters, 1 ) 96 | output = sghmcTest( testData )$Sigma[i,,] 97 | expect_equal( dim( output )[1], 2 ) 98 | expect_equal( dim( output )[2], 2 ) 99 | } ) 100 | 101 | test_that( "sghmccv: matrix parameters", { 102 | tryCatch({ 103 | tf$constant(c(1, 1)) 104 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 105 | testData = declareConsts() 106 | i = sample( testData$nIters, 1 ) 107 | output = sghmccvTest( testData )$Sigma[i,,] 108 | expect_equal( dim( output )[1], 2 ) 109 | expect_equal( dim( output )[2], 2 ) 110 | } ) 111 | 112 | test_that( "sgnht: matrix parameters", { 113 | tryCatch({ 114 | tf$constant(c(1, 1)) 115 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 116 | testData = declareConsts() 117 | i = sample( testData$nIters, 1 ) 118 | output = sgnhtTest( testData )$Sigma[i,,] 119 | expect_equal( dim( output )[1], 2 ) 120 | expect_equal( dim( output )[2], 2 ) 121 | } ) 122 | 123 | test_that( "sgnhtcv: matrix parameters", { 124 | tryCatch({ 125 | tf$constant(c(1, 1)) 126 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 127 | testData = declareConsts() 128 | i = sample( testData$nIters, 1 ) 129 | output = sgnhtcvTest( testData )$Sigma[i,,] 130 | expect_equal( dim( output )[1], 2 ) 131 | expect_equal( dim( output )[2], 2 ) 132 | } ) 133 | -------------------------------------------------------------------------------- /tests/testthat/testOptional.R: -------------------------------------------------------------------------------- 1 | # Declare constants and data for simulation from 1d gaussian 2 | declareConsts = function() { 3 | testData = list() 4 | # Simulate data 5 | testData$N = 10^4 6 | testData$mu = 0 7 | testData$sigma = 1 8 | testData$X = rnorm( testData$N, testData$mu, testData$sigma ) 9 | testData$n = 100 10 | testData$data = list( "X" = testData$X ) 11 | testData$params = list( "theta" = rnorm( 1, mean = 0, sd = 1 ) ) 12 | testData$optStepsize = 1e-5 13 | testData$nIters = 200 14 | testData$nItersOpt = 100 15 | testData$burnIn = 100 16 | return( testData ) 17 | } 18 | 19 | logLik = function( params, data ) { 20 | baseDist = tf$distributions$Normal( params$theta, 1 ) 21 | return( tf$reduce_sum( baseDist$log_prob( data$X ) ) ) 22 | } 23 | 24 | sgldTest = function( testData ) { 25 | stepsize = 1e-4 26 | storage = sgld( logLik, testData$data, testData$params, stepsize, nIters = testData$nIters, verbose = FALSE ) 27 | # Remove burn in 28 | thetaOut = storage$theta[-c(1:testData$burnIn)] 29 | return( thetaOut ) 30 | } 31 | 32 | sgldcvTest = function( testData ) { 33 | stepsize = 1e-4 34 | storage = sgldcv( logLik, testData$data, testData$params, stepsize, testData$optStepsize, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE ) 35 | # Remove burn in 36 | thetaOut = storage$theta[-c(1:testData$burnIn)] 37 | return( thetaOut ) 38 | } 39 | 40 | sghmcTest = function( testData ) { 41 | stepsize = 1e-4 42 | storage = sghmc( logLik, testData$data, testData$params, stepsize, nIters = testData$nIters, verbose = FALSE ) 43 | # Remove burn in 44 | thetaOut = storage$theta[-c(1:testData$burnIn)] 45 | return( thetaOut ) 46 | } 47 | 48 | sghmccvTest = function( testData ) { 49 | stepsize = 1e-4 50 | storage = sghmccv( logLik, testData$data, testData$params, stepsize, testData$optStepsize, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE ) 51 | # Remove burn in 52 | thetaOut = storage$theta[-c(1:testData$burnIn)] 53 | return( thetaOut ) 54 | } 55 | 56 | sgnhtTest = function( testData ) { 57 | stepsize = 1e-5 58 | storage = sgnht( logLik, testData$data, testData$params, stepsize, nIters = testData$nIters, verbose = FALSE ) 59 | # Remove burn in 60 | thetaOut = storage$theta[-c(1:testData$burnIn)] 61 | return( thetaOut ) 62 | } 63 | 64 | sgnhtcvTest = function( testData ) { 65 | stepsize = 1e-4 66 | storage = sgnhtcv( logLik, testData$data, testData$params, stepsize, testData$optStepsize, nIters = testData$nIters, nItersOpt = testData$nItersOpt, verbose = FALSE ) 67 | # Remove burn in 68 | thetaOut = storage$theta[-c(1:testData$burnIn)] 69 | return( thetaOut ) 70 | } 71 | 72 | test_that( "Check SGLD with optional parameters runs okay", { 73 | tryCatch({ 74 | tf$constant(c(1, 1)) 75 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 76 | testData = declareConsts() 77 | thetaOut = sgldTest( testData ) 78 | expect_that(T, is_true()) 79 | } ) 80 | 81 | 82 | test_that( "Check SGLDCV with optional parameters run okay", { 83 | tryCatch({ 84 | tf$constant(c(1, 1)) 85 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 86 | testData = declareConsts() 87 | thetaOut = sgldcvTest( testData ) 88 | expect_that(T, is_true()) 89 | } ) 90 | 91 | test_that( "Check SGHMC with optional parameters runs okay", { 92 | tryCatch({ 93 | tf$constant(c(1, 1)) 94 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 95 | testData = declareConsts() 96 | thetaOut = sghmcTest( testData ) 97 | expect_that(T, is_true()) 98 | } ) 99 | 100 | test_that( "Check SGHMCCV with optional parameters runs okay", { 101 | tryCatch({ 102 | tf$constant(c(1, 1)) 103 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 104 | testData = declareConsts() 105 | thetaOut = sghmccvTest( testData ) 106 | expect_that(T, is_true()) 107 | } ) 108 | 109 | test_that( "Check SGNHT with optional parameters runs okay", { 110 | tryCatch({ 111 | tf$constant(c(1, 1)) 112 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 113 | testData = declareConsts() 114 | thetaOut = sgnhtTest( testData ) 115 | expect_that(T, is_true()) 116 | } ) 117 | 118 | test_that( "Check SGNHTCV with optional parameters runs okay", { 119 | tryCatch({ 120 | tf$constant(c(1, 1)) 121 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 122 | testData = declareConsts() 123 | thetaOut = sgnhtcvTest( testData ) 124 | expect_that(T, is_true()) 125 | } ) 126 | -------------------------------------------------------------------------------- /tests/testthat/testSeeds.R: -------------------------------------------------------------------------------- 1 | logLik = function( params, data ) { 2 | baseDist = tf$distributions$Normal( params$theta, 1 ) 3 | return( tf$reduce_sum( baseDist$log_prob( data$X ) ) ) 4 | } 5 | 6 | test_that("Check setting seeds works", { 7 | tryCatch({ 8 | tf$constant(c(1, 1)) 9 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 10 | # Set precision for seeds 11 | precision = 1e-8 12 | # Build function arguments 13 | params = list("theta" = 0) 14 | dataset = list( "X" = rnorm(10^4) ) 15 | stepsize = 1e-6 16 | argsStd = list( "logLik" = logLik, "dataset" = dataset, "params" = params, 17 | "stepsize" = stepsize, nIters = 10, minibatchSize = 5, verbose = FALSE, seed = 1 ) 18 | # Check standard methods 19 | for (method in c("sgld", "sghmc", "sgnht")) { 20 | output1 = do.call(method, argsStd)$theta 21 | output2 = do.call(method, argsStd)$theta 22 | expect_lte(sum(output1 - output2), precision) 23 | } 24 | 25 | # Check control variate methods after adding extra arguments 26 | argsStd$optStepsize = 1e-5 27 | argsStd$nItersOpt = 10 28 | for (method in c("sgldcv", "sghmccv", "sgnhtcv")) { 29 | output1 = do.call(method, argsStd)$theta 30 | output2 = do.call(method, argsStd)$theta 31 | expect_lte(sum(output1 - output2), precision) 32 | } 33 | } ) 34 | -------------------------------------------------------------------------------- /tests/testthat/testSparse.R: -------------------------------------------------------------------------------- 1 | logLik = function(params, dataset) { 2 | uCurr = tf$gather(params$u, tf$to_int32((dataset$Group - 1))) 3 | uDistn = tf$distributions$Normal(uCurr, 1) 4 | logLik = tf$reduce_sum(uDistn$log_prob(dataset$X)) 5 | return(logLik) 6 | } 7 | 8 | createData = function(ng, N = 10^3, seed = 13) { 9 | set.seed(seed) 10 | ng = 200 11 | X = c() 12 | alloc = c() 13 | for (i in 1:ng) { 14 | n_obs = sample(5:15, 1) 15 | X = c(X, rnorm(n_obs, mean = i)) 16 | alloc = c(alloc, rep(i, n_obs)) 17 | } 18 | return(list("X" = X, "Group" = alloc)) 19 | } 20 | 21 | test_that("Check sparsity works", { 22 | tryCatch({ 23 | tf$constant(c(1, 1)) 24 | }, error = function (e) skip("tensorflow not fully built, skipping...")) 25 | # Build function arguments 26 | nGroups = 200 27 | params = list("u" = 1:nGroups) 28 | dataset = createData(nGroups) 29 | stepsize = 1e-6 30 | argsStd = list( "logLik" = logLik, "dataset" = dataset, "params" = params, 31 | "stepsize" = stepsize, nIters = 10, minibatchSize = 100, verbose = FALSE, seed = 1 ) 32 | # Check standard methods 33 | for (method in c("sgld", "sghmc", "sgnht")) { 34 | output = do.call(method, argsStd) 35 | } 36 | # Check control variate methods after adding extra arguments 37 | argsStd$optStepsize = 1e-5 38 | argsStd$nItersOpt = 10 39 | for (method in c("sgldcv", "sghmccv", "sgnhtcv")) { 40 | output = do.call(method, argsStd) 41 | } 42 | # We're just checking valid run behaviour 43 | # Put this dummy expect to stop testthat skipping 'empty test' 44 | expect_that(T, is_true()) 45 | } ) 46 | -------------------------------------------------------------------------------- /vignettes/.Rhistory: -------------------------------------------------------------------------------- 1 | library(MASS) 2 | # Declare number of observations 3 | N = 10^4 4 | # Set theta to be 0 and simulate the data 5 | theta = c( 0, 0 ) 6 | Sigma = diag(2) 7 | X = mvrnorm( N, theta, Sigma ) 8 | data = list( "X" = X ) 9 | params = list( "theta" = c( 0, 0 ) ) 10 | logLik = function( params, data ) { 11 | # Declare Sigma as a tensorflow object 12 | Sigma = tf$constant( diag(2), dtype = tf$float32 ) 13 | # Declare distribution of each observation 14 | baseDist = tf$contrib$distributions$MultivariateNormalFull( params$theta, Sigma ) 15 | # Declare log likelihood function and return 16 | logLik = tf$reduce_sum( baseDist$log_pdf( data$X ) ) 17 | return( logLik ) 18 | } 19 | logPrior = function( params, data ) { 20 | baseDist = tf$contrib$distributions$Normal( 0, 10 ) 21 | logPrior = tf$reduce_sum( baseDist$log_pdf( params$theta ) ) 22 | return( logPrior ) 23 | } 24 | stepsize = list( "theta" = 1e-5 ) 25 | n = 100 26 | chains = sgld( logLik, logPrior, data, params, stepsize, n, nIters = 10^4, verbose = FALSE ) 27 | --------------------------------------------------------------------------------