Docker et AWS pour l’industrialisation et l’archivage de modèles d’apprentissage 2/2 (Version GPU)

Dans un précédent article, nous avons montré comment utiliser Docker avec AWS (EC2 & S3) pour industrialiser vos modèles et archiver vos expérimentations. Le machine learning se repose aujourd’hui de plus en plus sur les architectures avec GPU.

En effet, ce dernier fait grand usage d’opérations matricielles qui peuvent être parallélisées. Les GPU ont été développés pour manipuler des grandes matrices (représentant des pixels) en parallèle, offrant aux algorithmes de machine learning beaucoup de puissance de calcul.

Ce tutoriel va vous montrer comment industrialiser vos applications et archiver vos expérimentations avec Docker et AWS (EC2 et S3) sur une architecture avec GPU.

Gains de performance

La figure ci-dessus illustre l’amélioration des performances liées à l’utilisation de GPU pour XGBOOST. Ces expérimentations ont été effectuées sur 2500 instances de XGBoost. Dans chacune de ces instances, on crée un modèle avec 600 arbres. Les paramètres du modèle (ex: taux d’apprentissage, taille minimale de l’arbre, etc.) sont variés d’une instance à l’autre afin de sélectionner les meilleurs paramètres. Ainsi, ces expérimentations fonctionnent comme un GridSearch sur SKlearn avec la différence qu’un algorithme génétique contrôle la sélection des meilleurs paramètres (algo gen: 5 générations, 50 individus dans la population, 50% de croisement, 10% de mutation). Leur objectif est de paramétrer XGBoost pour un dataset de prédiction de volumes de ventes de certains produits (prédiction de séries temporelles).

Les premières expérimentations ont été effectuées sur un serveur EC2 d’Amazon avec 4 GPU et 30 Gigas de RAM. Les secondes expérimentations ont été effectuées sur un serveur EC2 avec 4 CPU et 10.5 gigas de RAM. Le dataset étant à faible dimensions (série temporelle à 10 attributs), La RAM à peu d’effet sur les temps d’exécution.

Nous pouvons voir que le temps d’exécution sur le GPU est presque 6 fois inférieur au temps d’exécution sur le CPU. Ce gain en temps de calcul est bien inférieur aux gains enregistrés dans le cadre du Deep Learning, qui profite grandement de la parallélisation des calculs matriciels. Il reste néanmoins non négligeable.

Automatiser avec Docker : pourquoi ?

Différentes bibliothèques de machine learning offrent à leurs utilisateurs la possibilité de compiler leurs algorithmes sur des environnement applicatifs permettant de distribuer des calculs sur GPU (ex: CUDA).

Contrairement aux installations sur architecture avec CPU, les installations sur les architectures avec GPU nécessitent souvent plus de configuration et des compilations à partir de fichiers sources.

Ainsi, éviter de mettre en place l’environnement applicatif sur GPU pour chaque déploiement peut nous faire gagner beaucoup de temps. C’est ici que Docker entre en jeu, car il est capable d’automatiser le déploiement d’environnements applicatifs (article 1/2).

Docker offre plusieurs autres avantages concernant le déploiement et l’archivage d’applications sur GPU. Il permet de confiner des applications dans des “prisons applicatives”, les empêchant de se perturber mutuellement. Cela offre beaucoup de stabilité aux applications en production.

NVIDIA a permis la création d’une version docker pour GPU qui utilise ses drivers sans que cela nécessite de les installer sur chaque image. Ainsi, chaque machine ayant NVIDIA CUDA (Compute unified device architecture) permet d’héberger des images de docker pour GPU en communiquant les drivers .

Avant cette adaptation, il était nécessaire d’installer les driver NVIDIA sur les images docker. Ainsi, une image ne pouvait s’exécuter que sur des machines ayant des drivers identiques.

NVIDIA-docker permet de remédier à cela en utilisant une API de haut niveau qui donne accès aux fonctionnalités des drivers bas niveau.

Installation de docker pour GPU

L’installation de NVIDIA-docker nécessitera d’abord d’installer un framework qui standardise la communication avec les drivers GPU (en plus d’effectuer des calculs scientifiques). Ce dernier se dénomme CUDA (anciennement Compute Unified Device Architecture).

Installation de CUDA

La première étape est d’installer CUDA sur votre machine (si ce n’est pas déjà fait).

  • Les GPU sur AWS ont les drivers CUDA déjà pré-installés.
  • Si vous utilisez votre propre machine, les installations peuvent varier selon votre système d’exploitation et votre carte graphique. Des instructions détaillées pour son installations sont disponibles sur leur site officiel :
    (https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html)

Installation de nvidia-docker

1 la première étape de cette installation est d’ajouter des dépendances de NVIDIA CUDA qui permettent la communication entre CUDA et docker.


curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/ubuntu16.04/amd64/nvidia-docker.list | \
sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update

2 Ensuite, la dernière version de docker-ce doit être installée. Seuls les derniers docker-ce supportent le framework NVIDIA.


# Suppression de docker si installé
sudo apt-get remove docker docker-engine docker.io


# Ajout de la clé GPG de docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -


# Ajout du repo de docker
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable"
sudo apt-get update
sudo apt install docker-ce

3 La dernière étape est d’installer NVIDIA docker et de rebooter docker


sudo apt-get install -y nvidia-docker2
sudo pkill -SIGHUP dockerd

4 Vérification de l’installation
En exécutant la commande ci-dessous, une image construite par NVIDIA détaille l’état des drivers CUDA.


docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi

Le conteneur exécutant cette image devrait imprimer le message suivant :

Création d’une image Docker-NVIDIA

Alors qu’il existe plusieurs images Docker pour GPU sur lesquelles nous pouvons nous reposer, il est parfois nécessaire de créer sa propre image contenant des briques logicielles particulières à partir d’une image source basique.

Des exemples seraient les images docker pour XGBoost sur GPU. Certaines pré installent des driver CUDA, ce qui peut poser plusieurs problèmes de compatibilité. Le mieux serait d’utiliser les driver installés sur chaque machine (comme expliqué dans l’introduction), qui sont adaptés au hardware de cette dernière.

D’autres images font usage d’Anaconda. Ce dernier est déconseillé si l’on souhaite utiliser Sklearn-deap ( par les développeur de Sklearn-deap). Sklearn-deap est un package contenant plusieurs algorithmes, et plus particulièrement, une meta-heuristique permettant de paramétrer des algorithmes. Cette dernière fonctionne comme un GridSearch mais en utilisant un algorithme génétique. Cela évite ainsi d’essayer toutes les combinaisons possibles de paramètres pour un algorithme et réduit le temps nécessaire pour paramétrer un algorithme de manière exponentielle.

Alors que l’inclusion de XGBOOST dans une image qui s’exécute sur un CPU nécessite une ligne de code, son installation sur un GPU nécessite de construire les binaires à partir des fichiers sources.

a La première étape est télécharger les fichier sources de XGBOOST.


git clone --recursive https://github.com/dmlc/xgboost

b Ensuite, nous allons créer un dossier build


mkdir xgboost/build

c La prochaine étape est de créer un répertoire pour votre application

mkdir application

d La troisième étape est de créer un fichier Docker comme pour le tutoriel précédent

Contrairement au tutoriel précédent, nous allons cette fois créer une première image qui nous servira d’image source, au lieu de télécharger une image source existante. Nous ferons appel à cette image dans notre fichier docker.

L’image source nous permet de créer notre image en se basant sur un framework applicatif qui est déjà mis en place. Cela nous évite de tout installer à chaque fois.
On nomme la première image source que nous allons créer nom-utilisateur/env:gpu. Cette image source contiendra notre environnement de développement, et sera la base pour toute nouvelle image que nous allons créer pour une architecture GPU. Ainsi, si nous voulons créer une image pour du Deep Learning ou du Bagging, on fera appel à la même image source utilisée pour le Boosting, simplifiant nos fichiers docker et réduisant le temps nécessaire à l’industrialisation des applications.

Le fichier Docker ci-dessous va permettre de construire notre première image source. Cette image enrichit l’image source de nvidia en la dotant de certains packages incontournables (ex git, make, python, pip) et d’autres packages utiles (ex: cmake).


#Image source de base contenant le framwork CUDA
FROM nvidia/cuda:9.2-devel-centos7

# Environnement
ENV DEBIAN_FRONTEND noninteractive

# Installation de packages de bases et téléchargement de repo.
RUN yum -y install tar unzip wget xz git &&\
yum -y install yum-utils &&\
yum -y install epel-release &&\
yum -y install https://centos7.iuscommunity.org/ius-release.rpm &&\
#yum -y update &&\
yum -y install centos-release-scl &&\
yum -y update &&\
yum -y groupinstall development &&\
yum -y install devtoolset-7 &&\

#Installation de cmake. Ce dernier sera utilisé pour compiler des packages (ex XGBOOST)
wget -nv -nc https://cmake.org/files/v3.14/cmake-3.14.0-Linux-x86_64.sh --no-check-certificate &&\
bash cmake-3.14.0-Linux-x86_64.sh --skip-license --prefix=/usr &&\

yum -y update &&\

#Installation python
yum -y install python36u &&\
yum -y install python36u-libs &&\
yum -y install python36u-devel &&\
yum -y install python36u-pip &&\
ln -s /usr/bin/python3.6 /usr/bin/python3 &&\
ln -s /usr/local/bin/pip3 /usr/bin/pip3

ENV PATH="/usr/bin/python3.6:${PATH}"
ENV PATH="/usr/bin/python3.6/bin:${PATH}"

Nous allons maintenant compiler notre image avec docker build :
docker build -t nom-utilisateur/env:gpu

Ensuite, nous allons créer une image pour XGBoost qui se base sur l’image source pour GPU.
Le fichier docker ci-dessous décrit l’image créée.


#On fait appel à l’image source que nous avons créée
FROM ojaafor/env:gpu

#Installation de packages (possible grâce à l’image source)
RUN pip3.6 install pandas &&\
pip3.6 install numpy &&\
pip3.6 install sklearn-deap
#Téléchargement de xgboost (possible grâce à l’image source)
RUN git clone --recursive https://github.com/dmlc/xgboost
RUN mkdir xgboost/build
WORKDIR "/xgboost/build"

#Compilation de XGBoost (possible grâce à l’image source)
RUN cmake .. -DUSE_CUDA=ON &&\
make -j4
#Ajout du dossier de votre application
ADD ./application /application
#Installation de XGBoost
WORKDIR "/xgboost/python-package"
RUN python3 setup.py install

#Lancement de votre application
WORKDIR "./application"
CMD ["python3", "./app.py"]

e Ensuite, il faut compiler l’image docker avec


docker build -t identifiant-du-compte/nom-de-l-image:tag-optionnel

NB: Quand vous exécutez votre image, n’oubliez pas de spécifier à Docker que l’environnement d’exécution est CUDA. En effet, même si vous installez nvidia-docker, l’environnement d’exécution par défaut est le CPU.


sudo docker run --runtime=nvidia identifiant-du-compte/nom-de-l-image:tag-optionnel

Omar JAAFOR, Senior Data Scientist @Novagen