Speed Up With Microsoft

People use R for lots of reasons: “It’s great for the models I need”, “I like the functional approach”, “It’s the tool I’m most comfortable with”.

People don’t use R for these reasons: “I have a favourite processor core, I don’t want to use the others”, “I love how my memory needs to fit all my data”.

What if I told you that you didn’t need to worry about that any more?

Multi-threaded R

Microsoft have their own version of R called Microsoft R Client. It has a bunch of high-tech, whiz-bang features, but we’re going to focus on one: multi-threading calculations. Vanilla R is single threaded.This means any calculations are done sequentially, in order, one at a time. However, this isn’t using the ability of most modern, domestic laptops. To get setup with Microsoft R Client, follow the install instructions. Once you’ve got Microsoft R Client installed, you will need to make sure it’s the version of R that is active in your session. If you are using RStudio this is easy to do by going to Tools > Global Options > General > R Version.

You will probably be asked to Restart R Studio, so close it and open back up, then we can run the code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
R version 3.4.3 (2017-11-30) -- "Kite-Eating Tree"
Copyright (C) 2017 The R Foundation for Statistical Computing
Platform: x86_64-w64-mingw32/x64 (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

Microsoft R Open 3.4.3
The enhanced R distribution from Microsoft
Microsoft packages Copyright (C) 2018 Microsoft

Loading Microsoft R Client packages, version 3.4.3.0097. 
Microsoft R Client limits some functions to available memory.
See: https://go.microsoft.com/fwlink/?linkid=799476 for information
about additional features.

Type 'readme()' for release notes, privacy() for privacy policy, or
'RevoLicense()' for licensing information.

Using the Intel MKL for parallel mathematical computing(using 2 cores).
Default CRAN mirror snapshot taken on 2018-01-01.
See: https://mran.microsoft.com/.

This message will pop up, and it’s worth noting as it’s got some information in it that you might need to think about:

It’s worth noting that right now Microsoft r Client is lagging behind the current R version, and is based on version 3.4 of R, not 3.5. This will mean your default package libraries will not be shared between the installations if you are running R 3.5. It’s using a snapshot of CRAN called MRAN to source packages by default. 90% of the time it will operate just as you expect, but because it takes a ‘snapshot’ of packages, newer features and changes that have hit CRAN may not be in the version of the package you are grabbing.

RevoScaleR and probably the ggplot2 and dplyr packages will likely be installed for you already as default in Microsoft R Client. The other two you will probably have to install yourself.

1
2
3
4
5
6
7
8
knitr::opts_chunk$set(echo = TRUE)
library(microbenchmark)
library(RevoScaleR)
library(ggplot2)
library(lockeutils)
theme_set(theme_ld() + theme(axis.title.x = element_text(vjust = -1)))
library(dplyr)

Test Data

Here we make a set of example data, 3 data frame of random numbers with various ‘normal’ distributions. The data frames are of different lengths: 500,000 , 1,000,000 and 5,000,000.

1
2
3
4
5
6
7
8
9
10
11
12
13
set.seed(9000)
sample_df = function(n){
 data.frame(
 col_1 = c(rnorm(n, mean = 11, sd = 0.5)), 
 col_2 = c(rnorm(n, mean = 6, sd = 1)), 
 col_3 = c(rnorm(n, mean = 3, sd = 0.75))
 )
}

df_500k <- sample_df(500000)
df_1m <- sample_df(1000000)
df_5m <- sample_df(5000000)

Benchmarking

Running benchmarks in R is easy with the microbenchmark package. The package tries to be as accurate as possible in measuring the time for each of it’s runs, and also allows you to easily compare different approaches and specify the amount of repeats. I’ve decided to test each of the 3 data sets in each of 2 different linear modelling functions, giving 6 different groups of results. Each group will be run 10 times for a total set of 60 runs.

1
2
3
4
5
6
7
8
9
10
res <- microbenchmark(
 lm_50k = lm(col_1 ~ col_2 + col_3, data = df_500k),
 rxLM_50k = rxLinMod(col_1 ~ col_2 + col_3, data = df_500k, reportProgress = 0),
 lm_1m = lm(col_1 ~ col_2 + col_3, data = df_1m),
 rxLM_1m = rxLinMod(col_1 ~ col_2 + col_3, data = df_1m, reportProgress = 0),
 lm_5m = lm(col_1 ~ col_2 + col_3, data = df_5m),
 rxLM_5m = rxLinMod(col_1 ~ col_2 + col_3, data = df_5m, reportProgress = 0),
 times = 10
 )

Results

The res object is of class microbenchmark, and has a plotting method that can be used via ggplot2::autoplot().

1
2
3
4
5
autoplot(res) + 
 labs(title = "Violin plot of model run durations", 
 subtitle = "`rxLinMod()` vs `lm()`",
 caption = "Microsoft R Client 3.4.3, 2 cores")

In each of these tests, we can see that the RevoScaleR::rxLinMod() functions outperforms the base lm() by a large margin. Note the log scale for Time [milliseconds]!

1
2
knitr::kable(summary(res))

lm_50k 1106.2070 1141.3168 1740.0966 1340.5601 1474.8239 4679.1277 10
rxLM_50k 115.3501 120.7544 137.2811 136.9788 147.7357 171.9592 10
lm_1m 2203.7005 2890.8738 3018.6052 3072.3086 3340.6342 3934.8914 10
rxLM_1m 184.8220 199.1018 223.0184 214.2320 223.2292 307.1239 10
lm_5m 14897.7473 15450.7170 16295.3558 16183.4236 16720.8177 18837.9140 10
rxLM_5m 704.0234 805.8069 1108.2574 965.9696 1044.1400 2084.2737 10

But how?

It does this because the Microsoft R Client uses Intel MKL for parallel mathematical computing. This allows the RevoScaleR package to implement a ‘parallelised algorithm’ to solve the linear regression using the BLAS and LAPACK FORTRAN libraries. More technical details are avilable in the docs.

What about the out of memory part?

RevoScaleR and Microsoft R Client can help with that, though the solution requires a little more involvement. The short version is that it can leverage distributed data sources as a backend, such as spark, hadoop and sqlserver. this allows the data to be spread across many compute nodes that are managed by software called ‘Microsoft Machine Learning Server`. This is a good overview of the ideas on the main site, which also holds all the documentation.

Would you like to know more?

Locke Data have are developing course going into depth with this technology from an R context and are releasing it at the end of October. Please come and join us (virtually!) for some hands-on learning and detailed tutorials.