[PYTHON] J'ai essayé d'implémenter DeepPose avec PyTorch PartⅡ

introduction

Dans l'article précédent (j'ai essayé d'implémenter DeepPose avec PyTorch), j'ai comparé Chainer et PyTorch lors de l'implémentation de DeepPose. PyTorch est aussi facile à mettre en œuvre que Chainer, et en termes de performances, la prédiction est à peu près la même que Chainer, et l'apprentissage est plus rapide que Chainer. Cette fois, nous approfondirons l'aspect performance en menant l'enquête et la vérification qui n'ont pas été terminées la dernière fois.

Modifications de la mise en œuvre depuis la dernière fois

La dernière fois, concernant le fait que la vitesse d'apprentissage de PyTorch est plus rapide que celle de Chainer, PyTorch a émis l'hypothèse que la différenciation automatique du calcul en arrière de la fonction Loss est exécutée (nativement) en C. Cette fois, j'ai changé l'implémentation en deux points pour la vérifier.

  1. Nombre aléatoire fixe
  2. Mise en œuvre explicite de la rétroaction La correction du nombre aléatoire améliore la reproductibilité de la vérification, et la mise en œuvre explicite en arrière consiste à voir l'effet de la vitesse d'apprentissage.

Nombre aléatoire fixe

Ajout du processus pour spécifier la graine aléatoire avant de commencer l'apprentissage. Notez que l'itérateur de Chainer utilise MultiprocessIterator et qu'il était difficile de fixer des nombres aléatoires en multi-processus, donc l'augmentation des données dans l'itération est désactivée.

Chainer

     def start(self):
         """ Train pose net. """
+        # set random seed.
+        if self.seed is not None:
+            random.seed(self.seed)
+            np.random.seed(self.seed)
+            if self.gpu >= 0:
+                chainer.cuda.cupy.random.seed(self.seed)
         # initialize model to train.
         model = AlexNet(self.Nj, self.use_visibility)

PyTorch

     def start(self):
         """ Train pose net. """
+        # set random seed.
+        if self.seed is not None:
+            random.seed(self.seed)
+            torch.manual_seed(self.seed)
+            if self.gpu:
+                torch.cuda.manual_seed(self.seed)
         # initialize model to train.
         model = AlexNet(self.Nj)

Implémentation explicite de backward

Selon Extending PyTorch, dans PyTorch, la différenciation de «Module» est une différenciation automatique, et la différenciation de «Function» est une implémentation requise. Il semble. Donc, cette fois, il semble que vous devriez implémenter Function.backward. Notez également que l'entrée pour «Module» est «Variable» et que l'entrée pour «Fonction» est «Tensor». Notez que «Function» a une méthode pratique appelée «save_for_backward», qui vous permet d'enregistrer des variables pour «backward», mais elle ne prend pas en charge les valeurs au milieu du calcul et est utilisée pour le calcul «backward». Le résultat du calcul avant est stocké dans la variable membre.

PyTorch

     def forward(self, *inputs):
         x, t, v = inputs
-        diff = x - t
+        self.diff = x - t
         if self.use_visibility:
-            N = (v.sum()/2).data[0]
-            diff = diff*v
+            self.N = v.sum()/2
+            self.diff = self.diff*v
         else:
-            N = diff.numel()/2
-        diff = diff.view(-1)
-        return diff.dot(diff)/N
+            self.N = self.diff.numel()/2
+        diff = self.diff.view(-1)
+        return torch.Tensor([diff.dot(diff)/self.N])
+
+    def backward(self, *grad_outputs):
+        coeff = grad_outputs[0][0]*2/self.N
+        gx0 = coeff*self.diff
+        return gx0, None, None

Vérification

Une expérience supplémentaire a été menée pour vérifier la construction provisoire mise en place la dernière fois. L'ensemble de données et l'environnement utilisés pour la vérification sont les mêmes que la dernière fois.

Effet de la différenciation automatique

Afin de vérifier l'effet de la différenciation automatique de PyTorch sur la vitesse d'apprentissage en étant exécutée (nativement) en C, il est nécessaire d'entraîner la différenciation automatique et la différenciation explicite de PyTorch par 100 époques dans l'environnement CPU et l'environnement GPU, respectivement. J'ai mesuré le temps.

Environnement CPU

Dans l'environnement CPU, le temps d'apprentissage de la différenciation automatique et de la différenciation explicite de PyTorch est presque le même.

Bibliothèque Temps requis[h]
PyTorch(Différenciation automatique) 47.6
PyTorch(Différenciation explicite) 47.6

Puisque les nombres aléatoires sont fixes, les courbes d'apprentissage de PyTorch se chevauchent presque. Training_time_comparison_(CPU).png

Environnement GPU

Dans l'environnement GPU, le temps d'apprentissage était légèrement plus lent pour la différenciation automatique de PyTorch que pour la différenciation explicite. Il est difficile de comprendre que la mise en œuvre de Python est plus rapide, mais cela peut être dû au caractère aléatoire du GPU, et les résultats peuvent changer avec quelques essais.

Bibliothèque Temps requis[h]
PyTorch(Différenciation automatique) 2.60
PyTorch(Différenciation explicite) 2.49

Bien que les nombres aléatoires soient fixes, la courbe d'apprentissage de PyTorch peut être décalée dans la direction de l'axe des temps en fonction de la méthode de mise en œuvre en raison du caractère aléatoire causé par le GPU. Training_time_comparison_(GPU).png

Impact de la mise en œuvre de la couche réseau

En regardant les résultats expérimentaux ci-dessus, il semble que la construction temporaire faite la dernière fois n'est pas toujours la bonne réponse. En regardant à nouveau le code pour enquêter sur la cause, dans Chainer, l'implémentation de chaque couche telle que Convolution était Python, et dans PyTorch c'était C. Comme cela semble avoir un effet dominant sur le temps d'apprentissage, Chainer et PyTorch ont mesuré le temps total requis pour les calculs avant et arrière de la fonction de perte (y compris le réseau). Cette fois, pour une taille de lot de 2 $ ^ n $, nous avons mesuré 100 fois chacun et calculé la moyenne et la variance.

Environnement CPU

Dans l'environnement CPU, lorsque $ n = 0 $, le temps de traitement est presque le même, mais à mesure que le $ n $ augmente, PyTorch devient supérieur. Considérant que le temps d'apprentissage moyen d'une époque de Chainer et PyTorch dans l'environnement CPU est de 8,2 [sec] et 5,0 [sec], respectivement, l'hypothèse ci-dessus semble appropriée. Core_process_time_comparison_(CPU).png

Environnement GPU

Dans l'environnement GPU ainsi que dans l'environnement CPU, le résultat est que PyTorch devient supérieur à mesure que $ n $ augmente. Considérant que le temps d'apprentissage moyen d'une époque de Chainer et PyTorch dans l'environnement GPU est de 0,45 [sec] et 0,28 [sec], respectivement, l'hypothèse ci-dessus semble appropriée. Core_process_time_comparison_(GPU).png

Résumé

L'hypothèse précédente selon laquelle «le temps d'apprentissage de PyTorch est plus rapide que celui de Chainer est que le calcul bakcward de la fonction Loss est exécuté (nativement) en C» a abouti à des réponses à moitié correctes et à moitié incorrectes. C'était. L'effet sur le temps d'apprentissage dû à la différence de méthode de mise en œuvre du calcul à rebours de la fonction Loss semble insignifiant. Il semble que l'influence dominante sur le temps d'apprentissage soit la méthode de mise en œuvre telle que la convolution nécessaire pour calculer chaque couche du réseau. Une fois que vous l'avez compris, c'est une conclusion naturelle. Cependant, bien que j'aie utilisé PyTorch 0.1.10 dans cette expérience, j'ai également essayé l'expérience avec la dernière version 0.1.12 au moment de la rédaction, et le résultat était que Chainer était plutôt plus rapide. J'ai l'impression que PyTorch est juste en cours de développement. Le code est sur github, donc je réessayerai une fois le développement terminé.

Recommended Posts

J'ai essayé d'implémenter DeepPose avec PyTorch PartⅡ
J'ai essayé d'implémenter DeepPose avec PyTorch
J'ai essayé d'implémenter CVAE avec PyTorch
J'ai essayé d'implémenter la lecture de Dataset avec PyTorch
J'ai essayé fp-growth avec python
J'ai essayé de gratter avec Python
J'ai essayé Learning-to-Rank avec Elasticsearch!
Essayez d'implémenter XOR avec PyTorch
[Introduction à Pytorch] J'ai essayé de catégoriser Cifar10 avec VGG16 ♬
J'ai essayé gRPC avec Python
J'ai essayé de gratter avec du python
J'ai créé Word2Vec avec Pytorch
J'ai essayé d'implémenter SSD avec PyTorch maintenant (Dataset)
J'ai essayé de classer MNIST par GNN (avec PyTorch géométrique)
J'ai essayé d'implémenter SSD avec PyTorch maintenant (édition du modèle)
J'ai essayé de résumer des phrases avec summpy
J'ai essayé l'apprentissage automatique avec liblinear
J'ai essayé de déplacer de la nourriture avec SinGAN
J'ai essayé d'implémenter Attention Seq2Seq avec PyTorch
J'ai essayé d'expliquer l'ensemble de données de Pytorch
J'ai essayé la détection de visage avec MTCNN
[Tutoriel PyTorch ⑤] Apprentissage de PyTorch avec des exemples (Partie 1)
J'ai essayé d'exécuter prolog avec python 3.8.2.
J'ai essayé la communication SMTP avec Python
J'ai essayé la génération de phrases avec GPT-2
J'ai essayé d'apprendre LightGBM avec Yellowbrick
J'ai essayé la reconnaissance faciale avec OpenCV
[AWS / Tello] J'ai essayé de faire fonctionner le drone avec ma voix Part2
J'ai essayé d'utiliser PyEZ et JSNAPy. Partie 4: Automatisez la configuration du FAI avec PyEZ et JSNAPy
J'ai essayé d'implémenter la classification des phrases par Self Attention avec PyTorch
[AWS / Tello] J'ai essayé de faire fonctionner le drone avec ma voix Part1
J'ai essayé d'exécuter la partie DNN d'OpenPose avec le processeur Chainer
J'ai essayé l'analyse de régression multiple avec régression polypoly
J'ai essayé d'envoyer un SMS avec Twilio
J'ai essayé d'utiliser Amazon SQS avec django-celery
J'ai essayé d'implémenter la régularisation Shake-Shake (ShakeNet) avec PyTorch
J'ai essayé d'implémenter Autoencoder avec TensorFlow
J'ai essayé linebot avec flacon (anaconda) + heroku
J'ai essayé de visualiser AutoEncoder avec TensorFlow
J'ai essayé de commencer avec Hy
J'ai essayé d'utiliser du sélénium avec du chrome sans tête
J'ai essayé l'analyse factorielle avec des données Titanic!
J'ai essayé d'apprendre avec le Titanic de Kaggle (kaggle②)
J'ai essayé d'utiliser PyEZ et JSNAPy. Partie 2: J'ai essayé d'utiliser PyEZ
J'ai essayé le rendu non réaliste avec Python + opencv
J'ai essayé un langage fonctionnel avec Python
J'ai essayé la récurrence avec Python ② (séquence de nombres Fibonatch)
J'ai essayé de jouer avec l'image avec Pillow
J'ai essayé de résoudre TSP avec QAOA
J'ai essayé la reconnaissance d'image simple avec Jupyter
J'ai essayé le réglage fin de CNN avec Resnet
J'ai essayé le traitement du langage naturel avec des transformateurs.
# J'ai essayé quelque chose comme Vlookup avec Python # 2
J'ai essayé la reconnaissance manuscrite des caractères des runes avec scikit-learn
J'ai essayé de prédire l'année prochaine avec l'IA
J'ai essayé d'utiliser PyEZ et JSNAPy. Partie 1: Aperçu