<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>TensorFlow on R Views</title>
    <link>https://rviews.rstudio.com/tags/tensorflow/</link>
    <description>Recent content in TensorFlow on R Views</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Mon, 11 Nov 2019 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://rviews.rstudio.com/tags/tensorflow/" rel="self" type="application/rss+xml" />
    
    
    
    
    <item>
      <title>A comparison of methods for predicting clothing classes using the Fashion MNIST dataset in RStudio and Python (Part 1)</title>
      <link>https://rviews.rstudio.com/2019/11/11/a-comparison-of-methods-for-predicting-clothing-classes-using-the-fashion-mnist-dataset-in-rstudio-and-python-part-1/</link>
      <pubDate>Mon, 11 Nov 2019 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2019/11/11/a-comparison-of-methods-for-predicting-clothing-classes-using-the-fashion-mnist-dataset-in-rstudio-and-python-part-1/</guid>
      <description>
        


&lt;p&gt;&lt;em&gt;Florianne Verkroost is a PhD candidate at Nuffield College at the University of Oxford. With a passion for data science and a background in mathematics and econometrics. She applies her interdisciplinary knowledge to computationally address societal problems of inequality.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this series of blog posts, I will compare different machine and deep learning methods to predict clothing categories from images using the Fashion MNIST data. In this first blog of the series, we will explore and prepare the data for analysis. I will also show you how to predict the clothing categories of the Fashion MNIST data using my go-to model: an artificial neural network. To show you how to use one of RStudio’s incredible features to run Python from RStudio, I build my neural network in Python using the code in &lt;a href=&#34;https://github.com/fverkroost/RStudio-Blogs/blob/master/simple_neural_network_fashion_mnist.py&#34;&gt;this Python script&lt;/a&gt; or &lt;a href=&#34;https://github.com/fverkroost/RStudio-Blogs/blob/master/simple_neural_network_fashion_mnist.ipynb&#34;&gt;this Jupyter notebook&lt;/a&gt; on my Github. In the &lt;a href=&#34;https://github.com/fverkroost/RStudio-Blogs/blob/master/machine_learning_fashion_mnist_post2.Rmd&#34;&gt;second blog post&lt;/a&gt;, we will experiment with tree-based methods (single tree, random forests and boosting) and support vector machines to see whether we can beat the neural network in terms of performance. As Python cannot be run in this blog post, I will walk you through the results from this script produced earlier, but if you would also like to see how to embed Python code and results in R Markdown files, check out &lt;a href=&#34;https://github.com/fverkroost/RStudio-Blogs/blob/master/machine_learning_fashion_mnist_post1_embedded.Rmd&#34;&gt;this Markdown file on my Github&lt;/a&gt;! The R code used for this blog is also included on my &lt;a href=&#34;https://github.com/fverkroost/RStudio-Blogs/blob/master/machine_learning_fashion_mnist_post1.R&#34;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To start, we first set our seed to make sure the results are reproducible.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;set.seed(1234)&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;importing-and-exploring-the-data&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Importing and exploring the data&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;keras&lt;/code&gt; package contains the Fashion MNIST data, so we can easily import the data into RStudio from this package directly after installing it from Github and loading it.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(devtools)
install.packages(&amp;quot;keras&amp;quot;)
#devtools::install_github(&amp;quot;rstudio/keras&amp;quot;)
library(keras)        
install_keras()  
fashion_mnist &amp;lt;- keras::dataset_fashion_mnist()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting object named &lt;code&gt;fashion_mnist&lt;/code&gt; is a nested list, consisting of lists &lt;code&gt;train&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;. Each of these lists in turn consists of arrays &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;. To look at the dimensions of these elements, we recursively apply the &lt;code&gt;dim()&lt;/code&gt; function to the &lt;code&gt;fashion_mnist&lt;/code&gt; list.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rapply(fashion_mnist, dim)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;train.x1 train.x2 train.x3  train.y  test.x1  test.x2  test.x3   test.y 
   60000       28       28    60000    10000       28       28    10000 &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From the result, we observe that the &lt;code&gt;x&lt;/code&gt; array in the training data contains 28 matrices each of 60000 rows and 28 columns, or in other words 60000 images each of 28 by 28 pixels. The &lt;code&gt;y&lt;/code&gt; array in the training data contains 60000 labels for each of the images in the &lt;code&gt;x&lt;/code&gt; array of the training data. The test data has a similar structure but only contains 10000 images rather than 60000. For simplicity, we rename these lists elements to something more intuitive (where &lt;code&gt;x&lt;/code&gt; now represents images and &lt;code&gt;y&lt;/code&gt; represents labels):&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;c(train.images, train.labels) %&amp;lt;-% fashion_mnist$train
c(test.images, test.labels) %&amp;lt;-% fashion_mnist$test&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every image is captured by a 28 by 28 matrix, where entry [i, j] represents the opacity of that pixel on an integer scale from 0 (white) to 255 (black). The labels consist of integers between zero and nine, each representing a unique clothing category. As the category names are not contained in the data itself, we have to store and add them manually. Note that the categories are evenly distributed in the data.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cloth_cats = data.frame(category = c(&amp;#39;Top&amp;#39;, &amp;#39;Trouser&amp;#39;, &amp;#39;Pullover&amp;#39;, &amp;#39;Dress&amp;#39;, &amp;#39;Coat&amp;#39;,  
                                     &amp;#39;Sandal&amp;#39;, &amp;#39;Shirt&amp;#39;, &amp;#39;Sneaker&amp;#39;, &amp;#39;Bag&amp;#39;, &amp;#39;Boot&amp;#39;), 
                                     label = seq(0, 9))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get an idea of what the data entail and look like, we plot the first ten images of the test data. To do so, we first need to reshape the data slightly such that it becomes compatible with &lt;code&gt;ggplot2&lt;/code&gt;. We select the first ten test images, convert them to data frames, rename the columns into digits 1 to 28, create a variable named &lt;code&gt;y&lt;/code&gt; with digits 1 to 28 and then we melt by variable &lt;code&gt;y&lt;/code&gt;. We need package &lt;code&gt;reshape2&lt;/code&gt; to access the &lt;code&gt;melt()&lt;/code&gt; function. This results in a 28 times 28 equals 784 by 3 (y pixels (= y), x pixels (= variable) and the opacity (= value)) data frame. We bind these all together by rows using the &lt;code&gt;rbind.fill()&lt;/code&gt; function from the &lt;code&gt;plyr&lt;/code&gt; package and add a variable &lt;code&gt;Image&lt;/code&gt;, which is a unique string repeated 784 times for each of the nine images containing the image number and corresponding test set label.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(reshape2)
library(plyr)
subarray &amp;lt;- apply(test.images[1:10, , ], 1, as.data.frame)
subarray &amp;lt;- lapply(subarray, function(df){
  colnames(df) &amp;lt;- seq_len(ncol(df))
  df[&amp;#39;y&amp;#39;] &amp;lt;- seq_len(nrow(df))
  df &amp;lt;- melt(df, id = &amp;#39;y&amp;#39;)
  return(df)
})
plotdf &amp;lt;- rbind.fill(subarray)
first_ten_labels &amp;lt;- cloth_cats$category[match(test.labels[1:10], cloth_cats$label)]
first_ten_categories &amp;lt;- paste0(&amp;#39;Image &amp;#39;, 1:10, &amp;#39;: &amp;#39;, first_ten_labels)
plotdf[&amp;#39;Image&amp;#39;] &amp;lt;- factor(rep(first_ten_categories, unlist(lapply(subarray, nrow))), 
                          levels = unique(first_ten_categories))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We then plot these first ten test images using package &lt;code&gt;ggplot2&lt;/code&gt;. Note that we reverse the scale of the y-axis because the original dataset contains the images upside-down. We further remove the legend and axis labels and change the tick labels.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ggplot() + 
  geom_raster(data = plotdf, aes(x = variable, y = y, fill = value)) + 
  facet_wrap(~ Image, nrow = 2, ncol = 5) + 
  scale_fill_gradient(low = &amp;quot;white&amp;quot;, high = &amp;quot;black&amp;quot;, na.value = NA) + 
  theme(aspect.ratio = 1, legend.position = &amp;quot;none&amp;quot;) + 
  labs(x = NULL, y = NULL) + 
  scale_x_discrete(breaks = seq(0, 28, 7), expand = c(0, 0)) + 
  scale_y_reverse(breaks = seq(0, 28, 7), expand = c(0, 0))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-10-31-a-comparison-of-methods-for-predicting-clothing-classes-using-the-fashion-mnist-dataset-in-rstudio-and-python-part-1/index_files/figure-html/unnamed-chunk-8-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;data-preparation&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Data Preparation&lt;/h2&gt;
&lt;p&gt;Next, it’s time to start the more technical work of predicting the labels from the image data. First, we need to reshape our data to convert it from a multidimensional array into a two-dimensional matrix. To do so, we vectorize each 28 by 28 matrix into a column of length 784, and then we bind the columns for all images on top of each other, finally taking the transpose of the resulting matrix. This way, we can convert a 28 by 28 by 60000 array into a 60000 by 784 matrix. We also normalize the data by dividing between the maximum opacity of 255.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;train.images &amp;lt;- data.frame(t(apply(train.images, 1, c))) / max(fashion_mnist$train$x)
test.images &amp;lt;- data.frame(t(apply(test.images, 1, c))) / max(fashion_mnist$train$x)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also create two data frames that include all training and test data (images and labels), respectively.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pixs &amp;lt;- 1:ncol(fashion_mnist$train$x)^2
names(train.images) &amp;lt;- names(test.images) &amp;lt;- paste0(&amp;#39;pixel&amp;#39;, pixs)
train.labels &amp;lt;- data.frame(label = factor(train.labels))
test.labels &amp;lt;- data.frame(label = factor(test.labels))
train.data &amp;lt;- cbind(train.labels, train.images)
test.data &amp;lt;- cbind(test.labels, test.images)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;artificial-neural-network&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Artificial Neural Network&lt;/h2&gt;
&lt;p&gt;Now, let’s continue by building a simple neural network model to predict our clothing categories. Neural networks are artificial computing systems that were built with human neural networks in mind. Neural networks contain nodes, which transmit signals amongst one another. Usually the input at each node is a number, which is transformed according to a non-linear function of the input and weights, the latter being the parameters that are tuned while training the model. Sets of neurons are collected in different layers; neural networks are referred to as ‘deep’ when they contain at least two hidden layers. If you’re not familiar with artificial neural networks, then &lt;a href=&#34;http://neuralnetworksanddeeplearning.com/index.html&#34;&gt;this free online book&lt;/a&gt; is a good source to start learning about them.&lt;/p&gt;
&lt;p&gt;In this post, I will show you how artificial neural networks with different numbers of hidden layers compare, and I will also compare these networks to a convolutional network, which often performs better in the case of visual imagery. I will show you some basic models and how to code these, but will not spend too much time on tuning neural networks, for example when it comes to choosing the right amount of hidden layers or the number of nodes in each hidden layer. In essence, what it comes down to is that these parameters largely depend on your data structure, magnitude and complexity. The more hidden layers one adds, the more complex non-linear relationships can be modelled. Often, in my experience, adding hidden layers to a neural network increases their performance up to a certain number of layers, after which the increase becomes non-significant while the computational requirements and interpretation become more infeasible. It is up to you to play around a bit with your specific data and test how this trade-off works.&lt;/p&gt;
&lt;p&gt;Although neural networks can easily built in RStudio using TensorFlow and Keras, I really want to show you one of the incredible features of RStudio where you can run Python in RStudio. This can be done in two ways: either we choose “Terminal” on the top of the output console in RStudio and run Python via Terminal, or we use the base &lt;code&gt;system2()&lt;/code&gt; function to run Python in RStudio.&lt;/p&gt;
&lt;p&gt;For the second option, to use the &lt;code&gt;system2()&lt;/code&gt; command, it’s important to first check what version of Python should be used. You can check which versions of Python are installed on your machine by running &lt;code&gt;python --version&lt;/code&gt; in Terminal. Note that with RStudio 1.1 (1.1.383 or higher), you can run in Terminal directly from RStudio on the “Terminal” tab. You can also run &lt;code&gt;python3 --version&lt;/code&gt; to check if you have Python version 3 installed. On my machine, &lt;code&gt;python --version&lt;/code&gt; and &lt;code&gt;python3 --version&lt;/code&gt; return Python 2.7.16 and Python 3.7.0, respectively. You can then run &lt;code&gt;which python&lt;/code&gt; (or &lt;code&gt;which python3&lt;/code&gt; if you have Python version 3 installed) in Terminal, which will return the path where Python is installed. In my case, these respective commands return &lt;code&gt;/usr/bin/python&lt;/code&gt; and &lt;code&gt;/Library/Frameworks/Python.framework/Versions/3.7/bin/python3&lt;/code&gt;. As I will make use of Python version 3, I specify the latter as the path to Python in the &lt;code&gt;use_python()&lt;/code&gt; function from the &lt;code&gt;reticulate&lt;/code&gt; package. We can check whether the desired version of Python is used by using the &lt;code&gt;sys&lt;/code&gt; package from Python. Just make sure to change the path in the code below to what version of Python you desire using and where that version in installed.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(reticulate)
use_python(python = &amp;#39;/Library/Frameworks/Python.framework/Versions/3.7/bin/python3&amp;#39;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;sys &amp;lt;- import(&amp;quot;sys&amp;quot;)
sys$version&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we’ve specified the correct version of Python to be used, we can run our Python script from RStudio using the &lt;code&gt;system2()&lt;/code&gt; function. This function also takes an argument for the version of Python used, which in my case is Python version 3. If you are using an older version of Python, make sure to change &lt;code&gt;&amp;quot;python3&amp;quot;&lt;/code&gt; in the command below to &lt;code&gt;&amp;quot;python2&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;python_file &amp;lt;- &amp;quot;simple_neural_network_fashion_mnist.py&amp;quot;
system2(&amp;quot;python3&amp;quot;, args = c(python_file), stdout = NULL, stderr = &amp;quot;&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The source code used to build and fit the neural networks from the above script can be found in &lt;a href=&#34;https://github.com/fverkroost/RStudio-Blogs/blob/master/simple_neural_network_fashion_mnist.py&#34;&gt;this Python script&lt;/a&gt; or &lt;a href=&#34;https://github.com/fverkroost/RStudio-Blogs/blob/master/simple_neural_network_fashion_mnist.ipynb&#34;&gt;this Jupyter notebook&lt;/a&gt; on my Github.. In this post, I will walk you through the results from this script produced earlier, but if you would also like to see how to embed Python code and results in R Markdown files, check out &lt;a href=&#34;https://github.com/fverkroost/RStudio-Blogs/blob/master/machine_learning_fashion_mnist_post1_embedded.Rmd&#34;&gt;this file on my Github&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;I will now guide you step by step through the script called in the command above. First, we load the required packages in Python and set the session seed for replicability.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic1.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;We then load the fashion MNIST data from &lt;code&gt;keras&lt;/code&gt; and we normalize the data by dividing by maximum opacity of 255.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic2.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic3.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;We start by building a simple neural network containing one hidden layer. Note that as here we use the untransformed but normalized data, we need to flatten the 28 by 28 pixels input first. We add one hidden densely-connected layer which performs &lt;code&gt;output = relu(dot(input, kernel) + bias)&lt;/code&gt;, where the rectified linear unit (&lt;code&gt;relu&lt;/code&gt;) activation function has been proven to work well. We set the number of nodes equal to 128, because this seems to work well in our case. The number of nodes could essentially be any of the numbers 32, 64, 128, 256 and 512, as these are in a sequence of multiples between the number of nodes in the output (= 10) and input (= 784) layers. The &lt;code&gt;softmax&lt;/code&gt; layer then assigns predicted probabilities to each of the ten clothing categories, which is also why there are ten nodes in this layer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic4.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;After building the neural network, we compile it. We specify &lt;code&gt;sparse_categorical_crossentropy&lt;/code&gt; as the loss function, which is suitable for categorical multi-class responses. The optimizer controls the learning rate; &lt;code&gt;adam&lt;/code&gt; (adaptive moment estimation) is similar to classical stochastic gradient descent and usually a safe choice for the optimizer. We set our metric of interest to be the accuracy, or the percentage of correctly classified images. Hereafter, we fit the model onto our training data set using ten iterations through the training data (“epochs”). Here, 70% is used for training and 30% is used for validation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic5.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Next, we print the results of the model in terms of training and testing loss and accuracy.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic6.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;We can see that the neural network with one hidden layer already performs relatively well with a test accuracy of 87.09%. However, it seems like we are slightly overfitting (i.e. the model is fitted too well to a particular data set and therefore does not well extend to other data sets), as the training set accuracy (88.15%) is slightly higher than the test set accuracy. There are several ways to avoid overfitting in neural networks, such as simplifying our model by reducing the number of hidden layers and neurons, adding dropout layers that randomly remove some of the connections between layers, and early stopping when validation loss starts to increase. Later on in this post, I will demonstrate some of these methods to you. For further reading, I personally like &lt;a href=&#34;https://towardsdatascience.com/dont-overfit-how-to-prevent-overfitting-in-your-deep-learning-models-63274e552323&#34;&gt;this&lt;/a&gt; and &lt;a href=&#34;https://keras.rstudio.com/articles/tutorial_overfit_underfit.html&#34;&gt;this&lt;/a&gt; post showing how to avoid overfitting when building neural networks using &lt;code&gt;keras&lt;/code&gt;. Instead, to see whether a deep neural network performs better at predicting clothing categories, we build a neural network with three hidden layers in a similar way as before.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic7.png&#34; /&gt;
&lt;img src=&#34;screen_shots_python_code/pic8.png&#34; /&gt;
&lt;img src=&#34;screen_shots_python_code/pic9.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;It seems like the model with two additional layers does not perform better than the previous one with only one hidden layer, given that both the training (87.42%) and test set (86.03%) accuracies are lower and the loss (38.49) is higher. Let’s try whether adding another five hidden layers improves model performance, or whether we can include that increasing model complexity does not improve performance.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic10.png&#34; /&gt;
&lt;img src=&#34;screen_shots_python_code/pic11.png&#34; /&gt;
&lt;img src=&#34;screen_shots_python_code/pic12.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;The model with eight hidden layers performs best in terms of training (88.21%) and test (87.58%) accuracy as well as loss (36.12). Nevertheless, the difference in performance between the first model with one hidden layer and the current model with eight hidden layers is only quite small. Although it seems that with so many hidden layers, we can model additional complexity that improves the accuracy of the model, we must ask ourselves whether increasing model complexity at the cost of interpretability and computational feasibility is worth this slight improvement in accuracy and loss.&lt;/p&gt;
&lt;p&gt;Now that we have seen how the number of hidden layers affects model performance, let’s try and see whether increasing the number of epochs (i.e. the number of times the model iterates through the training data) from ten to fifty improves the performance of our first neural network with one hidden layer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic13.png&#34; /&gt;
&lt;img src=&#34;screen_shots_python_code/pic14.png&#34; /&gt;
&lt;img src=&#34;screen_shots_python_code/pic15.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;The three-layer model trained with fifty epochs has the highest train (89.32%) and test (88.68%) accuracies we have seen so far. However, the loss (54.73) is also about a third larger than we have seen before. Additionally, the model is also less time-efficient, given that the increase in accuracy is not substantial but the model takes significantly longer to fit. To better understand the trade-off between minimizing loss and maximizing accuracy, we plot model loss and accuracy over the number of epochs for the training and cross-validation data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic16.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;We observe that for the training data, loss decreases to zero while accuracy increases to one, as a result of overfitting. This is why we also check how the model performs on the cross-validation data, for which we observe that loss increases with the number of epochs while accuracy remains relatively stable. Using this figure, we can select an “optimal” number of epochs such that accuracy is maximized while loss is minimized. Looking at the cross-validation data accuracy, we see that the accuracy peak lays at around 20 epochs, for which loss is approximately 0.4. However, similar accuracies but much lower losses and modelling time are achieved with around 6 and 12 epochs, and so we might rather choose to train our model with around 6 or 20 epochs.&lt;/p&gt;
&lt;p&gt;Regarding the model output, the predictions returned are probabilities per class or clothing category. We can calculate the majority vote by taking class that has the maximum of predicted probabilities of all classes. We can print the first ten elements of the &lt;code&gt;majority_vote&lt;/code&gt; dictionary, which we can obtain as follows:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic17.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;All except the fifth (number 4) prediction are correct. In the fifth prediction, a shirt (category 6) is being misclassified as a top (category 0).&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;convolutional-neural-network&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Convolutional Neural Network&lt;/h2&gt;
&lt;p&gt;I also wanted to show you how to build a convolutional neural network and compare its performance to the neural networks presented earlier, mostly because convolutional neural networks have generally been shown to perform better on visual image data. Essentially, what happens in a convolutional neural network is that a smaller matrix (the “filter matrix” or “kernel”) slides over the full image matrix, moving pixel by pixel, multiplies the filter matrix with the part of the full image matrix covered by the filter matrix on that moment, sums up these values and then repeats this until the full image matrix has been covered. For a more extensive explanation on how convolutional neural networks, I refer you to &lt;a href=&#34;https://towardsdatascience.com/a-comprehensive-guide-to-convolutional-neural-networks-the-eli5-way-3bd2b1164a53&#34;&gt;this page&lt;/a&gt; or &lt;a href=&#34;https://medium.com/@RaghavPrabhu/understanding-of-convolutional-neural-network-cnn-deep-learning-99760835f148&#34;&gt;this page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As we need to prepare our data slightly differently for a convolutional neural network, we reload the data and reshape the images to “flatten” them. The last “1” in the reshape dimensions stand for a greyscale, as we have images on a black-to-white scale. If we would have RGB images, we would change the “1” into a “3”.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic18.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;We make sure the the values of the pixels, ranging from zero to 255, are of the float type and then we normalize the values as before.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic19.png&#34; /&gt;
&lt;img src=&#34;screen_shots_python_code/pic20.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;The convolutional neural network cannot deal with categorical labels. Therefore, we transform the labels to binary vectors, where all vectors have length ten (as there are ten categories), a “1” at the index of the category and zeros elsewhere. For example, category 3 and 8 would be coded as [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] and [0, 0, 0, 0, 0, 0, 0, 0, 1, 0], respectively. This transformation is referred to as “one hot encoding”.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic21.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Now, we can start building our convolutional neural network. The first layer &lt;code&gt;Conv2D&lt;/code&gt; is a convolutional layer that takes a 2-dimensional matrix of 28 by 28 pixels in greyscale (1) as input. As before, we use 128 nodes in this layer, as the size of the data is not extremely large and we want to avoid making our model unnecessarily complex. The filter matrix is of size 3 by 3, which is quite standard. As before, we use the rectified linear (“relu”) activation function. The &lt;code&gt;MaxPooling2D&lt;/code&gt; layer reduces the dimensionality (and thus required computational power) by outputting the maximum of the part of the input image that is captured by the filter matrix. The &lt;code&gt;Flatten&lt;/code&gt; layer simply flattens the result from the previous layer into a vector. As we saw before, the &lt;code&gt;softmax&lt;/code&gt; layer then assigns predicted probabilities to each of the ten clothing categories. Note that we use the same optimizer and metric as before, but that we now use “categorical_crossentropy” as the loss function instead of “sparse_categorical_crossentropy”. The reason for this is that the former works for one-hot encoded labels, whereas the other works for categorical labels.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic22.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;We fit our model to the training data, where we set the &lt;code&gt;batch_size&lt;/code&gt; argument equal to the number of neurons in the convolutional layers (= 128).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic23.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic24.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Although we are still overfitting, we observe that the convolutional neural network performs better than the neural networks we saw earlier, achieving a training set accuracy of 95.16% and a test set accuracy of 90.39%, and a lower loss of 28.70. This was to be expected, because convolutional neural networks have previously been shown to perform well on visual imagery data. Let’s see if we can reduce overfitting by reducing the number of neurons from 128 to 64, adding dropout layers and enabling early stopping. Note that the rate in the &lt;code&gt;Dropout&lt;/code&gt; layer is the percentage of connections between layers that are being removed. the &lt;code&gt;SpatialDropout2D&lt;/code&gt; is a special kind of dropout layer for convolutional neural networks, which drops certain multiplications of the filter matrix with parts of the original image before pooling across all movements over the original image.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic25.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;When fitting our model, we also enable early stopping to reduce overfitting. Instead of going through all epochs specified, early stopping automatically stops the iterations through the epoch once it’s being noticed that the validation loss increases.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic26.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;From the results, we observe that although the training and test accuracies have decreased, they are now much more similar than before. The test accuracy has not decreased substantially, but the training accuracy has, which means that overfitting is much less of a problem than before. Next, we can print the first ten predictions from the model and the first ten actual labels and compare them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;screen_shots_python_code/pic27.png&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Comparing these predictions to the first ten labels in the data set, we observe that the first ten predictions are correct!&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;next-up&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Next up…&lt;/h2&gt;
&lt;p&gt;Next up in this series of blog posts, I will experiment with tree-based methods and support vector machines to see if they perform as well as the neural network in predicting clothing categories in the Fashion MNIST data.&lt;/p&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2019/11/11/a-comparison-of-methods-for-predicting-clothing-classes-using-the-fashion-mnist-dataset-in-rstudio-and-python-part-1/&#39;;&lt;/script&gt;
      </description>
    </item>
    
    <item>
      <title>R and TensorFlow Presentations</title>
      <link>https://rviews.rstudio.com/2018/04/03/r-and-tensorflow-presentations/</link>
      <pubDate>Tue, 03 Apr 2018 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2018/04/03/r-and-tensorflow-presentations/</guid>
      <description>
        &lt;p&gt;In early March, the &lt;a href=&#34;https://www.meetup.com/R-Users/events/past/&#34;&gt;Bay Area useR Group&lt;/a&gt; was able to hold an R and TensorFlow mini-conference on Google&amp;rsquo;s new Sunnyvale campus. Pete Mohanty, a Stanford researcher and frequent BARUG speaker, lead off with a talk on his recent &lt;a href=&#34;https://cran.r-project.org/web/packages/kerasformula/index.html&#34;&gt;kerasformula package&lt;/a&gt;, which allows R users to call a &lt;a href=&#34;https://tensorflow.rstudio.com/keras/&#34;&gt;keras&lt;/a&gt;-based neural net with R formula objects. Pete&amp;rsquo;s &lt;a href=&#34;https://web.stanford.edu/~pmohanty/kerasformula_barug.pdf&#34;&gt;slides&lt;/a&gt; show an example of using using a regression-style formula with the  &lt;code&gt;kerasformula::kms()&lt;/code&gt; function to fit a sequential TensorFlow model.&lt;/p&gt;

&lt;p&gt;J.J. Allaire, RStudio&amp;rsquo;s founder and CEO, spoke for over an hour, delivering a polished and comprehensive presentation that ranged from big-picture vistas illuminating the merits and limitations of the Deep Learning methodology to the deep details of R based TensorFlow models. We were not able to record J.J.&amp;rsquo;s BARUG talk, but it was similar to his presentation at the January RStudio conference in San Diego, which is well worth watching.&lt;/p&gt;

&lt;iframe width=&#34;733&#34; height=&#34;340&#34; src=&#34;https://www.youtube.com/embed/atiYXm7JZv0&#34; frameborder=&#34;0&#34; allow=&#34;autoplay; encrypted-media&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;We do have the &lt;a href=&#34;https://beta.rstudioconnect.com/ml-with-tensorflow-and-r/#1&#34;&gt;slides for J.J.&amp;rsquo;s BARUG presentation&lt;/a&gt;. They comprise a comprehensive overview of Deep Learning and the TensorFlow Technology behind it. While most slide presentations are little more than collections of mnemonics, lifeless without the animation of the speaker, J.J.&amp;rsquo;s 113-slide deck stands on its own. Replete with links to current research papers and references that guide a reader to the frontiers of Deep Learning applications, is a very credible introduction and study guide. Because 113 slide are quite a bit to get through in one sitting, especially if you start following interesting links, I offer the following gloss:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Slide&lt;/th&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;What is TensorFlow?&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Why should R users care?&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;6 - 10&lt;/td&gt;
&lt;td&gt;What are tensors?&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;11 - 13&lt;/td&gt;
&lt;td&gt;What is the &amp;ldquo;flow&amp;rdquo;?&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;14 - 16&lt;/td&gt;
&lt;td&gt;Applications with links to examples&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;17 - 26&lt;/td&gt;
&lt;td&gt;What is Deep Learning, how does it work, and what is deep about it?&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;Statistical modeling vs. machine learning with links to seminal papers&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;28 - 36&lt;/td&gt;
&lt;td&gt;A technical overview of what goes on in a Deep Learning model&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;37 - 44&lt;/td&gt;
&lt;td&gt;Applications on the frontiers of Deep Learning with links to recent papers&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;45 - 47&lt;/td&gt;
&lt;td&gt;A perspective on problems, hype and the usefulness of Deep Learning&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;48 - 73&lt;/td&gt;
&lt;td&gt;The details of the R interface to Keras and TensorFlow, with links to the&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;technical documentation and R packages and code&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;73 - 84&lt;/td&gt;
&lt;td&gt;A tour of the models in &lt;a href=&#34;https://tensorflow.rstudio.com/gallery/&#34;&gt;RStudio&amp;rsquo;s TensorFlow Gallery&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;85 - 92&lt;/td&gt;
&lt;td&gt;Tools for running on GPUs, managing experiments, running in the cloud, and deploying TensorFlow models&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;93 - 101&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://tensorflow.rstudio.com/tools/cloudml/&#34;&gt;cloudml&lt;/a&gt;: an interface to Google CloudML&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;102 - 112&lt;/td&gt;
&lt;td&gt;R-based technology for deploying TensorFlow models&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2018/04/03/r-and-tensorflow-presentations/&#39;;&lt;/script&gt;
      </description>
    </item>
    
    <item>
      <title>Deep learning at rstudio::conf 2018</title>
      <link>https://rviews.rstudio.com/2018/02/14/deep-learning-rstudio-conf-2018/</link>
      <pubDate>Wed, 14 Feb 2018 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2018/02/14/deep-learning-rstudio-conf-2018/</guid>
      <description>
        

&lt;p&gt;Two weeks ago, &lt;a href=&#34;https://www.rstudio.com/conference/&#34;&gt;rstudio::conf 2018&lt;/a&gt; was held in San Diego. We had 1,100 people attend the sold-out event.  In this post, I summarize my experience of the talks on the topic of deep learning with R, including the keynote by &lt;a href=&#34;https://www.linkedin.com/profile/view?id=10843566/&#34;&gt;J.J. Allaire&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/post/2018-02-13_de_Vries_deep_learning_at_rstudio_conf_files/J.J._video.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;h1 id=&#34;keynote&#34;&gt;Keynote&lt;/h1&gt;

&lt;p&gt;The keynote on the second day was J.J. Allaire discussing &amp;ldquo;Machine Learning with Tensorflow and R&amp;rdquo;. In this talk, J.J. took us on a tour of how to use TensorFlow with R.  He started with the basics, e.g., what is a tensor (it&amp;rsquo;s an array), and explained how the tensors &amp;ldquo;flow&amp;rdquo; in a computation graph in the &lt;code&gt;TensorFlow&lt;/code&gt; library. The &lt;code&gt;tensorflow&lt;/code&gt; package in R is an interface to the &lt;code&gt;TensorFlow&lt;/code&gt; library, meaning you can access the full power of TensorFlow directly from R.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;/post/2018-02-13_de_Vries_deep_learning_at_rstudio_conf_files/tensors_flowing.gif&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;For several years, there has been a great deal of hype about deep learning, with multiple libraries (primarily written in Python and C++). Of these libraries, TensorFlow seems to get the dominant share of interest. R has always been a language that excels in its ability to interact with other languages, including Fortran, C++, and now Python. With the release of the &lt;code&gt;tensorflow&lt;/code&gt; package, R users can make full use of &lt;em&gt;all&lt;/em&gt; of the functions in TensorFlow.&lt;/p&gt;

&lt;p&gt;Advances in deep learning, including algorithms, GPU computing, and availability of large data sets, have combined for the enormous success of deep learning in many fields. This includes near-human-level performance in the fields of image classification, speech recognition, and machine translation, to name a few.&lt;/p&gt;

&lt;p&gt;However, J.J. points out that TensorFlow is quite a low-level mathematical library, and that most practitioners would benefit from writing their neural network code using &lt;code&gt;keras&lt;/code&gt;, a package that exposes a high-level API. Keras supports multiple back ends, including TensorFlow, CNTK and Theano. You can find out more at the &lt;a href=&#34;https://keras.rstudio.com/&#34;&gt;&lt;code&gt;keras&lt;/code&gt; package page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;J.J. concluded his talk by demonstrating several ways to deploy a &lt;code&gt;keras&lt;/code&gt; or &lt;code&gt;tensorflow&lt;/code&gt; model, including publishing to RStudio Connect.&lt;/p&gt;

&lt;p&gt;To find out more about J.J.&amp;rsquo;s talk, you can watch the &lt;a href=&#34;https://www.youtube.com/watch?v=atiYXm7JZv0&#34;&gt;keynote video&lt;/a&gt; or view the &lt;a href=&#34;https://rstd.io/ml-with-tensorflow-and-r/&#34;&gt;slides&lt;/a&gt;. You can also download the &lt;a href=&#34;https://github.com/rstudio/cheatsheets/raw/master/keras.pdf&#34;&gt;&lt;code&gt;keras&lt;/code&gt; cheat sheet&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&#34;other-talks&#34;&gt;Other talks&lt;/h1&gt;

&lt;p&gt;Following the keynote, the conference split into several tracks. I attended the session1: &amp;ldquo;interop&amp;rdquo;, which focused on interoperability between R and several deep-learning frameworks, including deployment options.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The first talk in this session was by &lt;a href=&#34;https://www.linkedin.com/in/michaelquinn32?lipi=urn%3Ali%3Apage%3Ad_flagship3_profile_view_base%3B87KZ5Uq%2FQxSpdhxC0jwFkg%3D%3D&#34;&gt;Michael Quinn&lt;/a&gt; from Google. Michael discussed &amp;ldquo;large-scale machine learning using TensorFlow, BigQuery and Cloud ML&amp;rdquo;. Once you have a &lt;code&gt;keras&lt;/code&gt; or &lt;code&gt;tensorflow&lt;/code&gt; model, you can deploy this to &lt;a href=&#34;https://cloud.google.com/ml-engine/&#34;&gt;Google Cloud Machine Learning&lt;/a&gt; (Cloud ML). What I find interesting about this is that Cloud ML is a service designed for machine learning. Using this service, you can deploy models without having to stand up a virtual machine first.  You can do this deployment using R code with the &lt;a href=&#34;https://tensorflow.rstudio.com/tools/cloudml/articles/getting_started.html&#34;&gt;&lt;code&gt;cloudml&lt;/code&gt; package&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The next talk was by Javier Luraschi from RStudio, who spoke about &amp;ldquo;Deploying TensorFlow models with &lt;code&gt;tfdeploy&lt;/code&gt;&amp;rdquo;. The &lt;a href=&#34;https://tensorflow.rstudio.com/tools/tfdeploy/articles/introduction.html&#34;&gt;&lt;code&gt;tfdeploy&lt;/code&gt; package&lt;/a&gt; exposes a unified way to deploy models to several platforms, including &lt;a href=&#34;https://www.tensorflow.org/serving/https://www.tensorflow.org/serving/&#34;&gt;TensorFlow Serving&lt;/a&gt;, &lt;a href=&#34;https://tensorflow.rstudio.com/tools/cloudml/&#34;&gt;Cloud ML&lt;/a&gt;, and &lt;a href=&#34;https://www.rstudio.com/products/connect/&#34;&gt;RStudio Connect&lt;/a&gt;. Javier made his talk available as &lt;a href=&#34;http://rpubs.com/jluraschi/deploying-tensorflow-rstudio-conf&#34;&gt;slides&lt;/a&gt; as well as &lt;a href=&#34;https://github.com/rstudio/rstudio-conf/tree/master/2018/Deploying_TensorFlow_Models--Javier%20Luraschi&#34;&gt;code&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The final presentation was by &lt;a href=&#34;https://www.linkedin.com/in/alikzaidi/&#34;&gt;Ali Zaid&lt;/a&gt; from Microsoft, who talked about &amp;ldquo;Reinforcement learning in Minecraft with CNTK-R&amp;rdquo;. Ali showed how he trained a deep-learning model to control an agent in &lt;a href=&#34;https://minecraft.net/en-us/&#34;&gt;Minecraft&lt;/a&gt;, the popular online game. In his experiment, he taught the agent to navigate a maze, as well as understand the some natural language, e.g., &amp;ldquo;Pick up the red flowers&amp;rdquo;. He used the &lt;a href=&#34;https://github.com/Microsoft/CNTK-R&#34;&gt;&lt;code&gt;CNTK-R&lt;/code&gt; package&lt;/a&gt;, which wraps the &lt;a href=&#34;https://github.com/microsoft/cntk&#34;&gt;Microsoft Cognitive Toolkit (CNTK)&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;In conclusion, I&amp;rsquo;ll quote directly from J.J. Allaire&amp;rsquo;s keynote, in which he describes the key takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;TensorFlow is a new general-purpose numerical-computing library with lots to offer the R community.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Deep learning has made great progress and will likely increase in importance in various fields in the coming years.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;R now has a great set of APIs and supporting tools for using TensorFlow and doing deep learning.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2018/02/14/deep-learning-rstudio-conf-2018/&#39;;&lt;/script&gt;
      </description>
    </item>
    
    <item>
      <title>Fitting a TensorFlow Linear Classifier with tfestimators</title>
      <link>https://rviews.rstudio.com/2018/01/12/linear-model-in-tensorflow/</link>
      <pubDate>Fri, 12 Jan 2018 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2018/01/12/linear-model-in-tensorflow/</guid>
      <description>
        


&lt;p&gt;In a &lt;a href=&#34;https://rviews.rstudio.com/2017/12/11/r-and-tensorflow/&#34;&gt;recent post&lt;/a&gt;, I mentioned three avenues for working with TensorFlow from R:&lt;br /&gt;
* The &lt;a href=&#34;https://cran.r-project.org/web/packages/keras/index.html&#34;&gt;&lt;code&gt;keras&lt;/code&gt; package&lt;/a&gt;, which uses the &lt;a href=&#34;https://keras.io/&#34;&gt;Keras API&lt;/a&gt; for building scaleable, deep learning models * The &lt;a href=&#34;https://cran.r-project.org/package=tfestimators&#34;&gt;&lt;code&gt;tfestimators&lt;/code&gt; package&lt;/a&gt;, which wraps Google’s &lt;a href=&#34;https://www.tensorflow.org/programmers_guide/estimators&#34;&gt;Estimators API&lt;/a&gt; for fitting models with pre-built estimators&lt;br /&gt;
* The &lt;a href=&#34;https://cran.r-project.org/package=tensorflow&#34;&gt;&lt;code&gt;tensorflow&lt;/code&gt; package&lt;/a&gt;, which provides an interface to Google’s low-level &lt;a href=&#34;https://www.tensorflow.org/api_docs/python/&#34;&gt;TensorFlow API&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this post, Edgar and I use the &lt;code&gt;linear_classifier()&lt;/code&gt; function, one of six pre-built models currently in the &lt;code&gt;tfestimators&lt;/code&gt; package, to train a linear classifier using data from the &lt;a href=&#34;https://cran.r-project.org/web/packages/titanic/index.html&#34;&gt;&lt;code&gt;titanic&lt;/code&gt;&lt;/a&gt; package.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2018-01-08-tfestimators_files/estimators.png&#34; /&gt;

&lt;/div&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(tfestimators)
library(tensorflow)
library(tidyverse)
library(titanic)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;titanic_train&lt;/code&gt; data set contains 12 fields of information on 891 passengers from the Titanic. First, we load the data, split it into training and test sets, and have a look at it.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;titanic_set &amp;lt;- titanic_train %&amp;gt;% filter(!is.na(Age))

# Split the data into training and test data sets
indices &amp;lt;- sample(1:nrow(titanic_set), size = 0.80 * nrow(titanic_set))
train &amp;lt;- titanic_set[indices, ]
test  &amp;lt;- titanic_set[-indices, ]

glimpse(titanic_set)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## Observations: 714
## Variables: 12
## $ PassengerId &amp;lt;int&amp;gt; 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16...
## $ Survived    &amp;lt;int&amp;gt; 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,...
## $ Pclass      &amp;lt;int&amp;gt; 3, 1, 3, 1, 3, 1, 3, 3, 2, 3, 1, 3, 3, 3, 2, 3, 3,...
## $ Name        &amp;lt;chr&amp;gt; &amp;quot;Braund, Mr. Owen Harris&amp;quot;, &amp;quot;Cumings, Mrs. John Bra...
## $ Sex         &amp;lt;chr&amp;gt; &amp;quot;male&amp;quot;, &amp;quot;female&amp;quot;, &amp;quot;female&amp;quot;, &amp;quot;female&amp;quot;, &amp;quot;male&amp;quot;, &amp;quot;mal...
## $ Age         &amp;lt;dbl&amp;gt; 22, 38, 26, 35, 35, 54, 2, 27, 14, 4, 58, 20, 39, ...
## $ SibSp       &amp;lt;int&amp;gt; 1, 1, 0, 1, 0, 0, 3, 0, 1, 1, 0, 0, 1, 0, 0, 4, 1,...
## $ Parch       &amp;lt;int&amp;gt; 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 0, 5, 0, 0, 1, 0,...
## $ Ticket      &amp;lt;chr&amp;gt; &amp;quot;A/5 21171&amp;quot;, &amp;quot;PC 17599&amp;quot;, &amp;quot;STON/O2. 3101282&amp;quot;, &amp;quot;1138...
## $ Fare        &amp;lt;dbl&amp;gt; 7.2500, 71.2833, 7.9250, 53.1000, 8.0500, 51.8625,...
## $ Cabin       &amp;lt;chr&amp;gt; &amp;quot;&amp;quot;, &amp;quot;C85&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;C123&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;E46&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;G6&amp;quot;...
## $ Embarked    &amp;lt;chr&amp;gt; &amp;quot;S&amp;quot;, &amp;quot;C&amp;quot;, &amp;quot;S&amp;quot;, &amp;quot;S&amp;quot;, &amp;quot;S&amp;quot;, &amp;quot;S&amp;quot;, &amp;quot;S&amp;quot;, &amp;quot;S&amp;quot;, &amp;quot;C&amp;quot;, &amp;quot;S&amp;quot;, ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that both &lt;code&gt;Sex&lt;/code&gt; and &lt;code&gt;Embarked&lt;/code&gt; are character variables. We would like to make both of these categorical variables for the analysis. We can do this “on the fly” by using the&lt;code&gt;tfestimators::feature_columns()&lt;/code&gt; function to get the data into the &lt;em&gt;shape&lt;/em&gt; expected for an input Tensor. Category levels are set by passing a list to the &lt;code&gt;vocabulary_list argument&lt;/code&gt;. The Pclass variable is passed as a numeric feature, so no further action is required.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cols &amp;lt;- feature_columns(
  column_categorical_with_vocabulary_list(&amp;quot;Sex&amp;quot;, vocabulary_list = 
                                            list(&amp;quot;male&amp;quot;, &amp;quot;female&amp;quot;)),
  column_categorical_with_vocabulary_list(&amp;quot;Embarked&amp;quot;, vocabulary_list = 
                                            list(&amp;quot;S&amp;quot;, &amp;quot;C&amp;quot;, &amp;quot;Q&amp;quot;, &amp;quot;&amp;quot;)),
  column_numeric(&amp;quot;Pclass&amp;quot;)
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far, no real processing has taken place. The data have not yet been evaluated by R or loaded into TensorFlow. Our first interaction with TensorFlow begins when we use the &lt;code&gt;linear_classifier()&lt;/code&gt; function to build the TensorFlow model object for a linear model.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;model &amp;lt;- linear_classifier(feature_columns = cols)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we use the &lt;code&gt;tfestimators::input_fn()&lt;/code&gt; to get the data into TensorFlow and define the model itself. The following helper function sets up the predictive variables and response variable for a model to predict survival from knowing a passenger’s sex, ticket class, and port of embarkation.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;titanic_input_fn &amp;lt;- function(data) {
  input_fn(data, 
           features = c(&amp;quot;Sex&amp;quot;, &amp;quot;Pclass&amp;quot;, &amp;quot;Embarked&amp;quot;), 
           response = &amp;quot;Survived&amp;quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;tfestimators::train()&lt;/code&gt; uses the helper function to fit and train the model on the training set constructed above.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;train(model, titanic_input_fn(train))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;tensorflow::evaluate()&lt;/code&gt; function evaluates the model’s performance.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;model_eval &amp;lt;- evaluate(model, titanic_input_fn(test))
glimpse(model_eval)  &lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## Observations: 1
## Variables: 9
## $ loss                 &amp;lt;dbl&amp;gt; 40.2544
## $ accuracy_baseline    &amp;lt;dbl&amp;gt; 0.5874126
## $ global_step          &amp;lt;dbl&amp;gt; 5
## $ auc                  &amp;lt;dbl&amp;gt; 0.8096247
## $ `prediction/mean`    &amp;lt;dbl&amp;gt; 0.3557937
## $ `label/mean`         &amp;lt;dbl&amp;gt; 0.4125874
## $ average_loss         &amp;lt;dbl&amp;gt; 0.5629987
## $ auc_precision_recall &amp;lt;dbl&amp;gt; 0.8102072
## $ accuracy             &amp;lt;dbl&amp;gt; 0.7132867&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s not a great model, by any means, but an AUC of 0.85 isn’t bad for a first try. We will use R’s familiar &lt;code&gt;predict()&lt;/code&gt; function to make some predictions with the &lt;code&gt;test&lt;/code&gt; data set. Notice that this data needs to be wrapped in the &lt;code&gt;titanic_input_fn()&lt;/code&gt; just like we did for the training data above.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;model_predict &amp;lt;- predict(model, titanic_input_fn(test))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following code unpacks the list containing the prediction results.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;res &amp;lt;- data.frame(matrix(unlist(model_predict[[1]]),ncol=2,byrow=TRUE), 
                  unlist(model_predict[[2]]), unlist(model_predict[[3]]), 
                  unlist(model_predict[[4]]), unlist(model_predict[[5]]))
names(res) &amp;lt;- c(&amp;quot;Prob Survive&amp;quot;, &amp;quot;Prob Perish&amp;quot;,names(model_predict)[2:5])
options(digits=3)
head(res)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;##   Prob Survive Prob Perish  logits classes class_ids logistic
## 1        0.380       0.620  0.4899       1         1    0.620
## 2        0.509       0.491 -0.0373       0         0    0.491
## 3        0.380       0.620  0.4899       1         1    0.620
## 4        0.509       0.491 -0.0373       0         0    0.491
## 5        0.781       0.219 -1.2697       0         0    0.219
## 6        0.735       0.265 -1.0180       0         0    0.265&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before finishing up, we note that TensorFlow writes quite a bit of information to disk:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;list.files(model$estimator$model_dir)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;##  [1] &amp;quot;checkpoint&amp;quot;                       &amp;quot;eval&amp;quot;                            
##  [3] &amp;quot;graph.pbtxt&amp;quot;                      &amp;quot;logs&amp;quot;                            
##  [5] &amp;quot;model.ckpt-1.data-00000-of-00001&amp;quot; &amp;quot;model.ckpt-1.index&amp;quot;              
##  [7] &amp;quot;model.ckpt-1.meta&amp;quot;                &amp;quot;model.ckpt-5.data-00000-of-00001&amp;quot;
##  [9] &amp;quot;model.ckpt-5.index&amp;quot;               &amp;quot;model.ckpt-5.meta&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we use the &lt;a href=&#34;https://www.tensorflow.org/get_started/summaries_and_tensorboard&#34;&gt;TensorBoard&lt;/a&gt; visualization tool to look at the data flow graph and other aspects of the model.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2018-01-08-tfestimators_files/linear_model.png&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;To see all of this, point your browser to address returned by the following command.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;tensorboard(model$estimator$model_dir, action=&amp;quot;start&amp;quot;) &lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## Started TensorBoard at http://127.0.0.1:5503&lt;/code&gt;&lt;/pre&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2018/01/12/linear-model-in-tensorflow/&#39;;&lt;/script&gt;
      </description>
    </item>
    
    <item>
      <title>Connecting R to Keras and TensorFlow</title>
      <link>https://rviews.rstudio.com/2017/12/11/r-and-tensorflow/</link>
      <pubDate>Mon, 11 Dec 2017 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2017/12/11/r-and-tensorflow/</guid>
      <description>
        


&lt;p&gt;It has always been the mission of R developers to connect R to the “good stuff”. As John Chambers puts it in his book &lt;em&gt;&lt;a href=&#34;http://amzn.to/2A2U1RG&#34;&gt;Extending R&lt;/a&gt;&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;One of the attractions of R has always been the ability to compute an interesting result quickly. A key motivation for the original S remains as important now: to give easy access to the best computations for understanding data.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;From the day it was announced a little over two years ago, it was clear that Google’s &lt;a href=&#34;https://www.tensorflow.org/&#34;&gt;TensorFlow&lt;/a&gt; platform for &lt;a href=&#34;https://en.wikipedia.org/wiki/Deep_learning#cite_note-dechter1986-22&#34;&gt;Deep Learning&lt;/a&gt; is good stuff. This September (see &lt;a href=&#34;https://blog.rstudio.com/2017/09/05/keras-for-r/&#34;&gt;announcment&lt;/a&gt;), J.J. Allaire, François Chollet, and the other authors of the &lt;a href=&#34;https://cran.r-project.org/package=keras&#34;&gt;keras package&lt;/a&gt; delivered on R’s “easy access to the best” mission in a big way. Data scientists can now build very sophisticated Deep Learning models from an R session while maintaining the &lt;em&gt;flow&lt;/em&gt; that R users expect. The strategy that made this happen seems to have been straightforward. But, the smooth experience of using the &lt;code&gt;Keras&lt;/code&gt; API indicates inspired programming all the way along the chain from TensorFlow to R.&lt;/p&gt;
&lt;div id=&#34;the-keras-strategy&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;The Keras Strategy&lt;/h3&gt;
&lt;p&gt;TensorFlow itself is implemented as a &lt;a href=&#34;https://en.wikipedia.org/wiki/Dataflow_programming&#34;&gt;Data Flow Language&lt;/a&gt; on a directed graph. Operations are implemented as nodes on the graph and the data, multi-dimensional arrays called “tensors”, flow over the graph as directed by control signals. An overview and some of the details of how this all happens is lucidly described in a &lt;a href=&#34;http://delivery.acm.org/10.1145/3090000/3088527/pldiws17mapl-maplmainid2.pdf?ip=73.71.144.79&amp;amp;id=3088527&amp;amp;acc=OA&amp;amp;key=4D4702B0C3E38B35%2E4D4702B0C3E38B35%2E4D4702B0C3E38B35%2E5945DC2EABF3343C&amp;amp;CFID=831811081&amp;amp;CFTOKEN=34450892&amp;amp;__acm__=1512687001_5cc6d6628bb281a58e545884cba347f9&#34;&gt;paper by Abadi, Isard and Murry&lt;/a&gt; of the Google Brain Team,&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2017-12-7-Rickert-TensorFlow_files/TF_graph.png&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;and even more details and some fascinating history are contained in Peter Goldsborough’s paper, &lt;a href=&#34;https://arxiv.org/pdf/1610.01178v1.pdf&#34;&gt;A Tour of TensorFlow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This kind of programming will probably strike most R users as being exotic and obscure, but my guess is that because of the &lt;a href=&#34;https://pdfs.semanticscholar.org/6869/4d0a776b55459392a1fdead1bad5266f4b38.pdf&#34;&gt;long history&lt;/a&gt; of dataflow programming and parallel computing, it was an obvious choice for the Google computer scientists who were tasked to develop a platform flexible enough to implement arbitrary algorithms, work with extremely large data sets, and be easily implementable on any kind of distributed hardware including GPUs, CPUs, and mobile devices.&lt;/p&gt;
&lt;p&gt;The TensorFlow operations are written in C++, &lt;a href=&#34;https://developer.nvidia.com/cuda-downloads&#34;&gt;CUDA&lt;/a&gt;, &lt;a href=&#34;http://eigen.tuxfamily.org/index.php?title=Main_Page&#34;&gt;Eigen&lt;/a&gt;, and other low-level languages optimized for different operation. Users don’t directly program TensorFlow at this level. Instead, they assemble flow graphs or algorithms using a higher-level language, most commonly Python, that accesses the elementary building blocks through an &lt;a href=&#34;https://www.tensorflow.org/api_docs/&#34;&gt;API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;keras&lt;/code&gt; R package wraps the &lt;a href=&#34;https://www.tensorflow.org/api_docs/&#34;&gt;Keras Python Library&lt;/a&gt; that was expressly built for developing Deep Learning Models. It supports convolutional networks (for computer vision), recurrent networks (for sequence processing), and any combination of both, as well as arbitrary network architectures: multi-input or multi-output models, layer sharing, model sharing, etc. (It should be pretty clear that the Python code that makes this all happen counts as good stuff too.)&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;getting-started-with-keras-and-tensorflow&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Getting Started with Keras and TensorFlow&lt;/h3&gt;
&lt;p&gt;Setting up the whole shebang on your local machine couldn’t be simpler, just three lines of code:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;install.packages(&amp;quot;keras&amp;quot;)
library(keras)
install_keras()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just install and load the &lt;code&gt;keras&lt;/code&gt; R package and then run the &lt;code&gt;keras::install_keras()&lt;/code&gt; function, which installs TensorFlow, Python and everything else you need including a &lt;a href=&#34;https://virtualenv.pypa.io/en/stable/&#34;&gt;Virtualenv&lt;/a&gt; or &lt;a href=&#34;https://conda.io/docs/&#34;&gt;Conda&lt;/a&gt; environment. It just works! For instructions on installing Keras and TensorFLow on GPUs, look &lt;a href=&#34;https://tensorflow.rstudio.com/installation_gpu.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That’s it; just a few minutes and you are ready to start a hands-on exploration of the extensive documentation on the RStudio’s TensorFlow webpage &lt;a href=&#34;https://tensorflow.rstudio.com/&#34;&gt;tensorflow.rstudio.com&lt;/a&gt;, or jump right in and build a &lt;a href=&#34;https://tensorflow.rstudio.com/keras/&#34;&gt;Deep Learning model&lt;/a&gt; to classify the hand-written numerals using&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2017-12-7-Rickert-TensorFlow_files/MNIST.png&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;MNIST data set which comes with the &lt;code&gt;keras&lt;/code&gt; package, or any one of the other twenty-five pre-built examples.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;beyond-deep-learning&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Beyond Deep Learning&lt;/h3&gt;
&lt;p&gt;Being able to build production-level Deep Learning applications from R is important, but Deep Learning is not the answer to everything, and TensorFlow is bigger than Deep Learning. The really big ideas around TensorFlow are: (1) TensorFlow is a general-purpose platform for building large, distributed applications on a wide range of cluster architectures, and (2) while data flow programming takes some getting used to, TensorFlow was designed for algorithm development with big data.&lt;/p&gt;
&lt;p&gt;Two additional R packages make general modeling and algorithm development in TensorFlow accessible to R users.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/rstudio/tfestimators&#34;&gt;&lt;code&gt;tfestimators&lt;/code&gt;&lt;/a&gt; package, currently on GitHub, provides an interface to Google’s &lt;a href=&#34;https://www.tensorflow.org/programmers_guide/estimators&#34;&gt;Estimators&lt;/a&gt; API, which provides access to pre-built TensorFlow models including SVM’s, Random Forests and KMeans. The architecture of the API looks something like this:&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2017-12-7-Rickert-TensorFlow_files/tfestimators.png&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;There are several layers in the stack, but execution on the small models I am running locally goes quickly. Look &lt;a href=&#34;https://tensorflow.rstudio.com/tfestimators/&#34;&gt;here&lt;/a&gt; for documentation and sample models that you can run yourself.&lt;/p&gt;
&lt;p&gt;At the deepest level, the &lt;a href=&#34;https://CRAN.R-project.org/package=tensorflow&#34;&gt;&lt;code&gt;tensorflow&lt;/code&gt;&lt;/a&gt; package provides an interface to the core &lt;a href=&#34;https://www.tensorflow.org/api_docs/python/&#34;&gt;TensorFlow API&lt;/a&gt;, which comprises a set of Python modules that enable constructing and executing TensorFlow graphs. The documentation on the package’s &lt;a href=&#34;https://tensorflow.rstudio.com/tensorflow/articles/tutorial_mnist_pros.html&#34;&gt;webpage&lt;/a&gt; is impressive, containing tutorials for different levels of expertise, several examples, and references for further reading. The &lt;a href=&#34;https://tensorflow.rstudio.com/tensorflow/articles/tutorial_mnist_beginners.html&#34;&gt;MNIST for ML Beginners&lt;/a&gt; tutorial works through the classification problem described above in terms of the Keras interface at a low level that works through the details of a softmax regression.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2017-12-7-Rickert-TensorFlow_files/softmax.png&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;While Deep Learning is sure to capture most of the R to TensorFlow attention in the near term, I think having easy access to a big league computational platform will turn out to be the most important benefit to R users in the long run.&lt;/p&gt;
&lt;p&gt;As a final thought, I am very much enjoying reading the &lt;a href=&#34;https://www.manning.com/books/deep-learning-with-r&#34;&gt;MEAP&lt;/a&gt; from the forthcoming Manning Book, &lt;em&gt;Deep Learning with R&lt;/em&gt; by François Chollet, the creator of Keras, and J.J. Allaire. It is a really good read, masterfully balancing theory and hands-on practice, that ought to be helpful to anyone interested in Deep Learning and TensorFlow.&lt;/p&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2017/12/11/r-and-tensorflow/&#39;;&lt;/script&gt;
      </description>
    </item>
    
    <item>
      <title>R and Singularity</title>
      <link>https://rviews.rstudio.com/2017/03/29/r-and-singularity/</link>
      <pubDate>Wed, 29 Mar 2017 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2017/03/29/r-and-singularity/</guid>
      <description>
        

&lt;p&gt;R (&lt;a href=&#34;https://www.r-project.org&#34; class=&#34;uri&#34;&gt;https://www.r-project.org&lt;/a&gt;) 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 (&lt;a href=&#34;http://singularity.lbl.gov/&#34; class=&#34;uri&#34;&gt;http://singularity.lbl.gov/&lt;/a&gt;).&lt;/p&gt;
&lt;div id=&#34;containers&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Containers&lt;/h2&gt;
&lt;p&gt;A &lt;em&gt;container&lt;/em&gt; 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.&lt;/p&gt;
&lt;p&gt;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 (&lt;a href=&#34;https://github.com/NERSC/shifter&#34; class=&#34;uri&#34;&gt;https://github.com/NERSC/shifter&lt;/a&gt;) 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;reproducible-research&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Reproducible research&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;However, as R integrates with an increasing number of external libraries and frameworks like cuDNN, Spark, and others, the ability to reproduce the &lt;em&gt;software environment&lt;/em&gt; 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.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;examples&#34; class=&#34;section level1&#34;&gt;
&lt;h1&gt;Examples&lt;/h1&gt;
&lt;p&gt;The following examples assume that Singularity is installed on your system. See &lt;a href=&#34;http://singularity.lbl.gov/&#34; class=&#34;uri&#34;&gt;http://singularity.lbl.gov/&lt;/a&gt; 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.&lt;/p&gt;
&lt;div id=&#34;hello-tensorflow&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Hello TensorFlow&lt;/h2&gt;
&lt;p&gt;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 (&lt;a href=&#34;https://github.com/tensorflow/tensorflow&#34; class=&#34;uri&#34;&gt;https://github.com/tensorflow/tensorflow&lt;/a&gt;, &lt;a href=&#34;https://github.com/python/cpython&#34; class=&#34;uri&#34;&gt;https://github.com/python/cpython&lt;/a&gt;), 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 &lt;code&gt;main.R&lt;/code&gt; in its working directory.&lt;/p&gt;
&lt;p&gt;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.)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BootStrap: debootstrap
OSVersion: xenial
MirrorURL: http://archive.ubuntu.com/ubuntu/

%post
  sed -i &amp;#39;s/main/main restricted universe/g&amp;#39; /etc/apt/sources.list
  apt-get update

  # Install R, Python, misc. utilities
  apt-get install -y libopenblas-dev r-base-core libcurl4-openssl-dev libopenmpi-dev openmpi-bin openmpi-common openmpi-doc openssh-client openssh-server libssh-dev wget vim git nano git cmake  gfortran g++ curl wget python autoconf bzip2 libtool libtool-bin python-pip python-dev
  apt-get clean
  locale-gen en_US.UTF-8

  # Install Tensorflow
  pip install tensorflow

  # Install required R packages
  R --slave -e &amp;#39;install.packages(&amp;quot;devtools&amp;quot;, repos=&amp;quot;https://cloud.r-project.org/&amp;quot;)&amp;#39;
  R --slave -e &amp;#39;devtools::install_github(&amp;quot;rstudio/tensorflow&amp;quot;)&amp;#39;

%test
  #!/bin/sh
  exec R --slave -e &amp;quot;library(tensorflow); \
                     sess  &amp;lt;- tensorflow::tf\$Session(); \
                     hello &amp;lt;- tensorflow::tf\$constant(&amp;#39;Hello, TensorFlow!&amp;#39;); \
                     sess\$run(hello)&amp;quot;


%runscript
  #!/bin/bash
  Rscript --slave &amp;quot;main.R&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt; If you’re running on Red Hat or CentOS, you’ll need the debootstrap program: &lt;code&gt;sudo yum install debootstrap&lt;/code&gt;. See the Singularity documentation for more information.&lt;/p&gt;
&lt;p&gt;Assuming that the above definition file is named &lt;code&gt;tensorflow.def&lt;/code&gt;, you can bootstrap a Singularity container image named &lt;code&gt;tensorflow.img&lt;/code&gt; with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo rm -f tensorflow.img &amp;amp;&amp;amp; \
sudo singularity create --size 4000 tensorflow.img &amp;amp;&amp;amp; \
sudo singularity bootstrap tensorflow.img tensorflow.def&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;%post&lt;/code&gt; section of the definition file installs R, Python, Tensorflow and miscellaneous utilities into the container. The &lt;code&gt;%test&lt;/code&gt; section runs the “hello world” program as an example to verify things are working. The &lt;code&gt;%run&lt;/code&gt; section of this example simply runs an arbitrary user R program named &lt;code&gt;main.R&lt;/code&gt; in the container’s working directory.&lt;/p&gt;
&lt;p&gt;Run the “hello world” &lt;code&gt;%test&lt;/code&gt; script with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;singularity test tensorflow.img&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;You can run an arbitrary R program in the container by creating a &lt;code&gt;main.R&lt;/code&gt; file in the container working directory and running:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;singularity run tensorflow.img&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;full-genome-variant-principal-components&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Full-genome variant Principal Components&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Genomic variants record differences in a genome relative to a reference. Many types of differences exist, see for instance &lt;a href=&#34;https://en.wikipedia.org/wiki/Structural_variation&#34; class=&#34;uri&#34;&gt;https://en.wikipedia.org/wiki/Structural_variation&lt;/a&gt;. 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, &lt;em&gt;Nature&lt;/em&gt; 526, 68-74 (01 October 2015) &lt;a href=&#34;doi:10.1038/nature15393&#34; class=&#34;uri&#34;&gt;doi:10.1038/nature15393&lt;/a&gt;). 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 &lt;code&gt;*.vcf.gz&lt;/code&gt; in the working directory).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;Rmpi&lt;/code&gt;, &lt;code&gt;doMPI&lt;/code&gt;, and &lt;code&gt;foreach&lt;/code&gt; 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:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Launched by MPI&lt;/li&gt;
&lt;li&gt;One or more gzip-compressed variant files ending in “.vcf.gz” (the program will use all files matching this pattern)&lt;/li&gt;
&lt;li&gt;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&lt;/li&gt;
&lt;li&gt;Optional CHUNKSIZE environment variable in number of variants per chunk&lt;/li&gt;
&lt;li&gt;Optional NCOMP environment variable specifying the number of principal components to return, defaulting to 3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A successful run produces the following output:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A file ‘pca.rdata’ in serialized R format containing the largest NCOMP singular values and corresponding principal component vectors of the variant data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This example was designed for deployment with supercomputer systems in mind. See &lt;a href=&#34;https://github.com/bwlewis/1000_genomes_examples&#34; class=&#34;uri&#34;&gt;https://github.com/bwlewis/1000_genomes_examples&lt;/a&gt; for other implementations that don’t require MPI.&lt;/p&gt;
&lt;p&gt;Singularity encapsulates the program logic and the external library dependency chain (MPI, etc.) required by the computation in the following definition file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BootStrap: debootstrap
OSVersion: xenial
MirrorURL: http://archive.ubuntu.com/ubuntu/
Include: bash

%post
  sed -i &amp;#39;s/main/main restricted universe/g&amp;#39; /etc/apt/sources.list
  apt-get update

  # Install R, openmpi, misc. utilities:
  apt-get install -y libopenblas-dev r-base-core libcurl4-openssl-dev libopenmpi-dev openmpi-bin openmpi-common openmpi-doc openssh-client openssh-server libssh-dev wget vim git nano git cmake  gfortran g++ curl wget python autoconf bzip2 libtool libtool-bin
  apt-get clean

  # Install required R packages
  R --slave -e &amp;#39;install.packages(c(&amp;quot;irlba&amp;quot;, &amp;quot;doMPI&amp;quot;), repos=&amp;quot;https://cloud.r-project.org/&amp;quot;)&amp;#39;

  # Install simple VCF parser helper
  wget https://raw.githubusercontent.com/bwlewis/1000_genomes_examples/master/parse.c &amp;amp;&amp;amp; cc -O2 parse.c &amp;amp;&amp;amp; mv a.out /usr/local/bin/parsevcf &amp;amp;&amp;amp; rm parse.c

  # Set up unit test
  mkdir -p /usr/local/share/R
  chmod a+rwx /usr/local/share/R
  wget https://raw.githubusercontent.com/bwlewis/1000_genomes_examples/master/unit.R &amp;amp;&amp;amp; mv unit.R /usr/local/share/R/

  # This is the main R program run by /singularity
  wget https://raw.githubusercontent.com/bwlewis/1000_genomes_examples/master/pca-mpi.R &amp;amp;&amp;amp; mv pca-mpi.R /usr/local/share/R/


%test
  #!/bin/sh
  exec Rscript --slave &amp;quot;/usr/local/share/R/unit.R&amp;quot;

%runscript
  #!/bin/bash
  Rscript --slave &amp;quot;/usr/local/share/R/pca-mpi.R&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Build and bootstrap a Singularity container using the &lt;code&gt;variant_pca.def&lt;/code&gt; definition file with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo rm -f variant_pca.img &amp;amp;&amp;amp; \
sudo singularity create --size 4000 variant_pca.img &amp;amp;&amp;amp; \
sudo singularity bootstrap variant_pca.img variant_pca.def&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;unit-test&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Unit test&lt;/h3&gt;
&lt;p&gt;The container includes a simple unit test that verifies MPI operation invoked by:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mpirun -np 4 singularity test variant_pca.img&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;small-example&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Small example&lt;/h3&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wget https://raw.githubusercontent.com/bwlewis/1000_genomes_examples/extra/chr21.head.vcf.gz
wget https://raw.githubusercontent.com/bwlewis/1000_genomes_examples/extra/chr22.head.vcf.gz
LANG=C CHUNKSIZE=10000000 mpirun -x LANG -x CHUNKSIZE -np 2 singularity run -H $(pwd) variant_pca.img &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read the output pca.rdata file from R using &lt;code&gt;readRDS()&lt;/code&gt;. The following code plots the first three estimated principal components.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- readRDS(&amp;#39;pca.rdata&amp;#39;)
library(lattice)
splom(x$v)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2017-03-27-r-and-singularity_files/figure-html/unnamed-chunk-2-1.png&#34; width=&#34;672&#34; /&gt; 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.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;full-sized-example&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Full-sized example&lt;/h3&gt;
&lt;p&gt;Finally, compute the whole genome principal components across all chromosomes and all 2,504 people in the 1000 Genomes project with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Remove small example files if they exist
rm -f chr21.head.vcf.gz chr22.head.vcf.gz

# Download the variant files
j=1
while test $j -lt 23; do
  wget ftp://ftp-trace.ncbi.nih.gov/1000genomes/ftp/release/20130502/ALL.chr${j}.phase3_shapeit2_mvncall_integrated_v5a.20130502.genotypes.vcf.gz &amp;amp;
  j=$(( $j + 1 ))
done
wait&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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 the files to each computer.&lt;/p&gt;
&lt;p&gt;The Singularity container image must also be available to run on each computer, so copy the image to each one.&lt;/p&gt;
&lt;p&gt;Now scatter the &lt;code&gt;*.vcf.gz&lt;/code&gt; files across your MPI computers, for instance using &lt;code&gt;scp&lt;/code&gt;. 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 &lt;a href=&#34;https://cran.r-project.org/web/packages/doMPI/vignettes/doMPI.pdf&#34; class=&#34;uri&#34;&gt;https://cran.r-project.org/web/packages/doMPI/vignettes/doMPI.pdf&lt;/a&gt; (the first listed host will operate as the R master program in a master/slave configuration).&lt;/p&gt;
&lt;p&gt;Assume that our four host computers are listed in a comma-separated list by the environment variable HOSTS, for instance by&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HOSTS=10.0.0.1,10.0.0.1,10.0.0.2,10.0.0.3,10.0.0.4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then a typical openmpi invocation is (for our four hosts):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LANG=C CHUNKSIZE=10000000 mpirun -wd $(pwd) -x LANG -x CHUNKSIZE -np 5 -host $(HOSTS) singularity run -H $(pwd) variant_pca.img&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace the host list and &lt;code&gt;-np 5&lt;/code&gt; with the number of computers available in your cluster plus one. Or, submit the job using an available cluster job manager like Slurm. See &lt;a href=&#34;https://cran.r-project.org/web/packages/doMPI/vignettes/doMPI.pdf&#34; class=&#34;uri&#34;&gt;https://cran.r-project.org/web/packages/doMPI/vignettes/doMPI.pdf&lt;/a&gt; for more details on using MPI with R.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;example-output&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Example output&lt;/h3&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;p&gt;As with the small example above, we can read the output file and plot the principal components:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;x &amp;lt;- readRDS(&amp;#39;pca.rdata&amp;#39;)
library(lattice)
splom(x$v)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2017-03-27-r-and-singularity_files/figure-html/unnamed-chunk-4-1.png&#34; width=&#34;672&#34; /&gt; 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.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;additional-notes&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Additional Notes&lt;/h3&gt;
&lt;p&gt;The computation uses an R program downloaded from &lt;a href=&#34;https://raw.githubusercontent.com/bwlewis/1000_genomes_examples/master/pca-mpi.R&#34; class=&#34;uri&#34;&gt;https://raw.githubusercontent.com/bwlewis/1000_genomes_examples/master/pca-mpi.R&lt;/a&gt; that we don’t reproduce here. See that file and &lt;a href=&#34;https://github.com/bwlewis/1000_genomes_examples/blob/master/PCA_whole_genome.Rmd&#34; class=&#34;uri&#34;&gt;https://github.com/bwlewis/1000_genomes_examples/blob/master/PCA_whole_genome.Rmd&lt;/a&gt; for additional notes.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2017/03/29/r-and-singularity/&#39;;&lt;/script&gt;
      </description>
    </item>
    
  </channel>
</rss>
