Ricerca nel sito web

Una delicata introduzione al riempimento e al passo per le reti neurali convoluzionali


Il livello convoluzionale nelle reti neurali convoluzionali applica sistematicamente filtri a un input e crea mappe di caratteristiche di output.

Sebbene lo strato convoluzionale sia molto semplice, è in grado di ottenere risultati sofisticati e impressionanti. Tuttavia, può essere difficile sviluppare un'intuizione su come la forma dei filtri influisce sulla forma della mappa delle funzionalità di output e su come dovrebbero essere configurati gli iperparametri di configurazione correlati come il riempimento e il passo.

In questo tutorial scoprirai l'intuizione per la dimensione del filtro, la necessità di riempimento e il passo nelle reti neurali convoluzionali.

Dopo aver completato questo tutorial, saprai:

  • In che modo la dimensione del filtro o la dimensione del kernel influisce sulla forma della mappa delle funzionalità di output.
  • Come la dimensione del filtro crea un effetto bordo nella mappa delle caratteristiche e come può essere superato con il riempimento.
  • Come utilizzare la larghezza del filtro sull'immagine di input per ridurre la dimensione della mappa delle caratteristiche di output.

Avvia il tuo progetto con il mio nuovo libro Deep Learning for Computer Vision, che include tutorial passo passo e i file codice sorgente Python per tutti gli esempi.

Cominciamo.

Panoramica dell'esercitazione

Questo tutorial è diviso in cinque parti; sono:

  1. Strato convoluzionale
  2. Problema degli effetti di frontiera
  3. Effetto della dimensione del filtro (dimensione del kernel)
  4. Risolvi il problema dell'effetto bordo con il riempimento
  5. Downsample Ingresso con Stride

Strato convoluzionale

In una rete neurale convoluzionale, uno strato convoluzionale è responsabile dell'applicazione sistematica di uno o più filtri a un input.

La moltiplicazione del filtro per l'immagine di input risulta in un singolo output. L'input è tipicamente costituito da immagini tridimensionali (ad esempio righe, colonne e canali) e, a loro volta, anche i filtri sono tridimensionali con lo stesso numero di canali e meno righe e colonne rispetto all'immagine di input. Pertanto, il filtro viene applicato ripetutamente a ciascuna parte dell'immagine di input, risultando in una mappa di attivazioni di output bidimensionale, denominata mappa delle caratteristiche.

Keras fornisce un'implementazione dello strato convoluzionale chiamato Conv2D.

È necessario specificare la forma prevista delle immagini di input in termini di righe (altezza), colonne (larghezza) e canali (profondità) o [righe, colonne, canali].

Il filtro contiene i pesi che devono essere appresi durante l'addestramento del layer. I pesi del filtro rappresentano la struttura o la caratteristica che il filtro rileverà e la forza dell'attivazione indica il grado in cui la caratteristica è stata rilevata.

Il livello richiede che sia specificato sia il numero di filtri che la forma dei filtri.

Possiamo dimostrarlo con un piccolo esempio. In questo esempio, definiamo una singola immagine o campione di input che ha un canale ed è un quadrato di otto x otto pixel con tutti i valori 0 e una linea verticale larga due pixel al centro.

# define input data
data = [[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0]]
data = asarray(data)
data = data.reshape(1, 8, 8, 1)

Successivamente, possiamo definire un modello che prevede che i campioni di input abbiano la forma (8, 8, 1) e abbia un singolo strato convoluzionale nascosto con un singolo filtro con la forma di tre pixel per tre pixel.

# create model
model = Sequential()
model.add(Conv2D(1, (3,3), input_shape=(8, 8, 1)))
# summarize model
model.summary()

Il filtro viene inizializzato con pesi casuali come parte dell'inizializzazione del modello. Sovrascriveremo i pesi casuali e codificheremo il nostro filtro 3×3 che rileverà le linee verticali.

Cioè il filtro si attiverà fortemente quando rileva una linea verticale e si attiverà debolmente quando non la rileva. Ci aspettiamo che applicando questo filtro all'immagine di input, la mappa delle caratteristiche di output mostri che è stata rilevata la linea verticale.

# define a vertical line detector
detector = [[[[0]],[[1]],[[0]]],
            [[[0]],[[1]],[[0]]],
            [[[0]],[[1]],[[0]]]]
weights = [asarray(detector), asarray([0.0])]
# store the weights in the model
model.set_weights(weights)

Successivamente, possiamo applicare il filtro alla nostra immagine di input chiamando la funzione predict() sul modello.

# apply filter to input data
yhat = model.predict(data)

Il risultato è un output quadridimensionale con un batch, un determinato numero di righe e colonne e un filtro, o [batch, righe, colonne, filtri].

Possiamo stampare le attivazioni nella mappa delle singole caratteristiche per confermare che la linea è stata rilevata.

# enumerate rows
for r in range(yhat.shape[1]):
	# print each column in the row
	print([yhat[0,r,c,0] for c in range(yhat.shape[2])])

Mettendo insieme tutto questo, l'esempio completo è elencato di seguito.

# example of using a single convolutional layer
from numpy import asarray
from keras.models import Sequential
from keras.layers import Conv2D
# define input data
data = [[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0]]
data = asarray(data)
data = data.reshape(1, 8, 8, 1)
# create model
model = Sequential()
model.add(Conv2D(1, (3,3), input_shape=(8, 8, 1)))
# summarize model
model.summary()
# define a vertical line detector
detector = [[[[0]],[[1]],[[0]]],
            [[[0]],[[1]],[[0]]],
            [[[0]],[[1]],[[0]]]]
weights = [asarray(detector), asarray([0.0])]
# store the weights in the model
model.set_weights(weights)
# apply filter to input data
yhat = model.predict(data)
# enumerate rows
for r in range(yhat.shape[1]):
	# print each column in the row
	print([yhat[0,r,c,0] for c in range(yhat.shape[2])])

L'esecuzione dell'esempio riassume innanzitutto la struttura del modello.

Da notare che il singolo strato convoluzionale nascosto prenderà l'immagine di input di 8×8 pixel e produrrà una mappa delle caratteristiche con le dimensioni di 6×6. Approfondiremo il motivo per cui questo accade nella prossima sezione.

Possiamo anche vedere che il livello ha 10 parametri, ovvero nove pesi per il filtro (3×3) e un peso per il bias.

Infine, viene stampata la mappa delle caratteristiche. Dall'esame dei numeri nella matrice 6×6 possiamo vedere che in effetti il filtro specificato manualmente ha rilevato la linea verticale al centro della nostra immagine di input.

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_1 (Conv2D)            (None, 6, 6, 1)           10
=================================================================
Total params: 10
Trainable params: 10
Non-trainable params: 0
_________________________________________________________________


[0.0, 0.0, 3.0, 3.0, 0.0, 0.0]
[0.0, 0.0, 3.0, 3.0, 0.0, 0.0]
[0.0, 0.0, 3.0, 3.0, 0.0, 0.0]
[0.0, 0.0, 3.0, 3.0, 0.0, 0.0]
[0.0, 0.0, 3.0, 3.0, 0.0, 0.0]
[0.0, 0.0, 3.0, 3.0, 0.0, 0.0]

Problema degli effetti di frontiera

Nella sezione precedente, abbiamo definito un singolo filtro con le dimensioni di tre pixel di altezza e tre pixel di larghezza (righe, colonne).

Abbiamo visto che l'applicazione del filtro 3×3, indicato come dimensione del kernel in Keras, all'immagine di input 8×8 ha prodotto una mappa delle caratteristiche con dimensione 6×6.

Cioè, l'immagine di input con 64 pixel è stata ridotta a una mappa delle caratteristiche con 36 pixel. Dove sono finiti gli altri 28 pixel?

Il filtro viene applicato sistematicamente all'immagine di input. Inizia nell'angolo in alto a sinistra dell'immagine e viene spostato da sinistra a destra una colonna di pixel alla volta finché il bordo del filtro non raggiunge il bordo dell'immagine.

Per un filtro di 3×3 pixel applicato a un'immagine di input di 8×8, possiamo vedere che può essere applicato solo sei volte, risultando in una larghezza di sei nella mappa delle caratteristiche di output.

Ad esempio, esaminiamo ciascuna delle sei patch dell'immagine di input (a sinistra), del prodotto punto (operatore "."), del filtro (a destra):

0, 0, 0   0, 1, 0
0, 0, 0 . 0, 1, 0 = 0
0, 0, 0   0, 1, 0

Spostato a destra di un pixel:

0, 0, 1   0, 1, 0
0, 0, 1 . 0, 1, 0 = 0
0, 0, 1   0, 1, 0

Spostato a destra di un pixel:

0, 1, 1   0, 1, 0
0, 1, 1 . 0, 1, 0 = 3
0, 1, 1   0, 1, 0

Spostato a destra di un pixel:

1, 1, 0   0, 1, 0
1, 1, 0 . 0, 1, 0 = 3
1, 1, 0   0, 1, 0

Spostato a destra di un pixel:

1, 0, 0   0, 1, 0
1, 0, 0 . 0, 1, 0 = 0
1, 0, 0   0, 1, 0

Spostato a destra di un pixel:

0, 0, 0   0, 1, 0
0, 0, 0 . 0, 1, 0 = 0
0, 0, 0   0, 1, 0

Questo ci dà la prima riga e ogni colonna della mappa delle caratteristiche di output:

0.0, 0.0, 3.0, 3.0, 0.0, 0.0

La riduzione delle dimensioni dell'input nella mappa delle caratteristiche viene definita effetto confine. È causato dall'interazione del filtro con il bordo dell'immagine.

Questo spesso non è un problema per immagini grandi e filtri piccoli, ma può esserlo con immagini piccole. Può anche diventare un problema una volta impilati un numero di strati convoluzionali.

Ad esempio, di seguito è riportato lo stesso modello aggiornato per avere due livelli convoluzionali impilati.

Ciò significa che un filtro 3×3 viene applicato all'immagine di input 8×8 per ottenere una mappa delle caratteristiche 6×6 come nella sezione precedente. Un filtro 3×3 viene quindi applicato alla mappa delle caratteristiche 6×6.

# example of stacked convolutional layers
from keras.models import Sequential
from keras.layers import Conv2D
# create model
model = Sequential()
model.add(Conv2D(1, (3,3), input_shape=(8, 8, 1)))
model.add(Conv2D(1, (3,3)))
# summarize model
model.summary()

L'esecuzione dell'esempio riassume la forma dell'output di ciascun livello.

Possiamo vedere che l'applicazione dei filtri all'output della mappa delle caratteristiche del primo livello, a sua volta, si traduce in una mappa delle caratteristiche 4×4 più piccola.

Questo può diventare un problema quando sviluppiamo modelli di reti neurali convoluzionali molto profonde con decine o centinaia di strati. Semplicemente esauriremo i dati nelle nostre mappe delle caratteristiche su cui operare.

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_1 (Conv2D)            (None, 6, 6, 1)           10
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 4, 4, 1)           10
=================================================================
Total params: 20
Trainable params: 20
Non-trainable params: 0
_________________________________________________________________

Effetto della dimensione del filtro (dimensione del kernel)

Filtri di dimensioni diverse rileveranno elementi di dimensioni diverse nell'immagine di input e, a loro volta, daranno come risultato mappe di elementi di dimensioni diverse.

È comune utilizzare filtri di dimensioni 3×3 e forse filtri di dimensioni 5×5 o anche 7×7, per immagini di input più grandi.

Ad esempio, di seguito è riportato un esempio del modello con un singolo filtro aggiornato per utilizzare una dimensione del filtro di 5×5 pixel.

# example of a convolutional layer
from keras.models import Sequential
from keras.layers import Conv2D
# create model
model = Sequential()
model.add(Conv2D(1, (5,5), input_shape=(8, 8, 1)))
# summarize model
model.summary()

L'esecuzione dell'esempio dimostra che il filtro 5×5 può essere applicato all'immagine di input 8×8 solo 4 volte, ottenendo un output della mappa delle caratteristiche 4×4.

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_1 (Conv2D)            (None, 4, 4, 1)           26
=================================================================
Total params: 26
Trainable params: 26
Non-trainable params: 0
_________________________________________________________________

Potrebbe essere utile sviluppare ulteriormente l'intuizione della relazione tra la dimensione del filtro e la mappa delle caratteristiche di output per esaminare due casi estremi.

Il primo è un filtro con le dimensioni di 1×1 pixel.

# example of a convolutional layer
from keras.models import Sequential
from keras.layers import Conv2D
# create model
model = Sequential()
model.add(Conv2D(1, (1,1), input_shape=(8, 8, 1)))
# summarize model
model.summary()

L'esecuzione dell'esempio dimostra che la mappa delle caratteristiche di output ha le stesse dimensioni dell'input, in particolare 8×8. Questo perché il filtro ha un solo peso (e un bias).

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_1 (Conv2D)            (None, 8, 8, 1)           2
=================================================================
Total params: 2
Trainable params: 2
Non-trainable params: 0
_________________________________________________________________

L'altro estremo è un filtro con le stesse dimensioni dell'input, in questo caso 8×8 pixel.

# example of a convolutional layer
from keras.models import Sequential
from keras.layers import Conv2D
# create model
model = Sequential()
model.add(Conv2D(1, (8,8), input_shape=(8, 8, 1)))
# summarize model
model.summary()

Eseguendo l'esempio, possiamo vedere che, come ci si potrebbe aspettare, c'è un peso per ogni pixel nell'immagine di input (64 + 1 per il bias) e che l'output è una mappa delle caratteristiche con un singolo pixel.

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_1 (Conv2D)            (None, 1, 1, 1)           65
=================================================================
Total params: 65
Trainable params: 65
Non-trainable params: 0
_________________________________________________________________

Ora che abbiamo familiarità con l'effetto delle dimensioni del filtro sulla dimensione della mappa delle caratteristiche risultante, vediamo come possiamo smettere di perdere pixel.

Risolvi il problema dell'effetto bordo con il riempimento

Per impostazione predefinita, un filtro inizia a sinistra dell'immagine con il lato sinistro del filtro posizionato sui pixel all'estrema sinistra dell'immagine. Il filtro viene quindi spostato sull'immagine una colonna alla volta finché il lato destro del filtro non si trova sui pixel all'estrema destra dell'immagine.

Un approccio alternativo all'applicazione di un filtro a un'immagine consiste nel garantire che a ciascun pixel dell'immagine venga data l'opportunità di trovarsi al centro del filtro.

Per impostazione predefinita, questo non è il caso, poiché i pixel sul bordo dell'input sono sempre esposti solo al bordo del filtro. Avviando il filtro all'esterno della cornice dell'immagine, si dà ai pixel sul bordo dell'immagine più un'opportunità per interagire con il filtro, più un'opportunità per far sì che le caratteristiche vengano rilevate dal filtro e, a sua volta, un output mappa delle caratteristiche che ha la stessa forma dell'immagine di input.

Ad esempio, nel caso di applicazione di un filtro 3×3 all'immagine di input 8×8, possiamo aggiungere un bordo di un pixel attorno all'esterno dell'immagine. Ciò ha l'effetto di creare artificialmente un'immagine di input 10×10. Quando viene applicato il filtro 3×3, il risultato è una mappa delle caratteristiche 8×8. I valori dei pixel aggiunti potrebbero avere il valore zero che non ha alcun effetto con l'operazione del prodotto scalare quando viene applicato il filtro.

x, x, x   0, 1, 0
x, 0, 0 . 0, 1, 0 = 0
x, 0, 0   0, 1, 0

L'aggiunta di pixel al bordo dell'immagine è chiamata riempimento.

In Keras, questo viene specificato tramite l'argomento "padding" sul livello Conv2D, che ha il valore predefinito di "valid" (nessun riempimento). Ciò significa che il filtro viene applicato solo ai percorsi validi per l'input.

Il valore 'padding' di 'same' calcola e aggiunge il riempimento richiesto all'immagine di input (o alla mappa delle caratteristiche) per garantire che l'output abbia la stessa forma dell'input .

L'esempio seguente aggiunge il riempimento allo strato convoluzionale nel nostro esempio elaborato.

# example a convolutional layer with padding
from keras.models import Sequential
from keras.layers import Conv2D
# create model
model = Sequential()
model.add(Conv2D(1, (3,3), padding='same', input_shape=(8, 8, 1)))
# summarize model
model.summary()

L'esecuzione dell'esempio dimostra che la forma della mappa delle caratteristiche di output è la stessa dell'immagine di input: che il riempimento ha l'effetto desiderato.

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_1 (Conv2D)            (None, 8, 8, 1)           10
=================================================================
Total params: 10
Trainable params: 10
Non-trainable params: 0
_________________________________________________________________

L'aggiunta del riempimento consente lo sviluppo di modelli molto profondi in modo tale che le mappe delle caratteristiche non si riducano a nulla.

L'esempio seguente lo dimostra con tre strati convoluzionali impilati.

# example a deep cnn with padding
from keras.models import Sequential
from keras.layers import Conv2D
# create model
model = Sequential()
model.add(Conv2D(1, (3,3), padding='same', input_shape=(8, 8, 1)))
model.add(Conv2D(1, (3,3), padding='same'))
model.add(Conv2D(1, (3,3), padding='same'))
# summarize model
model.summary()

Eseguendo l'esempio, possiamo vedere che con l'aggiunta del riempimento, la forma delle mappe delle caratteristiche di output rimane fissa a 8×8 anche a tre strati di profondità.

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_1 (Conv2D)            (None, 8, 8, 1)           10
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 8, 8, 1)           10
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 8, 8, 1)           10
=================================================================
Total params: 30
Trainable params: 30
Non-trainable params: 0
_________________________________________________________________

Downsample Ingresso con Stride

Il filtro viene spostato sull'immagine da sinistra a destra, dall'alto in basso, con una modifica della colonna di un pixel nei movimenti orizzontali, quindi una modifica della riga di un pixel nei movimenti verticali.

La quantità di movimento tra le applicazioni del filtro all'immagine di input viene definita passo ed è quasi sempre simmetrica in termini di altezza e larghezza.

Il passo o i passi predefiniti in due dimensioni sono (1,1) per il movimento in altezza e larghezza, eseguiti quando necessario. E questa impostazione predefinita funziona bene nella maggior parte dei casi.

È possibile modificare il passo, il che ha un effetto sia sul modo in cui il filtro viene applicato all'immagine che, di conseguenza, sulla dimensione della mappa delle caratteristiche risultante.

Ad esempio, il passo può essere modificato in (2,2). Ciò ha l'effetto di spostare il filtro di due pixel a destra per ogni movimento orizzontale del filtro e di due pixel verso il basso per ogni movimento verticale del filtro durante la creazione della mappa delle caratteristiche.

Possiamo dimostrarlo con un esempio utilizzando l'immagine 8×8 con un prodotto punto a linea verticale (a sinistra) (“.” operatore) con il filtro a linea verticale (a destra) con una falcata di due pixel:

0, 0, 0   0, 1, 0
0, 0, 0 . 0, 1, 0 = 0
0, 0, 0   0, 1, 0

Spostato a destra di due pixel:

0, 1, 1   0, 1, 0
0, 1, 1 . 0, 1, 0 = 3
0, 1, 1   0, 1, 0

Spostato a destra di due pixel:

1, 0, 0   0, 1, 0
1, 0, 0 . 0, 1, 0 = 0
1, 0, 0   0, 1, 0

Possiamo vedere che ci sono solo tre applicazioni valide dei filtri 3×3 all'immagine in ingresso 8×8 con un passo di due. Questo sarà lo stesso nella dimensione verticale.

Ciò ha l'effetto di applicare il filtro in modo tale che l'output della mappa delle caratteristiche normale (6×6) venga sottocampionato in modo che la dimensione di ciascuna dimensione venga ridotta della metà (3×3), risultando in 1/4 della numero di pixel (da 36 pixel a 9).

Lo stride può essere specificato in Keras sul layer Conv2D tramite l'argomento "stride" e specificato come una tupla con altezza e larghezza.

L'esempio dimostra l'applicazione del nostro filtro a linea verticale manuale sull'immagine di input 8×8 con uno strato convoluzionale che ha un passo di due.

# example of vertical line filter with a stride of 2
from numpy import asarray
from keras.models import Sequential
from keras.layers import Conv2D
# define input data
data = [[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0],
		[0, 0, 0, 1, 1, 0, 0, 0]]
data = asarray(data)
data = data.reshape(1, 8, 8, 1)
# create model
model = Sequential()
model.add(Conv2D(1, (3,3), strides=(2, 2), input_shape=(8, 8, 1)))
# summarize model
model.summary()
# define a vertical line detector
detector = [[[[0]],[[1]],[[0]]],
            [[[0]],[[1]],[[0]]],
            [[[0]],[[1]],[[0]]]]
weights = [asarray(detector), asarray([0.0])]
# store the weights in the model
model.set_weights(weights)
# apply filter to input data
yhat = model.predict(data)
# enumerate rows
for r in range(yhat.shape[1]):
	# print each column in the row
	print([yhat[0,r,c,0] for c in range(yhat.shape[2])])

Eseguendo l'esempio, possiamo vedere dal riepilogo del modello che la forma della mappa delle caratteristiche di output sarà 3×3.

Applicando il filtro artigianale all'immagine di input e stampando la mappa delle caratteristiche di attivazione risultante, possiamo vedere che, in effetti, il filtro ha ancora rilevato la linea verticale e può rappresentare questo risultato con meno informazioni.

Il downsampling può essere auspicabile in alcuni casi in cui una conoscenza più approfondita dei filtri utilizzati nel modello o dell'architettura del modello consente una certa compressione nelle mappe delle caratteristiche risultanti.

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
conv2d_1 (Conv2D)            (None, 3, 3, 1)           10
=================================================================
Total params: 10
Trainable params: 10
Non-trainable params: 0
_________________________________________________________________


[0.0, 3.0, 0.0]
[0.0, 3.0, 0.0]
[0.0, 3.0, 0.0]

Ulteriori letture

Questa sezione fornisce più risorse sull'argomento se desideri approfondire.

Messaggi

  • Corso accelerato di reti neurali convoluzionali per l'apprendimento automatico

Libri

  • Capitolo 9: Reti convoluzionali, Deep Learning, 2016.
  • Capitolo 5: Deep Learning per la visione artificiale, Deep Learning con Python, 2017.

API

  • API dei livelli convoluzionali Keras

Riepilogo

In questo tutorial hai scoperto l'intuizione per la dimensione del filtro, la necessità di riempimento e il passo nelle reti neurali convoluzionali.

Nello specifico, hai imparato:

  • In che modo la dimensione del filtro o la dimensione del kernel influisce sulla forma della mappa delle funzionalità di output.
  • Come la dimensione del filtro crea un effetto bordo nella mappa delle caratteristiche e come può essere superato con il riempimento.
  • Come utilizzare la larghezza del filtro sull'immagine di input per ridurre la dimensione della mappa delle caratteristiche di output.

Hai qualche domanda?
Poni le tue domande nei commenti qui sotto e farò del mio meglio per rispondere.

Articoli correlati