[PYTHON] Ich habe versucht, DeepPose mit PyTorch PartⅡ zu implementieren

Einführung

Im vorherigen Artikel (Ich habe versucht, DeepPose mit PyTorch zu implementieren) habe ich Chainer und PyTorch während der Implementierung von DeepPose verglichen. PyTorch ist so einfach zu implementieren wie Chainer. In Bezug auf die Leistung entspricht die Vorhersage in etwa der von Chainer, und das Lernen ist schneller als bei Chainer. Dieses Mal werden wir uns eingehender mit dem Leistungsaspekt befassen, indem wir die Untersuchung und Überprüfung durchführen, die wir beim letzten Mal zurückgelassen haben.

Implementierungsänderungen gegenüber dem letzten Mal

In Bezug auf die Tatsache, dass die Lerngeschwindigkeit von PyTorch schneller als die von Chainer ist, stellte PyTorch letztes Mal die Hypothese auf, dass die automatische Differenzierung der Rückwärtsberechnung der Verlustfunktion (nativ) in C ausgeführt wird. Dieses Mal habe ich die Implementierung in zwei Punkten geändert, um sie zu überprüfen.

  1. Feste Zufallszahl
  2. Explizite Implementierung von Rückwärts Durch das Festlegen der Zufallszahl wird die Reproduzierbarkeit der Überprüfung verbessert, und durch explizites Zurücksetzen wird der Effekt der Lerngeschwindigkeit ermittelt.

Feste Zufallszahl

Der Prozess zur Angabe des zufälligen Startwerts vor Beginn des Lernens wurde hinzugefügt. Beachten Sie, dass Chainers "Iterator" "MultiprocessIterator" verwendet und es schwierig war, Zufallszahlen in mehreren Prozessen zu korrigieren, sodass die Datenerweiterung in der Iteration deaktiviert ist.

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)

Explizite Implementierung von Rückwärts

Laut Extending PyTorch ist in PyTorch die Differenzierung von "Module" eine automatische Differenzierung, und die Differenzierung von "Function" ist eine Implementierung erforderlich. Es scheint, dass. Diesmal sollten Sie also "Function.backward" implementieren. Beachten Sie auch, dass der Eingang für "Modul" "Variabel" und der Eingang für "Funktion" "Tensor" ist. Beachten Sie, dass Function eine praktische Methode namens save_for_backward hat, mit der Sie Variablen für backward speichern können, die jedoch keine Werte in der Mitte der Berechnung unterstützt und für die backward-Berechnung verwendet wird. Das Ergebnis der Vorwärtsberechnung wird in der Mitgliedsvariablen gespeichert.

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

Überprüfung

Ein zusätzliches Experiment wurde durchgeführt, um die beim letzten Mal eingerichtete temporäre Konstruktion zu überprüfen. Der Datensatz und die Umgebung, die für die Überprüfung verwendet werden, sind dieselben wie beim letzten Mal.

Effekt der automatischen Differenzierung

Um die Auswirkung der automatischen Differenzierung von PyTorch auf die Lerngeschwindigkeit durch Ausführung in C (nativ) zu überprüfen, muss die automatische Differenzierung von PyTorch und die explizite Differenzierung nach 100 Epochen in der CPU-Umgebung bzw. der GPU-Umgebung trainiert werden. Ich habe die Zeit gemessen.

CPU-Umgebung

In der CPU-Umgebung ist die Lernzeit der automatischen und expliziten Differenzierung von PyTorch nahezu gleich.

Bibliothek Benötigte Zeit[h]
PyTorch(Automatische Differenzierung) 47.6
PyTorch(Explizite Differenzierung) 47.6

Da die Zufallszahlen fest sind, überlappen sich die Lernkurven von PyTorch fast. Training_time_comparison_(CPU).png

GPU-Umgebung

In der GPU-Umgebung war die Lernzeit für die automatische Differenzierung von PyTorch etwas langsamer als für die explizite Differenzierung. Es ist schwer zu verstehen, dass die Python-Implementierung schneller ist, aber es kann an der Zufälligkeit der GPU liegen, und die Ergebnisse können sich mit einigen Versuchen ändern.

Bibliothek Benötigte Zeit[h]
PyTorch(Automatische Differenzierung) 2.60
PyTorch(Explizite Differenzierung) 2.49

Obwohl die Zufallszahlen fest sind, kann die Lernkurve von PyTorch aufgrund der durch die GPU verursachten Zufälligkeit in Abhängigkeit von der Implementierungsmethode in Richtung der Zeitachse verschoben werden. Training_time_comparison_(GPU).png

Auswirkungen der Implementierung der Netzwerkschicht

Wenn man die obigen experimentellen Ergebnisse betrachtet, scheint es, dass die beim letzten Mal vorgenommene temporäre Konstruktion nicht immer die richtige Antwort ist. Wenn Sie den Code erneut betrachten, um die Ursache zu untersuchen, war in Chainer die Implementierung jeder Ebene wie Convolution Python und in PyTorch C. Da dies einen dominanten Einfluss auf die Lernzeit zu haben scheint, haben Chainer und PyTorch die Gesamtzeit gemessen, die für Vorwärts- und Rückwärtsberechnungen der Verlustfunktion (einschließlich Netzwerk) erforderlich ist. Dieses Mal haben wir für eine Chargengröße von $ 2 ^ n $ jeweils 100 Mal gemessen und den Mittelwert und die Varianz berechnet.

CPU-Umgebung

Wenn in der CPU-Umgebung $ n = 0 $ ist, ist die Verarbeitungszeit fast gleich, aber mit zunehmendem $ n $ wird PyTorch überlegen. In Anbetracht der Tatsache, dass die durchschnittliche Lernzeit von 1 Epoche Chainer und PyTorch in der CPU-Umgebung 8,2 [Sek.] Bzw. 5,0 [Sek.] Beträgt, erscheint die obige Hypothese angemessen. Core_process_time_comparison_(CPU).png

GPU-Umgebung

Sowohl in der GPU-Umgebung als auch in der CPU-Umgebung führt dies dazu, dass PyTorch mit zunehmendem $ n $ überlegen wird. In Anbetracht der Tatsache, dass die durchschnittliche Lernzeit von 1 Epoche Chainer und PyTorch in der GPU-Umgebung 0,45 [Sek.] Bzw. 0,28 [Sek.] Beträgt, erscheint die obige Hypothese angemessen. Core_process_time_comparison_(GPU).png

Zusammenfassung

Die vorherige Hypothese, dass "PyTorchs Lernzeit schneller ist als die von Chainer, weil die Backcward-Berechnung der Verlustfunktion (nativ) in C ausgeführt wird", führte zu halb richtigen und halb falschen Antworten. Es war. Die Auswirkung auf die Lernzeit aufgrund der unterschiedlichen Implementierungsmethode der Rückwärtsberechnung der Verlustfunktion scheint unbedeutend zu sein. Es scheint, dass der dominierende Einfluss auf die Lernzeit die Implementierungsmethode wie die Faltung ist, die zur Berechnung jeder Schicht des Netzwerks erforderlich ist. Sobald Sie es verstanden haben, ist es eine natürliche Schlussfolgerung. Obwohl ich in diesem Experiment PyTorch 0.1.10 verwendet habe, habe ich das Experiment zum Zeitpunkt des Schreibens auch mit der neuesten Version 0.1.12 versucht, und das Ergebnis war, dass Chainer ziemlich schneller war. Ich habe den Eindruck, dass sich PyTorch gerade in der Entwicklung befindet. Der Code befindet sich auf github, daher werde ich es erneut versuchen, wenn die Entwicklung abgeschlossen ist.

Recommended Posts

Ich habe versucht, DeepPose mit PyTorch PartⅡ zu implementieren
Ich habe versucht, DeepPose mit PyTorch zu implementieren
Ich habe versucht, CVAE mit PyTorch zu implementieren
Ich habe versucht, das Lesen von Dataset mit PyTorch zu implementieren
Ich habe fp-Wachstum mit Python versucht
Ich habe versucht, mit Python zu kratzen
Ich habe versucht, mit Elasticsearch Ranking zu lernen!
Versuchen Sie, XOR mit PyTorch zu implementieren
[Einführung in Pytorch] Ich habe versucht, Cifar10 mit VGG16 ♬ zu kategorisieren
Ich habe gRPC mit Python ausprobiert
Ich habe versucht, mit Python zu kratzen
Ich habe Word2Vec mit Pytorch gemacht
Ich habe versucht, SSD jetzt mit PyTorch zu implementieren (Dataset)
Ich habe versucht, MNIST nach GNN zu klassifizieren (mit PyTorch-Geometrie).
Ich habe versucht, SSD jetzt mit PyTorch zu implementieren (Modellversion)
Ich habe versucht, Sätze mit summpy zusammenzufassen
Ich habe maschinelles Lernen mit liblinear versucht
Ich habe versucht, Essen mit SinGAN zu bewegen
Ich habe versucht, Attention Seq2Seq mit PyTorch zu implementieren
Ich habe versucht, Pytorchs Datensatz zu erklären
Ich habe versucht, das Gesicht mit MTCNN zu erkennen
[PyTorch Tutorial ⑤] PyTorch anhand von Beispielen lernen (Teil 1)
Ich habe versucht, Prolog mit Python 3.8.2 auszuführen.
Ich habe die SMTP-Kommunikation mit Python versucht
Ich habe versucht, Sätze mit GPT-2 zu generieren
Ich habe versucht, LightGBM mit Yellowbrick zu lernen
Ich habe versucht, das Gesicht mit OpenCV zu erkennen
[AWS / Tello] Ich habe versucht, die Drohne mit meiner Stimme Part2 zu bedienen
Ich habe versucht, PyEZ und JSNAPy zu verwenden. Teil 4: Automatisieren Sie die ISP-Einrichtung mit PyEZ und JSNAPy
Ich habe versucht, die Satzklassifizierung durch Self Attention mit PyTorch zu implementieren
[AWS / Tello] Ich habe versucht, die Drohne mit meiner Stimme Part1 zu bedienen
Ich habe versucht, den DNN-Teil von OpenPose mit Chainer-CPU auszuführen
Ich habe eine multiple Regressionsanalyse mit Polypoly-Regression versucht
Ich habe versucht, eine SMS mit Twilio zu senden
Ich habe versucht, Amazon SQS mit Django-Sellerie zu verwenden
Ich habe versucht, Shake-Shake Regularization (ShakeNet) mit PyTorch zu implementieren
Ich habe versucht, Autoencoder mit TensorFlow zu implementieren
Ich habe Linebot mit Flasche (Anaconda) + Heroku ausprobiert
Ich habe versucht, AutoEncoder mit TensorFlow zu visualisieren
Ich habe versucht, mit Hy anzufangen
Ich habe versucht, Selen mit Headless-Chrom zu verwenden
Ich habe versucht, Faktoren mit Titanic-Daten zu analysieren!
Ich habe versucht, mit Kaggles Titanic (kaggle②) zu lernen.
Ich habe versucht, PyEZ und JSNAPy zu verwenden. Teil 2: Ich habe versucht, PyEZ zu verwenden
Ich habe versucht, mit Python + opencv nicht realistisch zu rendern
Ich habe eine funktionale Sprache mit Python ausprobiert
Ich habe versucht, mit Python ② (Fibonacci-Zahlenfolge) aufzuklären.
Ich habe versucht, mit Pillow mit dem Bild zu spielen
Ich habe versucht, TSP mit QAOA zu lösen
Ich habe mit Jupyter eine einfache Bilderkennung versucht
Ich habe versucht, CNN mit Resnet fein abzustimmen
Ich habe versucht, natürliche Sprache mit Transformatoren zu verarbeiten.
# Ich habe so etwas wie Vlookup mit Python # 2 ausprobiert
Ich habe versucht, Runenfiguren mit Scikit-Learn handschriftlich zu erkennen
Ich habe versucht, nächstes Jahr mit AI vorherzusagen
Ich habe versucht, PyEZ und JSNAPy zu verwenden. Teil 1: Übersicht