[PYTHON] [Super Einführung in das maschinelle Lernen] Lernen Sie Pytorch-Tutorials

Dies ist eine Zusammenstellung dessen, was der Autor geschrieben hat, anstelle eines Memos, das der Autor noch nicht vollständig erfasst hat. Ich werde den Inhalt des Pytorch-Tutorials + den in α untersuchten Inhalt zusammenfassen.

Diesmal ist Kapitel 1.

Einführung

Erfahren Sie mehr über die Installation und die grundlegenden Ebenen von CNN.

Bei Berechnung in einer großen Dimension wie einer 32 × 32-Matrix Es ist schwer vorstellbar, welche Art von Berechnung durchgeführt wird Ich habe den tatsächlichen Code anhand eines einfachen Beispiels berechnet und versucht, einige Formeln einzuschließen. Wir streben ein intuitives Erfassen an.

1-Installieren

https://pytorch.org/

Wählen Sie Ihre PC-Umgebung unter der obigen URL aus und führen Sie den Befehl [Diesen Befehl ausführen] aus.

1-0. Versuchen Sie zum ersten Mal zu berühren

Lassen Sie uns die Matrix auf die gleiche Weise wie numpy ausgeben. https://pytorch.org/tutorials/beginner/blitz/tensor_tutorial.html#sphx-glr-beginner-blitz-tensor-tutorial-py

test.py


x = torch.empty(5, 3)
print(x)
#Ausführungsergebnis
tensor([[1.9349e-19, 4.5445e+30, 4.7429e+30],
        [7.1354e+31, 7.1118e-04, 1.7444e+28],
        [7.3909e+22, 4.5828e+30, 3.2483e+33],
        [1.9690e-19, 6.8589e+22, 1.3340e+31],
        [1.1708e-19, 7.2128e+22, 9.2216e+29]])

Es sieht aus wie Numpy.

1-1 Gradient

Durch Setzen von $ require_grad $ scheint es, dass der Gradient an einem bestimmten Punkt erhalten werden kann.

test.py


x = torch.tensor([1.0, 2.0], requires_grad=True)

Lassen Sie uns als Beispiel den Gradienten für die Funktion der folgenden beiden Variablen ermitteln.

f(x,y)=2x + y^2\\

Die Formel für den Gradienten lautet wie folgt.

\frac
{\partial f}
{\partial x}
=
2\\
\frac
{\partial f}
{\partial y}
=
2y\\

Aus der obigen Gleichung ist ersichtlich, dass der Gradient in der $ x $ -Richtung durch 2 und der Gradient in der $ y $ -Richtung durch 2y bestimmt wird. Der Gradient am Punkt (x, y) = (1,2) beträgt (2,4) aus dem Folgenden.

\frac
{\partial f}
{\partial x}
=
2\\
\frac
{\partial f}
{\partial y}
=
2*2=4\\

Es ist require_grad, das die Berechnung durchführt. Folgendes habe ich mit Pytorch gemacht:

test.py


from __future__ import print_function
import torch

#Vorbereitung des Berechnungspunktes
z = torch.tensor([1.0, 2.0], requires_grad=True)

# f(z)Vorbereitung von
f = z[0]*2 + z[1]**2

#Differenzierung durchführen
f.backward()

print(z.grad)
#Ausführungsergebnis
tensor([2., 4.])

1-2. Neutrales Netzwerk

https://pytorch.org/tutorials/beginner/blitz/neural_networks_tutorial.html Das Netzwerk wird im nächsten Abschnitt des Tutorials definiert.

test.py


import torch
import torch.nn as nn
import torch.nn.functional as F


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        # 1 input image channel, 6 output channels, 3x3 square convolution
        # kernel
        self.conv1 = nn.Conv2d(1, 6, 3)
        self.conv2 = nn.Conv2d(6, 16, 3)
        # an affine operation: y = Wx + b
        self.fc1 = nn.Linear(16 * 6 * 6, 120)  # 6*6 from image dimension
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        # If the size is a square you can only specify a single number
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        x = x.view(-1, self.num_flat_features(x))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

    def num_flat_features(self, x):
        size = x.size()[1:]  # all dimensions except the batch dimension
        num_features = 1
        for s in size:
            num_features *= s
        return num_features


net = Net()
print(net)
params = list(net.parameters())
print(len(params))
print(params[0].size())  # conv1's .weight
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
net.zero_grad()
out.backward(torch.randn(1, 10))

Selbst wenn Sie es plötzlich ausführen, wird es "?" Sein. Schauen wir uns also den Inhalt einzeln an.

Klassenvererbung

test.py


class Net(nn.Module):
    def __init__(self):
    #Definieren Sie jede Ebene
    def forward(self, x):
    #Führen Sie die Verarbeitung für jede Schicht durch

Durch Erben der Klasse nn.Module Es scheint, dass Sie die Netzwerkkonfiguration frei definieren können.

Definieren Sie jede Ebene zum Zeitpunkt der Initialisierung der Klasse durch init. Rufen Sie die durch forward definierte Schicht auf, um die Hauptverarbeitung von CNN aufzurufen.

Als tatsächlicher Fluss, Die Weiterleitung wird ausgeführt, wenn die von Ihnen definierte Instanz der Klasse erstellt wird.

Weiterleitung

Die Hauptverarbeitung ist der Verarbeitungsinhalt von Forward. Lassen Sie uns die Beispielquelle zerlegen und jede Schicht einzeln betrachten. (Ich werde die Erklärung der Aktivierungsfunktion überspringen)

test.py


    def forward(self, x):
        # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        # If the size is a square you can only specify a single number
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        x = x.view(-1, self.num_flat_features(x))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

↓↓↓↓↓↓↓↓↓↓↓↓↓

        max_pool2d :Pooling-Schicht
        Conv2d     :Faltschicht
        Linear     :Vollständig verbundene Schicht

Pooling-Schicht (Pooling-Schicht)

Versuchen Sie, max_pool2d alleine auszuführen.

test.py


import torch
import torch.nn as nn
import numpy as np
import torch.nn.functional as F


class Test_Pooling(nn.Module):

    def __init__(self):
        super(Test_Pooling, self).__init__()
    def forward(self, x):
        print("Before")
        print("size : \t",x.size())
        print("data : \n",x.to('cpu').detach().numpy().copy())
        print("\n")

        x = F.max_pool2d(x, (2, 2))
        print("After")
        print("size : \t",x.size())
        print("data : \n",x.to('cpu').detach().numpy().copy())
        print("\n")
        return x

net = Test_Pooling()

#Eingang
nparr = np.array([1,2,3,4]).astype(np.float32).reshape(2,2)
nparr = np.block([[nparr,nparr],[nparr,nparr]]).reshape(1,1,4,4)
input = torch.from_numpy(nparr).clone()

#Ausgabe
out = net(input)

#Ausführungsergebnis
Before
size : 	 torch.Size([1, 1, 4, 4])
data : 
 [[[[1. 2. 1. 2.]
   [3. 4. 3. 4.]
   [1. 2. 1. 2.]
   [3. 4. 3. 4.]]]]


After
size : 	 torch.Size([1, 1, 2, 2])
data : 
 [[[[4. 4.]
   [4. 4.]]]]

Die Eingabedaten sind wie folgt.

input = \begin{pmatrix}
1 & 2 & 1 & 2\\
3 & 4 & 3 & 4\\
1 & 2 & 1 & 2\\
3 & 4 & 3 & 4\\
\end{pmatrix}\\

Die Operation von max_pool2d liegt innerhalb des durch das Argument angegebenen Bereichs von (2,2). Extrahiert den Maximalwert und gibt den Wert als Matrix zurück. Wenn es auf die obige Eingabematrix angewendet wird, wird es für die Submatrix 1, 2, 3 und 4 ausgeführt. Infolgedessen wird (2,2) ausgegeben, in dem vier 4er angeordnet sind.

Es gibt zwei Hauptzwecke für das Pooling.

1.Dimensionsreduzierung
2.Sicherstellung der Invarianz von Bewegung und Rotation

Eine ist die Reduzierung der Abmessungen. Wie Sie sehen können, wurden die 16 Zahlen auf 4 reduziert. Wenn Sie daran denken, Hunderte von Bildern zu verarbeiten, können Sie damit rechnen, die Verarbeitung um ein Vielfaches gleichzeitig zu verkürzen. (Da die reduzierte Informationsmenge verloren geht, Wie viel Pooling durchgeführt werden kann, hängt vom jeweiligen Artikel ab. )

Der andere ist unveränderlich. Dies kann natürlich passieren, wenn das Eingabebild gedreht oder falsch ausgerichtet ist. Pooling scheint etwas zu sein, das auch in solchen Fällen bis zu einem gewissen Grad garantieren kann.

Zum Beispiel ein Array von Pixeln in einem Graustufenbild Einerseits $ (0,0,0,0,1,2,3,4,5,1,2) $, Der andere ist $ (0,1,2,3,4,5,1,2,3,4,5) $ Betrachtet man den Fall, in dem ein Bild dasselbe zeigt, aber seitwärts verschoben ist.

Wenn das maximale Pooling im horizontal langen Bereich von (1,12) durchgeführt wird, (5) wird in beiden Bildern ausgegeben und "beide zeigen den gleichen numerischen Wert", d. H. Unabhängig von der Bewegung des Bildes können Hinweise auf das Merkmal gefunden werden.

(... Ich schrieb, dass ich untersucht habe, aber unabhängig vom Zweck von 1, Wie effektiv kann 2 tatsächlich erwartet werden? Ich habe den Eindruck, dass das Bild etwas unzuverlässig ist. (Wie auch immer, wenn die Punkte nicht in Ordnung sind)

Conv-Schicht (Faltschicht) Teil 1

Organisieren Sie das Bild der Faltung und welche Art von Berechnung tatsächlich durchgeführt wird.

Was ist "Falten"? Haben Sie keine Angst, durch Falten falsch zu verstehen Es ist eine Erkenntnis, dass es getan wird, um den charakteristischen Teil hervorzuheben und zu extrahieren.

GUID-11A815E1-3652-461E-8C76-56B7DCBF28FD-web.png

Zum Beispiel ein 5x5-Filter, der als Laplace-Filter bezeichnet wird Die Faltintegration erzeugt ein Bild mit hervorgehobenen Kanten, wie im obigen Bild. Die Eigenschaften des Randteils werden hervorgehoben und extrahiert. (Referenz: https://desktop.arcgis.com/ja/arcmap/10.3/manage-data/raster-and-images/convolution-function.htm)

In Bezug darauf, welche Art von Berechnung als Berechnungsformel durchgeführt wird, Es ist schwer zu verstehen, ob es sich um Sprachverarbeitung handelt, aber es ist visuell leicht zu verstehen, wenn es sich um ein Bild handelt. (↓) no_padding_no_strides.gif

Im Falle der Faltung des Bildbereichs für die Pixel des Zielbildes (blaue Matrix) Wie im obigen Video gezeigt, wird zur Berechnung der "Kernel" (grüne Matrix) angewendet.

img112.png

Als Berechnung wird im Beispiel des obigen Bildes Wenden Sie den Kernel um [1 Pixel von (2,2) in [Eingabedaten] an.

(1*2)+(2*0)+(3*1)+(0*0)+(1*1)+(2*2)+(3*1)+(0*0)+(1*2)=15

Und fügen Sie diejenigen hinzu, die sich an derselben Position befinden, multipliziert miteinander. Wenn Sie im gezeigten Beispiel versuchen, einen 3x3-Filter ohne Lücken einzubauen, 4x4 [Ausgabedaten] wird berechnet.

Während Sie also mit der darauf basierenden Quelle spielen, Werfen wir einen Blick auf die Berechnung.

test.py



class Test_Conv(nn.Module):

    kernel_filter = None
    def __init__(self):
        super(Test_Conv, self).__init__()
        # self.conv = nn.Conv2d(1, 1, 3)
        ksize = 4
        self.conv = nn.Conv2d(
            in_channels=1,
            out_channels=1,
            kernel_size=4,
            bias=False)
        self.kernel_filter = self.conv.weight.data.numpy().reshape(ksize,ksize)

    def forward(self, x):
        print("Before")
        print("size : \t",x.size())
        print("data : \n",x.to('cpu').detach().numpy().copy())
        print("\n")

        print("Calc Self Conv")
        x_np = x.to('cpu').detach().numpy().copy().reshape(4,4)
        calc_conv = 0 ;
        for col in range(self.kernel_filter.shape[0]):
            for row in range(self.kernel_filter.shape[1]):
                calc_conv += self.kernel_filter[row][col] * x_np[row][col]
        print("kernel filter :")
        print(self.kernel_filter )
        print("data : \n",calc_conv)
        print("\n")

        x = self.conv(x)
        print("After")
        print("size : \t",x.size())
        print("data : \n",x.to('cpu').detach().numpy().copy())
        print("\n")
        return x

net = Test_Conv()

#Eingang
nparr = np.array([1,2,3,4]).astype(np.float32).reshape(2,2)
nparr = np.block([[nparr,nparr],[nparr,nparr]]).reshape(1,1,4,4)
input = torch.from_numpy(nparr).clone()

#Ausgabe
out = net(input)
exit()


Mit einem Laplace-Filter, der Kanten extrahiert, Ich habe einen festen Kernelfilter angewendet.

Der von Conv2d von pytorch automatisch erzeugte Kernelfilter ist jedoch Es scheint, dass sich der Wert bei jeder Ausführung zufällig ändert. (Es wurde nicht untersucht, welche Art von Berechnung und welche Art von Absicht conv2d diesen Filter berechnet. Ist es nicht möglich, den Filter absichtlich einzustellen? )

Das Ausgabeergebnis ist übrigens wie folgt.

#Ausführungsergebnis
Before
size : 	 torch.Size([1, 1, 4, 4])
data : 
 [[[[1. 2. 1. 2.]
   [3. 4. 3. 4.]
   [1. 2. 1. 2.]
   [3. 4. 3. 4.]]]]


Calc Self Conv
kernel filter :
[[-0.03335193 -0.05553913  0.10690624 -0.0219309 ]
 [-0.02052614  0.23662615 -0.07596081 -0.04400161]
 [ 0.19031712 -0.06902602 -0.24611491 -0.06604707]
 [-0.05149609 -0.08155683  0.06496871 -0.15480098]]
data : 
 -0.8313058316707611


After
size : 	 torch.Size([1, 1, 1, 1])
data : 
 [[[[-0.8313058]]]]


[Dara] von [Vorher] ist Eingabedaten. Dies ist die blaue Prozession in der vorherigen Animation.

Und danach]. [dara] ist das in der Faltungsschicht berechnete Ergebnis. Es heißt [-0.8313058].

Schauen wir uns als nächstes [Calc Self Conv] an. Hier habe ich die obige Berechnung von Hand versucht. Da bei der Deklaration von Conv2d kernel_size = 4 angegeben wurde, Sie sehen, dass der Kernelfilter, der der Berechnung zugrunde liegt, eine 4x4-Matrix ausgibt. Dies ist die grüne Matrix in der vorherigen Animation.

Vergleichen wir nun das Ergebnis der manuellen Berechnung mit dem Ergebnis von conv2d. Betrachtet man [Daten] in [Calc Self Conv] und [After], Sie können sehen, dass die Zahlen fast gleich sind.

Mit einem solchen Bild wird die Faltungsschicht berechnet. Beachten Sie, dass dieses Beispiel ziemlich einfach ist, um die Berechnung zu vereinfachen Ich werde das nächste Mal etwas tiefer graben.

Conv-Schicht (Faltschicht) Teil 2

Ich werde ein bisschen mehr lernen. Ich verstand irgendwie, welche Art von Berechnung die Faltung machte. Schauen wir uns als nächstes die Parameter an, die bei der Durchführung der tatsächlichen Berechnungen eine Rolle spielen.

Die folgenden Parameter sind hauptsächlich in conv2d vorhanden.

test.py


in_channels
out_channels
kernel_size
stride
padding
bias

Eine intuitive Erklärung geben Schauen wir uns den tatsächlichen Code einzeln an.

in_channels Legen Sie die Anzahl der Dimensionen pro Daten in in_channels fest.

data : 
 [[[[0. 1. 0. 1.]
   [0. 0. 0. 0.]
   [0. 1. 0. 1.]
   [0. 0. 0. 0.]]]]

Nehmen wir als Beispiel die obigen Daten. In Bezug auf Bilder sind diese Daten ein Graustufenbild, Die Anzahl der Kanäle (Anzahl der Farben) ist nur ein Datenwert. Setzen Sie für solche Daten "1". "3" für RGB 3D-Daten, Wenn Sie eine Position und RGB wie eine Punktgruppe haben, geben Sie "6" ein.

out_channels Die Anzahl der Dimensionen der Ausgabedaten wird an out_channels ausgegeben. Es wird nur die hier angegebene Anzahl von Kernelfiltern generiert. Die angegebene Anzahl von Filteranwendungsergebnissen wird zurückgegeben.

Mit anderen Worten, je mehr Dimensionen hier, desto mehr Features werden durch Filter extrahiert, die für die Anzahl der Dimensionen erstellt wurden. Merkmale mit verschiedenen Merkmalen können als Menge extrahiert werden.

Zum Beispiel Filter zur Extraktion von Tiermerkmalen, Filter, die menschliche Eigenschaften extrahieren, Ein Filter, der die Eigenschaften des Bechers extrahiert, Und hier geben Sie die Anzahl der Filter an, die verschiedene Funktionen extrahieren.

(Wenn Sie nur auf diese Erklärung hören, scheint es umso besser zu sein, je mehr Sie haben. Intuitiv, wenn Sie die Funktionen zu fein extrahieren, Auch wenn Sie detaillierte Klassifizierungen wie Herr A und Herr B vornehmen können, Ich bin der Meinung, dass Probleme wie die Unfähigkeit, sich als Menschen zu klassifizieren, wahrscheinlich auftreten werden. (Bild ohne persönliche Übung))

stride Schritt bezieht sich auf die Bewegungsbreite beim Schreiben eines Filters. no_padding_no_strides.gif In diesem Bild ist der Schritt "1", weil er sich nacheinander bewegt.

Lassen Sie uns diese Bewegung etwas mehr im Code sehen.

test.py



class Test_Conv2(nn.Module):

    kernel_filter = None
    def __init__(self):
        super(Test_Conv2, self).__init__()
        self.conv = nn.Conv2d(
            in_channels=1,
            out_channels=2,
            kernel_size=2,
            stride=2,
            padding=0,
            bias=False)
        self.kernel_filter = self.conv.weight.data.numpy()

    def forward(self, x):
        print("Before")
        print("size : \t",x.size())
        print("data : \n",x.to('cpu').detach().numpy().copy())
        print("\n")

        print("Calc Self Conv")
        print("kernel filter :")
        print(self.kernel_filter )
        print("\n")

        x = self.conv(x)
        print("After")
        print("size : \t",x.size())
        print("data : \n",x.to('cpu').detach().numpy().copy())
        print("\n")
        return x

net = Test_Conv2()

#Eingang
nparr = np.array([0,1,0,0]).astype(np.float32).reshape(2,2)
nparr = np.block([[nparr,nparr],[nparr,nparr]]).reshape(1,1,4,4)
input = torch.from_numpy(nparr).clone()

#Ausgabe
out = net(input)
exit()
#Ausführungsergebnis
Before
size : 	 torch.Size([1, 1, 4, 4])
data : 
 [[[[0. 1. 0. 1.]
   [0. 0. 0. 0.]
   [0. 1. 0. 1.]
   [0. 0. 0. 0.]]]]


Calc Self Conv
kernel filter :
[[[[-0.07809174 -0.39049476]
   [-0.00448102 -0.09000683]]]


 [[[ 0.03750324  0.12070286]
   [-0.06378353  0.22772777]]]]


After
size : 	 torch.Size([1, 2, 2, 2])
data : 
 [[[[-0.39049476 -0.39049476]
   [-0.39049476 -0.39049476]]

  [[ 0.12070286  0.12070286]
   [ 0.12070286  0.12070286]]]]

Ich setze den Schritt auf "2". Da es sich zur Berechnung um zwei verschiebt, [Daten] von [Vorher] Mit [Kernelfilter] von [Calc Self Conv] Es wird multipliziert.

input = \begin{pmatrix}
0 & 1 \\
0 & 0
\end{pmatrix}\\\\

filter = \begin{pmatrix}
-0.07809174 & -0.39049476 \\
-0.00448102 & -0.09000683
\end{pmatrix}\\

Ist es tatsächlich um zwei aus? Überprüfen Sie das Ausführungsergebnis.

Die Eingabedaten sind eine Matrix, in der die obige Submatrix [Eingabe] ausgerichtet ist. Wenn Sie versuchen, den [Filter] von (2,2) auf solche Eingabedaten anzuwenden, Es wird viermal multipliziert, damit es genau zur Submatrix von [Eingabe] passt.

output = \begin{pmatrix}
-0.39049476 & -0.39049476 \\
-0.39049476 & -0.39049476
\end{pmatrix}\\

Deshalb, Da die Faltung der Submatrix [Eingabe] und der Matrix [Filter] viermal durchgeführt wird, Der numerische Wert des Filters, bei dem die Submatrix von [Eingabe] die einzige ist [1], wird viermal ausgegeben. Daher wird die Faltung als Ergebnis wie [Ausgabe] berechnet.

Von Oben, Ich denke, Sie können sehen, wie die Pixel um zwei verschoben werden und das Falten erfolgt.

padding Ich habe nichts Besonderes gesagt, aber als ich den Filter schritt, Ich erklärte unter der Annahme, dass der Filter innerhalb des Bereichs bewegt wird, der in das Bild passt.

no_padding_no_strides.gif In diesem Bild nahe der Mitte des Pixels im blauen Bild Sie filtern um (1,1) (1,2) (2,1) (2,2).

Wenn ich versuche, den Filter auf die obere linke Position von (0,0) anzuwenden, Es ist zu erwarten, dass sich der obere Teil nicht überlappt und keine Berechnung möglich ist.

Der zentrale Teil des Bildes wird gleichmäßig gefiltert Der Bildrand ist ungefiltert, Mit anderen Worten, dies ist ein Zustand, in dem die Merkmale des Randteils nicht extrahiert wurden.

Durch Hinzufügen einer virtuellen Spalte / Zeile von [0] an beiden Enden und Berechnen von Die Idee der "Polsterung" besteht darin, auch den Randteil zu berechnen.

1_1VJDP6qDY9-ExTuQVEOlVg.gif

bias Es werden lediglich allen Elementen der Ausgabe Werte hinzugefügt.

Wird es verwendet, um die Überlegenheit oder Unterlegenheit der Wichtigkeit für jeden Filter zu bestimmen?

Oder umgekehrt, etwas, das nur kleine Funktionen aufnehmen kann Gibt es so etwas wie eine Vergrößerung, um es wie jedes andere Feature zu behandeln?

Ausgabeergebnis

Die Dimension des Ausgabeergebnisses der Faltung ändert sich je nach Parameter. Mal sehen, wie sich die Dimensionen basierend auf den Parametern von conv2d ändern.

test.py


in_channels
out_channels
kernel_size
stride
padding
bias

Beispiel 1 Eingabedaten = (Dimension = 1, (4 × 4))) / Kernelgröße = 2 / Auffüllen = 0


in_channels=1\\
out_channels=1\\
kernel_size=2\\
stride=2\\
padding=0\\
bias=0\\
\\
\\
input = \begin{pmatrix}
0 & 1 & 0 & 1\\
0 & 0 & 0 & 0\\
0 & 1 & 0 & 1\\
0 & 0 & 0 & 0
\end{pmatrix}\\\\

filter = \begin{pmatrix}
-0.07809174 & -0.39049476 \\
-0.00448102 & -0.09000683
\end{pmatrix}\\

In diesem Fall nimmt der Filter von (2,2) die Eingabedaten von (4,4). Bewegen Sie sich zwei mal zwei und gehen Sie genau weiter. Das Ausgabeergebnis ist 2x2.

Beispiel 2 Eingabedaten = (Dimension = 1, (4 × 4))) / Kernelgröße = 3 / Auffüllen = 0

in_channels=1\\
out_channels=1\\
kernel_size=3\\
stride=2\\
padding=0\\
bias=0\\
\\
\\
input = \begin{pmatrix}
0 & 1 & 0 & 1\\
0 & 0 & 0 & 0\\
0 & 1 & 0 & 1\\
0 & 0 & 0 & 0
\end{pmatrix}\\\\

filter = \begin{pmatrix}
-0.41127872
\end{pmatrix}\\

In diesem Fall verschiebt der Filter (3,3) die Eingangsdaten von (4,4) um zwei. Da es von oben links berechnet wird, werden die Eingabedaten auf die Position (1,1) zentriert. Der Filter ist gefaltet.

Da der Schritt von dort 2 ist, wenn Sie 2 zur Seite verschieben, Die Mittelposition der nächsten Berechnung ist (1,3). Weil es ganz rechts ist Alle Filter passen nicht.

Da es sich in vertikaler Richtung um 2 verschiebt, Selbst wenn der Schrittvorgang wiederholt wird, wird er daher nur einmal gefaltet. Daher gibt es nur ein Ergebnis.

Beispiel 2 Eingabedaten = (Dimension = 1, (4 × 4))) / Kernelgröße = 3 / Auffüllen = 1

in_channels=1\\
out_channels=1\\
kernel_size=3\\
stride=2\\
padding=1\\
bias=0\\
\\
\\
input = \begin{pmatrix}
0 & 0 & 0 & 0 & 0 & 0\\
0 & 0 & 1 & 0 & 1 & 0\\
0 & 0 & 0 & 0 & 0 & 0\\
0 & 0 & 1 & 0 & 1 & 0\\
0 & 0 & 0 & 0 & 0 & 0\\
0 & 0 & 0 & 0 & 0 & 0\\
\end{pmatrix}\\\\

filter = \begin{pmatrix}
0.08725476 & 0.4106578  \\
0.08725476 & 0.4106578 \\
\end{pmatrix}\\

0s wurden an jedem Ende mit einer Zeile / Spalte aufgefüllt. Basierend auf der oberen linken Ecke, wenn Sie an der Position berechnen, an der der 3x3-Filter passt, Sie wird viermal um (1,1) (1,3) (3,1) (3,3) berechnet. Daher ist das Ausgabeergebnis 2x2.

Lineare Schicht (vollständig verbundene Schicht)

Vollständig verbundene Schicht.

Es ist sehr einfach, Verschiedene Merkmale, die durch die Faltschicht usw. extrahiert werden. Lass es uns zusammenstellen? Ich mache das

Wenn Sie es in einem Bild ohne Angst vor Missverständnissen sagen "Rotes Quadrat". Stellen Sie sich den Fall vor, in dem Sie versuchen, zwischen "blauem Quadrat" und "anders als das" zu unterscheiden.

Selbst wenn Sie nur die Eigenschaften des Quadrats extrahieren, können Sie nicht zwischen Rot und Blau unterscheiden. Sie müssen auch die Farbeigenschaften anpassen.

Daher ist es notwendig, die Eigenschaften des Quadrats, die Eigenschaften der Farbe und mehrere Eigenschaften zu kombinieren. Ich erkenne es als eine vollständig verbundene Schicht.

y = xA^T \\

Die Berechnung, die ich mache, ist einfach, Wenden Sie die lineare Transformation $ A $ auf die Eingabe $ x $ an. Berechnen Sie einfach $ y $ als Ausgabe.

y = xA^T \\
⇔\\

\begin{pmatrix}
y_1 \\
y_2 \\
\end{pmatrix}
=
\begin{pmatrix}
A_{00} & A_{01} \\
A_{10} & A_{11} \\
\end{pmatrix}

\begin{pmatrix}
x_1 \\
x_2 \\
\end{pmatrix}\\
⇔\\


\begin{pmatrix}
y_1 =  A_{00} x_1 + A_{01}x_2\\
y_2 =  A_{10} x_1 + A_{11}x_2 \\
\end{pmatrix}\\

Ich werde eine etwas intuitivere Erklärung versuchen. Die obige Gleichung ist die Erweiterung der vorherigen Gleichung für kleine zweidimensionale Daten. Eingabedaten $ x $ ist ein numerischer Wert, der durch Extrahieren von Features aus einem Bild erhalten wird. Die Formel hat Werte von $ x_1 $ und $ x_2 $. Lernen Sie dies aus dem vorherigen Beispiel. "Ergebnisse des Extrahierens quadratischer Merkmale aus Bildern" "Ergebnisse des Extrahierens von Farbmerkmalen aus Bildern" Wird besorgt.

Wie oben erwähnt, jeder für sich Ich weiß nicht, ob es ein rotes oder ein blaues Quadrat ist. Sie müssen auch das Ergebnis sehen.

Basierend darauf, mit Blick auf die endgültige Formel, Sie können sehen, dass $ x_1 $ und $ x_2 $ integriert sind.

Zur Zeit sehe ich die Operation im Code.

test.py



class Test_Linear(nn.Module):

    fc_filter = None
    def __init__(self):
        super(Test_Linear, self).__init__()
        self.conv = nn.Conv2d(
            in_channels=1,
            out_channels=2,
            kernel_size=4,
            stride=2,
            padding=0)
        self.kernel_filter = self.conv.weight.data.numpy()
        self.fc = nn.Linear(in_features=1,
                            out_features=1,
                            bias=False)
        self.fc_filter = self.fc.weight.data.numpy()
        print(self.fc_filter)

    def forward(self, x):
        nparr = np.array( [[[[1.0]],[[100.0]]]]).astype(np.float32)
        input = torch.from_numpy(nparr).clone()
        x = input

        print("Before")
        print("size : \t",x.size())
        print("data : \n",x.to('cpu').detach().numpy().copy())
        print("\n")

        x = self.fc(x)

        print("After Linear")
        print("size : \t",x.size())
        print("data : \n",x.to('cpu').detach().numpy().copy())

        print("\n")
        return x
net = Test_Linear()

#Eingang
nparr = np.array([0,1,0,0]).astype(np.float32).reshape(2,2)
nparr = np.block([[nparr,nparr],[nparr,nparr]]).reshape(1,1,4,4)
input = torch.from_numpy(nparr).clone()

#Ausgabe
out = net(input)
exit()

#Ausführungsergebnis
[[0.04909718]]
Before
size : 	 torch.Size([1, 2, 1, 1])
data : 
 [[[[  1.]]

  [[100.]]]]


After Linear
size : 	 torch.Size([1, 2, 1, 1])
data : 
 [[[[0.04909718]]

  [[4.909718  ]]]]


Es ist wahnsinnig einfach. A=[0.04909718] x=[1,100]^T Wird nach $ y = xA ^ T $ berechnet y=[0.04909718,4.909718]^T Wird nur ausgegeben.

Übrigens, als out_features = 2, Wenn Sie die Ausgabedimension erhöhen,

#Ausführungsergebnis
[[-0.5130856]
 [ 0.6920992]]
Before
size : 	 torch.Size([1, 2, 1, 1])
data : 
 [[[[  1.]]

  [[100.]]]]


After Linear
size : 	 torch.Size([1, 2, 1, 2])
data : 
 [[[[ -0.5130856   0.6920992]]

  [[-51.30856    69.20992  ]]]]


Eine weitere Dimension von A, A=[-0.5130856,0.6920992] Nächster, Die Ausgabe $ y $ wird auch in Form des Hinzufügens zum vorherigen Ergebnis ausgegeben.

Bisherige Inhaltszusammenfassung

https://pytorch.org/tutorials/beginner/blitz/neural_networks_tutorial.html Die Netzwerkkonfiguration in der Pytorch-Beispielquelle, Wenn Sie den Durchfluss grob analysieren,

    1. Extrahieren Sie die Merkmale mit der Faltschicht.
  1. Organisieren Sie die von der Pooling-Ebene und der Aktivierungsfunktion extrahierten Funktionen (auf dieser Seite nicht erwähnt).
    1. Eventuell an der Klebeschicht integriert Sie können sehen, dass es der Fluss ist.

Mit den bisherigen Inhalten konnten wir die Funktionen numerisch erfassen. Dies allein kann jedoch keine Identifikationsverarbeitung durchführen.

Wenn Sie den Inhalt bisher verwenden, Sie können die Eigenschaften von Herrn A und Herrn B erhalten, Wenn jemand ankommt, der A oder B nicht kennt Es muss beurteilt werden, ob das Merkmal der nicht identifizierten Person A oder B ist.

1-2. Verlustfunktion

Features können bereits mit den bisher beschriebenen Netzwerken extrahiert werden. Versuchen wir uns mit einem einfachen Beispiel zu identifizieren.

test.py



class Test_Conv(nn.Module):

    kernel_filter = None
    def __init__(self):
        super(Test_Conv, self).__init__()
        # self.conv = nn.Conv2d(1, 1, 3)
        ksize = 4
        self.conv = nn.Conv2d(
            in_channels=1,
            out_channels=1,
            kernel_size=4,
            bias=False)
        self.kernel_filter = self.conv.weight.data.numpy().reshape(ksize,ksize)

    def forward(self, x):
        x = self.conv(x)
        return x


net = Test_Conv()

#Eingang
nparr = np.array([0,1,0,0]).astype(np.float32).reshape(2,2)
nparr = np.block([[nparr,nparr],[nparr,nparr]]).reshape(1,1,4,4)
input = torch.from_numpy(nparr).clone()
print("*****Lernphase*****")
print("Eingabedaten für das Netzwerklernen")
print(input)
print("\n")
#Ausgabe
out = net(input)

#Zieleingabe#Geben Sie die gleichen Daten ein
out_target1 = net(input)
criterion = nn.MSELoss()
loss = criterion(out, out_target1)
print("*****Bewertungsphase*****")
print("Geben Sie die gleichen Daten ein")
print("input:")
print(input)
print("Auswertung",loss)
print("\n")

#Zieleingabe#Geben Sie etwas andere Daten ein
nparr2 = np.array([0,2,0,0]).astype(np.float32).reshape(2,2)
nparr2 = np.block([[nparr2,nparr2],[nparr2,nparr2]]).reshape(1,1,4,4)
input2 = torch.from_numpy(nparr2).clone()
out_target2 = net(input2)

criterion = nn.MSELoss()
loss = criterion(out, out_target2)
print("Geben Sie etwas andere Daten ein")
print("input:")
print(input2)
print("",loss)
print("\n")

##
nparr3 = np.array([10,122,1000,200]).astype(np.float32).reshape(2,2)
nparr3 = np.block([[nparr3,nparr3],[nparr3,nparr3]]).reshape(1,1,4,4)
input3 = torch.from_numpy(nparr3).clone()
out_target3 = net(input3)

criterion = nn.MSELoss()
loss = criterion(out, out_target3)
print("")
print("input:")
print(input3)
print("",loss)
print("\n")



#
*****Zieleingabe Eingabe völlig unterschiedlicher Daten Eingabe völlig unterschiedlicher Daten Bewertung Ausführungsergebnis Lernphase*****
Eingabedaten für das Netzwerklernen
tensor([[[[0., 1., 0., 1.],
          [0., 0., 0., 0.],
          [0., 1., 0., 1.],
          [0., 0., 0., 0.]]]])


*****Bewertungsphase*****
Geben Sie die gleichen Daten ein
input:
tensor([[[[0., 1., 0., 1.],
          [0., 0., 0., 0.],
          [0., 1., 0., 1.],
          [0., 0., 0., 0.]]]])
Bewertungstensor(0., grad_fn=<MseLossBackward>)


Geben Sie etwas andere Daten ein
input:
tensor([[[[0., 2., 0., 2.],
          [0., 0., 0., 0.],
          [0., 2., 0., 2.],
          [0., 0., 0., 0.]]]])
Bewertungstensor(0.4581, grad_fn=<MseLossBackward>)


Geben Sie ganz andere Daten ein
input:
tensor([[[[  10.,  122.,   10.,  122.],
          [1000.,  200., 1000.,  200.],
          [  10.,  122.,   10.,  122.],
          [1000.,  200., 1000.,  200.]]]])
Bewertungstensor(58437.6680, grad_fn=<MseLossBackward>)

Ich habe nichts zu erklären,

out = net(input)
out_target3 = net(input3)

Geben Sie alle Eingabedaten in das erstellte Netzwerk ein, um die Eigenschaften zu berechnen. (Out, out_target3 enthält die von conv2d berechnete Matrix.)

#Bewertungsmethode definieren
criterion = nn.MSELoss()
#Evaluierungsausführung
loss = criterion(out, out_target3)

Die Bewertungsmethode wird definiert (hier der durchschnittliche quadratische Fehler) und bewertet. Wenn die Features nahe beieinander liegen, liegt der Wert nahe bei 0, Je weiter die Funktion entfernt ist, desto größer ist der Wert.

Recommended Posts

[Super Einführung in das maschinelle Lernen] Lernen Sie Pytorch-Tutorials
Super Einführung in das maschinelle Lernen
Einführung in das maschinelle Lernen
Eine Einführung in das maschinelle Lernen
Einführung in das maschinelle Lernen Schreiben von Notizen
Einführung in die Bibliothek für maschinelles Lernen SHOGUN
Maschinelles Lernen mit Nogisaka 46 und Keyakizaka 46 Teil 1 Einführung
Pytorch super Einführung
Einführung in das maschinelle Lernen: Funktionsweise des Modells
Eine Einführung in OpenCV für maschinelles Lernen
Eine Einführung in Python für maschinelles Lernen
[Python] Einfache Einführung in das maschinelle Lernen mit Python (SVM)
Eine Einführung in maschinelles Lernen für Bot-Entwickler
Einführung in Lightning Pytorch
Lerne irgendwie maschinelles Lernen
PyTorch Super Einführung PyTorch-Grundlagen
[Für Anfänger] Einführung in die Vektorisierung beim maschinellen Lernen
[Super Einführung] Maschinelles Lernen mit Python - Von der Umgebungskonstruktion bis zur Implementierung von Simple Perceptron-
Site-Zusammenfassung zum Erlernen des maschinellen Lernens mit englischen Videos
Einführung in das maschinelle Lernen mit Simple Perceptron
[Lernmemorandum] Einführung in vim
Einführung in PyTorch (1) Automatische Differenzierung
Eine super Einführung in Linux
Maschinelles Lernen Minesweeper mit PyTorch
Einführung in Deep Learning ~ Lernregeln ~
Tiefe Stärkung des Lernens 1 Einführung in die Stärkung des Lernens
Einführung in Deep Learning ~ Backpropagation ~
MS Learn Recommended Learning Pass Februar-Ausgabe [Einführung in AI]
Einführung in das maschinelle Lernen mit scikit-learn-Von der Datenerfassung bis zur Parameteroptimierung
Supereinführung des maschinellen Lernens Probabilistisches Modell und wahrscheinlichste Schätzung
Einführung in das tiefe Lernen ~ Funktionsnäherung ~
[Details (?)] Einführung in Pytorch ~ CNN von CIFAR10 ~
Einführung in Deep Learning ~ Codierungsvorbereitung ~
Einführung in Deep Learning ~ Dropout Edition ~
Einführung in Deep Learning ~ Forward Propagation ~
Einführung in Deep Learning ~ CNN Experiment ~
Sammeln von Daten zum maschinellen Lernen
Python-Lernnotiz für maschinelles Lernen von Chainer Kapitel 8 Einführung in Numpy
Einführung in die Python-Grundlagen des maschinellen Lernens (unbeaufsichtigtes Lernen / Hauptanalyse)
Vor der Einführung in das maschinelle Lernen. ~ Techniken, die für anderes maschinelles Lernen als maschinelles Lernen erforderlich sind ~
Python-Lernnotiz für maschinelles Lernen von Chainer Kapitel 10 Einführung in Cupy
[Einführung in Style GAN] Einzigartiges Lernen von Animation mit Ihrer eigenen Maschine ♬
Python-Lernnotiz für maschinelles Lernen von Chainer Kapitel 9 Einführung in das Scikit-Lernen
Verbessertes Lernen, um von null bis tief zu lernen
Notieren Sie die Schritte zum Verständnis des maschinellen Lernens
[Einführung in das maschinelle Lernen] Bis Sie den Beispielcode mit Chainer ausführen
Python Bit Arithmetic Super Einführung
Ich habe Python 3.5.1 installiert, um maschinelles Lernen zu studieren
Einführung in Deep Learning ~ Falten und Pooling ~
[PyTorch] Einführung in die Dokumentklassifizierung mit BERT
Maschinelles Lernen
[Einführung in Pytorch] Ich habe mit sinGAN ♬ gespielt
Python-Anfänger veröffentlichen Web-Apps mit maschinellem Lernen [Teil 2] Einführung in explosives Python !!
Maschinelles Lernen mit Pytorch in Google Colab
Wie man Coursera / Maschinelles Lernen genießt (Woche 10)
Einführung in das maschinelle Lernen - Hard Margin SVM Edition-
"OpenCV-Python Tutorials" und "Praktisches maschinelles Lernsystem"
Einführung in TensorFlow - Erläuterung der Begriffe und Konzepte des maschinellen Lernens
[Maschinelles Lernen] Regressionsanalyse mit Scicit Learn