Ich lese ein Meisterwerk, ** "Deep Learning from Zero" **. Diesmal ist ein Memo von Kapitel 7. Um den Code auszuführen, laden Sie den gesamten Code von Github herunter und verwenden Sie das Jupiter-Notizbuch in Kapitel 07.
Ich werde ein Beispiel implementieren, um ** Convolution, Pooling **, das ich im Lehrbuch studiert habe, tatsächlich zu bewegen. Die verwendeten Daten sind MNIST und die Gewichte des Faltungsfilters werden gelernt (params.pkl wird im Ordner ch07 gespeichert). Der Code für Convolution and Pooling wird aus common / layer.py importiert und verwendet.
Lassen Sie es uns zuerst ausführen.
import sys, os
sys.path.append(os.pardir) #Einstellungen zum Importieren von Dateien in das übergeordnete Verzeichnis
import numpy as np
import matplotlib.pyplot as plt
from simple_convnet import SimpleConvNet
from common.layers import * #Ebenenimport
from dataset.mnist import load_mnist
#Anzeigefunktion(FH, FW)
def show(filters):
FH, FW = filters.shape
fig = plt.figure(figsize=(FH*0.1, FW*0.1)) #Anzeige der Größenangabe
plt.imshow(((filters)), cmap='gray')
plt.tick_params(left=False, labelleft=False, bottom=False, labelbottom=False) #Löschen Sie die Achsenskala / Beschriftung
plt.show()
#MNIST-Daten lesen
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)
x_train = x_train[5:6] #Wählen Sie die 5. Daten von Anfang an
#Gelernte Parameter laden
network = SimpleConvNet() #Instanziieren Sie SimpleConvNet
network.load_params("params.pkl") #Lesen Sie den gesamten Parameter
W1, b1 = network.params['W1'][:1], network.params['b1'][:1] #Nur der erste
#Schichterzeugung
conv = Convolution(W1, b1, stride=1, pad=0)
pool = Pooling(pool_h=2, pool_w=2, stride=2, pad=0)
#Vorwärtsausbreitung
out1 = conv.forward(x_train) #Falten
out2 = pool.forward(out1) #Pooling
#Anzeige
print('input.shape = ',x_train.shape)
show(x_train.reshape(28, 28))
print('filter.shape = ', W1.shape)
show(W1.reshape(5, 5))
print('convolution.shape = ', out1.shape)
show(out1.reshape(24, 24))
print('pooling.shape = ', out2.shape)
show(out2.reshape(12, 12))
Das MNIST-Bild (1, 1, 28, 28) wird mit Filter 5 * 5 gefaltet, Auffüllen = 0, Schritt = 1, und die Daten von (1, 1, 24, 24) werden weiter zu Filter 2 * 2 hinzugefügt, Auffüllen = 0, Das Pooling erfolgt mit Schritt = 2 (1, 1, 12, 12) und die Daten werden erhalten.
Schauen wir uns nun die wichtigsten Punkte des Codes an.
3.Convolution
# ------------- from common_layers.py -------------
def forward(self, x):
FN, C, FH, FW = self.W.shape
N, C, H, W = x.shape
out_h = 1 + int((H + 2*self.pad - FH) / self.stride)
out_w = 1 + int((W + 2*self.pad - FW) / self.stride)
#① Konvertieren Sie Bilddaten mit im2col in Matrixdaten
col = im2col(x, FH, FW, self.stride, self.pad)
#② Formen Sie den Filter neu und erweitern Sie ihn zu einem zweidimensionalen Array
col_W = self.W.reshape(FN, -1).T
#③ Berechnen Sie die Ausgabe durch Matrixberechnung
out = np.dot(col, col_W) + self.b
#④ Passen Sie die Form der Ausgabe an
out = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)
self.x = x
self.col = col
self.col_W = col_W
return out
Ein Diagramm, das zeigt, wie ein 4-dimensionales Bild (Stapelgröße, Anzahl der Kanäle, Bildhöhe, Bildbreite) durch die Faltungsoperation verarbeitet wird, sieht folgendermaßen aus. Werfen wir einen Blick auf die wichtigste Funktion ** ① im2col **.
4.im2col
# ------------- from common_layers.py -------------
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
N, C, H, W = input_data.shape
out_h = (H + 2*pad - filter_h)//stride + 1
out_w = (W + 2*pad - filter_w)//stride + 1
img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))
# 24*24 Filter 5*5 mal schneiden(stride=Wenn 1)
for y in range(filter_h): #5 Schleifen
y_max = y + stride*out_h # y_max = y + 24
for x in range(filter_w): #5 Schleifen
x_max = x + stride*out_w # x_max = x + 24
#y bis y+Bis zu 24,x bis x+Bis zu 24、スライシング
col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]
col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)
return col
"y: y_max: Schritt, x: x_max: Schritt" bedeutet, dass der Bereich von y bis y_max für jeden Schritt angegeben wird und der Bereich von x bis x_max für jeden Schritt angegeben wird.
Mit y_max = y + 24, x_max = x + 24, Schritt = 1 ist jede for-Schleife 5-mal eine Doppelschleife, sodass Sie am Ende 5 * 5-mal mit einem ** 24 * 24-Filter ** schneiden.
Auf der anderen Seite sollte es, wenn man bedenkt, was ich im Lehrbuch gelernt habe, 24 * 24-mal das Schneiden ** mit dem ** 5 * 5-Filter sein. Wenn Sie daraus einen Code machen, sieht es so aus.
# 5*24 mit 5 Filtern*24 mal schneiden(stride=Wenn 1)
for y in range(0, out_h, stride):
for x in range(0, out_w, stride):
col[:, :, y, x, :, :] = img[:, :, y:y+filter_h, x:x+filter_w]
In der Tat ist die Gesamtzahl der Elemente, die vom ** 24 * 24-Filter 5 * 5-fach geschnitten ** und vom ** 5 * 5-Filter 24 * 24-fach geschnitten ** gleich sind, gleich. Wenn die Ergebnisse gleich sind, welche ist besser? Natürlich ** der erstere **. Der Grund dafür ist, dass die Anzahl der for-Schleifen, die viel Verarbeitungszeit in Anspruch nehmen, überwiegend gering ist.
Wenn Sie die beiden Methoden in der Abbildung zeigen, sieht es so aus
Lassen Sie uns überprüfen, ob die Ergebnisse von beiden wirklich gleich sind. Führen Sie den folgenden Code aus, um das ursprüngliche im2col
und die Funktion my_im2col
zu visualisieren, die ** 24 * 24-mal mit einem ** 5 * 5-Filter in Scheiben schneidet, einschließlich der zu berechnenden Daten.
import sys, os
sys.path.append(os.pardir) #Einstellungen zum Importieren von Dateien in das übergeordnete Verzeichnis
import numpy as np
from dataset.mnist import load_mnist
import matplotlib.pyplot as plt
#Datenanzeigefunktion( x =Anzeigebreite, y=Anzeigehöhe, nx =Anzahl der Spalten)
def show(filters, x, y, nx, margin=1, scale=10):
FN, C, FH, FW = filters.shape
ny = int(np.ceil(FN / nx))
fig = plt.figure(figsize=(x, y))
fig.subplots_adjust(left=0, right=1.3, bottom=0, top=1.3, hspace=0.05, wspace=0.05)
for i in range(FN):
ax = fig.add_subplot(ny, nx, i+1, xticks=[], yticks=[])
ax.imshow(filters[i, 0], cmap='gray', interpolation='nearest')
plt.show()
def my_im2col(input_data, filter_h, filter_w, stride=1, pad=0):
N, C, H, W = input_data.shape
out_h = (H + 2*pad - filter_h)//stride + 1 #Ausgangshöhe
out_w = (W + 2*pad - filter_w)//stride + 1 #Ausgabebreite
img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant') #Bildauffüllung
col = np.zeros((N, C, out_h, out_w, filter_h, filter_w)) #Vorbereitung der Col-Berechnungsmatrix
# 5*24 mit 5 Filtern*24 mal schneiden(stride=Wenn 1)
for y in range(0, out_h, stride):
for x in range(0, out_w, stride):
col[:, :, y, x, :, :] = img[:, :, y:y+filter_h, x:x+filter_w]
# check1
print('col.shape after slicing = ', col.shape)
show(col.reshape(576, 1, 5, 5), x = 3.5, y = 3.5, nx = 24)
#Transponieren & umformen
col = col.transpose(0, 2, 3, 1, 4, 5).reshape(N*out_h*out_w, -1)
# check2
print('col.shape after transpose & reshape = ', col.shape)
show(col.reshape(1, 1, 25, 576), x = 18, y =3, nx=1)
return col
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
N, C, H, W = input_data.shape
out_h = (H + 2*pad - filter_h)//stride + 1 #Ausgangshöhe
out_w = (W + 2*pad - filter_w)//stride + 1 #Ausgabebreite
img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant') #Bildauffüllung
col = np.zeros((N, C, filter_h, filter_w, out_h, out_w)) #col Matrixvorbereitung zur Berechnung
# 24*24 Filter 5*5 mal schneiden(stride=Wenn 1)
for y in range(filter_h):
y_max = y + stride*out_h
for x in range(filter_w):
x_max = x + stride*out_w
col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]
# check1
print('col.shape after slicing = ', col.shape)
show(col.reshape(25, 1, 24, 24), x = 3.5, y = 3.5, nx = 5)
#Transponieren & umformen
col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)
# check2
print('col.shape after transpose & reshape = ', col.shape)
show(col.reshape(1, 1, 25, 576), x = 18, y =3, nx=1)
return col
#MNIST-Daten lesen
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)
x_train = x_train[5:6] #Wählen Sie die 5. Daten von Anfang an
out1 = my_im2col(x_train, 5, 5)
out2 = im2col(x_train, 5, 5)
print('all elements are same = ', (out1 == out2).all()) #Ob alle Elemente gleich sind
Die erste Hälfte ist das Ergebnis von "my_im2col" und die zweite Hälfte ist das Ergebnis von "im2col". In beiden Fällen beträgt die Spaltenform nach Transponieren und Umformen tatsächlich 576 Zeilen x 25 Spalten, was vertikal lang ist, aber nicht gut aussieht. Daher ist die Anzeige mit 25 Zeilen x 576 Spalten durch Vertauschen von Zeilen und Spalten horizontal lang. Ich werde. Und wenn Sie sich die beiden Bilder ansehen, haben sie sicherlich das gleiche Muster.
In der letzten Zeile der Ausgabe ** True ** beim Vergleich aller Elemente des mehrdimensionalen Arrays **, sodass wir sehen können, dass my_im2col
und im2col
genau das gleiche Ergebnis liefern. Wenn stride = 1 ist, müssen Sie im Allgemeinen nur ** filter_h * filter_w Slice **. Das ist eine großartige Technik, nicht wahr?
Hier ist ein einfaches, intuitives Beispiel dafür, warum Sie dies tun können.
6.Pooling
# ------------- from common_layers.py -------------
def forward(self, x):
N, C, H, W = x.shape
out_h = int(1 + (H - self.pool_h) / self.stride)
out_w = int(1 + (W - self.pool_w) / self.stride)
col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)
col = col.reshape(-1, self.pool_h*self.pool_w)
arg_max = np.argmax(col, axis=1)
out = np.max(col, axis=1)
out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)
self.x = x
self.arg_max = arg_max
return out
Es sieht so aus, wenn das 4D-Bild (Stapelgröße, Anzahl der Kanäle, Bildhöhe, Bildbreite) durch Pooling verarbeitet wird.
Wie bei der Faltung wird die im2col-Funktion verwendet, um die Matrix abzurufen und mit pool_h, pool_w, stride und pad als Argumenten zu verarbeiten.
Recommended Posts