H
IGH-P
ERFORMANCE ANDP
ARALLELC
OMPUTING WITHR
Julie Scholler
M Éc E n
R est un langage de programmation
R très utilisé
• pour les statistiques et les graphiques
• mais aussi langage de programmation complet, adapté à la programmation scientique
• langage interprété dont certaines fonctions de bases sont compilées
Langage de programmation
mauvaise utilisation + méconnaissance de ses spécicités
⇒ augmentation (forte) du temps de calcul
Création de fonction
nomFonction<-function(argument1,argument2){
instructions utilisant des arguments return(sortie de la fonction) }
Exemple de la somme des éléments de chaque ligne d'une matrice
myRowSums<-function(mat){
sums<-rep(0,nrow(mat)) for (i in 1:nrow(mat))
for (j in 1:ncol(mat))
sums[i]<-sums[i]+mat[i,j]
} sums
myRowSums(matrix(1:6,2,3))
## [1] 9 12
Améliorer les performance de R
Points à optimiser
• gestion de la mémoire
• vitesse de calul Actions
• mémoire : nettoyer la mémoire rm(list=ls()), utilisation de formats adaptés
• vitesse de calul : utilisation de fonctions vectorisées, utilisation intelligente des boucles, paralléliser le calcul
Vectorisation ou fonctions en langages compilés
• Fonctions déjà existantes : %*%, colSums, colMeans
• Famille *apply
• Famille **ply du package plyr (parallélisation possible)
apply(iris,2,max)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## "7.9" "4.4" "6.9" "2.5"
## Species
## "virginica"
ddply(iris,.(Species),summarise, mean=mean(Sepal.Length))
## Species mean
## 1 setosa 5.006
## 2 versicolor 5.936
## 3 virginica 6.588
Comparaison de l'ecacité de diérentes fonctions
mat<-matrix(rnorm(1e4*1e4),1e4,1e4) temps<-c(system.time(myRowSums(mat))[3],
system.time(apply(mat,1,sum))[3], system.time(rowSums(mat))[3])
names(temps)<-c("myRowSums","apply&sum","rowSums") temps
## myRowSums apply&sum rowSums
## 22.75 4.18 0.44
rm(mat)
Boucles en langage interprété
Quand les utiliser
• quand le code est dicile à vectoriser
• quand le code vectorisé utilise beaucoup de mémoire
• quand il n'existe pas de fonction en langage compilé permettant de faire ce que l'on souhaite
Règles de bonne utilisation
• initialiser les nouveaux objets à leur taille dénitive avant la boucle
• ne pas faire dans la boucle ce qui peut se faire dehors
# Sans initialisation initss <- function(n){
a <- NULL; for(i in 1:n) {a <- c(a,i^2)} }
# Avec initialisation init1 <- function(n){
a <- numeric(n);for(i in 1:n) {a[i] <- i^2} }
# Vectoriellement
init2 <- function(n){ a <- (1:n)^2 } n<-500
microbenchmark(initss(n),init1(n),init2(n),times=5)
## Unit: microseconds
## expr min lq mean median uq
## initss(n) 1095.779 1104.836 2143.741 1115.702 1164.604
## init1(n) 61.582 62.185 1098.073 62.789 64.600
## init2(n) 3.623 4.830 666.644 4.830 36.224
## max neval
## 6237.786 5
## 5239.210 5
## 3283.713 5
# multiplication à l'intérieur multi1 <- function(n){
a <- numeric(n);for(i in 1:n) {a[i] <- i^2*2} }
# multiplication à l'extérieur multi2 <- function(n){
a <- numeric(n);for(i in 1:n) {a[i] <- i^2}; a*2 }
# Vectoriellement
multi3 <- function(n){ a <- 2*(1:n)^2 } n<-500
microbenchmark(multi1(n),multi2(n),multi3(n),times=5)
## Unit: microseconds
## expr min lq mean median uq max
## multi1(n) 72.449 74.864 1301.1696 74.864 76.675 6206.996
## multi2(n) 64.601 66.412 1310.2258 67.015 68.223 6284.878
## multi3(n) 4.227 4.227 865.1526 6.642 22.339 4288.328
## neval
## 5
## 5
## 5
Parallélisation
• Jusqu'en 2005, la fréquence des processeurs augmentait jusqu'à 4GHz.
• Maintenant entre 3 et 4 GHz, mais plusieurs unités de calculs par processeurs.
• Il faut repenser le code de façon parallèle.
the free lunch is over
Parallélisation
library(parallel)
detectCores(logical=FALSE)
## [1] 16
detectCores(logical=TRUE)
## [1] 16
cl <- makeCluster(3)
Exemple simple avec multicore
Package multicore non disponible sous Windows Implémentation comme apply
mclapply(...,mc.cores=....)
Avec DoParallel et foreach
#sans parallélisation
foreach( indices , .combine=.... , .packages=c(...)) %do% { instructions
}
#avec parallélisation mais il faut créer un cluster en amont foreach( indices , .combine=.... ,
.packages=c(...)) %dopar% { instructions
}
Possibilités pour .combine : c, +,*, cbind, etc.
library(doParallel)
registerDoParallel(cores=4)
direct<-system.time(randomForest(Purchase~.,data=OJ,
method="class",ntree=25000) )[3]
paparallel <- system.time({
r <- foreach(1:50, .combine=combine,
.packages=c("randomForest","ISLR")) %do% { randomForest(Purchase~.,data=OJ,method="class",ntree=500) } })[3]
parallel <- system.time({
r <- foreach(1:50, .combine=combine,
.packages=c("randomForest","ISLR")) %dopar% { randomForest(Purchase~.,data=OJ,method="class",ntree=500) } })[3]
c(direct,paparallel,parallel)
Résultats 1 : direct=62s, paparallel=45s, parallel=23s Résultats 2 : direct=28s, paparallel=28s, parallel=9s
Commandes optimisées pour la gestion des données
• data.table : gestion optimisée des data frame en mémoire vive
• ff et ffbase : gestion de très grandes bases de données hors mémoire vive
• bigmemory : gestion de grandes bases de données sous le format big.matrix
Commandes optimisées pour le machine learning
• fastclust : classication hiérarchique, remplace la commande hclust de base
• speedlm et speedglm : régression optimisée pour des données en mémoire vive
• biganalytics : contenant biglm pour la régression,
bigkmeans pour la classication non supervisée, bigpca pour l'analyse factorielle, données de type big.matrix
• caret
Classication hiérarchique
library(MASS);library(FactoMineR)
c1<-system.time(ch<-HCPC(Boston,nb.clust=-1))[3]
library(fastcluster)
##
## Attaching package: 'fastcluster'
## The following object is masked from 'package:stats':
#### hclust
c2<-system.time(ch<-HCPC(Boston,nb.clust=-1))[3]
c(c1,c2)
## elapsed elapsed
## 1.72 2.63
Résultat : c=1.81s, c2=0.64s
Régression linéaire généralisé
flights <- read.table("flights14.csv",sep=",",header=TRUE) t1<-system.time(regl1<-lm(arr_delay~year+distance+dep_time,
data=flights))[3]
t2<-system.time(regl2<-glm(arr_delay~year+distance+dep_time, data=flights))[3]
t3<-system.time(regl3<-biglm(arr_delay~year+distance+dep_time, data=flights))[3]
t4<-system.time(regl4<-biglm.big.matrix(arr_delay~
year+distance+dep_time,data=flights))[3]
t5<-system.time(regl5<-speedlm(arr_delay~year+distance+dep_time, data=flights))[3]
t6<-system.time(regl6<-speedglm(arr_delay~year+distance+dep_time, data=flights))[3]
temps<-c(t1,t2,t3,t4,t5,t6)
names(temps)<-c("lm","glm","biglm","big.mat","speedlm","speedglm") temps
## lm glm biglm big.mat speedlm speedglm
## 0.45 0.68 0.42 0.53 0.25 0.40
Bootstrap avec caret
library(caret) library(ISLR)
library(randomForest) library(doParallel)
#50 bootstrap
control<-trainControl(method="boot",number=50) registerDoParallel(cores=1)
system.time(train(Purchase~.,data=OJ ,method="rf", trControl=control))[3]
registerDoParallel(cores=4)
system.time(train(Purchase~.,data=OJ ,method="rf", trControl=control))[3]
stopImplicitCluster()
Résultats : 1 c÷ur=170s, 4 c÷urs=85s Résultats bis : 1 c÷ur=94s, 4 c÷urs=39s
Validation croisée avec caret
#20 CV
control<-trainControl(method="cv",number=20) registerDoParallel(cores=1)
system.time(train(Purchase~.,data=OJ ,method="rf", trControl=control))[3]
registerDoParallel(cores=4)
system.time(train(Purchase~.,data=OJ ,method="rf", trControl=control))[3]
stopImplicitCluster()
Résultats 10 CV : 1 c÷ur=35s, 4 c÷urs=34s Résultats 20 CV : 1 c÷ur=67s, 4 c÷urs=44s
Résultats LOOCV : 4 c÷urs=697s, 6 c÷urs=560s, 8 c÷urs=477s
Quand R et un ordinateur seul ne susent plus
Données et Calcul Distribués
• MapReduce
• Hadoop Apache
• Spark Apache
• Flink Apache
MapReduce
• paradigme/méthode pour le développement informatique
• pour le calcul parallèle et distribué
• initié par Google
• opérations : split, map, shue, reduce Exemple
Analyse de sentiment de tweets
Hadoop
• framework libre et open source en Java
• pour les applications distribuées
• créé par Doug Cutting chez Yahoo puis fondation Apache Écosysteme
Modules de base
• stockage : HDFS
• traitement : MapReduce Ensemble de logiciels
• Apache Pig
• Apache Hive, etc.
Hadoop et R
• on peut faire tourner du code R sur un cluster Hadoop
• on peut utiliser des packages pour que R parle avec Hadoop comme RHipe
Spark
• framework libre et open source en Java
• pour les applications distribuées
• développé à l'universite de Berkeley
• maintenant produit de la fondation Apache
• plus ecace que la MapReduce d'Hadoop
• ne dispose pas de système de gestion de chier
• dispose d'une libraire d'algorithme pour le machine learning Avec R
• package sparklyr de l'écosystème tidyverse