In una CNN, ogni nuovo filtro ha pesi diversi per ciascun canale di input o gli stessi pesi di ciascun filtro vengono utilizzati nei canali di input?


28

La mia comprensione è che lo strato convoluzionale di una rete neurale convoluzionale ha quattro dimensioni: input_channels, filter_height, filter_width, number_of_filters. Inoltre, sono consapevole che ogni nuovo filtro viene contorto su TUTTI i canali di input (o mappe di funzionalità / attivazione dal livello precedente).

TUTTAVIA, il grafico sotto di CS231 mostra ogni filtro (in rosso) applicato a un CANALE SINGOLO, anziché lo stesso filtro utilizzato su tutti i canali. Questo sembra indicare che esiste un filtro separato per OGNI canale (in questo caso suppongo siano i tre canali di colore di un'immagine in ingresso, ma lo stesso si applicherebbe per tutti i canali di ingresso).

Ciò è confuso: esiste un filtro univoco diverso per ciascun canale di ingresso?

inserisci qui la descrizione dell'immagine

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

L'immagine sopra sembra contraddittoria con un estratto di "Fundamentals of Deep Learning" di O'reilly :

"... i filtri non funzionano solo su una singola mappa di funzionalità. Funzionano sull'intero volume di mappe di funzionalità che sono state generate su un determinato livello ... Di conseguenza, le mappe di funzionalità devono essere in grado di funzionare su volumi, non solo aree "

... Inoltre, capisco che queste immagini sottostanti indicano che un filtro THE SAME è solo contorto su tutti e tre i canali di input (contraddittorio con quanto mostrato nel grafico CS231 sopra):

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


Risposte:


13

In una rete neurale convoluzionale, esiste un filtro univoco per ciascun canale di input o vengono utilizzati gli stessi nuovi filtri su tutti i canali di input?

L'ex. In effetti esiste un kernel separato definito per ciascuna combinazione di canali di input / output.

In genere per un'architettura CNN, in un singolo filtro come descritto dal number_of_filtersparametro, esiste un kernel 2D per canale di input. Esistono input_channels * number_of_filtersserie di pesi, ognuna delle quali descrive un kernel di convoluzione. Quindi i diagrammi che mostrano un set di pesi per canale di input per ciascun filtro sono corretti. Il primo diagramma mostra anche chiaramente che i risultati dell'applicazione di questi kernel sono combinati sommandoli e aggiungendo distorsione per ciascun canale di output.

Questo può anche essere visto come usando una convoluzione 3D per ciascun canale di uscita, che sembra avere la stessa profondità dell'ingresso. Qual è ciò che mostra il tuo secondo diagramma e anche ciò che molte librerie faranno internamente. Matematicamente questo è lo stesso risultato (purché le profondità corrispondano esattamente), sebbene il tipo di livello sia tipicamente etichettato come "Conv2D" o simile. Allo stesso modo se il tuo tipo di input è intrinsecamente 3D, come voxel o video, potresti usare un livello "Conv3D", ma internamente potrebbe essere implementato come una convoluzione 4D.


grazie per questa spiegazione. Sembra che ogni filtro abbia in realtà un numero di input_channelsversioni con pesi diversi . Hai una fonte "ufficiale" che conferma questa comprensione?
Ryan Chase,

@RyanChase: Sì, è corretto. Vorrei solo indicarti il ​​corso di Andrew Ng sulle CNN - a partire da qui come verrà elaborata l'immagine a colori: coursera.org/learn/convolutional-neural-networks/lecture/ctQZz/…
Neil Slater

Vorrei sottolineare che, in quella fonte ( cs231n.github.io/convolutional-networks ), i filtri (pesi o kernesl) sono volumi (cioè tridimensionali) e hanno la stessa terza dimensione con quella dell'input volume. Inoltre, come è (almeno) ora affermato in quella fonte, i volumi sono stati suddivisi in 3a dimensione per visualizzare meglio l'applicazione del filtro al volume di input. Non penso che, in generale, "esiste un kernel separato definito per ogni combinazione di canali di input / output". è corretta.
nbro,

Si noti che i filtri (o kernel) sono i pesi che devono essere appresi (cioè non sono fissi, ma in realtà sono i parametri della CNN). Potrebbe essere che siano (cioè le sezioni del filtro), alla fine, lo stesso nella terza dimensione.
nbro,

@nbro: Sì, è possibile implementare una convoluzione 2D su più sezioni 2D come una singola convoluzione 3D con la profondità del kernel uguale al numero di canali. Matematicamente questo è identico alla mia descrizione. Puoi anche visualizzarlo come una rete di feed forward completamente connessa troncata con pesi condivisi (molti dei quali sono zero). Questa risposta si concentra su quale sia la vista dei filtri 2D, perché l'OP chiede come sono organizzati i filtri 2D. Possono infatti essere disposti in un kernel 3D più grande, ma vengono comunque applicati come kernel 2D usando il "trucco" che la convoluzione 3D è equivalente.
Neil Slater,

12

L'immagine seguente che hai usato nella tua domanda, descrive in modo molto preciso cosa sta succedendo. Ricorda che ogni elemento del filtro 3D (cubo grigio) è costituito da un valore ( 3x3x3=27valori) diverso . Pertanto, tre diversi filtri 2D di dimensioni 3x3possono essere concatenati per formare questo unico filtro 3D di dimensioni 3x3x3.

convnet2D

Il 3x3x3blocco RGB dall'immagine viene moltiplicato elementalmente da un filtro 3D (mostrato in grigio). In questo caso, il filtro ha 3x3x3=27pesi. Quando questi pesi vengono moltiplicati per elemento e quindi sommati, si ottiene un valore.


Quindi, esiste un filtro separato per ciascun canale di ingresso?

, ci sono tanti filtri 2D quanti sono i canali di input nell'immagine. Tuttavia , è utile se si pensa che per le matrici di input con più di un canale, esiste un solo filtro 3D (come mostrato nell'immagine sopra).


Allora perché si chiama convoluzione 2D (se il filtro è 3D e la matrice di input è 3D)?

Questa è una convoluzione 2D perché i passi del filtro sono solo lungo le dimensioni di altezza e larghezza ( NON profondità) e quindi anche l'output prodotto da questa convoluzione è una matrice 2D. Il numero di direzioni di movimento del filtro determina le dimensioni della convoluzione.

Nota: se costruisci la tua comprensione visualizzando un singolo filtro 3D anziché più filtri 2D (uno per ogni livello), allora ti sarà facile comprendere le architetture CNN avanzate come Resnet, InceptionV3, ecc.


questa è una buona spiegazione, ma più specificamente la domanda che sto cercando di capire è se i filtri che operano su ciascun canale di input sono copie degli stessi pesi o pesi completamente diversi. Questo non è in realtà mostrato nell'immagine e in effetti a me quel tipo di immagine suggerisce che sono gli stessi pesi applicati a ciascun canale (dal loro stesso colore) ... Per la risposta di @neil slater, sembra che ciascuno Il filtro ha in realtà un numero di input_channelsversioni con pesi diversi . Se anche questa è la tua comprensione, esiste una fonte "ufficiale" che lo conferma?
Ryan Chase,

Sì, davvero, anche questa è la mia comprensione. Per me, è stato chiaro quando ho cercato di pensare a quel cubo grigio composto da 27 diversi valori di peso. Ciò significa che ci sono 3 diversi filtri 2D piuttosto che lo stesso filtro 2D applicato a ciascun livello di input.
Mohsin Bukhari,

Non sono riuscito a trovare alcuna fonte ufficiale per confermarlo. Tuttavia, quando stavo cercando di avvolgere la mia testa attorno a questo stesso concetto, ho creato un input fittizio e un filtro peso in Tensorflow e osservato l'output. Ne ero contento. Se trovo qualche spiegazione ufficiale . Modificherò la mia risposta sopra.
Mohsin Bukhari,

Se segui il sentiero Tensorflow. È possibile stampare il filtro peso dopo aver mostrato al proprio manichino strato CNN un campione di input.
Mohsin Bukhari,

@Moshsin Bukhari Cercherò sicuramente di esplorare i filtri all'interno di TensorFlow. Saresti disposto a condividere il tuo codice per come hai esplorato ciò che è contenuto nei filtri? Ad esempio, sei in grado di stampare i valori del filtro in ogni passaggio della rete?
Ryan Chase,

3

Sto seguendo le risposte sopra con un esempio concreto nella speranza di chiarire ulteriormente come funziona la convoluzione rispetto ai canali di input e output e ai pesi, rispettivamente:

Lascia che l'esempio sia il seguente (scritto su 1 livello convoluzionale):

  • il tensore di ingresso è 9x9x5, cioè 5 canali di ingresso, quindi input_channels=5
  • la dimensione del filtro / kernel è 4x4 e il passo è 1
  • il tensore di uscita è 6x6x56, cioè 56 canali di uscita, quindi output_channels=56
  • il tipo di imbottitura è 'VALIDO' (ovvero nessuna imbottitura)

Notiamo che:

  • poiché l'ingresso ha 5 canali, la dimensione del filtro diventa 4x4x5, cioè ci sono 5 filtri 2D unici e separati di dimensione 4x4 (cioè ognuno ha 16 pesi); per evitare l'input della dimensione 9x9x5 il filtro diventa 3D e deve essere della dimensione 4x4x5
  • quindi: per ogni canale di input, esiste un filtro 2D distinto con 16 pesi diversi ciascuno. In altre parole, il numero di filtri 2D corrisponde al numero di canali di input
  • poiché ci sono 56 canali di uscita, ci devono essere 56 filtri tridimensionali W0, W1, ..., W55 di dimensioni 4x4x5 (cfr. nel grafico CS231 ci sono 2 filtri tridimensionali W0, W1 per tenere conto dell'uscita 2 canali), dove la 3a dimensione della dimensione 5 rappresenta il collegamento ai 5 canali di ingresso (cfr. nel grafico CS231 ogni filtro 3D W0, W1 ha la 3a dimensione 3, che corrisponde ai 3 canali di ingresso)
  • pertanto: il numero di filtri 3D è uguale al numero di canali di uscita

Tale strato convoluzionale contiene quindi:

56 filtri tridimensionali di dimensioni 4x4x5 (= 80 pesi diversi ciascuno) per tenere conto dei 56 canali di uscita in cui ciascuno ha un valore per la 3a dimensione di 5 per abbinare i 5 canali di ingresso. In totale ci sono

number_of_filters=input_channel*output_channels=5*56=280

Filtri 2D di dimensioni 4x4 (cioè 280x16 pesi diversi in totale).


0

Esistono solo restrizioni in 2D. Perché?

Immagina uno strato completamente connesso.

Sarebbe terribilmente enorme, ogni neurone sarebbe collegato a forse neuroni di input 1000x1000x3. Ma sappiamo che l'elaborazione del pixel vicino ha senso, quindi ci limitiamo a un piccolo vicinato 2D, quindi ogni neurone è collegato solo a un neurone 3x3 vicino in 2D. Non sappiamo una cosa del genere sui canali, quindi ci colleghiamo a tutti i canali.

Tuttavia, ci sarebbero troppi pesi. Ma a causa dell'invarianza della traduzione, un filtro che funziona bene in un'area è molto probabilmente utile in un'altra area. Quindi usiamo lo stesso set di pesi in 2D. Ancora una volta, non esiste tale invarianza di traduzione tra i canali, quindi non vi è tale restrizione lì.


0

Fare riferimento alla sezione "Connettività locale" in http://cs231n.github.io/convolutional-networks/ e slide 7-18.

L'iperparametro "Campo ricettivo" del filtro è definito solo da altezza e larghezza, poiché la profondità è fissata dalla profondità del livello precedente.

NOTA: "L'estensione della connettività lungo l'asse di profondità è sempre uguale alla PROFONDITÀ del volume di input" -o-- PROFONDITÀ della mappa di attivazione (in caso di livelli successivi).

Intuitivamente, ciò deve essere dovuto al fatto che i dati dei canali di immagine sono interlacciati, non planari. In questo modo, l'applicazione del filtro può essere ottenuta semplicemente moltiplicando i vettori di colonna.

NOTA che Convolutional Network apprende tutti i parametri del filtro (inclusa la dimensione della profondità) e sono totali "h w input_layer_depth + 1 (bias)".


0

Raccomando il capitolo 2.2.1 della mia tesi di master come risposta. Per aggiungere alle risposte rimanenti:

Keras è tuo amico per capire cosa succede:

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())

_________________________________________________________________
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

Prova a formulare le tue opzioni. Cosa significherebbe per i parametri se qualcos'altro fosse il caso?

2400=32(355)

Questo approccio ti aiuta anche con altri tipi di layer, non solo convoluzionali.

Si noti inoltre che si è liberi di implementare diverse soluzioni, che potrebbero avere altri numeri di parametri.


0

Giusto per chiarire due dettagli:

NN3×3N2N

N2N3×3×

Il modo più semplice per convincerti di questo è immaginare cosa succede in altri scenari e vedere che il calcolo diventa degenerato - cioè, se non interfogli e ricombini i risultati, i diversi output non farebbero davvero nulla - loro avrebbe lo stesso effetto di una singola uscita con pesi combinati.


0

Per chiunque cerchi di capire come vengono calcolate le convoluzioni, ecco un utile frammento di codice 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))

L'esecuzione di questo fornisce il seguente output:

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])

Notare come ciascun canale della convoluzione si somma su tutte le uscite dei canali precedenti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.