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.
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.
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)
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
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.
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.
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.
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.
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.
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.
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.
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