2020/1/27 Gepostet
Heutzutage liegt die Hauptforschung zum maschinellen Lernen in der Python-Sprache, da Python über viele Bibliotheken (sogenannte Module) für die schnelle Datenanalyse und -berechnung verfügt. Diesmal verwenden wir ein Modul namens ** pyTorch **, um zu erklären, wie die automatische Differenzierung durchgeführt wird und was getan werden kann und was nicht.
Dieser Artikel ähnelt jedoch Ihrem eigenen Memo, und ich möchte, dass Sie ihn nur als Referenz verwenden. Es kann Fälle geben, in denen Sie der Kürze halber falsche Ausdrücke oder Ausdrücke verwenden. Bitte haben Sie Verständnis dafür. Ich möchte, dass du es tust.
Außerdem werden wir in diesem Artikel nicht lernen, wie man mit Netzwerk umgeht. Wenn Sie daran interessiert sind, klicken Sie bitte auf den unten stehenden Link.
Gründliche Erklärung von CNNs mit pyTorch
Wenn Sie pyTorch zum ersten Mal verwenden, müssen Sie es mit cmd installieren, da pyTorch noch nicht in Python installiert ist. Wechseln Sie zu dem unten stehenden Link, wählen Sie den in Ihrer Umgebung mit "QUICK START LOCALLY" am Ende der Seite aus und geben Sie den Befehl ein, der mit cmd usw. angezeigt wird (Sie sollten in der Lage sein, den Befehl zu kopieren und auszuführen).
offizielle Website von pytorch
So wie numpy einen Typ namens ndarray hat, hat pyTorch einen Typ namens "** Tensor type **". Wie der ndarray-Typ kann er Matrixberechnungen durchführen und ist einander ziemlich ähnlich, aber der Tensor-Typ ist beim maschinellen Lernen insofern überlegen, als er die GPU verwenden kann. Dies liegt daran, dass maschinelles Lernen einen erheblichen Rechenaufwand erfordert und eine GPU mit einer hohen Berechnungsgeschwindigkeit verwendet. Darüber hinaus ist der Tensortyp für die Aktualisierung von Parametern des maschinellen Lernens sehr einfach zu unterscheiden. Der Schlüssel zu diesem Artikel ist, wie einfach dies ist.
Informationen zu Operationen und Erläuterungen vom Typ Tensor finden Sie unter dem folgenden Link.
Was ist der Tensor-Typ von pyTorch
Importieren Sie zunächst, damit Sie pyTorch verwenden können. Schreiben Sie von hier aus in die Python-Datei anstelle von cmd usw. Verwenden Sie das Modul, indem Sie den folgenden Code schreiben.
filename.rb
import torch
Das folgende einfache Berechnungsprogramm wird angezeigt.
filename.rb
x = torch.tensor(4.0, requires_grad = True)
c = torch.tensor(8.0)
b = 5.0
y = c*x + b
print(y)
------------Ausgabe unten---------------
tensor(37., grad_fn=<AddBackward0>)
Dies ist eine Formel
y = 8x+5
Es ist eine Berechnung, wenn $ x = 4 $ von und $ y $ als 37 ausgegeben wird. "** grad_fn = \ <AddBackward0 > **" dieser Ausgabe wird durch Hinzufügen von $ y $ berechnet Es zeigt, dass es berechnet wurde, und es ist möglich zu unterscheiden, indem Sie dies in jeder Variablen halten.
Diese Unterscheidung ist wie folgt.
filename.rb
y.backward()
Dies unterscheidet die Werte aller Variablen in $ y $.
Es wird nichts ausgegeben, wenn Sie dies überprüfen
filename.rb
print(x)
print(x.grad)
------------Ausgabe unten---------------
tensor(4., requires_grad=True)
tensor(8.)
Auf diese Weise liefert die Ausgabe von $ x $ keine Differentialinformationen, aber Sie können den Differentialwert 8.0 des Variablennamens sehen, indem Sie "** x.grad **" setzen.
Hier haben Sie gesagt, dass Sie die Werte aller Variablen früher differenziert haben, aber wenn Sie sich tatsächlich die Differentialinformationen anderer Variablen ansehen
filename.rb
print(c.grad)
print(b.grad)
------------Ausgabe unten---------------
None
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-5-881d89d572bd> in <module>
1 print(c.grad)
----> 2 print(b.grad)
AttributeError: 'float' object has no attribute 'grad'
Die erste Ausgabe ist "** None ". Tatsächlich wurde " require_grad = True **" nicht zur Variablen ** c ** hinzugefügt, als die erste Variable vorbereitet wurde. Dies veranlasst die Variable ** c ** zu differenzieren, wird jedoch nur als Konstante interpretiert.
Darüber hinaus hat die zweite Ausgabe eine Fehleranweisung. Dies ist ein Fehler, der durch den Versuch verursacht wird, eine Differentialberechnung durchzuführen, die nur für den Tensor-Typ, bei dem es sich um einen speziellen pyTorch-Typ handelt, für einen anderen Typ als den Tensor-Typ durchgeführt werden kann (diese Variable ** b ** ist nur ein Float-Typ).
Dies zeigt, dass der Tensor-Typ von pyTorch sehr gut ist. Wenn Sie "require_grad = True" festlegen, werden alle Differentialinformationen in nur einer Zeile berechnet.
Hier ist ein Beispiel für kompliziertere Berechnungen.
filename.rb
x = torch.ones(2,3, requires_grad = True)
c = torch.ones(2,3, requires_grad = True)
y = torch.exp(x)*(c*3) + torch.exp(x)
print(torch.exp(x))
print(c*3)
print(y)
------------Ausgabe unten---------------
tensor([[2.7183, 2.7183, 2.7183],
[2.7183, 2.7183, 2.7183]], grad_fn=<ExpBackward>)
tensor([[3., 3., 3.],
[3., 3., 3.]], grad_fn=<MulBackward0>)
tensor([[10.8731, 10.8731, 10.8731],
[10.8731, 10.8731, 10.8731]], grad_fn=<AddBackward0>)
Zunächst führt "** torch.exp () **" eine Berechnung durch, die für jedes Element der Argumentdaten zu $ e ^ {element} $ wird. Wie Sie sehen, ist jede Ausgabe dieses Mal "require_grad = True" auf beide Variablen ** x ** und ** c ** angewendet.
Wenn es nun tatsächlich rückwärts ist, wird es wie folgt.
filename.rb
y.backward()
------------Ausgabe unten---------------
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-11-ab75bb780f4c> in <module>
----> 1 y.backward()
......(Kürzung)......
RuntimeError: grad can be implicitly created only for scalar outputs
Ein Fehler wird ausgegeben. Wie in diesem Fehler geschrieben, kann Rückwärts tatsächlich nur für skalare Werte ausgeführt werden (einfach gesagt, Daten mit nur einem Wert, der keine Matrix oder kein Vektor ist).
Die tatsächliche Lösung lautet wie folgt.
filename.rb
s = torch.sum(y)
print(s)
------------Ausgabe unten---------------
tensor(65.2388, grad_fn=<SumBackward0>)
Diese "** torch.sum () **" gibt das Ergebnis des Hinzufügens aller Elemente des Arguments zurück. Jetzt haben Sie einen Skalarwert. Wenn Sie tatsächlich rückwärts machen
filename.rb
s.backward()
print(x.grad)
print(c.grad)
------------Ausgabe unten---------------
tensor([[10.8731, 10.8731, 10.8731],
[10.8731, 10.8731, 10.8731]])
tensor([[8.1548, 8.1548, 8.1548],
[8.1548, 8.1548, 8.1548]])
Auf diese Weise wird die Differenzierung auch für eine Matrix mit mehreren Variablen fest durchgeführt.
Von hier aus werde ich ein Beispiel schreiben, das eigentlich nicht rückwärts ist. Von hier an werde ich neue Beispiele hinzufügen, sobald ich sie finde oder Berichte erhalte.
Wie in Beispiel 5-2 der obigen automatischen Differenzierung erläutert, tritt es auf, wenn die zu differenzierende Variable ** Tensortyp ** und "** require_grad = True **" ist. Die Lösung ist einfach und der Typ sollte den Anforderungen entsprechen.
Wie in Beispiel 5-3 der obigen automatischen Differenzierung erläutert, tritt es auf, wenn die zu differenzierende Variable ** kein Skalarwert ** ist. Die Lösung besteht darin, es irgendwie zu einem Skalarwert zu machen. Zum Beispiel kann die Summe der im obigen Beispiel durchgeführten Elemente durchgeführt werden, ohne die Form der Matrix zu brechen.
Ein Beispiel ist unten gezeigt.
filename.rb
x = torch.tensor(1.0, requires_grad = True)
x = torch.exp(x)
c = torch.tensor(1.0, requires_grad = True)
c = c*3
b = 5.0
y = c*x + b
print(y)
------------Ausgabe unten---------------
tensor(13.1548, grad_fn=<AddBackward0>)
Wenn Sie es in einer Formel mit einem sehr einfachen Beispiel schreiben
y = (c*3)*e^{x}+5
Die Formel lautet $ c = 1 $, $ x = 1 $ und "require_grad = True" unterscheidet sowohl c als auch x voneinander. Der tatsächliche Differenzwert ist wie folgt.
filename.rb
y.backward()
print(x.grad)
print(c.grad)
------------Ausgabe unten---------------
None
None
Wie, weder x noch c haben einen Differenzwert. Dies liegt daran, dass das Überschreiben von Variablen den Berechnungsprozess von x und c (als Berechnungsdiagramm bezeichnet) eliminiert (die erste Definition von x und c, und alle früheren Berechnungen, die hier nicht durchgeführt werden, sind " Es wird von "torch.exp ()" und "* 3") überschrieben. In einem solchen Beispiel wird jedoch eine Fehlermeldung angezeigt, wenn Sie versuchen, es in den von der Taschenlampe vorbereiteten Optimierer (SGD usw.) zu legen. Ein aktuelles Beispiel ist unten gezeigt.
filename.rb
import torch.optim as optim
op = optim.SGD([x,c], lr=1.0)
------------Ausgabe unten---------------
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-18-775027da6d38> in <module>
----> 1 op = optim.SGD([x,c], lr=1.0)
............(Kürzung)............
ValueError: can't optimize a non-leaf Tensor
Bei Verwendung von SGD, einem Optimierer, wird ein Fehler ausgegeben. Wenn Sie an der ausführlichen Erläuterung dieses Optimierers interessiert sind, klicken Sie bitte auf den folgenden Link.
PyTorch Optimizer SGD ausführliche Erklärung
Wie ich hier kurz erläutern werde, bereitet sich diese SGD-Klasse darauf vor, jeden Parameter des Argumentparameters "** [x, c] **" unter Verwendung der Gradienteninformationen zu aktualisieren. Zu diesem Zeitpunkt gibt es jedoch einen Fehler, dass der Berechnungsgraph dieser Variablen abgeschnitten wird.
Die Lösung besteht darin, sie einer anderen Variablen zuzuweisen, ohne sie zu überschreiben, oder den Ausdruck direkt zu schreiben. Da Sie sehen können, dass es einer anderen Variablen zugewiesen ist, sehen Sie unten ein Beispiel für das direkte Schreiben des Ausdrucks.
filename.rb
x = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)
b = 5.0
y = c*3*torch.exp(x)
y = y + b
y.backward()
print(x.grad)
print(c.grad)
------------Ausgabe unten---------------
tensor(8.1548)
tensor(8.1548)
Hier werden die Operationen von ** y ** absichtlich in der 4. und 5. Zeile getrennt. Tatsächlich gibt es keine Strafe für das Überschreiben dieses ** y **. Da ** y ** nicht die Variable ist, die Sie unterscheiden möchten, spielt es keine Rolle, ob die Berechnung ordnungsgemäß durchgeführt wird.
Betrachten Sie zunächst die folgende Berechnung.
y = c\sqrt{x_1^2+x_2^2+x_3^2}
Wie Sie auf einen Blick sehen können, ist dies die ** L2-Norm ** (oder nur der Abstand) des Vektors $ [x_1, x_2, x_3] $ multipliziert mit c.
Dies wird unten programmgesteuert gezeigt.
filename.rb
x = torch.tensor([2.0,5.0,3.0], requires_grad = True)
c = torch.tensor(2.0)
y = torch.sqrt(torch.sum(x**2))
y = y*c
y.backward()
print(x.grad)
------------Ausgabe unten---------------
tensor([0.6489, 1.6222, 0.9733])
Es ist ersichtlich, dass der Differenzwert jedes Elements in Bezug auf den Vektor ** x ** richtig berechnet werden kann. Um das Programm ein wenig zu erklären, quadriert "** torch.sqrt (torch.sum (x \ * \ * 2)) **" in der dritten Zeile zuerst jedes Element von x und summiert jedes Element. Und lege es in die Wurzel.
Betrachten Sie nun das folgende Beispiel mit dieser Gleichung.
filename.rb
x = torch.tensor([0.0,0.0,0.0], requires_grad = True)
c = torch.tensor(2.0)
y = torch.sqrt(torch.sum(x**2))
y = y*c
y.backward()
print(x.grad)
------------Ausgabe unten---------------
tensor([nan, nan, nan])
Jetzt habe ich alle Werte jedes Elements der Variablen ** x ** auf 0,0 umgeschrieben (der Abstand des Vektors x ist 0). Infolgedessen wurden alle Differenzwerte ** nan **. Auf diese Weise nimmt der Differenzwert jedes Elements natürlich ∞ an. Weil die Differenzierung der obigen Gleichung ist
\frac{\partial y}{\partial x_1} = c\frac{x_1}{\sqrt{x_1^2+x_2^2+x_3^2}}
Und da der Abstand von $ x 0 $ ist, wird er durch 0 geteilt. Beim tatsächlichen maschinellen Lernen werden die Parameter automatisch aktualisiert. Wenn der Wert des Parameters jedoch auch nur einmal im Prozess 0 wird und sich im Berechnungsprozess $ \ sqrt {x} $ befindet, ist dies der Fall Das Phänomen wird passieren. Dies führt dazu, dass der Verlust divergiert oder nan unsichtbar wird.
Die Lösung ist wie folgt.
filename.rb
x = torch.tensor([0.0,0.0,0.0], requires_grad = True)
c = torch.tensor(2.0)
y = torch.norm(x)
y = y*c
y.backward()
print(x.grad)
------------Ausgabe unten---------------
tensor([0., 0., 0.])
Auf diese Weise ist der Differenzwert nicht ** nan , sondern 0, wenn Sie in der dritten Zeile " torch.norm () **" verwenden. Diese torch.norm () macht genau das Gleiche in der Berechnung selbst, hat aber wahrscheinlich einen Mechanismus, der die interne 0-Division verhindert.
Python verfügt über eine In-Place-Operation, mit der Sie Folgendes ausführen können:
filename.rb
i += 1
x *=3
Diese werden normalerweise beschrieben, indem die Stellen weggelassen werden, an denen "** i = i + 1 " und " x = x * 3 **" geschrieben sind. Diese Notation scheint schneller zu sein, ist jedoch nicht für die automatische Differenzierung geeignet. Ein Beispiel ist unten gezeigt.
filename.rb
x = torch.tensor(3.0, requires_grad = True)
c = torch.tensor(2.0)
c += 2.0
x += 2.0
y = x + c
------------Ausgabe unten---------------
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-94-beb1a427373d> in <module>
2 c = torch.tensor(2.0)
3 c += 2.0
----> 4 x += 2.0
5 y = x + c
RuntimeError: a leaf Variable that requires grad has been used in an in-place operation.
Eine direkte Operation ist für Variablen mit "require_grad = True" auf diese Weise nicht möglich (natürlich hängt die Variable c nicht mit der Differenzierung zusammen).
Die Lösung ist einfach und Sie müssen keinen direkten Betrieb verwenden. Das heißt, Sie müssen es nur normal schreiben.
Ein Beispiel ist unten gezeigt.
filename.rb
x = torch.tensor(3.0, requires_grad = True).cuda()
c = torch.tensor(2.0, requires_grad = True).cpu()
y = x*c
print(y)
------------Ausgabe unten---------------
tensor(6., device='cuda:0', grad_fn=<MulBackward0>)
Hier wird die Variable ** x ** angegeben, um gpu durch "**. Cuda () " zu verwenden, und die Variable ** c ** wird angegeben, um cpu durch ". Cpu () " zu verwenden. tun. Außerdem befinden sich beide Variablen in einem teilbaren Zustand. Die Ausgabe der Antwort verwendet gpu als " device = 'cuda: 0' **".
Lass uns rückwärts machen
filename.rb
y.backward()
------------Ausgabe unten---------------
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-118-8117d53c0658> in <module>
----> 1 y.backward()
...........(Kürzung).............
RuntimeError: Function MulBackward0 returned an invalid gradient at index 1 - expected type torch.FloatTensor but got torch.cuda.FloatTensor
Dieser Fehler tritt auf, weil die auf diese Weise zu unterscheidenden Variablen unterschiedliche Ressourcen verwenden.
Die Lösung besteht darin, die von einander verwendeten Ressourcen zu kombinieren. Natürlich ist es nicht notwendig, Variablen vorzubereiten, die nicht mit der Differenzierung zusammenhängen.
Unter den von pyTorch bereitgestellten Tensortypen gibt es auch den Typ int, den Typ float, den Typ double usw. Sie können diesen Typ wie folgt richtig verwenden.
filename.rb
a = torch.tensor(2)
b = torch.tensor(2.134)
c = torch.tensor(3.5)
c = c.type(torch.int32)
d = torch.tensor(3.1514, dtype = torch.float64)
print(a)
print(b)
print(c)
print(d)
------------Ausgabe unten---------------
tensor(2)
tensor(2.1340)
tensor(3, dtype=torch.int32)
tensor(3.1514, dtype=torch.float64)
Auf diese Weise können Sie zum Zeitpunkt der Deklaration "** dtype = " oder " xxxx.type (Typtyp) **" hinzufügen. Darüber hinaus wird der Typ jeder Variablen wie folgt gesehen.
filename.rb
print(a.dtype)
print(b.dtype)
print(c.dtype)
print(d.dtype)
------------Ausgabe unten---------------
torch.int64
torch.float32
torch.int32
torch.float64
Wie Sie sehen können, wird eine Ganzzahl, wenn Sie sie zum Zeitpunkt der Deklaration wie die Variable a angeben, ohne sie anzugeben, automatisch zu ** int64 **, und wenn Sie eine reelle Zahl wie die Variable b übergeben, wird sie automatisch zu ** float32 **. Noch interessanter ist, dass bei der Umwandlung von c in int32 der Bruchteil verschwindet.
Basierend auf dem oben Gesagten wird nun der tatsächliche Berechnungsprozess als Beispiel unten gezeigt.
filename.rb
x = torch.tensor(3.0, dtype = torch.int64, requires_grad = True)
c = torch.tensor(2.0, requires_grad = True)
y = x*c
------------Ausgabe unten---------------
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-22-7183168e453f> in <module>
----> 1 x = torch.tensor(3.0, dtype = torch.int64, requires_grad = True)
2 c = torch.tensor(2.0, requires_grad = True)
3 y = x*c
RuntimeError: Only Tensors of floating point dtype can require gradients
Hier habe ich versucht, die Variable ** x ** zu einem Integer-Typ zu machen. Wenn es sich um einen Ganzzahltyp handelt, kann anscheinend "** require_grad = True **" überhaupt nicht festgelegt werden, und dieser Fehler wird angezeigt.
Schreiben wir es als float um.
filename.rb
x = torch.tensor(3.0, dtype = torch.float64, requires_grad = True)
c = torch.tensor(2.0, requires_grad = True)
y = x*c
print(y)
------------Ausgabe unten---------------
tensor(6., dtype=torch.float64, grad_fn=<MulBackward0>)
Es hat gut funktioniert. Lassen Sie uns automatisch differenzieren.
filename.rb
y.backward()
------------Ausgabe unten---------------
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-8-ab75bb780f4c> in <module>
----> 1 y.backward()
............(Kürzung)............
RuntimeError: Function MulBackward0 returned an invalid gradient at index 1 - expected type torch.FloatTensor but got torch.DoubleTensor
Ich bekomme eine Fehlermeldung. Der Grund dafür ist einfach, in der Tat kann ** backward () nur mit torch.float32 Typ ** durchgeführt werden. Genau genommen wird ** torch.float64 **, das dieses Mal vorbereitet wurde, als ** Double Type ** behandelt, sodass backward () nicht möglich ist.
Die Lösung besteht darin, nur ** torch.float32 ** anstelle von ** torch.float64 ** zu verwenden.
Beim tatsächlichen maschinellen Lernen ist es üblich, Bakterien und Matrizen als Parameter vorzubereiten und zu verwenden. Ein Beispiel ist unten gezeigt.
filename.rb
x = torch.tensor([10.0,20.0,30.0], requires_grad = True)
c = torch.tensor([1.0,2.0,3.0], requires_grad = True)
x[0] = c[0]*x[0]
x[1] = c[1]*x[1]
x[2] = c[2]*x[2]
y = torch.sum(x)
print(y)
------------Ausgabe unten---------------
tensor(140., grad_fn=<SumBackward0>)
Dies ist ein Programm, das das innere Produkt des Vektors ** x ** und des Vektors ** c ** berechnet. Versuchen Sie es jetzt rückwärts ().
filename.rb
y.backward()
------------Ausgabe unten---------------
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-11-ab75bb780f4c> in <module>
----> 1 y.backward()
.........(Kürzung)..........
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor []], which is output 0 of SelectBackward, is at version 3; expected version 2 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True).
Ein solcher Fehler wurde ausgegeben. Das Wichtigste dabei ist, dass der Fehler lautet "** Gradientenberechnung wurde durch eine Inplace-Operation geändert **", und ich habe zuvor ein Beispiel für In-Place angegeben, aber ich kann es nirgendwo in diesem Programm finden. ..
Tatsächlich entspricht diese Berechnung des Arrays "** x [0] = c [0] * x [0] **" der In-Place-Berechnung. Wenn Sie es so betrachten, sieht es aus wie ein Fehler wie das Überschreiben der oben genannten Variablen, aber seien Sie vorsichtig, da es besagt, dass der Fehler durch In-Place verursacht wird. Die Lösung besteht darin, das folgende Programm zu verwenden.
filename.rb
x = torch.tensor([10.0,20.0,30.0], requires_grad = True)
c = torch.tensor([1.0,2.0,3.0], requires_grad = True)
w = torch.zeros(3)
w[0] = c[0]*x[0]
w[1] = c[1]*x[1]
w[2] = c[2]*x[2]
y = torch.sum(w)
print(y)
------------Ausgabe unten---------------
tensor(140., grad_fn=<SumBackward0>)
Auf diese Weise können Sie Variablen vorbereiten, die nichts mit Differenzierung zu tun haben. Wenn ich es tatsächlich rückwärts versuche ()
filename.rb
y.backward()
print(x.grad)
------------Ausgabe unten---------------
tensor([1., 2., 3.])
Es funktioniert gut.
Dieses Mal habe ich den automatischen Teil zusammengefasst, der auf der Rückseite von pyTorch unsichtbar ist, und das Beispiel, das nicht ausgeführt werden kann. Dieser Artikel wird weiterhin aktualisiert, sobald wir solche Beispiele finden. Ich denke, es gab viele Punkte, die schwer zu lesen waren, aber ich danke Ihnen für das Lesen.
Recommended Posts