R/fr: Difference between revisions
(Created page with "La commande R <tt>system()</tt> permet d'exécuter des commandes dans l'environnement actif, à l'intérieur de R; ceci risque de causer des problèmes sur les grappes de Calc...") |
(Updating to match new version of source page) |
||
Line 111: | Line 111: | ||
==Appels système== | ==Appels système== | ||
<div class="mw-translate-fuzzy"> | |||
La commande R <tt>system()</tt> permet d'exécuter des commandes dans l'environnement actif, à l'intérieur de R; ceci risque de causer des problèmes sur les grappes de Calcul Canada parce que R donne une valeur incorrecte à la variable d'environnement <tt>LD_LIBRARY_PATH</tt>. Utilisez plutôt la syntaxe <tt>system("LD_LIBRARY_PATH=$RSNT_LD_LIBRARY_PATH <my system call>")</tt> dans vos appels système. | La commande R <tt>system()</tt> permet d'exécuter des commandes dans l'environnement actif, à l'intérieur de R; ceci risque de causer des problèmes sur les grappes de Calcul Canada parce que R donne une valeur incorrecte à la variable d'environnement <tt>LD_LIBRARY_PATH</tt>. Utilisez plutôt la syntaxe <tt>system("LD_LIBRARY_PATH=$RSNT_LD_LIBRARY_PATH <my system call>")</tt> dans vos appels système. | ||
</div> | |||
==Parallélisation== | ==Parallélisation== |
Revision as of 21:00, 1 October 2019
R est un outil de calcul statistique et de graphiques. Il s'agit d'un langage de programmation additionné d'un environnement graphique, d'un débogueur, de l'accès à certaines fonctions de système et de la possibilité d'exécuter des scripts.
Même si R n'a pas été développé pour le calcul de haute performance, sa popularité au sein de plusieurs disciplines scientifiques incluant le génie, les mathématiques, la statistique et la bio-informatique, en fait un outil essentiel sur les supercalculateurs dédiés à la recherche académique. Certaines fonctionnalités étant écrites en C, compilées et parallélisées par fils d'exécution, permettent d'atteindre des performances raisonnables sur un seul nœud de calcul. Grâce à la nature modulaire de R, les utilisateurs peuvent personnaliser leur configuration en installant des paquets dans leur répertoire personnel à partir du Comprehensive R Archive Network (CRAN).
Interpréteur
Chargez d'abord un module R. Comme plusieurs versions sont disponibles, consultez la liste en lançant la commande
[name@server ~]$ module spider r
Pour charger un module R particulier, utilisez une variante de la commande
[name@server ~]$ module load r/3.3.3
Pour plus d'information, consultez Utiliser des modules.
Vous pouvez maintenant démarrer l'interpréteur et entrer le code R dans cet environnement.
[name@server ~]$ R
R version 3.3.3 (2017-03-06) -- "Another Canoe"
Copyright (C) 2017 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (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.
Natural language support but running in an English locale
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.
> values <- c(3,5,7,9)
> values[0]
[1] 3
> q()
Pour exécuter des scripts R, utilisez la commande Rscript suivie du fichier contenant les commandes R :
[name@server ~]$ Rscript computation.R
Cette commande passera automatiquement les options appropriées pour un traitement en lot, soit --slave et --no-restore à l'interpréteur R. Ces options empêcheront la création de fichiers d'espace de travail inutiles avec --no-save lors d'un traitement en lot.
Les calculs d'une durée de plus de deux ou trois minutes ne devraient pas être exécutés par un nœud de calcul, mais être soumis à l'ordonnanceur.
Voici un exemple de script simple :
#!/bin/bash
#SBATCH --account=def-someacct # replace this with your own account
#SBATCH --mem-per-cpu=2000M # memory; default unit is megabytes
#SBATCH --time=0-00:15 # time (DD-HH:MM)
module load r/3.3.3 # Adjust version and add the gcc module used for installing packages.
Rscript computation.R
Pour plus d'information, consultez Exécuter des tâches.
Installation des paquets R
install.packages()
Pour installer des paquets de CRAN, vous pouvez utiliser la commande install.packages dans une session R interactive opérant sur le nœud de connexion. Comme plusieurs paquets R sont développés avec la famille de compilateurs GNU nous recommandons de charger un module gcc avant d'installer un paquet R. Utilisez la même version de gcc pour tous les paquets que vous installez.
[name@server ~]$ module load gcc
Par exemple, pour installer le paquet sp qui offre des classes et des méthodes pour les données spatiales, utilisez cette commande sur un nœud de connexion.
[name@server ~]$ R
[...]
> install.packages("sp")
Lorsque R vous le demande, sélectionnez un miroir pour le téléchargement. Idéalement, ce miroir sera géographiquement proche de la grappe que vous utilisez.
Avant l'installation, certains paquets requièrent la définition de la variable d'environnement TMPDIR.
Dépendances
Certains paquets utilisent des bibliothèques qui sont déjà installées sur nos grappes. Si la bibliothèque se trouve dans la liste des logiciels disponibles, chargez le module approprié avant d'installer le paquet.
Par exemple, le paquet rgdal
utilise la bibliothèque gdal
. En lançant la commande module spider gdal/2.2.1
nous voyons que les modules nixpkgs
et gcc
sont requis. Si vous avez chargé gcc
comme indiqué plus haut, ces deux modules devraient déjà être chargés. Vérifiez ceci avec la commande
[name@server ~]$ module list
Si l'installation d'un paquet échoue, portez attention au message d'erreur qui pourrait indiquer d'autres modules qui seraient requis. Pour plus d'information sur les commandes de module
, consultez Utiliser des modules.
Téléchargement de paquets
Si vous cherchez à installer un paquet que vous avez téléchargé, c'est-à-dire que vous n'avez pas utilisé install.packages()
, vous pouvez l'installer comme suit. Par exemple, avec le paquet archive_package.tgz, vous exécuteriez la commande suivante dans l'interpréteur (shell) :
[name@server ~]$ R CMD INSTALL -l 'path for your local (home) R library' archive_package.tgz
Appels système
La commande R system() permet d'exécuter des commandes dans l'environnement actif, à l'intérieur de R; ceci risque de causer des problèmes sur les grappes de Calcul Canada parce que R donne une valeur incorrecte à la variable d'environnement LD_LIBRARY_PATH. Utilisez plutôt la syntaxe system("LD_LIBRARY_PATH=$RSNT_LD_LIBRARY_PATH <my system call>") dans vos appels système.
Parallélisation
Si les processeurs des grappes de Calcul Canada sont on ne peut plus ordinaires, ce qui rend ces supercalculateurs intéressants, c'est qu'ils offrent des milliers de CPU sur un réseau très performant. Pour profiter de cet avantage, vous devez utiliser la programmation parallèle. Cependant, avant d'allouer beaucoup de temps et d'effort à paralléliser votre code R, assurez-vous que votre implémentation série est aussi efficiente que possible. Comme dans tout langage interprété, d'importants goulots d'étranglement (bottlenecks) sont causés par les boucles et particulièrement les boucles imbriquées, ce qui a un impact sur la performance. Lorsque possible, essayez d'utiliser les fonctions vectorielles et les autres éléments plus fonctionnels comme la famille des fonctions apply et la fonction ifelse. Vous obtiendrez souvent un gain de performance en éliminant une boucle plutôt que de paralléliser son exécution avec plusieurs cœurs CPU.
La page CRAN Task View on High-Performance and Parallel Computing with R mentionne un grand nombre de paquets pouvant être utilisés avec R pour la programmation parallèle. Nous décrivons ci-dessous deux méthodes de parallélisation qui sont possibles avec les grappes de Calcul Canada.
Terminologie : Dans la documentation de Calcul Canada, les termes nœud et hôte sont quelquefois employés pour désigner un ordinateur distinct; un regroupement de nœuds ou d'hôtes constitue une grappe.
Par contre, dans la documentation pour R, le terme nœud désigne souvent un processus de travail (worker process); un regroupement de ces processus constitue une grappe. Prenons comme exemple la citation suivante : « Following snow, a pool of worker processes listening via sockets for commands from the master is called a 'cluster' of nodes. »[1]
.
Rmpi
Installation
La procédure suivante installe Rmpi, une interface (wrapper) pour les routines MPI qui permet d'exécuter R en parallèle.
1. Voyez les modules R disponibles avec la commande
module spider r
2. Sélectionnez la version et chargez le module OpenMPI approprié. Dans notre exemple, la version 1.10.7 est utilisée, pour que les processus s'exécutent correctement puisque le module par défaut 2.1.1 présente certains problèmes.
module load r/3.4.0
module load openmpi/1.10.7
3. Téléchargez la dernière version de Rmpi en remplaçant le numéro de la version selon le cas.
wget https://cran.r-project.org/src/contrib/Rmpi_0.6-6.tar.gz
4. Indiquez le répertoire dans lequel vous voulez copier les fichiers; vous devez avoir une permission d'écriture pour ce répertoire. Le nom du répertoire peut être modifié.
mkdir -p ~/local/R_libs/
export R_LIBS=~/local/R_libs/
5. Lancez la commande d'installation.
R CMD INSTALL --configure-args="--with-Rmpi-include=$EBROOTOPENMPI/include --with-Rmpi-libpath=$EBROOTOPENMPI/lib --with-Rmpi-type='OPENMPI' " Rmpi_0.6-6.tar.gz
Portez attention au message d'erreur qui s'affiche quand l'installation d'un paquet échoue; il pourrait indiquer d'autres modules qui seraient nécessaires.
Exécution
1. Placez le code R dans un fichier script, ici le fichier test.R.
#Tell all slaves to return a message identifying themselves.
library("Rmpi")
sprintf("TEST mpi.universe.size() = %i", mpi.universe.size())
ns <- mpi.universe.size() - 1
sprintf("TEST attempt to spawn %i slaves", ns)
mpi.spawn.Rslaves(nslaves=ns)
mpi.remote.exec(paste("I am",mpi.comm.rank(),"of",mpi.comm.size()))
mpi.remote.exec(paste(mpi.comm.get.parent()))
#Send execution commands to the slaves
x<-5
#These would all be pretty correlated one would think
x<-mpi.remote.exec(rnorm,x)
length(x)
x
mpi.close.Rslaves()
mpi.quit()
2. Copiez ce qui suit dans le script job.sh.
#!/bin/bash
#SBATCH --account=def-someacct # replace this with your own account
#SBATCH --ntasks=5 # number of MPI processes
#SBATCH --mem-per-cpu=2048M # memory; default unit is megabytes
#SBATCH --time=0-00:15 # time (DD-HH:MM)
module load r/3.4.0
module load openmpi/1.10.7
export R_LIBS=~/local/R_libs/
mpirun -np 1 R CMD BATCH test.R test.txt
3. Soumettez la tâche.
sbatch job.sh
Pour plus d'information sur comment soumettre des tâches, consultez Exécuter des tâches.
doParallel et foreach
Utilisation
Foreach peut être vu comme une interface unifiée pour tous les systèmes dorsaux (backends) comme doMC, doMPI, doParallel, doRedis, etc. et fonctionne sur toutes les plateformes pourvu que le système dorsal soit fonctionnel. doParallel agit comme interface entre foreach et le paquet parallèle et peut être chargé seul. Certains problèmes surviennent avec foreach lors de l'exécution d'un très grand nombre de très petites tâches. Notez que l'exemple simple qui suit n'utilise pas l'appel foreach() de façon optimale.
Enregistrez le système dorsal en lui indiquant le nombre de cœurs disponibles. Si le système dorsal n'est pas enregistré, foreach assume que le nombre de cœurs est 1 et exécute les itérations de façon séquentielle.
De façon générale, la procédure est de :
- charger foreach et le paquet du système dorsal;
- enregistrer le système dorsal;
- appeler foreach() sur la même ligne que %do% (série) ou de l'opérateur %dopar%.
Exécution
1. Placez le code R dans un fichier script, ici le fichier test_foreach.R.
# library(foreach) # optional if using doParallel
library(doParallel) #
# a very simple function
test_func <- function(var1, var2) {
return(var1*var2)
}
# we will iterate over two sets of values, you can modify this to explore the mechanism of foreach
var1.v = c(1:8)
var2.v = seq(0.1, 1, length.out = 8)
# Use the environment variable SLURM_NTASKS to set the number of cores.
# This is for SLURM. Replace SLURM_NTASKS by the proper variable for your system.
# Avoid manually setting a number of cores.
ncores = Sys.getenv("SLURM_NTASKS")
registerDoParallel(cores=ncores)# Shows the number of Parallel Workers to be used
print(ncores) # this how many cores are available, and how many you have requested.
getDoParWorkers()# you can compare with the number of actual workers
# be careful! foreach() and %dopar% must be on the same line!
foreach(var1=var1.v, .combine=rbind) %:% foreach(var2=var2.v, .combine=rbind) %dopar% {test_func(var1=var1, var2=var2)}
Copiez ce qui suit dans le script job_foreach.sh.
#!/bin/bash
#SBATCH --account=def-someacct # replace this with your own account
#SBATCH --ntasks=4 # number of processes
#SBATCH --mem-per-cpu=2048M # memory; default unit is megabytes
#SBATCH --time=0-00:15 # time (DD-HH:MM)
#SBATCH --mail-user=yourname@someplace.com # Send email updates to you or someone else
#SBATCH --mail-type=ALL # send an email in all cases (job started, job ended, job aborted)
module load r/3.4.3
export R_LIBS=~/local/R_libs/
R CMD BATCH --no-save --no-restore test_foreach.R
3. Soumettez la tâche.
[name@server ~]$ sbatch job_foreach.sh
Pour plus d'information sur comment soumettre des tâches, consultez Exécuter des tâches.
doParallel et makeCluster
Utilisation
Il faut enregistrer le système dorsal (backend) en lui donnant le nom des nœuds, multiplié par le nombre voulu de processus. Par exemple, nous créerions une grappe composée des hôtes node1 node1 node2 node2. Le type de grappe PSOCK exécute des commandes par des connexions SSH vers les nœuds.
Exécution
1. Placer le code R dans un fichier script, ici test_makecluster.R.
library(doParallel)
# Create an array from the NODESLIST environnement variable
nodeslist = unlist(strsplit(Sys.getenv("NODESLIST"), split=" "))
# Create the cluster with the nodes name. One process per count of node name.
# nodeslist = node1 node1 node2 node2, means we are starting 2 processes on node1, likewise on node2.
cl = makeCluster(nodeslist, type = "PSOCK")
registerDoParallel(cl)
# Compute (Source : https://cran.r-project.org/web/packages/doParallel/vignettes/gettingstartedParallel.pdf)
x <- iris[which(iris[,5] != "setosa"), c(1,5)]
trials <- 10000
ptime <- system.time({
foreach(icount(trials), .combine=cbind) %dopar%
{
ind <- sample(100, 100, replace=TRUE)
result1 <- glm(x[ind,2]~x[ind,1], family=binomial(logit))
coefficients(result1)
}
})
ptime[3]
# Don't forget to release resources
stopCluster(cl)
2. Copiez les lignes suivantes dans un script pour soumettre la tâche, ici job_makecluster.sh.
#!/bin/bash
#SBATCH --account=def-someacct # replace this with your own account
#SBATCH --ntasks=4 # number of processes
#SBATCH --mem-per-cpu=512M # memory; default unit is megabytes
#SBATCH --time=00:05:00 # time (HH:MM:SS)
module load r/3.5.0
# Export the nodes names.
# If all processes are allocated on the same node, NODESLIST contains : node1 node1 node1 node1
# Cut the domain name and keep only the node name
export NODESLIST=$(echo $(srun hostname | cut -f 1 -d '.'))
R -f test_makecluster.R
3. Soumettez la tâche avec
[name@server ~]$ sbatch job_makecluster.sh
Pour plus d'information sur comment soumettre une tâche, voyez Exécuter des tâches.