我正在尝试使用Keras构建我的第一个神经网络。我完全没有经验,搞不清楚为什么我的维度设置不正确。我无法从他们的文档中弄明白这个错误在抱怨什么,甚至不知道是哪一层引起了这个问题。
我的模型接收一个32字节的数字数组,并应该在另一端输出一个布尔值。我希望对输入的字节数组进行一维卷积。
arr1是32字节的数组,arr2是一个布尔值数组。
inputData = np.array(arr1)inputData = np.expand_dims(inputData, axis = 2)labelData = np.array(arr2)print inputData.shapeprint labelData.shapemodel = k.models.Sequential()model.add(k.layers.convolutional.Convolution1D(32,2, input_shape = (32, 1)))model.add(k.layers.Activation('relu'))model.add(k.layers.convolutional.Convolution1D(32,2))model.add(k.layers.Activation('relu'))model.add(k.layers.convolutional.Convolution1D(32,2))model.add(k.layers.Activation('relu'))model.add(k.layers.convolutional.Convolution1D(32,2))model.add(k.layers.Activation('relu'))model.add(k.layers.core.Dense(32))model.add(k.layers.Activation('sigmoid'))model.compile(loss = 'binary_crossentropy', optimizer = 'rmsprop', metrics=['accuracy'])model.fit( inputData,labelData)
打印形状的输出是(1000, 32, 1)和(1000,)
我收到的错误是:
Traceback (most recent call last): File “cnn/init.py”, line 50, in inputData,labelData File “/home/steve/Documents/cnn/env/local/lib/python2.7/site-packages/keras/models.py”, line 863, in fit initial_epoch=initial_epoch) File “/home/steve/Documents/cnn/env/local/lib/python2.7/site-packages/keras/engine/training.py”, line 1358, in fit batch_size=batch_size) File “/home/steve/Documents/cnn/env/local/lib/python2.7/site-packages/keras/engine/training.py”, line 1238, in _standardize_user_data exception_prefix=’target’) File “/home/steve/Documents/cnn/env/local/lib/python2.7/site-packages/keras/engine/training.py”, line 128, in _standardize_input_data str(array.shape)) ValueError: Error when checking target: expected activation_5 to have 3 dimensions, but got array with shape (1000, 1)
回答:
看起来你需要多搜索一些关于卷积网络的信息 🙂
你在每一步应用32个长度为2的滤波器到你的序列上。所以我们来看看每层之后张量的维度变化:
维度:(None, 32, 1)
model.add(k.layers.convolutional.Convolution1D(32,2, input_shape = (32, 1)))model.add(k.layers.Activation('relu'))
维度:(None, 31, 32)(你的长度为2的滤波器扫过整个序列,所以序列长度变为31)
model.add(k.layers.convolutional.Convolution1D(32,2))model.add(k.layers.Activation('relu'))
维度:(None, 30, 32)(由于你的滤波器长度为2,你再次损失了一个值,但仍有32个滤波器)
model.add(k.layers.convolutional.Convolution1D(32,2))model.add(k.layers.Activation('relu'))
维度:(None, 29, 32)(同样…)
model.add(k.layers.convolutional.Convolution1D(32,2))model.add(k.layers.Activation('relu'))
维度:(None, 28, 32)
现在你想在上面添加一个全连接层…问题是全连接层会像下面这样处理你的3D输入:
model.add(k.layers.core.Dense(32))model.add(k.layers.Activation('sigmoid'))
维度:(None, 28, 32)
这是你的输出。首先让我觉得奇怪的是你希望从全连接层得到32个输出…你应该把32改为1。但即使这样也无法解决你的问题。看看我们更改最后一层会发生什么:
model.add(k.layers.core.Dense(1))model.add(k.layers.Activation('sigmoid'))
维度:(None, 28, 1)
这是因为你对一个’2D’张量应用了全连接层。当你对一个[28, 32]的输入应用dense(1)层时,它会生成一个形状为(32,1)的权重矩阵,并应用于28个向量,所以你得到28个大小为1的输出。
为了解决这个问题,我建议你像这样更改最后两层:
model = k.models.Sequential()model.add(k.layers.convolutional.Convolution1D(32,2, input_shape = (32, 1)))model.add(k.layers.Activation('relu'))model.add(k.layers.convolutional.Convolution1D(32,2))model.add(k.layers.Activation('relu'))model.add(k.layers.convolutional.Convolution1D(32,2))model.add(k.layers.Activation('relu'))# 只使用一个滤波器,这样输出将是28个值的序列,而不是矩阵。model.add(k.layers.convolutional.Convolution1D(1,2))model.add(k.layers.Activation('relu'))# 将形状从(None, 28, 1)更改为(None, 28)model.add(k.layers.core.Flatten())# 只有一个神经元作为输出,以获得二进制目标。model.add(k.layers.core.Dense(1))model.add(k.layers.Activation('sigmoid'))
现在最后两步将把你的张量从
(None, 29, 32) -> (None, 28, 1) -> (None, 28) -> (None, 1)
希望这对你有帮助。
附注:如果你在想None是什么,它是批次的维度,你不是一次性输入1000个样本,而是批次批次输入的,因为值取决于选择什么,按惯例我们使用None。
编辑:
进一步解释为什么序列长度在每一步都减少一个值。
假设你有一个长度为4的值序列[x1 x2 x3 x4]
,你想用长度为2的滤波器[f1 f2]
来卷积这个序列。第一个值将由y1 = [f1 f2] * [x1 x2]
给出,第二个值将由y2 = [f1 f2] * [x2 x3]
给出,第三个值将由y3 = [f1 f2] * [x3 x4]
给出。然后你到达了序列的末尾,无法继续。你得到的结果序列是[y1 y2 y3]
。
这是由于滤波器长度和序列边界效应造成的。有多种选择,有些会用0填充序列以获得完全相同的输出长度…你可以使用'padding'
参数选择这个选项。你可以在这里阅读更多相关信息,并找到padding
参数的不同可能值。我鼓励你阅读最后一个链接,它提供了关于输入和输出形状的信息…
从文档中:
padding: “valid”或”same”之一(不区分大小写)。”valid”表示”无填充”。”same”表示填充输入,使输出与原始输入长度相同。
默认是’valid’,所以在你的例子中没有填充。
我还建议你升级到最新的Keras版本。Convolution1D现在是Conv1D,所以你可能会发现文档和教程令人困惑。