如何用等步长深度可分离卷积实现不等步长效果?
如何用等步长深度可分离卷积实现不等步长效果?
嘿,这个问题我之前也踩过坑!确实有些版本的tf.nn.depthwise_conv对高度和宽度方向不等步长的支持不太友好,但咱们完全可以通过组合几个基础操作来模拟出你想要的效果,下面给你两种实用的思路:
方法1:先做单维度下采样,再用等步长深度卷积
假设你想要实现高度步长为2、宽度步长为1的深度可分离卷积效果,可以先对输入特征图做对应方向的下采样,再用步长均为1的深度卷积:
- 下采样可以用池化层(最大池化/平均池化),也可以用1×1卷积层实现可学习的下采样,按需选择即可:
import tensorflow as tf # 假设输入特征图形状为 (batch_size, height, width, channels) input_tensor = tf.random.normal((16, 64, 64, 32)) # 第一步:高度方向下采样,步长2,宽度保持不变 downsampled_h = tf.keras.layers.MaxPool2D( pool_size=(2, 1), strides=(2, 1), padding='same' )(input_tensor) # 第二步:定义3×3的深度卷积核 depthwise_kernel = tf.random.normal((3, 3, 32, 1)) # 用等步长的深度卷积 depthwise_output = tf.nn.depthwise_conv2d( downsampled_h, filter=depthwise_kernel, strides=(1, 1, 1, 1), padding='SAME' ) # 按需添加逐点卷积(深度可分离卷积的标准流程) pointwise_kernel = tf.random.normal((1, 1, 32, 64)) final_output = tf.nn.conv2d( depthwise_output, filter=pointwise_kernel, strides=(1, 1, 1, 1), padding='SAME' )
这样组合后的整体效果,就和直接使用不等步长的深度卷积一致。如果需要宽度步长更大,把下采样方向换成宽度即可。
方法2:拆分两次单维度步长的深度卷积
如果不想用池化(担心丢失特征信息),可以把不等步长的需求拆成两次单维度的深度卷积操作:
比如先处理高度方向的步长需求,再处理宽度方向,用不同形状的卷积核拆分原有的卷积操作:
import tensorflow as tf input_tensor = tf.random.normal((16, 64, 64, 32)) # 第一步:用3×1的深度卷积核处理高度方向,步长设为2 depthwise_kernel_h = tf.random.normal((3, 1, 32, 1)) output_h = tf.nn.depthwise_conv2d( input_tensor, filter=depthwise_kernel_h, strides=(1, 2, 1, 1), padding='SAME' ) # 第二步:用1×3的深度卷积核处理宽度方向,步长保持1 depthwise_kernel_w = tf.random.normal((1, 3, 32, 1)) depthwise_output = tf.nn.depthwise_conv2d( output_h, filter=depthwise_kernel_w, strides=(1, 1, 1, 1), padding='SAME' ) # 添加逐点卷积得到最终输出 pointwise_kernel = tf.random.normal((1, 1, 32, 64)) final_output = tf.nn.conv2d( depthwise_output, filter=pointwise_kernel, strides=(1, 1, 1, 1), padding='SAME' )
这种方法相当于把3×3的卷积拆成了3×1和1×3的两次卷积,既绕开了原API的限制,也能尽量保留特征信息。
需要注意的是,两种方法都要留意padding的设置,确保输出特征图的维度符合你的预期。另外,如果你的TensorFlow版本较新,可以再检查下tf.nn.depthwise_conv2d的参数,新版本已经支持高度和宽度方向不等步长的直接设置了哦!
备注:内容来源于stack exchange,提问作者Ink
相关产品推荐
相关产品推荐

