技术背景
在卷积神经网络(CNN)的深度学习领域中,1D、2D和3D卷积是非常重要的概念。不同维度的卷积在不同类型的数据处理和任务中有着各自的应用场景,理解它们的区别和特点对于构建有效的CNN模型至关重要。
实现步骤
1D卷积
- 输入数据:通常是一个1D向量,形状为 [batch size, width, in channels]。
- 卷积核:形状为 [width, in channels, out channels]。
- 计算过程:卷积核在一个方向(时间轴)上移动进行卷积计算,输出形状为 [batch size, width, out_channels]。
2D卷积
- 输入数据:一般是图像数据,形状为 [batch_size, height, width, in channels]。
- 卷积核:形状为 [height, width, in channels, out channels]。
- 计算过程:卷积核在两个方向(x, y)上移动进行卷积计算,输出形状为 [batch_size, height, width, out_channels]。
3D卷积
- 输入数据:例如LIDAR数据,形状为 [batch size, height, width, depth, in channels]。
- 卷积核:形状为 [height, width, depth, in channels, out channels]。
- 计算过程:卷积核在三个方向(x, y, z)上移动进行卷积计算,输出形状为 [batch size, width, height, width, depth, out_channels]。
核心代码
1D卷积(TensorFlow 1示例)
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]]])}))
1D卷积(TensorFlow 2示例)
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)
2D卷积(TensorFlow 1示例)
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)})
2D卷积(TensorFlow 2示例)
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')
3D卷积(TensorFlow 1示例)
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))})
3D卷积(TensorFlow 2示例)
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')
最佳实践
- 1D卷积:常用于处理时间序列数据,如句子分类任务。
- 2D卷积:广泛应用于图像相关的深度学习任务,如CNN中的图像分类、目标检测等。
- 3D卷积:适用于处理3D图像数据,如MRI、CT扫描等,以及涉及LIDAR数据的机器学习应用。
常见问题
卷积方向是否重要?
卷积本身是平移不变的,对于计算而言卷积方向并不重要,但在理解2D卷积处理3D输入时,通过卷积方向解释会更清晰。
1D、2D、3D卷积的输入和输出数据维度有什么特点?
- 1D卷积:输入和输出数据为2维,常用于时间序列数据。
- 2D卷积:输入和输出数据为3维,常用于图像数据。
- 3D卷积:输入和输出数据为4维,常用于3D图像数据。
什么是步长(stride)和填充(padding)?
- 步长:控制卷积核在输入数据上移动的步幅。在2D卷积中,步长向量为 [batch stride, height stride, width stride, channel stride],通常 batch stride 和 channel stride 设为1;在3D卷积中,步长向量为 [batch stride, height stride, width stride, depth stride, channel stride],主要关注 height、width 和 depth 方向的步长。
- 填充:用于解决卷积过程中维度缩减的问题。常见的填充类型有 SAME 和 VALID。SAME 填充可以使输出的尺寸与输入的尺寸相同,避免在构建深度卷积神经网络时出现维度过度缩减的问题。