Pemahaman intuitif tentang konvolusi 1D, 2D, dan 3D dalam jaringan saraf konvolusional

Jawaban:

415

Saya ingin menjelaskan dengan gambar dari C3D .

Singkatnya, arah konvolusional & bentuk keluaran itu penting!

masukkan deskripsi gambar di sini

↑↑↑↑↑ 1D Konvolusi - Dasar ↑↑↑↑↑

  • hanya 1- arah (sumbu waktu) untuk menghitung konv
  • masukan = [W], filter = [k], keluaran = [W]
  • mis.) masukan = [1,1,1,1,1], filter = [0,25,0,5,0,25], keluaran = [1,1,1,1,1]
  • bentuk keluaran adalah larik 1D
  • contoh) penghalusan grafik

Contoh Mainan kode tf.nn.conv1d

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)

masukkan deskripsi gambar di sini

↑↑↑↑↑ Konvolusi 2D - Dasar ↑↑↑↑↑

  • 2 -direction (x, y) untuk menghitung konv
  • bentuk keluaran adalah 2D Matriks
  • masukan = [W, H], filter = [k, k] keluaran = [W, H]
  • contoh) Sobel Egde Fllter

tf.nn.conv2d - Contoh Mainan

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)

masukkan deskripsi gambar di sini

↑↑↑↑↑ Konvolusi 3D - Dasar ↑↑↑↑↑

  • 3 arah (x, y, z) untuk menghitung konv
  • bentuk keluaran adalah Volume 3D
  • masukan = [W, H, L ], filter = [k, k, d ] keluaran = [W, H, M]
  • d <L penting! untuk membuat keluaran volume
  • contoh) C3D

tf.nn.conv3d - Contoh Mainan

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)

masukkan deskripsi gambar di sini

↑↑↑↑↑ Konvolusi 2D dengan masukan 3D - LeNet, VGG, ..., ↑↑↑↑↑

  • Meskipun masukannya 3D misalnya) 224x224x3, 112x112x32
  • bentuk keluaran bukanlah Volume 3D , tapi 2D Matriks
  • karena kedalaman filter = L harus disesuaikan dengan saluran input = L
  • 2 -direction (x, y) untuk menghitung konv! bukan 3D
  • masukan = [W, H, L ], filter = [k, k, L ] keluaran = [W, H]
  • bentuk keluaran adalah 2D Matriks
  • bagaimana jika kita ingin melatih filter N (N adalah jumlah filter)
  • maka bentuk keluarannya adalah (2D tumpuk) 3D = 2D x N matriks.

conv2d - LeNet, VGG, ... untuk 1 filter

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)

conv2d - LeNet, VGG, ... untuk filter N.

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)

masukkan deskripsi gambar di sini ↑↑↑↑↑ Bonus 1x1 konv. Di CNN - GoogLeNet, ..., ↑↑↑↑↑

  • Konv. 1x1 membingungkan jika Anda menganggap ini sebagai filter gambar 2D seperti sobel
  • untuk konv. 1x1 di CNN, input berbentuk 3D seperti gambar di atas.
  • itu menghitung pemfilteran yang bijaksana
  • masukan = [W, H, L], filter = [1,1, L] keluaran = [W, H]
  • output bentuk tumpukan adalah 3D = 2D x N matriks.

tf.nn.conv2d - kasus khusus 1x1 konv

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)

Animasi (Konv 2D dengan input 3D)

masukkan deskripsi gambar di sini - Tautan Asli: LINK
- Penulis: Martin Görner
- Twitter: @martin_gorner
- Google +: plus.google.com/+MartinGorne

Bonus 1D Convolutions dengan input 2D

masukkan deskripsi gambar di sini ↑↑↑↑↑ 1D Konvolusi dengan masukan 1D ↑↑↑↑↑

masukkan deskripsi gambar di sini ↑↑↑↑↑ 1D Konvolusi dengan masukan 2D ↑↑↑↑↑

  • Meskipun inputnya 2D ex) 20x14
  • output-shape bukan 2D , melainkan Matriks 1D
  • karena tinggi filter = L harus disesuaikan dengan tinggi input = L
  • 1 -direction (x) untuk menghitung konv! bukan 2D
  • masukan = [W, L ], filter = [k, L ] keluaran = [W]
  • bentuk keluarannya adalah Matriks 1D
  • bagaimana jika kita ingin melatih filter N (N adalah jumlah filter)
  • maka bentuk keluarannya adalah (ditumpuk 1D) matriks 2D = 1D x N.

Bonus C3D

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

Input & Output di Tensorflow

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Ringkasan

masukkan deskripsi gambar di sini

runhani
sumber
18
Mempertimbangkan kerja keras Anda dan kejelasan dalam penjelasannya, suara positif 8 terlalu kurang.
pengguna3282777
3
Konv. 2d dengan masukan 3d adalah sentuhan yang bagus. Saya akan menyarankan pengeditan untuk menyertakan konv 1d dengan masukan 2d (misalnya array multi-saluran) dan membandingkan perbedaannya dengan konv 2d dengan masukan 2d.
SumNeuron
2
Jawaban luar biasa!
Ben
Mengapa arah konv. Dalam 2d ↲. Saya telah melihat sumber yang mengklaim bahwa arahnya adalah untuk baris 1, lalu untuk baris 1+stride. Konvolusi itu sendiri adalah pergeseran invariant, jadi mengapa arah konvolusi itu penting?
Minh Triet
Terima kasih atas pertanyaan anda Iya! konvolusi itu sendiri adalah shift invariant. jadi untuk perhitungan arah konv. tidak menjadi masalah. (Anda dapat menghitung konv 2d dengan perkalian dua matriks besar. kerangka kerja caffe sudah melakukannya) tetapi untuk pemahaman sebaiknya dijelaskan dengan arah konv. karena konv 2d dengan input 3d membingungkan tanpa arah. ^^
runhani
6

Mengikuti jawaban dari @runhani saya menambahkan beberapa detail lagi untuk membuat penjelasannya lebih jelas dan akan mencoba menjelaskannya sedikit lebih banyak (dan tentu saja dengan contoh dari TF1 dan TF2).

Salah satu bit tambahan utama yang saya sertakan adalah,

  • Penekanan pada aplikasi
  • Penggunaan tf.Variable
  • Penjelasan yang lebih jelas tentang konvolusi input / kernel / output 1D / 2D / 3D
  • Efek langkah / padding

Konvolusi 1D

Inilah cara Anda melakukan konvolusi 1D menggunakan TF 1 dan TF 2.

Dan untuk lebih spesifiknya, data saya memiliki bentuk berikut,

  • Vektor 1D - [batch size, width, in channels](misalnya 1, 5, 1)
  • Kernel - [width, in channels, out channels](misalnya 5, 1, 4)
  • Output - [batch size, width, out_channels](misalnya 1, 5, 4)

Contoh TF1

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

Contoh TF2

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)

Ini jauh lebih sedikit bekerja dengan TF2 karena TF2 tidak perlu Sessiondan variable_initializermisalnya.

Seperti apa ini dalam kehidupan nyata?

Jadi mari kita pahami apa yang dilakukan ini dengan menggunakan contoh penghalusan sinyal. Di sebelah kiri Anda mendapatkan yang asli dan di sebelah kanan Anda mendapatkan keluaran dari Konvolusi 1D yang memiliki 3 saluran keluaran.

masukkan deskripsi gambar di sini

Apa arti banyak saluran?

Beberapa saluran pada dasarnya adalah beberapa representasi fitur dari sebuah input. Dalam contoh ini Anda memiliki tiga representasi yang diperoleh dari tiga filter berbeda. Saluran pertama adalah filter smoothing berbobot sama. Yang kedua adalah filter yang memberi bobot lebih pada bagian tengah filter daripada batas. Filter terakhir melakukan kebalikan dari filter kedua. Jadi Anda dapat melihat bagaimana filter yang berbeda ini menghasilkan efek yang berbeda.

Aplikasi pembelajaran mendalam dari konvolusi 1D

Konvolusi 1D telah berhasil digunakan untuk tugas klasifikasi kalimat .

Konvolusi 2D

Beralih ke konvolusi 2D. Jika Anda adalah orang yang sangat belajar, kemungkinan Anda belum menemukan konvolusi 2D adalah… hampir nol. Ini digunakan di CNN untuk klasifikasi gambar, deteksi objek, dll. Serta dalam masalah NLP yang melibatkan gambar (misalnya pembuatan keterangan gambar).

Mari kita coba contoh, saya mendapat kernel konvolusi dengan filter berikut di sini,

  • Kernel deteksi tepi (jendela 3x3)
  • Blur kernel (jendela 3x3)
  • Pertajam kernel (jendela 3x3)

Dan untuk lebih spesifiknya, data saya memiliki bentuk berikut,

  • Gambar (hitam dan putih) - [batch_size, height, width, 1](mis. 1, 340, 371, 1)
  • Kernel (alias filter) - [height, width, in channels, out channels](misalnya 3, 3, 1, 3)
  • Output (alias peta fitur) - [batch_size, height, width, out_channels](misalnya 1, 340, 371, 3)

Contoh TF1,

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

Contoh TF2

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

Seperti apa ini dalam kehidupan nyata?

Di sini Anda dapat melihat output yang dihasilkan oleh kode di atas. Gambar pertama adalah gambar asli dan berjalan sesuai jam Anda memiliki output dari filter pertama, filter kedua, dan filter 3. masukkan deskripsi gambar di sini

Apa arti banyak saluran?

Dalam konteks jika konvolusi 2D, jauh lebih mudah untuk memahami apa arti beberapa saluran ini. Katakanlah Anda sedang melakukan pengenalan wajah. Anda dapat memikirkan (ini adalah penyederhanaan yang sangat tidak realistis tetapi mendapatkan intinya) setiap filter mewakili mata, mulut, hidung, dll. Sehingga setiap peta fitur akan menjadi representasi biner dari apakah fitur itu ada di gambar yang Anda berikan . Saya rasa saya tidak perlu menekankan bahwa untuk model pengenalan wajah, fitur tersebut sangat berharga. Informasi lebih lanjut di artikel ini .

Ini adalah ilustrasi dari apa yang saya coba utarakan.

masukkan deskripsi gambar di sini

Aplikasi pembelajaran mendalam tentang konvolusi 2D

Konvolusi 2D sangat lazim di ranah pembelajaran mendalam.

CNNs (Convolution Neural Networks) menggunakan operasi konvolusi 2D untuk hampir semua tugas computer vision (misalnya klasifikasi gambar, deteksi objek, klasifikasi video).

Konvolusi 3D

Sekarang semakin sulit untuk mengilustrasikan apa yang terjadi seiring dengan bertambahnya jumlah dimensi. Tetapi dengan pemahaman yang baik tentang cara kerja konvolusi 1D dan 2D, sangat mudah untuk menggeneralisasi pemahaman itu ke konvolusi 3D. Jadi begini.

Dan untuk lebih spesifiknya, data saya memiliki bentuk berikut,

  • Data 3D (LIDAR) - [batch size, height, width, depth, in channels](mis. 1, 200, 200, 200, 1)
  • Kernel - [height, width, depth, in channels, out channels](misalnya 5, 5, 5, 1, 3)
  • Output - [batch size, width, height, width, depth, out_channels](misalnya 1, 200, 200, 2000, 3)

Contoh TF1

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

Contoh TF2

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

Aplikasi pembelajaran mendalam tentang konvolusi 3D

Konvolusi 3D telah digunakan saat mengembangkan aplikasi pembelajaran mesin yang melibatkan data LIDAR (Light Detection and Ranging) yang bersifat 3 dimensi.

Apa ... lebih banyak jargon ?: Langkah dan bantalan

Baiklah Anda hampir sampai. Jadi tunggu sebentar. Mari kita lihat apa itu stride dan padding. Mereka cukup intuitif jika Anda memikirkannya.

Jika Anda melangkah melintasi koridor, Anda akan sampai di sana lebih cepat dengan langkah yang lebih sedikit. Tetapi itu juga berarti bahwa Anda mengamati sekeliling yang lebih rendah daripada jika Anda berjalan melintasi ruangan. Sekarang mari kita perkuat pemahaman kita dengan gambar yang indah juga! Mari kita pahami ini melalui konvolusi 2D.

Memahami langkah

Langkah konvolusi

Saat Anda menggunakan tf.nn.conv2dmisalnya, Anda perlu mengaturnya sebagai vektor dari 4 elemen. Tidak ada alasan untuk terintimidasi oleh ini. Ini hanya berisi langkah-langkah dalam urutan berikut.

  • Konvolusi 2D - [batch stride, height stride, width stride, channel stride]. Di sini, langkah batch dan langkah saluran yang baru saja Anda atur ke satu (saya telah menerapkan model pembelajaran mendalam selama 5 tahun dan tidak pernah harus mengaturnya ke apa pun kecuali satu). Sehingga hanya menyisakan 2 langkah untuk Anda atur.

  • Konvolusi 3D - [batch stride, height stride, width stride, depth stride, channel stride]. Di sini Anda hanya khawatir tentang langkah tinggi / lebar / kedalaman.

Memahami padding

Sekarang, Anda perhatikan bahwa sekecil apa pun langkah Anda (yaitu 1) ada pengurangan dimensi yang tidak dapat dihindari yang terjadi selama konvolusi (misalnya, lebarnya adalah 3 setelah mengkonvolusi gambar dengan lebar 4 unit). Ini tidak diinginkan terutama saat membangun jaringan neural konvolusi yang dalam. Di sinilah padding datang untuk menyelamatkan. Ada dua jenis bantalan yang paling umum digunakan.

  • SAME dan VALID

Di bawah ini Anda dapat melihat perbedaannya.

masukkan deskripsi gambar di sini

Kata terakhir : Jika Anda sangat penasaran, Anda mungkin bertanya-tanya. Kami baru saja menjatuhkan bom pada reduksi dimensi otomatis dan sekarang berbicara tentang memiliki langkah yang berbeda. Tetapi hal terbaik tentang langkah adalah Anda mengontrol kapan dan bagaimana dimensinya dikurangi.

thushv89.dll
sumber
2
  1. CNN 1D, 2D, atau 3D mengacu pada arah konvolusi, bukan dimensi input atau filter.

  2. Untuk 1 saluran masukan, CNN2D sama dengan CNN1D adalah panjang kernel = panjang masukan. (1 arah konv.)

Jerry Liu
sumber
2

Singkatnya, Dalam 1D CNN, kernel bergerak dalam 1 arah. Data masukan dan keluaran 1D CNN adalah 2 dimensi. Kebanyakan digunakan pada data Time-Series.

Dalam 2D ​​CNN, kernel bergerak dalam 2 arah. Data masukan dan keluaran 2D CNN adalah 3 dimensi. Banyak digunakan pada data gambar.

Dalam 3D CNN, kernel bergerak dalam 3 arah. Data masukan dan keluaran 3D CNN adalah 4 dimensi. Kebanyakan digunakan pada data Gambar 3D (MRI, CT Scans).

Anda dapat menemukan detail lebih lanjut di sini: https://medium.com/@xzz201920/conv1d-conv2d-and-conv3d-8a59182c4d6

zz x
sumber