Hat in einer CNN jeder neue Filter unterschiedliche Gewichte für jeden Eingangskanal oder werden dieselben Gewichte für jeden Filter für alle Eingangskanäle verwendet?

28

Ich verstehe, dass die Faltungsschicht eines neuronalen Faltungsnetzwerks vier Dimensionen hat: Eingabekanäle, Filterhöhe, Filterbreite, Anzahl der Filter. Ich verstehe außerdem, dass jeder neue Filter nur über ALLE input_channels (oder Feature- / Aktivierungskarten aus der vorherigen Ebene) gefaltet wird.

Die folgende Grafik aus CS231 zeigt jedoch, dass jeder Filter (in Rot) auf einen EINKANAL angewendet wird, anstatt dass derselbe Filter für alle Kanäle verwendet wird. Dies scheint darauf hinzudeuten, dass es einen separaten Filter für JEDEN Kanal gibt (in diesem Fall gehe ich davon aus, dass es sich um die drei Farbkanäle eines Eingabebildes handelt, aber dasselbe gilt für alle Eingabekanäle).

Dies ist verwirrend - gibt es für jeden Eingangskanal einen anderen eindeutigen Filter?

Bildbeschreibung hier eingeben

Quelle: http://cs231n.github.io/convolutional-networks/

Das obige Bild scheint einem Auszug aus O'reillys "Fundamentals of Deep Learning" zu widersprechen :

"... Filter funktionieren nicht nur auf einer einzelnen Feature-Map. Sie funktionieren auf dem gesamten Volumen von Feature-Maps, die auf einem bestimmten Layer generiert wurden ... Aus diesem Grund müssen Feature-Maps in der Lage sein, über Volumes hinweg zu funktionieren. nicht nur Gebiete "

... Ich verstehe auch, dass diese Bilder darauf hinweisen, dass der gleiche Filter nur über alle drei Eingangskanäle verteilt ist (im Widerspruch zu dem, was in der obigen CS231-Grafik gezeigt wird):

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

Ryan Chase
quelle
1
arxiv.org/pdf/1707.09725 Kapitel 2
Martin Thoma

Antworten:

13

Gibt es in einem neuronalen Faltungsnetzwerk einen eindeutigen Filter für jeden Eingangskanal oder werden für alle Eingangskanäle dieselben neuen Filter verwendet?

Das Vorherige. Tatsächlich ist für jede Kombination aus Eingangskanal und Ausgangskanal ein separater Kernel definiert.

Typischerweise gibt es für eine CNN-Architektur in einem einzelnen Filter, wie von Ihrem number_of_filtersParameter beschrieben, einen 2D-Kernel pro Eingangskanal. Es gibtinput_channels * number_of_filters Mengen von Gewichten, von denen jede einen Faltungskern beschreibt. Die Diagramme, die einen Satz von Gewichten pro Eingangskanal für jeden Filter zeigen, sind also korrekt. Das erste Diagramm zeigt auch deutlich, dass die Ergebnisse des Anwendens dieser Kernel kombiniert werden, indem sie aufsummiert und für jeden Ausgangskanal eine Vorspannung hinzugefügt wird.

Dies kann auch als 3D-Faltung für jeden Ausgangskanal angesehen werden, der zufällig die gleiche Tiefe wie der Eingang hat. Welches ist, was Ihr zweites Diagramm zeigt, und was viele Bibliotheken intern tun werden. Mathematisch ist dies dasselbe Ergebnis (vorausgesetzt, die Tiefen stimmen genau überein), obwohl der Layertyp normalerweise als "Conv2D" oder ähnlich bezeichnet wird. Wenn Ihr Eingabetyp von Natur aus 3D ist, wie z. B. Voxel oder ein Video, können Sie auch eine "Conv3D" -Ebene verwenden. Intern kann diese jedoch auch als 4D-Faltung implementiert werden.

Neil Slater
quelle
danke für diese erklärung. Es hört sich so an, als hätte jeder Filter tatsächlich eine Anzahl von input_channelsVersionen mit unterschiedlichen Gewichten . Haben Sie eine "offizielle" Quelle, die dieses Verständnis bestätigt?
Ryan Chase
@ RyanChase: Ja das ist richtig. Ich möchte Sie nur auf Andrew Ngs CNN
Neil Slater
Ich möchte darauf hinweisen, dass in dieser Quelle ( cs231n.github.io/convolutional-networks ) Filter (weight oder kernesl) Volumen (dh dreidimensional) sind und dieselbe 3. Dimension haben wie die Eingabe Volumen. Darüber hinaus wurden die Volumina, wie (zumindest) jetzt in dieser Quelle angegeben, über die 3. Dimension aufgeteilt, um die Anwendung des Filters auf das Eingangsvolumen besser zu veranschaulichen. Ich glaube nicht, dass im Allgemeinen "für jede Kombination aus Eingangskanal und Ausgangskanal ein separater Kernel definiert ist". ist richtig.
Nr.
Beachten Sie, dass die Filter (oder Kernel) die Gewichte sind, die gelernt werden müssen (dh sie sind nicht festgelegt, aber sie sind tatsächlich die Parameter des CNN). Es kann sein, dass sie (dh die Scheiben des Filters) am Ende in der 3. Dimension gleich sind.
Nr.
@nbro: Ja, Sie können eine 2D-Faltung über mehrere 2D-Schichten als einzelne 3D-Faltung mit der gleichen Kerneltiefe wie die Anzahl der Kanäle implementieren . Mathematisch ist das identisch mit meiner Beschreibung. Sie können es auch als abgeschnittenes, vollständig verbundenes Feedforward-Netzwerk mit gemeinsam genutzten Wertigkeiten (von denen viele null sind) anzeigen. Diese Antwort konzentriert sich auf die Ansicht von 2D-Filtern, da das OP nach der Anordnung der 2D-Filter fragt. Sie können in der Tat zu einem größeren 3D-Kernel angeordnet werden, werden jedoch weiterhin als 2D-Kernel angewendet, wobei der "Trick" verwendet wird, dass die 3D-Faltung äquivalent ist.
Neil Slater
12

Das folgende Bild, das Sie in Ihrer Frage verwendet haben, beschreibt sehr genau, was passiert. Denken Sie daran, dass jedes Element des 3D-Filters (grauer Würfel) aus einem anderen Wert ( 3x3x3=27Werten) besteht. So werden drei verschiedene 2D - Filter der Größe 3x3können verkettet werden , diese zu bilden 3D - Filter der Größe 3x3x3.

convnet2D

Der 3x3x3RGB-Teil des Bildes wird mit einem 3D-Filter (grau dargestellt) elementweise multipliziert . In diesem Fall hat der Filter Gewichte. Wenn diese Gewichte elementweise multipliziert und dann summiert werden, ergibt dies einen Wert. 3x3x3=27


Gibt es für jeden Eingangskanal einen eigenen Filter?

JA , es gibt so viele 2D-Filter wie Eingangskanäle im Bild. Es ist jedoch hilfreich, wenn Sie der Meinung sind, dass es für Eingangsmatrizen mit mehr als einem Kanal nur einen 3D-Filter gibt (siehe Abbildung oben).


Warum heißt das dann 2D-Faltung (wenn Filter 3D ist und Eingabematrix 3D ist)?

Dies ist eine 2D-Faltung, da sich die Schritte des Filters nur entlang der Höhen- und Breitendimensionen ( NICHT der Tiefe) befinden und daher die Ausgabe, die durch diese Faltung erzeugt wird, auch eine 2D-Matrix ist. Die Anzahl der Bewegungsrichtungen des Filters bestimmt die Abmessungen der Faltung.

Hinweis: Wenn Sie Ihr Verständnis verbessern, indem Sie einen einzelnen 3D-Filter anstelle mehrerer 2D-Filter (einen für jede Ebene) anzeigen, können Sie erweiterte CNN-Architekturen wie Resnet, InceptionV3 usw. problemlos verstehen.

Mohsin Bukhari
quelle
Dies ist eine gute Erklärung, aber genauer gesagt ist die Frage, die ich zu verstehen versuche, ob die Filter, die auf jedem Eingangskanal arbeiten, Kopien derselben Gewichtung oder völlig unterschiedliche Gewichtung sind. Dies wird im Bild nicht wirklich gezeigt, und tatsächlich deutet dieses Bild darauf hin, dass auf jeden Kanal die gleichen Gewichte angewendet werden (da sie die gleiche Farbe haben) ... Per @neil Slaters Antwort, es klingt nach jedem Filter hat tatsächlich eine Anzahl von input_channelsVersionen mit unterschiedlichen Gewichten. Wenn dies auch Ihr Verständnis ist, gibt es eine "offizielle" Quelle, die dies bestätigt?
Ryan Chase
Ja, das ist auch mein Verständnis. Für mich war das klar, als ich mir vorstellte, dass dieser graue Würfel aus 27 verschiedenen Gewichtswerten besteht. Dies bedeutet, dass 3 verschiedene 2D-Filter vorhanden sind, und nicht derselbe 2D-Filter auf jede Eingabeebene angewendet wird.
Mohsin Bukhari
Ich konnte keine offizielle Quelle finden, um dies zu bestätigen. Als ich jedoch versuchte, das gleiche Konzept in den Kopf zu bekommen, erstellte ich in Tensorflow einen Dummy-Eingabe- und Gewichtsfilter und beobachtete die Ausgabe. Damit war ich zufrieden. Wenn ich eine offizielle Erklärung finde . Ich werde meine Antwort oben bearbeiten.
Mohsin Bukhari
Wenn Sie dem Tensorflow-Pfad folgen. Sie können Ihren Gewichtsfilter ausdrucken, nachdem Sie Ihrem Dummy-CNN-Layer ein Eingabemuster gezeigt haben.
Mohsin Bukhari
@Moshsin Bukhari Ich werde auf jeden Fall versuchen, die Filter in TensorFlow zu untersuchen. Wären Sie bereit, Ihren Code mit anderen zu teilen, um herauszufinden, was in den Filtern enthalten ist? Können Sie beispielsweise die Werte des Filters bei jedem Schritt im Netzwerk drucken?
Ryan Chase
3

Ich verfolge die obigen Antworten mit einem konkreten Beispiel, um die Funktionsweise der Faltung in Bezug auf die Eingabe- und Ausgabekanäle bzw. die Gewichte näher zu erläutern:

Das Beispiel sei wie folgt (bezogen auf 1 Faltungsschicht):

  • der eingangstensor ist 9x9x5, dh 5 eingangskanäle, also input_channels=5
  • Die Filter- / Kernelgröße ist 4x4 und die Schrittweite ist 1
  • der ausgangstensor ist 6x6x56, dh 56 ausgangskanäle, also output_channels=56
  • der Auffüllungstyp ist 'GÜLTIG' (dh keine Auffüllung)

Wir notieren das:

  • da der Eingang 5 Kanäle hat, wird die Filterdimension 4x4x5, dh es gibt 5 separate, eindeutige 2D-Filter der Größe 4x4 (dh jeder hat 16 Gewichte); Um sich über den Eingang der Größe 9x9x5 zu falten, wird der Filter zu 3D und muss die Größe 4x4x5 haben
  • Deshalb: Für jeden Eingangskanal gibt es einen eigenen 2D-Filter mit jeweils 16 verschiedenen Gewichten. Mit anderen Worten entspricht die Anzahl der 2D-Filter der Anzahl der Eingangskanäle
  • Da es 56 Ausgangskanäle gibt, müssen 56 dreidimensionale Filter W0, W1, ..., W55 der Größe 4x4x5 vorhanden sein (vgl. in der CS231-Grafik gibt es 2 dreidimensionale Filter W0, W1, um die 2 Ausgänge zu berücksichtigen Kanäle), wobei die 3. Dimension der Größe 5 die Verknüpfung zu den 5 Eingangskanälen darstellt (vgl. in der CS231-Grafik hat jeder 3D-Filter W0, W1 die 3. Dimension 3, die den 3 Eingangskanälen entspricht)
  • Deshalb: Die Anzahl der 3D-Filter entspricht der Anzahl der Ausgangskanäle

Diese Faltungsschicht enthält somit:

56 3-dimensionale Filter der Größe 4x4x5 (= jeweils 80 verschiedene Gewichte), um die 56 Ausgangskanäle zu berücksichtigen, wobei jeder einen Wert für die 3. Dimension von 5 hat, der mit den 5 Eingangskanälen übereinstimmt. Insgesamt gibt es

number_of_filters=input_channel*output_channels=5*56=280

2D-Filter der Größe 4x4 (dh insgesamt 280x16 verschiedene Gewichte).

Lukas Z.
quelle
0

Es gibt nur Einschränkungen in 2D. Warum?

Stellen Sie sich eine vollständig verbundene Ebene vor.

Es wäre furchtbar groß, jedes Neuron würde mit vielleicht 1000x1000x3 Eingangsneuronen verbunden sein. Wir wissen jedoch, dass die Verarbeitung von Pixeln in der Nähe sinnvoll ist, daher beschränken wir uns auf eine kleine 2D-Nachbarschaft, sodass jedes Neuron in 2D nur mit 3x3-Neuronen in der Nähe verbunden ist. Wir kennen uns mit Kanälen nicht aus und stellen daher eine Verbindung zu allen Kanälen her.

Trotzdem würde es zu viele Gewichte geben. Aufgrund der Übersetzungsinvarianz ist ein Filter, der in einem Bereich gut funktioniert, höchstwahrscheinlich in einem anderen Bereich nützlich. Wir verwenden also die gleichen Gewichte in 2D. Auch hier gibt es keine solche Übersetzungsinvarianz zwischen den Kanälen, daher gibt es dort keine solche Einschränkung.

maaartinus
quelle
0

Siehe Abschnitt "Lokale Konnektivität" in http://cs231n.github.io/convolutional-networks/ und Folie 7-18.

Der Hyperparameter "Empfangsfeld" des Filters wird nur durch Höhe und Breite definiert, da die Tiefe durch die Tiefe der vorhergehenden Ebene festgelegt wird.

HINWEIS: "Das Ausmaß der Konnektivität entlang der Tiefenachse ist immer gleich der TIEFE des Eingabevolumens" - oder - TIEFE der Aktivierungskarte (bei späteren Ebenen).

Dies muss intuitiv darauf zurückzuführen sein, dass Bildkanaldaten verschachtelt und nicht planar sind. Auf diese Weise kann das Anwenden eines Filters einfach durch Multiplikation von Spaltenvektoren erreicht werden.

HINWEIS: Convolutional Network lernt alle Filterparameter (einschließlich der Tiefendimension) und sie sind insgesamt "h w input_layer_depth + 1 (bias)".

sunil4data
quelle
0

Als Antwort empfehle ich Kapitel 2.2.1 meiner Masterarbeit . So ergänzen Sie die verbleibenden Antworten:

Keras ist dein Freund, der versteht, was passiert:

from keras.models import Sequential
from keras.layers import Conv2D

model = Sequential()
model.add(Conv2D(32, input_shape=(28, 28, 3),
          kernel_size=(5, 5),
          padding='same',
          use_bias=False))
model.add(Conv2D(17, (3, 3), padding='same', use_bias=False))
model.add(Conv2D(13, (3, 3), padding='same', use_bias=False))
model.add(Conv2D(7, (3, 3), padding='same', use_bias=False))
model.compile(loss='categorical_crossentropy', optimizer='adam')

print(model.summary())

gibt

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 28, 28, 32)        2400      
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 28, 28, 17)        4896      
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 28, 28, 13)        1989      
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 28, 28, 7)         819       
=================================================================
Total params: 10,104

Versuchen Sie, Ihre Optionen zu formulieren. Was würde das für die Parameter bedeuten, wenn etwas anderes der Fall wäre?

Hinweis: 2400=32(355)

Dieser Ansatz hilft Ihnen auch bei anderen Ebenentypen, nicht nur bei Faltungsebenen.

Bitte beachten Sie auch, dass Sie andere Lösungen implementieren können, die möglicherweise eine andere Anzahl von Parametern haben.

Martin Thoma
quelle
0

Nur um zwei Details klar zu machen:

Sagen Sie, Sie haben N 2D-Eingangskanäle gehen auf N2D-Ausgabekanäle. Die Gesamtzahl von 2D3×3 Filtergewichte sind eigentlich N2. Aber wie wird die 3D-Faltung beeinflusst, dh wenn jeder Eingangskanal eine 2D-Ebene zu jedem Ausgangskanal beiträgt, besteht jeder Ausgangskanal zunächst ausN 2D-Ebenen, wie werden sie kombiniert?

Dies wird in fast jeder Veröffentlichung, die ich gesehen habe, beschönigt, aber das Schlüsselkonzept ist das N2 2D-Ausgabekanäle werden miteinander verschachtelt, um die zu bilden NAusgangskanäle, wie gemischte Kartendecks, bevor sie summiert werden. Dies ist alles logisch, wenn Sie feststellen, dass Sie entlang der Kanaldimensionen einer Faltung (die nie dargestellt wird) tatsächlich eine vollständig verbundene Ebene haben! Jeder 2D-Eingangskanal wird mit einem eindeutigen multipliziert3×3Filter, liefert einen 2D-Ausgabeschichtbeitrag für einen einzelnen Ausgabekanal. Einmal kombiniert, ist jede Ausgabeebene eine Kombination jeder Eingabeebene×ein einzigartiger Filter. Es ist ein All-in-All-Beitrag.

Am einfachsten können Sie sich davon überzeugen, indem Sie sich vorstellen, was in anderen Szenarien passiert, und feststellen, dass die Berechnung degeneriert. Wenn Sie also die Ergebnisse nicht verschachteln und neu kombinieren, würden die verschiedenen Ausgaben tatsächlich nichts bewirken hätte den gleichen Effekt wie eine einzelne Ausgabe mit kombinierten Gewichten.

user2465201
quelle
0

Für alle, die verstehen möchten, wie Windungen berechnet werden, ist hier ein nützlicher Codeausschnitt in Pytorch:

batch_size = 1
height = 3 
width = 3
conv1_in_channels = 2
conv1_out_channels = 2
conv2_out_channels = 2
kernel_size = 2
# (N, C_in, H, W) is shape of all tensors. (batch_size, channels, height, width)
input = torch.Tensor(np.arange(0, batch_size*height*width*in_channels).reshape(batch_size, in_channels, height, width))
conv1 = nn.Conv2d(in_channels, conv1_out_channels, kernel_size, bias=False) # no bias to make calculations easier
# set the weights of the convolutions to make the convolutions easier to follow
nn.init.constant_(conv1.weight[0][0], 0.25)
nn.init.constant_(conv1.weight[0][1], 0.5)
nn.init.constant_(conv1.weight[1][0], 1) 
nn.init.constant_(conv1.weight[1][1], 2) 
out1 = conv1(input) # compute the convolution

conv2 = nn.Conv2d(conv1_out_channels, conv2_out_channels, kernel_size, bias=False)
nn.init.constant_(conv2.weight[0][0], 0.25)
nn.init.constant_(conv2.weight[0][1], 0.5)
nn.init.constant_(conv2.weight[1][0], 1) 
nn.init.constant_(conv2.weight[1][1], 2) 
out2 = conv2(out1) # compute the convolution

for tensor, name in zip([input, conv1.weight, out1, conv2.weight, out2], ['input', 'conv1', 'out1', 'conv2', 'out2']):
    print('{}: {}'.format(name, tensor))
    print('{} shape: {}'.format(name, tensor.shape))

Wenn Sie dies ausführen, erhalten Sie die folgende Ausgabe:

input: tensor([[[[ 0.,  1.,  2.],
          [ 3.,  4.,  5.],
          [ 6.,  7.,  8.]],

         [[ 9., 10., 11.],
          [12., 13., 14.],
          [15., 16., 17.]]]])
input shape: torch.Size([1, 2, 3, 3])
conv1: Parameter containing:
tensor([[[[0.2500, 0.2500],
          [0.2500, 0.2500]],

         [[0.5000, 0.5000],
          [0.5000, 0.5000]]],


        [[[1.0000, 1.0000],
          [1.0000, 1.0000]],

         [[2.0000, 2.0000],
          [2.0000, 2.0000]]]], requires_grad=True)
conv1 shape: torch.Size([2, 2, 2, 2])
out1: tensor([[[[ 24.,  27.],
          [ 33.,  36.]],

         [[ 96., 108.],
          [132., 144.]]]], grad_fn=<MkldnnConvolutionBackward>)
out1 shape: torch.Size([1, 2, 2, 2])
conv2: Parameter containing:
tensor([[[[0.2500, 0.2500],
          [0.2500, 0.2500]],

         [[0.5000, 0.5000],
          [0.5000, 0.5000]]],


        [[[1.0000, 1.0000],
          [1.0000, 1.0000]],

         [[2.0000, 2.0000],
          [2.0000, 2.0000]]]], requires_grad=True)
conv2 shape: torch.Size([2, 2, 2, 2])
out2: tensor([[[[ 270.]],

         [[1080.]]]], grad_fn=<MkldnnConvolutionBackward>)
out2 shape: torch.Size([1, 2, 1, 1])

Beachten Sie, wie sich jeder Kanal der Faltung über alle vorherigen Kanalausgaben summiert.

Simon Alford
quelle