为什么 Keras Conv1D 层的输出张量没有输入维度?

Why do Keras Conv1D layers' output tensors not have the input dimension?

根据 keras 文档 (https://keras.io/layers/convolutional/),Conv1D 输出张量的形状是 (batch_size, new_steps, filters) 而输入张量形状是 (batch_size,步骤,input_dim)。我不明白这是怎么回事,因为这意味着如果你传递一个长度为 8000 的 1d 输入,其中 batch_size = 1 和 steps = 1(我听说 steps 意味着输入中的通道数)然后该层的输出形状为 (1,1,X),其中 X 是 Conv 层中过滤器的数量。但是输入维度会发生什么变化?由于层中的 X 过滤器应用于整个输入维度,因此输出维度之一不应该是 8000(或更小,取决于填充),类似于 (1,1,8000,X)?我检查了 Conv2D 层的行为方式更有意义它们的 output_shape 是 (samples, filters, new_rows, new_cols) where new_rows and new_cols where再次根据填充调整输入图像的尺寸。如果 Conv2D 层保留其输入维度,为什么 Conv1D 层不保留?我在这里遗漏了什么吗?

背景信息:

我正在尝试可视化我的 CNN 的一维卷积层激活,但我发现大多数在线工具似乎只适用于二维卷积层,因此我决定为其编写自己的代码。我已经很好地理解它是如何工作的,这里是我到目前为止得到的代码:

# all the model's activation layer output tensors
activation_output_tensors = [layer.output for layer in model.layers if type(layer) is keras.layers.Activation]

# make a function that computes activation layer outputs
activation_comp_function = K.function([model.input, K.learning_phase()], activation_output_tensors)

# 0 means learning phase = False (i.e. the model isn't learning right now)
activation_arrays = activation_comp_function([training_data[0,:-1], 0])

此代码基于 julienr 在此 thread 中的第一条评论,并对当前版本的 keras 进行了一些修改。当我使用它时,尽管所有激活数组的形状都是 (1,1,X) 确实如此......我昨天花了一整天试图弄清楚为什么会这样,但运气不好,非常感谢任何帮助。

更新:原来我把 input_dimension 的含义误认为是步骤维度。这主要是因为我使用的架构来自另一个在 mathematica 中构建模型的小组,在 mathematica 中,输入形状 (X,Y) 到 Conv1D 层意味着 X "channels"(或 input_dimension of X) 和 Y 步骤。感谢 gionni 帮助我意识到这一点,并很好地解释了 "input_dimension" 如何变成 "filter" 维度。

我曾经遇到过与二维卷积相同的问题。问题是,当您应用卷积层时,您应用的内核大小不是 (kernel_size, 1),但实际上是 (kernel_size, input_dim)

如果你想到它,如果不是这样,具有 kernel_size = 1 的一维卷积层将不会对其接收到的输入做任何事情。

相反,它在每个时间步计算输入特征的加权平均值,对每个时间步使用相同的权重(尽管每个过滤器使用一组不同的权重)。我认为将 input_dim 可视化为图像二维卷积中 channels 的数量会有所帮助,其中适用相同的推理(在这种情况下,channels 即 "get lost"并转化为过滤器的数量)。

为了让自己相信这一点,您可以使用 kernel_size=(1D_kernel_size, input_dim) 和相同数量的过滤器用二维卷积层重现一维卷积。举个例子:

from keras.layers import Conv1D, Conv2D
import keras.backend as K
import numpy as np

# create an input with 4 steps and 5 channels/input_dim
channels = 5
steps = 4
filters = 3
val = np.array([list(range(i * channels, (i + 1) * channels)) for i in range(1, steps + 1)])
val = np.expand_dims(val, axis=0)
x = K.variable(value=val)

# 1D convolution. Initialize the kernels to ones so that it's easier to compute the result by hand

conv1d = Conv1D(filters=filters, kernel_size=1, kernel_initializer='ones')(x)

# 2D convolution that replicates the 1D one

# need to add a dimension to your input since conv2d expects 4D inputs. I add it at axis 4 since my keras is setup with `channel_last`
val1 = np.expand_dims(val, axis=3)
x1 = K.variable(value=val1)

conv2d = Conv2D(filters=filters, kernel_size=(1, 5), kernel_initializer='ones')(x1)

# evaluate and print the outputs

print(K.eval(conv1d))
print(K.eval(conv2d))

正如我所说,我也花了一段时间才理解这一点,我想主要是因为没有教程解释清楚