Risposte:
Voglio spiegare con foto da C3D .
In poche parole, la direzione convoluzionale e la forma di uscita sono importanti!
↑↑↑↑↑ Convoluzioni 1D - Di base ↑↑↑↑↑
import tensorflow as tf
import numpy as np
sess = tf.Session()
ones_1d = np.ones(5)
weight_1d = np.ones(3)
strides_1d = 1
in_1d = tf.constant(ones_1d, dtype=tf.float32)
filter_1d = tf.constant(weight_1d, dtype=tf.float32)
in_width = int(in_1d.shape[0])
filter_width = int(filter_1d.shape[0])
input_1d = tf.reshape(in_1d, [1, in_width, 1])
kernel_1d = tf.reshape(filter_1d, [filter_width, 1, 1])
output_1d = tf.squeeze(tf.nn.conv1d(input_1d, kernel_1d, strides_1d, padding='SAME'))
print sess.run(output_1d)
↑↑↑↑↑ Convoluzioni 2D - Di base ↑↑↑↑↑
ones_2d = np.ones((5,5))
weight_2d = np.ones((3,3))
strides_2d = [1, 1, 1, 1]
in_2d = tf.constant(ones_2d, dtype=tf.float32)
filter_2d = tf.constant(weight_2d, dtype=tf.float32)
in_width = int(in_2d.shape[0])
in_height = int(in_2d.shape[1])
filter_width = int(filter_2d.shape[0])
filter_height = int(filter_2d.shape[1])
input_2d = tf.reshape(in_2d, [1, in_height, in_width, 1])
kernel_2d = tf.reshape(filter_2d, [filter_height, filter_width, 1, 1])
output_2d = tf.squeeze(tf.nn.conv2d(input_2d, kernel_2d, strides=strides_2d, padding='SAME'))
print sess.run(output_2d)
↑↑↑↑↑ Convoluzioni 3D - Di base ↑↑↑↑↑
ones_3d = np.ones((5,5,5))
weight_3d = np.ones((3,3,3))
strides_3d = [1, 1, 1, 1, 1]
in_3d = tf.constant(ones_3d, dtype=tf.float32)
filter_3d = tf.constant(weight_3d, dtype=tf.float32)
in_width = int(in_3d.shape[0])
in_height = int(in_3d.shape[1])
in_depth = int(in_3d.shape[2])
filter_width = int(filter_3d.shape[0])
filter_height = int(filter_3d.shape[1])
filter_depth = int(filter_3d.shape[2])
input_3d = tf.reshape(in_3d, [1, in_depth, in_height, in_width, 1])
kernel_3d = tf.reshape(filter_3d, [filter_depth, filter_height, filter_width, 1, 1])
output_3d = tf.squeeze(tf.nn.conv3d(input_3d, kernel_3d, strides=strides_3d, padding='SAME'))
print sess.run(output_3d)
↑↑↑↑↑ Convoluzioni 2D con ingresso 3D - LeNet, VGG, ..., ↑↑↑↑↑
in_channels = 32 # 3 for RGB, 32, 64, 128, ...
ones_3d = np.ones((5,5,in_channels)) # input is 3d, in_channels = 32
# filter must have 3d-shpae with in_channels
weight_3d = np.ones((3,3,in_channels))
strides_2d = [1, 1, 1, 1]
in_3d = tf.constant(ones_3d, dtype=tf.float32)
filter_3d = tf.constant(weight_3d, dtype=tf.float32)
in_width = int(in_3d.shape[0])
in_height = int(in_3d.shape[1])
filter_width = int(filter_3d.shape[0])
filter_height = int(filter_3d.shape[1])
input_3d = tf.reshape(in_3d, [1, in_height, in_width, in_channels])
kernel_3d = tf.reshape(filter_3d, [filter_height, filter_width, in_channels, 1])
output_2d = tf.squeeze(tf.nn.conv2d(input_3d, kernel_3d, strides=strides_2d, padding='SAME'))
print sess.run(output_2d)
in_channels = 32 # 3 for RGB, 32, 64, 128, ...
out_channels = 64 # 128, 256, ...
ones_3d = np.ones((5,5,in_channels)) # input is 3d, in_channels = 32
# filter must have 3d-shpae x number of filters = 4D
weight_4d = np.ones((3,3,in_channels, out_channels))
strides_2d = [1, 1, 1, 1]
in_3d = tf.constant(ones_3d, dtype=tf.float32)
filter_4d = tf.constant(weight_4d, dtype=tf.float32)
in_width = int(in_3d.shape[0])
in_height = int(in_3d.shape[1])
filter_width = int(filter_4d.shape[0])
filter_height = int(filter_4d.shape[1])
input_3d = tf.reshape(in_3d, [1, in_height, in_width, in_channels])
kernel_4d = tf.reshape(filter_4d, [filter_height, filter_width, in_channels, out_channels])
#output stacked shape is 3D = 2D x N matrix
output_3d = tf.nn.conv2d(input_3d, kernel_4d, strides=strides_2d, padding='SAME')
print sess.run(output_3d)
↑↑↑↑↑ Bonus 1x1 conv in CNN - GoogLeNet, ..., ↑↑↑↑↑
in_channels = 32 # 3 for RGB, 32, 64, 128, ...
out_channels = 64 # 128, 256, ...
ones_3d = np.ones((1,1,in_channels)) # input is 3d, in_channels = 32
# filter must have 3d-shpae x number of filters = 4D
weight_4d = np.ones((3,3,in_channels, out_channels))
strides_2d = [1, 1, 1, 1]
in_3d = tf.constant(ones_3d, dtype=tf.float32)
filter_4d = tf.constant(weight_4d, dtype=tf.float32)
in_width = int(in_3d.shape[0])
in_height = int(in_3d.shape[1])
filter_width = int(filter_4d.shape[0])
filter_height = int(filter_4d.shape[1])
input_3d = tf.reshape(in_3d, [1, in_height, in_width, in_channels])
kernel_4d = tf.reshape(filter_4d, [filter_height, filter_width, in_channels, out_channels])
#output stacked shape is 3D = 2D x N matrix
output_3d = tf.nn.conv2d(input_3d, kernel_4d, strides=strides_2d, padding='SAME')
print sess.run(output_3d)
- Link originale: LINK
- L'autore: Martin Görner
- Twitter: @martin_gorner
- Google +: plus.google.com/+MartinGorne
↑↑↑↑↑ Convoluzioni 1D con ingresso 1D ↑↑↑↑↑
↑↑↑↑↑ Convoluzioni 1D con ingresso 2D ↑↑↑↑↑
in_channels = 32 # 3, 32, 64, 128, ...
out_channels = 64 # 3, 32, 64, 128, ...
ones_4d = np.ones((5,5,5,in_channels))
weight_5d = np.ones((3,3,3,in_channels,out_channels))
strides_3d = [1, 1, 1, 1, 1]
in_4d = tf.constant(ones_4d, dtype=tf.float32)
filter_5d = tf.constant(weight_5d, dtype=tf.float32)
in_width = int(in_4d.shape[0])
in_height = int(in_4d.shape[1])
in_depth = int(in_4d.shape[2])
filter_width = int(filter_5d.shape[0])
filter_height = int(filter_5d.shape[1])
filter_depth = int(filter_5d.shape[2])
input_4d = tf.reshape(in_4d, [1, in_depth, in_height, in_width, in_channels])
kernel_5d = tf.reshape(filter_5d, [filter_depth, filter_height, filter_width, in_channels, out_channels])
output_4d = tf.nn.conv3d(input_4d, kernel_5d, strides=strides_3d, padding='SAME')
print sess.run(output_4d)
sess.close()
1
, quindi → per riga 1+stride
. La convoluzione stessa è invariante allo spostamento, quindi perché la direzione della convoluzione è importante?
Seguendo la risposta di @runhani aggiungo qualche dettaglio in più per rendere la spiegazione un po 'più chiara e cercherò di spiegarlo un po' di più (e ovviamente con esempi di TF1 e TF2).
Uno dei principali bit aggiuntivi che sto includendo sono,
tf.Variable
Ecco come potresti eseguire la convoluzione 1D usando TF 1 e TF 2.
E per essere precisi i miei dati hanno le seguenti forme,
[batch size, width, in channels]
(eg 1, 5, 1
)[width, in channels, out channels]
(eg 5, 1, 4
)[batch size, width, out_channels]
(ad esempio 1, 5, 4
)import tensorflow as tf
import numpy as np
inp = tf.placeholder(shape=[None, 5, 1], dtype=tf.float32)
kernel = tf.Variable(tf.initializers.glorot_uniform()([5, 1, 4]), dtype=tf.float32)
out = tf.nn.conv1d(inp, kernel, stride=1, padding='SAME')
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(out, feed_dict={inp: np.array([[[0],[1],[2],[3],[4]],[[5],[4],[3],[2],[1]]])}))
import tensorflow as tf
import numpy as np
inp = np.array([[[0],[1],[2],[3],[4]],[[5],[4],[3],[2],[1]]]).astype(np.float32)
kernel = tf.Variable(tf.initializers.glorot_uniform()([5, 1, 4]), dtype=tf.float32)
out = tf.nn.conv1d(inp, kernel, stride=1, padding='SAME')
print(out)
E 'molto meno lavoro con TF2 come TF2 non ha bisogno Session
e variable_initializer
, per esempio.
Quindi capiamo cosa sta facendo usando un esempio di attenuazione del segnale. A sinistra hai l'originale e a destra hai l'output di una Convolution 1D che ha 3 canali di uscita.
Più canali sono fondamentalmente più rappresentazioni di caratteristiche di un ingresso. In questo esempio hai tre rappresentazioni ottenute da tre diversi filtri. Il primo canale è il filtro levigante di uguale ponderazione. Il secondo è un filtro che pesa la metà del filtro più dei bordi. Il filtro finale fa l'opposto del secondo. Quindi puoi vedere come questi diversi filtri producono effetti diversi.
La convoluzione 1D è stata utilizzata con successo per l' attività di classificazione delle frasi .
Off alla convoluzione 2D. Se sei una persona che apprende profondamente, le probabilità che non ti sia imbattuto in una convoluzione 2D sono ... beh, circa zero. Viene utilizzato nelle CNN per la classificazione delle immagini, il rilevamento di oggetti, ecc. Nonché nei problemi di PNL che coinvolgono le immagini (ad esempio, la generazione di didascalie di immagini).
Facciamo un esempio, ho un kernel di convoluzione con i seguenti filtri qui,
E per essere precisi i miei dati hanno le seguenti forme,
[batch_size, height, width, 1]
(es. 1, 340, 371, 1
)[height, width, in channels, out channels]
(eg 3, 3, 1, 3
)[batch_size, height, width, out_channels]
(ad esempio 1, 340, 371, 3
)import tensorflow as tf
import numpy as np
from PIL import Image
im = np.array(Image.open(<some image>).convert('L'))#/255.0
kernel_init = np.array(
[
[[[-1, 1.0/9, 0]],[[-1, 1.0/9, -1]],[[-1, 1.0/9, 0]]],
[[[-1, 1.0/9, -1]],[[8, 1.0/9,5]],[[-1, 1.0/9,-1]]],
[[[-1, 1.0/9,0]],[[-1, 1.0/9,-1]],[[-1, 1.0/9, 0]]]
])
inp = tf.placeholder(shape=[None, image_height, image_width, 1], dtype=tf.float32)
kernel = tf.Variable(kernel_init, dtype=tf.float32)
out = tf.nn.conv2d(inp, kernel, strides=[1,1,1,1], padding='SAME')
with tf.Session() as sess:
tf.global_variables_initializer().run()
res = sess.run(out, feed_dict={inp: np.expand_dims(np.expand_dims(im,0),-1)})
import tensorflow as tf
import numpy as np
from PIL import Image
im = np.array(Image.open(<some image>).convert('L'))#/255.0
x = np.expand_dims(np.expand_dims(im,0),-1)
kernel_init = np.array(
[
[[[-1, 1.0/9, 0]],[[-1, 1.0/9, -1]],[[-1, 1.0/9, 0]]],
[[[-1, 1.0/9, -1]],[[8, 1.0/9,5]],[[-1, 1.0/9,-1]]],
[[[-1, 1.0/9,0]],[[-1, 1.0/9,-1]],[[-1, 1.0/9, 0]]]
])
kernel = tf.Variable(kernel_init, dtype=tf.float32)
out = tf.nn.conv2d(x, kernel, strides=[1,1,1,1], padding='SAME')
Qui puoi vedere l'output prodotto dal codice sopra. La prima immagine è l'originale e in senso orario si hanno le uscite del 1 ° filtro, 2 ° filtro e 3 filtri.
Nel contesto della convoluzione 2D, è molto più facile capire cosa significano questi canali multipli. Dì che stai facendo il riconoscimento facciale. Puoi pensare (questa è una semplificazione molto irrealistica ma fa capire il punto) ogni filtro rappresenta un occhio, una bocca, un naso, ecc. In modo che ogni mappa delle caratteristiche sia una rappresentazione binaria se quella caratteristica è presente nell'immagine che hai fornito . Non credo di dover sottolineare che per un modello di riconoscimento facciale queste sono caratteristiche molto preziose. Maggiori informazioni in questo articolo .
Questa è un'illustrazione di ciò che sto cercando di articolare.
La convoluzione 2D è molto diffusa nel regno del deep learning.
Le CNN (Convolution Neural Networks) utilizzano operazioni di convoluzione 2D per quasi tutte le attività di visione artificiale (ad es. Classificazione di immagini, rilevamento di oggetti, classificazione video).
Ora diventa sempre più difficile illustrare cosa sta succedendo all'aumentare del numero di dimensioni. Ma con una buona conoscenza di come funziona la convoluzione 1D e 2D, è molto semplice generalizzare tale comprensione alla convoluzione 3D. Quindi ecco qui.
E per essere precisi i miei dati hanno le seguenti forme,
[batch size, height, width, depth, in channels]
(eg 1, 200, 200, 200, 1
)[height, width, depth, in channels, out channels]
(eg 5, 5, 5, 1, 3
)[batch size, width, height, width, depth, out_channels]
(ad esempio 1, 200, 200, 2000, 3
)import tensorflow as tf
import numpy as np
tf.reset_default_graph()
inp = tf.placeholder(shape=[None, 200, 200, 200, 1], dtype=tf.float32)
kernel = tf.Variable(tf.initializers.glorot_uniform()([5,5,5,1,3]), dtype=tf.float32)
out = tf.nn.conv3d(inp, kernel, strides=[1,1,1,1,1], padding='SAME')
with tf.Session() as sess:
tf.global_variables_initializer().run()
res = sess.run(out, feed_dict={inp: np.random.normal(size=(1,200,200,200,1))})
import tensorflow as tf
import numpy as np
x = np.random.normal(size=(1,200,200,200,1))
kernel = tf.Variable(tf.initializers.glorot_uniform()([5,5,5,1,3]), dtype=tf.float32)
out = tf.nn.conv3d(x, kernel, strides=[1,1,1,1,1], padding='SAME')
La convoluzione 3D è stata utilizzata durante lo sviluppo di applicazioni di machine learning che coinvolgono dati LIDAR (Light Detection and Ranging) di natura tridimensionale.
Va bene, ci sei quasi. Quindi resisti. Vediamo cos'è l'andatura e l'imbottitura. Sono abbastanza intuitivi se ci pensi.
Se percorri un corridoio a grandi passi, ci arrivi più velocemente con meno passaggi. Ma significa anche che hai osservato un ambiente circostante minore rispetto a quando attraversavi la stanza. Rafforziamo ora la nostra comprensione anche con una bella immagine! Comprendiamoli tramite la convoluzione 2D.
Quando si utilizza, tf.nn.conv2d
ad esempio, è necessario impostarlo come vettore di 4 elementi. Non c'è motivo di lasciarsi intimidire da questo. Contiene solo i passi nel seguente ordine.
Convoluzione 2D - [batch stride, height stride, width stride, channel stride]
. Qui, batch stride e channel stride hai appena impostato su uno (ho implementato modelli di deep learning per 5 anni e non ho mai dovuto impostarli su nient'altro che uno). Quindi ti restano solo 2 passi da impostare.
Convoluzione 3D - [batch stride, height stride, width stride, depth stride, channel stride]
. Qui ti preoccupi solo dei passi di altezza / larghezza / profondità.
Ora, noti che non importa quanto piccolo sia il tuo passo (es. 1), si verifica un'inevitabile riduzione delle dimensioni durante la convoluzione (es. La larghezza è 3 dopo aver convolto un'immagine di 4 unità). Ciò è indesiderabile soprattutto quando si costruiscono reti neurali di convoluzione profonda. È qui che l'imbottitura viene in soccorso. Esistono due tipi di imbottitura più comunemente usati.
SAME
e VALID
Di seguito puoi vedere la differenza.
Ultima parola : se sei molto curioso, ti starai chiedendo. Abbiamo appena sganciato una bomba su tutta la riduzione automatica delle dimensioni e ora parliamo di passi diversi. Ma la cosa migliore della falcata è che controlli quando e come ridurre le dimensioni.
In sintesi, in 1D CNN, il kernel si muove in 1 direzione. I dati di input e output di 1D CNN sono bidimensionali. Utilizzato principalmente sui dati delle serie temporali.
Nella CNN 2D, il kernel si muove in 2 direzioni. I dati di input e output della CNN 2D sono tridimensionali. Utilizzato principalmente sui dati di immagine.
Nella CNN 3D, il kernel si muove in 3 direzioni. I dati di input e output della CNN 3D sono quadridimensionali. Utilizzato principalmente su dati di immagini 3D (MRI, scansioni TC).
Puoi trovare maggiori dettagli qui: https://medium.com/@xzz201920/conv1d-conv2d-and-conv3d-8a59182c4d6