Einführung
Die Faltung ist eine mathematische Operation, die das Produkt integral aus 2 Funktionen (Signalen) macht, wobei eines der Signale auf dem Kopf steht. Zum Beispiel falten wir unten 2 f(t)- und g(t)-Signale.
Als erstes muss also das g-Signal horizontal (180 Grad) umgedreht werden und dann das g auf f umgedreht werden, wobei alle seine Werte multipliziert und akkumuliert werden.
Die Reihenfolge, in der die Signale gefaltet werden, hat keine Bedeutung für das Endergebnis, also conv(a,b)==conv(b,a)
In diesem Fall ist zu bedenken, dass das blaue Signal f(τ) unser Eingangssignal und g(t) unser Kernel ist, der Begriff Kernel wird verwendet, wenn Faltungen zur Filterung von Signalen verwendet werden.
Ausgangssignalgröße 1D
Im Falle der 1D-Faltung wird die Ausgabegröße auf diese Weise berechnet:
outputSize=(InputSize-KernelSize)+1
Anwendung von Convolutions
Menschen verwenden die Faltung zur Signalverarbeitung für die folgenden Anwendungsfälle:
Filterung von Signalen (1D-Audio, 2D-Bildverarbeitung)
Prüfen, wie sehr ein Signal mit einem anderen in Beziehung steht
Auffinden von Mustern in Signalen
Ein einfaches Beispiel in Matlab und Python (betäubt)
Unten sind zwei Signale x = (0,1,2,3,4) mit w = (1,-1,2).
Von Hand machen
Um das Konzept der Faltung besser zu verstehen, nehmen wir das obige Beispiel von Hand. Im Grunde werden wir 2 Signale (x,w) falten. Zuerst wird W horizontal gespiegelt (O nach links um 180 Grad gedreht)
Danach müssen wir das umgedrehte W über den Eingang X
Beachten Sie, dass in den Schritten 3,4,5 das invertierte Fenster vollständig innerhalb des Eingangssignals liegt. Diese Ergebnisse werden als “gültige” Faltungen bezeichnet. In den Fällen, in denen das invertierte Fenster nicht vollständig innerhalb des Eingangsfensters liegt (X), können wir sie als Null betrachten, oder wir können berechnen, was berechnet werden kann, z.B. in Schritt 1 multiplizieren wir 1 mit Null und der Rest wird einfach ignoriert.
Auffüllen der Eingabe
Um die Größe des Faltungsergebnisses gleich der Größe der Eingabe zu halten und um einen Effekt namens zirkuläre Faltung zu vermeiden, füllen wir das Signal mit Nullen auf.
Wo Sie die Nullen anbringen, hängt davon ab, was Sie tun möchten, d.h.: im 1D-Fall können Sie sie an jedem Ende verknüpfen, aber im 2D-Fall platzieren Sie sie normalerweise um das Originalsignal herum.
Auf Matlab können Sie den Befehl ‘padarray’ verwenden, um die Eingabe aufzufüllen:
>> x
x(:,:,1) =
1 1 0 2 0
2 2 2 2 1
0 0 0 2 1
2 2 2 2 1
2 0 2 2 1
x(:,:,2) =
2 1 0 0 0
0 2 0 1 0
1 0 1 2 0
1 2 0 2 1
1 2 1 2 2
x(:,:,3) =
2 1 1 2 2
1 1 1 0 0
2 0 1 0 2
0 2 0 2 1
0 0 2 1 0
>> padarray(x,[1 1 1])
ans(:,:,1) =
0 0 0 0 0 0 0
0 1 1 0 2 0 0
0 2 2 2 2 1 0
0 0 0 0 2 1 0
0 2 2 2 2 1 0
0 2 0 2 2 1 0
0 0 0 0 0 0 0
ans(:,:,2) =
0 0 0 0 0 0 0
0 2 1 0 0 0 0
0 0 2 0 1 0 0
0 1 0 1 2 0 0
0 1 2 0 2 1 0
0 1 2 1 2 2 0
0 0 0 0 0 0 0
ans(:,:,3) =
0 0 0 0 0 0 0
0 2 1 1 2 2 0
0 1 1 1 0 0 0
0 2 0 1 0 2 0
0 0 2 0 2 1 0
0 0 0 2 1 0 0
0 0 0 0 0 0 0
Ausgabegröße für 2D
Informieren Sie sich bitte über den Umfang unserer Ausgabe, nachdem wir einige Faltungsoperationen daran durchgeführt haben. Glücklicherweise gibt es eine praktische Formel, die uns genau dies sagt.
Wenn wir die Faltung einer Eingabe mit räumlichen Dimensionen [H, W], die mit P aufgefüllt wird, mit einem quadratischen Kern der Größe F und unter Verwendung der Schrittweite S betrachten, dann ist die Ausgabegröße der Faltung definiert als
outputSizeW=(W-F+2P)/S+1 outputSizeH=(H-F+2P)/S+1 output
F ist die Größe des Kerns, wir verwenden normalerweise quadratische Kerne, also ist F sowohl die Breite als auch die Höhe des Kerns
Implementierung der Faltungsoperation
Im folgenden Beispiel handelt es sich um eine 5x5x3 Eingabe (LxHx3), mit einem Conv-Level mit den folgenden Parametern Stride=2, Pad=1, F=3 (3×3 Kernel) und K=2 (zwei Filter).
Unsere Eingabe hat 3 Kanäle, daher benötigen wir eine 3x3x3-Kernel-Gewichtung. Wir haben 2 Filter (K=2), so dass wir am Ende 2 Ausgangsaktivierungen haben werden. Weiter können wir die Größe dieser beiden Ausgänge berechnen, um zu sein: (5 – 3 + 2)/2 + 1 = 3.
Dieser untenstehende Code (Vanille-Version) kann im wirklichen Leben nicht verwendet werden, weil er langsam sein wird, aber er ist gut für ein grundlegendes Verständnis. In der Regel werden tiefe Lernbibliotheken die Faltung als Einzelmatrix-Multiplikation mit der im2col/col2im-Methode durchführen.
%% Faltung n Dimensionen
% Der folgende Code ist nur eine Erweiterung von conv2d_vanila für n Dimensionen.
% Parameter:
% Eingabe: H x B x Tiefe
% K: Kern F x F x Tiefe
% S: schreiten (Wie viele Pixel wird das Fenster auf der Eingabe gleiten)
% Diese Implementierung ist wie der ‘gültige’ Parameter bei normaler Faltung
Funktion outConv = convn_vanilla(Eingabe, Kernel, S)
% Ermittelt die Eingabegröße in Form von Zeilen und Spalten. Die Gewichte sollten
% gleiche Tiefe wie das Eingangsvolumen (Bild)
[rowsIn, colsIn, ~] = Größe(Eingabe);
% Volumendimensio erhalten
depthInput = ndims(eingabe);
% Ermittelt die Kernelgröße, wobei ein quadratischer Kernel immer
F = Größe(Kernel,1);
%% Ausgaben initialisieren
sizeRowsOut = ((rowsIn-F)/S) + 1;
sizeColsOut = ((colsIn-F)/S) + 1;
outConvAcc = Nullen(sizeRowsOut , sizeColsOut, depthInput);
%% Führen Sie die Faltung aus
% Jeden Kanal auf der Eingabe mit seinem jeweiligen Kernel-Kanal falten,
% am Ende die Summe aller Kanalergebnisse.
für Tiefe=1:TiefeEingabe
% Auswahl des Eingangs- und Kernelstromkanals
inputCurrDepth = input(:,:,Tiefe);
kernelCurrDepth = kernel(:,::,Tiefe);
% Iterieren Sie in jeder Zeile und Spalte, (unter Verwendung von stride)
für r=1:S:(rowsIn-1)
für c=1:S:(colsIn-1)
% Vermeiden Sie Stichproben aus dem Bild.
wenn (((c+F)-1) <= colsIn) && (((r+F)-1) <= rowsIn)
% Auswahlfenster auf Eingangsvolumen (Patch)
sampleWindow = inputCurrDepth(r:(r+F)-1,c:(c+F)-1);
% Do das Punktprodukt
dotProd = Summe(sampleWindow(:) .* kernelCurrDepth(:));
% Ergebnis speichern
outConvAcc(ceil(r/S),ceil(c/S),depth) = dotProd;
Ende
Ende
Ende
Ende
% Summenelemente über die Dimension des Eingangsvolumens (Summe aller Kanäle)
outConv = Summe(outConvAcc,depthInput);
Ende