Introduction

Dans cette section, la problématique a été d’étudier les performances de Julia, R et Python dans l’exécution d’une tâche spécifique. La tâche est d’entrainer et de faire une prédiction avec l’algorithme XGBoost. Pour Julia et R le wrapper de la librairie originale C++ est utilisé. Quant à python, on a utilisé la version de scikit-learn.

Cette partie a été assez compliquée. Il a fallu trouver un moyen de tester la vitesse d’exécution de tous les codes suivants. Sur le dataset utilisé en premier lieu (de taille 150), julia était en tête suivie de près par R et Python derrière.

J’ai donc choisi de faire la même opération sur un dataset plus important. Mais le temps pris était très grand en Python, moins grand en Julia et un peu moins en R.

J’ai donc décidé de faire le benchmark de manière séparée sur de multiple datasets de tailles différentes. Cette partie du projet m’a fait découvrir les scripts bash qui permettent de lancer plusieurs programmes et ecrire des commandes dans le shell plus facilement et d’un coup.

On a donc tout d’abord:

  • le script bash qui gère les fichiers pour la reproductibilité
  • la premiere partie du script python qui va créer le dataset
  • le reste qui va consister a produite toute la mécanique du xgboost (sépararation du dataset en entrainement/test, gestion des types etc..)

Information système

Le dernier test a été fait avec la configuration suivante:

Code
run(`neofetch`)
             .',;::::;,'.
         .';:cccccccccccc:;,.
      .;cccccccccccccccccccccc;.
    .:cccccccccccccccccccccccccc:.
  .;ccccccccccccc;.:dddl:.;ccccccc;.
 .:ccccccccccccc;OWMKOOXMWd;ccccccc:.
.:ccccccccccccc;KMMc;cc;xMMc:ccccccc:.
,cccccccccccccc;MMM.;cc;;WW::cccccccc,
:cccccccccccccc;MMM.;cccccccccccccccc:
:ccccccc;oxOOOo;MMM0OOk.;cccccccccccc:
cccccc:0MMKxdd:;MMMkddc.;cccccccccccc;
ccccc:XM0';cccc;MMM.;cccccccccccccccc'
ccccc;MMo;ccccc;MMW.;ccccccccccccccc;
ccccc;0MNc.ccc.xMMd:ccccccccccccccc;
cccccc;dNMWXXXWM0::cccccccccccccc:,
cccccccc;.:odl:.;cccccccccccccc:,.
:cccccccccccccccccccccccccccc:'.
.:cccccccccccccccccccccc:;,..
  '::cccccccccccccc::;,.
99DArthings-msi@fedora 
------------------- 
OS: Fedora Linux 37 (Workstation Edition) x86_64 
Host: GF63 8RD REV:1.0 
Kernel: 6.0.10-300.fc37.x86_64 
Uptime: 1 hour, 38 mins 
Packages: 3029 (rpm), 53 (flatpak) 
Shell: bash 5.2.9 
Resolution: 1920x1080 
DE: GNOME 43.1 
WM: Mutter 
WM Theme: Adwaita 
Theme: Adwaita [GTK2/3] 
Icons: Adwaita [GTK2/3] 
CPU: Intel i5-8300H (8) @ 4.000GHz 
GPU: Intel CoffeeLake-H GT2 [UHD Graphics 630] 
GPU: NVIDIA GeForce GTX 1050 Ti Max-Q 
Memory: 3655MiB / 7789MiB 

                        
                        

Process(`neofetch`, ProcessExited(0))

Script bash

#!/bin/bash

julia_file=./julia/mlj_xgboost.jl
python_file=./python/xgboost_iris.py
r_file=./r/pure_xgboost.R

header="language,t0,t1,taille_dataset"
touch r_duration.csv && echo $header > r_duration.csv
touch python_duration.csv && echo $header > python_duration.csv 
touch julia_duration.csv && echo $header > julia_duration.csv  

head r_duration.csv 
head python_duration.csv 
head julia_duration.csv

for i in {100..1000..100}
do
        echo $i
        python3 $python_file $i
        Rscript $r_file
        julia $julia_file
done

Génération du dataset

On a donc dans le code ci-dessous la génération du dataset. Le code utilise la taille donnée au moment de l’exécution de programme pour contruire un dataset adapté. Ce dataset est ensuite sauvé et utilisé par tous les autres programmes.

n = 100
taille_dataset = int(sys.argv[1]) 

ajout = pd.DataFrame(np.random.rand(4*taille_dataset).reshape(taille_dataset,4),
                     columns = ["sepal lenght", 
                                "sepal width", 
                                "petal length", 
                                "petal width"]
                     )
targ = np.random.choice(["versicolor", "setosa", "virginica"],taille_dataset)
ajout["target"] = targ
ajout.to_csv("iris_big.csv")

MLJ

Julia 1.8.2 a été utilisé.

Ici on a utilisé les fonctionalités de la librairie MLJ qui permettent de gérer toutes les manipulations de partition de bases de dataframe avec la séparation entrainement/test.

Tous les modèles ont été configurés avec les mêmes paramètres. A savoir une profondeur maximale de 6, et 100 étapes de boosting.

[...]
function simulate!(l0, l1, n, X, y)
        t0, t1 = l0, l1
        for i in 1:n
            # println("Entree boucle $i eme fois")

            t0[i] = time()
            boost = Boost(
                          max_depth = 6,
                          num_round = 100
                    )
            mach = machine(boost, X,y)
            fit!(mach, rows=train, verbosity = 0)
            yhat = MLJ.predict(mach, X[test,:])
            t1[i] = time()
        end
end


t0 = zeros(n) 
t1 = zeros(n)
simulate!(t0, t1, n, X, y)
[...]

J’ai essayé de mettre la partie du code qui simule les entrainements/prédiction dans une fonction ce qui permettrait d’améliorer les performances du programme.