groupe-dfo-bbo:projets:nni

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
groupe-dfo-bbo:projets:nni [2020/11/04 13:30]
tribchri [Tester NNI]
groupe-dfo-bbo:projets:nni [2021/05/19 15:39] (Version actuelle)
rochvivi [Tester NNI]
Ligne 7: Ligne 7:
 Cette page Wiki regroupe nos expériences sur l'​installation (NNI, Pytorch, Anaconda) et l'​exécution (GPU, ssh, interface Web usager) de NNI.  Cette page Wiki regroupe nos expériences sur l'​installation (NNI, Pytorch, Anaconda) et l'​exécution (GPU, ssh, interface Web usager) de NNI. 
  
-==== L'​installation est facile ==== +**N'HÉSITEZ PAS À COLLABORER AVEC VOS PROPRES EXPÉRIENCES**
-[[https://​nni.readthedocs.io/​en/​latest/​Tutorial/​InstallationLinux.html#​installation|L'installation]] requiert Python>​=3.6. Il est possible de faire l'​installation directement avec git en utilisant le code source de NNI sur [[https://​github.com/​Microsoft/​nni.git|Github]] et en lançant le script d'​installation : +
  
-''​git clone -b v1.9 https://github.com/Microsoft/​nni.git''​+Une [[[[https://youtu.be/nm7v5Bgx164|vidéo d'un mini-tutoriel]] basé sur un premier essai est disponible.
  
-''​cd ​nni''​+==== L'installation est facile ==== 
 +* [[https://nni.readthedocs.io/​en/​latest/​Tutorial/​InstallationLinux.html#​installation|L'installation]] requiert Python>​=3.6. Il est possible de faire l'​installation directement avec git en utilisant le code source de NNI sur [[https://​github.com/​Microsoft/​nni.git|Github]] et en lançant le script d'installation : 
  
-''​./​install.sh''​+    git clone -b v1.9 https://​github.com/​Microsoft/​nni.git 
 +    cd nni 
 +    ​./​install.sh
  
 ==== Quelques trucs en vrac pour commencer ==== ==== Quelques trucs en vrac pour commencer ====
  
   * [[https://​pytorch.org/​tutorials/​beginner/​deep_learning_60min_blitz.html|Tutoriel pytorch]], un framework pour l'​apprentissage machine (réseaux de neurones et apprentissage profond).   * [[https://​pytorch.org/​tutorials/​beginner/​deep_learning_60min_blitz.html|Tutoriel pytorch]], un framework pour l'​apprentissage machine (réseaux de neurones et apprentissage profond).
-  * Commande (shell) pour examiner l'​utilisation du GPU : ''​nvidia-smi''​ +  * Commande (shell) pour examiner l'​utilisation du GPU : ''​nvidia-smi'';​ En direct: ''​watch -d -n 0.5 nvidia-smi''​ 
-  * Pour accéder aux GPUs sur pandora il faut specifier une variable d'​environnement : ''​export MKL_THREADING_LAYER=GNU ''​+  * Pour accéder aux GPUs sur pandora il faut specifier une variable d'​environnement : ''​export MKL_THREADING_LAYER=GNU''​
   * Pour des évaluations sur un ou plusieurs GPUs, il faut faire : ''​export CUDA_VISIBLE_DEVICES=x,​y,​z''​   * Pour des évaluations sur un ou plusieurs GPUs, il faut faire : ''​export CUDA_VISIBLE_DEVICES=x,​y,​z''​
   * Pour accéder à l'​interface Web de NNI sur une machine distante, on peut utiliser un tunnel ssh (port 8080) vers les machines du GERAD **avec VPN** ([[https://​www.gerad.ca/​aide/​doku.php?​id=fr:​acces-exterieur-vpn|tunnelblick ou openVPN]]) : ''​ssh -L 8080:​localhost:​8080 [email protected]''​.   * Pour accéder à l'​interface Web de NNI sur une machine distante, on peut utiliser un tunnel ssh (port 8080) vers les machines du GERAD **avec VPN** ([[https://​www.gerad.ca/​aide/​doku.php?​id=fr:​acces-exterieur-vpn|tunnelblick ou openVPN]]) : ''​ssh -L 8080:​localhost:​8080 [email protected]''​.
-  * Il est possible de procéder sans VPN : chercher ''​ssh hop tunneling''​ sur le web.+  * Il est possible de procéder sans VPN en faisant un '​saut'​ par ''​ssh.gerad.ca'' ​: chercher ''​ssh hop tunneling''​ sur le web.
   * Pour le VPN, voir le site d'aide du GERAD.   * Pour le VPN, voir le site d'aide du GERAD.
  
Ligne 31: Ligne 33:
   * Avant de lancer l'​optimisation des hyperparamètres,​ on doit disposer de pytorch. Le plus simple est de procéder avec anaconda. Au GERAD, on peut charger anaconda sur nos machines. Par la suite on active l'​environnement conda pytorch-1.6.0 qui est disponible au GERAD:   * Avant de lancer l'​optimisation des hyperparamètres,​ on doit disposer de pytorch. Le plus simple est de procéder avec anaconda. Au GERAD, on peut charger anaconda sur nos machines. Par la suite on active l'​environnement conda pytorch-1.6.0 qui est disponible au GERAD:
  
-'' ​module load anaconda ​''​ +    ​module load anaconda 
- +    conda activate pytorch-1.6.0
-'' ​conda activate pytorch-1.6.0''​+
  
  
   * Avant de lancer l'​optimisation,​ on peut tester une évaluation simple. On se place dans le répertoire ''​nni/​examples/​trials/​cifar10-pytorch''​. On doit modifier le fichier ''​main.py''​ pour spécifier des valeurs des hyperparamètres. Créons un fichier ''​main_test.py''​ à partir de ''​main.py''​ et faisons quelques modifications. On trouve dans le fichier les lignes suivantes :   * Avant de lancer l'​optimisation,​ on peut tester une évaluation simple. On se place dans le répertoire ''​nni/​examples/​trials/​cifar10-pytorch''​. On doit modifier le fichier ''​main.py''​ pour spécifier des valeurs des hyperparamètres. Créons un fichier ''​main_test.py''​ à partir de ''​main.py''​ et faisons quelques modifications. On trouve dans le fichier les lignes suivantes :
  
-'' ​RCV_CONFIG = nni.get_next_parameter() ​''​ +    ​RCV_CONFIG = nni.get_next_parameter() 
- +    #RCV_CONFIG = {'​lr':​ 0.1, '​optimizer':​ '​Adam',​ '​model':'​senet18'​}
-''​#RCV_CONFIG = {'​lr':​ 0.1, '​optimizer':​ '​Adam',​ '​model':'​senet18'​}''​+
  
 On doit commenter (#) la première ligne et dé-commenter la deuxième. Je recommande aussi de faire un premier test avec un nombre réduit d'​epochs. Dans la partie '​main'​ du script python on remplace le défaut de 200 epochs par 5. On doit commenter (#) la première ligne et dé-commenter la deuxième. Je recommande aussi de faire un premier test avec un nombre réduit d'​epochs. Dans la partie '​main'​ du script python on remplace le défaut de 200 epochs par 5.
  
-''​parser.add_argument("​--epochs",​ type=int, default=200)''​ ==> ''​parser.add_argument("​--epochs",​ type=int, default=5)''​+    ​parser.add_argument("​--epochs",​ type=int, default=200)''​ ==> ''​parser.add_argument("​--epochs",​ type=int, default=5)
  
   * Lorsque l'on lance la commande ''​python3 main_test.py''​ on obtient :   * Lorsque l'on lance la commande ''​python3 main_test.py''​ on obtient :
  
-''​==> Preparing data..''​ +    ​==> Preparing data.. 
- +    .. ..  
-'' ​.. .. ''​ +    ==> Building model.. 
- +    Epoch: 0
-'' ​==> Building model.. ​''​ +
- +
-'' ​Epoch: 0 ''​+
  
 Le script ne fait pas utilisation de GPU (sinon on aurait une mention de CUDA) et on remarque que c'est très long car on utilise le CPU! Nous devons faire 2 commandes supplémentaires pour pouvoir utiliser les GPU avant de relancer le script : Le script ne fait pas utilisation de GPU (sinon on aurait une mention de CUDA) et on remarque que c'est très long car on utilise le CPU! Nous devons faire 2 commandes supplémentaires pour pouvoir utiliser les GPU avant de relancer le script :
Ligne 70: Ligne 67:
 ''​searchSpacePath:​ search_space.json '' ​ ''​searchSpacePath:​ search_space.json '' ​
   * Le fichier json précise le nom, le type et les valeurs possibles pour les variables.   * Le fichier json précise le nom, le type et les valeurs possibles pour les variables.
-''​ 
-{ 
  
-    "​lr":​{"​_type":"​choice",​ "​_value":​[0.1,​ 0.01, 0.001, 0.0001]}, +    ​
-    ​ +    ​"​lr":​{"​_type":"​choice",​ "​_value":​[0.1,​ 0.01, 0.001, 0.0001]},  
-    "​optimizer":​{"​_type":"​choice",​ "​_value":​["​SGD",​ "​Adadelta",​ "​Adagrad",​ "​Adam",​ "​Adamax"​]},​ +    "​optimizer":​{"​_type":"​choice",​ "​_value":​["​SGD",​ "​Adadelta",​ "​Adagrad",​ "​Adam",​ "​Adamax"​]},​  
-    ​ +    "​model":​{"​_type":"​choice",​ "​_value":​["​vgg",​ "​resnet18",​ "​googlenet",​ "​densenet121",​ "​mobilenet",​ "​dpn92",​ "​senet18"​]}  
-    "​model":​{"​_type":"​choice",​ "​_value":​["​vgg",​ "​resnet18",​ "​googlenet",​ "​densenet121",​ "​mobilenet",​ "​dpn92",​ "​senet18"​]} +    }
-    ​ +
-}''​  +
-  * Dans cet exemple, on a choix de modèles de réseaux de neurones qui sont prédéfinis,​ ce qui permet d'​avoir des performances très élevées. ​+
  
 +  * Dans cet exemple, on a choix de modèles de réseaux de neurones qui sont prédéfinis,​ ce qui permet d'​avoir des performances très élevées. ​
   * Dans NNI, l'​optimiseur des hyperparamètres est appelé "​tuner"​ (j'​imagine que c'est pour ne pas confondre avec l'​optimiseur qui modifie les poids du réseau de neurones). Le choix se fait dans le fichier de configuration. Plusieurs tuners sont disponibles : [[https://​nni.readthedocs.io/​en/​v1.6/​Tuner/​BuiltinTuner.html]].   * Dans NNI, l'​optimiseur des hyperparamètres est appelé "​tuner"​ (j'​imagine que c'est pour ne pas confondre avec l'​optimiseur qui modifie les poids du réseau de neurones). Le choix se fait dans le fichier de configuration. Plusieurs tuners sont disponibles : [[https://​nni.readthedocs.io/​en/​v1.6/​Tuner/​BuiltinTuner.html]].
   * Le fichier de configuration doit aussi préciser comment effectuer les évaluations (l'​équivalent de notre BB_EXE). Il faut fournir la commande pour lancer le script python : ''​python3 main.py'' ​   * Le fichier de configuration doit aussi préciser comment effectuer les évaluations (l'​équivalent de notre BB_EXE). Il faut fournir la commande pour lancer le script python : ''​python3 main.py'' ​
Ligne 94: Ligne 87:
   * Au début d'une expérience,​ NNI va créer un répertoire contenant tous les logs du tuner et les fichiers produits par les évaluations. Par défaut, ce répertoire se trouve dans ''​~/​nni-experiments''​ et porte comme nom l'​identifiant de l'​expérience (id). Cet identifiant est donné lorsque l'on créé un expérience. On peut modifier ce répertoire en rajoutant la ligne suivante dans le fichier ''​config.yml''​ :   * Au début d'une expérience,​ NNI va créer un répertoire contenant tous les logs du tuner et les fichiers produits par les évaluations. Par défaut, ce répertoire se trouve dans ''​~/​nni-experiments''​ et porte comme nom l'​identifiant de l'​expérience (id). Cet identifiant est donné lorsque l'on créé un expérience. On peut modifier ce répertoire en rajoutant la ligne suivante dans le fichier ''​config.yml''​ :
  
-'' ​logDir: /​home/​username/​mon_repertoire_adore/​NNI/​nni-experiments ​''​+    ​logDir: /​home/​username/​mon_repertoire_adore/​NNI/​nni-experiments
  
   * Une fois qu'une expérience est lancée sur une machine distante on peut visualiser ce qui se passe à partir de notre machine locale. Si ce n'est pas déjà fait, on se connecte par ssh et on créé un tunnel entre les ports 8080 (par défaut) de la machine locale et la machine distante (voir plus haut). On démarre notre fureteur préféré sur la machine locale et on entre l'​adresse ''​localhost:​8080''​. Magie, magie, normalement on devrait voir une page Web avec ce qui se passe dans notre expérience.   * Une fois qu'une expérience est lancée sur une machine distante on peut visualiser ce qui se passe à partir de notre machine locale. Si ce n'est pas déjà fait, on se connecte par ssh et on créé un tunnel entre les ports 8080 (par défaut) de la machine locale et la machine distante (voir plus haut). On démarre notre fureteur préféré sur la machine locale et on entre l'​adresse ''​localhost:​8080''​. Magie, magie, normalement on devrait voir une page Web avec ce qui se passe dans notre expérience.
Ligne 100: Ligne 93:
  
   * Éditer le fichier YAML (config.yml)   * Éditer le fichier YAML (config.yml)
-  * Pour faire plusieurs évaluations en parallèle, on met trialConcurrency:​ x +  * Pour faire plusieurs évaluations en parallèle, on met ''​trialConcurrency:​ x ''​ 
-  * Chaque évaluation peut être effectuée sur plusieurs ​GPU (à tester); pour utiliser ​un seul GPU, dans la section "​trials"​ on rajoute gpuNum: 1 +  * Chaque évaluation peut être effectuée sur plusieurs ​GPUs (à tester); pour utiliser ​une seule GPU, dans la section "​trials"​on rajoute ​''​gpuNum: 1''​ 
-  * Je n'ai pas eu de succès en spécifiant les GPU disponibles dans la section "​localConfig",​ avec gpuIndices: 0,1,2,3. +  * Je n'ai pas eu de succès en spécifiant les GPUs disponibles dans la section "​localConfig",​ avec ''​gpuIndices: 0, 1, 2, 3''​
-  * En définissant la variable d'​environnement CUDA_VISIBLE_DEVICES on peut spécifier quelles ​GPU utiliser : ''​export CUDA_VISIBLE_DEVICES=0,​1,​2,​3''​+  * En définissant la variable d'​environnement ​''​CUDA_VISIBLE_DEVICES'' ​on peut spécifier quelles ​GPUs utiliser : ''​export CUDA_VISIBLE_DEVICES=0,​1,​2,​3''​ 
 + 
 +==== Paralléliser une évaluation sur plusieurs GPUs ==== 
 + 
 +Quelques petites choses sur l'​évaluation avec plusieurs GPUs toujours en définissant correctement la variable d'​environnement ''​CUDA_VISIBLE_DEVICES''​. Les tests ont été fait sur ''​pandora''​.  
 + 
 +  * J’ai fait roulé ce [[https://​pytorch.org/​tutorials/​beginner/​blitz/​data_parallel_tutorial.html#​create-model-and-dataparallel|test]] sur un modèle simple et utilisant ''​PyTorch.''​ J'​observe que c'est plus lent avec 2 GPUs qu'​avec un seul. Oups! 
 +  * J’ai fait un test avec cifar100 et resnet101. Sur un GPU cela occupe ~ 9GB, chaque epoch prend ~ 2'​30"​. Sur deux GPUs, c’est 4-5 GB par GPU et chaque epoch prend ~ 1'​50"​. Sur trois GPUs, c’est 3-4 GB par GPU et chaque epoch prend 1'​30"​. Le speedup n’est pas génial mais avec des modèles plus gros ça doit valoir la peine. 
 +  * Ma conclusion c’est que pytorch peut gérer plusieurs GPUs sans que l’on ait grand chose à faire mais il faut que le réseau soit assez gros. Dans mon cas, pour cifar10 avec resnet18, cela ne vaut pas la peine et je suis mieux de paralléliser les blocs d’évaluations. 
 +  * Les tests précédents on été obtenu avec un ''​batch size''​ de 128. On peut changer ce paramètre qui influence la taille des batchs d'​images qui sont envoyés vers un GPU. Dans ''​pytorch''​ on peut modifier comment le ''​trainset''​ est chargé. 
 + 
 +''​trainset = torchvision.datasets.CIFAR100(root='​./​data',​ train=True, download=True,​ transform=transform_train)''​ 
 + 
 +''​trainloader = torch.utils.data.DataLoader(trainset,​ batch_size=128,​ shuffle=True,​ num_workers=2) ​''​
  
 +  * Sur les quelques tests que j'ai fait, le nombre de workers ne semble pas avoir d'​influence. Par contre le batch size a un effet : batch_size=128 avec 1 GPU: 2'​30"/​epoch et avec 2 GPUs: 1'​50'​‘/​epoch,​ batch_size=256 avec 2 GPUs : 1’25'​’/​epoch,​ batch_size=3*128 avec 3 GPUs : 1'/​epoch.  ​
  • groupe-dfo-bbo/projets/nni.1604496615.txt.gz
  • Dernière modification: 2020/11/04 13:30
  • par tribchri