<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/r-and-singularity/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://www.rstudio.com/rviews/2017/03/29/r-and-singularity/"> RStudio</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>

<p>by Bryan Lewis</p>
<p>R (<a target="_blank" rel="nofollow" href="https://www.r-project.org/">https://www.r-project.org</a>) is a premier system for statistical and scientific computing and data science. At its core, R is a very carefully curated high-level interface to low-level numerical libraries. True to this principle, R packages have greatly expanded the scope and number of these interfaces over the years, among them interfaces to a large number of distributed and parallel computing tools. Despite its impressive breadth of sophisticated high-performance computing (HPC) tools, R is not often that widely used for “big” problems.</p>
<p>I believe the idiosyncrasies of most HPC technologies represent the major road block to their adoption (in any language or system). HPC technologies are often difficult to set up, use, and manage. They often rely on frequently changing and complex software library dependencies, and sometimes highly specific library versions. Managing all this boils down to spending more time on system administration, and less time on research.</p>
<p>How do we make things easier? One approach to help accelerate the adoption of HPC technology by the R community uses Singularity, a modern application containerization technique suited to HPC (<a target="_blank" rel="nofollow" href="http://singularity.lbl.gov/">http://singularity.lbl.gov/</a>).</p>
<h1>Containers</h1>
<p>A <em>container</em> is a collection of the software requirements to run an application. Importantly, containers are defined and generated from a simple text recipe that can be easily communicated and versioned. Containers leverage modern operating system capabilities for virtualizing process and name spaces in a high-performance, low-overhead way. Container technology allows us to quickly turn recipes into runnable applications, and then deploy them anywhere.</p>
<p>The success of Docker, CoreOS, and related systems in enterprise business applications shows that there is a huge demand for lightweight, versionable, and portable containers. Notably, these technologies have not been all that widely successful in HPC settings, despite significant effort. Shifter (<a target="_blank" rel="nofollow" href="https://github.com/NERSC/shifter">https://github.com/NERSC/shifter</a>) is the most successful application of Docker to HPC, and while it is very impressive, it suffers from a few important drawbacks. The root-capable daemon program used by Docker is difficult to accommodate in many HPC environments. And the relatively heavy-weight nature of Docker virtualization can degrade the performance of high-performance hardware resources like Infiniband networking.</p>
<p>Singularity is a lightweight and very simple container technology that is particularly well-suited to HPC environments. Singularity virtualizes the minimum amount necessary to compute, allowing applications full access to fast hardware resources like Infiniband networks and GPUs. And Singularity runs without a server at all, eliminating possible server security exploits. The minimalist philosophy of Singularity makes it easy to install and run on everything from laptops to supercomputers, promoting the ability to quickly test containers before using them across large systems. Singularity is now widely available in supercomputer centers across the world.</p>
<h1>Reproducible research</h1>
<p>Publishing results with code and data that can be reproduced and validated by others is an obviously important concept that has seen increased urgency these days. The idea is an old one that has been supported by S, S+ and R from the beginning with ideas like Sweave and more recently knitr and R markdown. R even promotes reproducible simulation in distributed/parallel settings by including high-quality, reproducible, distributed random number generators out of the box.</p>
<p>However, as R integrates with an increasing number of external libraries and frameworks like cuDNN, Spark, and others, the ability to reproduce the<br>
<em>software environment</em> that R runs in is becoming both more important and more complex. Containers help us define these complex set ups with simple, versionable text files, and then portably run them in diverse environments.</p>
<h1>Examples</h1>
<p>The following examples assume that Singularity is installed on your system. See <a target="_blank" rel="nofollow" href="http://singularity.lbl.gov/">http://singularity.lbl.gov/</a> for details — it’s very easy to install. The examples can be run from nearly any modern Unix operating system, although the processor architecture must be supported by the container operating system.</p>
<h1>Hello TensorFlow</h1>
<p>The first example below shows a canonical “hello world” program. Instead of a completely trivial example, we print “Hello, TensorFlow!” using TensorFlow from R via Python (<a target="_blank" rel="nofollow" href="https://github.com/tensorflow/tensorflow">https://github.com/tensorflow/tensorflow</a>, <a target="_blank" rel="nofollow" href="https://github.com/python/cpython">https://github.com/python/cpython</a>), introducing a complex but typical software dependency chain. A test program validates operation by printing the “hello world” message from R through Tensorflow. The container generically will run any R program named <code>main.R</code> in its working directory.</p>
<p>Here is the Singularity container definition file for the example using the Ubuntu Xenial operating system. (Note that you can build a container from this definition file on any Singularity-supported operating system.)</p>
<p><iframe height="640px" width="1000px" src="https://beta.rstudioconnect.com/content/2639/r_and_singularity_block1.html"></iframe></p>
<p><strong>TIP</strong> If you’re running on Red Hat or CentOS, you’ll need the debootstrap program: <code>sudo yum install debootstrap</code>. See the Singularity documentation for more information.</p>
<p>Assuming that the above definition file is named <code>tensorflow.def</code>, you can bootstrap a Singularity container image named <code>tensorflow.img</code> with:</p>
<p><iframe height="90px" width="1000px" src="https://beta.rstudioconnect.com/content/2640/r_and_singularity_block2.html"></iframe></p>
<p>The <code>%post</code> section of the definition file installs R, Python, Tensorflow and miscellaneous utilities into the container. The <code>%test</code> section runs the “hello world” program as an example to verify things are working. The <code>%run</code> section of this example simply runs an arbitrary user R program named <code>main.R</code> in the container’s working directory.</p>
<p>Run the “hello world” <code>%test</code> script with:</p>
<p><iframe height="50px" width="1000px" src="https://beta.rstudioconnect.com/content/2641/r_and_singularity_block3.html"></iframe></p>
<p>I love Singularity’s ability to include unit tests in container definition files — it reminds me of building R packages! I encourage using the test section judiciously to confirm that the container will work as intended.</p>
<p>You can run an arbitrary R program in the container by creating a <code>main.R</code> file in the container working directory and running:</p>
<p><iframe height="50px" width="1000px" src="https://beta.rstudioconnect.com/content/2642/r_and_singularity_block4.html"></iframe></p>
<h1>Full-genome variant Principal Components</h1>
<p>The previous example illustrated a complex tool chain, but only running on a single computer. This example is closer to a complete distributed R application.</p>
<p>Genomic variants record differences in a genome relative to a reference. Many types of differences exist, see for instance <a target="_blank" rel="nofollow" href="https://en.wikipedia.org/wiki/Structural_variation">https://en.wikipedia.org/wiki/Structural_variation</a>. This example focuses on differences among the 2,504 whole human genomes curated by the 1000 Genomes Project (see: “A global reference for human genetic variation”, The 1000 Genomes Project Consortium, <em>Nature</em> 526, 68-74 (01 October 2015) doi:10.1038/nature15393). The example downloads whole genome data files in VCF 4.1 format. Although the 1000 Genome Project data files are used here, the example will work for any input set of VCF files (it processes all files named <code>*.vcf.gz</code> in the working directory).</p>
<p>The example constructs a sparse 2,504 row (people) by 81,271,844 column (genomic variants) R matrix from the VCF data files. The matrix entries are one if a particular variant occurs in the person, or a zero otherwise. Because not every person exhibits every variant, the matrix is very sparse with about 9.8 billion nonzero-elements, or about 2% fill-in. Rather than construct a single giant sparse matrix, the example partitions the data and saves many smaller sub-matrices each with CHUNKSIZE non-zero elements as R data files in the working directory, where CHUNKSIZE is an optional user-defined parameter that defaults to a value based on system memory size.</p>
<p>The example computes the first NCOMP principal components, where NCOMP is a user-specified environment variable specified by the user, of sparse genomic variant VCF files. The example is very general, requiring an arbitrary number of VCF data files as input and running on any number of computers. It uses MPI to coordinate parallel activity across computers, along with the <code>Rmpi</code>, <code>doMPI</code>, and <code>foreach</code> packages in R. The choice of MPI is well-suited to supercomputer deployment, and the example assumes that MPI is available along with the following assumptions:</p>
<ul>
<li>Launched by MPI</li>
<li>One or more gzip-compressed variant files ending in “.vcf.gz” (the program will use all files matching this pattern)</li>
<li>The input variant files are split up among working directories across the worker computers — each worker will parse and process only the variant files in its local working directory</li>
<li>Optional CHUNKSIZE environment variable in number of variants per chunk</li>
<li>Optional NCOMP environment variable specifying the number of principal components to return, defaulting to 3</li>
</ul>
<p>A successful run produces the following output:</p>
<ul>
<li>A file ‘pca.rdata’ in serialized R format containing the largest NCOMP singular values and corresponding principal component vectors of the variant data</li>
</ul>
<p>This example was designed for deployment with supercomputer systems in mind. See <a target="_blank" rel="nofollow" href="https://github.com/bwlewis/1000_genomes_examples">https://github.com/bwlewis/1000_genomes_examples</a> for other implementations that don’t require MPI.</p>
<p>Singularity encapsulates the program logic and the external library dependency chain (MPI, etc.) required by the computation in the following definition file:</p>
<p><iframe height="760px" width="1000px" src="https://beta.rstudioconnect.com/content/2643/r_and_singularity_block5.html"></iframe></p>
<p>Build and bootstrap a Singularity container using the <code>variant_pca.def</code> definition file with:</p>
<p><iframe height="90px" width="1000px" src="https://beta.rstudioconnect.com/content/2644/r_and_singularity_block6.html"></iframe></p>
<h2>Unit test</h2>
<p>The container includes a simple unit test that verifies MPI operation invoked by:</p>
<p><iframe height="50px" width="1000px" src="https://beta.rstudioconnect.com/content/2645/r_and_singularity_block7.html"></iframe></p>
<h2>Small example</h2>
<p>A small, fast-running example computes principal components for the first 10,000 variants from the 1000 Genomes Project chromosomes 21 and 22 as follows:</p>
<p><iframe height="90px" width="1000px" src="https://beta.rstudioconnect.com/content/2646/r_and_singularity_block8.html"></iframe></p>
<p>Read the output pca.rdata file from R using <code>readRDS()</code>. The following code plots the first three estimated principal components.</p>
<p><iframe height="580px" width="1000px" src="https://beta.rstudioconnect.com/content/2647/r_and_singularity_block9.html"></iframe></p>
<p>We see some obvious clusters in the data, but the clusters are not all that well-defined because we only use data from two smaller chromosomes (21 and 22) in this example. The clusters correspond to distinct genetic superpopulations. See the following example for a refined plot using the whole genomes.</p>
<h2>Full-sized example</h2>
<p>Finally, compute the whole genome principal components across all chromosomes and all 2,504 people in the 1000 Genomes project with:</p>
<p><iframe height="230px" width="1000px" src="https://beta.rstudioconnect.com/content/2648/r_and_singularity_block10.html"></iframe></p>
<p>When running on more than one computer, first distribute the vcf.gz files by scattering them across working directories on each computer. Each computer will only process the files located in its working directory, so copy a subset of<br>
the files to each computer.</p>
<p>The Singularity container image must also be available to run on each computer,<br>
so copy the image to each one.</p>
<p>Now scatter the <code>*.vcf.gz</code> files across your MPI computers, for instance using <code>scp</code>. Let’s assume for this example that we have four total computers. Then we need to invoke the program on 4 + 1 = 5 total MPI hosts, as outlined in <a target="_blank" rel="nofollow" href="https://cran.r-project.org/web/packages/doMPI/vignettes/doMPI.pdf">https://cran.r-project.org/web/packages/doMPI/vignettes/doMPI.pdf</a> (the first listed host will operate as the R master program in a master/slave configuration).</p>
<p>Assume that our four host computers are listed in a comma-separated list by the environment variable HOSTS, for instance by</p>
<p><iframe height="50px" width="1000px" src="https://beta.rstudioconnect.com/content/2649/r_and_singularity_block11.html"></iframe></p>
<p>Then a typical openmpi invocation is (for our four hosts):</p>
<p><iframe height="70px" width="1000px" src="https://beta.rstudioconnect.com/content/2650/r_and_singularity_block12.html"></iframe></p>
<p>Replace the host list and <code>-np 5</code> with the number of computers available in your cluster plus one. Or, submit the job using an available cluster job manager like Slurm. See <a target="_blank" rel="nofollow" href="https://cran.r-project.org/web/packages/doMPI/vignettes/doMPI.pdf">https://cran.r-project.org/web/packages/doMPI/vignettes/doMPI.pdf</a> for more details on using MPI with R.</p>
<h2>Example output</h2>
<p>To give you an idea of performance, I ran this example on four Amazon EC2 r4-4xlarge instances. The parsing step completed in about 20 minutes, and principal component computation took about 11 minutes (680 seconds).</p>
<p>As with the small example above, we can read the output file and plot the principal components:</p>
<p><iframe height="580px" width="1000px" src="https://beta.rstudioconnect.com/content/2651/r_and_singularity_block13.html"></iframe></p>
<p>The resulting clusters are much more highly defined, and split into four or five very well-defined data clusters, corresponding almost exactly to the NIH superpopulation categories for each person. Some of the data clusters themselves exhibit sub-cluster structure.</p>
<h2>Additional Notes</h2>
<p>The computation uses an R program downloaded from <a target="_blank" rel="nofollow" href="https://raw.githubusercontent.com/bwlewis/1000_genomes_examples/master/pca-mpi.R">https://raw.githubusercontent.com/bwlewis/1000_genomes_examples/master/pca-mpi.R</a> that we don’t reproduce here. See that file and <a target="_blank" rel="nofollow" href="https://github.com/bwlewis/1000_genomes_examples/blob/master/PCA_whole_genome.Rmd">https://github.com/bwlewis/1000_genomes_examples/blob/master/PCA_whole_genome.Rmd</a> for additional notes.</p>
<p>The computation proceeds in two sequential phases, first processing the raw VCF files into chunks of sparse R matrices corresponding to the variant data, and then computing principal components on the R matrices. Parallel computation is used within each phase.</p>
<p>Sparse matrix chunk size is specified by the user with the environment variable CHUNKSIZE to indicate the maximum number of nonzero matrix elements per chunk. If unspecified, CHUNKSIZE is automatically determined based on a heuristic using the host computer’s memory size.</p>
<p>The first processing phase of the computation stores the R sparse matrix chunks corresponding to the input available VCF files for re-use iteratively by the algorithm. In particular, this algorithm process the chunked VCF data out of core — alternative versions of the program pin sparse matrix chunks in memory on each computer and avoid intermediate file system use. That can be obviously more efficient than using a file system. But, importantly, the file system approach scales easily. In particular, this program will run (slowly) on a single laptop even if the total variant sparse matrix size vastly exceeds available RAM size. Thus, this example trades best performance for flexibility. Despite this trade off, performance can be excellent in the example, thanks to the efficient algorithm used and the fact that files are cached in each computer’s buffer cache if memory permits.</p>
<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://www.rstudio.com/rviews/2017/03/29/r-and-singularity/"> RStudio</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/FDynfQKCp0M"></a></div>