[PYTHON] col2im gründliches Verständnis

Zielperson

Für diejenigen, die mehr über die im2col-Funktion erfahren möchten, die bei der Bilderkennung mit CNN angezeigt wird Wir werden von der ersten Implementierung bis zur verbesserten Version, der Batch-Channel-kompatiblen Version und der Schritt-Padding-kompatiblen Version unter Verwendung von Gifs und Bildern ausführlich erläutern.

Inhaltsverzeichnis

Was ist col2im?

Die Funktion "col2im" ist eine wichtige Funktion, die in Bereichen wie der Bilderkennung, die mit der Funktion "im2im" gekoppelt ist, unverzichtbar ist. Seine Rolle ist das Gegenteil der im2col -Funktion, die von der im2col -Funktion während der ** Vorwärtsausbreitung ** in eine ** Tensor $ \ rightarrow $ -Matrix ** konvertiert wurde, während sie in ** Backpropagation ** konvertiert wurde. Konvertieren Sie mit der Funktion col2im in ** Matrix $ \ rightarrow $ tensor **. Auf diese Weise wird es in eine lernfähige Form wie einen Filter umgewandelt.

Verhalten und erste Implementierung von col2im

Beginnen wir mit der ersten Implementierung. Mit anderen Worten

stride = 1 \\
pad = 0

Nehme an, dass Die Operation ist die Umkehrung der Funktion "im2col", also wie folgt. col2im_image.gif Bitte beachten Sie zu diesem Zeitpunkt, dass ** die überlappenden Teile hinzugefügt werden **. Der Grund kann unter Berücksichtigung des Filtervorgangs verstanden werden. Wenn Sie sich auf ein Element konzentrieren, wird in der folgenden Abbildung die nächste Ebene der von der Filterung betroffenen Elemente angezeigt. col2im_NN.png Mit anderen Worten, es verzweigt sich in jedes Element. Dies bedeutet, dass ** die Gradienten, die in der Rückausbreitung flossen, addiert werden müssen **. Daher ist es beim Transformieren mit der Funktion "col2im" erforderlich, "die überlappenden Teile hinzuzufügen".

Lassen Sie uns nun einfach ein Programm nach dieser Logik erstellen.

Frühes `col2im`

col2im.py


def col2im(cols, I_shape, O_shape):
    def get_f_shape(i, o):
        return i - o + 1
    
    I_h, I_w = I_shape
    O_h, O_w = O_shape
    F_h = get_f_shape(I_h, O_h)
    F_w = get_f_shape(I_w, O_w)
    images = np.zeros((I_h, I_w))
    
    for h in range(O_h):
        h_lim = h + F_h
        for w in range(O_w):
            w_lim = w + F_w
            images[h:h_lim, w:w_lim] += cols[:, h*O_h+w].reshape(F_h, F_w)
    
    return images


x = np.ones((4, 4))
f = np.arange(-2*2, 0).reshape(2, 2)
im2col_x, O_shape = im2col(x, f, pad=0, get_out_size=True)
im2col_f, Of_shape = im2col(f, f, get_out_size=True)
print(im2col_x)
print(im2col_f)
print(col2im(im2col_x, x.shape, O_shape))
print(col2im(im2col_f, f.shape, Of_shape))

Ich fühle mich so. Zuerst bereiten wir eine Box vor, die nach der Verformung die Form hat, und transformieren sie dann und werfen sie in jede Reihe. Hier ist die Form des Filters der relationale Ausdruck zwischen der Eingabe und Ausgabe von im2col und dem Filter.

O_h = I_h - F_h + 1 \\
O_w = I_w - F_w + 1

Es wird berechnet mit.

Verbesserung von col2im

Schließlich erfordert die anfängliche Implementierung einen $ O_h O_w $ -Zugriff wie "im2col", was den Nachteil einer langsamen Verarbeitungsgeschwindigkeit und Unpraktikabilität hat. Entwickeln Sie also dasselbe wie für "im2col". Die Methode ist nur in umgekehrter Reihenfolge.

Verbesserte Version `col2im`

col2im.py


def col2im(cols, I_shape, O_shape):
    def get_f_shape(i, o):
        return i - o + 1
    
    I_h, I_w = I_shape
    O_h, O_w = O_shape
    F_h = get_f_shape(I_h, O_h)
    F_w = get_f_shape(I_w, O_w)
    cols = cols.reshape(F_h, F_w, O_h, O_w)
    images = np.zeros((I_h, I_w))
    
    for h in range(F_h):
        h_lim = h + O_h
        for w in range(F_w):
            w_lim = w + O_w
            images[h:h_lim, w:w_lim] += cols[h, w, :, :]
    
    return images


x = np.ones((4, 4))
f = np.arange(-2*2, 0).reshape(2, 2)
im2col_x, O_shape = im2col(x, f, pad=0, get_out_size=True)
im2col_f, Of_shape = im2col(f, f, get_out_size=True)
print(im2col_x)
print(im2col_f)
print(col2im(im2col_x, x.shape, O_shape))
print(col2im(im2col_f, f.shape, Of_shape))

Zuerst wird die Matrix in col2im eingegeben improved_im2col_reshape.png Von improved_col.png Es verwandelt sich in eine solche Form. Beim Zuweisen von Speicher für die Ausgabematrix in der verbesserten Version im2col Es hat die gleiche Form. später improved_col2im.gif Ich werde so darauf zugreifen. Es ist technisch ~

Abgeschlossene Version col2im

Betrachten Sie zum Schluss Schritt und Polsterung.

Abgeschlossene Version `col2im`

col2im.py


import numpy as np


def col2im(cols, I_shape, O_shape, stride=1, pad=0):
    def get_f_shape(i, o, s, p):
        return int(i + 2*p - (o - 1)*s)
    
    if len(I_shape) == 2:
        B = C = 1
        I_h, I_w = I_shape
    elif len(img_shape) == 3:
        C = 1
        B, I_h, I_w = I_shape
    else:
        B, C, I_h, I_w = I_shape
    O_h, O_w = O_shape
    
    if isinstance(stride, tuple):
        stride_ud, stride_lr = stride
    else:
        stride_ud = stride
        stride_lr = stride
    if isinstance(pad, tuple):
        pad_ud, pad_lr = pad
    elif isinstance(pad, int):
        pad_ud = pad
        pad_lr = pad
    
    F_h = get_f_shape(I_h, O_h, stride_ud, pad_ud)
    F_w = get_f_shape(I_w, O_w, stride_lr, pad_lr)
    pad_ud = int(np.ceil(pad_ud))
    pad_lr = int(np.ceil(pad_lr))
    cols = cols.reshape(C, F_h, F_w, B, O_h, O_w).transpose(3, 0, 1, 2, 4, 5)
    images = np.zeros((B, C, I_h+2*pad_ud+stride-1, I_w+2*pad_lr+stride-1))
    
    for h in range(F_h):
        h_lim = h + stride*O_h
        for w in range(F_w):
            w_lim = w + stride*O_w
            images[:, :, h:h_lim:stride, w:w_lim:stride] += cols[:, :, h, w, :, :]
    
    return images[:, :, pad_ud : I_h+pad_ud, pad_lr : I_w+pad_lr]

x = np.ones((4, 4))
f = np.arange(-2*2, 0).reshape(2, 2)
im2col_x, O_shape, x_pad = im2col(x, f, pad="same")
im2col_f, Of_shape, f_pad = im2col(f, f)
print(im2col_x)
print(im2col_f)
#print((im2col_f.T@im2col_x).reshape(*O_shape))
print(col2im(im2col_x, x.shape, O_shape, pad=x_pad))
print(col2im(im2col_f, f.shape, Of_shape, pad=f_pad))

Formberechnung unter Berücksichtigung von Schritt und Polsterung

O_h = \left\lceil \cfrac{I_h - F_h + 2\textrm{pad}_{ud}}{\textrm{stride}_{ud}} \right\rceil + 1 \\
O_w = \left\lceil \cfrac{I_w - F_w + 2\textrm{pad}_{lr}}{\textrm{stride}_{lr}} \right\rceil + 1 \\

Berechnen Sie also von hier aus die Form des Filters.

F_h = I_h + 2\textrm{pad}_{ud} - (O_h - 1) \textrm{stride}_{ud} \\
F_w = I_w + 2\textrm{pad}_{lr} - (O_w - 1) \textrm{stride}_{lr}

Ich habe über verschiedene Dinge nachgedacht, aber um es richtig wiederherzustellen, ist der genaue Wert von $ \ textrm {pad} \ _ {ud}, \ textrm {pad} \ _ {lr} $ (der Wert vor dem Aufrunden durch die Deckenfunktion) Es scheint notwendig, also habe ich die Implementierung der Funktion "im2col" entsprechend geändert.

Eine kleine Frage

Während ich experimentierte, bemerkte ich, dass das Hinzufügen von $ 4 \ mal 4 $ Matrix-Eingabematrix nach oben, unten, links und rechts $ \ textrm {pad} = 1 $ $ 6 \ mal 6 $ ergibt, was $ 2 \ mal 2 $ Matrix ist. Wenn Sie den Filter mit $ \ textrm {stride} = 1 $ anwenden, sollte die Ausgabematrix $ 5 \ times 5 $ sein, aber das ist nicht der Fall. pad_im2col.png Ich habe mich gefragt, warum, aber übrigens, wenn Sie unter dieser Bedingung $ \ textrm {pad} = \ textrm {same} $ in die Funktion im2col eingeben, lautet das Auffüllen des Berechnungsergebnisses $ \ textrm {pad} = 0,5 $. Es wird sein. Und natürlich ist die Auffüllbreite eine ganze Zahl, daher wird sie auf $ \ textrm {pad} = 1 $ aufgerundet, sodass sie zu einer $ 6 \ mal 6 $ -Matrix wird. Daher sollte es als $ 5 \ times 5 $ -Matrix behandelt werden, und Sie können sehen, dass die Funktion im2col tatsächlich ein Produkt zurückgibt, das nur die obere linke $ 5 \ times 5 $ -Matrix verwendet. Der Beweis ist, dass der überlappende Teil der col2im -Funktion col2im_result.png Ebenso wird der obere linke Teil viermal hinzugefügt. col2im_q.gif

abschließend

Die Erklärung wird erheblich vereinfacht, da es sich nur um die umgekehrte Reihenfolge der Funktion "im2col" handelt. Detailliertere Erklärungen können hinzugefügt werden, wenn Zeit verfügbar ist.

Deep Learning-Serie

Recommended Posts

col2im gründliches Verständnis
Im2col gründliches Verständnis
Verketten verstehen